Compare commits
No commits in common. "d3509a2eee7e0d8238c5c1eec73efa2f8e7efe83" and "44cea01b38b806fb63f9a47a026e8f52db87e57c" have entirely different histories.
d3509a2eee
...
44cea01b38
|
|
@ -1,10 +1,10 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:dio/dio.dart' hide Headers;
|
import 'package:dio/dio.dart' hide Headers;
|
||||||
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/favor_param.dart';
|
import 'package:making_school_asignment_app/common/job/marking_models/favor_param.dart';
|
||||||
import 'package:making_school_asignment_app/common/job/marking_models/original_manuscript_handwriting_params.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/page/home_page/children/homework_review/components/job_handwriting.dart';
|
|
||||||
import 'package:retrofit/retrofit.dart';
|
import 'package:retrofit/retrofit.dart';
|
||||||
import 'package:making_school_asignment_app/common/job/annotated_class.dart';
|
import 'package:making_school_asignment_app/common/job/annotated_class.dart';
|
||||||
import 'package:making_school_asignment_app/common/job/class_item.dart';
|
import 'package:making_school_asignment_app/common/job/class_item.dart';
|
||||||
|
|
@ -130,11 +130,12 @@ abstract class RetrofitClient {
|
||||||
@POST("/api/hms/Annotate/AnnotateSubmit")
|
@POST("/api/hms/Annotate/AnnotateSubmit")
|
||||||
Future reviewSubmission(@Body() ReviewSubmissionParams param);
|
Future reviewSubmission(@Body() ReviewSubmissionParams param);
|
||||||
|
|
||||||
// 获取原稿笔记
|
|
||||||
@GET("/api/hms/HmsReport/GetStudentPaperHandwriting")
|
|
||||||
Future<JobHandwriting> getOriginalManuscriptHandwriting(@Queries() OriginalManuscriptHandwritingParams param);
|
|
||||||
|
|
||||||
// OSS 上传key
|
// OSS 上传key
|
||||||
@GET("/api/infra/Oss/GetPresignedUri")
|
@GET("/api/infra/Oss/GetPresignedUri")
|
||||||
Future getOssPresignedUri(@Query('key') String key);
|
Future getOssPresignedUri(@Query('key') String key);
|
||||||
|
|
||||||
|
// OSS 图片上传
|
||||||
|
@PUT('{theUrl}')
|
||||||
|
@Headers(<String, dynamic>{'Content-Type': ''})
|
||||||
|
Future<void> uploadImag(@Path() String theUrl, @Part() File file);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class DoPaperDetailsResult extends Object {
|
||||||
@JsonKey(name: 'templateIdKeyMap')
|
@JsonKey(name: 'templateIdKeyMap')
|
||||||
Map<int, int>? templateIdKeyMap;
|
Map<int, int>? templateIdKeyMap;
|
||||||
|
|
||||||
@JsonKey(name: 'submitStudents') // 当前页 总提交学生集合
|
@JsonKey(name: 'students')
|
||||||
List<PaperStudents> students;
|
List<PaperStudents> students;
|
||||||
|
|
||||||
@JsonKey(name: 'templateId')
|
@JsonKey(name: 'templateId')
|
||||||
|
|
@ -59,9 +59,8 @@ class DoPaperDetailsResult extends Object {
|
||||||
@JsonKey(name: 'studentQuestions')
|
@JsonKey(name: 'studentQuestions')
|
||||||
List<StudentQuestions> studentQuestions;
|
List<StudentQuestions> studentQuestions;
|
||||||
|
|
||||||
// 当前页 未提交学生集合
|
|
||||||
@JsonKey(name: 'unSubmitStudents')
|
@JsonKey(name: 'unSubmitStudents')
|
||||||
List<PaperStudents> unSubmitStudents;
|
Object unSubmitStudents;
|
||||||
|
|
||||||
@JsonKey(name: 'lastPage')
|
@JsonKey(name: 'lastPage')
|
||||||
LastPage? lastPage;
|
LastPage? lastPage;
|
||||||
|
|
@ -69,12 +68,7 @@ class DoPaperDetailsResult extends Object {
|
||||||
@JsonKey(name: 'nextPage')
|
@JsonKey(name: 'nextPage')
|
||||||
NextPage? nextPage;
|
NextPage? nextPage;
|
||||||
|
|
||||||
// 所有页 总待提交数量
|
|
||||||
@JsonKey(name: 'totalUnAnnotateCount')
|
|
||||||
int totalUnAnnotateCount;
|
|
||||||
|
|
||||||
DoPaperDetailsResult(
|
DoPaperDetailsResult(
|
||||||
this.totalUnAnnotateCount,
|
|
||||||
this.templateIds,
|
this.templateIds,
|
||||||
this.students,
|
this.students,
|
||||||
this.templateId,
|
this.templateId,
|
||||||
|
|
@ -117,8 +111,8 @@ class DoPaperDetailsResult extends Object {
|
||||||
if (annotateTime != null) showZgtAnnotate = '${showZgtAnnotate!}?$annotateTime';
|
if (annotateTime != null) showZgtAnnotate = '${showZgtAnnotate!}?$annotateTime';
|
||||||
}
|
}
|
||||||
|
|
||||||
// print('学生作答图片:${annotatedCount}');
|
print('学生作答图片:${zgtAnswer}');
|
||||||
// print('老师批注图片提交数量:${submitCount}');
|
print('老师批注图片:${showZgtAnnotate}');
|
||||||
}
|
}
|
||||||
|
|
||||||
factory DoPaperDetailsResult.fromJson(Map<String, dynamic> srcJson) => _$DoPaperDetailsResultFromJson(srcJson);
|
factory DoPaperDetailsResult.fromJson(Map<String, dynamic> srcJson) => _$DoPaperDetailsResultFromJson(srcJson);
|
||||||
|
|
@ -134,7 +128,6 @@ class PaperStudents extends Object {
|
||||||
@JsonKey(name: 'name')
|
@JsonKey(name: 'name')
|
||||||
String name;
|
String name;
|
||||||
|
|
||||||
// 优先批阅
|
|
||||||
@JsonKey(name: 'isPriority')
|
@JsonKey(name: 'isPriority')
|
||||||
bool isPriority;
|
bool isPriority;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
// 原稿笔迹参数
|
|
||||||
|
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
|
|
||||||
part 'original_manuscript_handwriting_params.g.dart';
|
|
||||||
|
|
||||||
@JsonSerializable(checked: true, includeIfNull: false)
|
|
||||||
class OriginalManuscriptHandwritingParams extends Object {
|
|
||||||
@JsonKey(name: 'homeworkId')
|
|
||||||
String homeworkId;
|
|
||||||
|
|
||||||
@JsonKey(name: 'studentId')
|
|
||||||
int studentId;
|
|
||||||
|
|
||||||
@JsonKey(name: 'templateId')
|
|
||||||
int? templateId;
|
|
||||||
|
|
||||||
@JsonKey(name: 'questionNo')
|
|
||||||
int? questionNo;
|
|
||||||
|
|
||||||
@JsonKey(name: 'pageNum')
|
|
||||||
int? pageNum;
|
|
||||||
|
|
||||||
OriginalManuscriptHandwritingParams({
|
|
||||||
required this.homeworkId,
|
|
||||||
required this.studentId,
|
|
||||||
this.templateId,
|
|
||||||
this.pageNum,
|
|
||||||
this.questionNo,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory OriginalManuscriptHandwritingParams.fromJson(Map<String, dynamic> srcJson) => _$OriginalManuscriptHandwritingParamsFromJson(srcJson);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$OriginalManuscriptHandwritingParamsToJson(this);
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,6 @@
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:making_school_asignment_app/common/request/rest_dio.dart';
|
import 'package:making_school_asignment_app/common/request/rest_dio.dart';
|
||||||
import 'package:making_school_asignment_app/common/api/retrofit_client.dart';
|
import 'package:making_school_asignment_app/common/api/retrofit_client.dart';
|
||||||
|
|
||||||
mixin RequestToolMixin {
|
mixin RequestToolMixin {
|
||||||
// 获取DIO
|
|
||||||
Dio getClientDio() => RequestTool.instance.getDio();
|
|
||||||
// 获取Client
|
|
||||||
RetrofitClient getClient() => RequestTool.instance.getClient();
|
RetrofitClient getClient() => RequestTool.instance.getClient();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
|
||||||
import 'package:making_school_asignment_app/routes/app_pages.dart';
|
import 'package:making_school_asignment_app/routes/app_pages.dart';
|
||||||
|
|
||||||
class RequestTool {
|
class RequestTool {
|
||||||
static late Dio _dio;
|
|
||||||
// 初始化请求配置
|
// 初始化请求配置
|
||||||
static _init() {
|
static _init() {
|
||||||
BaseOptions options = BaseOptions(
|
BaseOptions options = BaseOptions(
|
||||||
|
|
@ -19,16 +18,16 @@ class RequestTool {
|
||||||
connectTimeout: const Duration(milliseconds: RequestConfig.connectTimeout),
|
connectTimeout: const Duration(milliseconds: RequestConfig.connectTimeout),
|
||||||
receiveTimeout: const Duration(milliseconds: RequestConfig.receiveTimeout),
|
receiveTimeout: const Duration(milliseconds: RequestConfig.receiveTimeout),
|
||||||
);
|
);
|
||||||
_dio = Dio(options);
|
Dio dio = Dio(options);
|
||||||
_dio.interceptors.add(AuthInterceptor()); // 添加 token
|
dio.interceptors.add(AuthInterceptor()); // 添加 token
|
||||||
_dio.interceptors.add(ResponseHandle()); // 添加 数据返回拦截
|
dio.interceptors.add(ResponseHandle()); // 添加 数据返回拦截
|
||||||
_dio.interceptors.add(TheError()); // 添加 数据返回拦截
|
dio.interceptors.add(TheError()); // 添加 数据返回拦截
|
||||||
const isProd = bool.fromEnvironment('dart.vm.product');
|
const isProd = bool.fromEnvironment('dart.vm.product');
|
||||||
if (!isProd && RequestConfig.requestDataPrinting) {
|
if (!isProd && RequestConfig.requestDataPrinting) {
|
||||||
_dio.interceptors.add(LogInterceptor(responseBody: true, requestBody: true)); //添加日志
|
dio.interceptors.add(LogInterceptor(responseBody: true, requestBody: true)); //添加日志
|
||||||
}
|
}
|
||||||
|
|
||||||
return RetrofitClient(_dio, baseUrl: RequestConfig().baseUrl);
|
return RetrofitClient(dio, baseUrl: RequestConfig().baseUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
final RetrofitClient _client;
|
final RetrofitClient _client;
|
||||||
|
|
@ -44,9 +43,6 @@ class RequestTool {
|
||||||
return _instance!;
|
return _instance!;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DIO
|
|
||||||
Dio getDio() => _dio;
|
|
||||||
|
|
||||||
RetrofitClient getClient() => _client;
|
RetrofitClient getClient() => _client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
|
|
||||||
part 'my_time_util.g.dart';
|
|
||||||
|
|
||||||
// 毫秒转小时、分钟、秒的函数
|
|
||||||
TimeUnitModel? convertMilliseconds(int milliseconds) {
|
|
||||||
try {
|
|
||||||
int hours = milliseconds ~/ (1000 * 60 * 60);
|
|
||||||
int minutes = (milliseconds % (1000 * 60 * 60)) ~/ (1000 * 60);
|
|
||||||
int seconds = (milliseconds % (1000 * 60)) ~/ 1000;
|
|
||||||
|
|
||||||
if ((milliseconds % 1000) > 500) seconds += 1;
|
|
||||||
|
|
||||||
return TimeUnitModel(hours, minutes, seconds);
|
|
||||||
} catch (e) {
|
|
||||||
print('时间转换报错');
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 毫秒转小时、分钟、秒的函数
|
|
||||||
TimeUnitModel? convertSeconds(int totalSeconds) {
|
|
||||||
try {
|
|
||||||
int hours = totalSeconds ~/ 3600; // 整除3600得到小时数
|
|
||||||
int remainingSeconds = totalSeconds % 3600; // 取模3600得到剩余的秒数
|
|
||||||
int minutes = remainingSeconds ~/ 60; // 整除60得到分钟数
|
|
||||||
int seconds = remainingSeconds % 60; // 取模60得到最终的秒数
|
|
||||||
|
|
||||||
return TimeUnitModel(hours, minutes, seconds);
|
|
||||||
} catch (e) {
|
|
||||||
print('时间转换报错');
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class TimeUnitModel extends Object {
|
|
||||||
int hours;
|
|
||||||
int minutes;
|
|
||||||
int seconds;
|
|
||||||
TimeUnitModel(this.hours, this.minutes, this.seconds);
|
|
||||||
|
|
||||||
factory TimeUnitModel.fromJson(Map<String, dynamic> srcJson) => _$TimeUnitModelFromJson(srcJson);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$TimeUnitModelToJson(this);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
var timeStr = '';
|
|
||||||
if (hours > 0) {
|
|
||||||
timeStr += '${hours > 9 ? hours : '0' + hours.toString()} ';
|
|
||||||
}
|
|
||||||
if (minutes > 0) {
|
|
||||||
timeStr += '${minutes > 9 ? minutes : '0' + minutes.toString()}';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeStr.length > 0) {
|
|
||||||
timeStr += ':${seconds > 9 ? seconds : '0' + seconds.toString()}';
|
|
||||||
} else {
|
|
||||||
timeStr += '00:${seconds > 9 ? seconds : '0' + seconds.toString()}';
|
|
||||||
}
|
|
||||||
|
|
||||||
return timeStr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -39,7 +39,6 @@ class MyApp extends StatelessWidget {
|
||||||
splitScreenMode: true,*/
|
splitScreenMode: true,*/
|
||||||
builder: () => GetMaterialApp(
|
builder: () => GetMaterialApp(
|
||||||
title: '作业',
|
title: '作业',
|
||||||
debugShowCheckedModeBanner: false,
|
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
brightness: Brightness.light,
|
brightness: Brightness.light,
|
||||||
primarySwatch: createMaterialColor(const Color.fromRGBO(46, 91, 255, 1)),
|
primarySwatch: createMaterialColor(const Color.fromRGBO(46, 91, 255, 1)),
|
||||||
|
|
@ -52,7 +51,8 @@ class MyApp extends StatelessWidget {
|
||||||
colorScheme: const ColorScheme.light(
|
colorScheme: const ColorScheme.light(
|
||||||
// 修改亮色主题的主题颜色
|
// 修改亮色主题的主题颜色
|
||||||
primary: Color.fromRGBO(46, 91, 255, 1),
|
primary: Color.fromRGBO(46, 91, 255, 1),
|
||||||
)),
|
)
|
||||||
|
),
|
||||||
enableLog: true,
|
enableLog: true,
|
||||||
logWriterCallback: (text, {bool isError = false}) {
|
logWriterCallback: (text, {bool isError = false}) {
|
||||||
// isError ? LoggerUtils.e(text) : LoggerUtils.i(text);
|
// isError ? LoggerUtils.e(text) : LoggerUtils.i(text);
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import 'package:making_school_asignment_app/common/config/colorUtils.dart';
|
||||||
// 快捷Text使用
|
// 快捷Text使用
|
||||||
Text quickText(text,
|
Text quickText(text,
|
||||||
{double? size,
|
{double? size,
|
||||||
double? wordSpacing,
|
|
||||||
Color color = CommonColors.defaultColor,
|
Color color = CommonColors.defaultColor,
|
||||||
TextAlign? align,
|
TextAlign? align,
|
||||||
FontWeight? fontWeight,
|
FontWeight? fontWeight,
|
||||||
|
|
@ -29,7 +28,6 @@ Text quickText(text,
|
||||||
fontSize: size,
|
fontSize: size,
|
||||||
color: color,
|
color: color,
|
||||||
fontWeight: fontWeight,
|
fontWeight: fontWeight,
|
||||||
wordSpacing: wordSpacing,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,42 +90,11 @@ class _DropdownSwitchStudentsTypeState extends State<DropdownSwitchStudentsType>
|
||||||
value: sateData.value?.studentId,
|
value: sateData.value?.studentId,
|
||||||
underline: Container(),
|
underline: Container(),
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
onTap: () {
|
|
||||||
print('数据..................');
|
|
||||||
},
|
|
||||||
items: sateData.value?.students.map((e) {
|
items: sateData.value?.students.map((e) {
|
||||||
return DropdownMenuItem(
|
return DropdownMenuItem(value: e.id, child: quickText(e.name, color: const Color.fromRGBO(79, 79, 79, 1), size: 14.sp));
|
||||||
value: e.id,
|
|
||||||
child: Stack(
|
|
||||||
alignment: const FractionalOffset(0, 0.62),
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
padding: sateData.value?.studentId != e.id && e.isPriority ? EdgeInsets.only(left: 14.w) : null,
|
|
||||||
child: quickText(
|
|
||||||
e.name,
|
|
||||||
size: 14.sp,
|
|
||||||
color: const Color.fromRGBO(79, 79, 79, 1),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (e.isPriority && sateData.value?.studentId != e.id)
|
|
||||||
Stack(
|
|
||||||
alignment: const FractionalOffset(0.52, 0.24),
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
const IconData(0xe63d, fontFamily: "AlibabaIcon"),
|
|
||||||
size: 12.sp,
|
|
||||||
color: e.isPriority ? const Color.fromRGBO(76, 199, 147, 1) : const Color.fromRGBO(164, 164, 164, 1),
|
|
||||||
),
|
|
||||||
quickText('优先', size: 4.sp, color: Colors.white),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
}).toList(),
|
||||||
hint: const Text('请选择学生'), // 锚点的显示文本
|
hint: const Text('请选择学生'), // 锚点的显示文本
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
print('1111111111');
|
|
||||||
if (logic.state.param.value.studentId == value) return;
|
if (logic.state.param.value.studentId == value) return;
|
||||||
logic.state.param.value.studentId = value;
|
logic.state.param.value.studentId = value;
|
||||||
logic.state.param.value = DoPaperDetailsParam.fromJson(logic.state.param.value.toJson());
|
logic.state.param.value = DoPaperDetailsParam.fromJson(logic.state.param.value.toJson());
|
||||||
|
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
import 'package:making_school_asignment_app/common/config/request_config.dart';
|
|
||||||
|
|
||||||
part 'job_handwriting.g.dart';
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class JobHandwriting extends Object {
|
|
||||||
@JsonKey(name: 'lattices')
|
|
||||||
List<Lattices> lattices;
|
|
||||||
|
|
||||||
@JsonKey(name: 'paperPicture')
|
|
||||||
String paperPicture;
|
|
||||||
|
|
||||||
@JsonKey(name: 'pageNum')
|
|
||||||
int pageNum;
|
|
||||||
|
|
||||||
@JsonKey(name: 'pageCount')
|
|
||||||
int pageCount;
|
|
||||||
|
|
||||||
JobHandwriting(this.lattices, this.paperPicture, this.pageNum, this.pageCount);
|
|
||||||
|
|
||||||
factory JobHandwriting.fromJson(Map<String, dynamic> srcJson) => _$JobHandwritingFromJson(srcJson);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$JobHandwritingToJson(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class Lattices extends Object {
|
|
||||||
// 笔画
|
|
||||||
@JsonKey(name: 'stroke')
|
|
||||||
int stroke;
|
|
||||||
|
|
||||||
@JsonKey(name: 'x')
|
|
||||||
double x;
|
|
||||||
|
|
||||||
@JsonKey(name: 'y')
|
|
||||||
double y;
|
|
||||||
|
|
||||||
@JsonKey(name: 'time')
|
|
||||||
int time;
|
|
||||||
|
|
||||||
@JsonKey(name: 'intervalTime')
|
|
||||||
int intervalTime;
|
|
||||||
|
|
||||||
@JsonKey(name: 'initialization')
|
|
||||||
bool initialization;
|
|
||||||
|
|
||||||
Lattices(this.stroke, this.x, this.y, this.time, [this.intervalTime = 0, this.initialization = false]);
|
|
||||||
|
|
||||||
factory Lattices.fromJson(Map<String, dynamic> srcJson) => _$LatticesFromJson(srcJson);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$LatticesToJson(this);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据基准初始化坐标数据
|
|
||||||
* @param double scaleRatio
|
|
||||||
*/
|
|
||||||
void toInitialization(double scaleRatio) {
|
|
||||||
x = x * scaleRatio;
|
|
||||||
y = y * scaleRatio;
|
|
||||||
initialization = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,979 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
||||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
||||||
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:get/get_connect/http/src/request/request.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/original_manuscript_handwriting_params.dart';
|
|
||||||
import 'package:making_school_asignment_app/common/mixins/event_bus_mixin.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/cached_network_img.dart';
|
|
||||||
import 'package:making_school_asignment_app/common/utils/my_time_util.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/page/global_widget/my_text.dart';
|
|
||||||
import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/job_handwriting.dart';
|
|
||||||
|
|
||||||
import 'configuration_files/logic.dart';
|
|
||||||
import 'configuration_files/states.dart';
|
|
||||||
|
|
||||||
part 'answer_handwriting_view.g.dart';
|
|
||||||
|
|
||||||
/// 学生答题轨迹
|
|
||||||
class AnswerHandwriting extends Dialog {
|
|
||||||
final String homeworkId;
|
|
||||||
final int studentId;
|
|
||||||
final int? templateId;
|
|
||||||
final int? pageNum;
|
|
||||||
final int? questionNo;
|
|
||||||
final Function closeCall;
|
|
||||||
AnswerHandwriting(
|
|
||||||
{super.key, required this.homeworkId, required this.studentId, required this.closeCall, this.templateId, this.pageNum, this.questionNo}) {
|
|
||||||
Get.find<HandwritingLogic>().params.value = OriginalManuscriptHandwritingParams(
|
|
||||||
homeworkId: homeworkId,
|
|
||||||
studentId: studentId,
|
|
||||||
templateId: templateId,
|
|
||||||
pageNum: pageNum,
|
|
||||||
questionNo: questionNo,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
final _handwritingLogic = Get.find<HandwritingLogic>();
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
var boxHeight = ScreenUtil().screenHeight / 1.168; // 盒子高度
|
|
||||||
var boxWidth = ScreenUtil().screenWidth - (ScreenUtil().scaleWidth < 1.5 ? 40.r : 40.r); // 盒子宽度
|
|
||||||
|
|
||||||
return Center(
|
|
||||||
child: Container(
|
|
||||||
height: boxHeight,
|
|
||||||
width: boxWidth,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: AnswerHandwritingMainBox(
|
|
||||||
handwritingLogic: _handwritingLogic,
|
|
||||||
boxHeight: boxHeight,
|
|
||||||
boxWidth: boxWidth,
|
|
||||||
homeworkId: homeworkId,
|
|
||||||
templateId: templateId,
|
|
||||||
studentId: studentId,
|
|
||||||
pageNum: pageNum,
|
|
||||||
questionNo: questionNo,
|
|
||||||
closeCall: closeCall,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> showAnswerHandwriting(
|
|
||||||
BuildContext context, {
|
|
||||||
required String homeworkId,
|
|
||||||
required int studentId,
|
|
||||||
int? templateId,
|
|
||||||
int? pageNum,
|
|
||||||
int? questionNo,
|
|
||||||
}) async {
|
|
||||||
try {
|
|
||||||
backCall() {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
Get.put(HandwritingLogic(backCall));
|
|
||||||
await showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (BuildContext context) => AnswerHandwriting(
|
|
||||||
homeworkId: homeworkId,
|
|
||||||
templateId: templateId,
|
|
||||||
studentId: studentId,
|
|
||||||
pageNum: pageNum,
|
|
||||||
questionNo: questionNo,
|
|
||||||
closeCall: backCall,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
Get.delete<HandwritingLogic>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 主图
|
|
||||||
class AnswerHandwritingMainBox extends HookWidget with EventBusMixin {
|
|
||||||
AnswerHandwritingMainBox({
|
|
||||||
required this.handwritingLogic,
|
|
||||||
required this.homeworkId,
|
|
||||||
required this.studentId,
|
|
||||||
required this.closeCall,
|
|
||||||
required this.boxHeight,
|
|
||||||
required this.boxWidth,
|
|
||||||
this.templateId,
|
|
||||||
this.pageNum,
|
|
||||||
this.questionNo,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
final HandwritingLogic handwritingLogic;
|
|
||||||
|
|
||||||
final String homeworkId;
|
|
||||||
final double boxHeight;
|
|
||||||
final double boxWidth;
|
|
||||||
final int? templateId;
|
|
||||||
final int studentId;
|
|
||||||
final int? pageNum;
|
|
||||||
final int? questionNo;
|
|
||||||
final Function closeCall;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
var _useStateModel = UseMainBoxState.use(homeworkId, studentId, pageNum, questionNo, templateId);
|
|
||||||
double barHeight = 62.h;
|
|
||||||
double imageHeight = boxHeight - barHeight;
|
|
||||||
useValueChanged<JobHandwriting?, void>(_useStateModel.handwritingData.value, (_, __) {
|
|
||||||
var theData = _useStateModel.handwritingData.value;
|
|
||||||
_useStateModel.pageNum.value = theData?.pageNum;
|
|
||||||
_useStateModel.pageCount.value = theData?.pageCount ?? 0;
|
|
||||||
_useStateModel.playPause.value = false;
|
|
||||||
_useStateModel.constantFastSpeed.value = false;
|
|
||||||
// Future.delayed(Duration.zero, () {
|
|
||||||
// _useStateModel.handwritingKey.currentState?.ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]);
|
|
||||||
// });
|
|
||||||
// _useStateModel.handwritingDetail.value = _useStateModel.getHandwritingDetail(theData);
|
|
||||||
});
|
|
||||||
|
|
||||||
useValueChanged<int?, void>(_useStateModel.pageNum.value, (oldVal, __) {
|
|
||||||
if (oldVal != null && oldVal != _useStateModel.pageNum.value) {
|
|
||||||
_useStateModel.questionNo = null;
|
|
||||||
// _useStateModel.getData().catchError((e) => closeCall());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
JobHandwriting? data = _useStateModel.handwritingData.value;
|
|
||||||
HandwritingInfo? dataDetail = _useStateModel.handwritingDetail.value;
|
|
||||||
|
|
||||||
// if (data == null || dataDetail == null) return Container();
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: imageHeight,
|
|
||||||
width: boxWidth,
|
|
||||||
child: Stack(
|
|
||||||
alignment: const FractionalOffset(0, 0.5),
|
|
||||||
children: [
|
|
||||||
// 图片展示主框
|
|
||||||
SingleChildScrollView(
|
|
||||||
child: HandwritingDrawBox(
|
|
||||||
boxWidth: boxWidth,
|
|
||||||
boxHeight: boxHeight,
|
|
||||||
key: _useStateModel.handwritingKey,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
PageNumberBox(),
|
|
||||||
PreviousNutton(), // 上一页按钮
|
|
||||||
NextPageButton(), // 下一题按钮
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
$BottomPlaybar(barHeight, handwritingLogic),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UseMainBoxState with RequestToolMixin {
|
|
||||||
final String homeworkId;
|
|
||||||
final int studentId;
|
|
||||||
final int? templateId;
|
|
||||||
int? questionNo;
|
|
||||||
final ValueNotifier<int?> pageNum;
|
|
||||||
final ValueNotifier<int> pageCount;
|
|
||||||
final ValueNotifier<JobHandwriting?> handwritingData;
|
|
||||||
final ValueNotifier<HandwritingInfo?> handwritingDetail;
|
|
||||||
|
|
||||||
final ValueNotifier<bool> playPause; // 播放暂停
|
|
||||||
final ValueNotifier<bool> constantFastSpeed; // 原速、快速 默认原速
|
|
||||||
|
|
||||||
GlobalKey<_HandwritingDrawBoxState> handwritingKey;
|
|
||||||
|
|
||||||
UseMainBoxState._({
|
|
||||||
required this.homeworkId,
|
|
||||||
required this.templateId,
|
|
||||||
required this.studentId,
|
|
||||||
required this.pageNum,
|
|
||||||
required this.handwritingData,
|
|
||||||
required this.questionNo,
|
|
||||||
required this.pageCount,
|
|
||||||
required this.playPause,
|
|
||||||
required this.constantFastSpeed,
|
|
||||||
required this.handwritingDetail,
|
|
||||||
required this.handwritingKey,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 工厂构造函数
|
|
||||||
factory UseMainBoxState.use(String homeworkId, int studentId, [int? pageNum, int? questionNo, int? templateId]) {
|
|
||||||
return UseMainBoxState._(
|
|
||||||
homeworkId: homeworkId,
|
|
||||||
templateId: templateId,
|
|
||||||
studentId: studentId,
|
|
||||||
questionNo: questionNo,
|
|
||||||
pageNum: useState(pageNum),
|
|
||||||
handwritingData: useState(null),
|
|
||||||
handwritingDetail: useState(null),
|
|
||||||
pageCount: useState(0),
|
|
||||||
playPause: useState(false),
|
|
||||||
constantFastSpeed: useState(false),
|
|
||||||
handwritingKey: GlobalKey(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 上一页
|
|
||||||
class PreviousNutton extends StatelessWidget {
|
|
||||||
PreviousNutton({super.key});
|
|
||||||
|
|
||||||
final HandwritingLogic handwritingLogic = Get.find<HandwritingLogic>();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Obx(() {
|
|
||||||
if (handwritingLogic.resultData.value?.pageNum != null && handwritingLogic.resultData.value!.pageNum > 1) {
|
|
||||||
return Positioned(
|
|
||||||
left: 3.w,
|
|
||||||
child: FloatingActionButton(
|
|
||||||
heroTag: '点击前往上一题',
|
|
||||||
tooltip: '点击前往上一题',
|
|
||||||
focusColor: Theme.of(context).primaryColor,
|
|
||||||
backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1),
|
|
||||||
elevation: 6.r,
|
|
||||||
onPressed: () => easyThrottle('answer_handwriting_previous', () {
|
|
||||||
var resultData = handwritingLogic.resultData.value;
|
|
||||||
var params = handwritingLogic.params.value;
|
|
||||||
if (resultData == null || params == null) return;
|
|
||||||
params.pageNum = resultData.pageNum - 1;
|
|
||||||
handwritingLogic.params.value = OriginalManuscriptHandwritingParams.fromJson(params.toJson());
|
|
||||||
// handwritingLogic.params.value = params;
|
|
||||||
}),
|
|
||||||
child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return const SizedBox();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 下一页
|
|
||||||
class NextPageButton extends StatelessWidget {
|
|
||||||
final HandwritingLogic handwritingLogic = Get.find<HandwritingLogic>();
|
|
||||||
|
|
||||||
NextPageButton({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Obx(() {
|
|
||||||
if (handwritingLogic.resultData.value?.pageNum != null &&
|
|
||||||
handwritingLogic.resultData.value!.pageNum < handwritingLogic.resultData.value!.pageCount) {
|
|
||||||
return Positioned(
|
|
||||||
right: 3.w,
|
|
||||||
child: FloatingActionButton(
|
|
||||||
heroTag: '点击前往下一题',
|
|
||||||
tooltip: '点击前往下一题',
|
|
||||||
elevation: 6.r,
|
|
||||||
backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1),
|
|
||||||
onPressed: () => easyThrottle('answer_handwriting_next', () {
|
|
||||||
var resultData = handwritingLogic.resultData.value;
|
|
||||||
var params = handwritingLogic.params.value;
|
|
||||||
if (resultData == null || params == null) return;
|
|
||||||
params.pageNum = resultData.pageNum + 1;
|
|
||||||
handwritingLogic.params.value = OriginalManuscriptHandwritingParams.fromJson(params.toJson());
|
|
||||||
}),
|
|
||||||
child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return const SizedBox();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 笔记还原主框
|
|
||||||
class HandwritingDrawBox extends StatefulWidget {
|
|
||||||
final double boxWidth;
|
|
||||||
final double boxHeight;
|
|
||||||
const HandwritingDrawBox({required this.boxWidth, required this.boxHeight, super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<HandwritingDrawBox> createState() => _HandwritingDrawBoxState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _HandwritingDrawBoxState extends State<HandwritingDrawBox> with EventBusMixin {
|
|
||||||
HandwritingLogic handwritingLogic = Get.find<HandwritingLogic>(); // 学生答题笔迹逻辑层
|
|
||||||
|
|
||||||
ImageStream? imageStream; // 图片监听数据
|
|
||||||
late ImageStreamListener theImageStreamListener; // 试题图片数据
|
|
||||||
|
|
||||||
late ValueNotifier<List<GestureHandwritingRecording>> _vnHandWritings;
|
|
||||||
late ValueNotifier<List<GestureHandwritingRecording>> _vnPrimaryHandWritings;
|
|
||||||
|
|
||||||
late StreamSubscription showManuscriptStream;
|
|
||||||
late StreamSubscription executionDataStream;
|
|
||||||
|
|
||||||
List<List<GestureHandwritingRecording>> _packagedHandwritingDatas = [];
|
|
||||||
List<GestureHandwritingRecording> _packagedHandwritingDataAll = []; // 总数据
|
|
||||||
List<GestureHandwritingRecording> pendingData = []; // 待执行数据
|
|
||||||
List<Timer> timers = [];
|
|
||||||
int handwritingTime = 0;
|
|
||||||
int handwritingDuration = 0;
|
|
||||||
double speed = 2.0; // 播放速度
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState(); /* */
|
|
||||||
|
|
||||||
theImageStreamListener = ImageStreamListener((ImageInfo info, bool _) {
|
|
||||||
// 获取图片的宽高
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
//需要创建的小组件
|
|
||||||
handwritingLogic.imagInfoModel.value = TestQuestionsImageInfo(
|
|
||||||
url: handwritingLogic.resultData.value!.paperPicture,
|
|
||||||
boxWidth: widget.boxWidth,
|
|
||||||
boxHeight: widget.boxHeight,
|
|
||||||
imageWidth: info.image.width.toDouble(),
|
|
||||||
imageHeight: info.image.height.toDouble(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
_vnHandWritings = ValueNotifier<List<GestureHandwritingRecording>>([]);
|
|
||||||
_vnPrimaryHandWritings = ValueNotifier<List<GestureHandwritingRecording>>(_packagedHandwritingDataAll);
|
|
||||||
|
|
||||||
handwritingLogic.toolbar.initialization.listen((e) {
|
|
||||||
// 数据初始化完成赋值数据
|
|
||||||
if (e) {
|
|
||||||
_packagedHandwritingDatas = handwritingLogic.packagedHandwritingDatas.value;
|
|
||||||
_packagedHandwritingDataAll = handwritingLogic.packagedHandwritingDataAll.value;
|
|
||||||
} else {
|
|
||||||
_packagedHandwritingDatas = [];
|
|
||||||
_packagedHandwritingDataAll = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
_vnPrimaryHandWritings.value = [..._packagedHandwritingDataAll]; // 总体数据
|
|
||||||
// eventFire(model: JobHandwritingPlaybarBus);
|
|
||||||
});
|
|
||||||
showManuscriptStream = handwritingLogic.toolbar.showManuscript.listen((e) {
|
|
||||||
// 查看原稿控制
|
|
||||||
if (e) {
|
|
||||||
// 查看原稿
|
|
||||||
eventFire(model: JobHandwritingPlaybarBus(false)); // 暂停
|
|
||||||
_vnPrimaryHandWritings.value = [..._packagedHandwritingDataAll];
|
|
||||||
} else {
|
|
||||||
// 清空原稿数据
|
|
||||||
_vnPrimaryHandWritings.value = [];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
executionDataStream = handwritingLogic.toolbar.executionData.listen((e) => _vnHandWritings.value = e);
|
|
||||||
|
|
||||||
eventOn(callback: (e) {
|
|
||||||
switch (e.runtimeType) {
|
|
||||||
case JobHandwritingRunTimeBus:
|
|
||||||
var _model = (e as JobHandwritingRunTimeBus);
|
|
||||||
var _runtime = _model.runTimeVal;
|
|
||||||
handwritingDuration = _model.totalVal;
|
|
||||||
handwritingTime = _runtime;
|
|
||||||
if (_runtime <= 0) {
|
|
||||||
pendingData.clear();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JobHandwritingDragProgressBarBus:
|
|
||||||
var _model = (e as JobHandwritingDragProgressBarBus);
|
|
||||||
dragProgressBarInitData(_model.changeVal, _model.totalVal);
|
|
||||||
break;
|
|
||||||
case JobHandwritingPlaybarBus:
|
|
||||||
// 播放 暂停
|
|
||||||
var _val = e as JobHandwritingPlaybarBus;
|
|
||||||
if (_val.play) {
|
|
||||||
// 播放
|
|
||||||
toGoPlay();
|
|
||||||
} else {
|
|
||||||
// 暂停
|
|
||||||
toGoPause(_val.recalculate);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PlaybackSpeedBus:
|
|
||||||
// 播放速度
|
|
||||||
var _model = (e as PlaybackSpeedBus);
|
|
||||||
speed = _model.speed;
|
|
||||||
dragProgressBarInitData(handwritingDuration - handwritingTime, handwritingDuration);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
imageStream?.removeListener(theImageStreamListener);
|
|
||||||
showManuscriptStream.cancel();
|
|
||||||
executionDataStream.cancel();
|
|
||||||
eventCancel();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 暂停播放
|
|
||||||
Future<void> toGoPause(bool recalculate) async {
|
|
||||||
timers.forEach((e) {
|
|
||||||
if (e.isActive) e.cancel();
|
|
||||||
});
|
|
||||||
timers = [];
|
|
||||||
// 总时间-剩余时间=已经执行时间
|
|
||||||
if (recalculate && pendingData.isNotEmpty && handwritingTime > 0 && (handwritingDuration - handwritingTime > 0)) {
|
|
||||||
// 待执行的数据不等于空 每个数据都需要减去当前暂停已经执行的时间
|
|
||||||
pendingData = pendingData.map((e) {
|
|
||||||
return GestureHandwritingRecording(
|
|
||||||
stroke: e.stroke,
|
|
||||||
data: e.data,
|
|
||||||
usageTime: e.usageTime,
|
|
||||||
intervalTime: e.intervalTime - (handwritingDuration - handwritingTime) * 1000,
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 开始播放
|
|
||||||
Future<void> toGoPlay() async {
|
|
||||||
try {
|
|
||||||
var executableData = _packagedHandwritingDataAll;
|
|
||||||
if (pendingData.isNotEmpty) {
|
|
||||||
// 待执行的数据没有执行完成 就继续执行待执行数据
|
|
||||||
executableData = pendingData;
|
|
||||||
} else {
|
|
||||||
// 需要重新添加所有数据进行播放
|
|
||||||
pendingData.addAll(_packagedHandwritingDataAll);
|
|
||||||
handwritingLogic.toolbar.executionData.value = []; // 重置已经执行的数据
|
|
||||||
}
|
|
||||||
handwritingLogic.toolbar.showManuscript.value = false;
|
|
||||||
executableData.forEach((e) {
|
|
||||||
var ter = Timer(Duration(milliseconds: e.intervalTime ~/ speed), () => zhixinCall(e));
|
|
||||||
timers.add(ter);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
print('播放报错:$e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> zhixinCall(GestureHandwritingRecording e) async {
|
|
||||||
if (mounted) {
|
|
||||||
List<GestureHandwritingRecording> trajectorys = handwritingLogic.toolbar.executionData.value..add(e);
|
|
||||||
handwritingLogic.toolbar.executionData.value = List.from(trajectorys);
|
|
||||||
pendingData.remove(e); // 执行后删除容器中的当前动作
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 拖动进度条后重新初始化数据
|
|
||||||
/// @param startTime 起始时间 单位秒
|
|
||||||
Future<void> dragProgressBarInitData(int startTime, int totalDuration) async {
|
|
||||||
eventFire(model: JobHandwritingPlaybarBus(false, false));
|
|
||||||
timers.forEach((e) {
|
|
||||||
if (e.isActive) e.cancel();
|
|
||||||
});
|
|
||||||
timers = [];
|
|
||||||
pendingData.clear();
|
|
||||||
|
|
||||||
if (startTime == 0) {
|
|
||||||
handwritingLogic.toolbar.executionData.value = []; // 重置已经执行的数据
|
|
||||||
pendingData.addAll(_packagedHandwritingDataAll);
|
|
||||||
} else {
|
|
||||||
// 待执行的数据不等于空 每个数据都需要减去当前暂停已经执行的时间
|
|
||||||
startTime = startTime * 1000; // 转为毫秒
|
|
||||||
List<GestureHandwritingRecording> executeImmediately = []; // 立即执行数据
|
|
||||||
List<GestureHandwritingRecording> waitingExecution = []; // 等待执行数据
|
|
||||||
|
|
||||||
for (var i = 0; i < _packagedHandwritingDataAll.length; i++) {
|
|
||||||
var item = _packagedHandwritingDataAll[i];
|
|
||||||
|
|
||||||
if (item.intervalTime < startTime) {
|
|
||||||
// 需要直接装配到直接打印的容器
|
|
||||||
executeImmediately.add(item);
|
|
||||||
} else {
|
|
||||||
var intervalTime = item.intervalTime - startTime;
|
|
||||||
// 需要等待的数据
|
|
||||||
waitingExecution.add(GestureHandwritingRecording(
|
|
||||||
stroke: item.stroke,
|
|
||||||
data: item.data,
|
|
||||||
usageTime: item.usageTime,
|
|
||||||
intervalTime: intervalTime,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingData = waitingExecution;
|
|
||||||
handwritingLogic.toolbar.executionData.value = executeImmediately;
|
|
||||||
}
|
|
||||||
eventFire(model: JobHandwritingPlaybarBus(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Obx(() {
|
|
||||||
print('进入了....................');
|
|
||||||
var paperPicture = handwritingLogic.resultData.value?.paperPicture;
|
|
||||||
if (paperPicture == null) return const SizedBox();
|
|
||||||
|
|
||||||
print('显示原稿:${handwritingLogic.toolbar.showManuscript.value} 数据:${_vnPrimaryHandWritings.value.length}');
|
|
||||||
return RepaintBoundary(
|
|
||||||
child: CustomPaint(
|
|
||||||
foregroundPainter: HandWritingDrawingPainter(
|
|
||||||
ctrl: handwritingLogic.toolbar.showManuscript.value ? _vnPrimaryHandWritings : _vnHandWritings,
|
|
||||||
),
|
|
||||||
child: $TheCachedNetworkImage(
|
|
||||||
imageUrl: paperPicture,
|
|
||||||
(context, imageProvider) {
|
|
||||||
Image imageWidget = Image(image: imageProvider, fit: BoxFit.contain);
|
|
||||||
if (handwritingLogic.imagInfoModel.value == null) {
|
|
||||||
imageStream?.removeListener(theImageStreamListener);
|
|
||||||
imageStream = imageWidget.image.resolve(const ImageConfiguration());
|
|
||||||
imageStream?.addListener(theImageStreamListener);
|
|
||||||
}
|
|
||||||
return imageWidget;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class HandWritingDrawingPainter extends CustomPainter {
|
|
||||||
final ValueNotifier<List<GestureHandwritingRecording>> ctrl;
|
|
||||||
HandWritingDrawingPainter({required this.ctrl}) : super(repaint: ctrl);
|
|
||||||
//[定义画笔]
|
|
||||||
final Paint paintBrush = Paint()
|
|
||||||
//画笔颜色
|
|
||||||
..color = Colors.black
|
|
||||||
//画笔笔触类型
|
|
||||||
..strokeCap = StrokeCap.round
|
|
||||||
//是否启动抗锯齿
|
|
||||||
..isAntiAlias = true
|
|
||||||
//绘画风格,默认为填充
|
|
||||||
// ..style = PaintingStyle.fill
|
|
||||||
//画笔的宽度
|
|
||||||
..style = PaintingStyle.stroke
|
|
||||||
..strokeWidth = 0.5.r;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void paint(Canvas canvas, Size size) {
|
|
||||||
// canvas.drawPoints(PointMode.points, thePoints, paintBrush);
|
|
||||||
canvas.save();
|
|
||||||
|
|
||||||
var points = ctrl.value;
|
|
||||||
var _length = points.length;
|
|
||||||
for (int i = 0; i < _length; i++) {
|
|
||||||
GestureHandwritingRecording item = points[i];
|
|
||||||
GestureHandwritingRecording? nextItem = i + 1 < _length ? points[i + 1] : null;
|
|
||||||
|
|
||||||
Offset offsetData = item.data;
|
|
||||||
Offset? nextOffsetData = nextItem?.data;
|
|
||||||
if (nextOffsetData != null && item.stroke == nextItem?.stroke) {
|
|
||||||
canvas.drawLine(offsetData, nextOffsetData, paintBrush);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
canvas.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool shouldRepaint(covariant CustomPainter oldDelegate) {
|
|
||||||
if (oldDelegate is HandWritingDrawingPainter) {
|
|
||||||
var repaint = ctrl.value.length != oldDelegate.ctrl.value.length || oldDelegate.ctrl.value != ctrl.value;
|
|
||||||
print('调用是否绘制:$repaint');
|
|
||||||
return repaint;
|
|
||||||
}
|
|
||||||
return true; // 如果 oldDelegate 不是 MyCustomPainter 的实例,则总是重绘
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 页码
|
|
||||||
class PageNumberBox extends StatelessWidget {
|
|
||||||
PageNumberBox({super.key});
|
|
||||||
|
|
||||||
final HandwritingLogic handwritingLogic = Get.find<HandwritingLogic>(); // 学生答题笔迹逻辑层
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Positioned(
|
|
||||||
top: 6.h,
|
|
||||||
right: 4.w,
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: const Color.fromRGBO(0, 0, 0, 0.47),
|
|
||||||
borderRadius: BorderRadius.circular(5.r),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
Obx(() {
|
|
||||||
return quickText('${handwritingLogic.resultData.value?.pageNum ?? 0}', color: Colors.white, size: 11.sp, align: TextAlign.end);
|
|
||||||
}),
|
|
||||||
quickText('/', color: Colors.white, size: 10.sp, align: TextAlign.end),
|
|
||||||
Obx(() {
|
|
||||||
return quickText('${handwritingLogic.resultData.value?.pageCount ?? 0}', color: Colors.white, size: 8.sp, align: TextAlign.end);
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@hwidget
|
|
||||||
Widget $bottomPlaybar(BuildContext context, double barHeight, HandwritingLogic handwritingLogic) {
|
|
||||||
var timeConsuming = useState(0);
|
|
||||||
var handwritingInfo = useState<HandwritingInfo?>(null);
|
|
||||||
|
|
||||||
var usePlaybar = UseBottomPlaybar.use(timeConsuming.value);
|
|
||||||
useValueChanged<int, void>(timeConsuming.value, (_, __) {
|
|
||||||
usePlaybar.playTimingSuspend();
|
|
||||||
usePlaybar.playPause.value = false;
|
|
||||||
var seds = timeConsuming.value ~/ 1000;
|
|
||||||
if ((timeConsuming.value % 1000) > 500) seds += 1;
|
|
||||||
usePlaybar.handwritingDuration.value = seds;
|
|
||||||
usePlaybar.constantFastSpeed.value = PlaybackSpeed.DOUBLE_SPEED;
|
|
||||||
});
|
|
||||||
|
|
||||||
useValueChanged<int, void>(usePlaybar.handwritingDuration.value, (_, __) {
|
|
||||||
usePlaybar.useTime.value = usePlaybar.handwritingDuration.value;
|
|
||||||
});
|
|
||||||
// 播放速度
|
|
||||||
useValueChanged<PlaybackSpeed, void>(usePlaybar.constantFastSpeed.value, (_, __) {
|
|
||||||
usePlaybar.eventFire(model: PlaybackSpeedBus(usePlaybar.constantFastSpeed.value.speed));
|
|
||||||
// 播放速度变化
|
|
||||||
usePlaybar.playTimingSuspend();
|
|
||||||
usePlaybar.playTimingStarts();
|
|
||||||
});
|
|
||||||
// 计时结束监听
|
|
||||||
useValueChanged<int, void>(usePlaybar.useTime.value, (_, __) {
|
|
||||||
var _runtime = usePlaybar.useTime.value;
|
|
||||||
if (_runtime <= 0 || usePlaybar.handwritingDuration.value == _runtime) {
|
|
||||||
Future.delayed(Duration.zero, () => (usePlaybar.playPause.value = false)); // 初始化播放按钮
|
|
||||||
}
|
|
||||||
usePlaybar.eventFire(model: JobHandwritingRunTimeBus(_runtime, usePlaybar.handwritingDuration.value));
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() {
|
|
||||||
// 初始化
|
|
||||||
var initialization = handwritingLogic.toolbar.initialization.listen((e) {
|
|
||||||
usePlaybar.handWritingReady.value = e;
|
|
||||||
});
|
|
||||||
var handwritingInfoStream = handwritingLogic.handwritingInfo.listen((e) {
|
|
||||||
// 笔迹数据
|
|
||||||
if (e == null) return;
|
|
||||||
handwritingInfo.value = e;
|
|
||||||
timeConsuming.value = e.timeConsuming;
|
|
||||||
});
|
|
||||||
usePlaybar.eventOn(callback: (e) {
|
|
||||||
switch (e.runtimeType) {
|
|
||||||
case JobHandwritingPlaybarBus:
|
|
||||||
// 出发播放暂停
|
|
||||||
var _val = e as JobHandwritingPlaybarBus;
|
|
||||||
if (_val.play) {
|
|
||||||
// 开始播放
|
|
||||||
usePlaybar.playTimingStarts();
|
|
||||||
if (!usePlaybar.playPause.value) usePlaybar.playPause.value = true;
|
|
||||||
} else {
|
|
||||||
// 暂停播放
|
|
||||||
usePlaybar.playTimingSuspend();
|
|
||||||
if (usePlaybar.playPause.value) usePlaybar.playPause.value = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case JobHandwritingGetReadyBus:
|
|
||||||
// 作业笔迹已经计算好坐标 可以开始播放
|
|
||||||
Future.delayed(Duration.zero, () => (usePlaybar.handWritingReady.value = true));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return () {
|
|
||||||
try {
|
|
||||||
initialization.cancel();
|
|
||||||
usePlaybar.eventCancel();
|
|
||||||
handwritingInfoStream.cancel();
|
|
||||||
usePlaybar.timer.value?.cancel();
|
|
||||||
} catch (e) {
|
|
||||||
print(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return Container(
|
|
||||||
height: barHeight,
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 10.w),
|
|
||||||
alignment: Alignment.center,
|
|
||||||
color: const Color.fromRGBO(0, 0, 0, 0.4),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
if (usePlaybar.handWritingReady.value)
|
|
||||||
InkWell(
|
|
||||||
onTap: () => easyThrottle('job_handwriting_play_pause', () {
|
|
||||||
if (usePlaybar.handwritingDuration.value == 0) return ToastUtils.showInfo('没有笔迹');
|
|
||||||
|
|
||||||
usePlaybar.playPause.value = !usePlaybar.playPause.value;
|
|
||||||
usePlaybar.eventFire(model: JobHandwritingPlaybarBus(usePlaybar.playPause.value));
|
|
||||||
}),
|
|
||||||
child: Icon(
|
|
||||||
!usePlaybar.playPause.value ? Icons.play_circle_outline : Icons.pause_circle_outline,
|
|
||||||
color: Colors.white,
|
|
||||||
size: 28.r,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
else
|
|
||||||
SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white),
|
|
||||||
SizedBox(width: 6.w),
|
|
||||||
Expanded(
|
|
||||||
child: LayoutBuilder(builder: (context, constraints) {
|
|
||||||
final double containerWidth = constraints.maxWidth; // 展示区域总宽度
|
|
||||||
var unitScale = containerWidth / timeConsuming.value; // 单位刻度
|
|
||||||
var pauseIntervalsLength = handwritingInfo.value?.pauseInterval.length ?? 0;
|
|
||||||
|
|
||||||
List<Widget> pauseTickMarks = handwritingInfo.value?.pauseInterval.asMap().keys.map((e) {
|
|
||||||
bool isLast = e == pauseIntervalsLength - 1;
|
|
||||||
bool isFirst = e == 0;
|
|
||||||
var item = handwritingInfo.value!.pauseInterval[e];
|
|
||||||
return Positioned(
|
|
||||||
top: 0,
|
|
||||||
left: unitScale * item.startTime,
|
|
||||||
child: Container(
|
|
||||||
width: unitScale * (item.apart ?? 0),
|
|
||||||
height: 10.h,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Color.fromRGBO(202, 201, 201, 1),
|
|
||||||
borderRadius: isFirst
|
|
||||||
? BorderRadius.only(topLeft: Radius.circular(8.r), bottomLeft: Radius.circular(10.r))
|
|
||||||
: (isLast ? BorderRadius.only(topRight: Radius.circular(8.r), bottomRight: Radius.circular(10.r)) : null),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList() ??
|
|
||||||
[];
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Stack(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
height: 10.h,
|
|
||||||
width: containerWidth,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
// color: Color.fromRGBO(146, 146, 146, 1),
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(50.r),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
...pauseTickMarks,
|
|
||||||
Container(
|
|
||||||
height: 10.h,
|
|
||||||
width: containerWidth,
|
|
||||||
// color: Theme.of(context).primaryColor,
|
|
||||||
child: SliderTheme(
|
|
||||||
data: SliderTheme.of(context).copyWith(
|
|
||||||
trackHeight: 10.h, // 轨道高度
|
|
||||||
trackShape: RoundedRectSliderTrackShape(), // 轨道形状,可以自定义
|
|
||||||
activeTrackColor: Theme.of(context).primaryColor, // 激活的轨道颜色
|
|
||||||
inactiveTrackColor: Colors.transparent, // 未激活的轨道颜色
|
|
||||||
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 0, disabledThumbRadius: 0),
|
|
||||||
thumbColor: Colors.white, // 滑块颜色
|
|
||||||
overlayShape: RoundSliderOverlayShape(overlayRadius: 0),
|
|
||||||
overlayColor: Colors.black54, // 滑块外圈颜色
|
|
||||||
// valueIndicatorShape: PaddleSliderValueIndicatorShape(), // 标签形状,可以自定义
|
|
||||||
),
|
|
||||||
child: Slider(
|
|
||||||
value: (usePlaybar.handwritingDuration.value - usePlaybar.useTime.value).toDouble(),
|
|
||||||
min: 0.0,
|
|
||||||
max: usePlaybar.handwritingDuration.value.toDouble(),
|
|
||||||
inactiveColor: Colors.transparent,
|
|
||||||
onChangeEnd: (value) {
|
|
||||||
if (!usePlaybar.handWritingReady.value) return;
|
|
||||||
usePlaybar.playTimingSuspend(); // 暂停计时器得暂停
|
|
||||||
usePlaybar.eventFire(model: JobHandwritingDragProgressBarBus(value.toInt(), usePlaybar.handwritingDuration.value));
|
|
||||||
usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt();
|
|
||||||
},
|
|
||||||
onChanged: (double value) {
|
|
||||||
if (!usePlaybar.handWritingReady.value) return;
|
|
||||||
usePlaybar.useTime.value = usePlaybar.handwritingDuration.value - value.toInt();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(height: 8.h),
|
|
||||||
SizedBox(
|
|
||||||
width: containerWidth,
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
quickText('累计停顿:${handwritingInfo.value?.pauseCount ?? 0}次', color: Colors.white, size: 7.sp),
|
|
||||||
quickText(convertSeconds(usePlaybar.useTime.value)?.toString() ?? '', color: Colors.white, size: 7.sp),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
SizedBox(width: 16.w),
|
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
InkWell(
|
|
||||||
onTap: () => easyThrottle('job_handwriting_speed', () {
|
|
||||||
var theIndex = PlaybackSpeed.values.indexOf(usePlaybar.constantFastSpeed.value);
|
|
||||||
if (theIndex == PlaybackSpeed.values.length - 1) {
|
|
||||||
theIndex = -1;
|
|
||||||
}
|
|
||||||
usePlaybar.constantFastSpeed.value = PlaybackSpeed.values[theIndex + 1];
|
|
||||||
}, duration: Duration(milliseconds: 500)),
|
|
||||||
child: Container(
|
|
||||||
// alignment: Alignment.,
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h),
|
|
||||||
decoration: BoxDecoration(color: Color.fromRGBO(182, 197, 250, 1), borderRadius: BorderRadius.circular(4.r)),
|
|
||||||
child: quickText(
|
|
||||||
'${usePlaybar.constantFastSpeed.value.name}',
|
|
||||||
color: Color.fromRGBO(79, 114, 244, 1),
|
|
||||||
size: 8.sp,
|
|
||||||
align: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 7.h),
|
|
||||||
StudentManuscriptBtn(handwritingLogic),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 学生原稿按钮视图
|
|
||||||
class StudentManuscriptBtn extends StatelessWidget {
|
|
||||||
final HandwritingLogic handwritingLogic;
|
|
||||||
const StudentManuscriptBtn(this.handwritingLogic, {super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Obx(() {
|
|
||||||
print('显示原噶:${handwritingLogic.toolbar.showManuscript.value}');
|
|
||||||
return InkWell(
|
|
||||||
onTap: () => easyThrottle('job_handwriting_udent_manuscript', () {
|
|
||||||
var showManuscript = handwritingLogic.toolbar.showManuscript.value;
|
|
||||||
handwritingLogic.toolbar.showManuscript.value = !showManuscript;
|
|
||||||
}),
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(4.r),
|
|
||||||
color: handwritingLogic.toolbar.showManuscript.value ? Theme.of(context).primaryColor : Colors.grey,
|
|
||||||
),
|
|
||||||
child: quickText('学生原稿', color: Colors.white, size: 8.sp, align: TextAlign.center),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SysjTime extends StatefulWidget {
|
|
||||||
const SysjTime({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<SysjTime> createState() => _SysjTimeState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _SysjTimeState extends State<SysjTime> with EventBusMixin<JobHandwritingRunTimeBus> {
|
|
||||||
int useTime = 0;
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
// eventOn(callback: (JobHandwritingRunTimeBus e) {
|
|
||||||
// useTime = e.runTimeVal;
|
|
||||||
// toUpState(setState, () {}, mounted);
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
eventCancel();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return quickText(convertSeconds(useTime)?.toString() ?? '', color: Colors.white, size: 7.sp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UseBottomPlaybar with EventBusMixin {
|
|
||||||
final ValueNotifier<int> handwritingDuration; // 笔迹总时长
|
|
||||||
final ValueNotifier<bool> playPause; // 播放暂停
|
|
||||||
final ValueNotifier<PlaybackSpeed> constantFastSpeed; // 播放速度
|
|
||||||
final ValueNotifier<bool> handWritingReady;
|
|
||||||
|
|
||||||
final ValueNotifier<int> useTime; // 耗时 单位:(秒)
|
|
||||||
|
|
||||||
final ValueNotifier<Timer?> timer;
|
|
||||||
|
|
||||||
UseBottomPlaybar._(
|
|
||||||
{required this.handWritingReady,
|
|
||||||
required this.handwritingDuration,
|
|
||||||
required this.playPause,
|
|
||||||
required this.constantFastSpeed,
|
|
||||||
required this.useTime,
|
|
||||||
required this.timer});
|
|
||||||
|
|
||||||
// 工厂构造函数
|
|
||||||
factory UseBottomPlaybar.use(int milliseconds) {
|
|
||||||
int handwritingDuration = milliseconds ~/ 1000;
|
|
||||||
if ((milliseconds % 1000) > 500) handwritingDuration += 1;
|
|
||||||
return UseBottomPlaybar._(
|
|
||||||
playPause: useState(false),
|
|
||||||
constantFastSpeed: useState(PlaybackSpeed.DOUBLE_SPEED), // 默认两倍速
|
|
||||||
useTime: useState(handwritingDuration),
|
|
||||||
timer: useState(null),
|
|
||||||
handwritingDuration: useState(handwritingDuration),
|
|
||||||
handWritingReady: useState(false),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 开始计时
|
|
||||||
void playTimingStarts() {
|
|
||||||
if (useTime.value > 0) {
|
|
||||||
timer.value?.cancel();
|
|
||||||
|
|
||||||
timer.value = Timer.periodic(Duration(milliseconds: 1000 ~/ constantFastSpeed.value.speed), (theTime) {
|
|
||||||
useTime.value -= 1;
|
|
||||||
if (useTime.value < 0) {
|
|
||||||
theTime.cancel();
|
|
||||||
timer.value?.cancel();
|
|
||||||
timer.value = null;
|
|
||||||
useTime.value = handwritingDuration.value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 暂停
|
|
||||||
void playTimingSuspend() {
|
|
||||||
timer.value?.cancel();
|
|
||||||
timer.value = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
// 逻辑文件
|
|
||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:making_school_asignment_app/common/config/request_config.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/original_manuscript_handwriting_params.dart';
|
|
||||||
import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart';
|
|
||||||
import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
|
|
||||||
import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/job_handwriting.dart';
|
|
||||||
import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/original_manuscript_handwriting/configuration_files/states.dart';
|
|
||||||
|
|
||||||
class HandwritingLogic extends GetxController with RequestToolMixin {
|
|
||||||
Rx<JobHandwriting?> resultData = Rx<JobHandwriting?>(null); // 笔迹数据
|
|
||||||
Rx<HandwritingInfo?> handwritingInfo = Rx<HandwritingInfo?>(null); // 笔迹数据
|
|
||||||
Rx<List<List<GestureHandwritingRecording>>> packagedHandwritingDatas = Rx<List<List<GestureHandwritingRecording>>>([]);
|
|
||||||
Rx<List<GestureHandwritingRecording>> packagedHandwritingDataAll = Rx<List<GestureHandwritingRecording>>([]); // 总数据
|
|
||||||
Rx<OriginalManuscriptHandwritingParams?> params = Rx<OriginalManuscriptHandwritingParams?>(null); // 参数
|
|
||||||
Rx<TestQuestionsImageInfo?> imagInfoModel = Rx<TestQuestionsImageInfo?>(null); // 图片加载后的数据
|
|
||||||
|
|
||||||
late ToolbarControl toolbar;
|
|
||||||
|
|
||||||
final Function backCall;
|
|
||||||
HandwritingLogic(this.backCall);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onInit() {
|
|
||||||
toolbar = ToolbarControl(
|
|
||||||
showManuscript: Rx<bool>(false), // 查看原卷
|
|
||||||
initialization: Rx<bool>(false), // 初始化完成
|
|
||||||
executionData: Rx<List<GestureHandwritingRecording>>([]), // 执行数据
|
|
||||||
);
|
|
||||||
ever(params, (callback) => getData());
|
|
||||||
ever(imagInfoModel, (callback) {
|
|
||||||
// 图像数据初始化后 计算笔迹数据
|
|
||||||
handwritingInfo.value = getHandwritingDetail(resultData.value);
|
|
||||||
getCalculatedSize();
|
|
||||||
});
|
|
||||||
super.onInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> getData() async {
|
|
||||||
if (params.value == null) return;
|
|
||||||
var dio = getClientDio();
|
|
||||||
try {
|
|
||||||
ToastUtils.showLoading();
|
|
||||||
toolbar.initialization.value = false;
|
|
||||||
imagInfoModel.value = null;
|
|
||||||
// 设置时长
|
|
||||||
|
|
||||||
dio.options.receiveTimeout = const Duration(seconds: 20);
|
|
||||||
var res = await getClient().getOriginalManuscriptHandwriting(params.value!);
|
|
||||||
resultData.value = res;
|
|
||||||
} catch (e) {
|
|
||||||
ToastUtils.showError('获取笔迹数据报错,请重试');
|
|
||||||
backCall();
|
|
||||||
} finally {
|
|
||||||
dio.options.receiveTimeout = const Duration(milliseconds: RequestConfig.receiveTimeout); // 还原接收数据时长
|
|
||||||
ToastUtils.dismiss();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算尺寸
|
|
||||||
Future<void> getCalculatedSize() async {
|
|
||||||
if (imagInfoModel.value == null || handwritingInfo.value == null) return;
|
|
||||||
Map<int, List<Lattices>> mapData = handwritingInfo.value!.strokeMap;
|
|
||||||
double scaleRatio = imagInfoModel.value!.scaleRatio;
|
|
||||||
if (mapData.isNotEmpty) {
|
|
||||||
List<int> keys = mapData.keys.toList();
|
|
||||||
|
|
||||||
List<List<GestureHandwritingRecording>> _packagedHandwritingDatas = [];
|
|
||||||
List<GestureHandwritingRecording> _packagedHandwritingDataAll = [];
|
|
||||||
for (var i = 0; i < keys.length; i++) {
|
|
||||||
List<GestureHandwritingRecording> newTrajectoryData = mapData[keys[i]]!.map((e) {
|
|
||||||
double theX = e.x;
|
|
||||||
double theY = e.y;
|
|
||||||
if (!e.initialization) {
|
|
||||||
// 未初始化基准
|
|
||||||
e.toInitialization(scaleRatio);
|
|
||||||
theX = e.x;
|
|
||||||
theY = e.y;
|
|
||||||
}
|
|
||||||
return GestureHandwritingRecording(
|
|
||||||
data: Offset(theX, theY),
|
|
||||||
usageTime: e.time.toInt(),
|
|
||||||
intervalTime: e.intervalTime,
|
|
||||||
stroke: e.stroke,
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
|
|
||||||
newTrajectoryData.sort((a, b) => a.usageTime.compareTo(b.usageTime));
|
|
||||||
_packagedHandwritingDatas.add(newTrajectoryData);
|
|
||||||
_packagedHandwritingDataAll.addAll(newTrajectoryData);
|
|
||||||
}
|
|
||||||
packagedHandwritingDatas.value = _packagedHandwritingDatas; // 分组数据
|
|
||||||
packagedHandwritingDataAll.value = _packagedHandwritingDataAll; // 不分组数据
|
|
||||||
toolbar.showManuscript.value = true; // 默认原稿展示
|
|
||||||
toolbar.initialization.value = true; // 数据初始化完成
|
|
||||||
|
|
||||||
// Future.delayed(Duration.zero, () => eventFire(model: JobHandwritingGetReadyBus())); // 通知外部可以播放笔迹
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HandwritingInfo? getHandwritingDetail(JobHandwriting? theData) {
|
|
||||||
if (theData == null) return null;
|
|
||||||
// 笔画分组
|
|
||||||
// var lattices = Map<int, List<Lattices>>.fromIterable(
|
|
||||||
// theData.lattices,
|
|
||||||
// key: (key) => key.stroke,
|
|
||||||
// value: (value) {
|
|
||||||
// // return theData.lattices.where((item) => item.stroke == value.stroke).toList()..sort((a, b) => a.time.compareTo(b.time));
|
|
||||||
// return theData.lattices.where((item) => item.stroke == value.stroke).toList();
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
var lattices = <int, List<Lattices>>{};
|
|
||||||
var theLattices = theData.lattices;
|
|
||||||
for (var i = 0; i < theLattices.length; i++) {
|
|
||||||
Lattices item = theLattices[i];
|
|
||||||
if (!lattices.containsKey(item.stroke)) lattices[item.stroke] = [];
|
|
||||||
lattices[item.stroke]!.add(item); // 添加笔画数据
|
|
||||||
}
|
|
||||||
|
|
||||||
List<int> latticeKeys = lattices.keys.toList(); // 笔画集合
|
|
||||||
int timeConsuming = 0;
|
|
||||||
if (latticeKeys.isNotEmpty) {
|
|
||||||
// 计算总时长
|
|
||||||
List<Lattices>? firstAction = lattices[latticeKeys[0]];
|
|
||||||
List<Lattices>? lastAction = lattices[latticeKeys[latticeKeys.length - 1]];
|
|
||||||
int firstTime = 0;
|
|
||||||
int lastTime = 0;
|
|
||||||
|
|
||||||
if (firstAction?.isNotEmpty ?? false) {
|
|
||||||
// 第一个笔画集合
|
|
||||||
firstTime = firstAction![0].time;
|
|
||||||
}
|
|
||||||
if (lastAction?.isNotEmpty ?? false) {
|
|
||||||
// 最后一笔画集合
|
|
||||||
lastTime = lastAction![0].time;
|
|
||||||
}
|
|
||||||
timeConsuming = lastTime - firstTime;
|
|
||||||
}
|
|
||||||
var pauseCount = 0; // 停顿次数
|
|
||||||
List<PauseIntervalTime> pauseInterval = [];
|
|
||||||
for (var i = 0; i < latticeKeys.length; i++) {
|
|
||||||
var currentLattices = lattices[latticeKeys[i]]!; // 当前循环笔画集合
|
|
||||||
var prevLattices = i == 0 ? null : lattices[latticeKeys[i - 1]]!; // 下一个笔画集合
|
|
||||||
for (var j = 0; j < currentLattices.length; j++) {
|
|
||||||
var intervalTime = 0;
|
|
||||||
var lattice = currentLattices[j];
|
|
||||||
|
|
||||||
if (j != 0) {
|
|
||||||
var prevItem = currentLattices[j - 1];
|
|
||||||
var adjacentSpacingTime = lattice.time - prevItem.time;
|
|
||||||
intervalTime = adjacentSpacingTime + prevItem.intervalTime;
|
|
||||||
if (adjacentSpacingTime > 5000) {
|
|
||||||
// 大于5秒算一次停顿
|
|
||||||
pauseCount++;
|
|
||||||
pauseInterval.add(PauseIntervalTime(startTime: prevItem.intervalTime, endTime: intervalTime));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (i != 0 && prevLattices != null) {
|
|
||||||
var prevLatticeLastItem = prevLattices[prevLattices.length - 1];
|
|
||||||
var adjacentSpacingTime = lattice.time - prevLatticeLastItem.time;
|
|
||||||
intervalTime = adjacentSpacingTime + prevLatticeLastItem.intervalTime;
|
|
||||||
if (adjacentSpacingTime > 5000) {
|
|
||||||
// 大于5秒算一次停顿
|
|
||||||
pauseCount++;
|
|
||||||
pauseInterval.add(PauseIntervalTime(startTime: prevLatticeLastItem.intervalTime, endTime: intervalTime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lattice.intervalTime = intervalTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return HandwritingInfo(pauseCount, timeConsuming, lattices, pauseInterval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
// 实体文件
|
|
||||||
|
|
||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/job_handwriting.dart';
|
|
||||||
|
|
||||||
part 'states.g.dart';
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class HandwritingInfo extends Object {
|
|
||||||
int pauseCount; // 停顿次数
|
|
||||||
List<PauseIntervalTime> pauseInterval;
|
|
||||||
int timeConsuming; // 耗时(毫秒)
|
|
||||||
Map<int, List<Lattices>> strokeMap; // 笔画数据
|
|
||||||
|
|
||||||
HandwritingInfo(this.pauseCount, this.timeConsuming, this.strokeMap, this.pauseInterval);
|
|
||||||
|
|
||||||
factory HandwritingInfo.fromJson(Map<String, dynamic> srcJson) => _$HandwritingInfoFromJson(srcJson);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$HandwritingInfoToJson(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
class ToolbarControl {
|
|
||||||
Rx<bool> showManuscript; // 查看原稿
|
|
||||||
Rx<bool> initialization;
|
|
||||||
Rx<List<GestureHandwritingRecording>> executionData;
|
|
||||||
|
|
||||||
ToolbarControl({
|
|
||||||
required this.executionData,
|
|
||||||
required this.showManuscript,
|
|
||||||
required this.initialization,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 播放倍速
|
|
||||||
enum PlaybackSpeed {
|
|
||||||
ORIGINAL_SPEED(name: '原速播放', speed: 1),
|
|
||||||
ONE_POINT_FIVE_SPEED(name: '1.5x播放', speed: 1.5),
|
|
||||||
DOUBLE_SPEED(name: '2.0x播放', speed: 2),
|
|
||||||
TRIPLE_SPEED(name: '3.0x播放', speed: 3),
|
|
||||||
FOUR_SPEED(name: '4.0x播放', speed: 4),
|
|
||||||
FIVE_SPEED(name: '5.0x播放', speed: 5),
|
|
||||||
SIX_SPEED(name: '6.0x播放', speed: 6);
|
|
||||||
|
|
||||||
const PlaybackSpeed({required this.name, required this.speed});
|
|
||||||
final double speed;
|
|
||||||
final String name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class PauseIntervalTime extends Object {
|
|
||||||
int? apart;
|
|
||||||
int startTime;
|
|
||||||
int endTime;
|
|
||||||
PauseIntervalTime({required this.startTime, required this.endTime}) {
|
|
||||||
apart = endTime - startTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
factory PauseIntervalTime.fromJson(Map<String, dynamic> srcJson) => _$PauseIntervalTimeFromJson(srcJson);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$PauseIntervalTimeToJson(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 播放按钮
|
|
||||||
class JobHandwritingPlaybarBus {
|
|
||||||
bool play;
|
|
||||||
bool recalculate;
|
|
||||||
JobHandwritingPlaybarBus(this.play, [this.recalculate = true]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 笔迹是否已经准备好(笔迹计算好坐标后通知通知栏可以开始播放)
|
|
||||||
class JobHandwritingGetReadyBus {
|
|
||||||
JobHandwritingGetReadyBus();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 笔记运行时间
|
|
||||||
class JobHandwritingRunTimeBus {
|
|
||||||
int runTimeVal;
|
|
||||||
int totalVal;
|
|
||||||
JobHandwritingRunTimeBus(this.runTimeVal, this.totalVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 拖动进度条
|
|
||||||
class JobHandwritingDragProgressBarBus {
|
|
||||||
int changeVal;
|
|
||||||
int totalVal;
|
|
||||||
JobHandwritingDragProgressBarBus(this.changeVal, this.totalVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 播放速度 (原速播放/快速播放)
|
|
||||||
class PlaybackSpeedBus {
|
|
||||||
double speed;
|
|
||||||
PlaybackSpeedBus(this.speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 手势记录(原稿笔记还原)
|
|
||||||
class GestureHandwritingRecording {
|
|
||||||
int stroke;
|
|
||||||
int usageTime; // 用时
|
|
||||||
Offset data;
|
|
||||||
int intervalTime; // 间隔时间
|
|
||||||
GestureHandwritingRecording({
|
|
||||||
required this.stroke,
|
|
||||||
required this.data,
|
|
||||||
required this.usageTime,
|
|
||||||
required this.intervalTime,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'dart:async';
|
||||||
|
|
||||||
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:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
|
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/config/request_config.dart';
|
||||||
import 'package:making_school_asignment_app/common/job/marking_models/do_paper_bus.dart';
|
import 'package:making_school_asignment_app/common/job/marking_models/do_paper_bus.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';
|
||||||
|
|
@ -34,9 +36,7 @@ class _QuestionPaperViewState extends State<QuestionPaperView> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(
|
return Row(
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
children: [
|
||||||
// 试题图片视图
|
// 试题图片视图
|
||||||
Expanded(
|
Expanded(
|
||||||
|
|
@ -49,7 +49,7 @@ class _QuestionPaperViewState extends State<QuestionPaperView> {
|
||||||
// 主图
|
// 主图
|
||||||
QuestionImageView(maxWidth, maxHeight, sateData, annotationState, logic),
|
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)),
|
||||||
// 上一题按钮
|
// 上一题按钮
|
||||||
Positioned(
|
Positioned(
|
||||||
left: 2.w,
|
left: 2.w,
|
||||||
|
|
@ -95,8 +95,6 @@ class _QuestionPaperViewState extends State<QuestionPaperView> {
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
// 底部数据
|
|
||||||
$TotalSubmitCountView(sateData)
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|
@ -104,122 +102,10 @@ class _QuestionPaperViewState extends State<QuestionPaperView> {
|
||||||
// 试题题号视图
|
// 试题题号视图
|
||||||
Expanded(flex: 2, child: $QuestionNumberView(sateData)),
|
Expanded(flex: 2, child: $QuestionNumberView(sateData)),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
Obx(() {
|
|
||||||
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
|
|
||||||
Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData) {
|
|
||||||
return Obx(() {
|
|
||||||
var data = sateData.data.value;
|
|
||||||
if (data == null) return Container();
|
|
||||||
return Positioned(
|
|
||||||
bottom: 10.h,
|
|
||||||
right: 8.w,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: () async {
|
|
||||||
var submitStudents = sateData.data.value?.students; // 已提交学生
|
|
||||||
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
elevation: 10,
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.only(topLeft: Radius.circular(10.r), topRight: Radius.circular(10.r))),
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return Padding(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 2.w),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.only(top: 14.h),
|
|
||||||
child: quickText(
|
|
||||||
'第${sateData.data.value!.templateIdKeyMap?[sateData.data.value!.templateId]}页未提交学生名单',
|
|
||||||
size: 15.sp,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: const Color.fromRGBO(60, 60, 60, 1),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 10.h),
|
|
||||||
Expanded(
|
|
||||||
child: ListView(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 4.w),
|
|
||||||
children: [
|
|
||||||
Wrap(
|
|
||||||
spacing: 7.2.w, // 主轴(水平)方向间距
|
|
||||||
runSpacing: 12.h, // 纵轴(垂直)方向间距
|
|
||||||
alignment: WrapAlignment.start, //沿主轴方向居中
|
|
||||||
children: submitStudents!.map((e) {
|
|
||||||
return Stack(
|
|
||||||
alignment: const FractionalOffset(0.05, 0.09),
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
padding: EdgeInsets.only(top: 1.2.h, bottom: 1.5.h, left: 13.w, right: 5.w),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(4.r),
|
|
||||||
color: const Color.fromRGBO(239, 242, 255, 1),
|
|
||||||
),
|
|
||||||
child: quickText(
|
|
||||||
e.name,
|
|
||||||
size: 12.sp,
|
|
||||||
wordSpacing: 2,
|
|
||||||
color: const Color.fromRGBO(80, 94, 110, 1),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Stack(
|
|
||||||
alignment: const FractionalOffset(0.52, 0.24),
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
const IconData(0xe63d, fontFamily: "AlibabaIcon"),
|
|
||||||
size: 12.sp,
|
|
||||||
color: e.isPriority ? const Color.fromRGBO(76, 199, 147, 1) : const Color.fromRGBO(164, 164, 164, 1),
|
|
||||||
),
|
|
||||||
quickText('优先', size: 4.sp, color: Colors.white),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
quickText('已阅', color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp),
|
|
||||||
quickText(data.annotatedCount, color: const Color.fromRGBO(76, 199, 147, 1), 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),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 试题题号视图
|
// 试题题号视图
|
||||||
@hwidget
|
@hwidget
|
||||||
Widget $questionNumberView(BuildContext context, HomeworkReviewState sateData) {
|
Widget $questionNumberView(BuildContext context, HomeworkReviewState sateData) {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dar
|
||||||
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:making_school_asignment_app/page/home_page/children/job_report/widget/personnel_data_overview.dart';
|
|
||||||
|
|
||||||
// 数据
|
// 数据
|
||||||
class HomeworkReviewState {
|
class HomeworkReviewState {
|
||||||
|
|
@ -31,9 +30,6 @@ class HomeworkReviewState {
|
||||||
late bool? panQuestView;
|
late bool? panQuestView;
|
||||||
late Rx<TestQuestionsImageInfo?> imageScale;
|
late Rx<TestQuestionsImageInfo?> imageScale;
|
||||||
List<dynamic> handwritings = [];
|
List<dynamic> handwritings = [];
|
||||||
bool needRefresh = false;
|
|
||||||
bool lastQuestionPrompt = false; // 最后一题提示
|
|
||||||
Rx<bool> getDataError = false.obs; // 获取作业数据报错
|
|
||||||
|
|
||||||
// late String dateEnd = '';
|
// late String dateEnd = '';
|
||||||
// late int knowledgeId = 0;
|
// late int knowledgeId = 0;
|
||||||
|
|
@ -103,14 +99,9 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
|
||||||
|
|
||||||
// item.topHeight = itemPre.height;
|
// item.topHeight = itemPre.height;
|
||||||
// }
|
// }
|
||||||
state.getDataError.value = false;
|
|
||||||
state.data.value = data;
|
state.data.value = data;
|
||||||
state.handwritings = [];
|
state.handwritings = [];
|
||||||
state.studentQuestions.value = data.studentQuestions;
|
state.studentQuestions.value = data.studentQuestions;
|
||||||
} catch (e) {
|
|
||||||
print('获取数据报错了:$e');
|
|
||||||
ToastUtils.showError('获取试题数据出错,请重试');
|
|
||||||
state.getDataError.value = true;
|
|
||||||
} finally {
|
} finally {
|
||||||
if (timerControl.isActive) timerControl.cancel();
|
if (timerControl.isActive) timerControl.cancel();
|
||||||
|
|
||||||
|
|
@ -196,6 +187,8 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
|
||||||
options: Options(contentType: null, headers: {Headers.contentLengthHeader: bytes.length}),
|
options: Options(contentType: null, headers: {Headers.contentLengthHeader: bytes.length}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// var res = await getClient().uploadImag(resUrl, file);
|
||||||
|
|
||||||
return imgKey;
|
return imgKey;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('图片上传失败');
|
print('图片上传失败');
|
||||||
|
|
@ -242,28 +235,20 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
|
||||||
);
|
);
|
||||||
}).toList()))
|
}).toList()))
|
||||||
.then((e) async {
|
.then((e) async {
|
||||||
state.needRefresh = true;
|
var annotatedCount = data.annotatedCount + 1; // 批阅数量
|
||||||
var totalUnAnnotateCount = data.totalUnAnnotateCount;
|
var submitCount = data.submitCount; // 学生提交数量
|
||||||
if (data.annotateTime == null) totalUnAnnotateCount -= 1;
|
if (annotatedCount == submitCount) {
|
||||||
|
|
||||||
if (totalUnAnnotateCount <= 0 && !state.lastQuestionPrompt) {
|
|
||||||
// 批阅完成
|
// 批阅完成
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context1) {
|
builder: (BuildContext context1) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: quickText('批阅已完成'),
|
title: quickText('完成批阅提示'),
|
||||||
content: const Text('暂无更多待批阅项'),
|
content: const Text('暂无更多待批阅项,是否返回主页?'),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
|
TextButton(child: const Text('否'), onPressed: () => Navigator.of(context1).pop()),
|
||||||
TextButton(
|
TextButton(
|
||||||
child: const Text('继续'),
|
child: const Text('是'),
|
||||||
onPressed: () {
|
|
||||||
state.lastQuestionPrompt = true;
|
|
||||||
Navigator.of(context1).pop();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
child: const Text('退出批阅'),
|
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context1).pop();
|
Navigator.of(context1).pop();
|
||||||
Get.back();
|
Get.back();
|
||||||
|
|
@ -275,11 +260,8 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var newParams = DoPaperDetailsParam.fromJson(state.param.value.toJson());
|
var newParams = DoPaperDetailsParam.fromJson(state.param.value.toJson());
|
||||||
if (totalUnAnnotateCount > 0) {
|
|
||||||
// 当前批阅任务完成 重复提交后 停留在当前数据位置
|
|
||||||
newParams.templateId = null;
|
newParams.templateId = null;
|
||||||
newParams.studentId = null;
|
newParams.studentId = null;
|
||||||
}
|
|
||||||
state.param.value = newParams;
|
state.param.value = newParams;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:get/get.dart';
|
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 'components/bottom_operation_bar.dart';
|
import 'components/bottom_operation_bar.dart';
|
||||||
import 'components/button_floating_action.dart';
|
import 'components/button_floating_action.dart';
|
||||||
|
|
@ -23,7 +22,6 @@ class HomeworkReview extends StatefulWidget {
|
||||||
class _HomeworkReviewState extends State<HomeworkReview> {
|
class _HomeworkReviewState extends State<HomeworkReview> {
|
||||||
final logic = Get.find<HomeworkReviewLogic>();
|
final logic = Get.find<HomeworkReviewLogic>();
|
||||||
final sateData = Get.find<HomeworkReviewLogic>().state;
|
final sateData = Get.find<HomeworkReviewLogic>().state;
|
||||||
final AnnotateClassLogic _controller = Get.find<AnnotateClassLogic>();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
|
@ -39,13 +37,7 @@ class _HomeworkReviewState extends State<HomeworkReview> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return PopScope(
|
return Scaffold(
|
||||||
canPop: false,
|
|
||||||
onPopInvoked: (e) {
|
|
||||||
if (e && sateData.needRefresh) _controller.getList();
|
|
||||||
},
|
|
||||||
child: SafeArea(
|
|
||||||
child: Scaffold(
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
// titleSpacing: 0,
|
// titleSpacing: 0,
|
||||||
leading: IconButton(icon: const Icon(Icons.arrow_back_ios), onPressed: () => Get.back()),
|
leading: IconButton(icon: const Icon(Icons.arrow_back_ios), onPressed: () => Get.back()),
|
||||||
|
|
@ -53,7 +45,11 @@ class _HomeworkReviewState extends State<HomeworkReview> {
|
||||||
title: quickText(sateData.param.value.homeworkName),
|
title: quickText(sateData.param.value.homeworkName),
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
actions: [const FavoriteWidget(), SizedBox(width: 5.w), const ReturnToHomepage()],
|
actions: [
|
||||||
|
const FavoriteWidget(),
|
||||||
|
SizedBox(width: 5.w),
|
||||||
|
const ReturnToHomepage(),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
@ -62,14 +58,12 @@ class _HomeworkReviewState extends State<HomeworkReview> {
|
||||||
const DropdownSwitchStudentsType(),
|
const DropdownSwitchStudentsType(),
|
||||||
SizedBox(height: 1.h),
|
SizedBox(height: 1.h),
|
||||||
const Expanded(child: QuestionPaperView()),
|
const Expanded(child: QuestionPaperView()),
|
||||||
const BottomAnnotationSwitch()
|
const BottomAnnotationSwitch(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// floatingActionButton: const ButtonFloatingAction(),
|
floatingActionButton: const ButtonFloatingAction(),
|
||||||
// floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
|
floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
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:get/get.dart';
|
import 'package:get/get.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/ReturnToHomepage.dart';
|
import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart';
|
||||||
import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/original_manuscript_handwriting/answer_handwriting_view.dart';
|
|
||||||
import 'package:making_school_asignment_app/page/home_page/children/student_personal/widget/student_kg_table.dart';
|
import 'package:making_school_asignment_app/page/home_page/children/student_personal/widget/student_kg_table.dart';
|
||||||
import 'package:making_school_asignment_app/page/home_page/children/student_personal/widget/student_zg_table.dart';
|
import 'package:making_school_asignment_app/page/home_page/children/student_personal/widget/student_zg_table.dart';
|
||||||
import 'package:making_school_asignment_app/routes/app_pages.dart';
|
import 'package:making_school_asignment_app/routes/app_pages.dart';
|
||||||
|
|
@ -76,8 +74,11 @@ class _StudentPersonalPageState extends State<StudentPersonalPage> {
|
||||||
width: 10.r,
|
width: 10.r,
|
||||||
),
|
),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () =>
|
onTap: () {
|
||||||
showAnswerHandwriting(context, homeworkId: state.homeworkId, studentId: state.studentId).then((e) => ToastUtils.dismiss()),
|
/* showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId).then((value) {
|
||||||
|
ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]);
|
||||||
|
});*/
|
||||||
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 93.r,
|
width: 93.r,
|
||||||
height: 28.r,
|
height: 28.r,
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,12 @@ class HomePage extends StatefulWidget {
|
||||||
State<HomePage> createState() => _HomePageState();
|
State<HomePage> createState() => _HomePageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin {
|
class _HomePageState extends State<HomePage>
|
||||||
|
with AutomaticKeepAliveClientMixin {
|
||||||
final logic = Get.find<HomeLogic>();
|
final logic = Get.find<HomeLogic>();
|
||||||
final state = Get.find<HomeLogic>().state;
|
final state = Get
|
||||||
|
.find<HomeLogic>()
|
||||||
|
.state;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get wantKeepAlive => true;
|
bool get wantKeepAlive => true;
|
||||||
|
|
@ -35,8 +38,7 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
var spaceWidth = SizedBox(height: ScreenUtil().screenWidth / 19);
|
var spaceWidth = SizedBox(height: ScreenUtil().screenWidth / 19);
|
||||||
return SafeArea(
|
return AnnotatedRegion(
|
||||||
child: AnnotatedRegion(
|
|
||||||
value: const SystemUiOverlayStyle(
|
value: const SystemUiOverlayStyle(
|
||||||
systemNavigationBarColor: Color(0xFF000000),
|
systemNavigationBarColor: Color(0xFF000000),
|
||||||
systemNavigationBarDividerColor: null,
|
systemNavigationBarDividerColor: null,
|
||||||
|
|
@ -73,21 +75,28 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),*/
|
),*/
|
||||||
|
SizedBox(height: 30.h),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
return $TermRow([
|
return $TermRow([
|
||||||
EntranceModel(title: '作业批阅', image: 'assets/images/job_home_marking.png', navigationUrl: Routes.readOverPage),
|
EntranceModel(title: '作业批阅',
|
||||||
|
image: 'assets/images/job_home_marking.png',
|
||||||
|
navigationUrl: Routes.readOverPage),
|
||||||
EntranceModel(
|
EntranceModel(
|
||||||
title: '学生历史作业',
|
title: '学生历史作业',
|
||||||
image: 'assets/images/job_home_history.png',
|
image: 'assets/images/job_home_history.png',
|
||||||
navigationUrl: Routes.studentHistoryWorkPage,
|
navigationUrl: Routes.studentHistoryWorkPage,
|
||||||
page: 'history',
|
page: 'history',
|
||||||
),
|
),
|
||||||
EntranceModel(title: '知识点点掌握', image: 'assets/images/job_home_knowledge.png', navigationUrl: Routes.knowledgePointsGraspPage)
|
EntranceModel(title: '知识点点掌握',
|
||||||
|
image: 'assets/images/job_home_knowledge.png',
|
||||||
|
navigationUrl: Routes.knowledgePointsGraspPage)
|
||||||
], state.totalCount.value);
|
], state.totalCount.value);
|
||||||
}),
|
}),
|
||||||
spaceWidth,
|
spaceWidth,
|
||||||
$TermRow([
|
$TermRow([
|
||||||
EntranceModel(title: '答题轨迹', image: 'assets/images/job_home_answer_record.png', navigationUrl: Routes.answerTrajectoryPage),
|
EntranceModel(title: '答题轨迹',
|
||||||
|
image: 'assets/images/job_home_answer_record.png',
|
||||||
|
navigationUrl: Routes.answerTrajectoryPage),
|
||||||
EntranceModel(
|
EntranceModel(
|
||||||
title: '优先批阅设定',
|
title: '优先批阅设定',
|
||||||
image: 'assets/images/job_home_youxian.png',
|
image: 'assets/images/job_home_youxian.png',
|
||||||
|
|
@ -127,7 +136,8 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 4.h),
|
SizedBox(height: 4.h),
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 10.w),
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: 16.h, horizontal: 10.w),
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(6.r),
|
borderRadius: BorderRadius.circular(6.r),
|
||||||
|
|
@ -142,18 +152,25 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment
|
||||||
|
.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment
|
||||||
|
.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
width: Utils.isPad() ? 32.w : 38.w,
|
width: Utils.isPad() ? 32.w : 38.w,
|
||||||
height: 18.h,
|
height: 18.h,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
padding: EdgeInsets.only(left: Utils.isPad() ? 2.w : 3.w),
|
padding: EdgeInsets.only(
|
||||||
|
left: Utils.isPad() ? 2.w : 3.w),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: state.type == 1 ? const Color.fromRGBO(104, 136, 253, 1) : const Color.fromRGBO(255, 175, 56, 1),
|
color: state.type == 1
|
||||||
|
? const Color.fromRGBO(
|
||||||
|
104, 136, 253, 1)
|
||||||
|
: const Color.fromRGBO(
|
||||||
|
255, 175, 56, 1),
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(14.r),
|
topLeft: Radius.circular(14.r),
|
||||||
topRight: Radius.circular(3.r),
|
topRight: Radius.circular(3.r),
|
||||||
|
|
@ -162,14 +179,17 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
margin: EdgeInsets.only(right: 4.w),
|
margin: EdgeInsets.only(right: 4.w),
|
||||||
child: quickText(state.type == 1 ? '作业' : '考试', color: Colors.white, size: 10.sp),
|
child: quickText(
|
||||||
|
state.type == 1 ? '作业' : '考试',
|
||||||
|
color: Colors.white, size: 10.sp),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: quickText(
|
child: quickText(
|
||||||
item.name,
|
item.name,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
size: Utils.isPad() ? 14.sp : 16.sp,
|
size: Utils.isPad() ? 14.sp : 16.sp,
|
||||||
color: const Color.fromRGBO(70, 70, 70, 1),
|
color: const Color.fromRGBO(
|
||||||
|
70, 70, 70, 1),
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -181,24 +201,41 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
|
||||||
children: [
|
children: [
|
||||||
quickText(
|
quickText(
|
||||||
EnumUtils.formatSubject(item.subject),
|
EnumUtils.formatSubject(item.subject),
|
||||||
color: const Color.fromRGBO(97, 97, 97, 1),
|
color: const Color.fromRGBO(
|
||||||
|
97, 97, 97, 1),
|
||||||
size: 12.sp,
|
size: 12.sp,
|
||||||
),
|
),
|
||||||
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),
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment
|
||||||
|
.end,
|
||||||
children: [
|
children: [
|
||||||
quickText('题量:', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp),
|
quickText('题量:',
|
||||||
|
color: const Color.fromRGBO(
|
||||||
|
130, 130, 130, 1),
|
||||||
|
size: 11.sp),
|
||||||
quickText(
|
quickText(
|
||||||
'${item.questionCount! - item.annotateCount!}',
|
'${item.questionCount! - item.annotateCount!}',
|
||||||
color: const Color.fromRGBO(97, 97, 97, 1),
|
color: const Color.fromRGBO(
|
||||||
|
97, 97, 97, 1),
|
||||||
size: 13.sp,
|
size: 13.sp,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
quickText(' / ', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp, fontWeight: FontWeight.w500),
|
quickText(' / ',
|
||||||
quickText(DateTime.parse(item.publishTime).toString().substring(0, 10),
|
color: const Color.fromRGBO(
|
||||||
color: const Color.fromRGBO(97, 97, 97, 1), size: 12.sp),
|
130, 130, 130, 1),
|
||||||
|
size: 11.sp,
|
||||||
|
fontWeight: FontWeight.w500),
|
||||||
|
quickText(DateTime.parse(item.publishTime)
|
||||||
|
.toString()
|
||||||
|
.substring(0, 10),
|
||||||
|
color: const Color.fromRGBO(
|
||||||
|
97, 97, 97, 1), size: 12.sp),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 10.h),
|
SizedBox(height: 10.h),
|
||||||
|
|
@ -207,16 +244,21 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(10.r),
|
borderRadius: BorderRadius.circular(
|
||||||
|
10.r),
|
||||||
),
|
),
|
||||||
child: LinearPercentIndicator(
|
child: LinearPercentIndicator(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
animation: true,
|
animation: true,
|
||||||
lineHeight: 8.h,
|
lineHeight: 8.h,
|
||||||
animationDuration: 2500,
|
animationDuration: 2500,
|
||||||
percent: item.annotateRate == null ? 0 : item.annotateRate! / 100,
|
percent: item.annotateRate == null
|
||||||
progressColor: const Color(0xFF6888FD),
|
? 0
|
||||||
backgroundColor: const Color(0xFFE8E8E8),
|
: item.annotateRate! / 100,
|
||||||
|
progressColor: const Color(
|
||||||
|
0xFF6888FD),
|
||||||
|
backgroundColor: const Color(
|
||||||
|
0xFFE8E8E8),
|
||||||
barRadius: Radius.circular(10.r),
|
barRadius: Radius.circular(10.r),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -224,7 +266,10 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 10.r,
|
width: 10.r,
|
||||||
),
|
),
|
||||||
quickText('${item.annotateRate!.toStringAsFixed(0)}%', size: 10.sp, color: const Color(0xFF464646)),
|
quickText(
|
||||||
|
'${item.annotateRate!.toStringAsFixed(
|
||||||
|
0)}%', size: 10.sp,
|
||||||
|
color: const Color(0xFF464646)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// FavoriteButton(jobTaskItem.id, jobTaskItem.title),
|
// FavoriteButton(jobTaskItem.id, jobTaskItem.title),
|
||||||
|
|
@ -242,7 +287,7 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -258,7 +303,8 @@ class EntranceModel extends Object {
|
||||||
String navigationUrl;
|
String navigationUrl;
|
||||||
String? page;
|
String? page;
|
||||||
|
|
||||||
EntranceModel({required this.title, required this.image, required this.navigationUrl, this.page});
|
EntranceModel(
|
||||||
|
{required this.title, required this.image, required this.navigationUrl, this.page});
|
||||||
}
|
}
|
||||||
|
|
||||||
@swidget
|
@swidget
|
||||||
|
|
@ -267,7 +313,8 @@ Widget $termRow(BuildContext context, List<EntranceModel> items, int? data) {
|
||||||
Widget childWidget;
|
Widget childWidget;
|
||||||
switch (leng) {
|
switch (leng) {
|
||||||
case 1:
|
case 1:
|
||||||
childWidget = Row(children: [Expanded(child: $TermItem(items[0], data!))]);
|
childWidget =
|
||||||
|
Row(children: [Expanded(child: $TermItem(items[0], data!))]);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
childWidget = Row(children: [
|
childWidget = Row(children: [
|
||||||
|
|
@ -301,11 +348,13 @@ Widget $termRow(BuildContext context, List<EntranceModel> items, int? data) {
|
||||||
childWidget = Container();
|
childWidget = Container();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Container(padding: EdgeInsets.symmetric(horizontal: 14.w), child: childWidget);
|
return Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 14.w), child: childWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@swidget
|
@swidget
|
||||||
Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHeight}) {
|
Widget $termItem(BuildContext context, EntranceModel e, int data,
|
||||||
|
{double? theHeight}) {
|
||||||
bool isJob = e.title == '作业批阅';
|
bool isJob = e.title == '作业批阅';
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
|
|
@ -334,10 +383,13 @@ Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHe
|
||||||
badgeStyle: badges.BadgeStyle(
|
badgeStyle: badges.BadgeStyle(
|
||||||
badgeColor: const Color.fromRGBO(255, 105, 105, 1),
|
badgeColor: const Color.fromRGBO(255, 105, 105, 1),
|
||||||
shape: badges.BadgeShape.square,
|
shape: badges.BadgeShape.square,
|
||||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(10.r), topRight: Radius.circular(8.5.r), bottomRight: Radius.circular(8.5.r)),
|
borderRadius: BorderRadius.only(topLeft: Radius.circular(10.r),
|
||||||
|
topRight: Radius.circular(8.5.r),
|
||||||
|
bottomRight: Radius.circular(8.5.r)),
|
||||||
// borderSide: BorderSide(color: Colors.white, width: 2),
|
// borderSide: BorderSide(color: Colors.white, width: 2),
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
padding: EdgeInsets.symmetric(horizontal: Utils.isPad() ? 11.w : 16.w, vertical: 2.h),
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: Utils.isPad() ? 11.w : 16.w, vertical: 2.h),
|
||||||
),
|
),
|
||||||
position: badges.BadgePosition.topEnd(top: 10.r, end: 10.r),
|
position: badges.BadgePosition.topEnd(top: 10.r, end: 10.r),
|
||||||
child: Container(
|
child: Container(
|
||||||
|
|
@ -360,17 +412,23 @@ Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHe
|
||||||
? Column(
|
? Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover),
|
Image.asset(
|
||||||
|
e.image, height: 32.r, width: 32.r, fit: BoxFit.cover),
|
||||||
SizedBox(height: 6.r),
|
SizedBox(height: 6.r),
|
||||||
quickText(e.title, size: 12.sp, color: const Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500),
|
quickText(e.title, size: 12.sp,
|
||||||
|
color: const Color.fromRGBO(79, 79, 79, 1),
|
||||||
|
fontWeight: FontWeight.w500),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: Row(
|
: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover),
|
Image.asset(
|
||||||
|
e.image, height: 32.r, width: 32.r, fit: BoxFit.cover),
|
||||||
SizedBox(width: 6.r),
|
SizedBox(width: 6.r),
|
||||||
quickText(e.title, size: 12.sp, color: const Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500),
|
quickText(e.title, size: 12.sp,
|
||||||
|
color: const Color.fromRGBO(79, 79, 79, 1),
|
||||||
|
fontWeight: FontWeight.w500),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue