Compare commits

..

No commits in common. "8fd6c57874479aaf104f05993d91448ac942ec51" and "5f4c9237c1d7ddfbdd93ae2d0a485379259631ba" have entirely different histories.

79 changed files with 1715 additions and 3159 deletions

View File

@ -1,3 +0,0 @@
{
"flutter": "3.32.0"
}

View File

@ -42,6 +42,3 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
# FVM Version Cache
.fvm/

View File

@ -1,3 +0,0 @@
{
"dart.flutterSdkPath": ".fvm/versions/3.32.0"
}

View File

@ -36,10 +36,6 @@ android {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
signingConfigs {
release {

View File

@ -4,7 +4,6 @@
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:enableOnBackInvokedCallback="true">
<!-- windowTranslucentStatus 设置顶部状态栏使用-->
<activity
android:name=".MainActivity"
android:exported="true"
@ -13,7 +12,6 @@
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowTranslucentStatus="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 KiB

After

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 KiB

After

Width:  |  Height:  |  Size: 69 B

View File

@ -3,10 +3,10 @@
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowSplashScreenBackground">#FFFFFF</item>
<item name="android:windowSplashScreenBackground">#8C68FF</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.

View File

@ -6,8 +6,8 @@
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.

View File

@ -3,10 +3,10 @@
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowSplashScreenBackground">#FFFFFF</item>
<item name="android:windowSplashScreenBackground">#8C68FF</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.

View File

@ -6,8 +6,8 @@
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.

View File

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

View File

@ -18,8 +18,8 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.8.0" apply false
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
id "com.android.application" version "7.3.0" apply false
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
}
include ":app"

View File

@ -1,109 +0,0 @@
@echo off
SETLOCAL EnableDelayedExpansion
:: 设置 UTF-8 代码页以支持中文显示
chcp 65001 > nul
:: 获取项目根目录
for %%I in ("%~dp0.") do set "PROJECT_DIR=%%~fI"
:: 1. 强制终止所有Java进程Gradle相关
echo Terminating processes...
taskkill /f /im java.exe 2>nul
taskkill /f /im gradlew.exe 2>nul
timeout /t 2 /nobreak >nul
:: 修复后的Flutter构建脚本
echo Running flutter clean...
call flutter clean
if !ERRORLEVEL! neq 0 (
echo flutter clean failed with error: !ERRORLEVEL!
pause
exit /b 1
)
:: 3. 强制删除构建目录(带重试机制)
echo Removing residual files
call :ForceDelete "build"
call :ForceDelete ".dart_tool"
call :ForceDelete "pubspec.lock"
echo Running flutter pub get...
call flutter pub get
if !ERRORLEVEL! neq 0 (
echo flutter pub get failed with error: !ERRORLEVEL!
pause
exit /b 1
)
echo Running build_runner...
call flutter packages pub run build_runner build --delete-conflicting-outputs
if !ERRORLEVEL! neq 0 (
echo build_runner failed with error: !ERRORLEVEL!
pause
exit /b 1
)
echo Building release APK...
call flutter build apk --release
if !ERRORLEVEL! neq 0 (
echo APK build failed with error: !ERRORLEVEL!
pause
exit /b 1
)
:: 新增打开APK所在文件夹
echo Opening APK directory
if exist "build\app\outputs\flutter-apk\" (
explorer "build\app\outputs\flutter-apk\"
) else (
echo APK directory does not exist
)
echo.
echo All steps completed successfully!
echo APK file generated at: %PROJECT_DIR%\build\app\outputs\flutter-apk\
echo.
timeout /t 3 /nobreak >nul
exit /b 0
:: 函数区 -------------------------------------------------
:ForceDelete
setlocal
set "target=%~1"
set "max_retries=3"
set "retry_delay=1"
:: 检查目标是否存在
if not exist "%target%" (
endlocal
goto :eof
)
:: 尝试多次删除
for /l %%i in (1,1,%max_retries%) do (
echo Attempting to delete %target% (try %%i of %max_retries%)
:: 先尝试删除文件
del /f /q /s "%target%\*" 2>nul
:: 再尝试删除目录
rmdir /s /q "%target%" 2>nul
:: 检查是否删除成功
if not exist "%target%" (
echo Successfully deleted %target%
endlocal
goto :eof
)
:: 如果未成功,等待后重试
if %%i lss %max_retries% (
timeout /t %retry_delay% /nobreak >nul
set /a retry_delay*=2 :: 指数退避策略
)
)
:: 如果所有尝试都失败
echo Warning: Could not completely delete %target%, some files may be in use
endlocal
goto :eof

View File

@ -5,15 +5,13 @@ flutter_native_splash:
# 如需恢复默认的白屏,执行如下命令
# flutter pub run flutter_native_splash:remove
# 设置闪屏页的默认态logo或背景图片路径
background_image: assets/images/splash_native.png
# 全屏模式
fullscreen: true
color: "#8C68FF"
image_ios: assets/images/splash_native.png
background_image_android: assets/images/splash_native.png
android_12:
color: "#FFFFFF"
image: assets/images/logo_splash.png
android: true
ios: true
# android_gravity: clip_vertical
# ios_content_mode: scaleToFill
android_gravity: clip_vertical
ios_content_mode: scaleToFill

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 KiB

After

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

After

Width:  |  Height:  |  Size: 240 KiB

View File

@ -17,7 +17,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="LaunchBackground" translatesAutoresizingMaskIntoConstraints="NO" id="tWc-Dq-wcI"/>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"></imageView>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"></imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
@ -38,7 +38,7 @@
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
<image name="LaunchImage" width="751" height="1734"/>
<image name="LaunchBackground" width="1" height="1"/>
</resources>
</document>

View File

@ -38,7 +38,7 @@
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIStatusBarHidden</key>
<true/>
<false/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>

View File

@ -1,6 +1,14 @@
import 'package:dio/dio.dart' hide Headers;
import 'package:making_school_asignment_app/common/job/annotated_class.dart';
import 'package:making_school_asignment_app/common/job/app_version.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/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/user_register_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: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/common/app_version_model.dart';
import 'package:making_school_asignment_app/common/job/common/base_app_version.dart';
@ -9,21 +17,13 @@ import 'package:making_school_asignment_app/common/job/enum_subject.dart';
import 'package:making_school_asignment_app/common/job/homework_details.dart';
import 'package:making_school_asignment_app/common/job/knowledge_points_grasp.dart';
import 'package:making_school_asignment_app/common/job/knowledge_report_detail.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/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/student_history.dart';
import 'package:making_school_asignment_app/common/job/student_history_params.dart';
import 'package:making_school_asignment_app/common/job/student_item.dart';
import 'package:making_school_asignment_app/common/job/student_personal_info.dart';
import 'package:making_school_asignment_app/common/job/user_info_detail.dart';
import 'package:making_school_asignment_app/common/job/user_register_params.dart';
import 'package:making_school_asignment_app/common/job/work_student.dart';
import 'package:making_school_asignment_app/common/job/work_student_params.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/job_handwriting.dart';
import 'package:retrofit/retrofit.dart';
part 'retrofit_client.g.dart';
@ -64,7 +64,7 @@ abstract class RetrofitClient {
//
@GET("/api/rbac/Student/GetPriorityAnnotateStudents")
Future<List<StudentItem>> getStudentList(@Query('ClassId') String classId, @Query('Subject') int? subject);
Future<List<StudentItem>> getStudentList(@Query('ClassId') String classId, @Query('Subject') int subject);
//
@GET("/api/hms/Annotate/GetUnAnnotateList")
@ -88,22 +88,16 @@ abstract class RetrofitClient {
//
@POST("/api/rbac/Student/PriorityAnnotateStudent")
Future getAnnotateStudent(
@Field() String classId, @Field() int studentId, @Field() bool priorityAnnotate, @Field() int? subject);
Future getAnnotateStudent(@Field() String classId, @Field() int studentId, @Field() bool priorityAnnotate, @Field() int subject);
//
@GET("/api/hms/HmsReport/GetStudentHomework")
Future<StudentPersonalInfo> getStudentHomework(
@Query('HomeworkId') String homeworkId, @Query('StudentId') int studentId);
Future<StudentPersonalInfo> getStudentHomework(@Query('HomeworkId') String homeworkId, @Query('StudentId') int studentId);
//
@GET("/api/hms/HmsReport/GetKnowledgeReport")
Future<List<KnowledgePointsGrasp>> getKnowledgeReport(
@Query('DateStart') String dateStart,
@Query('DateEnd') String dateEnd,
@Query('KnowledgeName') String knowledgeName,
@Query('ClassId') String classId,
@Query('Subject') int? subject);
@Query('DateStart') String dateStart, @Query('DateEnd') String dateEnd, @Query('KnowledgeName') String knowledgeName,@Query('ClassId') String classId,@Query('Subject') int subject);
//
@GET("/api/hms/HmsReport/GetKnowledgeReportDetail")
@ -112,8 +106,8 @@ abstract class RetrofitClient {
//
@GET("/api/hms/HmsReport/GetQuestionStudentState")
Future<List<Students>> getQuestionStudentState(@Query('HomeworkId') String homeworkId,
@Query('TemplateId') int templateId, @Query('QuestionNo') String questionNo);
Future<List<Students>> getQuestionStudentState(
@Query('HomeworkId') String homeworkId, @Query('TemplateId') int templateId, @Query('QuestionNo') String questionNo);
//
@POST("/api/hms/Homework/Collect")
@ -130,8 +124,7 @@ abstract class RetrofitClient {
//
@GET("/api/hms/FavStudent/GetList")
Future<BasePageData<HomeworkFavs>> getFavList(
@Query('HomeworkName') String homeworkName, @Query('ClassId') String classId);
Future<BasePageData<HomeworkFavs>> getFavList(@Query('HomeworkName') String homeworkName, @Query('ClassId') String classId);
// ()
@POST("/api/hms/Annotate/AllCorrect")
@ -155,6 +148,5 @@ abstract class RetrofitClient {
// APP
@GET("/api/infra/AppVersion/Get")
Future<AppVersion?> getLastAppVersion(
@Query('appName') String appName, @Query('ftuType') int ftuType); // ftuType 1 2IOS 3windows
Future<AppVersion?> getLastAppVersion(@Query('appName') String appName, @Query('ftuType') int ftuType); // ftuType 1 2IOS 3windows
}

View File

@ -1,33 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
///
class AppStateController extends GetxController with WidgetsBindingObserver {
//
final appLifecycleState = AppLifecycleState.resumed.obs;
// 便
bool get isAppInForeground => appLifecycleState.value == AppLifecycleState.resumed;
@override
void onInit() {
super.onInit();
WidgetsBinding.instance.addObserver(this); //
}
@override
void onClose() {
WidgetsBinding.instance.removeObserver(this); //
super.onClose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
appLifecycleState.value = state; //
// if (isAppInForeground) {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// Get.find<UpgradeLogic>().initiateVersionCheck(Get.context!);
// });
// }
}
}

View File

@ -1,61 +1,52 @@
import 'package:get/get.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:making_school_asignment_app/common/config/request_config.dart';
part 'do_paper_details_result.g.dart';
///
@JsonSerializable(checked: true, includeIfNull: false)
class DoPaperDetailsResult {
class DoPaperDetailsResult extends Object {
@JsonKey(name: 'templateIds')
final Map<String, bool> templateIds;
Map<String, bool> templateIds;
/// ID键列表
//
@JsonKey(name: 'templateIdKeys')
List<int>? templateIdKeys;
/// ID键映射表
//
@JsonKey(name: 'templateIdKeyMap')
Map<int, int>? templateIdKeyMap;
///
@JsonKey(name: 'submitStudents', toJson: _paperStudentsToJson)
final List<PaperStudents> students;
@JsonKey(name: 'submitStudents', toJson: _paperStudentsToJson) //
List<PaperStudents> students;
/// ID
@JsonKey(name: 'templateId')
final int templateId;
int templateId;
/// ID
@JsonKey(name: 'studentId')
final int studentId;
int studentId;
///
//
@JsonKey(name: 'priority', defaultValue: false)
bool priority;
///
@JsonKey(name: 'annotatedCount')
final int annotatedCount;
@JsonKey(name: 'annotatedCount') //
int annotatedCount;
///
@JsonKey(name: 'submitCount')
final int submitCount;
@JsonKey(name: 'submitCount') //
int submitCount;
///
@JsonKey(name: 'zgtAnswer')
@JsonKey(name: 'zgtAnswer') //
String zgtAnswer;
///
@JsonKey(name: 'showZgtAnnotate')
@JsonKey(name: 'showZgtAnnotate') //
String? showZgtAnnotate;
///
@JsonKey(name: 'zgtAnnotate')
@JsonKey(name: 'zgtAnnotate') //
String? zgtAnnotate;
///
@JsonKey(name: 'lastAnswerTime')
final String lastAnswerTime;
@JsonKey(name: 'lastAnswerTime') //
String lastAnswerTime;
//
@JsonKey(name: 'annotateTime')
@ -76,6 +67,7 @@ class DoPaperDetailsResult {
@JsonKey(name: 'continuePage', toJson: _continuePageToJson)
ContinuePage? continuePage;
@JsonKey(name: 'nextPage', toJson: _nextPageToJson)
NextPage? nextPage;
@ -110,42 +102,35 @@ class DoPaperDetailsResult {
this.annotateTime,
this.showZgtAnnotate,
{this.needAnnotate = false}) {
// ID键列表和映射表
if (templateIds.isNotEmpty) {
templateIdKeys = templateIds.keys.map(int.parse).toList();
if (templateIds.keys.isNotEmpty) {
templateIdKeys = templateIds.keys.map((e) => int.parse(e)).toList();
templateIdKeyMap = <int, int>{};
for (int i = 0; i < templateIdKeys!.length; i++) {
final templateId = templateIdKeys![i];
templateIdKeyMap![i + 1] = templateId;
templateIdKeyMap![templateId] = i + 1;
for (var i = 1; i <= templateIdKeys!.length; i++) {
var theVal = templateIdKeys![i - 1];
templateIdKeyMap![i] = theVal;
templateIdKeyMap![theVal] = i;
}
}
//
//
if (students.isNotEmpty) {
try {
final currentStudent = students.firstWhere((e) => e.id == studentId);
priority = currentStudent.isPriority;
} catch (e) {
//
}
var currentStudent = students.firstWhereOrNull((e) => e.id == studentId);
if (currentStudent != null) priority = currentStudent.isPriority;
}
// URL
if (!zgtAnswer.contains(RequestConfig.imgUrl)) {
zgtAnswer = '${RequestConfig.imgUrl}$zgtAnswer?$lastAnswerTime';
}
// URL
if (zgtAnnotate?.isNotEmpty == true) {
showZgtAnnotate = RequestConfig.imgUrl + zgtAnnotate!;
if (annotateTime != null) {
showZgtAnnotate = '${showZgtAnnotate!}?$annotateTime';
}
if (zgtAnnotate?.isNotEmpty ?? false) {
showZgtAnnotate = RequestConfig.imgUrl + zgtAnnotate!; //
if (annotateTime != null) showZgtAnnotate = '${showZgtAnnotate!}?$annotateTime';
}
//
needAnnotate = annotateTime == null || studentQuestions.any((e) => e.studentScore == null);
if (annotateTime == null || studentQuestions.indexWhere((e) => e.studentScore == null) != -1) {
needAnnotate = true;
}
// print('学生作答图片:${annotatedCount}');
// print('老师批注图片提交数量:${submitCount}');
}
@ -154,15 +139,14 @@ class DoPaperDetailsResult {
Map<String, dynamic> toJson() => _$DoPaperDetailsResultToJson(this);
static List<Map<String, dynamic>> _paperStudentsToJson(List<PaperStudents> examples) =>
examples.map((e) => e.toJson()).toList();
static List<Map<String, dynamic>> _paperStudentsToJson(List<PaperStudents> examples) => examples.map((e) => e.toJson()).toList();
static List<Map<String, dynamic>> _studentQuestionsToJson(List<StudentQuestions> examples) =>
examples.map((e) => e.toJson()).toList();
static List<Map<String, dynamic>> _studentQuestionsToJson(List<StudentQuestions> examples) => examples.map((e) => e.toJson()).toList();
static Map<String, dynamic>? _nextPageToJson(NextPage? example) => example?.toJson();
static Map<String, dynamic>? _lastPageToJson(LastPage? example) => example?.toJson();
static Map<String, dynamic>? _continuePageToJson(ContinuePage? example) => example?.toJson();
}
@JsonSerializable()
@ -276,20 +260,22 @@ class NextPage extends Object {
Map<String, dynamic> toJson() => _$NextPageToJson(this);
}
@JsonSerializable()
class ContinuePage extends Object {
class ContinuePage extends Object {
@JsonKey(name: 'templateId')
int templateId;
@JsonKey(name: 'studentId')
int studentId;
ContinuePage(
this.templateId,
this.studentId,
);
ContinuePage(this.templateId,this.studentId,);
factory ContinuePage.fromJson(Map<String, dynamic> srcJson) => _$ContinuePageFromJson(srcJson);
Map<String, dynamic> toJson() => _$ContinuePageToJson(this);
}

View File

@ -1,44 +0,0 @@
import 'package:get/get.dart';
import '../mixins/request_tool_mixin.dart';
/// getx GetxController的拓展
///
///
/// 1. State
/// ``` dart
/// dart class MyState {
/// final String name;
/// MyState(this.name);
/// }
/// ```
/// 2. Controller
/// ``` dart
/// class MyController extends GetxControllerExpand<MyState> {
/// @override
/// MyState get state => MyState('hello');
/// }
/// ```
/// 3. View
/// ``` dart
/// class MyView extends GetViewExpand<MyController, MyState> {
/// const MyView({super.key});
///
/// @override
/// Widget build(BuildContext context) {
/// return Text(state.name);
/// }
/// }
/// ```
abstract class GetViewExpand<T extends GetxControllerExpand<U>, U> extends GetView<T> {
const GetViewExpand({super.key});
U get state => controller.state;
@override
T get controller => GetInstance().find<T>(tag: tag);
}
abstract class GetxControllerExpand<U> extends GetxController with RequestToolMixin {
U get state;
}

View File

@ -1,44 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
abstract class GetxKeepAliveWidget<T extends GetxController> extends StatefulWidget {
const GetxKeepAliveWidget({super.key});
@override
State<GetxKeepAliveWidget<T>> createState() => _GetxKeepAliveWidgetState<T>();
Widget buildContent(BuildContext context, T controller);
void initState() {}
void dispose() {}
}
class _GetxKeepAliveWidgetState<T extends GetxController> extends State<GetxKeepAliveWidget<T>>
with AutomaticKeepAliveClientMixin {
T get controller => GetInstance().find<T>();
@override
bool get wantKeepAlive => true;
@override
void initState() {
widget.initState();
super.initState();
}
@override
void dispose() {
widget.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
super.build(context);
return GetBuilder<T>(
builder: (controller) => widget.buildContent(context, controller),
assignId: true,
);
}
}

View File

@ -1,16 +1,15 @@
import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:get/get.dart' as getx;
import 'package:dio/dio.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:making_school_asignment_app/common/api/retrofit_client.dart';
import 'package:making_school_asignment_app/common/config/request_config.dart';
import 'package:making_school_asignment_app/common/job/user_info.dart';
import 'package:making_school_asignment_app/common/store/user_store.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/routes/app_pages.dart';
import 'package:package_info_plus/package_info_plus.dart';
import '../job/user_info_detail.dart';
import '../utils/storage.dart';
@ -41,7 +40,7 @@ class RequestTool {
RequestTool._internal(this._client);
static RequestTool get instance {
static get instance {
if (_instance == null) {
RetrofitClient client = _init();
_instance = RequestTool._internal(client);
@ -167,7 +166,7 @@ class TheError extends Interceptor {
var errorMap = response.data;
if (errorMap is String && errorMap.isNotEmpty) {
if (errorMap is String && errorMap.length > 0) {
try {
var errorModel = jsonDecode(errorMap);
var error = errorModel['error'];

View File

@ -3,26 +3,18 @@ import 'package:making_school_asignment_app/common/store/user_store.dart';
class EnumUtils {
static String formatSubject(int id) {
if (UserStore.to.subjectList.isEmpty) {
return '';
}
try {
EnumSubject item = UserStore.to.subjectList.firstWhere((element) => element.id == id);
return item.name;
} catch (e) {
if (UserStore.to.subjectList.isEmpty || id == null) {
return '';
}
EnumSubject item = UserStore.to.subjectList.firstWhere((element) => element.id == id);
return item.name ?? '';
}
static String formatGrade(int id) {
if (UserStore.to.gradeList.isEmpty) {
return '';
}
try {
EnumSubject item = UserStore.to.gradeList.firstWhere((element) => element.id == id);
return item.name;
} catch (e) {
if (UserStore.to.gradeList.isEmpty || id == null) {
return '';
}
EnumSubject item = UserStore.to.gradeList.firstWhere((element) => element.id == id);
return item.name ?? '';
}
}

View File

@ -1,106 +0,0 @@
// ramer_douglas_peucker.dart
import 'package:flutter/material.dart';
/// --Ramer-Douglas-Peucker, RDP
///
/// RDP算法用于将一条由大量点组成的曲线
///
class RamerDouglasPeucker {
/// 线
///
/// [point]:
/// [start]: 线
/// [end]: 线
/// 线线0
static double _getPerpendicularDistance(Offset point, Offset start, Offset end) {
final double dx = end.dx - start.dx;
final double dy = end.dy - start.dy;
final double lengthSquared = dx * dx + dy * dy;
// 线0
if (lengthSquared == 0.0) {
return (point - start).distance;
}
// 线
// t是投影点在线段方向向量上的比例因子
final double t = ((point.dx - start.dx) * dx + (point.dy - start.dy) * dy) / lengthSquared;
// t限制在[0, 1]线
// t<0startt>1end
final double tClamped = t.clamp(0.0, 1.0);
final Offset projection = Offset(start.dx + tClamped * dx, start.dy + tClamped * dy);
return (point - projection).distance;
}
/// 使RDP简化算法
///
/// [points]:
/// [epsilon]:
///
static List<Offset> simplify(List<Offset> points, double epsilon) {
final int totalPoints = points.length;
//
if (totalPoints < 3) {
return points;
}
// 使
final List<List<int>> stack = [];
// `keepPoint`
final List<bool> keepPoint = List.filled(totalPoints, false);
//
keepPoint[0] = true;
keepPoint[totalPoints - 1] = true;
// [0, totalPoints - 1]
stack.add([0, totalPoints - 1]);
while (stack.isNotEmpty) {
final List<int> currentSegment = stack.removeLast();
final int startIndex = currentSegment[0];
final int endIndex = currentSegment[1];
double maxDistance = 0.0;
int farthestIndex = 0;
// 线startIndex和endIndex构成
for (int i = startIndex + 1; i < endIndex; i++) {
final double distance = _getPerpendicularDistance(points[i], points[startIndex], points[endIndex]);
if (distance > maxDistance) {
maxDistance = distance;
farthestIndex = i;
}
}
// epsilon
if (maxDistance > epsilon) {
//
keepPoint[farthestIndex] = true;
// 线
//
if (farthestIndex - startIndex > 1) {
stack.add([startIndex, farthestIndex]);
}
//
if (endIndex - farthestIndex > 1) {
stack.add([farthestIndex, endIndex]);
}
}
}
//
final List<Offset> simplifiedPoints = [];
for (int i = 0; i < totalPoints; i++) {
if (keepPoint[i]) {
simplifiedPoints.add(points[i]);
}
}
return simplifiedPoints;
}
}

View File

@ -1,414 +0,0 @@
// shape_recognizer.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'ramer_douglas_peucker.dart';
///
enum GestureType {
none, //
check, // ()
cross, // (X)
halfCheck, // ( x)线
slash, // 线 (\ /)线线
}
///
/// Offset点
/// RDP算法线
class ShapeRecognizer {
// --- ---
/// Ramer-Douglas-Peucker epsilon
final double rdpEpsilon;
///
final double checkAngleMin;
///
final double checkAngleMax;
/// 线
final double crossAngleMin;
/// 线
final double crossAngleMax;
/// 线线
/// 0.15 线 15%
final double minIntersectionDistance;
///
///
final double checkLengthRatio;
/// 线线线
final double slashSlopeMin;
/// 线线线
final double slashSlopeMax;
/// 线线线
final double slashRadianMax;
///
ShapeRecognizer({
this.rdpEpsilon = 8.0,
this.checkAngleMin = 60.0,
this.checkAngleMax = 140.0,
this.crossAngleMin = 40.0,
this.crossAngleMax = 160.0,
this.minIntersectionDistance = 0.15,
this.checkLengthRatio = 1.1,
this.slashSlopeMin = 0.5,
this.slashSlopeMax = 2.0,
this.slashRadianMax = 140,
});
/// --- ---
///
/// 122
/// GestureType GestureType.none
GestureType recognize(List<List<Offset>> strokes) {
if (strokes.isEmpty) return GestureType.none; //
switch (strokes.length) {
case 1:
/// () 线 (\ /)
final points = strokes.first; //
if (points.length < 2) return GestureType.none; // 2线
var result = _recognizeCheck(points); //
if (result != GestureType.none) return result;
return _recognizeSlash(points); // 线
case 2:
// []
//
var halfCheckResult = _recognizeHalfCheck(strokes);
if (halfCheckResult != GestureType.none) return halfCheckResult;
//
return _recognizeCross(strokes);
// // (X) ( + 线)
// var crossResult = _recognizeCross(strokes); //
// if (crossResult != GestureType.none) return crossResult;
// return _recognizeHalfCheck(strokes); //
default:
return GestureType.none; //
}
}
/// --- ---
///
/// `_getCheckmarkDetails` `GestureType.check`
GestureType _recognizeCheck(List<Offset> rawPoints) {
return _getCheckmarkDetails(rawPoints) != null ? GestureType.check : GestureType.none;
}
/// 线
/// `_getSlashDetails` 线 `GestureType.slash`
GestureType _recognizeSlash(List<Offset> rawPoints) {
return _getSlashDetails(rawPoints) ? GestureType.slash : GestureType.none;
}
///
/// `_getCrossDetails` `GestureType.cross`
GestureType _recognizeCross(List<List<Offset>> rawStrokes) {
//
return _getCrossDetails(rawStrokes) != null ? GestureType.cross : GestureType.none;
}
///
/// 线
GestureType _recognizeHalfCheck(List<List<Offset>> strokes) {
if (strokes.length != 2) return GestureType.none;
/// 线
var firstStroke = strokes[0];
var lastStroke = strokes[1];
/// ,线
List<Offset>? checkDetails = _getCheckmarkDetails(firstStroke);
if (checkDetails == null) {
///
checkDetails = _getCheckmarkDetails(lastStroke);
if (checkDetails == null) {
return GestureType.none;
} else {
// checkDetails
final temp = firstStroke;
firstStroke = lastStroke;
lastStroke = temp;
}
}
// 1 stroke1 stroke2 线
if (_isHalfCheckCombination(
checkCandidate: firstStroke, crosserCandidate: lastStroke, checkDetails: checkDetails)) {
return GestureType.halfCheck;
}
return GestureType.none;
// if (twoStrokes.length != 2) return GestureType.none;
// final stroke1 = twoStrokes[0];
// final stroke2 = twoStrokes[1];
// // 1: stroke1是勾stroke2是交叉线
// final checkDetails1 = _getCheckmarkDetails(stroke1);
// if (checkDetails1 != null) {
// if (_checkHalfCheckLogic(checkDetails1, stroke2)) {
// return GestureType.halfCheck;
// }
// }
// // 2: stroke2是勾stroke1是交叉线
// final checkDetails2 = _getCheckmarkDetails(stroke2);
// if (checkDetails2 != null) {
// if (_checkHalfCheckLogic(checkDetails2, stroke1)) {
// return GestureType.halfCheck;
// }
// }
// return GestureType.none;
}
///
/// [checkCandidate]
/// [crosserCandidate] 线
/// [checkDetails]
bool _isHalfCheckCombination({
required List<Offset> checkCandidate,
required List<Offset> crosserCandidate,
required List<Offset> checkDetails,
}) {
//
final checkCorner = checkDetails[1];
final checkEndpoint = checkDetails[2];
final simplifiedCrosser = RamerDouglasPeucker.simplify(crosserCandidate, rdpEpsilon);
if (simplifiedCrosser.length < 2) return false;
// 2线
// 使
final intersection = _findIntersectionNearTip(
simplifiedCrosser.first, simplifiedCrosser.last, //
checkCorner, checkEndpoint, //
);
if (intersection != null) {
//
final vCross = simplifiedCrosser.last - simplifiedCrosser.first;
final vCheckLeg = checkEndpoint - checkCorner;
final angle = _calculateAngleBetweenVectors(vCross, vCheckLeg);
if (angle > crossAngleMin && angle < crossAngleMax) {
return true; //
}
}
return false; //
}
///
/// `checkLeg` `crossLine`
Offset? _findIntersectionNearTip(
Offset crossLineStart, Offset crossLineEnd, Offset checkLegStart, Offset checkLegEnd) {
final s1X = crossLineEnd.dx - crossLineStart.dx;
final s1Y = crossLineEnd.dy - crossLineStart.dy;
final s2X = checkLegEnd.dx - checkLegStart.dx;
final s2Y = checkLegEnd.dy - checkLegStart.dy;
final denominator = -s2X * s1Y + s1X * s2Y;
if (denominator.abs() < 1e-6) return null;
// t crossLine
final t =
(s2X * (crossLineStart.dy - checkLegStart.dy) - s2Y * (crossLineStart.dx - checkLegStart.dx)) / denominator;
// s checkLeg
final s =
(-s1Y * (crossLineStart.dx - checkLegStart.dx) + s1X * (crossLineStart.dy - checkLegStart.dy)) / denominator;
// 1: 线穿
final isCrosserIntersectedWell = t > minIntersectionDistance && t < (1 - minIntersectionDistance);
print("minIntersectionDistance: $minIntersectionDistance, t: $t");
// 2: (s > 0.1) (s <= 1.0)
final isCheckLegIntersectedNearTip = s >= 0.1 && s <= 1.0;
print(
"isCheckLegIntersectedNearTip: $isCheckLegIntersectedNearTip,isCrosserIntersectedWell: $isCrosserIntersectedWell, s: $s");
if (isCrosserIntersectedWell && isCheckLegIntersectedNearTip) {
return Offset(crossLineStart.dx + (t * s1X), crossLineStart.dy + (t * s1Y));
}
return null;
}
/// --- ---
///
/// `null`
List<Offset>? _getCheckmarkDetails(List<Offset> rawPoints) {
// 1. 使 RDP
final simplifiedPoints = RamerDouglasPeucker.simplify(rawPoints, rdpEpsilon);
// 3
if (simplifiedPoints.length < 3) return null;
// 2.
int cornerIndex = -1; //
double minAngle = 180.0; //
for (int i = 1; i < simplifiedPoints.length - 1; i++) {
//
final angle = _calculateAngle(simplifiedPoints[i - 1], simplifiedPoints[i], simplifiedPoints[i + 1]);
if (angle < minAngle) {
minAngle = angle;
cornerIndex = i;
}
}
// 3.
if (cornerIndex == -1 || minAngle < checkAngleMin || minAngle > checkAngleMax) return null;
// 4.
final p1 = simplifiedPoints.first, p2 = simplifiedPoints[cornerIndex], p3 = simplifiedPoints.last;
// 5. (p1-p2) (p2-p3)
// p2 p1 p3 p2 `p3.dy < p2.dy` V字
// p2.dy > p1.dy p2在p1下方p3.dy < p2.dy p3在p2上方
if (p2.dy > p1.dy && p3.dy < p2.dy) {
final length1 = (p2 - p1).distance, length2 = (p3 - p2).distance; // 线
// 6. `length2` `length1` `checkLengthRatio`
if (length1 > 0 && length2 > length1 * checkLengthRatio) return [p1, p2, p3]; //
}
return null; //
}
/// 线线
/// 线 RDP
bool _getSlashDetails(List<Offset> points) {
if (points.isEmpty) return false;
final simplified = RamerDouglasPeucker.simplify(points, rdpEpsilon);
// 1. 2线线
if (simplified.length == 2) {
final p1 = simplified.first, p2 = simplified.last;
final deltaX = (p2.dx - p1.dx).abs();
final deltaY = (p2.dy - p1.dy).abs();
if (deltaX < 1e-6) return true;
if (deltaY < 1e-6) return false;
final slope = deltaY / deltaX;
return slope > slashSlopeMin && slope < slashSlopeMax;
}
// 2. 3线
if (simplified.length == 3) {
final p1 = simplified[0];
final p2 = simplified[1]; //
final p3 = simplified[2];
//
final angle = _calculateAngle(p1, p2, p3);
// > 160线
// 线线
// 160
if (angle > slashRadianMax) {
// 线
final overallP1 = points.first;
final overallP3 = points.last;
final deltaX = (overallP3.dx - overallP1.dx).abs();
final deltaY = (overallP3.dy - overallP1.dy).abs();
if (deltaX < 1e-6) return true;
if (deltaY < 1e-6) return false;
final slope = deltaY / deltaX;
return slope > slashSlopeMin && slope < slashSlopeMax;
}
}
// 3. 14线
return false;
}
/// null
/// 线
Offset? _getCrossDetails(List<List<Offset>> twoStrokes) {
if (twoStrokes.length != 2) return null; //
//
final simplifiedStroke1 = RamerDouglasPeucker.simplify(twoStrokes[0], rdpEpsilon);
final simplifiedStroke2 = RamerDouglasPeucker.simplify(twoStrokes[1], rdpEpsilon);
if (simplifiedStroke1.length < 2 || simplifiedStroke2.length < 2) return null; // 线2
// 线使
final intersection = _findIntersection(
simplifiedStroke1.first, simplifiedStroke1.last, simplifiedStroke2.first, simplifiedStroke2.last);
if (intersection == null) return null; //
// 线
final angle = _calculateAngleBetweenVectors(
simplifiedStroke1.last - simplifiedStroke1.first, // 线
simplifiedStroke2.last - simplifiedStroke2.first); // 线
if (angle > crossAngleMin && angle < crossAngleMax) return intersection; //
return null;
}
/// --- ---
/// `p1``p2``p3` 线 `p2`
/// `p1-p2` `p3-p2`
double _calculateAngle(Offset p1, Offset p2, Offset p3) {
return _calculateAngleBetweenVectors(p1 - p2, p3 - p2);
}
/// `v1` `v2`
/// 使 `cosTheta`
double _calculateAngleBetweenVectors(Offset v1, Offset v2) {
final double dotProduct = v1.dx * v2.dx + v1.dy * v2.dy; //
final double magnitude1 = v1.distance; // v1
final double magnitude2 = v2.distance; // v2
if (magnitude1 == 0 || magnitude2 == 0) return 0; // 00
// cosTheta [-1, 1] acos
final cosTheta = (dotProduct / (magnitude1 * magnitude2)).clamp(-1.0, 1.0);
return acos(cosTheta) * 180 / pi; //
}
/// 线 (p1, p2) (p3, p4)
/// 使线
/// 线线线线 `null`
Offset? _findIntersection(Offset p1, Offset p2, Offset p3, Offset p4) {
final double s1X = p2.dx - p1.dx, s1Y = p2.dy - p1.dy; // 线
final double s2X = p4.dx - p3.dx, s2Y = p4.dy - p3.dy; // 线
final double denominator = -s2X * s1Y + s1X * s2Y; // 线
if (denominator == 0) return null; // 线线
// s t
// s 线(p3, p4)
final double s = (-s1Y * (p1.dx - p3.dx) + s1X * (p1.dy - p3.dy)) / denominator;
// t 线(p1, p2)
final double t = (s2X * (p1.dy - p3.dy) - s2Y * (p1.dx - p3.dx)) / denominator;
// 线线
// `s` `t` `minIntersectionDistance` `1 - minIntersectionDistance`
// 线
if (s > minIntersectionDistance &&
s < (1 - minIntersectionDistance) &&
t > minIntersectionDistance &&
t < (1 - minIntersectionDistance)) {
return Offset(p1.dx + (t * s1X), p1.dy + (t * s1Y)); //
}
return null; // 线
}
}

View File

@ -12,13 +12,18 @@ class PermissionDescribePage extends StatefulWidget {
final String describe;
final List<Permission> permissions;
const PermissionDescribePage({required this.title, required this.describe, required this.permissions, super.key});
const PermissionDescribePage(
{required this.title,
required this.describe,
required this.permissions,
super.key});
@override
State<PermissionDescribePage> createState() => _PermissionDescribePageState();
}
class _PermissionDescribePageState extends State<PermissionDescribePage> with WidgetsBindingObserver {
class _PermissionDescribePageState extends State<PermissionDescribePage>
with WidgetsBindingObserver {
Timer? _timerPermission;
bool theOpenAppSettings = false;
int theExecutionFrequency = 0;
@ -35,7 +40,7 @@ class _PermissionDescribePageState extends State<PermissionDescribePage> with Wi
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
print("-didChangeAppLifecycleState-$state");
print("-didChangeAppLifecycleState-" + state.toString());
switch (state) {
case AppLifecycleState.inactive: //
break;
@ -92,7 +97,7 @@ class _PermissionDescribePageState extends State<PermissionDescribePage> with Wi
);
}
permissions.add(p);
} else if (status.isPermanentlyDenied) {
} else if (await status.isPermanentlyDenied) {
permanentRefusal.add(p);
}
}
@ -132,7 +137,8 @@ class _PermissionDescribePageState extends State<PermissionDescribePage> with Wi
///
/// @param List<Permission> permissions
Future<List<Permission>> getStoragePermission(BuildContext context, List<Permission> permissions,
Future<List<Permission>> getStoragePermission(
BuildContext context, List<Permission> permissions,
[int executionFrequency = 0]) async {
Map<Permission, PermissionStatus> statusRes = await permissions.request();
@ -174,7 +180,8 @@ class _PermissionDescribePageState extends State<PermissionDescribePage> with Wi
executionFrequency++;
}
if (executionFrequency <= 1) {
var res = await getStoragePermission(context, [key], executionFrequency);
var res =
await getStoragePermission(context, [key], executionFrequency);
permanentRefusal.addAll(res);
} else {
permanentRefusal.add(key);
@ -208,7 +215,7 @@ class _PermissionDescribePageState extends State<PermissionDescribePage> with Wi
color: Colors.black.withOpacity(0.5), //
spreadRadius: 2, //
blurRadius: 4, //
offset: const Offset(0, 3), // X Y
offset: Offset(0, 3), // X Y
),
],
),
@ -232,7 +239,7 @@ class PermissionDescribeUtil {
PermissionDescribeUtil._internal();
static PermissionDescribeUtil get instance => _instance ??= PermissionDescribeUtil._internal();
static get instance => _instance ??= PermissionDescribeUtil._internal();
///
Future<void> toLaunchPermissionRequest(
@ -250,7 +257,7 @@ class PermissionDescribeUtil {
}
}
if (isGranted) {
await Navigator.of(Get.context ?? context).push(PageRouteBuilder(
Navigator.of(Get.context ?? context).push(PageRouteBuilder(
opaque: false,
pageBuilder: (context, animation, secondaryAnimation) {
return PermissionDescribePage(

View File

@ -2,16 +2,14 @@ import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
class StorageService extends GetxService {
static StorageService get to => Get.find<StorageService>();
static StorageService get to => Get.find();
late final GetStorage _getStorage;
get storage => _getStorage;
///
StorageService._(this._getStorage);
static Future<StorageService> init() async {
Future<StorageService> init() async {
await GetStorage.init();
return StorageService._(GetStorage());
_getStorage = GetStorage();
return this;
}
T? read<T>(String key) {

View File

@ -8,9 +8,9 @@
*/
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
class ToastUtils {
static void getFluttertoast({
@ -60,16 +60,8 @@ class ToastUtils {
EasyLoading.showError(showMsg);
}
static showLoading({
bool? dismissOnTap = false,
//
EasyLoadingMaskType? maskType = EasyLoadingMaskType.clear,
}) {
EasyLoading.show(
maskType: maskType, // 使
dismissOnTap: dismissOnTap,
status: 'loading...',
);
static showLoading() {
EasyLoading.show(status: 'loading...');
}
static showInfo(String showMsg, {Duration? duration}) {

View File

@ -1,10 +1,12 @@
import 'dart:convert';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/homework_details.dart';
import 'package:making_school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_state.dart';
import 'dart:math';
import '../config/request_config.dart';
@ -21,13 +23,17 @@ class Utils {
///
static void hideKeyboard() {
final currentFocus = Get.focusScope?.nearestScope;
if (currentFocus != null && !currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
FocusScopeNode? currentFocus = Get.focusScope?.nearestScope;
if (currentFocus == null) {
return;
}
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus?.unfocus();
}
}
void setTimeOut(int seconds, VoidCallback call) => Future.delayed(Duration(seconds: seconds), call);
void setTimeOut(int seconds, call) =>
Future.delayed(Duration(seconds: seconds), call);
//
static bool isPad([double mobilePhoneScale = 1.2]) {
@ -37,9 +43,9 @@ class Utils {
static String getDoubleRemoveZero(double? val, [String? defaultVal]) {
try {
if (val == null) throw Exception('数据为空');
List<String> valArr = val.toString().split('.');
if (valArr.length >= 2) {
if (int.parse(valArr[1]) == 0) {
List<String> _valArr = val.toString().split('.');
if (_valArr.length >= 2) {
if (int.parse(_valArr[1]) == 0) {
return val.toInt().toString();
}
return val.toString();
@ -91,30 +97,43 @@ class Utils {
dataCount.kgtAnswerCount = kgt.where((w) => w.state != 0).length;
dataCount.kgtOkCount = kgt.where((w) => w.state == 3).length;
dataCount.kgtDtlCount = kgt.length;
dataCount.kgtAnswerRate = Utils.calcRate(dataCount.kgtAnswerCount!, dataCount.kgtDtlCount!);
dataCount.kgtOkRate = Utils.calcRate(dataCount.kgtOkCount!, dataCount.kgtDtlCount!);
dataCount.kgtAnswerRate =
Utils.calcRate(dataCount.kgtAnswerCount!, dataCount.kgtDtlCount!);
dataCount.kgtOkRate =
Utils.calcRate(dataCount.kgtOkCount!, dataCount.kgtDtlCount!);
dataCount.kgtCorrectRate = Utils.calcRate(dataCount.kgtOkCount!, dataCount.kgtAnswerCount!);
dataCount.kgtCount = data.questions.where((w) => w.questionType == 1).length;
dataCount.kgtCorrectRate =
Utils.calcRate(dataCount.kgtOkCount!, dataCount.kgtAnswerCount!);
dataCount.kgtCount =
data.questions.where((w) => w.questionType == 1).length;
List<Dtls> zgt = data.dtls.where((w) => w.questionType == 2).toList();
dataCount.zgtAnswerCount = zgt.where((w) => w.state != 0).length;
dataCount.zgtOkCount = zgt.where((w) => w.state == 3).length;
dataCount.zgtDtlCount = zgt.length;
dataCount.zgtAnswerRate = Utils.calcRate(dataCount.zgtAnswerCount!, dataCount.zgtDtlCount!);
dataCount.zgtOkRate = Utils.calcRate(dataCount.zgtOkCount!, dataCount.zgtDtlCount!);
dataCount.zgtAnswerRate =
Utils.calcRate(dataCount.zgtAnswerCount!, dataCount.zgtDtlCount!);
dataCount.zgtOkRate =
Utils.calcRate(dataCount.zgtOkCount!, dataCount.zgtDtlCount!);
dataCount.zgtCorrectRate = Utils.calcRate(dataCount.zgtOkCount!, dataCount.zgtAnswerCount!);
dataCount.zgtCount = data.questions.where((w) => w.questionType == 2).length;
dataCount.zgtCorrectRate =
Utils.calcRate(dataCount.zgtOkCount!, dataCount.zgtAnswerCount!);
dataCount.zgtCount =
data.questions.where((w) => w.questionType == 2).length;
dataCount.studentCount = data.students.length;
dataCount.priorityStudents = data.students.where((w) => w.priorityAnnotate!).toList();
dataCount.priorityStudents =
data.students.where((w) => w.priorityAnnotate!).toList();
//
dataCount.studentSubmitCount = data.students.where((s) => s.state != 0).length;
dataCount.studentSubmitStudents = data.students.where((s) => s.state != 0).toList();
dataCount.studentSubmitCount =
data.students.where((s) => s.state != 0).length;
dataCount.studentSubmitStudents =
data.students.where((s) => s.state != 0).toList();
//
dataCount.noAnswerCount = data.students.length - dataCount.studentSubmitCount!;
dataCount.noAnswerStudents = data.students.where((s) => s.state == 0).toList();
dataCount.noAnswerCount =
data.students.length - dataCount.studentSubmitCount!;
dataCount.noAnswerStudents =
data.students.where((s) => s.state == 0).toList();
for (var stu in data.students) {
stu.kgtStu = kgt.where((w) => w.studentId == stu.studentId).toList();
@ -122,13 +141,16 @@ class Utils {
// stu.kgtStu!.sort((a, b) => num.parse(a.questionNo).compareTo(num.parse(b.questionNo)));
stu.kgtStu!.sort((a, b) {
try {
if (RegExp(r'^\d*\.?\d+$').hasMatch(a.questionNo) && RegExp(r'^\d*\.?\d+$').hasMatch(b.questionNo)) {
if (RegExp(r'^\d*\.?\d+$').hasMatch(a.questionNo) &&
RegExp(r'^\d*\.?\d+$').hasMatch(b.questionNo)) {
return num.parse(a.questionNo).compareTo(num.parse(b.questionNo));
} else {
throw Exception();
}
} catch (e) {
return a.questionNo.toLowerCase().compareTo(b.questionNo.toLowerCase());
return a.questionNo
.toLowerCase()
.compareTo(b.questionNo.toLowerCase());
}
});
stu.kgtOkCount = stu.kgtStu!.where((w) => w.state == 3).length;
@ -139,13 +161,16 @@ class Utils {
// stu.zgtStu!.sort((a, b) => num.parse(a.questionNo).compareTo(num.parse(b.questionNo)));
stu.zgtStu!.sort((a, b) {
try {
if (RegExp(r'^\d*\.?\d+$').hasMatch(a.questionNo) && RegExp(r'^\d*\.?\d+$').hasMatch(b.questionNo)) {
if (RegExp(r'^\d*\.?\d+$').hasMatch(a.questionNo) &&
RegExp(r'^\d*\.?\d+$').hasMatch(b.questionNo)) {
return num.parse(a.questionNo).compareTo(num.parse(b.questionNo));
} else {
throw Exception();
}
} catch (e) {
return a.questionNo.toLowerCase().compareTo(b.questionNo.toLowerCase());
return a.questionNo
.toLowerCase()
.compareTo(b.questionNo.toLowerCase());
}
});
//
@ -156,32 +181,43 @@ class Utils {
stu.zgtUnrated = stu.zgtStu!.where((w) => w.state == 1).length;
//
stu.zgtAnswerCount = stu.zgtStu!.where((w) => w.state != 0).length;
stu.isAllCorrect = stu.kgtOkCount! + stu.zgtOkCount! == kgt.length + zgt.length ? true : false;
stu.isAllCorrect =
stu.kgtOkCount! + stu.zgtOkCount! == kgt.length + zgt.length
? true
: false;
stu.allOk = data.dtls.where((w) {
if (stu.studentId == w.studentId) {
stu.useTime = w.useTime;
}
for (var que in data.questions) {
if (w.templateId == que.templateId && w.questionNo == que.questionNo) {
w.answer = que.answer;
w.questionPicture = que.questionPicture;
}
}
return w.studentId == stu.studentId && w.state != 3;
}).length;
if ((stu.kgtStu!.length - stu.kgtAnswerCount!) + (stu.zgtStu!.length - stu.zgtAnswerCount!) ==
if (stu.studentId == w.studentId) {
stu.useTime = w.useTime;
}
for (var que in data.questions) {
if (w.templateId == que.templateId &&
w.questionNo == que.questionNo) {
w.answer = que.answer;
w.questionPicture = que.questionPicture;
}
}
return w.studentId == stu.studentId && w.state != 3;
}).length ??
0;
if ((stu.kgtStu!.length - stu.kgtAnswerCount!) +
(stu.zgtStu!.length - stu.zgtAnswerCount!) ==
(stu.kgtStu!.length + stu.zgtStu!.length)) {
stu.allNotDone = true;
} else {
stu.allNotDone = false;
}
stu.noAnswerCount = data.dtls.where((w) => w.state == 0 && stu.studentId == w.studentId).length;
stu.noAnswerCount = data.dtls
.where((w) => w.state == 0 && stu.studentId == w.studentId)
.length;
List<Questions> ques = data.questions;
stu.queDtls = data.dtls
.where((w) =>
w.studentId == stu.studentId &&
ques.indexWhere((q) => w.templateId == q.templateId && w.questionNo == q.questionNo) > -1)
ques.indexWhere((q) =>
w.templateId == q.templateId &&
w.questionNo == q.questionNo) >
-1)
.toList();
int okCount = stu.queDtls!.where((w) => w.state == 3).length;
int ttlCount = stu.queDtls!.length;
@ -205,7 +241,15 @@ class Utils {
secList.sort();
/* var maxSec = secList.isNotEmpty ? secList.last : 0;
var minSec = secList.isNotEmpty ? secList.first : 0;*/
final secTime = secList.isNotEmpty ? secList.last - secList.first : 0;
var maxSec = secList.isNotEmpty
? secList
.reduce((value, element) => value > element ? value : element)
: 0;
var minSec = secList.isNotEmpty
? secList
.reduce((value, element) => value < element ? value : element)
: 0;
var secTime = secList.isNotEmpty ? maxSec - minSec : 0;
stu.allTime = secTime;
stu.ttlSec = second2HMS(secTime);
}
@ -215,32 +259,43 @@ class Utils {
int num2 = b.state;
return num2.compareTo(num1);
});
//
final allCorrectStudents = data.students.where((w) => w.isAllCorrect == true).toList();
dataCount.allCorrect = allCorrectStudents.length;
dataCount.allCorrectStudents = allCorrectStudents;
//
dataCount.allCorrect =
data.students.where((w) => w.isAllCorrect == true).length;
dataCount.allCorrectStudents =
data.students.where((w) => w.isAllCorrect == true).toList();
//
dataCount.levelOneCount =
data.students.where((s) => s.okRate! >= 85).length;
dataCount.levelOneStudents =
data.students.where((s) => s.okRate! >= 85).toList();
final levelOneStudents = data.students.where((s) => s.okRate! >= 85).toList();
dataCount.levelOneCount = levelOneStudents.length;
dataCount.levelOneStudents = levelOneStudents;
//
dataCount.levelTwoCount =
data.students.where((s) => s.okRate! < 85 && s.okRate! >= 55).length;
dataCount.levelTwoStudents =
data.students.where((s) => s.okRate! < 85 && s.okRate! >= 55).toList();
final levelTwoStudents = data.students.where((s) => s.okRate! < 85 && s.okRate! >= 55).toList();
dataCount.levelTwoCount = levelTwoStudents.length;
dataCount.levelTwoStudents = levelTwoStudents;
//
dataCount.levelThreeCount =
data.students.where((s) => s.okRate! < 55 && s.okRate! >= 25).length;
dataCount.levelThreeStudents =
data.students.where((s) => s.okRate! < 55 && s.okRate! >= 25).toList();
final levelThreeStudents = data.students.where((s) => s.okRate! < 55 && s.okRate! >= 25).toList();
dataCount.levelThreeCount = levelThreeStudents.length;
dataCount.levelThreeStudents = levelThreeStudents;
final levelFourStudents = data.students.where((s) => s.okRate! < 25).toList();
dataCount.levelFourCount = levelFourStudents.length;
dataCount.levelFourStudents = levelFourStudents;
//
dataCount.levelFourCount =
data.students.where((s) => s.okRate! < 25).length;
dataCount.levelFourStudents =
data.students.where((s) => s.okRate! < 25).toList();
for (var que in data.questions) {
List<Dtls> ques =
data.dtls.where((w) => w.templateId == que.templateId && w.questionNo == que.questionNo).toList();
List<Dtls> ques = data.dtls
.where((w) =>
w.templateId == que.templateId && w.questionNo == que.questionNo)
.toList();
que.answerCount = ques.where((w) => w.state != 0).length;
que.answerRate = Utils.calcRate(que.answerCount!, dataCount.studentCount!);
que.answerRate =
Utils.calcRate(que.answerCount!, dataCount.studentCount!);
int okCount = ques.where((w) => w.state == 3).length;
que.okRate = Utils.calcRate(okCount, dataCount.studentCount!);
que.priorityInfo = ques.where((w) {
@ -253,12 +308,9 @@ class Utils {
}).toList();
que.correctRate = Utils.calcRate(okCount, que.answerCount!);
que.answerNgStudents = ques.where((w) {
try {
var student = data.students.firstWhere((s) => s.studentId == w.studentId);
w.studentName = student.studentName;
} catch (e) {
w.studentName = '';
}
w.studentName = data.students
.firstWhere((s) => s.studentId == w.studentId)
.studentName;
return w.state == 2;
}).toList();
@ -273,16 +325,21 @@ class Utils {
int middleTime = 0;
if (ques.length % 2 == 0) {
int index = (ques.length / 2).ceil();
middleTime = ((ques[index].useTime + ques[index - 1].useTime) / 2).ceil();
middleTime =
((ques[index].useTime + ques[index - 1].useTime) / 2).ceil();
} else {
int index = ((ques.length + 1) / 2).ceil();
middleTime = ques[index - 1].useTime;
}
var excellent = ques.where((w) => w.state == 3 && w.useTime <= middleTime).length;
var good = ques.where((w) => w.state == 3 && w.useTime > middleTime).length;
var middle = ques.where((w) => w.state != 3 && w.useTime <= middleTime).length;
var differ = ques.where((w) => w.state != 3 && w.useTime > middleTime).length;
var excellent =
ques.where((w) => w.state == 3 && w.useTime <= middleTime).length;
var good =
ques.where((w) => w.state == 3 && w.useTime > middleTime).length;
var middle =
ques.where((w) => w.state != 3 && w.useTime <= middleTime).length;
var differ =
ques.where((w) => w.state != 3 && w.useTime > middleTime).length;
que.overallTitles = [
OverallTitles('优秀', excellent),
@ -292,7 +349,8 @@ class Utils {
];
Map<String, int> optInfos = {};
for (var d in ques.where((w) => w.questionType == 1 && w.studentAnswer != null)) {
for (var d in ques
.where((w) => w.questionType == 1 && w.studentAnswer != null)) {
final key = d.studentAnswer!;
if (optInfos[key] != null) {
optInfos[key] = optInfos[key]! + 1;
@ -304,14 +362,21 @@ class Utils {
optInfos.forEach((key, value) {
// optInfos[key] = Utils.calcRate(value, ques.length).round();
List<Students> currentOptionStudents = data.students
.where((s) => ques.where((w) => w.studentAnswer == key && w.studentId == s.studentId).isNotEmpty)
.where((s) => ques
.where(
(w) => w.studentAnswer == key && w.studentId == s.studentId)
.isNotEmpty)
.toList();
//
String upStr = key.toUpperCase();
List<String> chars = upStr.split('')..sort();
String sortedStr = chars.join();
student.add(SelectionRate(sortedStr, Utils.calcRate(value, ques.length).round(), false, currentOptionStudents));
student.add(SelectionRate(
sortedStr,
Utils.calcRate(value, ques.length).round(),
false,
currentOptionStudents));
});
/* print('optitems=$optInfos');
var ARate = Utils.calcRate(
@ -320,10 +385,16 @@ class Utils {
}
for (var know in data.knows) {
List<Questions> ques =
data.questions.where((w) => w.knows.indexWhere((k) => k.knowledgeId == know.knowledgeId) > -1).toList();
List<Questions> ques = data.questions
.where((w) =>
w.knows.indexWhere((k) => k.knowledgeId == know.knowledgeId) > -1)
.toList();
List<Dtls> queDtls = data.dtls
.where((w) => ques.indexWhere((q) => w.templateId == q.templateId && w.questionNo == q.questionNo) > -1)
.where((w) =>
ques.indexWhere((q) =>
w.templateId == q.templateId &&
w.questionNo == q.questionNo) >
-1)
.toList();
know.okCount = queDtls.where((w) => w.state == 3).length;
know.ttlCount = queDtls.length;
@ -362,7 +433,8 @@ bool isPad([double mobilePhoneScale = 1.2]) {
return ScreenUtil().scaleWidth > mobilePhoneScale;
}
void toUpState(Function(void Function()) setState, VoidCallback fn, bool mounted) {
void toUpState(
Function(void Function()) setState, VoidCallback fn, bool mounted) {
if (mounted) setState(fn);
}

View File

@ -1,11 +1,8 @@
import 'dart:io';
import 'package:auto_updater/auto_updater.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/config/app_config.dart';
@ -14,20 +11,25 @@ import 'package:making_school_asignment_app/common/store/user_store.dart';
import 'package:making_school_asignment_app/common/utils/storage.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'common/config/request_config.dart';
import 'common/utils/app_upgrade/upgradeLogic.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
void main() async {
// Get
Get.testMode = true;
FlutterNativeSplash.preserve(widgetsBinding: WidgetsFlutterBinding.ensureInitialized());
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
///
await Get.putAsync<StorageService>(() => StorageService.init());
await Get.putAsync(() => StorageService().init());
/// UserStore
await Get.putAsync<UserStore>(() async => UserStore().init());
Get.put<UserStore>(UserStore().init());
Get.put(UpgradeLogic());
WidgetsFlutterBinding.ensureInitialized();
// Windows
if (Platform.isWindows) {
@ -41,11 +43,9 @@ void main() async {
statusBarColor: Colors.transparent, //
statusBarIconBrightness: Brightness.light // dark: light
));
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky, overlays: [SystemUiOverlay.top]); //
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top]); //
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); //
runApp(const MyApp());
Future.delayed(const Duration(seconds: 3), () => FlutterNativeSplash.remove());
}
class MyApp extends StatelessWidget {
@ -121,13 +121,12 @@ class MyApp extends StatelessWidget {
initialRoute: Routes.startPage,
///
initialBinding: MainBinding(),
getPages: AppPages.pages,
builder: EasyLoading.init(
builder: (context, child) {
return MediaQuery(
//Setting font does not change with system font size
data: MediaQuery.of(context).copyWith(textScaler: const TextScaler.linear(1.0)),
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
child: Scaffold(
body: GestureDetector(onTap: () => Utils.hideKeyboard(), child: child),
),
@ -139,12 +138,3 @@ class MyApp extends StatelessWidget {
);
}
}
/// MainBinding
class MainBinding implements Bindings {
@override
void dependencies() async {
/// APP
Get.put(UpgradeLogic(), permanent: true);
}
}

View File

@ -1,300 +0,0 @@
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:making_school_asignment_app/common/utils/gesture_recognition/ramer_douglas_peucker.dart';
import 'package:making_school_asignment_app/common/utils/gesture_recognition/shape_recognizer.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: const Size(375, 812),
builder: () => MaterialApp(
title: '手势识别实验',
theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true),
home: const GestureCanvasPage(),
),
);
}
}
class GestureCanvasPage extends StatefulWidget {
const GestureCanvasPage({super.key});
@override
State<GestureCanvasPage> createState() => _GestureCanvasPageState();
}
class _GestureCanvasPageState extends State<GestureCanvasPage> {
final List<List<Offset>> _allStrokes = [];
final _currentStrokeNotifier = ValueNotifier<List<Offset>>([]);
ui.Image? _cachedImage;
GestureType _recognizedGesture = GestureType.none;
late ShapeRecognizer _recognizer;
//
bool _showSimplifiedPoints = true;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
// 便
_recognizer = ShapeRecognizer(
rdpEpsilon: 8.r, //
///
checkAngleMin: 30.0,
///
checkAngleMax: 150.0,
crossAngleMin: 30.0,
crossAngleMax: 160.0,
minIntersectionDistance: 0.1,
checkLengthRatio: 1.1,
// [] 线
slashSlopeMin: 0.2, // 线11线
slashSlopeMax:
5.0, // 线79线线 _isSlash 线 (deltaX < 1e-6)线
);
}
});
}
Future<void> _updateCachedImage() async {
final recorder = ui.PictureRecorder();
final canvas = Canvas(recorder);
final size = context.size!;
_GestureCachePainter(allStrokes: _allStrokes).paint(canvas, size);
final picture = recorder.endRecording();
final newImage = await picture.toImage(size.width.toInt(), size.height.toInt());
if (mounted) {
setState(() {
_cachedImage = newImage;
});
}
}
void _onPanStart(DragStartDetails details) {
_currentStrokeNotifier.value = [details.localPosition];
}
void _onPanUpdate(DragUpdateDetails details) {
_currentStrokeNotifier.value = List.from(_currentStrokeNotifier.value)..add(details.localPosition);
}
void _onPanEnd(DragEndDetails details) {
if (_currentStrokeNotifier.value.isNotEmpty) {
_allStrokes.add(List.from(_currentStrokeNotifier.value));
_currentStrokeNotifier.value = [];
_updateCachedImage().then((_) {
if (mounted) {
setState(() {
_recognizedGesture = _recognizer.recognize(_allStrokes);
print('识别到的手势: $_recognizedGesture');
});
}
});
}
}
void _clearCanvas() {
setState(() {
_allStrokes.clear();
_recognizedGesture = GestureType.none;
_cachedImage = null;
});
_currentStrokeNotifier.value = [];
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('手势识别 (可视化调试)'),
actions: [
// AppBar中添加一个信息提示
Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Icon(
Icons.science_outlined,
color: _showSimplifiedPoints ? Colors.green : Colors.grey,
),
)
],
),
body: Stack(
children: [
GestureDetector(
onPanStart: _onPanStart,
onPanUpdate: _onPanUpdate,
onPanEnd: _onPanEnd,
child: ValueListenableBuilder<List<Offset>>(
valueListenable: _currentStrokeNotifier,
builder: (context, currentStroke, child) {
return CustomPaint(
painter: _GestureCanvasPainter(
cachedImage: _cachedImage,
currentStroke: currentStroke,
// [] Painter
allStrokes: _allStrokes,
rdpEpsilon: _recognizer.rdpEpsilon,
showSimplifiedPoints: _showSimplifiedPoints,
),
size: Size.infinite,
);
},
),
),
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'识别结果: ${_recognizedGesture.toString().split('.').last}\nEpsilon: ${_recognizer.rdpEpsilon.toStringAsFixed(2)}',
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.blue),
),
),
),
],
),
// [] 使Column包裹多个FAB
floatingActionButton: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: _clearCanvas,
tooltip: '清空画布',
child: const Icon(Icons.clear),
),
const SizedBox(height: 10),
//
FloatingActionButton(
onPressed: () {
setState(() {
_showSimplifiedPoints = !_showSimplifiedPoints;
});
},
tooltip: '切换特征点显示',
backgroundColor: _showSimplifiedPoints ? Colors.green : Colors.grey[400],
child: const Icon(Icons.science_outlined),
),
],
),
);
}
}
class _GestureCanvasPainter extends CustomPainter {
final ui.Image? cachedImage;
final List<Offset> currentStroke;
final Paint _paint;
// []
final List<List<Offset>> allStrokes;
final double rdpEpsilon;
final bool showSimplifiedPoints;
final Paint _debugPaint; //
_GestureCanvasPainter({
required this.cachedImage,
required this.currentStroke,
required this.allStrokes,
required this.rdpEpsilon,
required this.showSimplifiedPoints,
}) : _paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0
..style = PaintingStyle.stroke,
//
_debugPaint = Paint()
..color = Colors.red
..strokeCap = StrokeCap.round
..strokeWidth = 8.0;
@override
void paint(Canvas canvas, Size size) {
// 1: ()
if (cachedImage != null) {
canvas.drawImage(cachedImage!, Offset.zero, Paint());
}
// 2:
if (currentStroke.length > 1) {
final path = Path();
path.moveTo(currentStroke.first.dx, currentStroke.first.dy);
for (int i = 1; i < currentStroke.length; i++) {
path.lineTo(currentStroke[i].dx, currentStroke[i].dy);
}
canvas.drawPath(path, _paint);
}
// 3:
if (showSimplifiedPoints) {
//
for (final stroke in allStrokes) {
if (stroke.length > 1) {
final simplifiedPoints = RamerDouglasPeucker.simplify(stroke, rdpEpsilon);
canvas.drawPoints(ui.PointMode.points, simplifiedPoints, _debugPaint);
}
}
//
if (currentStroke.length > 1) {
final simplifiedPoints = RamerDouglasPeucker.simplify(currentStroke, rdpEpsilon);
canvas.drawPoints(ui.PointMode.points, simplifiedPoints, _debugPaint);
}
}
}
@override
bool shouldRepaint(covariant _GestureCanvasPainter oldDelegate) {
// []
return oldDelegate.currentStroke != currentStroke ||
oldDelegate.showSimplifiedPoints != showSimplifiedPoints ||
oldDelegate.allStrokes.length != allStrokes.length;
}
}
//
class _GestureCachePainter extends CustomPainter {
final List<List<Offset>> allStrokes;
final Paint _paint;
_GestureCachePainter({required this.allStrokes})
: _paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0
..style = PaintingStyle.stroke;
@override
void paint(Canvas canvas, Size size) {
for (final stroke in allStrokes) {
if (stroke.length > 1) {
final path = Path();
path.moveTo(stroke.first.dx, stroke.first.dy);
for (int i = 1; i < stroke.length; i++) {
path.lineTo(stroke[i].dx, stroke[i].dy);
}
canvas.drawPath(path, _paint);
}
}
}
@override
bool shouldRepaint(covariant _GestureCachePainter oldDelegate) {
return oldDelegate.allStrokes != allStrokes;
}
}

View File

@ -18,7 +18,7 @@ class ReturnToHomepage extends StatelessWidget {
child: Container(
padding: EdgeInsets.only(right: 4.5.w),
alignment: Alignment.center,
child: Icon(Icons.home_rounded, size: 30.r, color: bgColor),
child: Icon(Icons.home_rounded, size: 22.sp, color: bgColor),
),
);
}

View File

@ -18,7 +18,6 @@ Text quickText(text,
FontWeight? fontWeight,
TextOverflow overflow = TextOverflow.ellipsis,
int maxLines = 1,
double? height,
TextDecoration decoration = TextDecoration.none}) {
return Text(
text.toString(),
@ -31,7 +30,6 @@ Text quickText(text,
color: color,
fontWeight: fontWeight,
wordSpacing: wordSpacing,
height: height,
),
);
}

View File

@ -1,20 +1,21 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/user_info.dart';
import 'package:making_school_asignment_app/common/job/user_info_detail.dart';
import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart';
import 'package:making_school_asignment_app/common/store/user_store.dart';
import 'package:making_school_asignment_app/common/utils/app_upgrade/upgradeLogic.dart';
import 'package:making_school_asignment_app/common/utils/storage.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/page/home_page/children/my_info.dart';
import 'package:making_school_asignment_app/page/home_page/home_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'package:making_school_asignment_app/common/job/user_info.dart';
import 'package:making_school_asignment_app/common/utils/storage.dart';
import 'package:making_school_asignment_app/common/store/user_store.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/page/home_page/home_view.dart';
import 'package:making_school_asignment_app/page/home_page/home_logic.dart';
import 'package:making_school_asignment_app/page/work_page/work_logic.dart';
import 'package:making_school_asignment_app/common/job/user_info_detail.dart';
import 'package:making_school_asignment_app/page/home_page/children/my_info.dart';
import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart';
import 'package:making_school_asignment_app/common/utils/app_upgrade/upgradeLogic.dart';
class StartPage extends StatefulWidget {
const StartPage({super.key});
@ -36,13 +37,14 @@ class _StartPageState extends State<StartPage> with RequestToolMixin {
void initState() {
super.initState();
Future.delayed(const Duration(seconds: 3), () => FlutterNativeSplash.remove());
// const WorkPage(),
_bodyList = [const HomePage(), const MyInfo()];
// APP
WidgetsBinding.instance.addPostFrameCallback((e) {
/// 40APP
if (!_upgradeLogic.showUpgrade.value && UserStore.to.userDetailInfo.value != null)
_upgradeLogic.getAppUpgrade(context);
if (!_upgradeLogic.showUpgrade.value && UserStore.to.userDetailInfo.value != null) _upgradeLogic.getAppUpgrade(context);
});
_timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 40), (e) {
@ -89,8 +91,7 @@ class _StartPageState extends State<StartPage> with RequestToolMixin {
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
return WillPopScope(
child: Scaffold(
body: PageView(
controller: _pageController._pageIndexState.pageController,
@ -140,19 +141,15 @@ class _StartPageState extends State<StartPage> with RequestToolMixin {
);
}),
),
onPopInvokedWithResult: (bool didPop, dynamic result) async {
onWillPop: () async {
if (lastPopTime == null || DateTime.now().difference(lastPopTime!) > const Duration(seconds: 1)) {
lastPopTime = DateTime.now();
ToastUtils.getFluttertoast(
context: context,
msg: '连续两次返回就退出',
gravity: ToastGravity.CENTER,
fontSize: 18,
);
ToastUtils.getFluttertoast(context: context, msg: '连续两次返回就退出');
return Future.value(false);
} else {
lastPopTime = DateTime.now();
// 退app
SystemNavigator.pop();
return Future.value(true);
}
},
);

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:get/get.dart';
@ -37,9 +35,10 @@ class AnnotateClassLogic extends GetxController with RequestToolMixin {
}
void getList() async {
List<AnnotatedClass> data = await getClient().getAnnotatedClassList(state.homeworkId.value);
List<AnnotatedClass> data =
await getClient().getAnnotatedClassList(state.homeworkId.value);
state.classList.value = data;
/* print('state.classList[0]=${state.classList[0].finishTime}');
/* print('state.classList[0]=${state.classList[0].finishTime}');
print('state.classList[1]=${state.classList[1].finishTime}');*/
for (var element in state.classList.value) {
int commitStudentCount = 0;
@ -62,7 +61,9 @@ class AnnotateClassLogic extends GetxController with RequestToolMixin {
void getAllCorrect(classId) async {
EasyLoading.show(status: 'loading...');
try {
await getClient().getAllCorrect(state.homeworkId.value, classId).then((e) {
await getClient()
.getAllCorrect(state.homeworkId.value, classId)
.then((e) {
getList();
});
} catch (e) {
@ -107,25 +108,4 @@ class AnnotateClassLogic extends GetxController with RequestToolMixin {
super.dispose();
refreshController.dispose();
}
///
/// [homeworkId]
/// [homeworkName]
/// [classId]
/// [subject]
void toGoReviewhomework({required homeworkId, required homeworkName, required classId, required subject}) async {
// UI
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky, overlays: <SystemUiOverlay>[]);
WidgetsBinding.instance.addPostFrameCallback((_) async {
await Future.delayed(const Duration(milliseconds: 300));
await Get.toNamed(Routes.reviewHomework, arguments: {
'homeworkId': homeworkId,
'homeworkName': homeworkName,
'classId': classId,
'subject': subject
})?.then((value) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge, overlays: [SystemUiOverlay.top]);
});
});
}
}

View File

@ -1,17 +1,18 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/annotated_class.dart';
import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart';
import 'package:making_school_asignment_app/page/global_widget/show_student_list.dart';
import 'package:percent_indicator/percent_indicator.dart';
import 'package:making_school_asignment_app/common/job/annotated_class.dart';
import 'package:making_school_asignment_app/common/utils/enum_untils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/page/global_widget/show_student_list.dart';
import 'package:making_school_asignment_app/page/home_page/children/annotate_class/annotate_class_logic.dart';
import 'package:making_school_asignment_app/page/home_page/children/annotate_class/widget/item_btn.dart';
import 'package:making_school_asignment_app/page/home_page/widget/progress_bar.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'package:percent_indicator/percent_indicator.dart';
class AnnotateItem extends StatefulWidget {
final String homeworkId;
@ -19,13 +20,7 @@ class AnnotateItem extends StatefulWidget {
final double font;
final String name;
final AnnotateClassLogic logic;
const AnnotateItem(
{super.key,
required this.homeworkId,
required this.item,
required this.font,
required this.name,
required this.logic});
const AnnotateItem({super.key, required this.homeworkId, required this.item, required this.font, required this.name, required this.logic});
@override
State<AnnotateItem> createState() => _AnnotateItemState();
@ -164,16 +159,10 @@ class _AnnotateItemState extends State<AnnotateItem> {
Expanded(
flex: 4,
child: ItemBtn(
title:
"收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}",
title: "收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}",
font: widget.font - 2.sp,
clickFunction: () {
Get.toNamed(Routes.favStudentPage, arguments: {
'homeworkName': widget.name,
'classId': widget.item.classId,
'homeworkId': widget.logic.state.homeworkId.value,
'grade': widget.item.grade
});
Get.toNamed(Routes.favStudentPage, arguments: {'homeworkName': widget.name, 'classId': widget.item.classId, 'homeworkId': widget.logic.state.homeworkId.value, 'grade': widget.item.grade});
},
),
),
@ -218,16 +207,10 @@ class _AnnotateItemState extends State<AnnotateItem> {
Expanded(
flex: 4,
child: ItemBtn(
title:
"收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}",
title: "收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}",
font: widget.font - 2.sp,
clickFunction: () {
Get.toNamed(Routes.favStudentPage, arguments: {
'homeworkName': widget.name,
'classId': widget.item.classId,
'homeworkId': widget.logic.state.homeworkId.value,
'grade': widget.item.grade
});
Get.toNamed(Routes.favStudentPage, arguments: {'homeworkName': widget.name, 'classId': widget.item.classId, 'homeworkId': widget.logic.state.homeworkId.value, 'grade': widget.item.grade});
},
),
),
@ -238,10 +221,7 @@ class _AnnotateItemState extends State<AnnotateItem> {
padding: EdgeInsets.only(top: 10.r, left: 14.r, right: 14.r),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
quickText('批阅进度', size: widget.font - 2.sp, color: const Color(0xFF8E8E8E)),
quickText('${widget.item.annotateRate}%', size: widget.font + 10.sp, color: const Color(0xFF464646))
],
children: [quickText('批阅进度', size: widget.font - 2.sp, color: const Color(0xFF8E8E8E)), quickText('${widget.item.annotateRate}%', size: widget.font + 10.sp, color: const Color(0xFF464646))],
),
),
Padding(
@ -269,27 +249,9 @@ class _AnnotateItemState extends State<AnnotateItem> {
barRadius: Radius.circular(10.r),
),
),
ProgressBar(
title: '客观题正确率:',
color: const Color(0xFFADDCA5),
percent: widget.item.kgtCorrectRate / 100,
marginEdg: EdgeInsets.zero,
padingEdg: EdgeInsets.only(top: 8.h, left: 14.r, right: 14.r),
fontSize: widget.font - 2.sp),
ProgressBar(
title: '主观题正确率:',
color: const Color(0xFFADDCA5),
percent: widget.item.zgtCorrectRate / 100,
padingEdg: EdgeInsets.symmetric(horizontal: 10.r),
marginEdg: EdgeInsets.only(top: 8.h),
fontSize: widget.font - 2.sp),
ProgressBar(
title: '总正确率:',
color: const Color(0xFFADDCA5),
percent: widget.item.correctRate / 100,
padingEdg: EdgeInsets.symmetric(horizontal: 10.r),
marginEdg: EdgeInsets.only(top: 8.h),
fontSize: widget.font - 2.sp),
ProgressBar(title: '客观题正确率:', color: const Color(0xFFADDCA5), percent: widget.item.kgtCorrectRate / 100, marginEdg: EdgeInsets.zero, padingEdg: EdgeInsets.only(top: 8.h, left: 14.r, right: 14.r), fontSize: widget.font - 2.sp),
ProgressBar(title: '主观题正确率:', color: const Color(0xFFADDCA5), percent: widget.item.zgtCorrectRate / 100, padingEdg: EdgeInsets.symmetric(horizontal: 10.r), marginEdg: EdgeInsets.only(top: 8.h), fontSize: widget.font - 2.sp),
ProgressBar(title: '总正确率:', color: const Color(0xFFADDCA5), percent: widget.item.correctRate / 100, padingEdg: EdgeInsets.symmetric(horizontal: 10.r), marginEdg: EdgeInsets.only(top: 8.h), fontSize: widget.font - 2.sp),
Container(
margin: EdgeInsets.only(top: 10.r),
decoration: BoxDecoration(
@ -315,9 +277,7 @@ class _AnnotateItemState extends State<AnnotateItem> {
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 10.r),
decoration: BoxDecoration(
border: Border(
right: BorderSide(width: 1.r, color: const Color.fromRGBO(221, 221, 221, 1)))),
decoration: BoxDecoration(border: Border(right: BorderSide(width: 1.r, color: const Color.fromRGBO(221, 221, 221, 1)))),
alignment: Alignment.center,
child: quickText('数据快查', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font),
),
@ -338,20 +298,29 @@ class _AnnotateItemState extends State<AnnotateItem> {
: [
Expanded(
child: InkWell(
onTap: () => easyThrottle('TO_GO_REVIEWHOMEWORK', () {
///
widget.logic.toGoReviewhomework(
homeworkId: widget.homeworkId,
homeworkName: widget.name,
classId: itemData.classId,
subject: widget.logic.state.subject,
);
onTap: () => easyThrottle('TO_GO_REVIEWHOMEWORK', () async {
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
WidgetsBinding.instance.addPostFrameCallback((_) {
Future.delayed(const Duration(milliseconds: 300), () {
Get.toNamed(Routes.reviewHomework, arguments: {
'homeworkId': widget.homeworkId,
'homeworkName': widget.name,
'classId': itemData.classId,
'subject': widget.logic.state.subject,
});
});
});
// Get.toNamed(Routes.reviewHomework, arguments: {
// 'homeworkId': widget.homeworkId,
// 'homeworkName': widget.name,
// 'classId': itemData.classId,
// 'subject': widget.logic.state.subject,
// });
}),
child: Container(
padding: EdgeInsets.symmetric(vertical: 10.r),
decoration: BoxDecoration(
border: Border(
right: BorderSide(width: 1.r, color: const Color.fromRGBO(221, 221, 221, 1)))),
decoration: BoxDecoration(border: Border(right: BorderSide(width: 1.r, color: const Color.fromRGBO(221, 221, 221, 1)))),
alignment: Alignment.center,
child: quickText('批阅', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font),
),

View File

@ -1,6 +1,7 @@
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:making_school_asignment_app/common/job/student_item.dart';
import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart';
@ -15,8 +16,7 @@ class ClassStudentLogic extends GetxController with RequestToolMixin {
super.onInit();
state.title.value = Get.arguments['title'] ?? '';
state.classId = Get.arguments['classId'] ?? '';
final subject = Get.arguments['subject'];
state.subject = subject == 0 ? null : subject;
state.subject = Get.arguments['subject'] ?? -1;
state.page = Get.arguments['page'] ?? '';
EasyLoading.show(status: 'loading...');
refreshController = EasyRefreshController();

View File

@ -8,7 +8,7 @@ class ClassStudentState {
late RxString title = ''.obs;
late final String classId;
late final int? subject;
late final int subject;
late RxList<StudentItem> studentList = RxList();
late String page = '';
late bool isClicking = true;

View File

@ -12,7 +12,7 @@ import 'package:making_school_asignment_app/page/home_page/children/job_report/w
import 'fav_student_logic.dart';
class FavStudentPage extends StatefulWidget {
const FavStudentPage({super.key});
const FavStudentPage({Key? key}) : super(key: key);
@override
State<FavStudentPage> createState() => _FavStudentPageState();
@ -20,7 +20,9 @@ class FavStudentPage extends StatefulWidget {
class _FavStudentPageState extends State<FavStudentPage> {
final logic = Get.find<FavStudentLogic>();
final state = Get.find<FavStudentLogic>().state;
final state = Get
.find<FavStudentLogic>()
.state;
void showStudentDialog(BuildContext context, HomeworkFavs item, List groups) {
showDialog(
@ -29,13 +31,16 @@ class _FavStudentPageState extends State<FavStudentPage> {
return AlertDialog(
insetPadding: EdgeInsets.all(25.r),
content: FavoriteStudentDialog(
item: item, group: groups, deleteFav: logic.getDelete, confirmDialog: confirmDialog),
item: item,
group: groups,
deleteFav: logic.getDelete,
confirmDialog: confirmDialog),
contentPadding: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15.r))));
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15.r))));
},
);
}
Future<bool> confirmDialog() async {
return await showDialog(
context: context,
@ -57,9 +62,9 @@ class _FavStudentPageState extends State<FavStudentPage> {
),
child: const Center(
child: Text(
'确定',
style: TextStyle(color: Colors.white),
))),
'确定',
style: TextStyle(color: Colors.white),
))),
onTap: () {
//
// Navigator.of(context).pop(true);
@ -80,245 +85,300 @@ class _FavStudentPageState extends State<FavStudentPage> {
),
child: const Center(
child: Text(
'取消',
style: TextStyle(color: Color(0xFF666666)),
))),
'取消',
style: TextStyle(color: Color(0xFF666666)),
))),
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color.fromRGBO(245, 245, 245, 1),
appBar: AppBar(
// titleSpacing: 0,
elevation: 0.0,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: () {
Get.back();
}),
iconTheme: const IconThemeData(color: Colors.black),
title: quickText('收藏夹'),
centerTitle: true,
backgroundColor: Colors.white,
actions: const [
ReturnToHomepage(),
],
),
body: OrientationBuilder(builder: (BuildContext context, Orientation orientation) {
return Column(
children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 0.r, horizontal: 14.r),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Obx(() {
return Text(
state.homeworkName.value,
style: TextStyle(
fontSize: 14.sp,
color: const Color(0xFF3C3C3C),
),
overflow: TextOverflow.ellipsis,
);
backgroundColor: const Color.fromRGBO(245, 245, 245, 1),
appBar: AppBar(
// titleSpacing: 0,
elevation: 0.0,
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: () {
Get.back();
}),
iconTheme: const IconThemeData(color: Colors.black),
title: quickText('收藏夹'),
centerTitle: true,
backgroundColor: Colors.white,
actions: const [
ReturnToHomepage(),
],
),
body:OrientationBuilder(
builder: (BuildContext context, Orientation orientation){
return Column(
children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 0.r, horizontal: 14.r),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Obx(() {
return Text(
state.homeworkName.value,
style:
TextStyle(fontSize: 14.sp, color: const Color(0xFF3C3C3C),),
overflow: TextOverflow.ellipsis,
);
}),
),
//
Container(
padding: EdgeInsets.symmetric(
vertical: 10.h, horizontal: 10.w),
child: Row(
children: [
Obx(() {
return DropdownSelection(
bgColor: Colors.white,
involveClasses: state.involveClasses.value,
classData: state.classData.value,
call: (AnnotatedClass item) {
state.classData.value = item;
if (item.grade == -1) state.classData.value = state.defaultClass;
logic.getList();
});
}),
),
//
Container(
padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 10.w),
child: Row(
children: [
Obx(() {
return DropdownSelection(
bgColor: Colors.white,
involveClasses: state.involveClasses.value,
classData: state.classData.value,
onClassSelected: (AnnotatedClass item) {
state.classData.value = item;
if (item.grade == -1) state.classData.value = state.defaultClass;
logic.getList();
});
}),
],
),
),
],
],
),
),
),
Container(
width: MediaQuery.of(context).size.width,
height: 1.r,
decoration: const BoxDecoration(
color: Color(0xFFEEEEEE),
),
),
Obx(() {
return state.favList.isNotEmpty
? Expanded(
child: Utils.isPad()
? Padding(
padding: EdgeInsets.only(top: 10.r, bottom: 8.r, left: 14.r, right: 14.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(state.favList.length, (index) {
var item = state.favList[index];
return Padding(
padding: EdgeInsets.only(bottom: 8.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(bottom: 5.r),
child: Text(
'${item['questionPage']}',
style:
TextStyle(fontSize: 12.sp, color: Theme.of(context).primaryColor),
),
),
GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 8.r,
crossAxisSpacing: 10.r,
childAspectRatio: 556 / 112,
),
shrinkWrap: true,
children: List.generate(item['list'].length, (i) {
HomeworkFavs student = item['list'][i];
return Container(
padding: EdgeInsets.symmetric(vertical: 5.r, horizontal: 10.r),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(6.r)),
),
child: InkWell(
onTap: () {
showStudentDialog(context, student, state.favList);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
quickText(student.studentName,
color: const Color(0xFF333333), size: 12.sp),
Expanded(child: Container()),
Padding(
padding: EdgeInsets.only(right: 8.r),
child: Text(
student.className!,
style: TextStyle(
fontSize: 12.sp, color: const Color(0xFF666666)),
),
),
InkWell(
onTap: () async {
var confim = await confirmDialog();
if (confim) {
logic.getDelete(student);
}
},
child: Image.asset(
'assets/images/favorite_delete_icon.png',
width: 24.r,
height: 24.r,
),
),
],
),
),
);
})),
],
),
);
})),
)
: ListView.builder(
],
),
),
Container(
width: MediaQuery
.of(context)
.size
.width,
height: 1.r,
decoration: const BoxDecoration(
color: Color(0xFFEEEEEE),
),
),
Obx((){
return state.favList.isNotEmpty
? Expanded(
child: Utils.isPad()
? Padding(
padding: EdgeInsets.only(
top: 10.r,
bottom: 8.r,
left: 14.r,
right: 14.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children:
List.generate(state.favList.length, (index) {
var item = state.favList[index];
return Padding(
padding: EdgeInsets.only(bottom: 8.r),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Padding(
padding:
EdgeInsets.only(bottom: 5.r),
child: Text(
'${item['questionPage']}',
style: TextStyle(
fontSize: 12.sp,
color:Theme.of(context).primaryColor),
),
),
GridView(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 8.r,
crossAxisSpacing: 10.r,
childAspectRatio: 556 / 112,
),
shrinkWrap: true,
itemBuilder: (context, index) {
var item = state.favList[index];
return Padding(
padding: EdgeInsets.only(top: 10.r, bottom: 8.r, left: 14.r, right: 14.r),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(bottom: 5.r),
child: Text(
'${item['questionPage']}',
style: TextStyle(fontSize: 14.sp, color: Theme.of(context).primaryColor),
children: List.generate(
item['list'].length, (i) {
HomeworkFavs student = item['list'][i];
return Container(
padding: EdgeInsets.symmetric(
vertical: 5.r,
horizontal: 10.r),
decoration: BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.all(
Radius.circular(
6.r)),
),
child: InkWell(
onTap: () {
showStudentDialog(context,
student, state.favList);
},
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
quickText(
student.studentName,
color: const Color(
0xFF333333),
size: 12.sp),
Expanded(
child: Container()),
Padding(
padding:
EdgeInsets.only(
right: 8.r),
child: Text(
student.className!,
style: TextStyle(
fontSize: 12.sp,
color: const Color(
0xFF666666)),
),
),
),
ListView.builder(
itemBuilder: (context, i) {
HomeworkFavs student = item['list'][i];
return InkWell(
onTap: () {
showStudentDialog(context, student, state.favList);
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 5.r, horizontal: 10.r),
margin: EdgeInsets.only(top: 5.r),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(6.r)),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
quickText(student.studentName,
color: const Color(0xFF333333), size: 14.sp),
Expanded(child: Container()),
Padding(
padding: EdgeInsets.only(right: 8.r),
child: Text(
student.className!,
style:
TextStyle(fontSize: 14.sp, color: const Color(0xFF666666)),
),
),
InkWell(
onTap: () async {
var confim = await confirmDialog();
if (confim) {
logic.getDelete(student);
}
},
child: Image.asset(
'assets/images/favorite_delete_icon.png',
width: 32.r,
height: 32.r,
),
),
],
),
),
);
},
itemCount: item['list'].length,
shrinkWrap: true,
),
],
InkWell(
onTap: () async {
var confim =
await confirmDialog();
if (confim) {
logic.getDelete(
student);
}
},
child: Image.asset(
'assets/images/favorite_delete_icon.png',
width: 24.r,
height: 24.r,
),
),
],
),
),
);
},
itemCount: state.favList.length,
),
)
: Padding(
padding: EdgeInsets.only(top: MediaQuery.of(context).size.height / 2 - 200.r),
child: const MyEmptyWidget(),
})),
],
),
);
}),
],
);
}));
})),
)
: ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) {
var item = state.favList[index];
return Padding(
padding: EdgeInsets.only(
top: 10.r,
bottom: 8.r,
left: 14.r,
right: 14.r),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(bottom: 5.r),
child: Text(
'${item['questionPage']}',
style: TextStyle(
fontSize: 14.sp,
color:Theme.of(context).primaryColor),
),
),
ListView.builder(
itemBuilder: (context, i) {
HomeworkFavs student = item['list'][i];
return InkWell(
onTap: () {
showStudentDialog(
context, student, state.favList);
},
child: Container(
padding: EdgeInsets.symmetric(
vertical: 5.r,
horizontal: 10.r),
margin: EdgeInsets.only(top: 5.r),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(6.r)),
),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
quickText(student.studentName,
color: const Color(0xFF333333),
size: 14.sp),
Expanded(child: Container()),
Padding(
padding: EdgeInsets.only(
right: 8.r),
child: Text(
student.className!,
style: TextStyle(
fontSize: 14.sp,
color: const Color(
0xFF666666)),
),
),
InkWell(
onTap: () async {
var confim =
await confirmDialog();
if (confim) {
logic.getDelete(student);
}
},
child: Image.asset(
'assets/images/favorite_delete_icon.png',
width: 32.r,
height: 32.r,
),
),
],
),
),
);
},
itemCount: item['list'].length,
shrinkWrap: true,
),
],
),
);
},
itemCount: state.favList.length,
),
)
: Padding(
padding: EdgeInsets.only(
top: MediaQuery
.of(context)
.size
.height / 2 - 200.r),
child: const MyEmptyWidget(),
);
}),
],
);
}
)
);
}
@override
@ -327,4 +387,4 @@ class _FavStudentPageState extends State<FavStudentPage> {
super.dispose();
logic.controller.getList();
}
}
}

View File

@ -1,5 +1,5 @@
import 'dart:async';
import 'dart:ffi';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
@ -7,6 +7,7 @@ import 'package:making_school_asignment_app/common/job/marking_models/do_paper_b
import 'package:making_school_asignment_app/common/mixins/event_bus_mixin.dart';
import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import '../configuration_files/index.dart';
@ -18,8 +19,7 @@ class BottomAnnotationSwitch extends StatefulWidget {
State<BottomAnnotationSwitch> createState() => _BottomAnnotationSwitchJobState();
}
class _BottomAnnotationSwitchJobState extends State<BottomAnnotationSwitch>
with SingleTickerProviderStateMixin, EventBusMixin<BottomOperationBar> {
class _BottomAnnotationSwitchJobState extends State<BottomAnnotationSwitch> with SingleTickerProviderStateMixin, EventBusMixin<BottomOperationBar> {
late AnimationController _animationController; //
final _homeworkLogic = Get.find<HomeworkReviewLogic>();
final _logicControl = Get.find<HomeworkReviewLogic>().annotationState;
@ -61,275 +61,179 @@ class _BottomAnnotationSwitchJobState extends State<BottomAnnotationSwitch>
@override
Widget build(BuildContext context) {
return SafeArea(
left: false,
right: false,
top: false,
child: Container(
width: double.infinity,
height: _animationController.value * 70.h,
decoration: BoxDecoration(
color: const Color.fromRGBO(83, 83, 83, 1),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
offset: const Offset(0, -2),
),
],
),
child: Row(
children: [
Expanded(
flex: 7,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
children: [
//
Expanded(
child: _buildActionButton(
'全对',
Icons.check_circle_outline,
() => easyThrottle('homework_bottom_operation_bar_scoring_related',
() => _homeworkLogic.allPairs(context)),
isEnabled: !_homeworkLogic.state.submitLoading.value,
isPrimary: true,
),
double iconSize = 18.sp;
Color actionColor = Colors.white;
Color defaultColor = const Color.fromRGBO(132, 146, 163, 1);
return Container(
width: double.infinity,
height: _animationController.value * 64.h,
color: const Color.fromRGBO(83, 83, 83, 1),
// padding: EdgeInsets.symmetric(vertical: 1.h),
child: Row(
children: [
Expanded(
flex: 7,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
children: [
//
Expanded(
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: TextButton(
child: quickText('全 对', color: Colors.white, size: 12.sp),
onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.allPairs(context)),
),
Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)),
//
Expanded(
child: Obx(() => _buildIconButton(
const IconData(0xe635, fontFamily: "AlibabaIcon"),
() => easyThrottle('homework_bottom_action_bar_annotations', () {
//
_logicControl.gestureMove.value = false;
_logicControl.pen.value = true;
}),
isActive: _logicControl.pen.value,
tooltip: '注解笔',
)),
),
),
Container(width: 0.3.w, height: double.infinity, color: Colors.white),
//
Expanded(
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: IconButton(
icon: Obx(() {
return Icon(
const IconData(0xe635, fontFamily: "AlibabaIcon"),
size: iconSize,
color: _logicControl.pen.value ? Theme.of(context).primaryColor : defaultColor,
);
}),
onPressed: () => easyThrottle('homework_bottom_action_bar_annotations', () {
_logicControl.gestureMove.value = false;
_logicControl.pen.value = !_logicControl.pen.value;
}),
),
Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)),
//
Expanded(
child: Obx(() => _buildIconButton(
),
),
Container(width: 0.3.w, height: double.infinity, color: Colors.white),
//
Expanded(
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: IconButton(
icon: Obx(
() {
return Icon(
const IconData(0xe636, fontFamily: "AlibabaIcon"),
() => easyThrottle('homework_bottom_action_bar_annotations', () {
//
_logicControl.pen.value = false;
_logicControl.gestureMove.value = true;
}),
isActive: _logicControl.gestureMove.value,
tooltip: '滑动试题',
)),
size: iconSize,
color: _logicControl.gestureMove.value ? actionColor : defaultColor,
);
},
),
onPressed: () => easyThrottle('homework_bottom_action_bar_annotations', () {
_logicControl.pen.value = false;
_logicControl.gestureMove.value = !_logicControl.gestureMove.value;
}),
),
],
),
),
],
),
),
Container(width: double.infinity, color: Colors.white, height: 0.35.h),
Expanded(
child: Row(
children: [
//
Expanded(
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: TextButton(
onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.allWrongRating(context)),
child: quickText('全 错', color: Colors.white, size: 12.sp),
),
),
),
Container(width: 0.3.w, height: double.infinity, color: Colors.white),
//
Expanded(
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: IconButton(
onPressed: () => easyThrottle(
'homework_bottom_action_bar_annotations',
() => eventFire(model: BottomOperationBar(revokeAll: false, revokePreStep: true)),
),
icon: Icon(const IconData(0xe638, fontFamily: "AlibabaIcon"), size: iconSize, color: defaultColor),
),
),
),
Container(width: 0.3.w, height: double.infinity, color: Colors.white),
//
Expanded(
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: IconButton(
icon: Icon(const IconData(0xe637, fontFamily: "AlibabaIcon"), size: iconSize, color: defaultColor),
onPressed: () => easyThrottle(
'homework_bottom_action_bar_annotations',
() => eventFire(model: BottomOperationBar(revokeAll: true, revokePreStep: false)),
),
),
),
),
],
),
),
],
),
),
Container(width: 0.3.w, height: double.infinity, color: Colors.white),
Expanded(
flex: 3,
child: Row(
children: [
Expanded(
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: TextButton(
onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.cancelAllRatings()),
child: quickText('取 消', size: 14.sp, color: Colors.white),
),
Container(width: double.infinity, color: Colors.white.withOpacity(0.3), height: 0.5.h),
Expanded(
),
),
Container(width: 0.3.w, height: double.infinity, color: Colors.white),
Expanded(
child: SizedBox(
width: double.infinity,
height: double.infinity,
child: TextButton(
onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.submit(context)),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
//
Expanded(
child: _buildActionButton(
'全错',
Icons.cancel_outlined,
() => easyThrottle('homework_bottom_operation_bar_scoring_related',
() => _homeworkLogic.allWrongRating(context)),
isEnabled: !_homeworkLogic.state.submitLoading.value,
isPrimary: false,
),
),
Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)),
//
Expanded(
child: _buildIconButton(
const IconData(0xe638, fontFamily: "AlibabaIcon"),
() => easyThrottle(
'homework_bottom_action_bar_annotations',
() => eventFire(model: BottomOperationBar(revokeAll: false, revokePreStep: true)),
),
tooltip: '撤销上一步',
),
),
Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)),
//
Expanded(
child: _buildIconButton(
const IconData(0xe637, fontFamily: "AlibabaIcon"),
() => easyThrottle(
'homework_bottom_action_bar_annotations',
() => eventFire(model: BottomOperationBar(revokeAll: true, revokePreStep: false)),
),
tooltip: '全部撤销',
),
),
Obx(() {
if (_homeworkLogic.state.submitLoading.value) {
return Padding(
padding: EdgeInsets.only(right: 4.w),
child: const SizedBox(width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2)),
);
}
return const SizedBox();
}),
quickText('提 交', size: 14.sp, color: Theme.of(context).primaryColor),
],
),
),
],
),
),
Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)),
Expanded(
flex: 3,
child: Row(
children: [
Expanded(
child: _buildActionButton(
'取消',
Icons.clear,
() => easyThrottle(
'homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.cancelAllRatings()),
isEnabled: true,
isPrimary: false,
isSecondary: true,
),
),
Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)),
Expanded(
child: Obx(() {
final submitLoading = _homeworkLogic.state.submitLoading.value;
return _buildActionButton(
'提交',
Icons.send,
() => easyThrottle(
'homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.submit(context)),
isEnabled: !submitLoading,
isPrimary: true,
isLoading: submitLoading,
);
}),
),
],
),
),
],
),
));
}
Widget _buildActionButton(
String text,
IconData icon,
VoidCallback? onPressed, {
required bool isEnabled,
required bool isPrimary,
bool isSecondary = false,
bool isLoading = false,
}) {
final primaryColor = Theme.of(context).primaryColor;
const defaultColor = Color.fromRGBO(132, 146, 163, 1);
return Material(
color: Colors.transparent,
child: InkWell(
onTap: isEnabled ? onPressed : null,
child: Semantics(
label: text,
hint: isLoading ? '正在处理中' : (isEnabled ? '点击执行$text操作' : '$text按钮已禁用'),
button: true,
enabled: isEnabled && !isLoading,
child: Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(
color: isPrimary
? (isEnabled ? primaryColor : primaryColor.withOpacity(0.5))
: isSecondary
? Colors.transparent
: Colors.transparent,
borderRadius: BorderRadius.circular(4.r),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (isLoading)
SizedBox(
width: 16.w,
height: 16.w,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
isPrimary ? Colors.white : primaryColor,
),
),
)
else
Icon(
icon,
size: 16.sp,
color: isEnabled
? (isPrimary ? Colors.white : (isSecondary ? Colors.white70 : defaultColor))
: Colors.white38,
),
SizedBox(height: 2.h),
Text(
text,
style: TextStyle(
fontSize: 10.sp,
color: isEnabled
? (isPrimary ? Colors.white : (isSecondary ? Colors.white70 : Colors.white))
: Colors.white38,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
),
);
}
Widget _buildIconButton(
IconData icon,
VoidCallback? onPressed, {
bool isActive = false,
String? tooltip,
}) {
final primaryColor = Theme.of(context).primaryColor;
const defaultColor = Color.fromRGBO(132, 146, 163, 1);
return Material(
color: Colors.transparent,
child: InkWell(
onTap: onPressed,
child: Tooltip(
message: tooltip ?? '',
child: Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(
color: isActive ? primaryColor.withOpacity(0.2) : Colors.transparent,
borderRadius: BorderRadius.circular(4.r),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
icon,
size: 18.sp,
color: isActive ? primaryColor : defaultColor,
),
SizedBox(height: 2.h),
Container(
width: 4.w,
height: 4.w,
decoration: BoxDecoration(
color: isActive ? primaryColor : Colors.transparent,
shape: BoxShape.circle,
),
),
],
),
),
),
],
),
);
}

View File

@ -4,9 +4,9 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart';
import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_result.dart';
import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/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/configuration_files/index.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
@ -61,8 +61,7 @@ class DropdownSwitchStudentsType extends StatelessWidget {
items: sateData.value?.templateIdKeys?.map((e) {
return DropdownMenuItem(
value: e,
child: quickText('${sateData.value!.templateIdKeyMap![e]}',
color: const Color.fromRGBO(79, 79, 79, 1), size: 14.sp),
child: quickText('${sateData.value!.templateIdKeyMap![e]}', color: const Color.fromRGBO(79, 79, 79, 1), size: 14.sp),
);
}).toList(),
onChanged: (value) {
@ -78,14 +77,7 @@ class DropdownSwitchStudentsType extends StatelessWidget {
final students = sateData.value?.students ?? [];
//
PaperStudents? currentStudent;
if (currentStudentId != null) {
try {
currentStudent = students.firstWhere((e) => e.id == currentStudentId);
} catch (e) {
currentStudent = null;
}
}
final currentStudent = currentStudentId != null ? students.firstWhereOrNull((e) => e.id == currentStudentId) : null;
final studentName = currentStudent?.name ?? '当前学生';
final questionNumber = templateIdKeyMap?[value] ?? '当前选择页';
@ -103,7 +95,7 @@ class DropdownSwitchStudentsType extends StatelessWidget {
}),
),
),
SizedBox(width: 8.w),
const Expanded(flex: 1, child: SizedBox()),
Expanded(
flex: 3,
child: Stack(
@ -128,9 +120,7 @@ class DropdownSwitchStudentsType extends StatelessWidget {
alignment: const FractionalOffset(0, 0.62),
children: [
Container(
padding: sateData.value?.studentId != e.id && e.isPriority
? EdgeInsets.only(left: 14.w)
: null,
padding: sateData.value?.studentId != e.id && e.isPriority ? EdgeInsets.only(left: 14.w) : null,
child: quickText(
e.name,
size: 14.sp,
@ -144,9 +134,7 @@ class DropdownSwitchStudentsType extends StatelessWidget {
Icon(
const IconData(0xe63d, fontFamily: "AlibabaIcon"),
size: 12.sp,
color: e.isPriority
? Theme.of(context).primaryColor
: const Color.fromRGBO(164, 164, 164, 1),
color: e.isPriority ? Theme.of(context).primaryColor : const Color.fromRGBO(164, 164, 164, 1),
),
quickText('优先', size: 4.sp, color: Colors.white),
],
@ -173,9 +161,7 @@ class DropdownSwitchStudentsType extends StatelessWidget {
return Icon(
const IconData(0xe63d, fontFamily: "AlibabaIcon"),
size: 12.sp,
color: sateData.value?.priority ?? false
? Theme.of(context).primaryColor
: const Color.fromRGBO(164, 164, 164, 1),
color: sateData.value?.priority ?? false ? Theme.of(context).primaryColor : const Color.fromRGBO(164, 164, 164, 1),
);
}),
quickText('优先', size: 4.sp, color: Colors.white),
@ -187,9 +173,9 @@ class DropdownSwitchStudentsType extends StatelessWidget {
),
// const Expanded(flex: 1, child: SizedBox()),
SizedBox(width: 8.w),
const Expanded(
flex: 5,
child: Row(
Expanded(
flex: isPad() ? 4 : 5,
child: const Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
@ -222,8 +208,7 @@ Widget $studentHandwriting(BuildContext context) {
if (templateIdKeyMap != null && templateId != null) {
pageNum = templateIdKeyMap[templateId];
}
await showAnswerHandwriting(context,
homeworkId: homeworkId, studentId: studentId, templateId: templateId, pageNum: pageNum);
await showAnswerHandwriting(context, homeworkId: homeworkId, studentId: studentId, templateId: templateId, pageNum: pageNum);
ToastUtils.dismiss();
},
),
@ -253,10 +238,7 @@ Widget $continueToReview(BuildContext context, {bool isFloatingAction = false})
int? annotatedCount = data?.annotatedCount; //
// || (submitCount == annotatedCount || (param.templateId == null && param.studentId == null))
// if (data == null || (data.needAnnotate ? true : data.totalUnAnnotateCount <= 0) ) return const SizedBox();
if (data == null ||
(data.needAnnotate
? (data.continuePage == null ? true : data.continuePage!.templateId == data.templateId)
: data.totalUnAnnotateCount <= 0)) return const SizedBox();
if (data == null || (data.needAnnotate ? (data.continuePage == null ? true : data.continuePage!.templateId == data.templateId) : data.totalUnAnnotateCount <= 0)) return const SizedBox();
callFun() => easyThrottle(
'DO_PAPERS_JOB_CONTINUE_TO_REVIEW',
() {
@ -307,18 +289,10 @@ Widget $historyHomework(BuildContext context) {
int? studentId = sateData.value?.studentId;
if (kDebugMode) print(studentId);
if (studentId == null || (sateData.value?.students.isEmpty ?? true)) return;
PaperStudents? currentStudent;
try {
currentStudent = sateData.value!.students.firstWhere((e) => e.id == studentId);
} catch (e) {
return;
}
var currentStudent = sateData.value!.students.firstWhereOrNull((e) => e.id == studentId);
if (currentStudent == null) return;
var theState = Get.find<HomeworkReviewLogic>().state;
Get.toNamed(Routes.studentWorkDetailPage, arguments: {
'studentId': studentId,
'studentName': currentStudent.name,
'subject': theState.param.value.subject
});
Get.toNamed(Routes.studentWorkDetailPage, arguments: {'studentId': studentId, 'studentName': currentStudent.name, 'subject': theState.param.value.subject});
}),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,

View File

@ -1,6 +1,6 @@
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart';
@ -19,8 +19,7 @@ class FavoriteWidget extends StatelessWidget {
return Container(
padding: EdgeInsets.symmetric(horizontal: 4.r),
child: InkWell(
onTap: () => easyThrottle('homework_review_collect_btn', () => logic.toFavorite(),
duration: const Duration(milliseconds: 500)),
onTap: () => easyThrottle('homework_review_collect_btn', () => logic.toFavorite(), duration: const Duration(milliseconds: 500)),
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
child: Row(
@ -29,10 +28,8 @@ class FavoriteWidget extends StatelessWidget {
Obx(() {
return Icon(
const IconData(0xe63c, fontFamily: "AlibabaIcon"),
size: 24.r,
color: sateData.favorite.value
? const Color.fromRGBO(255, 172, 48, 1)
: const Color.fromRGBO(164, 164, 164, 1),
size: 18.sp,
color: sateData.favorite.value ? const Color.fromRGBO(255, 172, 48, 1) : const Color.fromRGBO(164, 164, 164, 1),
);
}),
SizedBox(width: 6.w),

View File

@ -3,14 +3,13 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
import 'package:get/get.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_result.dart';
import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:percent_indicator/linear_percent_indicator.dart';
import 'package:vector_math/vector_math_64.dart' as vm64;
import '../configuration_files/index.dart';
import '../configuration_files/zoom_logic.dart';
@ -38,11 +37,7 @@ class QuestionNumberView extends GetView<HomeworkReviewLogic> {
if (zoomFile == null || studentQuestions.isEmpty) return const SizedBox();
return $QuestionNumberScrollView(
controller: controller,
sateData: sateData,
sateZoomData: sateZoomData,
studentQuestions: studentQuestions);
return $QuestionNumberScrollView(controller: controller, sateData: sateData, sateZoomData: sateZoomData, studentQuestions: studentQuestions);
}),
),
);
@ -68,10 +63,11 @@ Widget $questionNumberScrollView({
// var studentQuestionsStream = sateData.studentQuestions.listen((e) {
// studentQuestions.value = e ?? [];
// });
var sateDataDataStream = sateData.data.listen((e) {
var sateDataDataStream = sateData.data.listen((e){
scrollControllerNum.jumpTo(0);
});
var stream = sateZoomData.initScale.listen((e) {
// print("initScale : $e");
useZoom.value = e ?? 1;
@ -105,18 +101,6 @@ Widget $questionNumberScrollView({
scrollControllerNum.addListener(() {
///
// if (sateData.panQuestView == false) sateData.slide.value = scrollControllerNum.offset;
final currentMatrix = controller.zoomController.value;
//
final newMatrix = Matrix4.copy(currentMatrix)
..setTranslation(vm64.Vector3(
currentMatrix.getTranslation().x, //
-scrollControllerNum.offset, //
currentMatrix.getTranslation().z, // Z
));
controller.zoomController.value = newMatrix;
});
var listenVal = sateData.slide.listen((e) {
if (sateData.panQuestView != null && sateData.panQuestView == true && e != scrollControllerNum.offset) {
@ -132,7 +116,9 @@ Widget $questionNumberScrollView({
// var actualImgHeight = useImageInfo.value?.actualImgHeight ?? 0; //
print("图片高度:${usePiddingTop.value}");
// print("图片高度:$actualImgHeight");
print("FFFFFFFFF ${usePiddingTop.value}");
return SingleChildScrollView(
controller: scrollControllerNum,
@ -147,11 +133,11 @@ Widget $questionNumberScrollView({
children: studentQuestions
.map((e) => $ScoringQuestionsView(
key: Key('${sateData.data.value?.templateId}_${sateData.data.value?.studentId}_${e.questionNo}'),
sateData: sateData,
item: e,
logic: controller,
scaleRatio: sateZoomData.zoomFile.value!.scaleRatio,
initScale: useZoom.value,
sateData:sateData,
item:e,
logic:controller,
scaleRatio:sateZoomData.zoomFile.value!.scaleRatio,
initScale:useZoom.value,
))
.toList(),
),
@ -184,12 +170,8 @@ Widget $scoringQuestionsView(
studentScoreListener() {
print(item.toJson());
item.studentScore = studentScore.value;
try {
var theVal = sateData.studentQuestions.value?.firstWhere((e) => e.questionNo == item.questionNo);
theVal?.studentScore = studentScore.value;
} catch (e) {
//
}
var theVal = sateData.studentQuestions.value?.firstWhereOrNull((e) => e.questionNo == item.questionNo);
if (theVal != null) theVal.studentScore = studentScore.value;
var studentQuestions = sateData.studentQuestions.value;
if (item.studentScore == null) return;
@ -197,25 +179,17 @@ Widget $scoringQuestionsView(
//
var annotateTime = logic.state.data.value?.annotateTime;
if (annotateTime == null) {
try {
studentQuestions!.firstWhere((e) => e.useTime != 0 && e.studentScore == null);
} catch (e) {
//
logic.submit(context);
}
var noRatingGiven = studentQuestions!.firstWhereOrNull((e) => e.useTime != 0 && e.studentScore == null);
if (noRatingGiven == null) logic.submit(context);
}
}
studentScore.addListener(studentScoreListener);
var studentQuestionsStream = sateData.studentQuestions.listen((e) {
try {
var itemVal = (e ?? []).firstWhere((e1) => e1.questionNo == item.questionNo);
if (studentScore.value != itemVal.studentScore) {
studentScore.value = itemVal.studentScore;
}
} catch (e) {
//
var itemVal = (e ?? []).firstWhereOrNull((e1) => e1.questionNo == item.questionNo);
if (itemVal != null && studentScore.value != itemVal.studentScore) {
studentScore.value = itemVal.studentScore;
}
});

View File

@ -2,10 +2,10 @@ import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'package:flutter/cupertino.dart' hide TransformationController;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/marking_models/do_paper_bus.dart';
@ -30,7 +30,8 @@ class QuestionPaperView extends GetView<HomeworkReviewLogic> {
HomeworkReviewState get sateData => controller.state;
ZoomState get zoomState => controller.zoomLogic.zoomState;
HomeworkReviewAnnotationsControlState get annotationState => controller.annotationState;
HomeworkReviewAnnotationsControlState get annotationState =>
controller.annotationState;
@override
Widget build(BuildContext context) {
@ -46,11 +47,13 @@ class QuestionPaperView extends GetView<HomeworkReviewLogic> {
if (zoomFileModel == null) {
///
return LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) {
WidgetsBinding.instance.addPostFrameCallback((_) => zoomState.zoomFile.value = ZoomFileModel(
viewWidth: constraints.maxWidth,
viewHeight: constraints.maxHeight,
));
return LayoutBuilder(builder:
(BuildContext context, BoxConstraints constraints) {
WidgetsBinding.instance.addPostFrameCallback(
(_) => zoomState.zoomFile.value = ZoomFileModel(
viewWidth: constraints.maxWidth,
viewHeight: constraints.maxHeight,
));
return const SizedBox();
});
}
@ -64,14 +67,10 @@ class QuestionPaperView extends GetView<HomeworkReviewLogic> {
children: [
//
QuestionImageView(
maxWidth,
maxHeight,
annotationState,
controller,
zoomState: zoomState,
sateData: sateData,
actualHeight: zoomFileModel.actualHeight!,
),
maxWidth, maxHeight, annotationState, controller,
zoomState: zoomState,
sateData: sateData,
actualHeight: zoomFileModel.actualHeight!),
//
// Positioned(right: 3.w, bottom: 4.h, child: const $ContinueToReview(isFloatingAction: true)),
//
@ -85,15 +84,19 @@ class QuestionPaperView extends GetView<HomeworkReviewLogic> {
heroTag: '点击前往上一题',
tooltip: '点击前往上一题',
focusColor: Theme.of(context).primaryColor,
backgroundColor: const Color.fromRGBO(24, 32, 32, 0.05),
backgroundColor:
const Color.fromRGBO(24, 32, 32, 0.05),
elevation: 10.r,
onPressed: () => easyThrottle('TestQuestionSwitch', () {
onPressed: () =>
easyThrottle('TestQuestionSwitch', () {
var param = sateData.param.value;
param.studentId = lastPageVal.studentId;
param.templateId = lastPageVal.templateId;
sateData.param.value = DoPaperDetailsParam.fromJson(param.toJson());
sateData.param.value =
DoPaperDetailsParam.fromJson(param.toJson());
}),
child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp),
child: Icon(Icons.arrow_back_ios,
color: Colors.white, size: 22.sp),
);
}),
),
@ -109,14 +112,18 @@ class QuestionPaperView extends GetView<HomeworkReviewLogic> {
heroTag: '点击前往下一题',
tooltip: '点击前往下一题',
elevation: 10.r,
backgroundColor: const Color.fromRGBO(24, 32, 32, 0.05),
onPressed: () => easyThrottle('TestQuestionSwitch', () {
backgroundColor:
const Color.fromRGBO(24, 32, 32, 0.05),
onPressed: () =>
easyThrottle('TestQuestionSwitch', () {
var param = sateData.param.value;
param.studentId = nextPageVal.studentId;
param.templateId = nextPageVal.templateId;
sateData.param.value = DoPaperDetailsParam.fromJson(param.toJson());
sateData.param.value =
DoPaperDetailsParam.fromJson(param.toJson());
}),
child: Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp),
child: Icon(Icons.arrow_forward_ios,
color: Colors.white, size: 22.sp),
);
}),
),
@ -153,7 +160,8 @@ class DataErrorThenRequestAgainButton extends StatelessWidget {
child: CupertinoButton(
color: Colors.grey[300],
onPressed: () => easyThrottle('home_work_reload_data', () {
sateData.param.value = DoPaperDetailsParam.fromJson(sateData.param.value.toJson());
sateData.param.value =
DoPaperDetailsParam.fromJson(sateData.param.value.toJson());
}),
child: quickText('再次请求', color: Colors.black38),
),
@ -164,7 +172,8 @@ class DataErrorThenRequestAgainButton extends StatelessWidget {
//
@swidget
Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData) {
Widget $totalSubmitCountView(
BuildContext context, HomeworkReviewState sateData) {
return Obx(() {
var data = sateData.data.value;
if (data == null) return Container();
@ -180,7 +189,9 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
elevation: 10,
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(topLeft: Radius.circular(10.r), topRight: Radius.circular(10.r))),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.r),
topRight: Radius.circular(10.r))),
builder: (BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 2.w),
@ -198,7 +209,8 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
SizedBox(height: 10.h),
Expanded(
child: ListView(
padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 4.w),
padding: EdgeInsets.symmetric(
vertical: 8.h, horizontal: 4.w),
children: [
Wrap(
spacing: 7.2.w, // ()
@ -209,29 +221,39 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
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),
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),
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),
color:
const Color.fromRGBO(80, 94, 110, 1),
),
),
Stack(
alignment: const FractionalOffset(0.52, 0.24),
alignment:
const FractionalOffset(0.52, 0.24),
children: [
Icon(
const IconData(0xe63d, fontFamily: "AlibabaIcon"),
const IconData(0xe63d,
fontFamily: "AlibabaIcon"),
size: 12.sp,
color: e.isPriority
? Theme.of(context).primaryColor
: const Color.fromRGBO(164, 164, 164, 1),
: const Color.fromRGBO(
164, 164, 164, 1),
),
quickText('优先', size: 4.sp, color: Colors.white),
quickText('优先',
size: 4.sp, color: Colors.white),
],
),
],
@ -253,11 +275,15 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
children: [
Padding(
padding: EdgeInsets.only(bottom: 1.h),
child: quickText('已阅', color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp),
child: quickText('已阅',
color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp),
),
quickText(data.annotatedCount,
color: Theme.of(context).primaryColor, size: 12.sp, fontWeight: FontWeight.bold),
quickText('/', color: const Color.fromRGBO(117, 117, 117, 1), size: 12.sp),
color: Theme.of(context).primaryColor,
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),
],
@ -268,7 +294,8 @@ Widget $totalSubmitCountView(BuildContext context, HomeworkReviewState sateData)
}
//
class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar> {
class QuestionImageView extends HookWidget
with EventBusMixin<BottomOperationBar> {
final double maxWidth;
final double maxHeight;
final double actualHeight;
@ -277,15 +304,11 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
final HomeworkReviewState sateData;
final HomeworkReviewAnnotationsControlState annotationState;
QuestionImageView(
this.maxWidth,
this.maxHeight,
this.annotationState,
this.logic, {
required this.actualHeight,
required this.zoomState,
required this.sateData,
super.key,
});
this.maxWidth, this.maxHeight, this.annotationState, this.logic,
{required this.actualHeight,
required this.zoomState,
required this.sateData,
super.key});
///
int _findTargetIndex<T>(List<T> list, T target, [int reciprocal = 2]) {
@ -311,7 +334,7 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
timer = Timer(const Duration(milliseconds: timeoutDuration), () {
if (_activePointers > 2) {
_activePointers = 0;
if (vnHandWritings.value.isNotEmpty && vnHandWritings.value.last != null) {
if (vnHandWritings.value.last != null) {
vnHandWritings.value.add(null); // 线
sateData.handwritings = vnHandWritings.value; //
}
@ -339,10 +362,12 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
@override
Widget build(BuildContext context) {
final theMaxHeight = useState<double>(maxHeight);
useValueChanged<double, void>(maxHeight, (oldValue, __) => theMaxHeight.value = maxHeight);
useValueChanged<double, void>(
maxHeight, (oldValue, __) => theMaxHeight.value = maxHeight);
var zoomKey = useState<GlobalKey>(GlobalKey());
useValueChanged<int?, void>(zoomState.zoomFile.value?.templateId, (old, __) {
useValueChanged<int?, void>(zoomState.zoomFile.value?.templateId,
(old, __) {
zoomKey.value = GlobalKey();
});
@ -363,9 +388,11 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
var streamSubscriptionSlide = sateData.slide.listen((e) {
if (sateData.panQuestView != null &&
sateData.panQuestView == false &&
initPosition.value?.dy.abs().toInt().toDouble() != sateData.slide.value) {
initPosition.value?.dy.abs().toInt().toDouble() !=
sateData.slide.value) {
if (sateData.zoomOffset != null) {
sateData.zoomOffset = Offset(sateData.zoomOffset!.dx, -sateData.slide.value);
sateData.zoomOffset =
Offset(sateData.zoomOffset!.dx, -sateData.slide.value);
}
initPosition.value = sateData.zoomOffset;
}
@ -386,12 +413,17 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
bool? res = await showDialog<bool>(
context: Get.context ?? context,
builder: (context1) {
return AlertDialog(content: quickText("是否撤销全部批注痕迹?"), actions: <Widget>[
TextButton(child: quickText("取消"), onPressed: () => Navigator.pop(context1, false)),
TextButton(
child: quickText("确定", color: Theme.of(context1).primaryColor),
onPressed: () => Navigator.pop(context1, true))
]);
return AlertDialog(
content: quickText("是否撤销全部批注痕迹?"),
actions: <Widget>[
TextButton(
child: quickText("取消"),
onPressed: () => Navigator.pop(context1, false)),
TextButton(
child: quickText("确定",
color: Theme.of(context1).primaryColor),
onPressed: () => Navigator.pop(context1, true))
]);
},
);
if (res == true) vnHandWritings.value = [];
@ -401,35 +433,43 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
await showDialog<bool>(
context: Get.context ?? context,
builder: (context1) {
return AlertDialog(content: quickText("是否撤销上次批阅批注痕迹?"), actions: <Widget>[
TextButton(child: quickText("取消"), onPressed: () => Navigator.pop(context1, false)),
TextButton(
child: quickText("确定", color: Theme.of(context1).primaryColor),
onPressed: () => easyThrottle(
'REVOKE_THE_LAST_ANNOTATION_AND_SUBMIT',
() {
Navigator.pop(context1, true);
sateData.data.value?.zgtAnnotate = null;
sateData.data.value?.showZgtAnnotate = null;
if (sateData.data.value != null) {
sateData.data.update((_) {
var theStudentQuestions = sateData.studentQuestions.value;
if (theStudentQuestions?.isNotEmpty ?? false) {
try {
var noMarking = theStudentQuestions?.firstWhere((e) => e.studentScore == null);
ToastUtils.showInfo("未提交!请为第${noMarking?.questionNo}题打分,再手动提交");
return;
} catch (e) {
//
}
return AlertDialog(
content: quickText("是否撤销上次批阅批注痕迹?"),
actions: <Widget>[
TextButton(
child: quickText("取消"),
onPressed: () => Navigator.pop(context1, false)),
TextButton(
child: quickText("确定",
color: Theme.of(context1).primaryColor),
onPressed: () => easyThrottle(
'REVOKE_THE_LAST_ANNOTATION_AND_SUBMIT',
() {
Navigator.pop(context1, true);
sateData.data.value?.zgtAnnotate = null;
sateData.data.value?.showZgtAnnotate = null;
if (sateData.data.value != null) {
sateData.data.update((_) {
var theStudentQuestions =
sateData.studentQuestions.value;
if (theStudentQuestions?.isNotEmpty ??
false) {
var noMarking =
theStudentQuestions?.firstWhereOrNull(
(e) => e.studentScore == null);
if (noMarking != null) {
ToastUtils.showInfo(
"未提交!请为第${noMarking.questionNo}题打分,再手动提交");
return;
}
}
logic.submit(Get.context ?? context);
});
}
logic.submit(Get.context ?? context);
});
}
},
),
)
]);
},
),
)
]);
},
);
}
@ -444,23 +484,29 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
await showDialog<bool>(
context: context,
builder: (context1) {
return AlertDialog(content: quickText("是否撤销上次批阅批注痕迹?"), actions: <Widget>[
TextButton(child: quickText("取消"), onPressed: () => Navigator.pop(context1, false)),
TextButton(
child: quickText("确定", color: Theme.of(context).primaryColor),
onPressed: () => easyThrottle(
'REVOKE_THE_LAST_ANNOTATION_AND_SUBMIT',
() {
Navigator.pop(context1, true);
sateData.data.value?.zgtAnnotate = null;
sateData.data.value?.showZgtAnnotate = null;
if (sateData.data.value != null) {
sateData.data.update((_) => logic.submit(Get.context ?? context));
}
},
),
)
]);
return AlertDialog(
content: quickText("是否撤销上次批阅批注痕迹?"),
actions: <Widget>[
TextButton(
child: quickText("取消"),
onPressed: () => Navigator.pop(context1, false)),
TextButton(
child: quickText("确定",
color: Theme.of(context).primaryColor),
onPressed: () => easyThrottle(
'REVOKE_THE_LAST_ANNOTATION_AND_SUBMIT',
() {
Navigator.pop(context1, true);
sateData.data.value?.zgtAnnotate = null;
sateData.data.value?.showZgtAnnotate = null;
if (sateData.data.value != null) {
sateData.data.update(
(_) => logic.submit(Get.context ?? context));
}
},
),
)
]);
},
);
}
@ -520,15 +566,17 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
Offset localPosition = event.localPosition; //
var zoomFile = zoomState.zoomFile.value!;
// var imageHeightOffsetStart = zoomFile.imageHeightOffsetStart??0;
var imageHeightOffsetStart = zoomState.zoomFile.value!.getZoomFileOffsetStart(zoomState.initScale.value ?? 1);
var imageHeightOffsetStart = zoomState.zoomFile.value!
.getZoomFileOffsetStart(zoomState.initScale.value ?? 1);
// print("位置:$localPosition; 图片所在位置:$imageHeightOffsetStart");
if (imageHeightOffsetStart == 0) return;
var dy = localPosition.dy;
// print(zoomFile.getZoomFileHeightOffsetEnd(zoomState.initScale.value ?? 1));
if (dy < imageHeightOffsetStart || dy > zoomFile.getZoomFileHeightOffsetEnd(zoomState.initScale.value ?? 1)) {
return; //
}
if (dy < imageHeightOffsetStart ||
dy >
zoomFile.getZoomFileHeightOffsetEnd(
zoomState.initScale.value ?? 1)) return; //
var theScale = zoomState.initScale.value ?? 1;
// if (theScale != 1) {
@ -549,104 +597,101 @@ class QuestionImageView extends HookWidget with EventBusMixin<BottomOperationBar
// }
// (dy / theScale) - (max(0, imageHeightOffsetStart) / theScale) + ((sateData.zoomOffset?.dy.abs() ?? 0) / theScale),
var leftOffset = zoomFile.getZoomFileOffsetStartWidth(theScale);
var topOffset = max(0, imageHeightOffsetStart);
var zoomWtdthSpaceVal = zoomFile
.getZoomFileOffsetStartWidth(zoomState.initScale.value ?? 1);
// 使//
final translation = logic.zoomController.value.getTranslation();
final panDx = translation.x;
final panDy = translation.y;
//
final correctedDx = (localPosition.dx - leftOffset - panDx) / theScale;
final correctedDy = (dy - topOffset - panDy) / theScale;
localPosition = Offset(correctedDx, correctedDy);
localPosition = Offset(
(localPosition.dx -
zoomFile.getZoomFileOffsetStartWidth(
zoomState.initScale.value ?? 1) +
((zoomWtdthSpaceVal <= 0.1)
? (sateData.zoomOffset?.dx.abs() ?? 0)
: 0)) /
theScale,
(dy -
max(0, imageHeightOffsetStart) +
((zoomFile.imageHeightOffsetStart == null ||
zoomFile.imageHeightOffsetStart! <= 0.1)
? (sateData.zoomOffset?.dy.abs() ?? 0)
: 0)) /
theScale,
);
///
if (Platform.isAndroid) {
var lastDrop = getLastDrop(vnHandWritings.value, vnHandWritings.value.length - 1);
var lastDrop = getLastDrop(
vnHandWritings.value, vnHandWritings.value.length - 1);
if (lastDrop != null &&
((lastDrop.dx - localPosition.dx).abs() > 65 || (lastDrop.dy - localPosition.dy).abs() > 65)) {
((lastDrop.dx - localPosition.dx).abs() > 65 ||
(lastDrop.dy - localPosition.dy).abs() > 65)) {
/// X点和上一个x点相差 10
return;
}
}
// print("最终位置 $localPosition");
vnHandWritings.value = List.from(vnHandWritings.value)..add(localPosition);
vnHandWritings.value = List.from(vnHandWritings.value)
..add(localPosition);
sateData.handwritings = vnHandWritings.value;
},
child: Obx(() {
var isPen = annotationState.pen.value;
var showZgtAnnotate = sateData.data.value?.showZgtAnnotate;
print(sateData.data.value!.zgtAnswer);
return Container(
height: double.infinity,
width: double.infinity,
alignment: Alignment.center,
child: IgnorePointer(
// Zoom
ignoring: !annotationState.gestureMove.value,
child:
// ZoomView(
// key: zoomKey.value,
// viewWidth: maxWidth,
// viewHeight: maxHeight,
// imageDisplayHeight: actualHeight,
// url: sateData.data.value!.zgtAnswer,
// onScale: logic.zoomLogic.onScaleUpdate,
// // onTrans: (offset) {
// // print("偏移位置:$offset");
// // },
// onContentOffset: logic.zoomLogic.onPanUpPosition,
// ),
Obx(
() => Zoom(
key: zoomKey.value,
// initTotalZoomOut: true, //
zoomSensibility: 0.05,
scrollWeight: 4.r,
doubleTapAnimDuration: Duration.zero,
maxZoomWidth: maxWidth,
maxZoomHeight: actualHeight,
canvasColor: Colors.transparent,
doubleTapScaleChange: 1,
// initPosition: initPosition.value,
// initScale: logic.zoomLogic.zoomState.initScale.value ?? 1,
backgroundColor: Colors.transparent,
onScaleUpdate: (double scale, double zoom) => logic.zoomLogic.onScaleUpdate(zoom),
onPositionUpdate: logic.zoomLogic.onPanUpPosition,
transformationController: logic.zoomController,
child: Stack(
children: [
$TheCachedNetworkImage(
imgWidth: maxWidth,
imageUrl: sateData.data.value!.zgtAnswer,
(_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth),
),
RepaintBoundary(
key: logic.pictureOverviewKey,
child: CustomPaint(
// isComplex: true,
size: Size(maxWidth, actualHeight),
foregroundPainter: DrawingPainter(ctrl: vnHandWritings),
// child: $TheCachedNetworkImage(
// imgWidth: maxWidth,
// imageUrl: showZgtAnnotate ?? sateData.data.value!.zgtAnswer,
// (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth),
// ),
child: showZgtAnnotate != null
? $TheCachedNetworkImage(
imgWidth: maxWidth,
imageUrl: showZgtAnnotate,
(_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth))
: null,
),
),
],
ignoring: isPen,
child: Zoom(
key: zoomKey.value,
// initTotalZoomOut: true, //
zoomSensibility: 0.05,
scrollWeight: 4.r,
doubleTapAnimDuration: Duration.zero,
maxZoomWidth: maxWidth,
maxZoomHeight: actualHeight,
canvasColor: Colors.transparent,
// initPosition: initPosition.value,
// initScale: logic.zoomLogic.zoomState.initScale.value ?? 1,
backgroundColor: Colors.transparent,
onScaleUpdate: logic.zoomLogic.onScaleUpdate,
onPositionUpdate: logic.zoomLogic.onPanUpPosition,
child: Stack(
children: [
$TheCachedNetworkImage(
imgWidth: maxWidth,
imageUrl: sateData.data.value!.zgtAnswer,
(_, imageProvider) =>
Image(image: imageProvider, fit: BoxFit.fitWidth),
),
),
)),
RepaintBoundary(
key: logic.pictureOverviewKey,
child: CustomPaint(
// isComplex: true,
size: Size(
maxWidth, zoomState.zoomFile.value!.actualHeight!),
foregroundPainter: DrawingPainter(ctrl: vnHandWritings),
// child: $TheCachedNetworkImage(
// imgWidth: maxWidth,
// imageUrl: showZgtAnnotate ?? sateData.data.value!.zgtAnswer,
// (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth),
// ),
child: showZgtAnnotate != null
? $TheCachedNetworkImage(
imgWidth: maxWidth,
imageUrl: showZgtAnnotate,
(_, imageProvider) => Image(
image: imageProvider, fit: BoxFit.fitWidth))
: null,
),
),
],
),
),
),
);
}),
);
@ -669,9 +714,8 @@ class DrawingPainter extends CustomPainter {
for (int i = 0; i < pointsLength; i++) {
Offset? offsetData = points[i];
Offset? nextOffsetData = pointsLength - 1 == i ? null : points[i + 1];
if (offsetData != null && nextOffsetData != null) {
if (offsetData != null && nextOffsetData != null)
canvas.drawLine(offsetData, nextOffsetData, paintBrush);
}
}
}

View File

@ -1,108 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:making_school_asignment_app/common/utils/cached_network_img.dart';
/// [url]
/// [viewWidth]
/// [viewHeight]
/// [imageDisplayHeight]
/// [onTrans]
/// [onScale]
/// [onContentOffset]
/// [transformationController]
class ZoomView extends HookWidget {
final String url;
final double viewWidth;
final double viewHeight;
final double imageDisplayHeight;
final Function(Offset)? onTrans;
final Function(double)? onScale;
final Function(Offset)? onContentOffset;
final TransformationController? transformationController;
const ZoomView({
required this.url,
required this.viewWidth,
required this.viewHeight,
required this.imageDisplayHeight,
this.onTrans,
this.onScale,
this.onContentOffset,
this.transformationController,
super.key,
});
@override
Widget build(BuildContext context) {
final controller = transformationController ?? useTransformationController();
useEffect(() {
double? lastScale;
Offset? lastOffset;
Offset? lastContentOffset;
void notifyIfChanged() {
final matrix = controller.value;
final scale = matrix.getMaxScaleOnAxis();
final translation = matrix.getTranslation();
final offset = Offset(translation.x, translation.y);
// scale
if (onScale != null && (lastScale == null || (lastScale! - scale).abs() > 0.001)) {
onScale!(scale);
lastScale = scale;
}
// offset
if (onTrans != null && (lastOffset == null || (lastOffset! - offset).distance > 0.5)) {
onTrans!(offset);
lastOffset = offset;
}
//
if (onContentOffset != null) {
final scaledHeight = imageDisplayHeight * scale;
final dx = translation.x;
double dy = viewHeight > scaledHeight ? (viewHeight - scaledHeight) / 2.0 : 0;
dy += translation.y;
final contentOffset = Offset(dx, dy);
if (lastContentOffset == null || (lastContentOffset! - contentOffset).distance > 0.5) {
onContentOffset!(contentOffset);
lastContentOffset = contentOffset;
}
}
//
// final scaledHeight = imageDisplayHeight * scale;
// if (imageDisplayHeight < viewHeight && scaledHeight <= viewHeight) {
// final centerY = (viewHeight - scaledHeight) / 2.0;
// if ((translation.y - centerY).abs() > 0.5 || translation.x.abs() > 0.5) {
// final newMatrix = Matrix4.identity()
// ..translate(0.0, centerY)
// ..scale(scale);
// controller.value = newMatrix;
// }
// }
}
controller.addListener(notifyIfChanged);
return () {
controller.removeListener(notifyIfChanged);
};
}, [controller, imageDisplayHeight, viewHeight]);
return InteractiveViewer(
minScale: 1,
maxScale: 2.0,
panEnabled: true,
constrained: imageDisplayHeight < viewHeight,
transformationController: controller,
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Center(
child: $TheCachedNetworkImage(
imageUrl: url,
imgWidth: viewWidth,
(_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth),
),
),
);
}
}

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:ui' as ui;
import 'package:device_info_plus/device_info_plus.dart';
@ -6,8 +7,8 @@ import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:get/get_rx/get_rx.dart';
import 'package:making_school_asignment_app/common/job/annotate_list_to_refresh.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';
@ -19,8 +20,8 @@ import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dar
import 'package:making_school_asignment_app/common/utils/permission_describe_util.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/common/utils/upload_oss_img_utils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:zoom_widget/zoom_widget.dart' as zoomWidget;
import 'zoom_logic.dart';
@ -34,7 +35,7 @@ class HomeworkReviewState {
late Rx<DoPaperDetailsResult?> data = Rx<DoPaperDetailsResult?>(null);
late Rx<List<StudentQuestions>?> studentQuestions = Rx<List<StudentQuestions>?>(null);
late Rx<double> slide = 0.0.obs; //
bool? panQuestView;
bool? panQuestView = null;
// late Rx<TestQuestionsImageInfo?> imageScale;
// late Rx<TestQuestionsImageInfo?> imageScaleZoom = Rx<TestQuestionsImageInfo?>(null);
@ -79,19 +80,18 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
late StreamSubscription<DoPaperDetailsResult?> _dataListen;
final HomeworkReviewState state = HomeworkReviewState();
final HomeworkReviewAnnotationsControlState annotationState = HomeworkReviewAnnotationsControlState();
double appBarHeight = kToolbarHeight;
double appBarHeight = 56;
StreamSubscription<TestQuestionsImageInfo?>? imageScaleZoomStream;
late final zoomWidget.TransformationController zoomController;
@override
void onInit() {
appBarHeight = MediaQuery.of(Get.context!).padding.top;
print("appBarHeight $appBarHeight");
// WidgetsFlutterBinding.ensureInitialized();
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); //
zoomController = zoomWidget.TransformationController();
state.param = DoPaperDetailsParam(
homeworkId: Get.arguments['homeworkId'],
homeworkName: Get.arguments['homeworkName'],
@ -107,6 +107,8 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
if (e == null) return;
var zoomState = zoomLogic.zoomState;
final currentTemplateId = zoomState.zoomFile.value?.templateId; // ID
if (currentTemplateId != null && currentTemplateId != e.templateId) {
// zoom zoom文件
@ -131,10 +133,9 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
void onReady() {
Future.delayed(Duration.zero, () {
DeviceInfoPlugin().androidInfo.then((androidInfo) {
Permission storagePermission =
androidInfo.version.sdkInt >= 33 ? Permission.manageExternalStorage : Permission.storage;
Permission storagePermission = androidInfo.version.sdkInt >= 33 ? Permission.manageExternalStorage : Permission.storage;
PermissionDescribeUtil.instance.toLaunchPermissionRequest(
Get.context!,
Get.context,
title: '储存权限请求',
describe: "为了提供更好的服务,需要获取到存储权限用于保存批阅痕迹并上传",
permissions: [storagePermission],
@ -147,8 +148,7 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
@override
void onClose() {
zoomController.dispose();
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top]); //
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top]); //
eventCancel();
_dataListen.cancel();
_paramListen.cancel();
@ -157,25 +157,29 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
}
void getData() async {
//
if (state.submitLoading.value) return;
var timerControl = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading());
try {
DoPaperDetailsResult data = await getClient().getDoPaperDetails(state.param.value);
// var studentQuestions = data.studentQuestions;
// // 0
// for (var i = 0; i < studentQuestions.length; i++) {
// var item = studentQuestions[i];
// item.topHeight = itemPre.height;
// }
state.getDataError.value = false;
state.handwritings = [];
state.param.value.templateId ??= data.templateId;
state.param.value.studentId ??= data.studentId;
state.studentQuestions.value = data.studentQuestions; //
state.data.value = data;
} catch (e) {
print('获取数据报错了:$e');
// ToastUtils.showError('未获取到试题数据,请重试');
state.getDataError.value = true;
ToastUtils.showError('获取试题数据失败,请检查网络连接后重试');
} finally {
if (timerControl.isActive) timerControl.cancel();
ToastUtils.dismiss();
@ -229,8 +233,7 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
if (data == null) return null;
// OSS url
String imgKey = UploadOssImgUtils.getInstance()
.setImgKey(param.homeworkId, data.studentId.toString(), data.templateId.toString());
String imgKey = UploadOssImgUtils.getInstance().setImgKey(param.homeworkId, data.studentId.toString(), data.templateId.toString());
var resUrl = await getClient().getOssPresignedUri(imgKey);
if (resUrl == null) return null;
@ -273,27 +276,17 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
ToastUtils.showInfo("正在提交批阅数据,请勿重复操作");
return;
}
state.submitLoading.value = true;
var data = state.data.value;
if (data == null) {
ToastUtils.showError('数据异常,请重新加载');
return;
}
if ((state.data.value?.studentQuestions.isEmpty ?? true) || (state.studentQuestions.value?.isEmpty ?? true)) {
ToastUtils.showError('没有可批阅的试题');
return;
}
if (data == null) return;
if ((state.data.value?.studentQuestions.isEmpty ?? true) || (state.studentQuestions.value?.isEmpty ?? true)) return;
var studentQuestions = state.studentQuestions.value!.where((e) => e.useTime != null && e.useTime! > 0).toList();
//
try {
var noRatingElement = studentQuestions.firstWhere((e) => e.studentScore == null);
ToastUtils.showInfo('${noRatingElement.questionNo}题请评分');
var noRatingElement = studentQuestions.firstWhereOrNull((e) => e.studentScore == null);
if (noRatingElement != null) {
ToastUtils.showInfo('${noRatingElement.questionNo}题请评分');
return;
} catch (e) {
//
}
//
@ -323,13 +316,35 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
if (totalUnAnnotateCount <= 0) {
//
if (!state.lastQuestionPrompt) {
await _showCompletionDialog(context);
await showDialog(
context: Get.context ?? context,
builder: (BuildContext context1) {
return AlertDialog(
title: quickText('批阅已完成'),
content: const Text('暂无更多批阅项'),
actions: <Widget>[
TextButton(
child: const Text('继续'),
onPressed: () {
state.lastQuestionPrompt = true;
Navigator.of(context1).pop();
},
),
TextButton(
child: const Text('退出批阅'),
onPressed: () {
Navigator.of(context1).pop();
Get.back();
}),
],
);
},
);
} else {
ToastUtils.showSuccess("批阅已提交", duration: const Duration(milliseconds: 800));
ToastUtils.showSuccess("提交", duration: const Duration(milliseconds: 800));
}
return;
}
var newParams = DoPaperDetailsParam.fromJson(state.param.value.toJson());
if (totalUnAnnotateCount > 0) {
//
@ -337,52 +352,14 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
newParams.studentId = null;
}
state.param.value = newParams;
ToastUtils.showSuccess("批阅已提交");
});
} catch (e) {
print("批阅提交报错 $e");
ToastUtils.showError('提交失败,请检查网络连接后重试');
} catch (_) {
print("批阅提交报错 $_");
} finally {
state.submitLoading.value = false;
}
}
Future<void> _showCompletionDialog(BuildContext context) async {
await showDialog(
context: Get.context ?? context,
barrierDismissible: false,
builder: (BuildContext context1) {
return AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.r)),
title: Row(
children: [
Icon(Icons.check_circle, color: Colors.green, size: 24.sp),
SizedBox(width: 8.w),
Text('批阅已完成', style: TextStyle(fontSize: 18.sp, fontWeight: FontWeight.w600)),
],
),
content: Text('暂无更多批阅项,是否继续?', style: TextStyle(fontSize: 14.sp)),
actions: <Widget>[
TextButton(
child: Text('退出批阅', style: TextStyle(color: Colors.grey[600])),
onPressed: () {
Navigator.of(context1).pop();
Get.back();
},
),
TextButton(
child: Text('继续', style: TextStyle(color: Theme.of(context).primaryColor)),
onPressed: () {
state.lastQuestionPrompt = true;
Navigator.of(context1).pop();
},
),
],
);
},
);
}
Future<void> toFavorite() async {
try {
var data = state.data.value!;

View File

@ -1,9 +1,12 @@
import 'dart:async';
import 'dart:ui' show ImmutableBuffer, ImageDescriptor;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart' as anti_shake_throttling;
import 'package:flutter/widgets.dart';
import 'dart:async';
import 'package:get/get.dart';
import 'package:json_annotation/json_annotation.dart';
import 'index.dart';
@ -75,8 +78,8 @@ class ZoomLogic extends GetxController {
}
// ==>
void onScaleUpdate(double zoom) async {
print("缩放比例:$zoom");
void onScaleUpdate(double scale, double zoom) async {
print("$scale $zoom");
///
zoomState.initScale.value = zoom;
@ -87,10 +90,13 @@ class ZoomLogic extends GetxController {
void onPanUpPosition(Offset val) async {
//
var state = Get.find<HomeworkReviewLogic>().state;
print('**************** 正在移动位置 YYY:${val.dy}');
print('**************** 正在移动位置 XXX:${val.dx}');
state.zoomOffset = val;
state.slide.value = val.dy.abs().toInt().toDouble();
if (state.zoomOffset?.dy.toStringAsFixed(2) != val.dy.toStringAsFixed(2) ||
state.zoomOffset?.dx.toStringAsFixed(2) != val.dx.toStringAsFixed(2)) {
// print('**************** 正在移动位置 YYY:${val.dy}');
// print('**************** 正在移动位置 XXX:${val.dx}');
state.zoomOffset = val;
state.slide.value = val.dy.abs().toInt().toDouble();
}
}
}

View File

@ -3,11 +3,12 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/annotate_list_to_refresh.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/home_page/children/annotate_class/annotate_class_logic.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/bottom_operation_bar.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/question_paper_view.dart';
import 'package:making_school_asignment_app/page/home_page/home_logic.dart';
import 'components/bottom_operation_bar.dart';
import 'components/dropdown_switch_students_type.dart';
import 'components/favorite_widget.dart';
import 'configuration_files/index.dart';
@ -17,64 +18,42 @@ class HomeworkReview extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GetBuilder<HomeworkReviewLogic>(builder: (logic) {
final sateData = logic.state;
return PopScope(
canPop: false,
onPopInvoked: (e) {
if (e && sateData.needRefresh) {
Get.find<AnnotateClassLogic>().getList();
Get.find<HomeLogic>().getList();
logic.eventFire(model: AnnotateListToRefresh());
}
},
child: Scaffold(
backgroundColor: Colors.transparent,
body: Stack(
children: [
// body内容AppBar高度
const Padding(
padding: EdgeInsets.only(top: kToolbarHeight),
child: Column(
children: [
//
DropdownSwitchStudentsType(),
//
Expanded(child: QuestionPaperView()),
//
BottomAnnotationSwitch()
],
),
),
// AppBar
Container(
height: kToolbarHeight,
color: Colors.white,
child: Row(
children: [
SizedBox(width: 5.w),
IconButton(
icon: const Icon(Icons.arrow_back_ios, color: Colors.black),
onPressed: () => Get.back(),
tooltip: '返回'),
Expanded(
child: Text(
sateData.param.value.homeworkName,
style: TextStyle(fontSize: 18.sp, fontWeight: FontWeight.w600),
overflow: TextOverflow.ellipsis,
),
),
const FavoriteWidget(),
SizedBox(width: 10.w),
const ReturnToHomepage(),
SizedBox(width: 8.w),
],
),
),
],
),
final logic = Get.find<HomeworkReviewLogic>();
final sateData = logic.state;
final AnnotateClassLogic controller = Get.find<AnnotateClassLogic>();
final HomeLogic homeLogicController = Get.find<HomeLogic>();
return PopScope(
canPop: false,
onPopInvoked: (e) {
if (e && sateData.needRefresh) {
controller.getList();
homeLogicController.getList();
logic.eventFire(model: AnnotateListToRefresh());
}
},
child: Scaffold(
appBar: AppBar(
// titleSpacing: 0,
leading: IconButton(icon: const Icon(Icons.arrow_back_ios), onPressed: () => Get.back()),
iconTheme: const IconThemeData(color: Colors.black),
title: quickText(sateData.param.value.homeworkName),
backgroundColor: Colors.white,
elevation: 0,
actions: [const FavoriteWidget(), SizedBox(width: 5.w), const ReturnToHomepage()],
),
);
});
body: const Column(
children: [
//
DropdownSwitchStudentsType(),
// SizedBox(height: 10),
//
Expanded(child: QuestionPaperView()),
//
BottomAnnotationSwitch()
],
),
),
);
}
}

View File

@ -4,8 +4,8 @@ import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/annotated_class.dart';
import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.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/home_page/children/job_report/widget/dropdown_selection.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/knowledge_point.dart';
import 'package:making_school_asignment_app/page/home_page/children/job_report/widget/personnel_data_overview.dart';
import 'package:making_school_asignment_app/page/home_page/children/job_report/widget/top_count.dart';
@ -64,7 +64,7 @@ class _JobReportPageState extends State<JobReportPage> {
return DropdownSelection(
involveClasses: state.involveClasses.value,
classData: state.classData.value,
onClassSelected: (AnnotatedClass item) {
call: (AnnotatedClass item) {
state.classData.value = item;
if (item.grade == -1) state.classData.value = state.defaultClass;
logic.getWorkData();
@ -75,19 +75,18 @@ class _JobReportPageState extends State<JobReportPage> {
),
),
//
TopCount(
state.dataCount, state.classData.value.className ?? '', state.homeworkId.value, state.subject),
TopCount(state.dataCount, state.classData == null ? '' : state.classData.value.className, state.homeworkId.value, state.subject),
//
KgtZgtTable(
studentCount: state.dataCount.studentCount!,
homeworkId: state.homeworkId.value,
kgReport: state.kgReport,
zgReport: state.zgReport,
kgtOkRate: state.dataCount.kgtOkRate!.toStringAsFixed(0),
zgtOkRate: state.dataCount.zgtOkRate!.toStringAsFixed(0),
kgtCorrectRate: state.dataCount.kgtCorrectRate!.toStringAsFixed(0),
zgtCorrectRate: state.dataCount.zgtCorrectRate!.toStringAsFixed(0),
subject: state.subject,
studentCount: state.dataCount.studentCount!,
homeworkId: state.homeworkId.value,
kgReport: state.kgReport,
zgReport: state.zgReport,
kgtOkRate: state.dataCount.kgtOkRate!.toStringAsFixed(0),
zgtOkRate: state.dataCount.zgtOkRate!.toStringAsFixed(0),
kgtCorrectRate: state.dataCount.kgtCorrectRate!.toStringAsFixed(0),
zgtCorrectRate: state.dataCount.zgtCorrectRate!.toStringAsFixed(0),
subject: state.subject,
),
//
Container(
@ -95,7 +94,7 @@ class _JobReportPageState extends State<JobReportPage> {
child: KnowledgePoint(
knowsList: state.knowsList,
data: state.homeData,
className: state.classData.value.className ?? '',
className: state.classData.value.className,
homeworkId: state.homeworkId.value,
subject: state.subject,
)),
@ -108,9 +107,7 @@ class _JobReportPageState extends State<JobReportPage> {
margin: EdgeInsets.symmetric(horizontal: 10.r),
child: $UnitTimeAnsweringSituation(widget.id, data.questionAnswerInfos)),*/
//
Container(
margin: EdgeInsets.symmetric(horizontal: 10.r),
child: PersonnelDataOverview(studentList: state.studentList.value)),
Container(margin: EdgeInsets.symmetric(horizontal: 10.r), child: PersonnelDataOverview(studentList: state.studentList.value)),
SizedBox(
height: 30.r,
@ -119,9 +116,7 @@ class _JobReportPageState extends State<JobReportPage> {
),
);
} else {
return Padding(
padding: EdgeInsets.only(top: MediaQuery.of(context).size.height / 2 - 200.r),
child: const MyEmptyWidget());
return Padding(padding: EdgeInsets.only(top: MediaQuery.of(context).size.height / 2 - 200.r), child: const MyEmptyWidget());
}
}),
);

View File

@ -7,11 +7,9 @@ import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
class DropdownSelection extends StatefulWidget {
final List<AnnotatedClass>? involveClasses;
final AnnotatedClass? classData;
final void Function(AnnotatedClass) onClassSelected;
final Function(AnnotatedClass) call;
final Color? bgColor;
const DropdownSelection(
{super.key, required this.involveClasses, required this.classData, required this.onClassSelected, this.bgColor});
const DropdownSelection({Key? key, required this.involveClasses, required this.classData, required this.call,this.bgColor}) : super(key: key);
@override
State<DropdownSelection> createState() => _DropdownSelectionState();
@ -31,27 +29,18 @@ class _DropdownSelectionState extends State<DropdownSelection> {
)),
child: DropdownButton(
value: widget.classData?.classId ?? '-1',
style: TextStyle(color: const Color.fromRGBO(89, 89, 89, 1), fontSize: 12.sp),
style: TextStyle(color: Color.fromRGBO(89, 89, 89, 1), fontSize: 12.sp),
underline: Container(),
// isExpanded:true,
items: widget.involveClasses?.map((classItem) {
return DropdownMenuItem<String>(
value: classItem.classId,
child: quickText(
classItem.classId == '-1' ? '全部' : ' ${EnumUtils.formatGrade(classItem.grade)}${classItem.className}',
size: 12.sp,
color: Colors.black),
items: widget.involveClasses?.map((e) {
return DropdownMenuItem(
value: e.classId!,
child: quickText(e.classId == '-1' ? '全部' : ' ${EnumUtils.formatGrade(e.grade)}${e.className}', size: 12.sp, color: Colors.black),
);
}).toList(),
onChanged: (String? value) {
if (value == null || widget.involveClasses == null) return;
try {
final selectedClass = widget.involveClasses!.firstWhere((element) => element.classId == value);
widget.onClassSelected(selectedClass);
} catch (e) {
//
}
onChanged: (value) {
if (value == null) return;
widget.call(widget.involveClasses!.firstWhere((element) => element.classId == value));
},
),
);

View File

@ -5,6 +5,7 @@ import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/knowledge_points_grasp.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/common/utils/utils.dart';
import 'knowledge_points_grasp_state.dart';
@ -18,9 +19,7 @@ class KnowledgePointsGraspLogic extends GetxController with RequestToolMixin, Ge
@override
void onInit() {
super.onInit();
final subject = Get.arguments['subject'];
state.subject = subject == 0 ? null : subject;
state.subject = Get.arguments['subject'] ?? -1;
state.classId = Get.arguments['classId'] ?? '';
textController = TextEditingController();
refreshController = EasyRefreshController();
@ -32,9 +31,8 @@ class KnowledgePointsGraspLogic extends GetxController with RequestToolMixin, Ge
void getList() async {
try {
ToastUtils.showLoading();
List<KnowledgePointsGrasp> data = await getClient()
.getKnowledgeReport(state.dateStart, state.dateEnd, textController.text, state.classId, state.subject);
print('data: ${data.length}');
List<KnowledgePointsGrasp> data =
await getClient().getKnowledgeReport(state.dateStart, state.dateEnd, textController.text, state.classId, state.subject);
state.dataList.value = data;
} catch (_) {
} finally {

View File

@ -13,6 +13,7 @@ class KnowledgePointsGraspState {
late String dateStart = Utils.getWeekStartDate().toString().substring(0, 10);
late String dateEnd = Utils.getWeekEndDate().toString().substring(0, 10);
late RxString customTimeStr = '自定义'.obs;
late final int? subject;
late final int subject;
late final String classId;
}

View File

@ -1,3 +1,4 @@
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
@ -86,8 +87,7 @@ class _KnowledgePointsGraspPageState extends State<KnowledgePointsGraspPage> {
child: Container(
width: 50.r,
height: 30.r,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.r), color: Theme.of(context).primaryColor),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(4.r), color: Theme.of(context).primaryColor),
child: Center(
child: Text(
'查询',
@ -104,11 +104,12 @@ class _KnowledgePointsGraspPageState extends State<KnowledgePointsGraspPage> {
jobType: 1,
controller: logic.tabController,
customTimeStr: state.customTimeStr.value,
customTime: logic.tabController.index != 2 || ((state.dateEnd == '') && (state.dateStart == ''))
customTime: logic.tabController.index != 2 ||
((state.dateEnd == null || state.dateEnd == '') && (state.dateStart == null || state.dateStart == ''))
? null
: PickerDateRange(
state.dateStart == '' ? null : DateTime.parse(state.dateStart),
state.dateEnd == '' ? null : DateTime.parse(state.dateEnd),
state.dateStart == null || state.dateStart == '' ? null : DateTime.parse(state.dateStart!),
state.dateEnd == null || state.dateEnd == '' ? null : DateTime.parse(state.dateEnd!),
),
onTimeFilter: (String? startTime, String? endTime) {
EasyLoading.show(status: 'loading...');
@ -132,11 +133,9 @@ class _KnowledgePointsGraspPageState extends State<KnowledgePointsGraspPage> {
state.customTimeStr.value = value.startDate?.toString().substring(0, 10) ?? '';
if (value.endDate != null) {
if (!Utils.isPad() && value.startDate!.year == value.endDate!.year) {
state.customTimeStr.value =
'${value.startDate.toString().substring(5, 10)}~${value.endDate.toString().substring(5, 10)}';
state.customTimeStr.value = '${value.startDate.toString().substring(5, 10)}~${value.endDate.toString().substring(5, 10)}';
} else {
state.customTimeStr.value =
'${state.customTimeStr.value}~${value.endDate?.toString().substring(0, 10)}';
state.customTimeStr.value = '${state.customTimeStr.value}~${value.endDate?.toString().substring(0, 10)}';
}
}
}
@ -181,8 +180,7 @@ class _KnowledgePointsGraspPageState extends State<KnowledgePointsGraspPage> {
child: Container(
margin: EdgeInsets.symmetric(vertical: 5.r, horizontal: 14.r),
padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 10.r),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10.r)), color: Colors.white),
decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(10.r)), color: Colors.white),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
@ -209,14 +207,12 @@ class _KnowledgePointsGraspPageState extends State<KnowledgePointsGraspPage> {
children: [
Text(
'${item.count}',
style:
TextStyle(fontSize: 10.sp, color: Theme.of(context).primaryColor),
style: TextStyle(fontSize: 10.sp, color: Theme.of(context).primaryColor),
),
SizedBox(width: 1.w),
Padding(
padding: EdgeInsets.only(top: 2.h),
child: Icon(Icons.chevron_right,
size: 12.r, color: Theme.of(context).primaryColor),
child: Icon(Icons.chevron_right, size: 12.r, color: Theme.of(context).primaryColor),
),
// Image.asset(
// 'assets/images/job_data_right_icon.png',

View File

@ -81,167 +81,162 @@ class _MyInfoState extends State<MyInfo> with AutomaticKeepAliveClientMixin {
fontSize: 13.sp,
);
return Stack(
children: [
SizedBox(
height: double.infinity,
child: Column(
children: [
Container(
height: 220.h,
width: double.infinity,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/personal_bg.png'),
fit: BoxFit.cover,
),
),
),
Expanded(
child: Container(
color: const Color.fromRGBO(248, 248, 248, 1),
))
],
),
),
SafeArea(
child: Scaffold(
backgroundColor: Colors.transparent,
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
return OrientationBuilder(builder: (BuildContext context, Orientation orientation) {
return Stack(
children: [
SizedBox(
height: double.infinity,
child: Column(
children: [
Container(
height: 150.h,
padding: EdgeInsets.only(left: 20.r, right: 20.r),
// alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.asset(
'assets/images/default_user_dead.png',
),
SizedBox(
width: 5.w,
),
InkWell(
onTap: () {
/*if (tokenState == '' || userState.id == '') {
height: 220.h,
width: double.infinity,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/personal_bg.png'),
fit: BoxFit.cover,
),
),
),
Expanded(
child: Container(
color: const Color.fromRGBO(248, 248, 248, 1),
))
],
),
),
SafeArea(
child: Scaffold(
backgroundColor: Colors.transparent,
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 150.h,
padding: EdgeInsets.only(left: 20.r, right: 20.r),
// alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Image.asset(
'assets/images/default_user_dead.png',
),
SizedBox(
width: 5.w,
),
InkWell(
onTap: () {
/*if (tokenState == '' || userState.id == '') {
toLoginPage(context);
}*/
},
child: Container(
margin: EdgeInsets.only(top: 0.h),
child: Text(
userInfo.value?.name ?? '请前往登录',
style:
TextStyle(fontSize: 16.sp, color: const Color(0xFF332A2A), fontWeight: FontWeight.w500),
},
child: Container(
margin: EdgeInsets.only(top: 0.h),
child: Text(
userInfo.value?.name ?? '请前往登录',
style: TextStyle(fontSize: 16.sp, color: const Color(0xFF332A2A), fontWeight: FontWeight.w500),
),
),
),
),
const Spacer(),
InkWell(
onTap: () {
_showAlertDialog(context);
},
child: Container(
padding: EdgeInsets.all(2.r),
decoration: BoxDecoration(
color: const Color.fromRGBO(255, 255, 255, 1),
borderRadius: BorderRadius.circular(50.r),
const Spacer(),
InkWell(
onTap: () {
_showAlertDialog(context);
},
child: Container(
padding: EdgeInsets.all(2.r),
decoration: BoxDecoration(
color: const Color.fromRGBO(255, 255, 255, 1),
borderRadius: BorderRadius.circular(50.r),
),
child: Image.asset('assets/images/out_icon.png',fit: BoxFit.cover),
),
child: Image.asset('assets/images/out_icon.png', fit: BoxFit.cover),
),
)
],
),
),
SizedBox(height: 14.h),
Container(
margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w),
padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(6.w)),
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color.fromRGBO(46, 91, 255, 0.1),
offset: Offset.zero, //y轴偏移量
blurRadius: 20, //
spreadRadius: 10, //
)
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('账号', style: personalInfoTitleStly),
Text(userInfo.value?.name ?? '请前往登录', style: personalInfoValStly)
],
),
),
Container(
margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w),
padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(6.w)),
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color.fromRGBO(46, 91, 255, 0.1),
offset: Offset.zero, //y轴偏移量
blurRadius: 20, //
spreadRadius: 10, //
)
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('所在学校', style: personalInfoTitleStly),
Text(userInfo.value?.schoolName ?? '', style: personalInfoValStly)
],
),
),
Container(
margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w),
padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(6.w)),
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color.fromRGBO(46, 91, 255, 0.1),
offset: Offset.zero, //y轴偏移量
blurRadius: 20, //
spreadRadius: 10, //
)
],
),
child: InkWell(
onTap: () {
Get.toNamed(Routes.otherPage);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('其他', style: personalInfoTitleStly),
Icon(
Icons.arrow_forward_ios,
color: const Color.fromRGBO(80, 87, 103, 1),
size: 13.sp,
)
],
),
),
),
],
SizedBox(height: 14.h),
Container(
margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w),
padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(6.w)),
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color.fromRGBO(46, 91, 255, 0.1),
offset: Offset.zero, //y轴偏移量
blurRadius: 20, //
spreadRadius: 10, //
)
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [Text('账号', style: personalInfoTitleStly), Text(userInfo.value?.name ?? '请前往登录', style: personalInfoValStly)],
),
),
Container(
margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w),
padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(6.w)),
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color.fromRGBO(46, 91, 255, 0.1),
offset: Offset.zero, //y轴偏移量
blurRadius: 20, //
spreadRadius: 10, //
)
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [Text('所在学校', style: personalInfoTitleStly), Text(userInfo.value?.schoolName ?? '', style: personalInfoValStly)],
),
),
Container(
margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w),
padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(6.w)),
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Color.fromRGBO(46, 91, 255, 0.1),
offset: Offset.zero, //y轴偏移量
blurRadius: 20, //
spreadRadius: 10, //
)
],
),
child: InkWell(
onTap: () {
Get.toNamed(Routes.otherPage);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('其他', style: personalInfoTitleStly),
Icon(
Icons.arrow_forward_ios,
color: const Color.fromRGBO(80, 87, 103, 1),
size: 13.sp,
)
],
),
),
),
],
),
),
),
),
],
);
],
);
});
}
}

View File

@ -1,7 +1,7 @@
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/page/home_page/children/read_over/widget/annotate_list.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
@ -37,7 +37,7 @@ class _ReadOverPageState extends State<ReadOverPage> {
statusBarBrightness: Brightness.light,
),
child: Scaffold(
backgroundColor: Colors.white,
backgroundColor: const Color.fromRGBO(244, 244, 244, 1),
body: OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
return Column(
@ -117,9 +117,7 @@ class _ReadOverPageState extends State<ReadOverPage> {
child: quickText(
'待批阅',
size: 14.sp,
color: state.tabIndex.value == 0
? Theme.of(context).primaryColor
: const Color.fromRGBO(80, 94, 110, 1),
color: state.tabIndex.value == 0 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null,
),
);
@ -139,9 +137,7 @@ class _ReadOverPageState extends State<ReadOverPage> {
child: quickText(
'已批阅',
size: 14.sp,
color: state.tabIndex.value == 1
? Theme.of(context).primaryColor
: const Color.fromRGBO(80, 94, 110, 1),
color: state.tabIndex.value == 1 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null,
),
);
@ -157,23 +153,19 @@ class _ReadOverPageState extends State<ReadOverPage> {
onTap: () {
Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'});
},
child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"),
color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp),
child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"), color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp),
),
),
],
),
),
Expanded(
child: Container(
color: const Color.fromRGBO(245, 245, 245, 1),
child: Obx(() {
return AnnotateList(
tabIndex: state.tabIndex.value,
assessType: 0,
);
}),
),
child: Obx(() {
return AnnotateList(
tabIndex: state.tabIndex.value,
assessType: 0,
);
}),
),
],
);

