diff --git a/marking_app/assets/images/basic_info.png b/marking_app/assets/images/basic_info.png new file mode 100644 index 0000000..f7fbc7a Binary files /dev/null and b/marking_app/assets/images/basic_info.png differ diff --git a/marking_app/assets/images/overall_level.png b/marking_app/assets/images/overall_level.png new file mode 100644 index 0000000..09f3aa6 Binary files /dev/null and b/marking_app/assets/images/overall_level.png differ diff --git a/marking_app/assets/images/report_group_bg.png b/marking_app/assets/images/report_group_bg.png new file mode 100644 index 0000000..a68eeef Binary files /dev/null and b/marking_app/assets/images/report_group_bg.png differ diff --git a/marking_app/assets/images/reports_bg.png b/marking_app/assets/images/reports_bg.png new file mode 100644 index 0000000..0a5af02 Binary files /dev/null and b/marking_app/assets/images/reports_bg.png differ diff --git a/marking_app/assets/images/reports_card.png b/marking_app/assets/images/reports_card.png new file mode 100644 index 0000000..9afe10d Binary files /dev/null and b/marking_app/assets/images/reports_card.png differ diff --git a/marking_app/assets/images/reports_focus.png b/marking_app/assets/images/reports_focus.png new file mode 100644 index 0000000..7d504d4 Binary files /dev/null and b/marking_app/assets/images/reports_focus.png differ diff --git a/marking_app/assets/images/reports_score.png b/marking_app/assets/images/reports_score.png new file mode 100644 index 0000000..c37207b Binary files /dev/null and b/marking_app/assets/images/reports_score.png differ diff --git a/marking_app/assets/images/right_icon.png b/marking_app/assets/images/right_icon.png new file mode 100644 index 0000000..4697c99 Binary files /dev/null and b/marking_app/assets/images/right_icon.png differ diff --git a/marking_app/assets/images/school_icon.png b/marking_app/assets/images/school_icon.png new file mode 100644 index 0000000..7b8febc Binary files /dev/null and b/marking_app/assets/images/school_icon.png differ diff --git a/marking_app/assets/images/search_icon.png b/marking_app/assets/images/search_icon.png new file mode 100644 index 0000000..e1634ae Binary files /dev/null and b/marking_app/assets/images/search_icon.png differ diff --git a/marking_app/lib/common/model/report/detail_base_info.dart b/marking_app/lib/common/model/report/detail_base_info.dart new file mode 100644 index 0000000..58648a7 --- /dev/null +++ b/marking_app/lib/common/model/report/detail_base_info.dart @@ -0,0 +1,204 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'detail_base_info.g.dart'; + + +@JsonSerializable() +class DetailBaseInfo extends Object { + + @JsonKey(name: 'BaseInfo') + BaseInfo baseInfo; + + @JsonKey(name: 'Module1_CJZL') + Module1_CJZL module1CJZL; + + @JsonKey(name: 'Module2_ZDGZ') + Module2_ZDGZ module2ZDGZ; + + DetailBaseInfo(this.baseInfo,this.module1CJZL,this.module2ZDGZ,); + + factory DetailBaseInfo.fromJson(Map srcJson) => _$DetailBaseInfoFromJson(srcJson); + + Map toJson() => _$DetailBaseInfoToJson(this); + +} + + +@JsonSerializable() +class BaseInfo extends Object { + + @JsonKey(name: 'ExamName') + String examName; + + @JsonKey(name: 'ExamType') + String examType; + + @JsonKey(name: 'Grade') + String grade; + + @JsonKey(name: 'Subject') + String subject; + + @JsonKey(name: 'ExamTime') + String examTime; + + @JsonKey(name: 'TotalScore') + double totalScore; + + @JsonKey(name: 'AvgScore') + double avgScore; + + @JsonKey(name: 'MaxScore') + double maxScore; + + @JsonKey(name: 'RateGood') + String rateGood; + + @JsonKey(name: 'RatePass') + String ratePass; + + BaseInfo(this.examName,this.examType,this.grade,this.subject,this.examTime,this.totalScore,this.avgScore,this.maxScore,this.rateGood,this.ratePass,); + + factory BaseInfo.fromJson(Map srcJson) => _$BaseInfoFromJson(srcJson); + + Map toJson() => _$BaseInfoToJson(this); + +} + + +@JsonSerializable() +class Module1_CJZL extends Object { + + @JsonKey(name: 'BatchNO') + String batchNO; + + @JsonKey(name: 'HeadStartRowIndex') + int headStartRowIndex; + + @JsonKey(name: 'BodyStartRowIndex') + int bodyStartRowIndex; + + @JsonKey(name: 'Sheets') + List sheets; + + Module1_CJZL(this.batchNO,this.headStartRowIndex,this.bodyStartRowIndex,this.sheets,); + + factory Module1_CJZL.fromJson(Map srcJson) => _$Module1_CJZLFromJson(srcJson); + + Map toJson() => _$Module1_CJZLToJson(this); + +} + + +@JsonSerializable() +class Sheets extends Object { + + @JsonKey(name: 'SheetName') + String? sheetName; + + @JsonKey(name: 'HeadData') + List headData; + + @JsonKey(name: 'BodyData') + List bodyData; + + @JsonKey(name: 'BodyRowHeightPx') + double bodyRowHeightPx; + + @JsonKey(name: 'HeadsRowHeightPx') + double headsRowHeightPx; + + Sheets(this.sheetName,this.headData,this.bodyData,this.bodyRowHeightPx,this.headsRowHeightPx,); + + factory Sheets.fromJson(Map srcJson) => _$SheetsFromJson(srcJson); + + Map toJson() => _$SheetsToJson(this); + +} + + +@JsonSerializable() +class HeadData extends Object { + + @JsonKey(name: 'RowData') + List> rowData; + + @JsonKey(name: 'AutoMerge') + bool autoMerge; + + @JsonKey(name: 'TotalMerge') + bool totalMerge; + + @JsonKey(name: 'ColumnWidthPx') + double columnWidthPx; + + HeadData(this.rowData,this.autoMerge,this.totalMerge,this.columnWidthPx,); + + factory HeadData.fromJson(Map srcJson) => _$HeadDataFromJson(srcJson); + + Map toJson() => _$HeadDataToJson(this); + +} + + +@JsonSerializable() +class Module2_ZDGZ extends Object { + + @JsonKey(name: 'TopExcelData') + TopExcelData topExcelData; + + @JsonKey(name: 'BottomExcelData') + BottomExcelData bottomExcelData; + + Module2_ZDGZ(this.topExcelData,this.bottomExcelData,); + + factory Module2_ZDGZ.fromJson(Map srcJson) => _$Module2_ZDGZFromJson(srcJson); + + Map toJson() => _$Module2_ZDGZToJson(this); + +} + + +@JsonSerializable() +class TopExcelData extends Object { + + @JsonKey(name: 'HeadStartRowIndex') + int headStartRowIndex; + + @JsonKey(name: 'BodyStartRowIndex') + int bodyStartRowIndex; + + @JsonKey(name: 'Sheets') + List sheets; + + TopExcelData(this.headStartRowIndex,this.bodyStartRowIndex,this.sheets,); + + factory TopExcelData.fromJson(Map srcJson) => _$TopExcelDataFromJson(srcJson); + + Map toJson() => _$TopExcelDataToJson(this); + +} + + + +@JsonSerializable() +class BottomExcelData extends Object { + + @JsonKey(name: 'HeadStartRowIndex') + int headStartRowIndex; + + @JsonKey(name: 'BodyStartRowIndex') + int bodyStartRowIndex; + + @JsonKey(name: 'Sheets') + List sheets; + + BottomExcelData(this.headStartRowIndex,this.bodyStartRowIndex,this.sheets,); + + factory BottomExcelData.fromJson(Map srcJson) => _$BottomExcelDataFromJson(srcJson); + + Map toJson() => _$BottomExcelDataToJson(this); + +} + + diff --git a/marking_app/lib/common/model/report/exam_records.dart b/marking_app/lib/common/model/report/exam_records.dart new file mode 100644 index 0000000..8eb7fcc --- /dev/null +++ b/marking_app/lib/common/model/report/exam_records.dart @@ -0,0 +1,62 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'exam_records.g.dart'; + + +@JsonSerializable() +class ExamRecords extends Object { + + @JsonKey(name: 'Classes') + String classes; + + @JsonKey(name: 'ClassIds') + Map classIds; + + @JsonKey(name: 'Id') + int id; + + @JsonKey(name: 'UserId') + int userId; + + @JsonKey(name: 'Name') + String name; + + @JsonKey(name: 'Type') + int type; + + @JsonKey(name: 'TypeName') + String typeName; + + @JsonKey(name: 'Grade') + String grade; + + @JsonKey(name: 'Subjects') + String subjects; + + @JsonKey(name: 'SubjectStr') + String subjectStr; + + @JsonKey(name: 'StartTime') + String startTime; + + @JsonKey(name: 'StartTimeStr') + String startTimeStr; + + @JsonKey(name: 'Status') + int status; + + @JsonKey(name: 'StatusName') + String statusName; + + @JsonKey(name: 'CreateTime') + String createTime; + + ExamRecords(this.classes,this.classIds,this.id,this.userId,this.name,this.type,this.typeName,this.grade,this.subjects,this.subjectStr,this.startTime,this.startTimeStr,this.status,this.statusName,this.createTime,); + + factory ExamRecords.fromJson(Map srcJson) => _$ExamRecordsFromJson(srcJson); + + Map toJson() => _$ExamRecordsToJson(this); + +} + + diff --git a/marking_app/lib/common/model/report/exam_records_all.dart b/marking_app/lib/common/model/report/exam_records_all.dart new file mode 100644 index 0000000..b6247dc --- /dev/null +++ b/marking_app/lib/common/model/report/exam_records_all.dart @@ -0,0 +1,141 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'exam_records_all.g.dart'; + +@JsonSerializable() +class ExamRecordsAll extends Object { + @JsonKey(name: 'Type') + Type type; + + @JsonKey(name: 'Grade') + Grade grade; + + @JsonKey(name: 'Subject') + Subject subject; + + @JsonKey(name: 'TimePeriod') + TimePeriod timePeriod; + + ExamRecordsAll( + this.type, + this.grade, + this.subject, + this.timePeriod, + ); + + factory ExamRecordsAll.fromJson(Map srcJson) => + _$ExamRecordsAllFromJson(srcJson); + + Map toJson() => _$ExamRecordsAllToJson(this); +} + +@JsonSerializable() +class Type extends Object { + @JsonKey(name: 'IsDisabled') + bool isDisabled; + + @JsonKey(name: 'DefaultValue') + String defaultValue; + + @JsonKey(name: 'ComboData') + List comboData; + + Type( + this.isDisabled, + this.defaultValue, + this.comboData, + ); + + factory Type.fromJson(Map srcJson) => + _$TypeFromJson(srcJson); + + Map toJson() => _$TypeToJson(this); +} + +@JsonSerializable() +class ComboData extends Object { + @JsonKey(name: 'Value') + dynamic value; + + @JsonKey(name: 'Text') + String text; + + @JsonKey(name: 'isCheck') + bool isCheck; + + ComboData(this.value, this.text, {this.isCheck = false}); + + factory ComboData.fromJson(Map srcJson) => + _$ComboDataFromJson(srcJson); + + Map toJson() => _$ComboDataToJson(this); +} + +@JsonSerializable() +class Grade extends Object { + @JsonKey(name: 'IsDisabled') + bool isDisabled; + + @JsonKey(name: 'DefaultValue') + String defaultValue; + + @JsonKey(name: 'ComboData') + List comboData; + + Grade( + this.isDisabled, + this.defaultValue, + this.comboData, + ); + + factory Grade.fromJson(Map srcJson) => + _$GradeFromJson(srcJson); + + Map toJson() => _$GradeToJson(this); +} + +@JsonSerializable() +class Subject extends Object { + @JsonKey(name: 'IsDisabled') + bool isDisabled; + + @JsonKey(name: 'DefaultValue') + String defaultValue; + + @JsonKey(name: 'ComboData') + List comboData; + + Subject( + this.isDisabled, + this.defaultValue, + this.comboData, + ); + + factory Subject.fromJson(Map srcJson) => + _$SubjectFromJson(srcJson); + + Map toJson() => _$SubjectToJson(this); +} + +@JsonSerializable() +class TimePeriod extends Object { + @JsonKey(name: 'IsDisabled') + bool isDisabled; + + @JsonKey(name: 'DefaultValue') + String defaultValue; + + @JsonKey(name: 'ComboData') + List comboData; + + TimePeriod( + this.isDisabled, + this.defaultValue, + this.comboData, + ); + + factory TimePeriod.fromJson(Map srcJson) => + _$TimePeriodFromJson(srcJson); + + Map toJson() => _$TimePeriodToJson(this); +} diff --git a/marking_app/lib/common/model/report/exam_records_params.dart b/marking_app/lib/common/model/report/exam_records_params.dart new file mode 100644 index 0000000..2c2aa89 --- /dev/null +++ b/marking_app/lib/common/model/report/exam_records_params.dart @@ -0,0 +1,39 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:marking_app/common/model/common/base_page_report.dart'; + +part 'exam_records_params.g.dart'; + + +@JsonSerializable() +class ExamRecordsParams extends BasePageReport { + + @JsonKey(name: 'SearchStr') + String? searchStr; + + @JsonKey(name: 'Grade') + String? grade; + + @JsonKey(name: 'ClassId') + int? classId; + + @JsonKey(name: 'PositionId') + int? positionId; + + @JsonKey(name: 'ReportType') + String? reportType; + + @JsonKey(name: 'Subject') + int? subject; + + @JsonKey(name: 'TimePeriod') + int? timePeriod; + + ExamRecordsParams({this.searchStr = '',this.grade,this.classId = -1,this.positionId = -1,this.reportType,this.subject = -1,this.timePeriod = -1,page,limit}) : super(page, limit); + + factory ExamRecordsParams.fromJson(Map srcJson) => _$ExamRecordsParamsFromJson(srcJson); + + Map toJson() => _$ExamRecordsParamsToJson(this); + +} + + diff --git a/marking_app/lib/common/model/report/question_know_point.dart b/marking_app/lib/common/model/report/question_know_point.dart new file mode 100644 index 0000000..d62279d --- /dev/null +++ b/marking_app/lib/common/model/report/question_know_point.dart @@ -0,0 +1,97 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:marking_app/common/model/report/detail_base_info.dart'; + +part 'question_know_point.g.dart'; + + +@JsonSerializable() +class QuestionKnowPoint extends Object { + + @JsonKey(name: 'QuestionList') + List questionList; + + @JsonKey(name: 'UserQuestion') + UserQuestion userQuestion; + + @JsonKey(name: 'KnowPointList') + List knowPointList; + + QuestionKnowPoint(this.questionList,this.userQuestion,this.knowPointList,); + + factory QuestionKnowPoint.fromJson(Map srcJson) => _$QuestionKnowPointFromJson(srcJson); + + Map toJson() => _$QuestionKnowPointToJson(this); + +} + + +@JsonSerializable() +class UserQuestion extends Object { + + @JsonKey(name: 'BatchNO') + String batchNO; + + @JsonKey(name: 'HeadStartRowIndex') + int headStartRowIndex; + + @JsonKey(name: 'BodyStartRowIndex') + int bodyStartRowIndex; + + @JsonKey(name: 'Sheets') + List sheets; + + UserQuestion(this.batchNO,this.headStartRowIndex,this.bodyStartRowIndex,this.sheets,); + + factory UserQuestion.fromJson(Map srcJson) => _$UserQuestionFromJson(srcJson); + + Map toJson() => _$UserQuestionToJson(this); + +} + + +@JsonSerializable() +class HeadData extends Object { + + @JsonKey(name: 'RowData') + List> rowData; + + @JsonKey(name: 'AutoMerge') + bool autoMerge; + + @JsonKey(name: 'TotalMerge') + bool totalMerge; + + @JsonKey(name: 'ColumnWidthPx') + int columnWidthPx; + + HeadData(this.rowData,this.autoMerge,this.totalMerge,this.columnWidthPx,); + + factory HeadData.fromJson(Map srcJson) => _$HeadDataFromJson(srcJson); + + Map toJson() => _$HeadDataToJson(this); + +} + + +@JsonSerializable() +class KnowPointList extends Object { + + @JsonKey(name: 'Name') + String name; + + @JsonKey(name: 'QuestionNums') + String questionNums; + + @JsonKey(name: 'CorrectRate') + String correctRate; + + @JsonKey(name: 'GradeCorrectRate') + String gradeCorrectRate; + + KnowPointList(this.name,this.questionNums,this.correctRate,this.gradeCorrectRate,); + + factory KnowPointList.fromJson(Map srcJson) => _$KnowPointListFromJson(srcJson); + + Map toJson() => _$KnowPointListToJson(this); + +} diff --git a/marking_app/lib/common/model/report/report_card.dart b/marking_app/lib/common/model/report/report_card.dart new file mode 100644 index 0000000..e03db36 --- /dev/null +++ b/marking_app/lib/common/model/report/report_card.dart @@ -0,0 +1,92 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'report_card.g.dart'; + + +@JsonSerializable() +class ReportCard extends Object { + + @JsonKey(name: 'TotalCount') + int totalCount; + + @JsonKey(name: 'Head') + List head; + + @JsonKey(name: 'Data') + List data; + + ReportCard(this.totalCount,this.head,this.data,); + + factory ReportCard.fromJson(Map srcJson) => _$ReportCardFromJson(srcJson); + + Map toJson() => _$ReportCardToJson(this); + +} + + +@JsonSerializable() +class Data extends Object { + + @JsonKey(name: 'SubjectDetails') + List subjectDetails; + + @JsonKey(name: 'ExamStudentId') + String examStudentId; + + @JsonKey(name: 'ExamNo') + String examNo; + + @JsonKey(name: 'Name') + String name; + + @JsonKey(name: 'ClassName') + String className; + + @JsonKey(name: 'TotalScore') + double totalScore; + + @JsonKey(name: 'TotalRanking') + int totalRanking; + + @JsonKey(name: 'TotalRankingChange') + String totalRankingChange; + + @JsonKey(name: 'TotalGradeRanking') + int totalGradeRanking; + + @JsonKey(name: 'TotalClassRanking') + int totalClassRanking; + + Data(this.subjectDetails,this.examStudentId,this.examNo,this.name,this.className,this.totalScore,this.totalRanking,this.totalRankingChange,this.totalGradeRanking,this.totalClassRanking,); + + factory Data.fromJson(Map srcJson) => _$DataFromJson(srcJson); + + Map toJson() => _$DataToJson(this); + +} + + +@JsonSerializable() +class SubjectDetails extends Object { + + @JsonKey(name: 'Score') + String score; + + @JsonKey(name: 'ExamSubjectId') + int examSubjectId; + + @JsonKey(name: 'GradeRanking') + String gradeRanking; + + @JsonKey(name: 'ClassRanking') + String classRanking; + + SubjectDetails(this.score,this.examSubjectId,this.gradeRanking,this.classRanking,); + + factory SubjectDetails.fromJson(Map srcJson) => _$SubjectDetailsFromJson(srcJson); + + Map toJson() => _$SubjectDetailsToJson(this); + +} + + diff --git a/marking_app/lib/common/model/report/report_card_params.dart b/marking_app/lib/common/model/report/report_card_params.dart new file mode 100644 index 0000000..fcba487 --- /dev/null +++ b/marking_app/lib/common/model/report/report_card_params.dart @@ -0,0 +1,24 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:marking_app/common/model/common/base_page_report.dart'; + +part 'report_card_params.g.dart'; + + +@JsonSerializable() +class ReportCardParams extends BasePageReport { + + @JsonKey(name: 'ExamId') + int examId; + + @JsonKey(name: 'ClassId') + int classId; + + ReportCardParams({required this.examId,required this.classId,page,limit}):super(page,limit); + + factory ReportCardParams.fromJson(Map srcJson) => _$ReportCardParamsFromJson(srcJson); + + Map toJson() => _$ReportCardParamsToJson(this); + +} + + diff --git a/marking_app/lib/common/model/report/report_marking_detail.dart b/marking_app/lib/common/model/report/report_marking_detail.dart new file mode 100644 index 0000000..6786c1f --- /dev/null +++ b/marking_app/lib/common/model/report/report_marking_detail.dart @@ -0,0 +1,122 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'report_marking_detail.g.dart'; + + +@JsonSerializable() +class ReportMarkingDetail extends Object { + + @JsonKey(name: 'MarkingPagerImgs') + List markingPagerImgs; + + @JsonKey(name: 'ExamOriginPapers') + List examOriginPapers; + + @JsonKey(name: 'QuestionAnswers') + List questionAnswers; + + ReportMarkingDetail(this.markingPagerImgs,this.examOriginPapers,this.questionAnswers,); + + factory ReportMarkingDetail.fromJson(Map srcJson) => _$ReportMarkingDetailFromJson(srcJson); + + Map toJson() => _$ReportMarkingDetailToJson(this); + +} + + +@JsonSerializable() +class ExamOriginPapers extends Object { + + @JsonKey(name: 'PageIndex') + int pageIndex; + + @JsonKey(name: 'ImageUrl') + String imageUrl; + + @JsonKey(name: 'Width') + double width; + + @JsonKey(name: 'Height') + double height; + + @JsonKey(name: 'PaperType') + int paperType; + + @JsonKey(name: 'Question') + List question; + + ExamOriginPapers(this.pageIndex,this.imageUrl,this.width,this.height,this.paperType,this.question,); + + factory ExamOriginPapers.fromJson(Map srcJson) => _$ExamOriginPapersFromJson(srcJson); + + Map toJson() => _$ExamOriginPapersToJson(this); + +} + + +@JsonSerializable() +class Question extends Object { + + @JsonKey(name: 'QuestionNum') + String questionNum; + + @JsonKey(name: 'isObj') + bool isObj; + + @JsonKey(name: 'X') + double x; + + @JsonKey(name: 'Y') + double y; + + @JsonKey(name: 'Width') + double width; + + @JsonKey(name: 'Height') + double height; + + @JsonKey(name: 'score') + double score; + + @JsonKey(name: 'totalScore') + double totalScore; + + Question(this.questionNum,this.isObj,this.x,this.y,this.width,this.height,this.score,this.totalScore,); + + factory Question.fromJson(Map srcJson) => _$QuestionFromJson(srcJson); + + Map toJson() => _$QuestionToJson(this); + +} + + +@JsonSerializable() +class QuestionAnswers extends Object { + + @JsonKey(name: 'QuestionNum') + String questionNum; + + @JsonKey(name: 'Answer') + String answer; + + @JsonKey(name: 'YourAnswer') + String yourAnswer; + + @JsonKey(name: 'AnswerType') + int answerType; + + @JsonKey(name: 'TotalScore') + double totalScore; + + @JsonKey(name: 'Score') + double score; + + QuestionAnswers(this.questionNum,this.answer,this.yourAnswer,this.answerType,this.totalScore,this.score,); + + factory QuestionAnswers.fromJson(Map srcJson) => _$QuestionAnswersFromJson(srcJson); + + Map toJson() => _$QuestionAnswersToJson(this); + +} + + diff --git a/marking_app/lib/common/model/report/report_marking_detail_params.dart b/marking_app/lib/common/model/report/report_marking_detail_params.dart new file mode 100644 index 0000000..782e9f1 --- /dev/null +++ b/marking_app/lib/common/model/report/report_marking_detail_params.dart @@ -0,0 +1,23 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'report_marking_detail_params.g.dart'; + + +@JsonSerializable() +class ReportMarkingDetailParams extends Object { + + @JsonKey(name: 'ExamSubjectId') + int examSubjectId; + + @JsonKey(name: 'StudentExamNum') + String studentExamNum; + + ReportMarkingDetailParams(this.examSubjectId,this.studentExamNum,); + + factory ReportMarkingDetailParams.fromJson(Map srcJson) => _$ReportMarkingDetailParamsFromJson(srcJson); + + Map toJson() => _$ReportMarkingDetailParamsToJson(this); + +} + + diff --git a/marking_app/lib/pages/report_detail/index.dart b/marking_app/lib/pages/report_detail/index.dart new file mode 100644 index 0000000..e74f68b --- /dev/null +++ b/marking_app/lib/pages/report_detail/index.dart @@ -0,0 +1,651 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:marking_app/common/mixin/common.dart'; +import 'package:marking_app/common/model/common/base_structure_result_report.dart'; +import 'package:marking_app/common/model/report/detail_base_info.dart'; +import 'package:marking_app/common/model/report/exam_records_all.dart'; +import 'package:marking_app/common/model/report/question_know_point.dart'; +import 'package:marking_app/common/model/report/report_card.dart'; +import 'package:marking_app/common/model/report/report_card_params.dart'; +import 'package:marking_app/pages/report_detail/widgets/basic_table.dart'; +import 'package:marking_app/pages/report_detail/widgets/card_table.dart'; +import 'package:marking_app/pages/report_detail/widgets/know_point_list.dart'; +import 'package:marking_app/pages/report_detail/widgets/lab_title.dart'; +import 'package:marking_app/pages/report_detail/widgets/no_data.dart'; +import 'package:marking_app/pages/report_detail/widgets/overall_level_table.dart'; +import 'package:marking_app/pages/report_detail/widgets/report_card_dialog.dart'; +import 'package:marking_app/pages/report_detail/widgets/question_table.dart'; +import 'package:marking_app/utils/request/rest_client_report.dart'; + +class ReportDetail extends StatefulHookConsumerWidget { + final int examId; + final bool showGrade; + + const ReportDetail({Key? key, required this.examId, required this.showGrade}) + : super(key: key); + + @override + _ReportDetailState createState() => _ReportDetailState(); +} + +class _ReportDetailState extends ConsumerState with CommonMixin { + bool isGrade = true; + bool isHasData = false; + + BaseInfo? baseInfo; + BaseStructureResultReport? overallLevelRes; + BaseStructureResultReport? questionKnowPointRes; + List subjectList = []; //科目 + List classList = []; //班级 + ComboData currentSubject = ComboData('', ''); + ComboData currentClass = ComboData('', ''); + bool isClass = false; + + // List cardHeadList = ['序号', '考号', '姓名', '班级', '分数', '班次', '校次']; + List cardHeadList = []; //成绩单表头 + List cardBodyList = []; //成绩单表格 + int currentPage = 1; //成绩单当前页 + int pageSize = 10; //成绩单当前页面请求数量 + int totalPage = 1; //成绩单总页数 + bool isRefresh = true; //防止请求未返回多次点击 + List initialList = []; + + void initState() { + super.initState(); + EasyLoading.show(status: 'loading...'); + getClass(); + } + + void getClass() async { + RestClientReport clientReport = await getClientReport(); + BaseStructureResultReport> res = + await clientReport.getClassList(widget.examId); + + BaseStructureResultReport> subjecData = + await clientReport.getExamsubject(widget.examId); + + setState(() { + classList = res.data!; + classList[0].isCheck = true; + currentClass = classList[0]; + + subjectList = subjecData.data!; + subjectList[0].isCheck = true; + currentSubject = subjectList[0]; + }); + getData(); + } + + void getData() { + getBaseInfo(); + getQuestionKnowPointTable(); + getCard(); + EasyLoading.dismiss(); + } + + //基础信息,总体水平,重点关注 + void getBaseInfo() async { + RestClientReport clientReport = await getClientReport(); + BaseStructureResultReport result = + await clientReport.getReportDetail(widget.examId, + widget.showGrade && isGrade ? -1 : currentClass.value); + setState(() { + overallLevelRes = result; + if (result!.data != null) { + baseInfo = result!.data!.baseInfo; + } + }); + } + + //小题得分,知识点 + void getQuestionKnowPointTable() async { + RestClientReport clientReport = await getClientReport(); + BaseStructureResultReport res = + await clientReport.getQuestionKnowPoint( + widget.examId, currentClass.value, currentSubject.value); + setState(() { + questionKnowPointRes = res; + print( + "%%%%%%%%%%%%%%%%%%%widget.examId=${widget.examId}¤tClass.value=${currentClass.value}¤tSubject.value=${currentSubject.value}"); + }); + EasyLoading.dismiss(); + } + + void getCard() async { + RestClientReport clientReport = await getClientReport(); + + ReportCardParams params = ReportCardParams( + examId: widget.examId, + classId: widget.showGrade && isGrade ? -1 : currentClass.value, + page: currentPage, + limit: pageSize); + BaseStructureResultReport result = + await clientReport.getReportCard(params); + print( + "#######${params.examId}¶ms.classId=${params.classId}¶ms.page=${params.page}¶ms.limit=${params.limit}"); + List head = result.data!.head; + head.removeAt(0); + List beforeList = ['序号', '考号', '姓名', '班级', '分数', '班次', '校次']; + beforeList.addAll(head); + cardHeadList = beforeList; + List bodylist = []; + initialList = result.data!.data; + result.data!.data.forEach((item) { + List arr = [ + item.examNo, + item.examStudentId, + item.name, + item.className, + item.totalScore.toString(), + item.totalClassRanking.toString(), + item.totalRanking.toString() + ]; + item.subjectDetails.forEach((subject) { + arr.add(subject.score); + }); + bodylist.add(arr); + }); + totalPage = (result.data!.totalCount / pageSize).ceil(); + setState(() { + cardBodyList = []; + cardBodyList = bodylist; + isRefresh = true; + }); + EasyLoading.dismiss(); + } + +//成绩单详情 + void showAlertDialog(BuildContext context, int index) { + List detailHead = []; + detailHead.addAll(cardHeadList.slice(5)); + detailHead.insert(0, '总分'); + + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + insetPadding: EdgeInsets.all(25.r), + content: ReportCardDialog(initialList[index], detailHead), + contentPadding: EdgeInsets.all(0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(15.r)))); + }, + ); + } + + void refreshData(item, bl) { + setState(() { + isClass = bl; + if (isClass) { + currentClass = item; + // getBaseInfo(); + } else { + currentSubject = item; + } + }); + getData(); + // getQuestionKnowPointTable(); + } + + void showSubjectDialog( + BuildContext context, List list, bool isclass) { + showModalBottomSheet( + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10.r))), + builder: (BuildContext context) { + return StatefulBuilder(builder: (context, setDialogState) { + return Container( + padding: EdgeInsets.only(top: 20.r), + height: list.length * 100.r, + constraints: BoxConstraints(maxHeight: 300.r), + child: ListView.builder( + itemBuilder: (BuildContext context, int index) { + var item = list?[index]; + return InkWell( + onTap: () { + setDialogState(() { + list.forEach((element) { + element.isCheck = false; + }); + item!.isCheck = true; + }); + EasyLoading.show(status: 'loading...'); + refreshData(item, isclass); + Navigator.pop(context); + }, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 10.r), + child: Center( + child: Text( + item!.text, + style: TextStyle( + fontSize: 14.r, + color: item.isCheck + ? Color(0xFF5F81FD) + : Color(0xFF2E2E2E)), + ))), + ); + }, + itemCount: list.length, + ), + ); + }); + }); + } + + @override + Widget build(BuildContext context) { + if (baseInfo == null || overallLevelRes == null) { + return Container(); + } + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.dark, + statusBarIconBrightness: Brightness.light, + ), + child: Container( + color: Color(0xFFF8F9FF), + child: Column( + children: [ + Padding( + padding: EdgeInsets.only( + top: MediaQuery.of(context).padding.top + 20.h, + bottom: 20.r), + child: Stack( + alignment: const FractionalOffset(0.04, 0.1), + children: [ + Container( + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + baseInfo!.examName, + style: TextStyle( + fontSize: 16.sp, color: Color(0xFF2D384C)), + ), + ], + ), + ), + InkWell( + onTap: () => Navigator.pop(context), + child: Icon(Icons.arrow_back_ios_new_rounded, + color: Color(0xFF505767), size: 24.sp), + ), + ], + ), + ), + if (widget.showGrade) + Container( + margin: + EdgeInsets.only(left: 20.r, right: 20.r, bottom: 10.r), + width: MediaQuery.of(context).size.width - 40.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20.r), + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Color(0x566787FD), + offset: Offset(1.0, 1.0), //阴影xy轴偏移量 + blurRadius: 10.0, //阴影模糊程度 + spreadRadius: 0.1, //阴影扩散程度 + ) + ]), + child: Flex( + direction: Axis.horizontal, + children: [ + Expanded( + flex: 1, + child: InkWell( + onTap: () { + setState(() { + isGrade = true; + }); + EasyLoading.show(status: 'loading...'); + getData(); + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 10.r), + decoration: BoxDecoration( + color: isGrade ? Color(0xFF6787FD) : Colors.white, + borderRadius: BorderRadius.circular(20.r), + ), + child: Center( + child: Text( + '年级', + style: TextStyle( + fontSize: 14.sp, + color: isGrade ? Colors.white : Colors.black), + )), + ), + ), + ), + Expanded( + flex: 1, + child: InkWell( + onTap: () { + setState(() { + isGrade = false; + }); + EasyLoading.show(status: 'loading...'); + getData(); + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 10.r), + decoration: BoxDecoration( + color: + !isGrade ? Color(0xFF6787FD) : Colors.white, + borderRadius: BorderRadius.circular(20.r), + ), + child: Center( + child: Text( + '班级', + style: TextStyle( + fontSize: 14.sp, + color: + !isGrade ? Colors.white : Colors.black), + ), + ), + ), + ), + ), + // Text('99'), + ], + ), + ), + //基本信息 + Expanded( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (!widget.showGrade || !isGrade) + Padding( + padding: EdgeInsets.only(left: 16.r), + child: Row( + children: [ + Text( + '班级:', + style: TextStyle( + fontSize: 14.sp, color: Color(0xFF474747)), + ), + InkWell( + onTap: () { + showSubjectDialog(context, classList, true); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 3.r, horizontal: 30.r), + decoration: BoxDecoration( + color: Color.fromRGBO(197, 223, 255, 0.31), + border: Border.all( + width: 1.r, color: Color(0xFFC0DCFF)), + borderRadius: + BorderRadius.all(Radius.circular(20.r)), + ), + child: Text( + currentClass.text, + style: TextStyle( + fontSize: 14.r, + color: Color(0xFF6787FD), + fontWeight: FontWeight.w500), + ), + ), + ) + ], + ), + ), + LabTitle('基本信息', 'assets/images/basic_info.png'), + BasicTable(baseInfo), + LabTitle('总体水平', 'assets/images/overall_level.png'), + OverallLevelTable( + overallLevelRes!.data!.module1CJZL.sheets[0]), + LabTitle('重点关注学生', 'assets/images/reports_focus.png'), + OverallLevelTable(overallLevelRes! + .data!.module2ZDGZ.topExcelData.sheets[0]), + SizedBox( + height: 20.r, + ), + OverallLevelTable(overallLevelRes! + .data!.module2ZDGZ.bottomExcelData.sheets[0]), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + LabTitle('小题得分', 'assets/images/reports_score.png'), + Container( + padding: EdgeInsets.symmetric( + vertical: 2.r, horizontal: 10.r), + margin: EdgeInsets.only(right: 14.r), + decoration: BoxDecoration( + color: Color(0xFF6787FD), + borderRadius: + BorderRadius.all(Radius.circular(15.r)), + ), + child: InkWell( + onTap: () { + showSubjectDialog(context, subjectList, false); + }, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + currentSubject.text, + style: TextStyle( + fontSize: 14.sp, + color: Colors.white, + fontWeight: FontWeight.w500), + ), + Padding( + padding: EdgeInsets.only(left: 8.r), + child: Image.asset( + 'assets/images/right_icon.png', + width: 6.r, + height: 10.r, + ), + ) + ], + ), + ), + ) + ], + ), + if (questionKnowPointRes != null) + Container( + // color: Colors.white, + margin: EdgeInsets.symmetric(horizontal: 14.r), + padding: EdgeInsets.only(bottom: 10.r, top: 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + (questionKnowPointRes!.data!.userQuestion + .sheets[0].headData.length > + 0 && + questionKnowPointRes!.data!.userQuestion + .sheets[0].bodyData.length > + 0) + ? SizedBox( + height: questionKnowPointRes! + .data! + .userQuestion + .sheets[0] + .bodyData + .length > + 10 + ? 300.r + : questionKnowPointRes! + .data! + .userQuestion + .sheets[0] + .bodyData + .length * + 30.r, + // width: MediaQuery.of(context).size.width, + child: CardList( + headList: questionKnowPointRes!.data! + .userQuestion.sheets[0].headData, + bodyList: questionKnowPointRes!.data! + .userQuestion.sheets[0].bodyData, + isScore: true, + fixedRows: 1, + fixedCols: 3, + ), + + /*QuestionTable( + headList: questionKnowPointRes!.data! + .userQuestion.sheets[0].headData, + bodyList: questionKnowPointRes!.data! + .userQuestion.sheets[0].bodyData, + ),*/ + ) + : NoData(), + Padding( + padding: EdgeInsets.symmetric( + vertical: 10.r, horizontal: 10.r), + child: Text( + '知识点分析', + style: TextStyle( + fontSize: 16.sp, + color: Color(0xFF2D384C), + fontWeight: FontWeight.w500), + ), + ), + questionKnowPointRes!.data!.knowPointList.length > + 0 + ? SizedBox( + height: 300.r, + child: KnowPointTable( + questionKnowPointRes! + .data!.knowPointList), + ) + : NoData(), + /* questionKnowPointRes!.data!.knowPointList.length > + 0 + ? KnowPointTable( + questionKnowPointRes!.data!.knowPointList) + : NoData(),*/ + ], + ), + ), + LabTitle('成绩单', 'assets/images/reports_card.png'), + if (cardBodyList.length > 0) + Container( + // width: MediaQuery.of(context).size.width, + height: 330.r, + margin: EdgeInsets.symmetric(horizontal: 14.r), + child: CardList( + headList: cardHeadList, + bodyList: cardBodyList, + showCardDetail: showAlertDialog, + fixedRows: 1, + fixedCols: 3, + ), + ), + if (cardBodyList.length > 0) + Padding( + padding: EdgeInsets.only(right: 14.r,top: 6.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + InkWell( + onTap: () { + setState(() { + if (currentPage > 1 && isRefresh) { + isRefresh = false; + currentPage = currentPage - 1; + getCard(); + EasyLoading.show(status: 'loading...'); + } + }); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 2.r, horizontal: 5.r), + decoration: BoxDecoration( + border: Border.all( + color: currentPage == 1 + ? Color(0xFFB3B9B9) + : Color(0xFF6787FD), + width: 1.r), + borderRadius: BorderRadius.all( + Radius.circular(2.r)), + ), + child: Text( + '上一页', + style: TextStyle( + color: currentPage == 1 + ? Color(0xFFB3B9B9) + : Color(0xFF6787FD)), + ), + ) + + /*Icon(Icons.keyboard_arrow_left, + color: currentPage == 1 + ? Color(0xFFB3B9B9) + : Color(0xFF505767), + size: 24.sp),*/ + ), + SizedBox( + width: 15.r, + ), + InkWell( + onTap: () { + setState(() { + if (currentPage < totalPage && + isRefresh) { + isRefresh = false; + currentPage = currentPage + 1; + getCard(); + EasyLoading.show(status: 'loading...'); + } + }); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 2.r, horizontal: 5.r), + decoration: BoxDecoration( + border: Border.all( + color: totalPage - currentPage > 0 + ? Color(0xFF6787FD) + : Color(0xFFB3B9B9), + width: 1.r), + borderRadius: BorderRadius.all( + Radius.circular(2.r)), + ), + child: Text( + '下一页', + style: TextStyle( + color: totalPage - currentPage > 0 + ? Color(0xFF6787FD) + : Color(0xFFB3B9B9)), + ), + ) + /*Icon(Icons.keyboard_arrow_right, + color: totalPage - currentPage > 0 + ? Color(0xFF505767) + : Color(0xFFB3B9B9), + size: 24.sp),*/ + ) + ], + ), + ), + if (cardBodyList.length == 0) NoData(), + SizedBox( + height: 20.r, + ), + ], + ), + ), + ), + ], + ), + )); + } +} diff --git a/marking_app/lib/pages/report_detail/widgets/basic_table.dart b/marking_app/lib/pages/report_detail/widgets/basic_table.dart new file mode 100644 index 0000000..0a0b6b1 --- /dev/null +++ b/marking_app/lib/pages/report_detail/widgets/basic_table.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:marking_app/common/model/report/detail_base_info.dart'; +import 'package:marking_app/pages/report_detail/widgets/basic_tablecell.dart'; + +class BasicTable extends StatelessWidget { + final BaseInfo? baseInfo; + + const BasicTable(this.baseInfo, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.symmetric(horizontal: 14.r), + padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 10.r), + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + color: Colors.white, borderRadius: BorderRadius.circular(5.r)), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + decoration: BoxDecoration( + // color: Color(0xFFF5F7FF), + border: Border( + bottom: BorderSide(width: 1, color: Color(0xFFE8EBFF)), + ) + ), + child: IntrinsicHeight( + child: Row( + children: [ + Expanded(flex: 1, child: BasicTableCell('考试名称', false)), + Expanded(flex: 1, child: BasicTableCell(baseInfo!.examName, true)), + Expanded(flex: 1, child: BasicTableCell('考试类型', false)), + Expanded(flex: 1, child: BasicTableCell(baseInfo!.examType, true)), + ], + ), + ), + ), + Container( + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1, color: Color(0xFFE8EBFF))) + ), + child: IntrinsicHeight( + child: Row( + children: [ + Expanded(flex: 1, child: BasicTableCell('年级', false)), + Expanded(flex: 1, child: BasicTableCell(baseInfo!.grade, true)), + Expanded(flex: 1, child: BasicTableCell('学科', false)), + Expanded(flex: 1, child: BasicTableCell(baseInfo!.subject, true)), + ], + ), + ), + ), + Container( + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1, color: Color(0xFFE8EBFF))) + ), + child: IntrinsicHeight( + child: Row( + children: [ + Expanded(flex: 1, child: BasicTableCell('考试日期', false)), + Expanded(flex: 1, child: BasicTableCell(baseInfo!.examTime, true)), + Expanded(flex: 1, child: BasicTableCell('满分', false)), + Expanded(flex: 1, child: BasicTableCell(baseInfo!.totalScore.toString(), true)), + ], + ), + ), + ), + Container( + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1, color: Color(0xFFE8EBFF))) + ), + child: IntrinsicHeight( + child: Row( + children: [ + Expanded(flex: 1, child: BasicTableCell('平均分', false)), + Expanded(flex: 1, child: BasicTableCell(baseInfo!.avgScore.toString(), true)), + Expanded(flex: 1, child: BasicTableCell('最高分', false)), + Expanded(flex: 1, child: BasicTableCell(baseInfo!.maxScore.toString(), true)), + ], + ), + ), + ), + Container( + decoration: BoxDecoration( + border: Border(bottom: BorderSide(width: 1, color: Color(0xFFE8EBFF))) + ), + child: IntrinsicHeight( + child: Row( + children: [ + Expanded(flex: 1, child: BasicTableCell('优秀率', false)), + Expanded(flex: 1, child: BasicTableCell(baseInfo!.rateGood, true)), + Expanded(flex: 1, child: BasicTableCell('及格率', false)), + Expanded(flex: 1, child: BasicTableCell(baseInfo!.ratePass, true)), + ], + ), + ), + ) + ], + ), + ); + } +} diff --git a/marking_app/lib/pages/report_detail/widgets/basic_tablecell.dart b/marking_app/lib/pages/report_detail/widgets/basic_tablecell.dart new file mode 100644 index 0000000..ab7457e --- /dev/null +++ b/marking_app/lib/pages/report_detail/widgets/basic_tablecell.dart @@ -0,0 +1,22 @@ +//基本信息表格单元格 +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; + +class BasicTableCell extends StatelessWidget { + final String content; + final bool isBold; + const BasicTableCell(this.content,this.isBold,{Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + height: double.infinity, + padding: EdgeInsets.symmetric(vertical:6.r,horizontal: 8.r), + decoration: BoxDecoration( + color: isBold?Colors.white:Color(0xFFF5F7FF), + ), + child: Text(content,style: TextStyle(fontSize: 12.sp,color: isBold?Colors.black:Color(0xFF505767),fontWeight: isBold?FontWeight.w500:FontWeight.w400),) + ); + } +} \ No newline at end of file diff --git a/marking_app/lib/pages/report_detail/widgets/card_table.dart b/marking_app/lib/pages/report_detail/widgets/card_table.dart new file mode 100644 index 0000000..6d512d7 --- /dev/null +++ b/marking_app/lib/pages/report_detail/widgets/card_table.dart @@ -0,0 +1,137 @@ +import 'package:data_table_2/data_table_2.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class CardList extends StatefulWidget { + final List headList; + final List bodyList; + final Function? showCardDetail; + final bool? isScore; + final int? fixedRows; + final int? fixedCols; + + const CardList({ + Key? key, + required this.headList, + required this.bodyList, + this.showCardDetail, + this.isScore = false, + this.fixedCols, + this.fixedRows, + }) : super(key: key); + + @override + State createState() => _CardListState(); +} + +class _CardListState extends State { + final ScrollController _controller = ScrollController(); + int? _sortColumnIndex; + bool _sortAscending = true; + + DataRow _getRow(int index, [Color? color]) { + assert(index >= 0); + var body = widget.bodyList[index]; + return DataRow2.byIndex( + index: index, + color: color != null ? MaterialStateProperty.all(color) : null, + cells: List.generate(widget.headList.length, (itemIndex) { + var item = body[itemIndex]; + return + itemIndex == 0 && widget.isScore == false ?DataCell(Center( + child: Text((index + 1).toString(), + style: + TextStyle(fontSize: 12.sp, color: Color(0xFF262626))), + )): + DataCell(itemIndex == 2 && widget.isScore == false + ? InkWell( + onTap: () { + if (widget.showCardDetail != null) { + widget.showCardDetail!(context, index); + } + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Expanded( + child: Center( + child: Text(item.toString(), + style: TextStyle( + fontSize: 12.sp, color: Color(0xFF262626))), + ), + ), + Padding( + padding: EdgeInsets.only(right: 5.r), + child: Image.asset( + 'assets/images/search_icon.png', + width: 14.r, + height: 14.r, + ), + ), + ], + ), + ) + : Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text(item.toString(), + style: + TextStyle(fontSize: 12.sp, color: Color(0xFF262626))), + ), + )); + }), + ); + } + + @override + Widget build(BuildContext context) { + return DataTable2( + dividerThickness: 0, + scrollController: _controller, + columnSpacing: 0, + horizontalMargin: 0, + dataRowHeight:50.r, + bottomMargin: 0, + border: TableBorder( + horizontalInside: BorderSide( + width: 1, color: Color(0xFFE0E5FF), style: BorderStyle.solid), + bottom: BorderSide( + width: 1, color: Color(0xFFE0E5FF), style: BorderStyle.solid), + verticalInside: BorderSide( + width: 1, color: Color(0xFFE0E5FF), style: BorderStyle.solid)), + headingRowColor: MaterialStateProperty.resolveWith((states) => + widget.fixedCols! > 0 ? Color(0xFFF0F3FF) : Colors.transparent), + /* headingRowDecoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Colors.grey[400]!, + Colors.grey[200]!, + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ),*/ + headingRowDecoration: BoxDecoration(color: Color(0xFFF0F3FF)), + fixedColumnsColor: Color(0xFFF0F3FF), + fixedCornerColor: Colors.grey[400], + minWidth: 70.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(widget.isScore == true ? item.rowData[0][0] : item, + style: TextStyle(fontSize: 12.sp, color: Color(0xFF505767))), + ), + // size: ColumnSize.S, + fixedWidth: index == 0 && widget.isScore == false?50.r:70.r, + ); + }), + rows: List.generate(widget.bodyList.length, + (index) => _getRow(index, Colors.transparent))); + } +} diff --git a/marking_app/lib/pages/report_detail/widgets/custom_rect.dart b/marking_app/lib/pages/report_detail/widgets/custom_rect.dart new file mode 100644 index 0000000..8e6f3c8 --- /dev/null +++ b/marking_app/lib/pages/report_detail/widgets/custom_rect.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:marking_app/common/model/report/report_marking_detail.dart'; + +class CustomRect extends StatefulWidget { + ExamOriginPapers examOriginItem; + + CustomRect(this.examOriginItem, {Key? key}) : super(key: key); + + @override + _CustomRectState createState() => _CustomRectState(); +} + +class _CustomRectState extends State { + @override + Widget build(BuildContext context) { + return Container( + width: widget.examOriginItem.width, + height: widget.examOriginItem.height, + decoration: BoxDecoration( + image: DecorationImage( + image: NetworkImage(widget.examOriginItem.imageUrl), + fit: BoxFit.cover, + )), + child: CustomPaint( + size: + Size(widget.examOriginItem.width, widget.examOriginItem.height), + painter: MyPainter(widget.examOriginItem.question), + child: Stack( + children: List.generate(widget.examOriginItem.question.length, (index) { + var item = widget.examOriginItem.question[index]; + return Positioned( + left: item.x + item.width - 50, + top: item.y, + child: Row( + children: [ + Text(item.score.toInt().toString(),style: TextStyle(fontSize: 12.sp,color: Colors.red),), + Text('/',style: TextStyle(fontSize: 12.sp,color: Colors.red),), + Text(item.totalScore.toInt().toString(),style: TextStyle(fontSize: 12.sp,color: Colors.red),), + ], + )); + }), + ), + ), + ); + } +} + +///[定义画笔] +Paint _paint = Paint() + ..color = Colors.red //画笔颜色 + ..strokeCap = StrokeCap.round //画笔笔触类型 + ..isAntiAlias = true //是否启动抗锯齿 + ..style = PaintingStyle.stroke //绘画风格,默认为填充 + ..strokeWidth = 3.0; //画笔的宽度 + +class MyPainter extends CustomPainter { + final List questions; + + MyPainter(this.questions); + + + @override + void paint(Canvas canvas, Size size) { + questions.forEach((item) { + Rect rect = Rect.fromLTWH(item.x,item.y + ,item.width, item.height); + //根据上面的矩形,构建一个圆角矩形 + RRect rrect = RRect.fromRectAndRadius(rect, Radius.circular(0.0)); + + canvas.drawRRect(rrect, _paint); + }); + + /* Rect rect1 = Rect.fromCenter(center: Offset(140.0, 491.0), width: 91.0,height: 35.0); + //根据上面的矩形,构建一个圆角矩形 + RRect rrect1 = RRect.fromRectAndRadius(rect1, Radius.circular(0.0)); + canvas.drawRRect(rrect1, _paint);*/ + /* Rect rect2 = Rect.fromLTWH( 209.0, 549.0, 449.0,210.0); + //根据上面的矩形,构建一个圆角矩形 + RRect rrect2 = RRect.fromRectAndRadius(rect2, Radius.circular(0.0)); + canvas.drawRRect(rrect2, _paint);*/ + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + + return true; + } +} diff --git a/marking_app/lib/pages/report_detail/widgets/know_point_list.dart b/marking_app/lib/pages/report_detail/widgets/know_point_list.dart new file mode 100644 index 0000000..2514251 --- /dev/null +++ b/marking_app/lib/pages/report_detail/widgets/know_point_list.dart @@ -0,0 +1,127 @@ +import 'package:data_table_2/data_table_2.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:marking_app/common/model/report/question_know_point.dart'; + +class KnowPointTable extends StatefulWidget { + final List knowPointList; + + KnowPointTable(this.knowPointList, {Key? key}) : super(key: key); + + @override + State createState() => _KnowPointTableState(); +} + +class _KnowPointTableState extends State { + List headList = ['题号', '知识点', '正确率', '得分率']; + + DataRow _getRow(int index, [Color? color]) { + assert(index >= 0); + var bodyItem = widget.knowPointList[index]; + return DataRow2.byIndex( + index: index, + color: color != null ? MaterialStateProperty.all(color) : null, + cells:[ + DataCell(Center( + child: Container( + padding: EdgeInsets.symmetric( + vertical: 6.r, horizontal: 5.r), + child: Text( + bodyItem.questionNums, + style: TextStyle( + fontSize: 12.sp, color: Color(0xFF262626)), + ), + ), + ),), + DataCell(Container( + padding: EdgeInsets.symmetric( + vertical: 6.r, horizontal: 5.r), + child: Text( + bodyItem.name, + style: TextStyle( + fontSize: 12.sp, color: Color(0xFF262626)), + ), + ),), + DataCell(Center( + child: Container( + padding: EdgeInsets.symmetric( + vertical: 6.r, horizontal: 5.r), + child: Text( + bodyItem.correctRate, + style: TextStyle( + fontSize: 12.sp, color: Color(0xFF262626)), + ), + ), + ),), + DataCell( Center( + child: Container( + padding: EdgeInsets.symmetric( + vertical: 6.r, horizontal: 5.r), + child: Text( + bodyItem.gradeCorrectRate, + style: TextStyle( + fontSize: 12.sp, color: Color(0xFF262626)), + ), + ), + ),), + ], + ); + } + + @override + Widget build(BuildContext context) { + int fixedRows = 1; + int fixedCols = 0; + final ScrollController _controller = ScrollController(); + int? _sortColumnIndex; + bool _sortAscending = true; + + return DataTable2( + dividerThickness: 0, + scrollController: _controller, + columnSpacing: 0, + horizontalMargin: 0, + bottomMargin: 0, + border: TableBorder( + horizontalInside: BorderSide( + width: 1, color: Color(0xFFE0E5FF), style: BorderStyle.solid), + bottom: BorderSide( + width: 1, color: Color(0xFFE0E5FF), style: BorderStyle.solid), + verticalInside: BorderSide( + width: 1, color: Color(0xFFE0E5FF), style: BorderStyle.solid)), + headingRowColor: MaterialStateProperty.resolveWith((states) => + fixedCols > 0 ? Color(0xFFF0F3FF) : Colors.transparent), + /* headingRowDecoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Colors.grey[400]!, + Colors.grey[200]!, + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), + ),*/ + headingRowDecoration: BoxDecoration(color: Color(0xFFF0F3FF)), + fixedColumnsColor: Color(0xFFF0F3FF), + fixedCornerColor: Colors.grey[400], + // minWidth: 70.r * headList.length, + fixedTopRows: fixedRows, + fixedLeftColumns: fixedCols, + sortColumnIndex: _sortColumnIndex, + sortAscending: _sortAscending, + // onSelectAll: (val) => setState(() => selectAll(val)), + columns: List.generate(headList.length, (index) { + var item = headList[index]; + return DataColumn2( + label: Center( + child: Text(item, + style: TextStyle(fontSize: 12.sp, color: Color(0xFF505767))), + ), + // size: ColumnSize.S, + fixedWidth: index == 0?60.r:(MediaQuery.of(context).size.width - 90.r)/3, + ); + }), + rows: List.generate(widget.knowPointList.length, + (index) => _getRow(index, Colors.transparent))); + } +} diff --git a/marking_app/lib/pages/report_detail/widgets/lab_title.dart b/marking_app/lib/pages/report_detail/widgets/lab_title.dart new file mode 100644 index 0000000..8ed369c --- /dev/null +++ b/marking_app/lib/pages/report_detail/widgets/lab_title.dart @@ -0,0 +1,30 @@ +//基本信息、总体水平 +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class LabTitle extends StatelessWidget { + final String name; + final String img; + + const LabTitle(this.name, this.img, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only(left: 14.r,top: 15.r,bottom: 15.r), + child: Row( + children: [ + Image.asset( + img, + width: 23.r, + height: 23.r, + ), + Text( + name, + style: TextStyle(fontSize: 16.sp, color: Color(0xFF2D384C)), + ) + ], + ), + ); + } +} diff --git a/marking_app/lib/pages/report_detail/widgets/no_data.dart b/marking_app/lib/pages/report_detail/widgets/no_data.dart new file mode 100644 index 0000000..a8ddee3 --- /dev/null +++ b/marking_app/lib/pages/report_detail/widgets/no_data.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class NoData extends StatelessWidget { + const NoData({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Center(child: Text('-暂无数据-',style: TextStyle(fontSize: 14.sp,color: Color(0xFF505767)),)); + } +} diff --git a/marking_app/lib/pages/report_detail/widgets/overall_level_table.dart b/marking_app/lib/pages/report_detail/widgets/overall_level_table.dart new file mode 100644 index 0000000..5a584b0 --- /dev/null +++ b/marking_app/lib/pages/report_detail/widgets/overall_level_table.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; +import 'package:marking_app/common/model/report/detail_base_info.dart'; + +class OverallLevelTable extends StatelessWidget { + final Sheets? tableList; + final bool? hasPad; + const OverallLevelTable(this.tableList,{Key? key,this.hasPad = true}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only(left: hasPad == true?14.r:0,right: hasPad == true?14.r:0), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Table( + defaultVerticalAlignment: TableCellVerticalAlignment.middle, + + defaultColumnWidth: tableList!.headData.length<7?FixedColumnWidth((MediaQuery.of(context).size.width - 28.r) / tableList!.headData.length):IntrinsicColumnWidth(), + // defaultColumnWidth: IntrinsicColumnWidth(), + border: TableBorder(horizontalInside: BorderSide(width: 1, color: Color(0xFFE0E5FF), style: BorderStyle.solid), + bottom: BorderSide(width: 1, color: Color(0xFFE0E5FF), style: BorderStyle.solid), + verticalInside: BorderSide(width: 1, color: Color(0xFFE0E5FF), style: BorderStyle.solid)) + + /*TableBorder.symmetric( + inside: BorderSide(width: 1, color: Color(0xFFE0E5FF)), + // outside: BorderSide.none, + outside: hasPad == true?BorderSide.none:BorderSide(width: 1, color: Color(0xFFE0E5FF)), + )*/, + // borderRadius: BorderRadius.circular(5.r), + children: List.generate(tableList!.bodyData.length + 1, (bodyIndex) { + var bodyItem ; + if(bodyIndex > 0){ + bodyItem = tableList!.bodyData[bodyIndex - 1]; + } + return bodyIndex == 0? TableRow( + decoration: BoxDecoration( + color: Color(0xFFF0F3FF), + ), + children:List.generate(tableList!.headData.length, (index) { + var item = tableList!.headData[index]; + return Center( + child: Container( + padding: EdgeInsets.symmetric(vertical: 6.r,horizontal: 10.r), + child: Text( + item.rowData[0][0], + style: TextStyle( + fontSize: 12.sp, color: Color(0xFF505767)), + ), + ), + ); + }) + ):TableRow( + decoration: BoxDecoration( + color: Colors.white, + ), + children: List.generate(tableList!.headData.length, (cell){ + return Center( + child: Container( + padding: EdgeInsets.symmetric(vertical: 6.r,horizontal: 5.r), + child: cell == 0?Text( + bodyItem[cell].toString(), + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF262626)), + ):HtmlWidget(bodyItem[cell].toString(),textStyle: TextStyle(fontSize: 12.sp,color: Color(0xFF262626)),), + ), + ); + }) + ); + }) + ), + ), + ); + } +} diff --git a/marking_app/lib/pages/report_detail/widgets/question_table.dart b/marking_app/lib/pages/report_detail/widgets/question_table.dart new file mode 100644 index 0000000..e9694c5 --- /dev/null +++ b/marking_app/lib/pages/report_detail/widgets/question_table.dart @@ -0,0 +1,113 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:horizontal_data_table/horizontal_data_table.dart'; + + +class QuestionTable extends StatefulWidget { + final List headList; + final List bodyList; + const QuestionTable({ + Key? key, required this.headList, required this.bodyList, + }) : super(key: key); + + + @override + State createState() => _QuestionTableState(); +} + +class _QuestionTableState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return HorizontalDataTable( + leftHandSideColumnWidth: 100, + rightHandSideColumnWidth: (80.r * (widget.headList.length - 1)).toDouble(), + isFixedHeader: true, + headerWidgets: _getTitleWidget(), + isFixedFooter: false, + footerWidgets: _getTitleWidget(), + leftSideItemBuilder: _generateFirstColumnRow, + rightSideItemBuilder: _generateRightHandSideColumnRow, + itemCount:widget.bodyList.length, + rowSeparatorWidget: const Divider( + color: Color(0xFFE0E5FF), + height: 1.0, + thickness: 0.0, + ), + // leftHandSideColBackgroundColor: const Color(0xFFFFFFFF), + // rightHandSideColBackgroundColor: const Color(0xFFFFFFFF), + // itemExtent: 31.r, + ); + } + + List _getTitleWidget() { + return List.generate(widget.headList.length, (index){ + var item = widget.headList[index]; + return Container( + height: 30.r, + decoration: BoxDecoration( + color: Color(0xFFF0F3FF), + border:Border(right: BorderSide(width: 0.5.r,color: Color(0xFFE0E5FF))) + ), + width: index == 0?100.r:80.r, + child: Center( + child: Text(item.rowData[0][0],style: TextStyle( + fontSize: 12.sp, color: Color(0xFF505767))), + ),); + }); + } + + Widget _getTitleItemWidget(String label, double width) { + return Container( + width: width, + height: 56, + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Text(label, style: const TextStyle(fontWeight: FontWeight.bold)), + ); + } + + Widget _generateFirstColumnRow(BuildContext context, int index) { + var item = widget.bodyList[index][0]; + return Container( + width: 100.r, + height: 30.r, + decoration: BoxDecoration( + border:Border(right: BorderSide(width: 0.5.r,color: Color(0xFFE0E5FF))) + ), + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Center( + child: Text(item.toString(), style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF262626))), + ), + ); + } + + Widget _generateRightHandSideColumnRow(BuildContext context, int index) { + var bodyItem = widget.bodyList[index]; + return Row( + children: List.generate(widget.headList.length -1, (bodyIndex){ + return Container( + width: 80.r, + height: 30.r, + decoration: BoxDecoration( + border:Border(right: BorderSide(width: 0.5.r,color: Color(0xFFE0E5FF))) + ), + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Center( + child: Text(bodyItem[bodyIndex + 1].toString(), style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF262626))), + ), + ); + }), + ); + } +} \ No newline at end of file diff --git a/marking_app/lib/pages/report_detail/widgets/report_card_dialog.dart b/marking_app/lib/pages/report_detail/widgets/report_card_dialog.dart new file mode 100644 index 0000000..10bd671 --- /dev/null +++ b/marking_app/lib/pages/report_detail/widgets/report_card_dialog.dart @@ -0,0 +1,371 @@ +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:marking_app/common/mixin/common.dart'; +import 'package:marking_app/common/model/common/base_structure_result_report.dart'; +import 'package:marking_app/common/model/report/exam_records_all.dart'; +import 'package:marking_app/common/model/report/report_card.dart'; +import 'package:marking_app/common/model/report/report_marking_detail.dart'; +import 'package:marking_app/common/model/report/report_marking_detail_params.dart'; +import 'package:marking_app/pages/report_detail/widgets/custom_rect.dart'; +import 'package:marking_app/utils/easy_refresh/MyEmptyWidget.dart'; +import 'package:marking_app/utils/request/rest_client_report.dart'; + +class ReportCardDialog extends StatefulHookConsumerWidget { + final Data cardItem; + final List headList; + + const ReportCardDialog(this.cardItem, this.headList, {Key? key}) + : super(key: key); + + @override + _ReportCardDialogState createState() => _ReportCardDialogState(); +} + +class _ReportCardDialogState extends ConsumerState + with CommonMixin { + List subjectList = []; + ExamOriginPapers? examOrigin; + List examOriginList = []; + int currentSubjectId = 0; + + void initState() { + super.initState(); + List arr = widget.headList.slice(3); + arr.asMap().forEach((index, name) { + var subject = widget.cardItem.subjectDetails; + ComboData item = + ComboData(subject[index].examSubjectId, name, isCheck: false); + subjectList.add(item); + }); + subjectList[0].isCheck = true; + currentSubjectId = subjectList[0].value; + getImageDetail(); + } + + void getImageDetail() async { + RestClientReport clientReport = await getClientReport(); + ReportMarkingDetailParams params = + ReportMarkingDetailParams(currentSubjectId, widget.cardItem.examStudentId); + BaseStructureResultReport res = + await clientReport.getMarkingDetail(params); + + setState(() { + if(res.data!=null){ + examOrigin = res.data!.examOriginPapers[0]; + examOriginList = res.data!.examOriginPapers; + }else{ + examOriginList = []; + examOrigin = null; + } + }); + EasyLoading.dismiss(); + } + + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + child: Column(children: [ + Padding( + padding: EdgeInsets.only(top: 10.r, left: 20.r, right: 20.r), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.cardItem.name, + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF6787FD), + fontWeight: FontWeight.w500), + ), + InkWell( + onTap: (){ + Navigator.pop(context); + }, + child: Icon(Icons.close,color: Colors.grey,size: 20.r,)) + ], + ), + Container( + margin: EdgeInsets.only(top: 10.r), + width: double.infinity, + height: 30.r, + decoration: BoxDecoration( + color: Color(0xFFEFF1FF), + borderRadius: BorderRadius.all(Radius.circular(2.r))), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: List.generate( + widget.headList.length > 7 ? 7 : widget.headList.length, + (index) { + var item = widget.headList[index]; + return Container( + width: (MediaQuery.of(context).size.width - 90.r) / 7, + child: _subjectText(item)); + }), + ), + ), + Container( + width: double.infinity, + height: 30.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(2.r))), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + width: (MediaQuery.of(context).size.width - 90.r) / 7, + child: _subjectText( + widget.cardItem.totalScore.toString())), + Container( + width: (MediaQuery.of(context).size.width - 90.r) / 7, + child: _subjectText( + widget.cardItem.totalClassRanking.toString())), + Container( + width: (MediaQuery.of(context).size.width - 90.r) / 7, + child: _subjectText( + widget.cardItem.totalRanking.toString())), + SizedBox( + width: + (MediaQuery.of(context).size.width - 90.r) / 7 * 4, + child: Row( + children: List.generate( + widget.cardItem.subjectDetails.length > 4 + ? 4 + : widget.cardItem.subjectDetails.length, + (index) { + var subject = widget.cardItem.subjectDetails[index]; + return Container( + width: + (MediaQuery.of(context).size.width - 90.r) / + 7, + child: _subjectText(subject.score)); + }), + )), + ], + ), + ), + if (widget.headList.length > 7) + Container( + width: double.infinity, + height: 30.r, + decoration: BoxDecoration( + color: Color(0xFFEFF1FF), + borderRadius: BorderRadius.all(Radius.circular(2.r))), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: + List.generate(widget.headList.length - 7, (index) { + var item = widget.headList[index + 7]; + return Container( + width: (MediaQuery.of(context).size.width - 90.r) / 7, + child: _subjectText(item)); + }), + ), + ), + if (widget.headList.length > 7) + Container( + width: double.infinity, + height: 30.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(2.r))), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: List.generate( + widget.cardItem.subjectDetails.length - 4, (index) { + var subject = widget.cardItem.subjectDetails[index + 4]; + return Container( + width: (MediaQuery.of(context).size.width - 90.r) / 7, + child: _subjectText(subject.score)); + }), + ), + ), + ], + ), + ), + Expanded( + child: Container( + margin: EdgeInsets.only(top: 0.r), + padding: EdgeInsets.symmetric(vertical: 5.r, horizontal: 20.r), + width: double.infinity, + decoration: BoxDecoration( + color: Color(0xFFEFF1FF), + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(15.r), + bottomRight: Radius.circular(15.r))), + child: Column( + children: [ + SizedBox( + height: 30.r, + width: MediaQuery.of(context).size.width, + child: ListView.builder( + itemBuilder: (BuildContext context, int index) { + var item = subjectList[index]; + return InkWell( + onTap: () { + setState(() { + subjectList.forEach((element) { + element.isCheck = false; + }); + item.isCheck = true; + currentSubjectId = item.value; + EasyLoading.show(status: 'loading...'); + getImageDetail(); + }); + }, + child: Container( + width: 30.r, + height: 30.r, + margin: EdgeInsets.only( + right: index == subjectList.length + ? 0 + : (MediaQuery.of(context).size.width - + 30.r * 9 - + 110.r) / + 8), + decoration: BoxDecoration( + color: item.isCheck + ? Color(0xFF6787FD) + : Color(0xFFFFFFFF), + shape: BoxShape.circle, + // borderRadius: BorderRadius.all(Radius.circular(13.r)), + ), + child: Center( + child: Text( + item.text, + style: TextStyle( + fontSize: 11.sp, + color: item.isCheck + ? Colors.white + : Color(0xFF667095), + fontWeight: FontWeight.w400), + )), + ), + ); + }, + itemCount: subjectList.length, + scrollDirection: Axis.horizontal, + ), + ), + Expanded( + child: examOrigin != null && examOrigin!.imageUrl != '' + ? Padding( + padding: EdgeInsets.only(top:5.r), + child: InteractiveViewer( + constrained: false, + boundaryMargin: EdgeInsets.all(140.r), + minScale: 0.1, // 最小缩放 + maxScale: 4.0, // 最大缩放 + child: CustomRect(examOrigin!)), + ) + : MyEmptyWidget(), + ), + SizedBox(height: 6.r,), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if(examOrigin != null && examOrigin!.pageIndex > 1) + InkWell( + onTap: () { + var num = examOrigin!.pageIndex; + if (num > 1) { + setState(() { + examOrigin = examOriginList[num - 1 - 1]; + }); + } + }, + child:Container( + padding: EdgeInsets.symmetric( + vertical: 2.r, horizontal: 5.r), + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFF6787FD), + width: 1.r), + borderRadius: BorderRadius.all( + Radius.circular(2.r)), + ), + child: Text( + '下一页', + style: TextStyle( + color: Color(0xFF6787FD), + ), + ), + ), + /* Image.asset( + 'assets/images/report_left_icon.png', + width: 33.r, + height: 33.r, + )*/ + ), + SizedBox( + width: 30.r, + ), + if(examOrigin != null && examOrigin!.pageIndex < examOriginList.length) + InkWell( + onTap: () { + var num = examOrigin!.pageIndex; + if (num < examOriginList.length) { + setState(() { + examOrigin = examOriginList[num]; + }); + + } + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 2.r, horizontal: 5.r), + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFF6787FD), + width: 1.r), + borderRadius: BorderRadius.all( + Radius.circular(2.r)), + ), + child: Text( + '上一页', + style: TextStyle( + color: Color(0xFF6787FD), + ), + ), + ), + /* Image.asset( + 'assets/images/report_right_icon.png', + width: 33.r, + height: 33.r, + )*/ + ), + ], + ), + ], + ), + )) + ]), + ); + } +} + +class _subjectText extends StatelessWidget { + final String name; + final bool isTitle; + + const _subjectText(this.name, {this.isTitle = true, Key? key}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return Center( + child: Text( + name, + style: TextStyle( + fontSize: isTitle ? 11.sp : 12.sp, + color: isTitle ? Color(0xFF667095) : Color(0xFF424242), + fontWeight: FontWeight.w400), + ), + ); + } +} diff --git a/marking_app/lib/pages/reports/index.dart b/marking_app/lib/pages/reports/index.dart index 27cedee..24920d2 100644 --- a/marking_app/lib/pages/reports/index.dart +++ b/marking_app/lib/pages/reports/index.dart @@ -8,21 +8,30 @@ import 'package:functional_widget_annotation/functional_widget_annotation.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:marking_app/common/mixin/common.dart'; +import 'package:marking_app/common/model/common/base_page_data_report.dart'; import 'package:marking_app/common/model/common/base_structure_result_report.dart'; import 'package:marking_app/common/model/enum/reportUserIdentity.dart'; +import 'package:marking_app/common/model/report/exam_records.dart'; +import 'package:marking_app/common/model/report/exam_records_all.dart'; +import 'package:marking_app/common/model/report/exam_records_params.dart'; import 'package:marking_app/common/model/report/report_histogram_model.dart'; import 'package:marking_app/common/model/report/report_home_model.dart'; import 'package:marking_app/common/model/user/user_info.dart'; import 'package:marking_app/common/model/user/user_info_report.dart'; +import 'package:marking_app/pages/report_detail/widgets/no_data.dart'; import 'package:marking_app/pages/reports/bar_chart_histogram.dart'; import 'package:marking_app/pages/reports/services/report_home_services.dart'; import 'package:marking_app/provider/user_provider.dart'; import 'package:marking_app/routes/RouterManager.dart'; +import 'package:marking_app/utils/easy_refresh/MyEmptyWidget.dart'; import 'package:marking_app/utils/index.dart'; import 'package:marking_app/utils/my_text.dart'; import 'package:marking_app/utils/request/rest_client_report.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; +import 'widgets/myDrawer.dart'; +import 'widgets/userInfo.dart'; + part 'index.g.dart'; class TheReport extends StatefulHookConsumerWidget { @@ -32,20 +41,34 @@ class TheReport extends StatefulHookConsumerWidget { _TheReportState createState() => _TheReportState(); } -class _TheReportState extends ConsumerState with CommonMixin, AutomaticKeepAliveClientMixin { +class _TheReportState extends ConsumerState + with CommonMixin, AutomaticKeepAliveClientMixin { late RemoveListener _userReportListener; + late RestClientReport ClientReport; late UserInfo _user; late UserInfoReport _userReport; late Future _future; int? theExamId; + List gradeList = []; + List testTypeList = []; + List selectList = []; + bool isGrade = false; + ComboData currentGrade = ComboData('', ''); + ComboData currentTestType = ComboData('', ''); + List reportList = []; + bool showGrade = false; @override bool get wantKeepAlive => true; @override void initState() { - _future = initData(); + getHomeComboExam(); + // getExamTypeList(); + // getGradeEnumList(); + + // _future = initData(); Future.delayed(Duration.zero, () { _user = ref.read(userProvider); _userReportListener = ref.read(userReportProvider.notifier).addListener( @@ -67,6 +90,91 @@ class _TheReportState extends ConsumerState with CommonMixin, Automat super.dispose(); } + //获取考试类别、年级 + void getHomeComboExam() async { + RestClientReport clientReport = await getClientReport(); + BaseStructureResultReport res = + await clientReport.getHomeCombo(); + testTypeList = res.data!.type.comboData; + gradeList = res.data!.grade.comboData; + testTypeList[0].isCheck = true; + gradeList[0].isCheck = true; + setState(() { + currentTestType = testTypeList[0]; + currentGrade = gradeList[0]; + }); + // getExamRecordsList(); + getLevel(); + } + + //获取考试类别 +/* void getExamTypeList() async { + RestClientReport clientReport = await getClientReport(); + BaseStructureResultReport res = await clientReport.getExamType(); + testTypeList = res.data!.comboData; + testTypeList[0].isCheck = true; + setState(() { + currentTestType = testTypeList[0]; + }); + }*/ + /* //获取年级 + void getGradeEnumList() async { + RestClientReport clientReport = await getClientReport(); + BaseStructureResultReport> result = await clientReport.getGradeEnum(); + gradeList = result.data!; + + print(gradeList); + gradeList[0].isCheck = true; + setState(() { + currentGrade = gradeList[0]; + }); + }*/ + //获取列表数据 + void getExamRecordsList() async { + RestClientReport clientReport = await getClientReport(); + ExamRecordsParams params = ExamRecordsParams( + reportType: currentTestType.value, + grade: currentGrade.value, + page: 1, + limit: 10); + BaseStructureResultReport> result = + await clientReport.getExamrecords(params); + setState(() { + reportList = result.data!.items; + }); + + } + + void checkHandle(item) { + setState(() { + if (isGrade) { + gradeList.forEach((element) { + element.isCheck = false; + }); + item.isCheck = true; + currentGrade = item; + } else { + testTypeList.forEach((element) { + element.isCheck = false; + }); + item.isCheck = true; + currentTestType = item; + } + }); + } + + void getLevel() async { + getExamRecordsList(); + RestClientReport clientReport = await getClientReport(); + BaseStructureResultReport res = + await clientReport.getPositionlevel(currentGrade.text); + if (res.data <= 3) { + showGrade = true; + }else{ + showGrade = false; + } + } + /// 初始化数据 Future initData({int? examId}) async { try { @@ -74,12 +182,14 @@ class _TheReportState extends ConsumerState with CommonMixin, Automat UserInfoReport _userReport = ref.read(userReportProvider); if (!_userReport.normal) { // 用户职位数据是否已经请求,在主页已经请求一次 为正常使用 备用 - bool theFlag = await ref.read(userReportProvider.notifier).initUserReport(); + bool theFlag = + await ref.read(userReportProvider.notifier).initUserReport(); if (!theFlag) { return ToastUtils.showError('请求失败请重试'); } } - BaseStructureResultReport res = await clientReport.getReportHomeData(examId); + BaseStructureResultReport res = + await clientReport.getReportHomeData(examId); if (res.success) { return res.data; } else { @@ -99,6 +209,7 @@ class _TheReportState extends ConsumerState with CommonMixin, Automat return null; } + var _scaffoldkey = new GlobalKey(); //将Scaffold设置为全局变量 @override Widget build(BuildContext context) { super.build(context); //调用super.build(返回值始终返回null,应将其忽略) @@ -113,45 +224,334 @@ class _TheReportState extends ConsumerState with CommonMixin, Automat statusBarBrightness: Brightness.light, ), child: Scaffold( - body: Stack( - children: [ - // 渐变背景色 - $ScaffoldBgc(), + key: _scaffoldkey, + drawer: MyDrawer( + list: selectList, + isGrade: isGrade, + onChanged: checkHandle, + refresh: getLevel), + body: Column( + children: [ + Container( + color: Colors.white, + padding: EdgeInsets.only( + top: MediaQuery.of(context).padding.top + 4.h, + left: 14.w, + right: 14.w, + bottom: 19.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: TopUserInfo(), + ), + /* InkWell( + onTap: () {}, + child: Text( + '历史报告', + style: TextStyle( + fontSize: 14.sp, + color: Color.fromRGBO(128, 128, 128, 1)), + ), + ),*/ + ], + ), + ), + Expanded( + child: Padding( + padding: EdgeInsets.only(left: 14.w, right: 14.w), + child: Column( + children: [ + SizedBox( + height: 50.r, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/school_icon.png', + width: 22.w, + height: 22.w, + ), + Text( + '远轩高级中学', + style: TextStyle( + fontSize: 14.sp, + color: Color.fromRGBO(62, 86, 173, 1)), + ) + ], + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () { + setState(() { + selectList = gradeList; + isGrade = true; + _scaffoldkey.currentState?.openDrawer(); + }); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 8.h, horizontal: 20.r), + width: + MediaQuery.of(context).size.width / 2 - 50.r, + child: Row( + children: [ + Text( + '年级:', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF585858)), + ), + Text( + currentGrade.text, + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF6686FD)), + ), + ], + ), + decoration: BoxDecoration( + color: Color.fromRGBO(197, 220, 255, 0.3), + borderRadius: BorderRadius.circular(20.r), + border: Border.all( + color: Color(0xFFC0DCFF), width: 1.r), + ), + ), + ), + InkWell( + onTap: () { + setState(() { + selectList = testTypeList; + isGrade = false; + _scaffoldkey.currentState?.openDrawer(); + }); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 8.h, horizontal: 20.r), + width: + MediaQuery.of(context).size.width / 2 - 60.r, + child: Row( + children: [ + Text( + '考试类别:', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF585858)), + ), + Text( + currentTestType.text, + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF6686FD)), + ), + ], + ), + decoration: BoxDecoration( + color: Color.fromRGBO(197, 220, 255, 0.3), + borderRadius: BorderRadius.circular(20.r), + border: Border.all( + color: Color(0xFFC0DCFF), width: 1.r), + ), + ), + ) + ], + ), + SizedBox( + height: 20.r, + ), - RefreshIndicator( - displacement: 50, - color: Theme.of(context).primaryColor, - backgroundColor: Colors.white, - child: MyFutureBuilder.buildFutureBuilderOfSingleInstance(context, _future, - (ReportHomeModel? datas) { - return _TheReportBody( - user: _user, - userReport: _userReport, - data: datas, - refreshReport: () { - _future = initData(); - toUpState(setState, () {}, mounted); - }, - switchCall: (int? examId, int positionIndex) { - theExamId = examId; - if (examId != null) { - ref.read(userReportProvider.notifier).setPositionIndex(positionIndex); - - _future = initData(examId: examId); - toUpState(setState, () {}, mounted); - } - }, - ); - }), - onRefresh: () async { - _future = initData(examId: theExamId); - await _future; - await Future.delayed(Duration(seconds: 1), () => toUpState(setState, () => {}, mounted)); - }, - ), - ], - ), - ), + Expanded( + child: reportList.length>0?ListView.builder( + itemBuilder: (BuildContext context, int index) { + var item = reportList[index]; + return Container( + // padding: EdgeInsets.all(6.r), + margin: EdgeInsets.only(bottom: 20.r), + width: double.infinity, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'assets/images/reports_bg.png'), + fit: BoxFit.fill, + ), + border: Border.all( + width: 1.r, + color: Color.fromRGBO(46, 91, 255, 0.2)), + borderRadius: BorderRadius.circular(5.r), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.symmetric( + vertical: 20.r, horizontal: 25.r), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage( + 'assets/images/report_group_bg.png'), + fit: BoxFit.fill, + )), + child: Text( + item.typeName, + style: TextStyle( + fontSize: 12.sp, + color: Colors.white), + ), + ), + Text( + item.name, + style: TextStyle( + fontSize: 14.sp, + color: Colors.black), + ) + ], + ), + Container( + padding: + EdgeInsets.symmetric(horizontal: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5.r), + ), + child: Table( + defaultVerticalAlignment: + TableCellVerticalAlignment.middle, + border: TableBorder.symmetric( + inside: BorderSide( + width: 1, color: Color(0xFFD7DBF0)), + outside: BorderSide.none, + ), + // borderRadius: BorderRadius.circular(5.r), + children: [ + TableRow( + decoration: BoxDecoration( + color: Color(0xFFECECEC), + ), + children: [ + Center( + child: Container( + padding: EdgeInsets.symmetric( + vertical: 6.r), + child: Text( + '年级', + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF8A8A8A)), + ), + ), + ), + Center( + child: Text( + '科目', + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF8A8A8A)), + ), + ), + Center( + child: Text( + '考试日期', + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF8A8A8A)), + ), + ), + ], + ), + TableRow( + decoration: BoxDecoration( + color: Colors.white, + ), + children: [ + Center( + child: Container( + padding: EdgeInsets.symmetric( + vertical: 6.r), + child: Text( + item.grade, + style: TextStyle( + fontSize: 14.sp, + color: + Color(0xFF4A4A4A)), + ), + ), + ), + Center( + child: Text( + item.subjectStr, + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF4A4A4A)), + ), + ), + Center( + child: Text( + item.startTimeStr, + style: TextStyle( + fontSize: 14.sp, + color: Color(0xFF4A4A4A)), + ), + ), + ]) + ], + ), + ), + InkWell( + onTap: () { + RouterManager.router.navigateTo( + context, + RouterManager.reportDetailPath + + '?examId=${item.id}&showGrade=${showGrade}', + transition: getTransition(), + ); + }, + child: Container( + margin: EdgeInsets.symmetric( + horizontal: 60.r, vertical: 20.r), + padding: + EdgeInsets.symmetric(vertical: 5.r), + width: double.infinity, + decoration: BoxDecoration( + borderRadius: + BorderRadius.circular(20.r), + gradient: LinearGradient( + begin: Alignment(0.95, -0.30), + end: Alignment(-0.95, 0.3), + colors: [ + Color(0xFF3561FE), + Color(0xFF6A89FC) + ])), + child: Center( + child: Text( + '查看报告', + style: TextStyle( + fontSize: 16.sp, + color: Colors.white), + )), + ), + ) + ], + ), + ); + }, + itemCount: reportList.length, + ):MyEmptyWidget(), + ), + ], + ), + ), + ) + ], + )), ); } } @@ -176,24 +576,33 @@ class _TheReportBody extends HookWidget { @override Widget build(BuildContext context) { ExamData? examData = data?.examData; - List? tagComparisonList = - examData?.tagComparisonList.map((e) => ReportHistogramModel(name: e.name, val: e.count)).toList(); + List? tagComparisonList = examData?.tagComparisonList + .map((e) => ReportHistogramModel(name: e.name, val: e.count)) + .toList(); List? examSubjectDatas = data?.examSubjectDatas; List _positions = userReport.positions; - SwitchIdentityExamsController potnAndExamCotl = SwitchIdentityExamsController.use( - position: userReport.positionIndex, exam: -1, initExamId: examData?.examId, positons: userReport.positions); - Positions? theCurrentPosition = _positions.isEmpty ? null : _positions[potnAndExamCotl.positionIndex.value]; + SwitchIdentityExamsController potnAndExamCotl = + SwitchIdentityExamsController.use( + position: userReport.positionIndex, + exam: -1, + initExamId: examData?.examId, + positons: userReport.positions); + Positions? theCurrentPosition = _positions.isEmpty + ? null + : _positions[potnAndExamCotl.positionIndex.value]; if (examData == null || theCurrentPosition == null) { return Padding( - padding: EdgeInsets.only(left: 16.w, right: 16.w, top: MediaQuery.of(context).padding.top), + padding: EdgeInsets.only( + left: 16.w, right: 16.w, top: MediaQuery.of(context).padding.top), child: Column( children: [ $ReportTitle( titleName: '', - switchCall: () => easyThrottle('reportHomeExamSwitchCall', () async { + switchCall: () => + easyThrottle('reportHomeExamSwitchCall', () async { // switchCall(examId, potnAndExamCotl.positionIndex.value); List positions = userReport.positions; if (positions.isEmpty) { @@ -215,8 +624,10 @@ class _TheReportBody extends HookWidget { //按钮被按下时的不透明度程度,0~1之间 pressedOpacity: 1, //这也可以自己定义Container然后固定大小进行设置等等 - child: quickText('没有数据,请重试', color: Colors.white, size: 14.sp), - onPressed: () => easyThrottle('reportHomeNoDataAgain', () => refreshReport()), + child: + quickText('没有数据,请重试', color: Colors.white, size: 14.sp), + onPressed: () => easyThrottle( + 'reportHomeNoDataAgain', () => refreshReport()), ), ), ), @@ -228,20 +639,24 @@ class _TheReportBody extends HookWidget { // 内容区域 return Padding( - padding: EdgeInsets.only(left: 16.w, right: 16.w, top: MediaQuery.of(context).padding.top), + padding: EdgeInsets.only( + left: 16.w, right: 16.w, top: MediaQuery.of(context).padding.top), child: Column( children: [ SizedBox(height: 6.h), // 考试报告TITLE $ReportTitle( titleName: examData.examName, - switchCall: () => easyThrottle('reportHomeExamSwitchCall', () async { + switchCall: () => + easyThrottle('reportHomeExamSwitchCall', () async { List positions = userReport.positions; if (positions.isEmpty) { return ToastUtils.showInfo('没有数据,请刷新'); } int? examId = await potnAndExamCotl.openSwitch( - context: context, currentExamId: examData.examId, currentPositionIndex: userReport.positionIndex); + context: context, + currentExamId: examData.examId, + currentPositionIndex: userReport.positionIndex); switchCall(examId, potnAndExamCotl.positionIndex.value); }), @@ -254,7 +669,9 @@ class _TheReportBody extends HookWidget { children: [ // 顶部平均分模块 $TopAverageContainer( - averageVal: examData.averageScore, totalVal: examData.totalScore, context: context), + averageVal: examData.averageScore, + totalVal: examData.totalScore, + context: context), // 详细报告入口区域 $DetailedReportEntry( @@ -282,7 +699,8 @@ class _TheReportBody extends HookWidget { $GraphicDataArea( title: '单科概况', titleImg: 'assets/images/report_home_icon_subject.png', - graphicContainer: $TheProgressChart(context, examSubjectDatas!)), + graphicContainer: + $TheProgressChart(context, examSubjectDatas!)), ], ), ), @@ -335,11 +753,13 @@ Widget $reportTitle({required String titleName, required switchCall}) { ), ), InkWell( - onTap: () => easyThrottle('switchRoleExamSheetCall', () => switchCall()), + onTap: () => + easyThrottle('switchRoleExamSheetCall', () => switchCall()), child: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon(Icons.swap_vert_rounded, color: Color.fromRGBO(80, 87, 103, 0.8), size: 16.sp), + Icon(Icons.swap_vert_rounded, + color: Color.fromRGBO(80, 87, 103, 0.8), size: 16.sp), quickText('切换', color: Color.fromRGBO(80, 87, 103, 1), size: 12.sp), ], ), @@ -350,7 +770,10 @@ Widget $reportTitle({required String titleName, required switchCall}) { /// 顶部平均分模块 @swidget -Widget $topAverageContainer({required double averageVal, required double totalVal, required BuildContext context}) { +Widget $topAverageContainer( + {required double averageVal, + required double totalVal, + required BuildContext context}) { return Stack( alignment: const FractionalOffset(0.99, 0), children: [ @@ -366,7 +789,8 @@ Widget $topAverageContainer({required double averageVal, required double totalVa borderRadius: BorderRadius.circular(3).r, child: Container( alignment: Alignment.centerLeft, - padding: EdgeInsets.only(left: 4, right: 4, top: 4, bottom: 7).r, + padding: + EdgeInsets.only(left: 4, right: 4, top: 4, bottom: 7).r, child: quickText('平均分', size: 6.sp, color: Colors.white), decoration: ShapeDecoration( shape: BeveledRectangleBorder( @@ -380,22 +804,29 @@ Widget $topAverageContainer({required double averageVal, required double totalVa gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, - colors: [Theme.of(context).primaryColor, Theme.of(context).primaryColor.withOpacity(0.3)], + colors: [ + Theme.of(context).primaryColor, + Theme.of(context).primaryColor.withOpacity(0.3) + ], ), ), ), ), SizedBox(height: 1.h), quickText(averageVal.toString(), - size: 38.sp, color: Color.fromRGBO(45, 56, 76, 1), fontWeight: FontWeight.bold), + size: 38.sp, + color: Color.fromRGBO(45, 56, 76, 1), + fontWeight: FontWeight.bold), SizedBox(height: 1.h), - quickText('满分' + totalVal.toString(), size: 12.sp, color: Color.fromRGBO(80, 87, 103, 0.7)), + quickText('满分' + totalVal.toString(), + size: 12.sp, color: Color.fromRGBO(80, 87, 103, 0.7)), ], ), ], ), ), - Image.asset("assets/images/report_home_top_img.png", width: 100.r, height: 100.r) + Image.asset("assets/images/report_home_top_img.png", + width: 100.r, height: 100.r) ], ); } @@ -441,9 +872,13 @@ Widget $detailedReportEntry({ mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - quickText('年级', size: 12.sp, color: Color.fromRGBO(80, 87, 103, 1)), + quickText('年级', + size: 12.sp, color: Color.fromRGBO(80, 87, 103, 1)), SizedBox(height: 5.h), - quickText(grade, size: 16.sp, fontWeight: FontWeight.bold, color: Color.fromRGBO(45, 56, 76, 1)), + quickText(grade, + size: 16.sp, + fontWeight: FontWeight.bold, + color: Color.fromRGBO(45, 56, 76, 1)), ], ), SizedBox(width: 23.w), @@ -454,10 +889,14 @@ Widget $detailedReportEntry({ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - quickText('学科', size: 12.sp, color: Color.fromRGBO(80, 87, 103, 1)), + quickText('学科', + size: 12.sp, color: Color.fromRGBO(80, 87, 103, 1)), SizedBox(height: 5.h), quickText(subject, - size: 16.sp, fontWeight: FontWeight.bold, color: Color.fromRGBO(45, 56, 76, 1), maxLines: 2), + size: 16.sp, + fontWeight: FontWeight.bold, + color: Color.fromRGBO(45, 56, 76, 1), + maxLines: 2), ], ) ], @@ -468,9 +907,13 @@ Widget $detailedReportEntry({ mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - quickText('考试日期', size: 12.sp, color: Color.fromRGBO(80, 87, 103, 1)), + quickText('考试日期', + size: 12.sp, color: Color.fromRGBO(80, 87, 103, 1)), SizedBox(height: 5.h), - quickText(examDate, size: 16.sp, fontWeight: FontWeight.bold, color: Color.fromRGBO(45, 56, 76, 1)), + quickText(examDate, + size: 16.sp, + fontWeight: FontWeight.bold, + color: Color.fromRGBO(45, 56, 76, 1)), ], ), ], @@ -485,7 +928,8 @@ Widget $detailedReportEntry({ '?examId=$examId&classId=$classId&subject=$subjectId&subjectName=${Uri.encodeComponent(subjectName)}'; break; case ReportUserIdentity.CLASS: // 班主任 - rootPath = RouterManager.reportClassTeacherPath + '?examId=$examId'; + rootPath = + RouterManager.reportClassTeacherPath + '?examId=$examId'; break; case ReportUserIdentity.GRADE: // 年级 case ReportUserIdentity.SCHOOL_LEVEL: // 校级 @@ -500,7 +944,8 @@ Widget $detailedReportEntry({ color: Theme.of(context).primaryColor, ).show(context); } - RouterManager.router.navigateTo(context, rootPath, transition: getTransition()); + RouterManager.router + .navigateTo(context, rootPath, transition: getTransition()); }), child: Container( width: double.infinity, @@ -512,7 +957,10 @@ Widget $detailedReportEntry({ gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, - colors: [Color.fromRGBO(54, 86, 255, 1), Color.fromRGBO(93, 128, 255, 1)], + colors: [ + Color.fromRGBO(54, 86, 255, 1), + Color.fromRGBO(93, 128, 255, 1) + ], ), boxShadow: [ BoxShadow( @@ -523,7 +971,8 @@ Widget $detailedReportEntry({ ) ], ), - child: quickText('查看详细报告', color: Colors.white, size: 14.sp, fontWeight: FontWeight.w400), + child: quickText('查看详细报告', + color: Colors.white, size: 14.sp, fontWeight: FontWeight.w400), ), ), ], @@ -533,7 +982,10 @@ Widget $detailedReportEntry({ /// 图形数据模块 @swidget -Widget $graphicDataArea({required String title, required String titleImg, required Widget graphicContainer}) { +Widget $graphicDataArea( + {required String title, + required String titleImg, + required Widget graphicContainer}) { return Container( margin: EdgeInsets.only(bottom: 28.h), child: Column( @@ -587,7 +1039,8 @@ Widget $theProgressChart(context, List datas) { return $theProgressWidget( context: context, isMultiple: isMultiple, - linearGradient: LinearGradient(colors: [Colors.white, Theme.of(context).primaryColor]), + linearGradient: LinearGradient( + colors: [Colors.white, Theme.of(context).primaryColor]), subjectName: e.subjectName + '平均分', suffixTitle: e.totalScoreStr + '分', contentVal: e.averageScoreStr + '分', @@ -603,7 +1056,8 @@ Widget $theProgressChart(context, List datas) { return $theProgressWidget( context: context, isMultiple: isMultiple, - linearGradient: LinearGradient(colors: [Colors.white, Color.fromRGBO(0, 131, 253, 1)]), + linearGradient: LinearGradient( + colors: [Colors.white, Color.fromRGBO(0, 131, 253, 1)]), subjectName: e.subjectName + '及格率', suffixTitle: '100%', contentVal: e.passRateStr + '%', @@ -637,14 +1091,18 @@ Widget $theProgressWidget({ mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - quickText(subjectName, size: 14.sp, color: Color.fromRGBO(45, 56, 76, 1), fontWeight: FontWeight.w400), + quickText(subjectName, + size: 14.sp, + color: Color.fromRGBO(45, 56, 76, 1), + fontWeight: FontWeight.w400), SizedBox(height: 6.h), Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: LinearPercentIndicator( - padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 0), + padding: + const EdgeInsets.symmetric(horizontal: 0, vertical: 0), // width: MediaQuery.of(context).size.width - 50, animation: true, lineHeight: 9.h, @@ -657,7 +1115,8 @@ Widget $theProgressWidget({ // ), // linearStrokeCap: LinearStrokeCap.butt, // progressColor: Theme.of(context).primaryColor, - backgroundColor: const Color.fromRGBO(219, 224, 243, 1).withOpacity(0.45), + backgroundColor: const Color.fromRGBO(219, 224, 243, 1) + .withOpacity(0.45), barRadius: Radius.circular(10.h), ), ), @@ -666,13 +1125,16 @@ Widget $theProgressWidget({ alignment: Alignment.centerRight, // padding: EdgeInsets.only(left: 20.w),suffixTitle child: quickText(suffixTitle, - size: 12.sp, color: Color.fromRGBO(148, 163, 182, 1), fontWeight: FontWeight.w400), + size: 12.sp, + color: Color.fromRGBO(148, 163, 182, 1), + fontWeight: FontWeight.w400), ), ], ), ], ), - quickText(contentVal, size: 12.sp, fontWeight: FontWeight.w700, color: contentColor), + quickText(contentVal, + size: 12.sp, fontWeight: FontWeight.w700, color: contentColor), ], ), ); diff --git a/marking_app/lib/pages/reports/widgets/myDrawer.dart b/marking_app/lib/pages/reports/widgets/myDrawer.dart new file mode 100644 index 0000000..f87d22e --- /dev/null +++ b/marking_app/lib/pages/reports/widgets/myDrawer.dart @@ -0,0 +1,59 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class MyDrawer extends StatefulWidget { + final List list; + final bool isGrade; + final ValueChanged onChanged; + final Function refresh; + + MyDrawer({required this.list, required this.isGrade, required this.onChanged,required this.refresh,Key? key}) : super(key: key); + + @override + State createState() => _MyDrawerState(); +} + +class _MyDrawerState extends State { + @override + void dispose() { + widget.refresh(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + // margin:EdgeInsets.only(top: 100.r), + child: Drawer( + width: MediaQuery.of(context).size.width / 2 - 20.r, + child: Padding( + padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top + 50.r), + child: Column( + children: [ + Text(widget.isGrade?'年级':'考试类别',style: TextStyle(fontSize: 16.sp,fontWeight: FontWeight.w500),), + Expanded( + child: ListView.builder( + itemBuilder: (BuildContext context, int index) { + var item = widget.list[index]; + return InkWell( + onTap: (){ + widget.onChanged(item); + Navigator.pop(context); + }, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 20.r), + child: Center( + child: Text(item.text,style: TextStyle(fontSize: 14.sp,fontWeight: FontWeight.w400,color: item.isCheck?Color(0xFF5F81FD):Color(0xFF2E2E2E)),)), + ), + ); + }, + itemCount: widget.list.length, + ), + ), + ], + ), + )), + ); + } +} diff --git a/marking_app/lib/pages/reports/widgets/userInfo.dart b/marking_app/lib/pages/reports/widgets/userInfo.dart new file mode 100644 index 0000000..9c8469c --- /dev/null +++ b/marking_app/lib/pages/reports/widgets/userInfo.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +import 'package:marking_app/provider/user_provider.dart'; +import 'package:marking_app/routes/RouterManager.dart'; +import 'package:marking_app/utils/index.dart'; + +class TopUserInfo extends ConsumerWidget { + const TopUserInfo({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final userState = ref.watch(userProvider); + + return InkWell( + onTap: () { + RouterManager.router.navigateTo(context, RouterManager.userMinePath, transition: getTransition()); + }, + child: Row( + children: [ + Container( + decoration: BoxDecoration( + color: Color.fromRGBO(245, 246, 251, 1), + borderRadius: BorderRadius.circular(30.r), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(50.w), + child: Container( + alignment: Alignment.center, + color: Color.fromRGBO(163, 211, 255, 1), + padding: EdgeInsets.all(1.r), + child: Image.asset('assets/images/logo.png', width: 32.w, height: 32.w), + ), + ), + Container( + margin: EdgeInsets.only(left: 10.h), + child: Text( + userState.userName, + style: TextStyle(fontSize: 15.sp, color: const Color.fromRGBO(45, 56, 76, 0.9)), + ), + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 4.w), + child: Icon( + Icons.arrow_forward_ios_rounded, + size: 12.sp, + color: const Color.fromRGBO(45, 56, 76, 0.9), + ), + ), + SizedBox(width: 5.w) + ], + ), + ), + Expanded(child: SizedBox()) + ], + ), + ); + } +} \ No newline at end of file diff --git a/marking_app/lib/routes/RouterManager.dart b/marking_app/lib/routes/RouterManager.dart index c8eb776..5ee4c23 100644 --- a/marking_app/lib/routes/RouterManager.dart +++ b/marking_app/lib/routes/RouterManager.dart @@ -25,6 +25,7 @@ import 'package:marking_app/pages/marking/review.dart'; import 'package:marking_app/pages/mine/index.dart'; import 'package:marking_app/pages/mine/other_pages/index.dart'; import 'package:marking_app/pages/other/agreement_page.dart'; +import 'package:marking_app/pages/report_detail/index.dart'; import 'package:marking_app/pages/reports/report_class_teacher.dart'; import 'package:marking_app/pages/reports/report_personal_subject.dart'; import 'package:marking_app/pages/reports/report_subject_teacher.dart'; @@ -50,6 +51,7 @@ class RouterManager { static const String reportSubjectTeacherPath = 'report/details/reportSubjectTeacher'; static const String reportPersonalSubjectPath = 'report/details/reportPersonalSubject'; static const String userMinePath = 'user/mine/index'; + static const String reportDetailPath = '/report_detail/index'; // TheMine static final FluroRouter router = FluroRouter(); @@ -188,6 +190,13 @@ class RouterManager { static final _userMinePageHandler = Handler( handlerFunc: (BuildContext? context, Map> params) => TheMine(), ); + static final _reportDetailPath = Handler( + handlerFunc: (BuildContext? context, Map> params){ + int examId = int.parse(params['examId']![0]); + bool showGrade = params['showGrade']![0] == 'true'; + return ReportDetail(examId: examId,showGrade:showGrade); + }, + ); static final _reportPersonalSubjectPageHandler = Handler( handlerFunc: (BuildContext? context, Map> params) { @@ -238,6 +247,7 @@ class RouterManager { router.define(reportPersonalSubjectPath, handler: _reportPersonalSubjectPageHandler, transitionType: TransitionType.material); router.define(userMinePath, handler: _userMinePageHandler, transitionType: TransitionType.material); + router.define(reportDetailPath, handler: _reportDetailPath, transitionType: TransitionType.material); // getTransition() diff --git a/marking_app/lib/utils/request/rest_client_report.dart b/marking_app/lib/utils/request/rest_client_report.dart index 64f62b8..9cc5760 100644 --- a/marking_app/lib/utils/request/rest_client_report.dart +++ b/marking_app/lib/utils/request/rest_client_report.dart @@ -10,8 +10,15 @@ import 'package:dio/dio.dart'; import 'package:marking_app/common/model/common/base_page_data_report.dart'; import 'package:marking_app/common/model/common/base_structure_result_report.dart'; +import 'package:marking_app/common/model/report/detail_base_info.dart'; +import 'package:marking_app/common/model/report/exam_records.dart'; +import 'package:marking_app/common/model/report/exam_records_all.dart'; +import 'package:marking_app/common/model/report/exam_records_params.dart'; import 'package:marking_app/common/model/report/marked_item.dart'; import 'package:marking_app/common/model/report/marked_item_params.dart'; +import 'package:marking_app/common/model/report/question_know_point.dart'; +import 'package:marking_app/common/model/report/report_card.dart'; +import 'package:marking_app/common/model/report/report_card_params.dart'; import 'package:marking_app/common/model/report/report_for_class_teacher_model.dart'; import 'package:marking_app/common/model/report/report_for_class_teacher_params.dart'; import 'package:marking_app/common/model/report/report_for_marking_pagerdetail_model.dart'; @@ -21,6 +28,8 @@ import 'package:marking_app/common/model/report/report_for_subject_student_param import 'package:marking_app/common/model/report/report_for_subject_teacher_model.dart'; import 'package:marking_app/common/model/report/report_for_subject_teacher_params.dart'; import 'package:marking_app/common/model/report/report_home_model.dart'; +import 'package:marking_app/common/model/report/report_marking_detail.dart'; +import 'package:marking_app/common/model/report/report_marking_detail_params.dart'; import 'package:marking_app/common/model/user/user_info_report.dart'; import 'package:retrofit/retrofit.dart' as the_retrofit; @@ -67,4 +76,64 @@ abstract class RestClientReport { @the_retrofit.POST("/api/user/template/getmarkingpagerdetails") Future> getMarkingPagerDetails( @the_retrofit.Body() ReportForMarkingPagerdetailParams params); + + /* // 报告 => 获取考试类别 + @the_retrofit.GET("/api/user/exam/getexamtypecombo") + Future> getExamType();*/ + + // 报告 => 获取年级 + @the_retrofit.GET("/api/public/enum/GradeEnum") + Future>> getGradeEnum(); + + // 报告 => 首页列表 + @the_retrofit.GET("/api/user/exam/examrecords") + Future>> getExamrecords( + @the_retrofit.Queries() ExamRecordsParams params + ); + + // 报告 => 获取考试类别、年级 + @the_retrofit.GET("/api/user/exam/mobilehomecombo") + Future> getHomeCombo(); + + // 报告 => 首页详情 + @the_retrofit.GET("/api/exam/report/master_mobile") + Future> getReportDetail( + @the_retrofit.Query("examId") int examId, @the_retrofit.Query("classId") int classId + ); + + // 报告 => 考试学科 + @the_retrofit.GET("/api/user/exam/examsubject") + Future>> getExamsubject( + @the_retrofit.Query("examId") int examId + ); + + // 报告 => 可选下拉考试类型(是否有年级模块的报告权限) + @the_retrofit.GET("/api/user/exam/positionlevel") + Future getPositionlevel( + @the_retrofit.Query("grade") String grade + ); + + // 报告 => 可选班级 + @the_retrofit.GET("/api/exam/report/classList") + Future>> getClassList( + @the_retrofit.Query("examId") int examId + ); + // 报告 => 可选班级 + @the_retrofit.GET("/api/exam/report/master_mobilesubject") + Future> getQuestionKnowPoint( + @the_retrofit.Query("examId") int examId, + @the_retrofit.Query("classId") int classId, + @the_retrofit.Query("subject") int subject + ); + + // 报告 =>成绩单 + @the_retrofit.POST("/api/user/exam/reportcard") + Future> getReportCard( + @the_retrofit.Body() ReportCardParams params); + + // 报告 =>阅卷详情 + @the_retrofit.POST("/api/exam/report/getmarkingpagerdetails") + Future> getMarkingDetail( + @the_retrofit.Body() ReportMarkingDetailParams params + ); } diff --git a/marking_app/pubspec.yaml b/marking_app/pubspec.yaml index 2073a64..1be5a43 100644 --- a/marking_app/pubspec.yaml +++ b/marking_app/pubspec.yaml @@ -106,6 +106,8 @@ dependencies: image: ^4.1.3 awesome_dialog: ^3.1.0 badges: ^3.1.2 + horizontal_data_table: ^4.1.1 + data_table_2: ^2.5.10 dev_dependencies: flutter_test: