Compare commits

..

No commits in common. "80256a6042278b64e73091dce9cb3120f6f4e06b" and "78f2d20536cb9a4824ac36f8a480849254b0760f" have entirely different histories.

27 changed files with 923 additions and 1167 deletions

View File

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-7.6.3-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip

View File

@ -18,8 +18,8 @@ class RequestConfig {
static RequestConfig? _instance; static RequestConfig? _instance;
String baseUrl; String baseUrl;
static const connectTimeout = 8 * 1000; // static const connectTimeout = 8000; //
static const receiveTimeout = 8 * 1000; // static const receiveTimeout = 8000; //
static const bool requestDataPrinting = true; // static const bool requestDataPrinting = true; //
static const bool printSwitch = true; // static const bool printSwitch = true; //
static const successCode = [204, 200]; // code static const successCode = [204, 200]; // code

View File

@ -4,7 +4,7 @@ import 'package:making_school_asignment_app/common/config/request_config.dart';
part 'do_paper_details_result.g.dart'; part 'do_paper_details_result.g.dart';
@JsonSerializable(checked: true, includeIfNull: false) @JsonSerializable(checked: true)
class DoPaperDetailsResult extends Object { class DoPaperDetailsResult extends Object {
@JsonKey(name: 'templateIds') @JsonKey(name: 'templateIds')
Map<String, bool> templateIds; Map<String, bool> templateIds;
@ -17,7 +17,7 @@ class DoPaperDetailsResult extends Object {
@JsonKey(name: 'templateIdKeyMap') @JsonKey(name: 'templateIdKeyMap')
Map<int, int>? templateIdKeyMap; Map<int, int>? templateIdKeyMap;
@JsonKey(name: 'submitStudents', toJson: _paperStudentsToJson) // @JsonKey(name: 'submitStudents') //
List<PaperStudents> students; List<PaperStudents> students;
@JsonKey(name: 'templateId') @JsonKey(name: 'templateId')
@ -55,17 +55,17 @@ class DoPaperDetailsResult extends Object {
@JsonKey(name: 'isFav') @JsonKey(name: 'isFav')
bool isFav; bool isFav;
@JsonKey(name: 'studentQuestions', toJson: _studentQuestionsToJson) @JsonKey(name: 'studentQuestions')
List<StudentQuestions> studentQuestions; List<StudentQuestions> studentQuestions;
// //
@JsonKey(name: 'unSubmitStudents', toJson: _paperStudentsToJson) @JsonKey(name: 'unSubmitStudents')
List<PaperStudents> unSubmitStudents; List<PaperStudents> unSubmitStudents;
@JsonKey(name: 'lastPage', toJson: _lastPageToJson) @JsonKey(name: 'lastPage')
LastPage? lastPage; LastPage? lastPage;
@JsonKey(name: 'nextPage', toJson: _nextPageToJson) @JsonKey(name: 'nextPage')
NextPage? nextPage; NextPage? nextPage;
// //
@ -112,34 +112,27 @@ class DoPaperDetailsResult extends Object {
var currentStudent = students.firstWhereOrNull((e) => e.id == studentId); var currentStudent = students.firstWhereOrNull((e) => e.id == studentId);
if (currentStudent != null) priority = currentStudent.isPriority; if (currentStudent != null) priority = currentStudent.isPriority;
} }
zgtAnswer = '${RequestConfig.imgUrl}$zgtAnswer?$lastAnswerTime';
if (!zgtAnswer.contains(RequestConfig.imgUrl)) {
zgtAnswer = '${RequestConfig.imgUrl}$zgtAnswer?$lastAnswerTime';
}
if (zgtAnnotate?.isNotEmpty ?? false) { if (zgtAnnotate?.isNotEmpty ?? false) {
showZgtAnnotate = RequestConfig.imgUrl + zgtAnnotate!; // showZgtAnnotate = RequestConfig.imgUrl + zgtAnnotate!; //
if (annotateTime != null) showZgtAnnotate = '${showZgtAnnotate!}?$annotateTime'; if (annotateTime != null)
showZgtAnnotate = '${showZgtAnnotate!}?$annotateTime';
} }
// //
if (annotateTime == null || studentQuestions.indexWhere((e) => e.studentScore == null) != -1) { if (annotateTime == null ||
studentQuestions.indexWhere((e) => e.studentScore == null) != -1) {
needAnnotate = true; needAnnotate = true;
} }
// print('学生作答图片:${annotatedCount}'); // print('学生作答图片:${annotatedCount}');
// print('老师批注图片提交数量:${submitCount}'); // print('老师批注图片提交数量:${submitCount}');
} }
factory DoPaperDetailsResult.fromJson(Map<String, dynamic> srcJson) => _$DoPaperDetailsResultFromJson(srcJson); factory DoPaperDetailsResult.fromJson(Map<String, dynamic> srcJson) =>
_$DoPaperDetailsResultFromJson(srcJson);
Map<String, dynamic> toJson() => _$DoPaperDetailsResultToJson(this); Map<String, dynamic> toJson() => _$DoPaperDetailsResultToJson(this);
static List<Map<String, dynamic>> _paperStudentsToJson(List<PaperStudents> examples) => examples.map((e) => e.toJson()).toList();
static List<Map<String, dynamic>> _studentQuestionsToJson(List<StudentQuestions> examples) => examples.map((e) => e.toJson()).toList();
static Map<String, dynamic>? _nextPageToJson(NextPage? example) => example?.toJson();
static Map<String, dynamic>? _lastPageToJson(LastPage? example) => example?.toJson();
} }
@JsonSerializable() @JsonSerializable()
@ -160,7 +153,8 @@ class PaperStudents extends Object {
this.isPriority, this.isPriority,
); );
factory PaperStudents.fromJson(Map<String, dynamic> srcJson) => _$PaperStudentsFromJson(srcJson); factory PaperStudents.fromJson(Map<String, dynamic> srcJson) =>
_$PaperStudentsFromJson(srcJson);
Map<String, dynamic> toJson() => _$PaperStudentsToJson(this); Map<String, dynamic> toJson() => _$PaperStudentsToJson(this);
} }
@ -212,7 +206,8 @@ class StudentQuestions extends Object {
this.useTime, this.useTime,
}); });
factory StudentQuestions.fromJson(Map<String, dynamic> srcJson) => _$StudentQuestionsFromJson(srcJson); factory StudentQuestions.fromJson(Map<String, dynamic> srcJson) =>
_$StudentQuestionsFromJson(srcJson);
Map<String, dynamic> toJson() => _$StudentQuestionsToJson(this); Map<String, dynamic> toJson() => _$StudentQuestionsToJson(this);
} }
@ -230,7 +225,8 @@ class LastPage extends Object {
this.studentId, this.studentId,
); );
factory LastPage.fromJson(Map<String, dynamic> srcJson) => _$LastPageFromJson(srcJson); factory LastPage.fromJson(Map<String, dynamic> srcJson) =>
_$LastPageFromJson(srcJson);
Map<String, dynamic> toJson() => _$LastPageToJson(this); Map<String, dynamic> toJson() => _$LastPageToJson(this);
} }
@ -248,7 +244,8 @@ class NextPage extends Object {
this.studentId, this.studentId,
); );
factory NextPage.fromJson(Map<String, dynamic> srcJson) => _$NextPageFromJson(srcJson); factory NextPage.fromJson(Map<String, dynamic> srcJson) =>
_$NextPageFromJson(srcJson);
Map<String, dynamic> toJson() => _$NextPageToJson(this); Map<String, dynamic> toJson() => _$NextPageToJson(this);
} }

View File

@ -28,7 +28,7 @@ class TestQuestionsImageInfo extends Object {
@JsonKey(name: 'actualImgHeight') // @JsonKey(name: 'actualImgHeight') //
double actualImgHeight; double actualImgHeight;
@JsonKey(name: 'remainingHeight') // .() @JsonKey(name: 'remainingHeight') // .()
double remainingHeight; double remainingHeight;
@JsonKey(name: 'imageHeightOffsetStart') // Y @JsonKey(name: 'imageHeightOffsetStart') // Y
@ -62,8 +62,8 @@ class TestQuestionsImageInfo extends Object {
}) { }) {
// //
scaleRatio = boxWidth / imageWidth; scaleRatio = boxWidth / imageWidth;
actualImgWidth = imageWidth * scaleRatio * zoom; actualImgWidth = imageWidth * scaleRatio;
actualImgHeight = imageHeight * scaleRatio * zoom; actualImgHeight = imageHeight * scaleRatio;
remainingHeight = boxHeight - actualImgHeight; remainingHeight = boxHeight - actualImgHeight;
imageHeightOffsetStart = remainingHeight / 2; imageHeightOffsetStart = remainingHeight / 2;
imageHeightOffsetend = imageHeightOffsetStart + actualImgHeight; imageHeightOffsetend = imageHeightOffsetStart + actualImgHeight;

View File

@ -2,7 +2,6 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:get/get.dart' as getx; import 'package:get/get.dart' as getx;
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:making_school_asignment_app/common/api/retrofit_client.dart'; import 'package:making_school_asignment_app/common/api/retrofit_client.dart';
import 'package:making_school_asignment_app/common/config/request_config.dart'; import 'package:making_school_asignment_app/common/config/request_config.dart';
@ -115,10 +114,6 @@ class AuthInterceptor extends Interceptor {
class ResponseHandle extends Interceptor { class ResponseHandle extends Interceptor {
@override @override
void onResponse(Response response, ResponseInterceptorHandler handler) { void onResponse(Response response, ResponseInterceptorHandler handler) {
const isProd = bool.fromEnvironment('dart.vm.product');
if (!isProd && RequestConfig.requestDataPrinting) {
toPrint(val: response.data, toPrintJson: true);
}
if (RequestConfig.successCode.contains(response.statusCode)) { if (RequestConfig.successCode.contains(response.statusCode)) {
// //
String? token = response.headers.value('access-token'); String? token = response.headers.value('access-token');
@ -185,11 +180,9 @@ class TheError extends Interceptor {
message = '用户登录失效,请重新登录'; message = '用户登录失效,请重新登录';
Future.delayed(const Duration(seconds: 2), () { Future.delayed(const Duration(seconds: 2), () {
if (getx.Get.currentRoute != Routes.login) { UserStore.to.erase();
UserStore.to.erase(); StorageService.to.erase();
StorageService.to.erase(); getx.Get.offAllNamed(Routes.login);
getx.Get.offAllNamed(Routes.login);
}
}); });
break; break;
case 404: case 404:

View File

@ -12,7 +12,9 @@ import 'package:flutter/material.dart';
VoidCallback debounce(Function func, [Duration delay = const Duration(milliseconds: 2000)]) { VoidCallback debounce(Function func, [Duration delay = const Duration(milliseconds: 2000)]) {
Timer? timer; Timer? timer;
target() { target() {
timer?.cancel(); if (timer?.isActive ?? false) {
timer?.cancel();
}
timer = Timer(delay, () { timer = Timer(delay, () {
func.call(); func.call();
}); });

View File

@ -9,14 +9,14 @@ import 'package:functional_widget_annotation/functional_widget_annotation.dart';
part 'cached_network_img.g.dart'; part 'cached_network_img.g.dart';
@hwidget @hwidget
Widget $theCachedNetworkImage(ImageWidgetBuilder imageBuilder, {required String imageUrl, double? imgWidth}) { Widget $theCachedNetworkImage(ImageWidgetBuilder imageBuilder, {required String imageUrl}) {
UseCachedImgRefresh useImgRefsh = UseCachedImgRefresh.use(); UseCachedImgRefresh useImgRefsh = UseCachedImgRefresh.use();
return CachedNetworkImage( return CachedNetworkImage(
key: useImgRefsh.imageKey.value, key: useImgRefsh.imageKey.value,
cacheKey: imageUrl, cacheKey: imageUrl,
fit: BoxFit.fitWidth, fit: BoxFit.fitWidth,
width: imgWidth ?? double.infinity, width: double.infinity,
imageUrl: imageUrl, imageUrl: imageUrl,
imageBuilder: imageBuilder, imageBuilder: imageBuilder,
placeholder: (context, url) => Center(child: SpinKitWave(color: Theme.of(context).primaryColor, size: 50.r)), placeholder: (context, url) => Center(child: SpinKitWave(color: Theme.of(context).primaryColor, size: 50.r)),

View File

@ -1,5 +1,3 @@
import 'dart:convert';
import 'package:flutter/src/widgets/framework.dart'; import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -8,8 +6,6 @@ import 'package:making_school_asignment_app/common/job/homework_details.dart';
import 'package:making_school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_state.dart'; import 'package:making_school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_state.dart';
import 'dart:math'; import 'dart:math';
import '../config/request_config.dart';
class Utils { class Utils {
static Utils? _instance; static Utils? _instance;
Utils._internal(); Utils._internal();
@ -181,7 +177,9 @@ class Utils {
stu.noAnswerCount = data.dtls.where((w) => w.state == 0 && stu.studentId == w.studentId).length; stu.noAnswerCount = data.dtls.where((w) => w.state == 0 && stu.studentId == w.studentId).length;
List<Questions> ques = data.questions; List<Questions> ques = data.questions;
stu.queDtls = data.dtls.where((w) => w.studentId == stu.studentId && ques.indexWhere((q) => w.templateId == q.templateId && w.questionNo == q.questionNo) > -1).toList(); stu.queDtls = data.dtls
.where((w) => w.studentId == stu.studentId && ques.indexWhere((q) => w.templateId == q.templateId && w.questionNo == q.questionNo) > -1)
.toList();
int okCount = stu.queDtls!.where((w) => w.state == 3).length; int okCount = stu.queDtls!.where((w) => w.state == 3).length;
int ttlCount = stu.queDtls!.length; int ttlCount = stu.queDtls!.length;
stu.okRate = Utils.calcRate(okCount, ttlCount); stu.okRate = Utils.calcRate(okCount, ttlCount);
@ -289,26 +287,23 @@ class Utils {
} }
static DateTime getWeekStartDate() { static DateTime getWeekStartDate() {
// DateTime now = DateTime.now();
// int dayOfWeek = now.weekday; // 17
// int diff = dayOfWeek - 1; //
// if (diff < 0) {
// diff += 7; //
// }
// return now.subtract(Duration(days: diff)); //
DateTime now = DateTime.now(); DateTime now = DateTime.now();
return now.subtract(const Duration(days: 6)); int dayOfWeek = now.weekday; // 17
int diff = dayOfWeek - 1; //
if (diff < 0) {
diff += 7; //
}
return now.subtract(Duration(days: diff)); //
} }
static DateTime getWeekEndDate() { static DateTime getWeekEndDate() {
// DateTime now = DateTime.now(); DateTime now = DateTime.now();
// int dayOfWeek = now.weekday; // int dayOfWeek = now.weekday; //
// int diff = 7 - dayOfWeek; // int diff = 7 - dayOfWeek; //
// if (diff == 0) { if (diff == 0) {
// diff = 7; // diff = 7; //
// } }
// return now.add(Duration(days: diff)); // return now.add(Duration(days: diff)); //
return DateTime.now();
} }
} }
@ -320,24 +315,3 @@ bool isPad([double mobilePhoneScale = 1.2]) {
void toUpState(Function(void Function()) setState, VoidCallback fn, bool mounted) { void toUpState(Function(void Function()) setState, VoidCallback fn, bool mounted) {
if (mounted) setState(fn); if (mounted) setState(fn);
} }
void toPrint({required dynamic val, bool toPrintJson = false}) {
bool printSwitch = RequestConfig.printSwitch;
if (printSwitch && val != null) toPrintJson ? printJson(val) : print(val);
}
/// Json格式输出打印
void printJson(Object object) {
try {
JsonEncoder encoder = const JsonEncoder.withIndent(' ');
var encoderString = encoder.convert(object);
// print(encoderString);
// 使print()
// 使debugPrint()
debugPrint(encoderString);
// debugPrint
//encoderString.split('\n').forEach((element) => print(element));
} catch (e) {
toPrint(val: e);
}
}

View File

@ -52,10 +52,8 @@ class MyApp extends StatelessWidget {
const MyApp({super.key}); const MyApp({super.key});
// This widget is the root of your application. // This widget is the root of your application.
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// String? oldRouter;
return ScreenUtilInit( return ScreenUtilInit(
designSize: const Size(AppConfig.UI_WIDTH, AppConfig.UI_HEIGHT), designSize: const Size(AppConfig.UI_WIDTH, AppConfig.UI_HEIGHT),
/* minTextAdapt: true, /* minTextAdapt: true,
@ -89,13 +87,6 @@ class MyApp extends StatelessWidget {
// systemStatusBarContrastEnforced: false, // systemStatusBarContrastEnforced: false,
// )); // ));
// } // }
// if (Routes.reviewHomework == currentRouter) {
// // SystemChrome.setEnabledSystemUIMode(SystemUiMode.leanBack, overlays: []);
// } else if (oldRouter == Routes.reviewHomework) {
// // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]); //
// }
// oldRouter = currentRouter;
}, },
// flutter_localizations依赖 // flutter_localizations依赖
supportedLocales: const [ supportedLocales: const [
@ -115,7 +106,7 @@ class MyApp extends StatelessWidget {
return locale; return locale;
}, },
// //
defaultTransition: getTransition(), defaultTransition: Transition.fade,
// //
initialRoute: Routes.startPage, initialRoute: Routes.startPage,

View File

@ -1,9 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart';
import 'package:making_school_asignment_app/page/global_widget/show_student_list.dart'; import 'package:making_school_asignment_app/page/global_widget/show_student_list.dart';
import 'package:percent_indicator/percent_indicator.dart'; import 'package:percent_indicator/percent_indicator.dart';
import 'package:making_school_asignment_app/common/job/annotated_class.dart'; import 'package:making_school_asignment_app/common/job/annotated_class.dart';
@ -83,7 +81,6 @@ class _AnnotateItemState extends State<AnnotateItem> {
), ),
); );
} }
void showStudentList(context, List<AnnotatedStudents> students, [bool submitted = false]) async { void showStudentList(context, List<AnnotatedStudents> students, [bool submitted = false]) async {
showDialog( showDialog(
context: context, context: context,
@ -92,13 +89,12 @@ class _AnnotateItemState extends State<AnnotateItem> {
title: '${widget.item.className ?? ''} ${submitted ? '已提交' : '未提交'}作业学生', title: '${widget.item.className ?? ''} ${submitted ? '已提交' : '未提交'}作业学生',
studentList: students, studentList: students,
homeworkId: widget.homeworkId, homeworkId: widget.homeworkId,
subject: widget.logic.state.subject, subject:widget.logic.state.subject,
); );
}, },
); );
EasyLoading.dismiss(); EasyLoading.dismiss();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
AnnotatedClass itemData = widget.item; AnnotatedClass itemData = widget.item;
@ -122,7 +118,7 @@ class _AnnotateItemState extends State<AnnotateItem> {
), ),
const Spacer(), const Spacer(),
InkWell( InkWell(
onTap: () { onTap: (){
EasyLoading.show(status: 'loading...'); EasyLoading.show(status: 'loading...');
showStudentList(context, widget.item.commitStudent!, true); showStudentList(context, widget.item.commitStudent!, true);
}, },
@ -135,7 +131,7 @@ class _AnnotateItemState extends State<AnnotateItem> {
width: 20.r, width: 20.r,
), ),
InkWell( InkWell(
onTap: () { onTap: (){
EasyLoading.show(status: 'loading...'); EasyLoading.show(status: 'loading...');
showStudentList(context, widget.item.noCommitStudent!, true); showStudentList(context, widget.item.noCommitStudent!, true);
}, },
@ -162,7 +158,12 @@ class _AnnotateItemState extends State<AnnotateItem> {
title: "收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}", title: "收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}",
font: widget.font - 2.sp, font: widget.font - 2.sp,
clickFunction: () { clickFunction: () {
Get.toNamed(Routes.favStudentPage, arguments: {'homeworkName': widget.name, 'classId': widget.item.classId, 'homeworkId': widget.logic.state.homeworkId.value, 'grade': widget.item.grade}); Get.toNamed(Routes.favStudentPage, arguments: {
'homeworkName': widget.name,
'classId': widget.item.classId,
'homeworkId': widget.logic.state.homeworkId.value,
'grade': widget.item.grade
});
}, },
), ),
), ),
@ -210,7 +211,12 @@ class _AnnotateItemState extends State<AnnotateItem> {
title: "收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}", title: "收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}",
font: widget.font - 2.sp, font: widget.font - 2.sp,
clickFunction: () { clickFunction: () {
Get.toNamed(Routes.favStudentPage, arguments: {'homeworkName': widget.name, 'classId': widget.item.classId, 'homeworkId': widget.logic.state.homeworkId.value, 'grade': widget.item.grade}); Get.toNamed(Routes.favStudentPage, arguments: {
'homeworkName': widget.name,
'classId': widget.item.classId,
'homeworkId': widget.logic.state.homeworkId.value,
'grade': widget.item.grade
});
}, },
), ),
), ),
@ -218,14 +224,16 @@ class _AnnotateItemState extends State<AnnotateItem> {
), ),
), ),
Padding( Padding(
padding: EdgeInsets.only(top: 10.r, left: 14.r, right: 14.r), padding: EdgeInsets.only(top: 10.r,left: 14.r,right: 14.r),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [quickText('批阅进度', size: widget.font - 2.sp, color: const Color(0xFF8E8E8E)), quickText('${widget.item.annotateRate}%', size: widget.font + 10.sp, color: const Color(0xFF464646))], children: [
), quickText('批阅进度', size: widget.font - 2.sp, color: const Color(0xFF8E8E8E)),
), quickText('${widget.item.annotateRate}%', size: widget.font + 10.sp, color: const Color(0xFF464646))
],
),),
Padding( Padding(
padding: EdgeInsets.only(top: 0.r, left: 14.r, right: 14.r, bottom: 10.r), padding: EdgeInsets.only(top: 0.r, left: 14.r,right: 14.r,bottom: 10.r),
child: LinearPercentIndicator( child: LinearPercentIndicator(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
animation: true, animation: true,
@ -239,9 +247,9 @@ class _AnnotateItemState extends State<AnnotateItem> {
colors: widget.item.annotateRate / 100 != 1 colors: widget.item.annotateRate / 100 != 1
? [Theme.of(context).primaryColor.withOpacity(0.1), Theme.of(context).primaryColor] ? [Theme.of(context).primaryColor.withOpacity(0.1), Theme.of(context).primaryColor]
: [ : [
const Color.fromRGBO(144, 224, 190, 1).withOpacity(0.1), const Color.fromRGBO(144, 224, 190, 1).withOpacity(0.1),
const Color.fromRGBO(144, 224, 190, 1), const Color.fromRGBO(144, 224, 190, 1),
], ],
), ),
// linearStrokeCap: LinearStrokeCap.butt, // linearStrokeCap: LinearStrokeCap.butt,
// progressColor: Theme.of(context).primaryColor, // progressColor: Theme.of(context).primaryColor,
@ -249,9 +257,27 @@ class _AnnotateItemState extends State<AnnotateItem> {
barRadius: Radius.circular(10.r), barRadius: Radius.circular(10.r),
), ),
), ),
ProgressBar(title: '客观题正确率:', color: const Color(0xFFADDCA5), percent: widget.item.kgtCorrectRate / 100, marginEdg: EdgeInsets.zero, padingEdg: EdgeInsets.only(top: 8.h, left: 14.r, right: 14.r), fontSize: widget.font - 2.sp), ProgressBar(
ProgressBar(title: '主观题正确率:', color: const Color(0xFFADDCA5), percent: widget.item.zgtCorrectRate / 100, padingEdg: EdgeInsets.symmetric(horizontal: 10.r), marginEdg: EdgeInsets.only(top: 8.h), fontSize: widget.font - 2.sp), title: '客观题正确率:',
ProgressBar(title: '总正确率:', color: const Color(0xFFADDCA5), percent: widget.item.correctRate / 100, padingEdg: EdgeInsets.symmetric(horizontal: 10.r), marginEdg: EdgeInsets.only(top: 8.h), fontSize: widget.font - 2.sp), color: const Color(0xFFADDCA5),
percent: widget.item.kgtCorrectRate / 100,
marginEdg: EdgeInsets.zero,
padingEdg: EdgeInsets.only(top: 8.h, left: 14.r, right: 14.r),
fontSize: widget.font - 2.sp),
ProgressBar(
title: '主观题正确率:',
color: const Color(0xFFADDCA5),
percent: widget.item.zgtCorrectRate / 100,
padingEdg: EdgeInsets.symmetric(horizontal: 10.r),
marginEdg: EdgeInsets.only(top: 8.h),
fontSize: widget.font - 2.sp),
ProgressBar(
title: '总正确率:',
color: const Color(0xFFADDCA5),
percent: widget.item.correctRate / 100,
padingEdg: EdgeInsets.symmetric(horizontal: 10.r),
marginEdg: EdgeInsets.only(top: 8.h),
fontSize: widget.font - 2.sp),
Container( Container(
margin: EdgeInsets.only(top: 10.r), margin: EdgeInsets.only(top: 10.r),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -276,8 +302,10 @@ class _AnnotateItemState extends State<AnnotateItem> {
widget.logic.goQuickDataCheck(widget.item); widget.logic.goQuickDataCheck(widget.item);
}, },
child: Container( child: Container(
padding: EdgeInsets.symmetric(vertical: 10.r), padding:EdgeInsets.symmetric(vertical:10.r),
decoration: BoxDecoration(border: Border(right: BorderSide(width: 1.r, color: const Color.fromRGBO(221, 221, 221, 1)))), decoration: BoxDecoration(
border: Border(right: BorderSide(width: 1.r,color:const Color.fromRGBO(221, 221, 221, 1) ))
),
alignment: Alignment.center, alignment: Alignment.center,
child: quickText('数据快查', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font), child: quickText('数据快查', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font),
), ),
@ -298,27 +326,20 @@ class _AnnotateItemState extends State<AnnotateItem> {
: [ : [
Expanded( Expanded(
child: InkWell( child: InkWell(
onTap: () => easyThrottle('TO_GO_REVIEWHOMEWORK', () { onTap: () {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.leanBack, overlays: []).then((_) { print('批阅..........');
WidgetsBinding.instance.addPostFrameCallback((_) { Get.toNamed(Routes.reviewHomework, arguments: {
Get.toNamed(Routes.reviewHomework, arguments: { 'homeworkId': widget.homeworkId,
'homeworkId': widget.homeworkId, 'homeworkName': widget.name,
'homeworkName': widget.name, 'classId': itemData.classId,
'classId': itemData.classId, 'subject': widget.logic.state.subject,
'subject': widget.logic.state.subject,
});
});
}); });
// Get.toNamed(Routes.reviewHomework, arguments: { },
// 'homeworkId': widget.homeworkId,
// 'homeworkName': widget.name,
// 'classId': itemData.classId,
// 'subject': widget.logic.state.subject,
// });
}),
child: Container( child: Container(
padding: EdgeInsets.symmetric(vertical: 10.r), padding:EdgeInsets.symmetric(vertical:10.r),
decoration: BoxDecoration(border: Border(right: BorderSide(width: 1.r, color: const Color.fromRGBO(221, 221, 221, 1)))), decoration: BoxDecoration(
border: Border(right: BorderSide(width: 1.r,color:const Color.fromRGBO(221, 221, 221, 1) ))
),
alignment: Alignment.center, alignment: Alignment.center,
child: quickText('批阅', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font), child: quickText('批阅', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font),
), ),
@ -327,7 +348,7 @@ class _AnnotateItemState extends State<AnnotateItem> {
// Container(width: 1.w, height: 30.h, color: const Color.fromRGBO(221, 221, 221, 1)), // Container(width: 1.w, height: 30.h, color: const Color.fromRGBO(221, 221, 221, 1)),
Expanded( Expanded(
child: InkWell( child: InkWell(
onTap: () async { onTap: () async{
var confim = await confirmDialog('当前批阅任务未完成,请确认需要结束此任务?'); var confim = await confirmDialog('当前批阅任务未完成,请确认需要结束此任务?');
if (confim) { if (confim) {
widget.logic.getOverAnnotate(widget.item.classId); widget.logic.getOverAnnotate(widget.item.classId);

View File

@ -1,3 +1,4 @@
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -5,29 +6,49 @@ import 'package:functional_widget_annotation/functional_widget_annotation.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart'; import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart';
import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart';
import 'package:making_school_asignment_app/common/utils/permission_describe_util.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart'; import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart'; import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart'; import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'package:permission_handler/permission_handler.dart';
import 'original_manuscript_handwriting/answer_handwriting_view.dart'; import 'original_manuscript_handwriting/answer_handwriting_view.dart';
part 'dropdown_switch_students_type.g.dart'; part 'dropdown_switch_students_type.g.dart';
/// ///
/// class DropdownSwitchStudentsType extends StatefulWidget {
class DropdownSwitchStudentsType extends StatelessWidget {
const DropdownSwitchStudentsType({super.key}); const DropdownSwitchStudentsType({super.key});
@override @override
Widget build(BuildContext context) { State<DropdownSwitchStudentsType> createState() => _DropdownSwitchStudentsTypeState();
final logic = Get.find<HomeworkReviewLogic>(); }
final sateData = logic.state.data;
class _DropdownSwitchStudentsTypeState extends State<DropdownSwitchStudentsType> {
final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
final logic = Get.find<HomeworkReviewLogic>();
final sateData = Get.find<HomeworkReviewLogic>().state.data;
@override
void initState() {
deviceInfoPlugin.androidInfo.then((androidInfo) {
Permission storagePermission = androidInfo.version.sdkInt >= 33 ? Permission.manageExternalStorage : Permission.storage;
PermissionDescribeUtil.instance.toLaunchPermissionRequest(
context,
title: '储存权限请求',
describe: "为了提供更好的服务,需要获取到存储权限用于保存批阅痕迹并上传",
permissions: [storagePermission],
);
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Container( return Container(
height: 30.h,
padding: EdgeInsets.only(bottom: 2.r, left: 12.r, right: 12.r), padding: EdgeInsets.only(bottom: 2.r, left: 12.r, right: 12.r),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
@ -269,8 +290,7 @@ Widget $historyHomework(BuildContext context) {
if (studentId == null || (sateData.value?.students.isEmpty ?? true)) return; if (studentId == null || (sateData.value?.students.isEmpty ?? true)) return;
var currentStudent = sateData.value!.students.firstWhereOrNull((e) => e.id == studentId); var currentStudent = sateData.value!.students.firstWhereOrNull((e) => e.id == studentId);
if (currentStudent == null) return; if (currentStudent == null) return;
var theState = Get.find<HomeworkReviewLogic>().state; Get.toNamed(Routes.studentWorkDetailPage, arguments: {'studentId': studentId, 'studentName': currentStudent.name});
Get.toNamed(Routes.studentWorkDetailPage, arguments: {'studentId': studentId, 'studentName': currentStudent.name,'subject':theState.param.value.subject});
}), }),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,

View File

@ -1,25 +1,69 @@
import 'dart:async';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:making_school_asignment_app/common/api/retrofit_client.dart';
import 'package:making_school_asignment_app/common/job/marking_models/favor_param.dart';
import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart';
import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart'; import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart';
/// ///
/// isFavorite /// isFavorite
/// favoriteNum /// favoriteNum
class FavoriteWidget extends StatefulWidget {
class FavoriteWidget extends StatelessWidget {
const FavoriteWidget({super.key}); const FavoriteWidget({super.key});
@override @override
Widget build(BuildContext context) { State<FavoriteWidget> createState() => _FavoriteState();
final logic = Get.find<HomeworkReviewLogic>(); }
final sateData = logic.state;
class _FavoriteState extends State<FavoriteWidget> with RequestToolMixin {
late StreamSubscription _listen;
final _controller = Get.find<HomeworkReviewLogic>();
final sateData = Get.find<HomeworkReviewLogic>().state;
RxBool favorite = false.obs; //
@override
void initState() {
_listen = _controller.state.data.listen((e) {
if (e == null) return;
if (favorite.value != e.isFav) favorite.value = !favorite.value;
});
super.initState();
}
@override
void dispose() {
_listen.cancel();
super.dispose();
}
Future<void> toFavorite() async {
try {
var data = sateData.data.value!;
var param = sateData.param.value;
await getClient().toFavStudent(FavorParam(
homeworkId: param.homeworkId,
studentId: data.studentId,
templateId: data.templateId,
questionNo: data.studentQuestions[0].questionNo,
isFav: !data.isFav,
));
favorite.value = !data.isFav;
data.isFav = favorite.value;
} catch (e) {
ToastUtils.showError('操作失败,请重试');
}
}
@override
Widget build(BuildContext context) {
return Container( return Container(
padding: EdgeInsets.symmetric(horizontal: 4.r), padding: EdgeInsets.symmetric(horizontal: 4.r),
child: InkWell( child: InkWell(
onTap: () => easyThrottle('homework_review_collect_btn', () => logic.toFavorite(), duration: const Duration(milliseconds: 500)), onTap: () => easyThrottle('homework_review_collect_btn', () => toFavorite(), duration: const Duration(milliseconds: 500)),
splashColor: Colors.transparent, splashColor: Colors.transparent,
highlightColor: Colors.transparent, highlightColor: Colors.transparent,
child: Row( child: Row(
@ -29,7 +73,7 @@ class FavoriteWidget extends StatelessWidget {
return Icon( return Icon(
const IconData(0xe63c, fontFamily: "AlibabaIcon"), const IconData(0xe63c, fontFamily: "AlibabaIcon"),
size: 18.sp, size: 18.sp,
color: sateData.favorite.value ? const Color.fromRGBO(255, 172, 48, 1) : const Color.fromRGBO(164, 164, 164, 1), color: favorite.value ? const Color.fromRGBO(255, 172, 48, 1) : const Color.fromRGBO(164, 164, 164, 1),
); );
}), }),
SizedBox(width: 6.w), SizedBox(width: 6.w),

View File

@ -1,270 +0,0 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_result.dart';
import 'package:making_school_asignment_app/common/job/marking_models/do_test_questions_image_info.dart';
import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:percent_indicator/linear_percent_indicator.dart';
import '../configuration_files/index.dart';
import '../configuration_files/zoom_logic.dart';
part 'question_number_view.g.dart';
///
class QuestionNumberView extends GetView<HomeworkReviewLogic> {
const QuestionNumberView({super.key});
HomeworkReviewState get sateData => controller.state;
ZoomState get sateZoomData => controller.zoomLogic.zoomState;
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(color: Color.fromRGBO(159, 159, 159, 0.97)),
child: GestureDetector(
onPanDown: (_) => sateData.panQuestView = false,
child: Obx(() {
var zoomFile = sateZoomData.zoomFile.value;
if (zoomFile == null) return const SizedBox();
var studentQuestions = sateData.studentQuestions.value ?? [];
return $QuestionNumberScrollView(
controller:controller,
sateData: sateData,
sateZoomData: sateZoomData,
studentQuestions: studentQuestions,
);
}),
),
);
}
}
//
@hwidget
Widget $questionNumberScrollView({
required HomeworkReviewLogic controller,
required ZoomState sateZoomData,
required HomeworkReviewState sateData,
required List<StudentQuestions> studentQuestions,
}) {
final scrollControllerNum = useScrollController(); //
var useZoom = useState<double>(sateZoomData.initScale.value ?? 1);
var usePiddingTop = useState<double>(sateZoomData.zoomFile.value?.imageHeightOffsetStart ?? 0);
useValueChanged<double?, void>(sateZoomData.zoomFile.value?.imageHeightOffsetStart, (_, __) {
usePiddingTop.value = sateZoomData.zoomFile.value?.imageHeightOffsetStart ?? 0;
});
useEffect(() {
var stream = sateZoomData.initScale.listen((e) {
// print("initScale : $e");
useZoom.value = e ?? 1;
var zoomFile = sateZoomData.zoomFile.value;
if (zoomFile?.actualHeight == null) return;
// print(zoomFile?.toJson());
// print("缩放基数:${useZoom.value}");
// print("图片实际高度:${zoomFile!.actualHeight! * useZoom.value}");
// print("视图剩余高度:${zoomFile.viewHeight - (zoomFile.actualHeight! * useZoom.value)}");
// var topDistance = (zoomFile!.viewHeight - (zoomFile.actualHeight! * useZoom.value)) / 2;
var topDistance = zoomFile!.getZoomFileOffsetStart(useZoom.value);
// print("视图剩余高度/2${max(0, topDistance)}");
// 使 max topDistance 0
usePiddingTop.value = max(0, topDistance);
});
return () {
stream.cancel();
};
}, []);
var actualImgHeight = useState(sateZoomData.zoomFile.value?.actualHeight);
useValueChanged<double?, void>(sateZoomData.zoomFile.value?.actualHeight, (_, __) {
actualImgHeight.value = sateZoomData.zoomFile.value?.actualHeight ?? 0;
});
useEffect(() {
scrollControllerNum.addListener(() {
if (sateData.panQuestView == false) sateData.slide.value = scrollControllerNum.offset;
});
var listenVal = sateData.slide.listen((e) {
if (sateData.panQuestView != null && sateData.panQuestView == true && e != scrollControllerNum.offset) {
print("进来了试题题号视图");
scrollControllerNum.jumpTo(e);
}
});
return () {
listenVal.cancel();
};
}, []);
// var actualImgHeight = useImageInfo.value?.actualImgHeight ?? 0; //
// print("图片高度:$actualImgHeight");
print("数据长度:${studentQuestions.length}");
print("FFFFFFFFF ${usePiddingTop.value}");
return SingleChildScrollView(
controller: scrollControllerNum,
physics: const BouncingScrollPhysics(),
padding: EdgeInsets.only(top: usePiddingTop.value > 0 ? usePiddingTop.value : 0),
scrollDirection: Axis.vertical, //
child: SizedBox(
height: (actualImgHeight.value ?? 0) * useZoom.value,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: studentQuestions
.map((e) => $ScoringQuestionsView(
studentQuestions,
e,
controller,
sateZoomData.zoomFile.value!.scaleRatio,
useZoom.value,
))
.toList(),
),
),
);
}
//
@hwidget
Widget $scoringQuestionsView(BuildContext context, List<StudentQuestions>? studentQuestions,StudentQuestions item, HomeworkReviewLogic logic, double scaleRatio, double initScale) {
var studentScore = useState<int?>(item.studentScore);
useValueChanged<int?, void>(studentScore.value, (_, __) {
item.studentScore = studentScore.value;
//
var annotateTime = logic.state.data.value?.annotateTime;
if (annotateTime == null) {
var noRatingGiven = studentQuestions!.firstWhereOrNull((e) => e.studentScore == null);
if (noRatingGiven == null) logic.submit(context);
}
});
useValueChanged<StudentQuestions, void>(item, (_, __) {
studentScore.value = item.studentScore;
});
useEffect(() {
return () {};
}, []);
var padinVal = item.correctRate > 0 ? EdgeInsets.only(top: 6.4.h) : EdgeInsets.symmetric(vertical: 2.h);
return Container(
height: item.height! * scaleRatio * initScale,
padding: EdgeInsets.zero,
child: item.useTime == 0
? Container()
: Stack(
alignment: const FractionalOffset(0, 0),
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
backgroundColor: const Color.fromRGBO(237, 237, 237, 1), //
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), //
),
child: Padding(
padding: padinVal,
child: Icon(
size: 22.sp,
color: studentScore.value == 2 ? Colors.green : const Color.fromRGBO(114, 114, 114, 1),
const IconData(0xe62b, fontFamily: "AlibabaIcon"),
),
),
onPressed: () => easyThrottle('scoring_homework_questions', () {
studentScore.value = studentScore.value == 2 ? null : 2;
}, duration: const Duration(milliseconds: 222)),
),
),
//
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
backgroundColor: const Color.fromRGBO(237, 237, 237, 1), //
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), //
),
child: Padding(
padding: padinVal,
child: Icon(
size: 22.sp,
color: studentScore.value == 1 ? Colors.green : const Color.fromRGBO(114, 114, 114, 1),
const IconData(0xe62c, fontFamily: "AlibabaIcon"),
),
),
onPressed: () => easyThrottle('scoring_homework_questions', () {
studentScore.value = studentScore.value == 1 ? null : 1;
}, duration: const Duration(milliseconds: 222)),
),
),
//
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
backgroundColor: const Color.fromRGBO(237, 237, 237, 1), //
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), //
),
child: Padding(
padding: padinVal,
child: Icon(
size: 22.sp,
color: studentScore.value == 0 ? Colors.green : const Color.fromRGBO(114, 114, 114, 1),
const IconData(0xe62a, fontFamily: "AlibabaIcon"),
),
),
onPressed: () => easyThrottle('scoring_homework_questions', () {
studentScore.value = studentScore.value == 0 ? null : 0;
}, duration: const Duration(milliseconds: 222)),
),
),
],
),
IgnorePointer(
// 穿
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(width: 1.1.w),
quickText(item.questionNo, color: Theme.of(context).primaryColor.withOpacity(0.7), size: 8.sp),
if (item.correctRate > 0) quickText(' 正确率', color: Colors.grey, size: 5.sp),
if (item.correctRate > 0)
Expanded(
child: LinearPercentIndicator(
lineHeight: 6.h,
percent: item.correctRate / 100,
barRadius: Radius.circular(1.2.r),
alignment: MainAxisAlignment.center,
progressColor: Theme.of(context).primaryColor,
backgroundColor: const Color(0xFFB8C7CB).withOpacity(0.35),
center: quickText("${item.correctRate}%", size: 5.sp, align: TextAlign.center, color: Colors.white),
),
)
],
),
),
],
),
);
}

View File

@ -13,20 +13,24 @@ import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.d
import 'package:making_school_asignment_app/common/utils/cached_network_img.dart'; import 'package:making_school_asignment_app/common/utils/cached_network_img.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart'; import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart';
import 'package:zoom_widget/zoom_widget.dart'; import 'package:percent_indicator/linear_percent_indicator.dart';
import '../configuration_files/zoom_logic.dart'; import 'dropdown_switch_students_type.dart';
import 'question_number_view.dart';
part 'question_paper_view.g.dart'; part 'question_paper_view.g.dart';
// //
class QuestionPaperView extends GetView<HomeworkReviewLogic> { class QuestionPaperView extends StatefulWidget {
const QuestionPaperView({super.key}); const QuestionPaperView({super.key});
HomeworkReviewState get sateData => controller.state; @override
ZoomState get zoomState => controller.zoomLogic.zoomState; State<QuestionPaperView> createState() => _QuestionPaperViewState();
HomeworkReviewAnnotationsControlState get annotationState => controller.annotationState; }
class _QuestionPaperViewState extends State<QuestionPaperView> {
final logic = Get.find<HomeworkReviewLogic>();
final sateData = Get.find<HomeworkReviewLogic>().state;
final annotationState = Get.find<HomeworkReviewLogic>().annotationState;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -37,29 +41,15 @@ class QuestionPaperView extends GetView<HomeworkReviewLogic> {
// //
Expanded( Expanded(
flex: 7, flex: 7,
child: Obx(() { child: LayoutBuilder(
ZoomFileModel? zoomFileModel = zoomState.zoomFile.value; builder: (BuildContext context, BoxConstraints constraints) {
var maxWidth = constraints.maxWidth;
if (zoomFileModel == null) { var maxHeight = constraints.maxHeight;
///
return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
WidgetsBinding.instance.addPostFrameCallback((_) => zoomState.zoomFile.value = ZoomFileModel(
viewWidth: constraints.maxWidth,
viewHeight: constraints.maxHeight,
));
return const SizedBox();
});
}
///
if (zoomFileModel.fileHeight == null) return const SizedBox();
var maxWidth = zoomFileModel.viewWidth;
var maxHeight = zoomFileModel.viewHeight;
return Stack( return Stack(
children: [ children: [
// //
QuestionImageView(maxWidth, maxHeight, annotationState, controller, zoomState: zoomState, sateData: sateData, actualHeight: zoomFileModel.actualHeight!), QuestionImageView(
maxWidth, maxHeight, sateData, annotationState, logic),
// //
// Positioned(right: 3.w, bottom: 4.h, child: const $ContinueToReview(isFloatingAction: true)), // Positioned(right: 3.w, bottom: 4.h, child: const $ContinueToReview(isFloatingAction: true)),
// //
@ -73,15 +63,19 @@ class QuestionPaperView extends GetView<HomeworkReviewLogic> {
heroTag: '点击前往上一题', heroTag: '点击前往上一题',
tooltip: '点击前往上一题', tooltip: '点击前往上一题',
focusColor: Theme.of(context).primaryColor, focusColor: Theme.of(context).primaryColor,
backgroundColor: const Color.fromRGBO(24, 32, 32, 0.05), backgroundColor:
const Color.fromRGBO(24, 32, 32, 0.05),
elevation: 10.r, elevation: 10.r,
onPressed: () => easyThrottle('TestQuestionSwitch', () { onPressed: () =>
easyThrottle('TestQuestionSwitch', () {
var param = sateData.param.value; var param = sateData.param.value;
param.studentId = lastPageVal.studentId; param.studentId = lastPageVal.studentId;
param.templateId = lastPageVal.templateId; param.templateId = lastPageVal.templateId;
sateData.param.value = DoPaperDetailsParam.fromJson(param.toJson()); sateData.param.value =
DoPaperDetailsParam.fromJson(param.toJson());
}), }),
child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp), child: Icon(Icons.arrow_back_ios,
color: Colors.white, size: 22.sp),
); );
}), }),
), ),
@ -92,19 +86,22 @@ class QuestionPaperView extends GetView<HomeworkReviewLogic> {
child: Obx(() { child: Obx(() {
NextPage? nextPageVal = sateData.data.value?.nextPage; NextPage? nextPageVal = sateData.data.value?.nextPage;
if (nextPageVal == null) return const SizedBox(); if (nextPageVal == null) return const SizedBox();
return FloatingActionButton( return FloatingActionButton(
heroTag: '点击前往下一题', heroTag: '点击前往下一题',
tooltip: '点击前往下一题', tooltip: '点击前往下一题',
elevation: 10.r, elevation: 10.r,
backgroundColor: const Color.fromRGBO(24, 32, 32, 0.05), backgroundColor:
onPressed: () => easyThrottle('TestQuestionSwitch', () { const Color.fromRGBO(24, 32, 32, 0.05),
onPressed: () =>
easyThrottle('TestQuestionSwitch', () {
var param = sateData.param.value; var param = sateData.param.value;
param.studentId = nextPageVal.studentId; param.studentId = nextPageVal.studentId;
param.templateId = nextPageVal.templateId; param.templateId = nextPageVal.templateId;
sateData.param.value = DoPaperDetailsParam.fromJson(param.toJson()); sateData.param.value =
DoPaperDetailsParam.fromJson(param.toJson());
}), }),
child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp), child: Icon(Icons.arrow_forward_ios,
color: Colors.white, size: 22.sp),
); );
}), }),
), ),
@ -115,44 +112,32 @@ class QuestionPaperView extends GetView<HomeworkReviewLogic> {
}), }),
), ),
// //
const Expanded(flex: 2, child: QuestionNumberView()), Expanded(flex: 2, child: $QuestionNumberView(logic, sateData)),
], ],
), ),
Obx(() {
if (!sateData.getDataError.value) return const SizedBox();
/// return Center(
const DataErrorThenRequestAgainButton(), child: CupertinoButton(
color: Colors.grey[300],
onPressed: () => easyThrottle('home_work_reload_data', () {
sateData.param.value =
DoPaperDetailsParam.fromJson(sateData.param.value.toJson());
}),
child: quickText('重新请求', color: Colors.black38),
),
);
}),
], ],
); );
} }
} }
///
class DataErrorThenRequestAgainButton extends StatelessWidget {
const DataErrorThenRequestAgainButton({super.key});
@override
Widget build(BuildContext context) {
return GetBuilder<HomeworkReviewLogic>(builder: (logic) {
final sateData = logic.state;
if (!sateData.getDataError.value) return const SizedBox();
return Center(
child: CupertinoButton(
color: Colors.grey[300],
onPressed: () => easyThrottle('home_work_reload_data', () {
sateData.param.value = DoPaperDetailsParam.fromJson(sateData.param.value.toJson());
}),
child: quickText('再次请求', color: Colors.black38),
),
);
});
}
}
// //
@swidget @swidget
Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData) { Widget $totalSubmitCountView(
BuildContext context, HomeworkReviewState sateData) {
return Obx(() { return Obx(() {
var data = sateData.data.value; var data = sateData.data.value;
if (data == null) return Container(); if (data == null) return Container();
@ -167,7 +152,10 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
context: context, context: context,
elevation: 10, elevation: 10,
backgroundColor: Colors.white, backgroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(10.r), topRight: Radius.circular(10.r))), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.r),
topRight: Radius.circular(10.r))),
builder: (BuildContext context) { builder: (BuildContext context) {
return Padding( return Padding(
padding: EdgeInsets.symmetric(horizontal: 2.w), padding: EdgeInsets.symmetric(horizontal: 2.w),
@ -185,7 +173,8 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
SizedBox(height: 10.h), SizedBox(height: 10.h),
Expanded( Expanded(
child: ListView( child: ListView(
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 4.w), padding: EdgeInsets.symmetric(
vertical: 8.h, horizontal: 4.w),
children: [ children: [
Wrap( Wrap(
spacing: 7.2.w, // () spacing: 7.2.w, // ()
@ -196,27 +185,39 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
alignment: const FractionalOffset(0.05, 0.09), alignment: const FractionalOffset(0.05, 0.09),
children: [ children: [
Container( Container(
padding: EdgeInsets.only(top: 1.2.h, bottom: 1.5.h, left: 13.w, right: 5.w), padding: EdgeInsets.only(
top: 1.2.h,
bottom: 1.5.h,
left: 13.w,
right: 5.w),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.r), borderRadius: BorderRadius.circular(4.r),
color: const Color.fromRGBO(239, 242, 255, 1), color: const Color.fromRGBO(
239, 242, 255, 1),
), ),
child: quickText( child: quickText(
e.name, e.name,
size: 12.sp, size: 12.sp,
wordSpacing: 2, wordSpacing: 2,
color: const Color.fromRGBO(80, 94, 110, 1), color:
const Color.fromRGBO(80, 94, 110, 1),
), ),
), ),
Stack( Stack(
alignment: const FractionalOffset(0.52, 0.24), alignment:
const FractionalOffset(0.52, 0.24),
children: [ children: [
Icon( Icon(
const IconData(0xe63d, fontFamily: "AlibabaIcon"), const IconData(0xe63d,
fontFamily: "AlibabaIcon"),
size: 12.sp, size: 12.sp,
color: e.isPriority ? Theme.of(context).primaryColor : const Color.fromRGBO(164, 164, 164, 1), color: e.isPriority
? Theme.of(context).primaryColor
: const Color.fromRGBO(
164, 164, 164, 1),
), ),
quickText('优先', size: 4.sp, color: Colors.white), quickText('优先',
size: 4.sp, color: Colors.white),
], ],
), ),
], ],
@ -238,11 +239,17 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
children: [ children: [
Padding( Padding(
padding: EdgeInsets.only(bottom: 1.h), padding: EdgeInsets.only(bottom: 1.h),
child: quickText('已阅', color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp), child: quickText('已阅',
color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp),
), ),
quickText(data.annotatedCount, color: Theme.of(context).primaryColor, size: 12.sp, fontWeight: FontWeight.bold), quickText(data.annotatedCount,
quickText('/', color: const Color.fromRGBO(117, 117, 117, 1), size: 12.sp), color: Theme.of(context).primaryColor,
quickText(data.submitCount - data.annotatedCount, color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp), size: 12.sp,
fontWeight: FontWeight.bold),
quickText('/',
color: const Color.fromRGBO(117, 117, 117, 1), size: 12.sp),
quickText(data.submitCount - data.annotatedCount,
color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp),
], ],
), ),
), ),
@ -250,16 +257,245 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
}); });
} }
//
@hwidget
Widget $questionNumberView(BuildContext context, HomeworkReviewLogic logic,
HomeworkReviewState sateData) {
final scrollControllerNum = useScrollController(); //
useEffect(() {
scrollControllerNum.addListener(() {
if (sateData.panQuestView == false)
sateData.slide.value = scrollControllerNum.offset;
});
var listenVal = sateData.slide.listen((e) {
if (e != scrollControllerNum.offset && sateData.panQuestView == true)
scrollControllerNum.jumpTo(e);
});
return () {
listenVal.cancel();
};
}, []);
return Container(
height: double.infinity,
decoration: BoxDecoration(
color: const Color.fromRGBO(159, 159, 159, 0.97),
boxShadow: [
BoxShadow(
color: const Color.fromRGBO(46, 91, 255, 0.2),
offset: Offset(0, 8.w), //y轴偏移量
blurRadius: 1, //
spreadRadius: 2, //
)
],
),
child: GestureDetector(
onPanDown: (_) => sateData.panQuestView = false,
child: SingleChildScrollView(
controller: scrollControllerNum,
physics: const BouncingScrollPhysics(),
padding: EdgeInsets.zero,
scrollDirection: Axis.vertical, //
child: Obx(() {
var imageVal = sateData.imageScale.value;
if (imageVal == null) return const SizedBox();
var studentQuestions = sateData.studentQuestions.value;
var boxHeight = imageVal.boxHeight;
var actualImgHeight = imageVal.actualImgHeight; //
return Container(
height: boxHeight > actualImgHeight ? boxHeight : actualImgHeight,
padding: EdgeInsets.only(
top: imageVal.remainingHeight > 0
? imageVal.remainingHeight / 2
: 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: studentQuestions
?.asMap()
.keys
.map((e) => $ScoringQuestionsView(
logic,
studentQuestions[e],
imageVal.scaleRatio,
studentQuestions))
.toList() ??
[],
),
);
}),
)),
);
}
//
@hwidget
Widget $scoringQuestionsView(
BuildContext context,
HomeworkReviewLogic logic,
StudentQuestions item,
double scaleRatio,
List<StudentQuestions>? studentQuestions) {
var studentScore = useState<int?>(item.studentScore);
useValueChanged<int?, void>(studentScore.value, (_, __) {
item.studentScore = studentScore.value;
//
var annotateTime = logic.state.data.value?.annotateTime;
if (annotateTime == null) {
var noRatingGiven =
studentQuestions!.firstWhereOrNull((e) => e.studentScore == null);
if (noRatingGiven == null) logic.submit(context);
}
});
useValueChanged<StudentQuestions, void>(item, (_, __) {
studentScore.value = item.studentScore;
});
useEffect(() {
return () {};
}, []);
var padinVal = item.correctRate > 0
? EdgeInsets.only(top: 6.4.h)
: EdgeInsets.symmetric(vertical: 2.h);
return Container(
height: item.height! * scaleRatio,
padding: EdgeInsets.zero,
child: item.useTime == 0?Container():Stack(
alignment: const FractionalOffset(0, 0),
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
backgroundColor:
const Color.fromRGBO(237, 237, 237, 1), //
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero), //
),
child: Padding(
padding: padinVal,
child: Icon(
size: 22.sp,
color: studentScore.value == 2
? const Color(0xFF54971F)
: const Color.fromRGBO(114, 114, 114, 1),
const IconData(0xe62b, fontFamily: "AlibabaIcon"),
),
),
onPressed: () => easyThrottle('scoring_homework_questions', () {
studentScore.value = studentScore.value == 2 ? null : 2;
}, duration: const Duration(milliseconds: 222)),
),
),
//
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
backgroundColor:
const Color.fromRGBO(237, 237, 237, 1), //
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero), //
),
child: Padding(
padding: padinVal,
child: Icon(
size: 22.sp,
color: studentScore.value == 1
? const Color(0xFF54971F)
: const Color.fromRGBO(114, 114, 114, 1),
const IconData(0xe62c, fontFamily: "AlibabaIcon"),
),
),
onPressed: () => easyThrottle('scoring_homework_questions', () {
studentScore.value = studentScore.value == 1 ? null : 1;
}, duration: const Duration(milliseconds: 222)),
),
),
//
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
backgroundColor:
const Color.fromRGBO(237, 237, 237, 1), //
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.zero), //
),
child: Padding(
padding: padinVal,
child: Icon(
size: 22.sp,
color: studentScore.value == 0
? const Color(0xFF54971F)
: const Color.fromRGBO(114, 114, 114, 1),
const IconData(0xe62a, fontFamily: "AlibabaIcon"),
),
),
onPressed: () => easyThrottle('scoring_homework_questions', () {
studentScore.value = studentScore.value == 0 ? null : 0;
}, duration: const Duration(milliseconds: 222)),
),
),
],
),
IgnorePointer(
// 穿
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(width: 1.1.w),
quickText('${item.questionNo}',
color: Theme.of(context).primaryColor.withOpacity(0.7),
size: 8.sp),
if (item.correctRate > 0)
quickText(' 正确率', color: Colors.grey, size: 5.sp),
if (item.correctRate > 0)
Expanded(
child: LinearPercentIndicator(
lineHeight: 6.h,
percent: item.correctRate / 100,
barRadius: Radius.circular(1.2.r),
alignment: MainAxisAlignment.center,
progressColor: Theme.of(context).primaryColor,
backgroundColor: const Color(0xFFB8C7CB).withOpacity(0.35),
center: quickText("${item.correctRate}%",
size: 5.sp,
align: TextAlign.center,
color: Colors.white),
),
)
],
),
),
],
),
);
}
// //
class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar> { class QuestionImageView extends HookWidget
with EventBusMixin<BottomOperationBar> {
final double maxWidth; final double maxWidth;
final double maxHeight; final double maxHeight;
final double actualHeight;
final HomeworkReviewLogic logic; final HomeworkReviewLogic logic;
final ZoomState zoomState;
final HomeworkReviewState sateData; final HomeworkReviewState sateData;
final HomeworkReviewAnnotationsControlState annotationState; final HomeworkReviewAnnotationsControlState annotationState;
QuestionImageView(this.maxWidth, this.maxHeight, this.annotationState, this.logic, {required this.actualHeight, required this.zoomState, required this.sateData, super.key}); QuestionImageView(this.maxWidth, this.maxHeight, this.sateData,
this.annotationState, this.logic,
{super.key});
/// ///
int _findTargetIndex<T>(List<T> list, T target, [int reciprocal = 2]) { int _findTargetIndex<T>(List<T> list, T target, [int reciprocal = 2]) {
@ -273,47 +509,37 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
return -1; return -1;
} }
int _activePointers = 0; int activePointers = 0;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theMaxHeight = useState<double>(maxHeight); final scrollControllerQuestion = useScrollController(); //
useValueChanged<double, void>(maxHeight, (oldValue, __) => theMaxHeight.value = maxHeight);
var zoomKey = useState<GlobalKey>(GlobalKey());
useValueChanged<int?, void>(zoomState.zoomFile.value?.templateId, (old, __) {
zoomKey.value = GlobalKey();
});
var vnHandWritings = useValueNotifier<List<dynamic>>([]); var vnHandWritings = useValueNotifier<List<dynamic>>([]);
///
var initPosition = useState<Offset?>(null);
// var customPaintSize = useState<Size>(Size.zero);
useEffect(() { useEffect(() {
var listenStream = sateData.data.listen((e) { var listenStream = sateData.data.listen((e) {
// //
sateData.handwritings = []; sateData.handwritings = [];
vnHandWritings.value = sateData.handwritings; vnHandWritings.value = sateData.handwritings;
}); });
return () => listenStream.cancel();
var streamSubscriptionSlide = sateData.slide.listen((e) {
if (sateData.panQuestView != null && sateData.panQuestView == false && initPosition.value?.dy.abs().toInt().toDouble() != sateData.slide.value) {
if (sateData.zoomOffset != null) {
sateData.zoomOffset = Offset(sateData.zoomOffset!.dx, -sateData.slide.value);
}
initPosition.value = sateData.zoomOffset;
print("赋值 initPosition.value ${initPosition.value}");
}
});
return () {
listenStream.cancel();
streamSubscriptionSlide.cancel();
};
}, []); }, []);
ImageStream? imageStream;
var imageStreamListener = useState<ImageStreamListener>(
ImageStreamListener((ImageInfo info, bool _) {
WidgetsBinding.instance.addPostFrameCallback((_) {
sateData.imageScale.value = TestQuestionsImageInfo(
templateId: sateData.data.value?.templateId,
boxWidth: maxWidth,
boxHeight: maxHeight,
imageWidth: info.image.width.toDouble(),
imageHeight: info.image.height.toDouble(),
url: sateData.data.value!.zgtAnswer,
);
});
}));
// //
useEffect(() { useEffect(() {
eventOn(callback: (BottomOperationBar e) async { eventOn(callback: (BottomOperationBar e) async {
@ -322,9 +548,19 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
// //
if (annotationsData.isNotEmpty) { if (annotationsData.isNotEmpty) {
bool? res = await showDialog<bool>( bool? res = await showDialog<bool>(
context: Get.context ?? context, context: context,
builder: (context1) { builder: (context1) {
return AlertDialog(content: quickText("是否撤销全部批注痕迹?"), actions: <Widget>[TextButton(child: quickText("取消"), onPressed: () => Navigator.pop(context1, false)), TextButton(child: quickText("确定", color: Theme.of(context1).primaryColor), onPressed: () => Navigator.pop(context1, true))]); return AlertDialog(
content: quickText("是否撤销全部批注痕迹?"),
actions: <Widget>[
TextButton(
child: quickText("取消"),
onPressed: () => Navigator.pop(context1, false)),
TextButton(
child: quickText("确定",
color: Theme.of(context).primaryColor),
onPressed: () => Navigator.pop(context1, true))
]);
}, },
); );
if (res == true) vnHandWritings.value = []; if (res == true) vnHandWritings.value = [];
@ -334,17 +570,22 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
await showDialog<bool>( await showDialog<bool>(
context: context, context: context,
builder: (context1) { builder: (context1) {
return AlertDialog(content: quickText("是否撤销上次批阅批注痕迹?"), actions: <Widget>[ return AlertDialog(
TextButton(child: quickText("取消"), onPressed: () => Navigator.pop(context1, false)), content: quickText("是否撤销上次批阅批注痕迹?"),
TextButton( actions: <Widget>[
child: quickText("确定", color: Theme.of(context).primaryColor), TextButton(
onPressed: () { child: quickText("取消"),
Navigator.pop(context1, true); onPressed: () => Navigator.pop(context1, false)),
sateData.data.value?.zgtAnnotate = null; TextButton(
sateData.data.value?.showZgtAnnotate = null; child: quickText("确定",
}, color: Theme.of(context).primaryColor),
) onPressed: () {
]); Navigator.pop(context1, true);
sateData.data.value?.zgtAnnotate = null;
sateData.data.value?.showZgtAnnotate = null;
},
)
]);
}, },
); );
} }
@ -359,17 +600,22 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
await showDialog<bool>( await showDialog<bool>(
context: context, context: context,
builder: (context1) { builder: (context1) {
return AlertDialog(content: quickText("是否撤销上次批阅批注痕迹?"), actions: <Widget>[ return AlertDialog(
TextButton(child: quickText("取消"), onPressed: () => Navigator.pop(context1, false)), content: quickText("是否撤销上次批阅批注痕迹?"),
TextButton( actions: <Widget>[
child: quickText("确定", color: Theme.of(context).primaryColor), TextButton(
onPressed: () { child: quickText("取消"),
Navigator.pop(context1, true); onPressed: () => Navigator.pop(context1, false)),
sateData.data.value?.zgtAnnotate = null; TextButton(
sateData.data.value?.showZgtAnnotate = null; child: quickText("确定",
}, color: Theme.of(context).primaryColor),
) onPressed: () {
]); Navigator.pop(context1, true);
sateData.data.value?.zgtAnnotate = null;
sateData.data.value?.showZgtAnnotate = null;
},
)
]);
}, },
); );
} }
@ -385,107 +631,114 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
vnHandWritings.value = annotationsData; vnHandWritings.value = annotationsData;
}); });
scrollControllerQuestion.addListener(() {
sateData.slide.value = scrollControllerQuestion.offset;
}); //
var listenVal = sateData.slide.listen((e) {
if (e != scrollControllerQuestion.offset &&
sateData.panQuestView == false) scrollControllerQuestion.jumpTo(e);
});
//
return () { return () {
_activePointers = 0; activePointers = 0;
listenVal.cancel();
imageStream?.removeListener(imageStreamListener.value);
}; };
}, []); }, []);
print("++++++++++++++++++++++ ${theMaxHeight.value}"); return Container(
print("+++++ 位置:${initPosition.value}"); height: maxHeight,
// padding: EdgeInsets.only(bottom: 2.h, top: 2.h),
return Listener( alignment: Alignment.center,
behavior: HitTestBehavior.opaque,
onPointerDown: (PointerDownEvent event) {
//
//
_activePointers++;
sateData.panQuestView = true;
},
onPointerUp: (PointerUpEvent details) {
//
// activePointers--;
// globalPosition = null;
_activePointers--;
if (!annotationState.pen.value) return;
vnHandWritings.value.add(null); // 线
sateData.handwritings = vnHandWritings.value; //
},
onPointerMove: (PointerMoveEvent event) {
if (_activePointers != 1) return;
if (!annotationState.pen.value) return;
Offset localPosition = event.localPosition; //
var zoomFile = zoomState.zoomFile.value!;
// var imageHeightOffsetStart = zoomFile.imageHeightOffsetStart??0;
var imageHeightOffsetStart = zoomState.zoomFile.value!.getZoomFileOffsetStart(zoomState.initScale.value ?? 1);
print("位置:$localPosition; 图片所在位置:$imageHeightOffsetStart");
if (imageHeightOffsetStart == 0) return;
var dy = localPosition.dy;
print(zoomFile.getZoomFileHeightOffsetEnd(zoomState.initScale.value ?? 1));
if (dy < imageHeightOffsetStart || dy > zoomFile.getZoomFileHeightOffsetEnd(zoomState.initScale.value ?? 1)) return; //
var theScale = zoomState.initScale.value ?? 1;
// if (theScale != 1) {
// print("PPPPPPPPPPPPPPPPPPPPPPPP ${(zoomFile.imageHeightOffsetStart ?? 0)}");
// localPosition = Offset(localPosition.dx, localPosition.dy + (zoomFile.imageHeightOffsetStart ?? 0));
// // localPosition = Offset(localPosition.dx / theScale, localPosition.dy / theScale);
// // var theZoomOffset = sateData.zoomOffset;
// // if (theZoomOffset != null) {
// // var dx = theZoomOffset.dx;
// // var dy = theZoomOffset.dy;
// // localPosition = Offset(localPosition.dx + dx, localPosition.dy + dy);
// // }
// }
// - imageHeightOffsetStart
// if (theScale == 1) {
// }
localPosition = Offset((localPosition.dx+(sateData.zoomOffset?.dx.abs()??0)) / theScale, (dy / theScale) - (imageHeightOffsetStart/ theScale));
print("最终位置 $localPosition");
vnHandWritings.value = List.from(vnHandWritings.value)..add(localPosition);
sateData.handwritings = vnHandWritings.value;
},
child: Obx(() { child: Obx(() {
var isPen = annotationState.pen.value; var imageUrl = sateData.data.value?.zgtAnswer;
var showZgtAnnotate = sateData.data.value?.showZgtAnnotate; var showZgtAnnotate = sateData.data.value?.showZgtAnnotate;
if (imageUrl == null) return const SizedBox();
return Container( return GestureDetector(
height: double.infinity, onPanDown: (_) => sateData.panQuestView = true,
width: double.infinity, child: SingleChildScrollView(
alignment: Alignment.center, controller: scrollControllerQuestion,
child: IgnorePointer( physics: !annotationState.pen.value
ignoring: isPen, ? const BouncingScrollPhysics()
child: Zoom( : const NeverScrollableScrollPhysics(),
key: zoomKey.value, padding: EdgeInsets.zero,
initTotalZoomOut: true, // scrollDirection: Axis.vertical, //
zoomSensibility: 0.05, child: Container(
scrollWeight: 4.r, decoration: BoxDecoration(boxShadow: [
doubleTapAnimDuration: Duration.zero, BoxShadow(
maxZoomWidth: maxWidth, color: Colors.grey.withOpacity(0.2),
maxZoomHeight: actualHeight, offset: Offset(-6.r, 1.r),
canvasColor: Colors.transparent, blurRadius: 10.r,
// initPosition: initPosition.value, spreadRadius: 8.r)
// initScale: logic.zoomLogic.zoomState.initScale.value ?? 1, ]),
backgroundColor: Colors.transparent, child: Listener(
onScaleUpdate: logic.zoomLogic.onScaleUpdate, behavior: HitTestBehavior.opaque,
onPositionUpdate: logic.zoomLogic.onPanUpPosition, onPointerDown: (PointerDownEvent event) {
child: RepaintBoundary( //
key: logic.pictureOverviewKey,
child: CustomPaint( //
// isComplex: true, activePointers++;
// size: customPaintSize.value, },
foregroundPainter: DrawingPainter(ctrl: vnHandWritings), onPointerUp: (PointerUpEvent details) {
child: $TheCachedNetworkImage( //
imgWidth: maxWidth, // activePointers--;
imageUrl: showZgtAnnotate ?? sateData.data.value!.zgtAnswer, // globalPosition = null;
(_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth), activePointers--;
),
// child: showZgtAnnotate != null ? $TheCachedNetworkImage(imgWidth: maxWidth, imageUrl: showZgtAnnotate, (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth)) : null, var imageScale = sateData.imageScale.value;
if (imageScale == null || !annotationState.pen.value) return;
vnHandWritings.value.add(null); // 线
sateData.handwritings = vnHandWritings.value; //
},
onPointerMove: (PointerMoveEvent event) {
if (activePointers != 1) return;
var imageScale = sateData.imageScale.value;
if (imageScale == null || !annotationState.pen.value) return;
Offset localPosition = event.localPosition;
var dy = localPosition.dy;
if (dy > imageScale.actualImgHeight || dy < 0)
return; //
vnHandWritings.value = List.from(vnHandWritings.value)
..add(localPosition);
sateData.handwritings = vnHandWritings.value;
},
child: Stack(
children: [
$TheCachedNetworkImage(
imageUrl: imageUrl,
(context, imageProvider) {
Image imageWidget =
Image(image: imageProvider, fit: BoxFit.fitWidth);
imageStream?.removeListener(imageStreamListener.value);
imageStream = imageWidget.image
.resolve(const ImageConfiguration())
..addListener(imageStreamListener.value);
return imageWidget;
},
),
RepaintBoundary(
key: logic.pictureOverviewKey,
child: CustomPaint(
foregroundPainter: DrawingPainter(ctrl: vnHandWritings),
size: Size(
sateData.imageScale.value?.actualImgWidth ?? 0,
sateData.imageScale.value?.actualImgHeight ?? 0,
),
child: showZgtAnnotate != null
? $TheCachedNetworkImage(
imageUrl: showZgtAnnotate,
(_, imageProvider) => Image(
image: imageProvider, fit: BoxFit.fitWidth),
)
: null,
),
),
],
), ),
), ),
), ),
@ -502,7 +755,7 @@ class DrawingPainter extends CustomPainter {
final Paint paintBrush = Paint() final Paint paintBrush = Paint()
..color = Colors.red ..color = Colors.red
..strokeCap = StrokeCap.round ..strokeCap = StrokeCap.round
..strokeWidth = 0.75.sp; ..strokeWidth = 0.6.r;
DrawingPainter({required this.ctrl}) : super(repaint: ctrl); DrawingPainter({required this.ctrl}) : super(repaint: ctrl);
@override @override
@ -512,7 +765,8 @@ class DrawingPainter extends CustomPainter {
for (int i = 0; i < pointsLength; i++) { for (int i = 0; i < pointsLength; i++) {
Offset? offsetData = points[i]; Offset? offsetData = points[i];
Offset? nextOffsetData = pointsLength - 1 == i ? null : points[i + 1]; Offset? nextOffsetData = pointsLength - 1 == i ? null : points[i + 1];
if (offsetData != null && nextOffsetData != null) canvas.drawLine(offsetData, nextOffsetData, paintBrush); if (offsetData != null && nextOffsetData != null)
canvas.drawLine(offsetData, nextOffsetData, paintBrush);
} }
} }

View File

@ -2,7 +2,6 @@ import 'dart:async';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:device_info_plus/device_info_plus.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
@ -11,16 +10,11 @@ import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart'; import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart';
import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_result.dart'; import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_result.dart';
import 'package:making_school_asignment_app/common/job/marking_models/do_test_questions_image_info.dart'; import 'package:making_school_asignment_app/common/job/marking_models/do_test_questions_image_info.dart';
import 'package:making_school_asignment_app/common/job/marking_models/favor_param.dart';
import 'package:making_school_asignment_app/common/job/marking_models/review_submission_params.dart'; import 'package:making_school_asignment_app/common/job/marking_models/review_submission_params.dart';
import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart';
import 'package:making_school_asignment_app/common/utils/permission_describe_util.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/common/utils/upload_oss_img_utils.dart'; import 'package:making_school_asignment_app/common/utils/upload_oss_img_utils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:permission_handler/permission_handler.dart';
import 'zoom_logic.dart';
// //
class HomeworkReviewState { class HomeworkReviewState {
@ -32,18 +26,13 @@ class HomeworkReviewState {
late Rx<DoPaperDetailsResult?> data; late Rx<DoPaperDetailsResult?> data;
late Rx<List<StudentQuestions>?> studentQuestions; late Rx<List<StudentQuestions>?> studentQuestions;
late Rx<double> slide; // late Rx<double> slide; //
bool? panQuestView = null; late bool? panQuestView;
// late Rx<TestQuestionsImageInfo?> imageScale; late Rx<TestQuestionsImageInfo?> imageScale;
// late Rx<TestQuestionsImageInfo?> imageScaleZoom = Rx<TestQuestionsImageInfo?>(null);
///
List<dynamic> handwritings = []; List<dynamic> handwritings = [];
bool needRefresh = false; bool needRefresh = false;
bool lastQuestionPrompt = false; // bool lastQuestionPrompt = false; //
Rx<bool> getDataError = false.obs; // Rx<bool> getDataError = false.obs; //
Offset? zoomOffset;
RxBool favorite = false.obs; //
// late String dateEnd = ''; // late String dateEnd = '';
// late int knowledgeId = 0; // late int knowledgeId = 0;
// late RxList<KnowledgeReportDetail> dataList = RxList(); // late RxList<KnowledgeReportDetail> dataList = RxList();
@ -64,31 +53,20 @@ class HomeworkReviewAnnotationsControlState {
class HomeworkReviewBinding extends Bindings { class HomeworkReviewBinding extends Bindings {
@override @override
void dependencies() { void dependencies() => Get.lazyPut(() => HomeworkReviewLogic());
Get.lazyPut(() => HomeworkReviewLogic());
}
} }
class HomeworkReviewLogic extends GetxController with RequestToolMixin { class HomeworkReviewLogic extends GetxController with RequestToolMixin {
final zoomLogic = Get.find<ZoomLogic>();
final GlobalKey pictureOverviewKey = GlobalKey(); final GlobalKey pictureOverviewKey = GlobalKey();
late StreamSubscription<DoPaperDetailsParam> _paramListen; late StreamSubscription<DoPaperDetailsParam> _paramListen;
late StreamSubscription<DoPaperDetailsResult?> _dataListen; late StreamSubscription<DoPaperDetailsResult?> _dataListen;
final HomeworkReviewState state = HomeworkReviewState(); final HomeworkReviewState state = HomeworkReviewState();
final HomeworkReviewAnnotationsControlState annotationState = HomeworkReviewAnnotationsControlState(); final HomeworkReviewAnnotationsControlState annotationState =
double appBarHeight = 56; HomeworkReviewAnnotationsControlState();
StreamSubscription<TestQuestionsImageInfo?>? imageScaleZoomStream;
@override @override
void onInit() { void onInit() {
super.onInit();
appBarHeight = MediaQuery.of(Get.context!).padding.top;
print("appBarHeight $appBarHeight");
// WidgetsFlutterBinding.ensureInitialized();
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); //
state.param = DoPaperDetailsParam( state.param = DoPaperDetailsParam(
homeworkId: Get.arguments['homeworkId'], homeworkId: Get.arguments['homeworkId'],
homeworkName: Get.arguments['homeworkName'], homeworkName: Get.arguments['homeworkName'],
@ -97,69 +75,28 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
).obs; ).obs;
state.data = Rx<DoPaperDetailsResult?>(null); state.data = Rx<DoPaperDetailsResult?>(null);
state.studentQuestions = Rx<List<StudentQuestions>?>(null); state.studentQuestions = Rx<List<StudentQuestions>?>(null);
// state.imageScale = Rx<TestQuestionsImageInfo?>(null); state.imageScale = Rx<TestQuestionsImageInfo?>(null);
state.slide = 0.0.obs; state.slide = 0.0.obs;
getData();
// //
_paramListen = state.param.listen((e) => getData()); _paramListen = state.param.listen((e) => getData());
// //
_dataListen = state.data.listen((e) { _dataListen = state.data.listen((e) => state.imageScale.value = null);
if (e == null) return;
var zoomState = zoomLogic.zoomState;
state.studentQuestions.value = e.studentQuestions; //
final currentTemplateId = zoomState.zoomFile.value?.templateId; // ID
if (currentTemplateId != null && currentTemplateId != e.templateId) {
// zoom zoom文件
zoomState.initScale.value = null;
zoomState.zoomFile.value!.clearZoomFile(e.templateId);
zoomState.zoomFile.update((_) {}); //
}
if (state.favorite.value != e.isFav) state.favorite.value = !state.favorite.value;
});
// imageScaleZoomStream = state.imageScale.listen((e) {
// // state.imageScaleZoom.value = theImageScale;
// var theImageScaleZoom = state.imageScaleZoom.value;
// if (theImageScaleZoom == null || theImageScaleZoom.url != e?.url) state.imageScaleZoom.value = e;
// });
WidgetsBinding.instance.addPostFrameCallback((_) => getData());
super.onInit();
} }
@override @override
void onReady() { void disposeId(Object id) {
Future.delayed(Duration.zero, () {
DeviceInfoPlugin().androidInfo.then((androidInfo) {
Permission storagePermission = androidInfo.version.sdkInt >= 33 ? Permission.manageExternalStorage : Permission.storage;
PermissionDescribeUtil.instance.toLaunchPermissionRequest(
Get.context,
title: '储存权限请求',
describe: "为了提供更好的服务,需要获取到存储权限用于保存批阅痕迹并上传",
permissions: [storagePermission],
);
});
});
super.onReady();
}
@override
void onClose() {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]); //
_dataListen.cancel(); _dataListen.cancel();
_paramListen.cancel(); _paramListen.cancel();
imageScaleZoomStream?.cancel(); super.disposeId(id);
super.onClose();
} }
void getData() async { void getData() async {
var timerControl = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading()); var timerControl = Timer(
const Duration(milliseconds: 300), () => ToastUtils.showLoading());
try { try {
DoPaperDetailsResult? data = await getClient().getDoPaperDetails(state.param.value); DoPaperDetailsResult? data =
await getClient().getDoPaperDetails(state.param.value);
// var studentQuestions = data.studentQuestions; // var studentQuestions = data.studentQuestions;
// // 0 // // 0
// for (var i = 0; i < studentQuestions.length; i++) { // for (var i = 0; i < studentQuestions.length; i++) {
@ -168,14 +105,16 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
// item.topHeight = itemPre.height; // item.topHeight = itemPre.height;
// } // }
state.getDataError.value = false; state.getDataError.value = false;
state.handwritings = [];
state.data.value = data; state.data.value = data;
state.handwritings = [];
state.studentQuestions.value = data.studentQuestions;
} catch (e) { } catch (e) {
print('获取数据报错了:$e'); print('获取数据报错了:$e');
// ToastUtils.showError('获取试题数据,请重试'); ToastUtils.showError('获取试题数据出错,请重试');
state.getDataError.value = true; state.getDataError.value = true;
} finally { } finally {
if (timerControl.isActive) timerControl.cancel(); if (timerControl.isActive) timerControl.cancel();
ToastUtils.dismiss(); ToastUtils.dismiss();
} }
} }
@ -229,29 +168,41 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
if (data == null) return null; if (data == null) return null;
// OSS url // OSS url
String imgKey = UploadOssImgUtils.getInstance().setImgKey(param.homeworkId, data.studentId.toString(), data.templateId.toString()); String imgKey = UploadOssImgUtils.getInstance().setImgKey(
param.homeworkId,
data.studentId.toString(),
data.templateId.toString());
var resUrl = await getClient().getOssPresignedUri(imgKey); var resUrl = await getClient().getOssPresignedUri(imgKey);
if (resUrl == null) return null; if (resUrl == null) return null;
// //
RenderRepaintBoundary? boundary = pictureOverviewKey.currentContext!.findRenderObject() as RenderRepaintBoundary?; RenderRepaintBoundary? boundary = pictureOverviewKey.currentContext!
.findRenderObject() as RenderRepaintBoundary?;
if (boundary == null) return null; if (boundary == null) return null;
// double dpr = MediaQuery.of(context).devicePixelRatio; // double dpr = MediaQuery.of(context).devicePixelRatio;
/// double pixelRatio = MediaQuery.of(context).devicePixelRatio;
double? pixelRatio = zoomLogic.zoomState.zoomFile.value?.scaleRatio ?? MediaQuery.of(context).devicePixelRatio; var imageScale = state.imageScale.value;
if (imageScale != null) {
//
pixelRatio = imageScale.imageWidth / imageScale.boxWidth;
}
ui.Image image = await boundary.toImage(pixelRatio: pixelRatio); ui.Image image = await boundary.toImage(pixelRatio: pixelRatio);
ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png); ByteData? byteData =
await image.toByteData(format: ui.ImageByteFormat.png);
if (byteData == null) return null; if (byteData == null) return null;
Dio dio = Dio(); Dio dio = Dio();
dio.options.contentType = null; dio.options.contentType = null;
List<int> bytes = byteData.buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes); List<int> bytes = byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes);
await dio.put( await dio.put(
resUrl, resUrl,
data: Stream.fromIterable(bytes.map((e) => [e])), data: Stream.fromIterable(bytes.map((e) => [e])),
options: Options(contentType: null, headers: {Headers.contentLengthHeader: bytes.length}), options: Options(
contentType: null,
headers: {Headers.contentLengthHeader: bytes.length}),
); );
return imgKey; return imgKey;
@ -273,7 +224,8 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
if (state.data.value?.studentQuestions.isEmpty ?? true) return; if (state.data.value?.studentQuestions.isEmpty ?? true) return;
var studentQuestions = state.data.value!.studentQuestions; var studentQuestions = state.data.value!.studentQuestions;
var noRatingElement = studentQuestions.firstWhereOrNull((e) => e.studentScore == null); var noRatingElement =
studentQuestions.firstWhereOrNull((e) => e.studentScore == null);
if (noRatingElement != null) { if (noRatingElement != null) {
ToastUtils.showInfo('${noRatingElement.questionNo}题请评分'); ToastUtils.showInfo('${noRatingElement.questionNo}题请评分');
return; return;
@ -341,22 +293,4 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
state.param.value = newParams; state.param.value = newParams;
}); });
} }
Future<void> toFavorite() async {
try {
var data = state.data.value!;
var param = state.param.value;
await getClient().toFavStudent(FavorParam(
homeworkId: param.homeworkId,
studentId: data.studentId,
templateId: data.templateId,
questionNo: data.studentQuestions[0].questionNo,
isFav: !data.isFav,
));
state.favorite.value = !data.isFav;
data.isFav = state.favorite.value;
} catch (e) {
ToastUtils.showError('操作失败,请重试');
}
}
} }

View File

@ -1,262 +0,0 @@
import 'dart:ui' show ImmutableBuffer, ImageDescriptor;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart' as anti_shake_throttling;
import 'package:flutter/widgets.dart';
import 'dart:async';
import 'package:get/get.dart';
import 'package:json_annotation/json_annotation.dart';
import 'index.dart';
part 'zoom_logic.g.dart';
class ZoomLogic extends GetxController {
ZoomState zoomState = ZoomState(
initScale: Rx<double?>(null),
zoomFile: Rx<ZoomFileModel?>(null),
);
var oldTemplateId;
late StreamSubscription _streamHomework;
late StreamSubscription _streamZoomState;
StreamSubscription<double?>? initScaleStream;
@override
void onInit() {
oldTemplateId = zoomState.zoomFile.value?.templateId;
///
_streamZoomState = zoomState.zoomFile.listen((e) {
var templateId = e?.templateId;
print("ZOOMFILE 变化了 $templateId");
if (templateId == null) return;
var homeworkData = Get.find<HomeworkReviewLogic>().state.data.value;
var zgtAnswer = homeworkData?.zgtAnswer;
print("333333");
if (zgtAnswer == null) return;
print("444444 ${homeworkData!.templateId}${templateId}");
if (oldTemplateId == templateId) return;
// getNetworkImageDimensions(zgtAnswer);
//
oldTemplateId = templateId;
print("获取图片尺寸....");
CachedNetworkImageProvider(zgtAnswer).getImageSize().then((s) {
//
if (s == null) return;
var oldVal = zoomState.zoomFile.value!;
oldVal.fileWidth = s.width;
oldVal.fileHeight = s.height;
zoomState.zoomFile.value = ZoomFileModel.fromJson(oldVal.toJson());
});
});
WidgetsBinding.instance.addPostFrameCallback((e) {
///
_streamHomework = Get.find<HomeworkReviewLogic>().state.data.listen((e) {
print("HOMEWORKSTATE 变化了");
if (e == null || zoomState.zoomFile.value == null) return;
zoomState.zoomFile.value!.templateId = e.templateId;
print("666666 ${e.templateId}");
zoomState.zoomFile.value = ZoomFileModel.fromJson(zoomState.zoomFile.value!.toJson());
});
});
///
initScaleStream = zoomState.initScale.listen((e) {});
super.onInit();
}
@override
void onClose() {
_streamHomework.cancel();
_streamZoomState.cancel();
super.onClose();
}
// ==>
void onScaleUpdate(double scale, double zoom) async {
print("$scale $zoom");
///
zoomState.initScale.value = zoom;
// anti_shake_throttling.debounce(() => zoomState.initScale.value = zoom, const Duration(milliseconds: 100))();
}
// ==>
void onPanUpPosition(Offset val) async {
//
var state = Get.find<HomeworkReviewLogic>().state;
if (state.zoomOffset?.dy.toStringAsFixed(2) != val.dy.toStringAsFixed(2) || state.zoomOffset?.dx.toStringAsFixed(2) != val.dx.toStringAsFixed(2)) {
// print('**************** 正在移动位置 YYY:${val.dy}');
// print('**************** 正在移动位置 XXX:${val.dx}');
state.zoomOffset = val;
state.slide.value = val.dy.abs().toInt().toDouble();
}
}
}
class HomeworkReviewZoomBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => ZoomLogic());
}
}
class ZoomState {
final Rx<double?> initScale;
final Rx<ZoomFileModel?> zoomFile;
const ZoomState({required this.zoomFile, required this.initScale});
}
@JsonSerializable()
class ZoomFileModel extends Object {
double viewWidth; //
double viewHeight; //
double scaleRatio; //
int? templateId; //
double? pixelRatio; //
double? fileWidth; //
double? fileHeight; //
double? actualWidth; //
double? actualHeight; //
double? remainingHeight; // .()
double? imageHeightOffsetStart; // Y
double? imageHeightOffsetend; // Y
ZoomFileModel({
required this.viewWidth,
required this.viewHeight,
this.scaleRatio = 1,
this.templateId,
this.fileWidth,
this.fileHeight,
this.actualWidth,
this.actualHeight,
this.remainingHeight,
this.imageHeightOffsetStart,
this.imageHeightOffsetend,
this.pixelRatio,
}) {
// .
if (fileHeight == null || fileWidth == null) return;
scaleRatio = viewWidth / fileWidth!;
actualWidth = fileWidth! * scaleRatio;
actualHeight = fileHeight! * scaleRatio;
pixelRatio = fileWidth! / viewWidth; //
remainingHeight = viewHeight - actualHeight!;
imageHeightOffsetStart = remainingHeight! / 2;
imageHeightOffsetend = imageHeightOffsetStart! + actualHeight!;
}
factory ZoomFileModel.fromJson(Map<String, dynamic> srcJson) => _$ZoomFileModelFromJson(srcJson);
Map<String, dynamic> toJson() => _$ZoomFileModelToJson(this);
// zoom文件templateId
ZoomFileModel clearZoomFile(int newTemplateId) {
templateId = newTemplateId; //
fileWidth = null; //
fileHeight = null; //
actualWidth = null; //
actualHeight = null; //
remainingHeight = null; // .()
imageHeightOffsetStart = null; // Y
imageHeightOffsetend = null; // Y
return this;
}
///
/// zoom
double getZoomFileOffsetStart(double zoom) {
if (zoom == 1 || actualHeight == null) return imageHeightOffsetStart ?? 0;
return (viewHeight - (actualHeight! * zoom)) / 2;
}
///
/// zoom
double getZoomFileHeightOffsetEnd(double zoom) {
if (zoom == 1 || actualHeight == null) return imageHeightOffsetend ?? 0;
var topSpaceDimensions = getZoomFileOffsetStart(zoom);
return topSpaceDimensions + (actualHeight! * zoom);
}
}
//
extension GetImageSize on ImageProvider {
Future<Size?> getImageSize({bool avoidDecode = false}) async {
if (avoidDecode) {
//
final cacheStatus = await obtainCacheStatus(configuration: const ImageConfiguration());
final tracked = cacheStatus?.tracked ?? false;
// ImageDescriptor
if (!tracked) {
ImmutableBuffer? buffer;
if (this is AssetBundleImageProvider) {
final key = await obtainKey(const ImageConfiguration()) as AssetBundleImageKey;
buffer = await key.bundle.loadBuffer(key.name);
} else if (this is FileImage) {
final file = (this as FileImage).file;
final int lengthInBytes = await file.length();
if (lengthInBytes > 0) {
buffer = await ImmutableBuffer.fromFilePath(file.path);
}
} else if (this is MemoryImage) {
final bytes = (this as MemoryImage).bytes;
buffer = await ImmutableBuffer.fromUint8List(bytes);
}
if (buffer != null) {
final descriptor = await ImageDescriptor.encoded(buffer);
final size = Size(descriptor.width.toDouble(), descriptor.height.toDouble());
buffer.dispose();
descriptor.dispose();
if (!size.isEmpty) return size;
}
}
}
//
final completer = Completer<Size?>();
ImageStream imageStream = resolve(const ImageConfiguration());
ImageStreamListener? listener;
listener = ImageStreamListener(
(imageInfo, synchronousCall) {
if (!completer.isCompleted) {
completer.complete(Size(imageInfo.image.width.toDouble(), imageInfo.image.height.toDouble()));
}
WidgetsBinding.instance.addPostFrameCallback((_) {
imageInfo.dispose();
imageStream.removeListener(listener!);
});
},
onError: (exception, stackTrace) {
if (!completer.isCompleted) {
completer.complete();
}
imageStream.removeListener(listener!);
},
);
imageStream.addListener(listener);
return completer.future;
}
}

View File

@ -5,52 +5,83 @@ import 'package:get/get.dart';
import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/page/home_page/children/annotate_class/annotate_class_logic.dart'; import 'package:making_school_asignment_app/page/home_page/children/annotate_class/annotate_class_logic.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/question_paper_view.dart';
import 'package:making_school_asignment_app/page/home_page/home_logic.dart'; import 'package:making_school_asignment_app/page/home_page/home_logic.dart';
import 'components/bottom_operation_bar.dart'; import 'components/bottom_operation_bar.dart';
import 'components/dropdown_switch_students_type.dart'; import 'components/dropdown_switch_students_type.dart';
import 'components/favorite_widget.dart'; import 'components/favorite_widget.dart';
import 'components/question_paper_view.dart';
import 'configuration_files/index.dart'; import 'configuration_files/index.dart';
class HomeworkReview extends StatelessWidget { class HomeworkReview extends StatefulWidget {
const HomeworkReview({super.key}); const HomeworkReview({super.key});
@override @override
Widget build(BuildContext context) { State<HomeworkReview> createState() => _HomeworkReviewState();
final logic = Get.find<HomeworkReviewLogic>(); }
final sateData = logic.state;
final AnnotateClassLogic controller = Get.find<AnnotateClassLogic>();
final HomeLogic homeLogicController = Get.find<HomeLogic>();
class _HomeworkReviewState extends State<HomeworkReview> {
final logic = Get.find<HomeworkReviewLogic>();
final sateData = Get.find<HomeworkReviewLogic>().state;
final AnnotateClassLogic _controller = Get.find<AnnotateClassLogic>();
final HomeLogic _homeLogicController = Get.find<HomeLogic>();
@override
void initState() {
WidgetsFlutterBinding.ensureInitialized();
super.initState();
}
@override
void dispose() {
Get.delete<HomeworkReviewLogic>();
super.dispose();
}
@override
Widget build(BuildContext context) {
return PopScope( return PopScope(
canPop: false, canPop: false,
onPopInvoked: (e) { onPopInvoked: (e) {
if (e && sateData.needRefresh) { if (e && sateData.needRefresh) {
controller.getList(); _controller.getList();
homeLogicController.getList(); _homeLogicController.getList();
} }
}, },
child: Scaffold( child: AnnotatedRegion(
appBar: AppBar( value: const SystemUiOverlayStyle(
// titleSpacing: 0, systemNavigationBarColor: Color(0xFF000000),
leading: IconButton(icon: const Icon(Icons.arrow_back_ios), onPressed: () => Get.back()), systemNavigationBarDividerColor: null,
iconTheme: const IconThemeData(color: Colors.black), statusBarColor: Colors.transparent,
title: quickText(sateData.param.value.homeworkName), systemNavigationBarIconBrightness: Brightness.light,
backgroundColor: Colors.white, statusBarIconBrightness: Brightness.light,
elevation: 0, statusBarBrightness: Brightness.light,
actions: [const FavoriteWidget(), SizedBox(width: 5.w), const ReturnToHomepage()],
), ),
body: const Column( child: SafeArea(
children: [ child: Scaffold(
// appBar: AppBar(
DropdownSwitchStudentsType(), // titleSpacing: 0,
// SizedBox(height: 10), leading: IconButton(icon: const Icon(Icons.arrow_back_ios), onPressed: () => Get.back()),
// iconTheme: const IconThemeData(color: Colors.black),
Expanded(child: QuestionPaperView()), title: quickText(sateData.param.value.homeworkName),
// backgroundColor: Colors.white,
BottomAnnotationSwitch() elevation: 0,
], actions: [const FavoriteWidget(), SizedBox(width: 5.w), const ReturnToHomepage()],
),
body: SafeArea(
child: Column(
children: [
//
const DropdownSwitchStudentsType(),
SizedBox(height: 1.h),
const Expanded(child: QuestionPaperView()),
const BottomAnnotationSwitch()
],
),
),
// floatingActionButton: const ButtonFloatingAction(),
// floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
),
), ),
), ),
); );

View File

@ -28,7 +28,7 @@ class _JobReportPageState extends State<JobReportPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return OrientationBuilder(builder: (BuildContext context, Orientation orientation) { return OrientationBuilder(builder: (BuildContext context, Orientation orientation) {
return Scaffold( return Scaffold(
backgroundColor: const Color.fromRGBO(245, 245, 245, 1), backgroundColor: Color.fromRGBO(245, 245, 245, 1),
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.white, backgroundColor: Colors.white,
centerTitle: true, centerTitle: true,

View File

@ -5,7 +5,7 @@ import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
class PersonnelDataOverview extends StatefulWidget { class PersonnelDataOverview extends StatefulWidget {
final List<Students> studentList; final List<Students> studentList;
const PersonnelDataOverview({super.key, required this.studentList}); const PersonnelDataOverview({Key? key, required this.studentList}) : super(key: key);
@override @override
State<PersonnelDataOverview> createState() => _PersonnelDataOverviewState(); State<PersonnelDataOverview> createState() => _PersonnelDataOverviewState();
@ -28,13 +28,13 @@ class _PersonnelDataOverviewState extends State<PersonnelDataOverview> {
var student = widget.studentList[i]; var student = widget.studentList[i];
TimeUnits timeUnits = convertMilliseconds(student.useTime!); TimeUnits timeUnits = convertMilliseconds(student.useTime!);
String timeerStr = ''; String timeerStr = '';
if (timeUnits.hours > 0) timeerStr = '${timeUnits.hours}:'; if (timeUnits.hours > 0) timeerStr = timeUnits.hours.toString() + ':';
if (timeUnits.minutes > 0) timeerStr += '${timeUnits.minutes}:'; if (timeUnits.minutes > 0) timeerStr += timeUnits.minutes.toString() + ':';
timeerStr += timeUnits.seconds.toString(); timeerStr += timeUnits.seconds.toString();
names.add(student.studentName); names.add(student.studentName);
useTimes.add(timeerStr); useTimes.add(timeerStr);
correctRates.add('${student.okRate!.toStringAsFixed(0)}%'); correctRates.add(student.okRate!.toStringAsFixed(0) + '%');
noAnswerCounts.add(student.noAnswerCount.toString()); noAnswerCounts.add(student.noAnswerCount.toString());
rankings.add('${i + 1}'); rankings.add('${i + 1}');
} }
@ -60,7 +60,7 @@ class _PersonnelDataOverviewState extends State<PersonnelDataOverview> {
children: [ children: [
Container( Container(
margin: EdgeInsets.only(bottom: 20.h), margin: EdgeInsets.only(bottom: 20.h),
child: quickText('人员数据概况', color: const Color.fromRGBO(92, 92, 92, 1), size: 14.sp, fontWeight: FontWeight.bold), child: quickText('人员数据概况', color: Color.fromRGBO(92, 92, 92, 1), size: 14.sp, fontWeight: FontWeight.bold),
), ),
Scrollbar( Scrollbar(
thickness: 8.w, thickness: 8.w,
@ -88,7 +88,7 @@ class _PersonnelDataOverviewState extends State<PersonnelDataOverview> {
color: const Color.fromRGBO(230, 230, 230, 1), color: const Color.fromRGBO(230, 230, 230, 1),
margin: EdgeInsets.only(bottom: 1.h, right: 1.w), margin: EdgeInsets.only(bottom: 1.h, right: 1.w),
padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 8.w), padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 8.w),
child: quickText(entrie.key, color: const Color.fromRGBO(24, 35, 77, 1), size: 12.sp, maxLines: 2), child: quickText(entrie.key, color: Color.fromRGBO(24, 35, 77, 1), size: 12.sp, maxLines: 2),
), ),
...entrie.value.map((e) { ...entrie.value.map((e) {
bool isTransparentChineseNew = isTransparentChinese && (e?.length ?? 0) == 0; bool isTransparentChineseNew = isTransparentChinese && (e?.length ?? 0) == 0;
@ -97,23 +97,23 @@ class _PersonnelDataOverviewState extends State<PersonnelDataOverview> {
alignment: Alignment.center, alignment: Alignment.center,
margin: EdgeInsets.only(bottom: 1.h, right: 1.w), margin: EdgeInsets.only(bottom: 1.h, right: 1.w),
padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 8.w), padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 8.w),
color: const Color.fromRGBO(245, 245, 245, 1), color: Color.fromRGBO(245, 245, 245, 1),
child: isTransparentChineseNew child: isTransparentChineseNew
? quickText('透明', color: Colors.transparent, size: 12.sp) ? quickText('透明', color: Colors.transparent, size: 12.sp)
: RegExp(r'^\d+$').hasMatch(e) || e.contains('%') : RegExp(r'^\d+$').hasMatch(e) || e.contains('%')
? Row( ? Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
quickText(e, color: const Color.fromRGBO(82, 82, 82, 1), size: 12.sp, maxLines: 2), quickText(e, color: Color.fromRGBO(82, 82, 82, 1), size: 12.sp, maxLines: 2),
quickText('', color: Colors.transparent, size: 12.sp), quickText('', color: Colors.transparent, size: 12.sp),
], ],
) )
: quickText(e, color: const Color.fromRGBO(82, 82, 82, 1), size: 12.sp, maxLines: 2), : quickText(e, color: Color.fromRGBO(82, 82, 82, 1), size: 12.sp, maxLines: 2),
); );
}), }).toList(),
], ],
); );
}), }).toList(),
], ],
), ),
), ),

View File

@ -28,10 +28,9 @@ class _ReadOverPageState extends State<ReadOverPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AnnotatedRegion( return AnnotatedRegion(
value: const SystemUiOverlayStyle( value: const SystemUiOverlayStyle(
/* systemNavigationBarColor: Color(0xFF000000), /* systemNavigationBarColor: Color(0xFF000000),
systemNavigationBarDividerColor: null,*/ systemNavigationBarDividerColor: null,*/
statusBarColor: Colors.white, statusBarColor: Colors.transparent,
systemNavigationBarDividerColor: null,
systemNavigationBarIconBrightness: Brightness.light, systemNavigationBarIconBrightness: Brightness.light,
statusBarIconBrightness: Brightness.light, statusBarIconBrightness: Brightness.light,
statusBarBrightness: Brightness.light, statusBarBrightness: Brightness.light,
@ -178,12 +177,7 @@ class _ReadOverPageState extends State<ReadOverPage> {
@override @override
void dispose() { void dispose() {
Get.delete<ReadOverLogic>(); Get.delete<ReadOverLogic>();
logic.homeController.getList();
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarColor: Colors.transparent, //
statusBarIconBrightness: Brightness.light,
systemStatusBarContrastEnforced: false,
));
super.dispose(); super.dispose();
logic.homeController.getList();
} }
} }

View File

@ -19,7 +19,7 @@ class TaskListItem extends StatefulWidget {
final int tabIndex; final int tabIndex;
final Function(Items item) collectFun; final Function(Items item) collectFun;
const TaskListItem({Key? key, required this.completed, required this.jobTaskItem, required this.type, required this.collectFun, required this.tabIndex}) : super(key: key); const TaskListItem({Key? key, required this.completed, required this.jobTaskItem, required this.type, required this.collectFun,required this.tabIndex}) : super(key: key);
@override @override
State<TaskListItem> createState() => _TaskListItemState(); State<TaskListItem> createState() => _TaskListItemState();
@ -31,7 +31,8 @@ class _TaskListItemState extends State<TaskListItem> {
return widget.completed return widget.completed
? InkWell( ? InkWell(
onTap: () { onTap: () {
Get.toNamed(Routes.annotateClassPage, arguments: {'id': widget.jobTaskItem.id, 'name': widget.jobTaskItem.name, 'grade': widget.jobTaskItem.grade, 'subject': widget.jobTaskItem.subject, 'completed': true, 'tabIndex': widget.tabIndex}); Get.toNamed(Routes.annotateClassPage,
arguments: {'id': widget.jobTaskItem.id, 'name': widget.jobTaskItem.name, 'grade': widget.jobTaskItem.grade,'subject': widget.jobTaskItem.subject, 'completed': true,'tabIndex':widget.tabIndex});
}, },
child: Container( child: Container(
width: double.infinity, width: double.infinity,
@ -72,7 +73,7 @@ class _TaskListItemState extends State<TaskListItem> {
), ),
), ),
margin: EdgeInsets.only(right: 4.w), margin: EdgeInsets.only(right: 4.w),
child: quickText(widget.jobTaskItem.assessType == 0 ? '作业' : '考试', color: Colors.white, size: 10.sp), child: quickText( widget.jobTaskItem.assessType == 0?'作业':'考试', color: Colors.white, size: 10.sp),
), ),
Expanded( Expanded(
child: quickText( child: quickText(
@ -142,13 +143,7 @@ class _TaskListItemState extends State<TaskListItem> {
child: Row(children: [ child: Row(children: [
Expanded( Expanded(
child: InkWell( child: InkWell(
onTap: () { onTap: () {},
Get.toNamed(Routes.jobReportPage, arguments: {
'title': widget.jobTaskItem.name,
'homeworkId': widget.jobTaskItem.id,
'grade': widget.jobTaskItem.grade,
});
},
child: Container( child: Container(
alignment: Alignment.center, alignment: Alignment.center,
child: quickText('查看报告', color: const Color.fromRGBO(118, 118, 118, 1), size: 13.sp), child: quickText('查看报告', color: const Color.fromRGBO(118, 118, 118, 1), size: 13.sp),
@ -161,10 +156,11 @@ class _TaskListItemState extends State<TaskListItem> {
), ),
) )
: Padding( : Padding(
padding: EdgeInsets.only(top: 10.r), padding: EdgeInsets.only(top: 10.r),
child: InkWell( child: InkWell(
onTap: () { onTap: () {
Get.toNamed(Routes.annotateClassPage, arguments: {'id': widget.jobTaskItem.id, 'name': widget.jobTaskItem.name, 'grade': widget.jobTaskItem.grade, 'subject': widget.jobTaskItem.subject, 'tabIndex': widget.tabIndex}); Get.toNamed(Routes.annotateClassPage,
arguments: {'id': widget.jobTaskItem.id, 'name': widget.jobTaskItem.name, 'grade': widget.jobTaskItem.grade,'subject':widget.jobTaskItem.subject,'tabIndex':widget.tabIndex});
}, },
child: Container( child: Container(
margin: EdgeInsets.only(bottom: 16.h), margin: EdgeInsets.only(bottom: 16.h),
@ -206,8 +202,8 @@ class _TaskListItemState extends State<TaskListItem> {
bottomRight: Radius.circular(12.r), bottomRight: Radius.circular(12.r),
), ),
), ),
margin: EdgeInsets.only(top: 0.h, right: 4.w), margin: EdgeInsets.only(top:0.h,right: 4.w),
child: quickText(widget.jobTaskItem.assessType == 0 ? '作业' : '考试', color: Colors.white, size: 10.sp), child: quickText(widget.jobTaskItem.assessType == 0?'作业':'考试', color: Colors.white, size: 10.sp),
), ),
Expanded( Expanded(
child: Padding( child: Padding(
@ -247,7 +243,8 @@ class _TaskListItemState extends State<TaskListItem> {
], ],
), ),
quickText(' / ', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp, fontWeight: FontWeight.w500), quickText(' / ', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp, fontWeight: FontWeight.w500),
quickText(DateTime.parse(widget.jobTaskItem.publishTime).toString().substring(0, 10), color: const Color.fromRGBO(97, 97, 97, 1), size: 12.sp), quickText(DateTime.parse(widget.jobTaskItem.publishTime).toString().substring(0, 10),
color: const Color.fromRGBO(97, 97, 97, 1), size: 12.sp),
], ],
), ),
), ),
@ -269,7 +266,7 @@ class _TaskListItemState extends State<TaskListItem> {
), ),
child: Text( child: Text(
widget.jobTaskItem.isFixed! ? '已订正' : '收集订正', widget.jobTaskItem.isFixed! ? '已订正' : '收集订正',
style: TextStyle(fontSize: 10.sp, color: widget.jobTaskItem.isFixed! ? const Color(0xFFF16262) : const Color(0xFF8C68FF)), style: TextStyle(fontSize: 10.sp, color: widget.jobTaskItem.isFixed! ?const Color(0xFFF16262): const Color(0xFF8C68FF)),
), ),
), ),
), ),
@ -277,17 +274,15 @@ class _TaskListItemState extends State<TaskListItem> {
], ],
), ),
), ),
SizedBox( SizedBox(width: 10.r,),
width: 10.r,
),
Container( Container(
padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 9.r), padding: EdgeInsets.symmetric(vertical: 10.r,horizontal: 9.r),
decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.white), decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.white),
child: CircularPercentIndicator( child: CircularPercentIndicator(
radius: 50.r, radius: 50.r,
lineWidth: 10.r, lineWidth: 10.r,
animation: true, animation: true,
reverse: true, reverse:true,
percent: widget.jobTaskItem.annotateRate == null ? 0 : widget.jobTaskItem.annotateRate! / 100, percent: widget.jobTaskItem.annotateRate == null ? 0 : widget.jobTaskItem.annotateRate! / 100,
center: Text.rich(TextSpan(children: [ center: Text.rich(TextSpan(children: [
TextSpan( TextSpan(
@ -322,6 +317,6 @@ class _TaskListItemState extends State<TaskListItem> {
), ),
), ),
), ),
); );
} }
} }

View File

@ -18,7 +18,7 @@ import 'package:syncfusion_flutter_datepicker/datepicker.dart';
import 'student_work_detail_logic.dart'; import 'student_work_detail_logic.dart';
class StudentWorkDetailPage extends StatefulWidget { class StudentWorkDetailPage extends StatefulWidget {
const StudentWorkDetailPage({super.key}); const StudentWorkDetailPage({Key? key}) : super(key: key);
@override @override
State<StudentWorkDetailPage> createState() => _StudentWorkDetailPageState(); State<StudentWorkDetailPage> createState() => _StudentWorkDetailPageState();
@ -33,14 +33,14 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
return OrientationBuilder( return OrientationBuilder(
builder: (BuildContext context, Orientation orientation) { builder: (BuildContext context, Orientation orientation) {
return Scaffold( return Scaffold(
backgroundColor: const Color.fromRGBO(245, 245, 245, 1), backgroundColor: Color.fromRGBO(245, 245, 245, 1),
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.white, backgroundColor: Colors.white,
title: Text('${state.studentName}作业详情', title: Text('${state.studentName}作业详情',
style: TextStyle(fontSize: 14.sp, color: const Color(0xFF333333))), style: TextStyle(fontSize: 14.sp, color: Color(0xFF333333))),
centerTitle: true, centerTitle: true,
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.black), icon: Icon(Icons.arrow_back_ios, color: Colors.black),
onPressed: () => Get.back(), onPressed: () => Get.back(),
), ),
actions: const [ actions: const [
@ -53,7 +53,7 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
Container( Container(
height: 1.r, height: 1.r,
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
color: const Color.fromRGBO(179, 179, 179, 0.3), color: Color.fromRGBO(179, 179, 179, 0.3),
), ),
Container( Container(
color: Colors.white, color: Colors.white,
@ -79,7 +79,7 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
fontSize: 14.sp, fontSize: 14.sp,
color: state.isJob.value color: state.isJob.value
? Theme.of(context).primaryColor ? Theme.of(context).primaryColor
: const Color(0xFF505E6E)), : Color(0xFF505E6E)),
)); ));
}), }),
), ),
@ -87,7 +87,7 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
Container( Container(
height: 40.r, height: 40.r,
width: 1.r, width: 1.r,
color: const Color.fromRGBO(179, 179, 179, 0.3), color: Color.fromRGBO(179, 179, 179, 0.3),
), ),
InkWell( InkWell(
onTap: () { onTap: () {
@ -107,7 +107,7 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
fontSize: 14.sp, fontSize: 14.sp,
color: !state.isJob.value color: !state.isJob.value
? Theme.of(context).primaryColor ? Theme.of(context).primaryColor
: const Color(0xFF505E6E)), : Color(0xFF505E6E)),
); );
})), })),
), ),
@ -223,7 +223,7 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
children: [ children: [
Text( Text(
'注:', '注:',
style: TextStyle(fontSize: 8.sp, color: const Color(0xFF8B8B8B)), style: TextStyle(fontSize: 8.sp, color: Color(0xFF8B8B8B)),
), ),
Container( Container(
width: 10.r, width: 10.r,
@ -239,7 +239,7 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
), ),
Text( Text(
'正确', '正确',
style: TextStyle(fontSize: 8.sp, color: const Color(0xFF8B8B8B)), style: TextStyle(fontSize: 8.sp, color: Color(0xFF8B8B8B)),
), ),
SizedBox( SizedBox(
width: 15.r, width: 15.r,
@ -258,7 +258,7 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
), ),
Text( Text(
'错误', '错误',
style: TextStyle(fontSize: 8.sp, color: const Color(0xFF8B8B8B)), style: TextStyle(fontSize: 8.sp, color: Color(0xFF8B8B8B)),
), ),
SizedBox( SizedBox(
width: 15.r, width: 15.r,
@ -269,7 +269,7 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.r)), borderRadius: BorderRadius.all(Radius.circular(5.r)),
// color: Color(0xFF666666), // color: Color(0xFF666666),
border: Border.all(width: 1.r, color: const Color(0xFF666666)), border: Border.all(width: 1.r, color: Color(0xFF666666)),
// border: Border.all(width: 1.r,color: Colors.grey), // border: Border.all(width: 1.r,color: Colors.grey),
/* boxShadow: [ /* boxShadow: [
BoxShadow( BoxShadow(
@ -286,7 +286,7 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
), ),
Text( Text(
'已作答未批阅', '已作答未批阅',
style: TextStyle(fontSize: 8.sp, color: const Color(0xFF8B8B8B)), style: TextStyle(fontSize: 8.sp, color: Color(0xFF8B8B8B)),
), ),
SizedBox( SizedBox(
width: 15.r, width: 15.r,
@ -296,7 +296,7 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
height: 10.r, height: 10.r,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.r)), borderRadius: BorderRadius.all(Radius.circular(5.r)),
border: Border.all(width: 1.r, color: const Color(0xFFDDDDDD)), border: Border.all(width: 1.r, color: Color(0xFFDDDDDD)),
// color: Color(0xFFDDDDDD), // color: Color(0xFFDDDDDD),
), ),
), ),
@ -305,7 +305,7 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
), ),
Text( Text(
'未做', '未做',
style: TextStyle(fontSize: 8.sp, color: const Color(0xFF8B8B8B)), style: TextStyle(fontSize: 8.sp, color: Color(0xFF8B8B8B)),
), ),
], ],
), ),
@ -394,7 +394,7 @@ class _StudentWorkDetailPageState extends State<StudentWorkDetailPage> {
item.name, item.name,
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: const Color(0xFF464646)), color: Color(0xFF464646)),
)), )),
// SizedBox(width: 5.r,), // SizedBox(width: 5.r,),
// Text('2024.1',style: TextStyle(fontSize: 12.sp,color: Color(0xFF5B5B5B)),), // Text('2024.1',style: TextStyle(fontSize: 12.sp,color: Color(0xFF5B5B5B)),),

View File

@ -40,21 +40,19 @@ class _JobConditionFilterState extends State<JobConditionFilter> {
} }
DateTime getMonthStartDate() { DateTime getMonthStartDate() {
// DateTime now = DateTime.now();
// return DateTime(now.year, now.month, 1); //
DateTime now = DateTime.now(); DateTime now = DateTime.now();
return now.subtract(const Duration(days: 29)); return DateTime(now.year, now.month, 1); //
} }
DateTime getMonthEndDate() { DateTime getMonthEndDate() {
DateTime now = DateTime.now(); DateTime now = DateTime.now();
// int nextMonth = now.month + 1; int nextMonth = now.month + 1;
// if (nextMonth > 12) { if (nextMonth > 12) {
// nextMonth = 1; nextMonth = 1;
// now = now.add(Duration(days: 31 - now.day)); // now = now.add(Duration(days: 31 - now.day)); //
// } else { } else {
// now = now.add(Duration(days: DateTime(now.year, nextMonth, 0).day - now.day)); // now = now.add(Duration(days: DateTime(now.year, nextMonth, 0).day - now.day)); //
// } }
return now; return now;
} }

View File

@ -7,6 +7,7 @@ import 'package:making_school_asignment_app/common/store/user_store.dart';
import 'package:making_school_asignment_app/common/utils/storage.dart'; import 'package:making_school_asignment_app/common/utils/storage.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart'; import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/page/login_page/children/sys_protocol.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart'; import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'package:making_school_asignment_app/common/store/app_storage_key.dart'; import 'package:making_school_asignment_app/common/store/app_storage_key.dart';
@ -15,6 +16,12 @@ import 'login_state.dart';
class LoginLogic extends GetxController with RequestToolMixin { class LoginLogic extends GetxController with RequestToolMixin {
final LoginState state = LoginState(); final LoginState state = LoginState();
@override
void onReady() {
// TODO: implement onReady
super.onReady();
}
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
@ -30,8 +37,6 @@ class LoginLogic extends GetxController with RequestToolMixin {
state.passwordController.text = pwd; state.passwordController.text = pwd;
state.keepPwd.value = true; state.keepPwd.value = true;
} }
state.userNameController.text = "AppleTester";
state.passwordController.text = "AppleTester123!";
state.pwdFocus = FocusNode(); state.pwdFocus = FocusNode();
state.theFocus = FocusNode(); state.theFocus = FocusNode();

View File

@ -29,14 +29,17 @@ class _LoginPageState extends State<LoginPage> {
statusBarIconBrightness: Brightness.light, statusBarIconBrightness: Brightness.light,
statusBarColor: Colors.transparent, // statusBarColor: Colors.transparent, //
)); ));
Future.delayed(Duration.zero, () => upgradeLogic.getAppUpgrade(context));
WidgetsBinding.instance.addPostFrameCallback((_) async { Future.delayed(Duration.zero, () => sysProtocol(context));
await sysProtocol(context);
await Future.delayed(Duration.zero, () => upgradeLogic.getAppUpgrade(context));
});
super.initState(); super.initState();
} }
@override
void dispose() {
Get.delete<LoginLogic>();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
@ -228,7 +231,7 @@ class _LoginPageState extends State<LoginPage> {
padding: EdgeInsets.only(right: 0.w), padding: EdgeInsets.only(right: 0.w),
child: Obx(() { child: Obx(() {
return Transform.scale( return Transform.scale(
scale: 1.0, scale: 1.2,
child: Checkbox( child: Checkbox(
// activeColor: Colors.transparent, // // activeColor: Colors.transparent, //
@ -287,10 +290,10 @@ class _LoginPageState extends State<LoginPage> {
}, },
child: Obx(() { child: Obx(() {
return Container( return Container(
margin: EdgeInsets.symmetric(vertical: 10.h), margin: EdgeInsets.symmetric(vertical: 10.h),
decoration: BoxDecoration( decoration: BoxDecoration(
color: state.canLogin.value ? const Color(0xFF8C68FF) : const Color(0xFFdddddd), color: state.canLogin.value ? const Color(0xFF8C68FF) : const Color(0xFFdddddd),
/*boxShadow: [ /*boxShadow: [
BoxShadow( BoxShadow(
color: color:
const Color.fromRGBO(76, 199, 147, 0.5), const Color.fromRGBO(76, 199, 147, 0.5),
@ -299,14 +302,15 @@ class _LoginPageState extends State<LoginPage> {
spreadRadius: 0.5, // spreadRadius: 0.5, //
) )
],*/ ],*/
borderRadius: BorderRadius.all( borderRadius: BorderRadius.all(
Radius.circular(17.w), Radius.circular(17.w),
),
), ),
alignment: Alignment.center, ),
width: double.infinity, alignment: Alignment.center,
height: 50.h, width: double.infinity,
child: quickText('登 录', size: 18.sp, color: Colors.white)); height: 50.h,
child: Text('登 录', style: TextStyle(fontSize: 16.sp, color: Colors.white)),
);
}), }),
), ),
Row( Row(
@ -316,7 +320,7 @@ class _LoginPageState extends State<LoginPage> {
padding: EdgeInsets.only(right: 0.w), padding: EdgeInsets.only(right: 0.w),
child: Obx(() { child: Obx(() {
return Transform.scale( return Transform.scale(
scale: 1.0, scale: 1.2,
child: Checkbox( child: Checkbox(
activeColor: Theme.of(context).primaryColor, activeColor: Theme.of(context).primaryColor,
checkColor: Colors.white, checkColor: Colors.white,
@ -368,7 +372,7 @@ class _LoginPageState extends State<LoginPage> {
child: quickText( child: quickText(
'《隐私协议》', '《隐私协议》',
size: 12.sp, size: 12.sp,
color: Theme.of(context).primaryColor, color:Theme.of(context).primaryColor,
), ),
), ),
], ],

View File

@ -14,7 +14,6 @@ import 'package:making_school_asignment_app/page/home_page/children/class_studen
import 'package:making_school_asignment_app/page/home_page/children/fav_student/fav_student_binding.dart'; import 'package:making_school_asignment_app/page/home_page/children/fav_student/fav_student_binding.dart';
import 'package:making_school_asignment_app/page/home_page/children/fav_student/fav_student_view.dart'; import 'package:making_school_asignment_app/page/home_page/children/fav_student/fav_student_view.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart'; import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/zoom_logic.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/index.dart'; import 'package:making_school_asignment_app/page/home_page/children/homework_review/index.dart';
import 'package:making_school_asignment_app/page/home_page/children/job_report/job_report_binding.dart'; import 'package:making_school_asignment_app/page/home_page/children/job_report/job_report_binding.dart';
import 'package:making_school_asignment_app/page/home_page/children/job_report/job_report_view.dart'; import 'package:making_school_asignment_app/page/home_page/children/job_report/job_report_view.dart';
@ -45,30 +44,63 @@ part 'app_routes.dart';
abstract class AppPages { abstract class AppPages {
static final pages = [ static final pages = [
GetPage(name: Routes.login, page: () => const LoginPage(), binding: LoginBinding(), transition: getTransition()), GetPage(name: Routes.login, page: () => const LoginPage(), binding: LoginBinding(), transition: Transition.noTransition),
GetPage(name: Routes.register, page: () => const Register(), transition: getTransition()), GetPage(name: Routes.register, page: () => const Register(), transition: getTransition()),
GetPage(name: Routes.agreementPage, page: () => const AgreementPage(), binding: LoginBinding(), transition: getTransition()), GetPage(name: Routes.agreementPage, page: () => const AgreementPage(), binding: LoginBinding(), transition: Transition.noTransition),
GetPage(name: Routes.home, page: () => const HomePage(), binding: HomeBinding(), transition: getTransition()), GetPage(name: Routes.home, page: () => const HomePage(), binding: HomeBinding(), transition: Transition.noTransition),
GetPage(name: Routes.startPage, page: () => const StartPage(), binding: StartPageIndexBinding(), transition: getTransition()), GetPage(name: Routes.startPage, page: () => const StartPage(), binding: StartPageIndexBinding(), transition: Transition.noTransition),
GetPage(name: Routes.myInfo, page: () => const MyInfo(), transition: getTransition()), GetPage(name: Routes.myInfo, page: () => const MyInfo(), transition: Transition.noTransition),
GetPage(name: Routes.work, page: () => const WorkPage(), binding: WorkBinding(), transition: getTransition()), GetPage(name: Routes.work, page: () => const WorkPage(), binding: WorkBinding(), transition: Transition.noTransition),
GetPage(name: Routes.otherPage, page: () => const OhterPage(), transition: getTransition()), GetPage(name: Routes.otherPage, page: () => const OhterPage(), transition: Transition.noTransition),
GetPage(name: Routes.readOverPage, page: () => const ReadOverPage(), binding: ReadOverBinding(), transition: getTransition()), GetPage(name: Routes.readOverPage, page: () => const ReadOverPage(), binding: ReadOverBinding(), transition: Transition.noTransition),
GetPage(name: Routes.studentHistoryWorkPage, page: () => const StudentHistoryWorkPage(), binding: StudentHistoryWorkBinding(), transition: getTransition()), GetPage(
GetPage(name: Routes.classStudentPage, page: () => const ClassStudentPage(), binding: ClassStudentBinding(), transition: getTransition()), name: Routes.studentHistoryWorkPage,
GetPage(name: Routes.annotateClassPage, page: () => const AnnotateClassPage(), binding: AnnotateClassBinding(), transition: getTransition()), page: () => const StudentHistoryWorkPage(),
GetPage(name: Routes.quickDataCheckPage, page: () => const QuickDataCheckPage(), binding: QuickDataCheckBinding(), transition: getTransition()), binding: StudentHistoryWorkBinding(),
GetPage(name: Routes.jobReportPage, page: () => const JobReportPage(), binding: JobReportBinding(), transition: getTransition()), transition: Transition.noTransition),
GetPage(name: Routes.studentPersonalPage, page: () => const StudentPersonalPage(), binding: StudentPersonalBinding(), transition: getTransition()), GetPage(name: Routes.classStudentPage, page: () => const ClassStudentPage(), binding: ClassStudentBinding(), transition: Transition.noTransition),
GetPage(name: Routes.studentWorkDetailPage, page: () => const StudentWorkDetailPage(), binding: StudentWorkDetailBinding(), transition: getTransition()), GetPage(
GetPage(name: Routes.knowledgePointsGraspPage, page: () => const KnowledgePointsGraspPage(), binding: KnowledgePointsGraspBinding(), transition: getTransition()), name: Routes.annotateClassPage, page: () => const AnnotateClassPage(), binding: AnnotateClassBinding(), transition: Transition.noTransition),
GetPage(name: Routes.knowledgePointsGraspDetailPage, page: () => const KnowledgePointsGraspDetailPage(), binding: KnowledgePointsGraspDetailBinding(), transition: getTransition()), GetPage(
GetPage(name: Routes.answerTrajectoryPage, page: () => const AnswerTrajectoryPage(), binding: AnswerTrajectoryBinding(), transition: getTransition()), name: Routes.quickDataCheckPage,
GetPage(name: Routes.answerTrajectoryDetailPage, page: () => const AnswerTrajectoryDetailPage(), binding: AnswerTrajectoryDetailBinding(), transition: getTransition()), page: () => const QuickDataCheckPage(),
binding: QuickDataCheckBinding(),
transition: Transition.noTransition),
GetPage(name: Routes.jobReportPage, page: () => const JobReportPage(), binding: JobReportBinding(), transition: Transition.noTransition),
GetPage(
name: Routes.studentPersonalPage,
page: () => const StudentPersonalPage(),
binding: StudentPersonalBinding(),
transition: Transition.noTransition),
GetPage(
name: Routes.studentWorkDetailPage,
page: () => const StudentWorkDetailPage(),
binding: StudentWorkDetailBinding(),
transition: Transition.noTransition),
GetPage(
name: Routes.knowledgePointsGraspPage,
page: () => const KnowledgePointsGraspPage(),
binding: KnowledgePointsGraspBinding(),
transition: Transition.noTransition),
GetPage(
name: Routes.knowledgePointsGraspDetailPage,
page: () => const KnowledgePointsGraspDetailPage(),
binding: KnowledgePointsGraspDetailBinding(),
transition: Transition.noTransition),
GetPage(
name: Routes.answerTrajectoryPage,
page: () => const AnswerTrajectoryPage(),
binding: AnswerTrajectoryBinding(),
transition: Transition.noTransition),
GetPage(
name: Routes.answerTrajectoryDetailPage,
page: () => const AnswerTrajectoryDetailPage(),
binding: AnswerTrajectoryDetailBinding(),
transition: Transition.noTransition),
// //
GetPage(name: Routes.reviewHomework, page: () => const HomeworkReview(), bindings: [HomeworkReviewBinding(), HomeworkReviewZoomBinding()], transition: getTransition()), GetPage(name: Routes.reviewHomework, page: () => const HomeworkReview(), binding: HomeworkReviewBinding(), transition: getTransition()),
// GetPage(name: Routes.reviewExam, page: () => const HomeworkReview(), bindings: [HomeworkReviewBinding(), HomeworkReviewZoomBinding()], transition: getTransition()), GetPage(name: Routes.reviewExam, page: () => const HomeworkReview(), binding: HomeworkReviewBinding(), transition: getTransition()),
GetPage(name: Routes.favStudentPage, page: () => const FavStudentPage(), binding: FavStudentBinding(), transition: getTransition()), GetPage(name: Routes.favStudentPage, page: () => const FavStudentPage(), binding: FavStudentBinding(), transition: Transition.noTransition),
]; ];
} }

View File

@ -37,7 +37,7 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.6 cupertino_icons: ^1.0.6
# 路由、依赖、状态插件 # 路由、依赖、状态插件
get: ^4.7.2 get: ^4.6.5
# loading插件 # loading插件
flutter_easyloading: ^3.0.5 flutter_easyloading: ^3.0.5
# 日志插件 # 日志插件
@ -65,7 +65,6 @@ dependencies:
flutter_widget_from_html_core: ^0.14.12 flutter_widget_from_html_core: ^0.14.12
# APP内存及本地存储插件 # APP内存及本地存储插件
get_storage: ^2.0.3 get_storage: ^2.0.3
zoom_widget: ^2.0.1
# start retrofit请求封装 # start retrofit请求封装
retrofit: ^4.1.0 retrofit: ^4.1.0