View File

@ -3,6 +3,7 @@ import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/work_student.dart';
import 'package:making_school_asignment_app/common/job/work_student_params.dart';
import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart';
import 'package:making_school_asignment_app/common/store/user_store.dart';
import 'home_state.dart';
@ -23,20 +24,16 @@ class HomeLogic extends GetxController with RequestToolMixin, GetTickerProviderS
}
void getList() async {
try {
params.pageNumber = state.pageNumber;
WorkStudent data = await getClient().getUnAnnotateList(params);
state.totalCount.value = data.totalCount;
state.readOver.value = data.items.length;
//
refreshController.finishRefresh();
} catch (e) {
print('获取作业列表失败: $e');
//
refreshController.finishRefresh();
//
params.pageNumber = state.pageNumber;
WorkStudent data = await getClient().getUnAnnotateList(params);
state.totalCount.value = data.totalCount;
state.readOver.value = data.items.length;
/* if(params.pageNumber == 1){
state.workList.value = data.items;
}else{
state.workList.addAll(data.items);
}
refreshController.finishRefresh();*/
}
@override

View File

@ -1,12 +1,15 @@
import 'package:badges/badges.dart' as badges;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/mixins/getx_keepalive_widget.dart';
import 'package:badges/badges.dart' as badges;
import 'package:percent_indicator/percent_indicator.dart';
import 'package:making_school_asignment_app/common/job/work_student.dart';
import 'package:making_school_asignment_app/common/utils/enum_untils.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
@ -14,100 +17,136 @@ import 'home_logic.dart';
part 'home_view.g.dart';
class HomePage extends GetxKeepAliveWidget<HomeLogic> {
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin {
final logic = Get.find<HomeLogic>();
final state = Get.find<HomeLogic>().state;
@override
bool get wantKeepAlive => true;
@override
void initState() {
super.initState();
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarColor: Colors.transparent, //
statusBarIconBrightness: Brightness.light,
systemStatusBarContrastEnforced: false,
));
super.initState();
}
@override
Widget buildContent(context, controller) {
Widget build(BuildContext context) {
super.build(context);
var spaceWidth = SizedBox(height: ScreenUtil().screenWidth / 30);
return Scaffold(
backgroundColor: Colors.white,
body: OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
final state = controller.state;
return EasyRefresh(
firstRefresh: false,
taskIndependence: true,
enableControlFinishLoad: true,
controller: controller.refreshController,
controller: logic.refreshController,
header: MaterialHeader(),
// footer: TaurusFooter(),
onRefresh: () async {
state.pageNumber = 1;
return controller.getList();
return logic.getList();
},
child: CustomScrollView(
slivers: [
//
SliverAppBar(
expandedHeight: 300.h,
floating: false,
pinned: false,
backgroundColor: Colors.transparent,
flexibleSpace: FlexibleSpaceBar(
background: Image.asset(
'assets/images/home_banner.png',
width: Get.width,
fit: BoxFit.cover,
),
),
// onLoad: () async {
// if (state.workList.length < state.totalCount.value) {
// state.pageNumber++;
// return logic.getList();
// }
// },
child: Stack(
children: [
Image.asset(
'assets/images/home_banner.png',
width: Get.width,
fit: BoxFit.fill,
),
//
SliverToBoxAdapter(
child: Container(
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20.r),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(topLeft: Radius.circular(30.r), topRight: Radius.circular(30.r)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 20.r),
//
Row(
children: [
Icon(
Icons.assignment_outlined,
size: 24.sp,
color: const Color(0xFF4F4F4F),
),
SizedBox(width: 8.r),
Text(
'我的作业管理',
style: TextStyle(
fontSize: 22.sp, color: const Color(0xFF2C2C2C), fontWeight: FontWeight.w700),
),
const Spacer(),
//
IconButton(
onPressed: () => controller.refreshController.callRefresh(),
icon: Icon(
Icons.refresh,
size: 20.sp,
color: const Color(0xFF4F4F4F),
),
tooltip: '刷新数据',
)
],
),
SizedBox(height: 24.r),
//
_buildMenuGrid(context, state),
SizedBox(height: 20.r),
],
),
Container(
margin: EdgeInsets.only(top: 300.h),
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20.r),
decoration: BoxDecoration(
color: Colors.white, borderRadius: BorderRadius.only(topLeft: Radius.circular(30.r), topRight: Radius.circular(30.r))),
child: Column(
children: [
SizedBox(
height: 15.r,
),
Text(
'我的作业管理',
style: TextStyle(fontSize: 20.sp, color: const Color(0xFF676666), fontWeight: FontWeight.w600),
),
SizedBox(
height: 15.r,
),
Row(
children: [
Expanded(
child: Obx(() {
return menuItem(
bgImg: 'assets/images/home_bg_01.png',
name: '作业批阅',
value: state.totalCount.value.toString(),
url: Routes.readOverPage,
);
}),
),
SizedBox(
width: 20.r,
),
Expanded(
child: menuItem(bgImg: 'assets/images/home_bg_02.png', name: '知识点掌握', url: Routes.studentHistoryWorkPage, page: 'points'),
),
],
),
SizedBox(
height: 20.r,
),
Row(
children: [
Expanded(
child:
menuItem(bgImg: 'assets/images/home_bg_03.png', name: '学生历史作业', url: Routes.studentHistoryWorkPage, page: 'history'),
),
SizedBox(
width: 20.r,
),
Expanded(
child: menuItem(bgImg: 'assets/images/home_bg_04.png', name: '答题轨迹', url: Routes.answerTrajectoryPage),
),
],
),
SizedBox(
height: 20.r,
),
Row(
children: [
menuItem(
bgImg: 'assets/images/home_bg_05.png',
name: '优先批阅设定',
url: Routes.studentHistoryWorkPage,
page: 'set',
),
SizedBox(
width: 20.r,
),
],
),
SizedBox(height: 15.h),
],
),
),
)
],
),
);
@ -116,229 +155,68 @@ class HomePage extends GetxKeepAliveWidget<HomeLogic> {
);
}
Widget _buildStatCard(String title, String value, Color color, IconData icon) {
return Container(
padding: EdgeInsets.all(12.r),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.r),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Column(
children: [
Icon(icon, color: color, size: 20.sp),
SizedBox(height: 4.r),
Text(
value,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: color,
),
),
Text(
title,
style: TextStyle(
fontSize: 12.sp,
color: const Color(0xFF6C757D),
),
),
],
),
);
}
Widget _buildMenuGrid(BuildContext context, dynamic state) {
return Column(
children: [
//
Row(
children: [
Expanded(
child: Obx(() => $MenuItem(
bgImg: 'assets/images/home_bg_01.png',
name: '作业批阅',
value: state.totalCount.value > 0 ? state.totalCount.value.toString() : null,
url: Routes.readOverPage,
isPrimary: true,
)),
),
SizedBox(width: 16.r),
const Expanded(
child: $MenuItem(
bgImg: 'assets/images/home_bg_02.png',
name: '知识点掌握',
url: Routes.studentHistoryWorkPage,
page: 'points',
),
),
],
),
SizedBox(height: 16.r),
//
Row(
children: [
const Expanded(
child: $MenuItem(
bgImg: 'assets/images/home_bg_03.png',
name: '学生历史作业',
url: Routes.studentHistoryWorkPage,
page: 'history',
),
),
SizedBox(width: 16.r),
const Expanded(
child: $MenuItem(bgImg: 'assets/images/home_bg_04.png', name: '答题轨迹', url: Routes.answerTrajectoryPage),
),
],
),
SizedBox(height: 16.r),
//
Row(
children: [
const Expanded(
child: $MenuItem(
bgImg: 'assets/images/home_bg_05.png',
name: '优先批阅设定',
url: Routes.studentHistoryWorkPage,
page: 'set',
),
),
SizedBox(width: 16.r),
//
const Expanded(child: SizedBox()),
],
),
],
);
@override
void dispose() {
Get.delete<HomeLogic>();
super.dispose();
}
}
@swidget
Widget $menuItem({
required String bgImg,
required String name,
String? value,
required String url,
String? page,
bool isPrimary = false,
}) {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
Get.toNamed(url, arguments: {'page': page ?? ''});
},
borderRadius: BorderRadius.circular(12.r),
child: Semantics(
label: '$name${value != null ? ',待处理数量:$value' : ''}',
hint: '点击进入$name页面',
button: true,
child: Container(
width: (Get.width - 60.r) / 2,
height: (Get.width - 60.r) / 2 * 86 / 164,
padding: EdgeInsets.all(16.r),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.r),
gradient: isPrimary
? const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFF667eea),
Color(0xFF764ba2),
],
)
: null,
color: isPrimary ? null : Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.08),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
image: !isPrimary
? DecorationImage(
image: AssetImage(bgImg),
fit: BoxFit.cover,
colorFilter: ColorFilter.mode(
Colors.white.withOpacity(0.8),
BlendMode.srcATop,
),
)
: null,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Text(
name,
style: TextStyle(
fontSize: 14.sp,
color: isPrimary ? Colors.white : const Color(0xFF2C2C2C),
fontWeight: FontWeight.w600,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
if (value != null && value != '')
Semantics(
label: '待处理数量:$value',
child: Container(
width: 20.r,
height: 20.r,
alignment: Alignment.center,
decoration: BoxDecoration(
color: isPrimary ? Colors.white : const Color(0xFFFF6969),
borderRadius: BorderRadius.all(Radius.circular(10.r)),
),
child: Text(
value,
style: TextStyle(
fontSize: 10.sp,
color: isPrimary ? const Color(0xFFFF6969) : Colors.white,
fontWeight: FontWeight.w600),
),
),
)
],
),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (isPrimary)
Icon(
Icons.arrow_forward_ios,
size: 14.sp,
color: Colors.white,
)
else
Image.asset(
'assets/images/home_right_icon.png',
width: 16.r,
height: 16.r,
semanticLabel: '进入图标',
),
],
),
],
),
Widget menuItem({required String bgImg, required String name, String? value, required String url, String? page}) {
return InkWell(
onTap: () {
Get.toNamed(url, arguments: {'page': page ?? ''});
},
child: Container(
width: (Get.width - 60.r) / 2,
height: (Get.width - 60.r) / 2 * 86 / 164,
padding: EdgeInsets.symmetric(vertical: 15.r, horizontal: 15.r),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(bgImg),
fit: BoxFit.contain,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
name,
style: TextStyle(fontSize: 14.sp, color: const Color(0xFF4F4F4F), fontWeight: FontWeight.w600),
),
if (value != null && value != '')
Container(
width: 18.r,
height: 18.r,
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color(0xFFFF6969),
borderRadius: BorderRadius.all(Radius.circular(9.r)),
),
child: Text(
value!,
style: TextStyle(fontSize: 10.sp, color: Colors.white, fontWeight: FontWeight.w600),
),
)
],
),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Image.asset(
'assets/images/home_right_icon.png',
width: 16.r,
height: 16.r,
),
],
),
],
),
),
);
}
@ -365,7 +243,7 @@ Widget $termRow(BuildContext context, List<EntranceModel> items, int? data) {
Expanded(flex: 9, child: $TermItem(items[0], data!)),
// const Expanded(flex: 1, child: SizedBox()),
SizedBox(width: ScreenUtil().screenWidth / 30),
Expanded(flex: 9, child: $TermItem(items[1], data)),
Expanded(flex: 9, child: $TermItem(items[1], data!)),
]);
break;
case 3:
@ -426,8 +304,7 @@ Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHe
badgeStyle: badges.BadgeStyle(
badgeColor: const Color.fromRGBO(255, 105, 105, 1),
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),
elevation: 1,
padding: EdgeInsets.symmetric(horizontal: Utils.isPad() ? 11.w : 16.w, vertical: 2.h),
@ -455,8 +332,7 @@ Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHe
children: [
Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover),
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(
@ -464,8 +340,7 @@ Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHe
children: [
Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover),
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),
],
),
),

View File

@ -11,12 +11,12 @@ class StudentGroupList extends StatelessWidget {
final Function goNextPage;
final Widget? rightBtn;
const StudentGroupList(this.studentGroups, this.goNextPage, {super.key, this.rightBtn});
const StudentGroupList(this.studentGroups, this.goNextPage, {Key? key, this.rightBtn}) : super(key: key);
@override
Widget build(BuildContext context) {
return Obx(() {
return studentGroups.isNotEmpty
return studentGroups != null && studentGroups.isNotEmpty
? Utils.isPad()
? GridView(
shrinkWrap: true,
@ -45,12 +45,12 @@ class StudentGroupList extends StatelessWidget {
padding: EdgeInsets.only(right: 8.r),
child: Text(
'${EnumUtils.formatGrade(item.grade)}${item.className}',
style: TextStyle(fontSize: 10.sp, color: Theme.of(context).primaryColor),
style: TextStyle(fontSize: 10.sp, color:Theme.of(context).primaryColor),
),
),
Text(
EnumUtils.formatSubject(item.subject!),
style: TextStyle(fontSize: 10.sp, color: const Color(0xFF8B8B8B)),
style: TextStyle(fontSize: 10.sp, color: Color(0xFF8B8B8B)),
),
const Spacer(),
/*Expanded(
@ -114,7 +114,7 @@ class StudentGroupList extends StatelessWidget {
),
Text(
EnumUtils.formatSubject(item.subject!),
style: TextStyle(fontSize: 10.sp, color: const Color(0xFF8B8B8B)),
style: TextStyle(fontSize: 10.sp, color: Color(0xFF8B8B8B)),
),
const Spacer(),
/* Expanded(

View File

@ -1,141 +1,169 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/mixins/getx_keepalive_widget.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/read_over/read_over_logic.dart';
import 'package:making_school_asignment_app/page/home_page/children/read_over/read_over_view.dart';
import 'package:making_school_asignment_app/page/home_page/children/read_over/widget/annotate_list.dart';
import 'package:making_school_asignment_app/page/home_page/children/student_work_detail/widget/job_condition_filter.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'package:syncfusion_flutter_datepicker/datepicker.dart';
import 'work_logic.dart';
class WorkPage extends GetxKeepAliveWidget<WorkLogic> {
class WorkPage extends StatefulWidget {
const WorkPage({super.key});
@override
Widget buildContent(BuildContext context, WorkLogic controller) {
final state = controller.state;
State<WorkPage> createState() => _WorkPageState();
}
class _WorkPageState extends State<WorkPage> with AutomaticKeepAliveClientMixin {
final logic = Get.find<WorkLogic>();
final state = Get.find<WorkLogic>().state;
@override
bool get wantKeepAlive => true;
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
super.build(context);
return Scaffold(
backgroundColor: const Color.fromRGBO(244, 244, 244, 1),
body: Column(
children: <Widget>[
Container(
color: Colors.white,
margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
padding: EdgeInsets.only(bottom: 9.h, top: 4.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 10.w),
)),
Expanded(
flex: 4,
child: Container(
padding: EdgeInsets.symmetric(vertical: 2.h),
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color.fromRGBO(243, 243, 243, 1),
borderRadius: BorderRadius.circular(8.r),
),
child: TabBar(
padding: EdgeInsets.zero,
indicatorPadding: EdgeInsets.zero,
indicatorWeight: 0,
labelPadding: EdgeInsets.symmetric(horizontal: 2.w),
controller: controller.tabController,
unselectedLabelStyle: TextStyle(
fontSize: 14.sp,
color: const Color.fromRGBO(69, 83, 100, 1),
),
labelStyle: TextStyle(
fontSize: 14.sp,
color: const Color(0xFF4CC793),
),
// labelColor: const Color.fromRGBO(45, 56, 76, 1),
indicator: const BoxDecoration(),
onTap: (index) {
state.tabIndex.value = index;
if (index == 1 && state.completedToRefresh) {
//
// _refreshController2.callRefresh();
state.completedToRefresh = false;
}
},
tabs: <Widget>[
Tab(
iconMargin: EdgeInsets.zero,
height: 34.h,
child: Obx(() {
return Container(
width: 140.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: state.tabIndex.value == 0 ? const Color.fromRGBO(255, 255, 255, 1) : null,
borderRadius: BorderRadius.all(Radius.circular(8.r)),
),
child: quickText(
'待批阅',
size: 14.sp,
color: state.tabIndex.value == 0
? Theme.of(context).primaryColor
: const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null,
),
);
}),
body: OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
return Column(
children: <Widget>[
Container(
color: Colors.white,
margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
padding: EdgeInsets.only(bottom: 9.h, top: 4.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 1,
child: Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 10.w),
)),
Expanded(
flex: 4,
child: Container(
padding: EdgeInsets.symmetric(vertical: 2.h),
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color.fromRGBO(243, 243, 243, 1),
borderRadius: BorderRadius.circular(8.r),
),
Tab(
iconMargin: EdgeInsets.zero,
height: 34.h,
child: Obx(() {
return Container(
width: 140.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: state.tabIndex.value == 1 ? const Color.fromRGBO(255, 255, 255, 1) : null,
borderRadius: BorderRadius.all(Radius.circular(8.r)),
),
child: quickText(
'已批阅',
size: 14.sp,
color: state.tabIndex.value == 1
? Theme.of(context).primaryColor
: const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null,
),
);
}),
child: TabBar(
padding: EdgeInsets.zero,
indicatorPadding: EdgeInsets.zero,
indicatorWeight: 0,
labelPadding: EdgeInsets.symmetric(horizontal: 2.w),
controller: logic.tabController,
unselectedLabelStyle: TextStyle(
fontSize: 14.sp,
color: const Color.fromRGBO(69, 83, 100, 1),
),
labelStyle: TextStyle(
fontSize: 14.sp,
color: const Color(0xFF4CC793),
),
// labelColor: const Color.fromRGBO(45, 56, 76, 1),
indicator: const BoxDecoration(),
onTap: (index) {
state.tabIndex.value = index;
if (index == 1 && state.completedToRefresh) {
//
// _refreshController2.callRefresh();
state.completedToRefresh = false;
}
},
tabs: <Widget>[
Tab(
iconMargin: EdgeInsets.zero,
height: 34.h,
child: Obx(() {
return Container(
width: 140.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: state.tabIndex.value == 0 ? const Color.fromRGBO(255, 255, 255, 1) : null,
borderRadius: BorderRadius.all(Radius.circular(8.r)),
),
child: quickText(
'待批阅',
size: 14.sp,
color: state.tabIndex.value == 0 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null,
),
);
}),
),
Tab(
iconMargin: EdgeInsets.zero,
height: 34.h,
child: Obx(() {
return Container(
width: 140.w,
alignment: Alignment.center,
decoration: BoxDecoration(
color: state.tabIndex.value == 1 ? const Color.fromRGBO(255, 255, 255, 1) : null,
borderRadius: BorderRadius.all(Radius.circular(8.r)),
),
child: quickText(
'已批阅',
size: 14.sp,
color: state.tabIndex.value == 1 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null,
),
);
}),
),
],
),
],
),
),
),
Expanded(
flex: 1,
child: InkWell(
onTap: () {
Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'});
},
child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"), color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp),
),
),
],
),
Expanded(
flex: 1,
child: InkWell(
onTap: () {
Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'});
},
child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"),
color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp),
),
),
],
),
),
Expanded(
child: Obx(() {
return AnnotateList(
tabIndex: state.tabIndex.value,
assessType: 1,
);
}),
),
],
),
Expanded(
child: Obx(() {
return AnnotateList(
tabIndex: state.tabIndex.value,
assessType: 1,
);
}),
),
],
);
},
),
);
}
@override
void dispose() {
Get.delete<WorkLogic>();
super.dispose();
}
}

View File

@ -12,9 +12,8 @@ import connectivity_plus
import device_info_plus
import package_info_plus
import path_provider_foundation
import sqflite_darwin
import sqflite
import url_launcher_macos
import webview_flutter_wkwebview
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AppInstallerPlugin.register(with: registry.registrar(forPlugin: "AppInstallerPlugin"))
@ -26,5 +25,4 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
}

View File

@ -62,18 +62,14 @@ dependencies:
fluttertoast: ^8.0.9
#
functional_widget_annotation: ^0.10.0
flutter_widget_from_html_core: ^0.17.0
flutter_widget_from_html_core: ^0.14.12
# APP内存及本地存储插件
get_storage: ^2.0.3
# zoom_widget: ^2.0.1
zoom_widget:
git:
url: https://gitea.23544.com/wangyang/zoom_widget.git
# url: https://github.com/semakers/zoom-widget.git
# ref: a35c9da6afe405c23b5897b449683d424016e9f1
zoom_widget: ^2.0.1
# start retrofit请求封装
retrofit: ^4.1.0
json_annotation: 4.9.0
json_annotation: ^4.9.0
# end retrofit请求封装
# 进度条
percent_indicator: ^4.2.3
@ -83,7 +79,7 @@ dependencies:
data_table_2: 2.5.10
flutter_staggered_grid_view: ^0.7.0
dropdown_button2: ^2.3.9
syncfusion_flutter_datepicker: ^30.2.7
syncfusion_flutter_datepicker: ^25.2.5
easy_debounce: ^2.0.3 # 防抖节流
flutter_hooks: ^0.20.5
flutter_spinkit: ^5.2.1
@ -97,26 +93,24 @@ dependencies:
app_installer: ^1.1.0
auto_updater: ^0.2.1
permission_handler: ^11.3.1
flutter_distributor: 0.6.5
# fastforge: ^0.6.5
flutter_native_splash: ^2.4.6
flutter_distributor: ^0.4.5
flutter_native_splash: ^2.4.1
icons_launcher: ^2.1.7
app_settings: ^5.1.1
device_info_plus: ^11.1.0
auto_size_text: ^3.0.0
dependency_overrides:
archive: ^4.0.2
# dependency_overrides:
# meta: ^1.15.0
dev_dependencies:
flutter_test:
sdk: flutter
retrofit_generator: 9.6.0
build_runner: 2.5.4
json_serializable: 6.9.5
retrofit_generator: ^8.1.0
build_runner: ^2.4.10
json_serializable: ^6.6.2
# 分离样式
functional_widget: ^0.10.3
functional_widget: ^0.10.2
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your

View File

@ -7,7 +7,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:making_school_asignment_app/main_offest.dart';
import 'package:making_school_asignment_app/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {

View File

@ -201,20 +201,6 @@
@ -238,9 +224,8 @@
body {
margin: 0;
min-height: 100%;
background-color: #ffffff;
background-image: url("splash/img/light-background.png");
background-size: 100% 100%;
background-color: #8C68FF;
background-size: 100% 100%;
}
.center {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 KiB