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/debug
/android/app/profile /android/app/profile
/android/app/release /android/app/release
# FVM Version Cache
.fvm/

View File

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

View File

@ -37,10 +37,6 @@ android {
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
} }
kotlinOptions {
jvmTarget = "1.8"
}
signingConfigs { signingConfigs {
release { release {
keyAlias keystoreProperties['keyAlias'] keyAlias keystoreProperties['keyAlias']

View File

@ -4,7 +4,6 @@
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:enableOnBackInvokedCallback="true"> android:enableOnBackInvokedCallback="true">
<!-- windowTranslucentStatus 设置顶部状态栏使用-->
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
@ -13,7 +12,6 @@
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:windowTranslucentStatus="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as <!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user 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 --> <!-- 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"> <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:forceDarkAllowed">false</item> <item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">true</item> <item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</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> <item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
</style> </style>
<!-- Theme applied to the Android Window as soon as the process has started. <!-- 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 --> the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item> <item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">true</item> <item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style> </style>
<!-- Theme applied to the Android Window as soon as the process has started. <!-- 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 --> <!-- 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"> <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:forceDarkAllowed">false</item> <item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">true</item> <item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</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> <item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
</style> </style>
<!-- Theme applied to the Android Window as soon as the process has started. <!-- 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 --> the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item> <item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">true</item> <item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item> <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style> </style>
<!-- Theme applied to the Android Window as soon as the process has started. <!-- 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 distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-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 { plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.8.0" apply false id "com.android.application" version "7.3.0" apply false
id "org.jetbrains.kotlin.android" version "1.8.22" apply false id "org.jetbrains.kotlin.android" version "1.7.10" apply false
} }
include ":app" 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 # flutter pub run flutter_native_splash:remove
# 设置闪屏页的默认态logo或背景图片路径 # 设置闪屏页的默认态logo或背景图片路径
background_image: assets/images/splash_native.png color: "#8C68FF"
image_ios: assets/images/splash_native.png
# 全屏模式 background_image_android: assets/images/splash_native.png
fullscreen: true
android_12: android_12:
color: "#FFFFFF"
image: assets/images/logo_splash.png image: assets/images/logo_splash.png
android: true android: true
ios: true ios: true
# android_gravity: clip_vertical android_gravity: clip_vertical
# ios_content_mode: scaleToFill 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"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="LaunchBackground" translatesAutoresizingMaskIntoConstraints="NO" id="tWc-Dq-wcI"/> <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> </subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints> <constraints>
@ -38,7 +38,7 @@
</scene> </scene>
</scenes> </scenes>
<resources> <resources>
<image name="LaunchImage" width="168" height="185"/> <image name="LaunchImage" width="751" height="1734"/>
<image name="LaunchBackground" width="1" height="1"/> <image name="LaunchBackground" width="1" height="1"/>
</resources> </resources>
</document> </document>

View File

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

View File

@ -1,6 +1,14 @@
import 'package:dio/dio.dart' hide Headers; 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/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/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/app_version_model.dart';
import 'package:making_school_asignment_app/common/job/common/base_app_version.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/homework_details.dart';
import 'package:making_school_asignment_app/common/job/knowledge_points_grasp.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/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.dart';
import 'package:making_school_asignment_app/common/job/student_history_params.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_item.dart';
import 'package:making_school_asignment_app/common/job/student_personal_info.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_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.dart';
import 'package:making_school_asignment_app/common/job/work_student_params.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'; part 'retrofit_client.g.dart';
@ -64,7 +64,7 @@ abstract class RetrofitClient {
// //
@GET("/api/rbac/Student/GetPriorityAnnotateStudents") @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") @GET("/api/hms/Annotate/GetUnAnnotateList")
@ -88,22 +88,16 @@ abstract class RetrofitClient {
// //
@POST("/api/rbac/Student/PriorityAnnotateStudent") @POST("/api/rbac/Student/PriorityAnnotateStudent")
Future getAnnotateStudent( Future getAnnotateStudent(@Field() String classId, @Field() int studentId, @Field() bool priorityAnnotate, @Field() int subject);
@Field() String classId, @Field() int studentId, @Field() bool priorityAnnotate, @Field() int? subject);
// //
@GET("/api/hms/HmsReport/GetStudentHomework") @GET("/api/hms/HmsReport/GetStudentHomework")
Future<StudentPersonalInfo> getStudentHomework( Future<StudentPersonalInfo> getStudentHomework(@Query('HomeworkId') String homeworkId, @Query('StudentId') int studentId);
@Query('HomeworkId') String homeworkId, @Query('StudentId') int studentId);
// //
@GET("/api/hms/HmsReport/GetKnowledgeReport") @GET("/api/hms/HmsReport/GetKnowledgeReport")
Future<List<KnowledgePointsGrasp>> getKnowledgeReport( Future<List<KnowledgePointsGrasp>> getKnowledgeReport(
@Query('DateStart') String dateStart, @Query('DateStart') String dateStart, @Query('DateEnd') String dateEnd, @Query('KnowledgeName') String knowledgeName,@Query('ClassId') String classId,@Query('Subject') int subject);
@Query('DateEnd') String dateEnd,
@Query('KnowledgeName') String knowledgeName,
@Query('ClassId') String classId,
@Query('Subject') int? subject);
// //
@GET("/api/hms/HmsReport/GetKnowledgeReportDetail") @GET("/api/hms/HmsReport/GetKnowledgeReportDetail")
@ -112,8 +106,8 @@ abstract class RetrofitClient {
// //
@GET("/api/hms/HmsReport/GetQuestionStudentState") @GET("/api/hms/HmsReport/GetQuestionStudentState")
Future<List<Students>> getQuestionStudentState(@Query('HomeworkId') String homeworkId, Future<List<Students>> getQuestionStudentState(
@Query('TemplateId') int templateId, @Query('QuestionNo') String questionNo); @Query('HomeworkId') String homeworkId, @Query('TemplateId') int templateId, @Query('QuestionNo') String questionNo);
// //
@POST("/api/hms/Homework/Collect") @POST("/api/hms/Homework/Collect")
@ -130,8 +124,7 @@ abstract class RetrofitClient {
// //
@GET("/api/hms/FavStudent/GetList") @GET("/api/hms/FavStudent/GetList")
Future<BasePageData<HomeworkFavs>> getFavList( Future<BasePageData<HomeworkFavs>> getFavList(@Query('HomeworkName') String homeworkName, @Query('ClassId') String classId);
@Query('HomeworkName') String homeworkName, @Query('ClassId') String classId);
// () // ()
@POST("/api/hms/Annotate/AllCorrect") @POST("/api/hms/Annotate/AllCorrect")
@ -155,6 +148,5 @@ abstract class RetrofitClient {
// APP // APP
@GET("/api/infra/AppVersion/Get") @GET("/api/infra/AppVersion/Get")
Future<AppVersion?> getLastAppVersion( Future<AppVersion?> getLastAppVersion(@Query('appName') String appName, @Query('ftuType') int ftuType); // ftuType 1 2IOS 3windows
@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:json_annotation/json_annotation.dart';
import 'package:making_school_asignment_app/common/config/request_config.dart'; import 'package:making_school_asignment_app/common/config/request_config.dart';
part 'do_paper_details_result.g.dart'; part 'do_paper_details_result.g.dart';
///
@JsonSerializable(checked: true, includeIfNull: false) @JsonSerializable(checked: true, includeIfNull: false)
class DoPaperDetailsResult { class DoPaperDetailsResult extends Object {
@JsonKey(name: 'templateIds') @JsonKey(name: 'templateIds')
final Map<String, bool> templateIds; Map<String, bool> templateIds;
/// ID键列表 //
@JsonKey(name: 'templateIdKeys') @JsonKey(name: 'templateIdKeys')
List<int>? templateIdKeys; List<int>? templateIdKeys;
/// ID键映射表 //
@JsonKey(name: 'templateIdKeyMap') @JsonKey(name: 'templateIdKeyMap')
Map<int, int>? templateIdKeyMap; Map<int, int>? templateIdKeyMap;
/// @JsonKey(name: 'submitStudents', toJson: _paperStudentsToJson) //
@JsonKey(name: 'submitStudents', toJson: _paperStudentsToJson) List<PaperStudents> students;
final List<PaperStudents> students;
/// ID
@JsonKey(name: 'templateId') @JsonKey(name: 'templateId')
final int templateId; int templateId;
/// ID
@JsonKey(name: 'studentId') @JsonKey(name: 'studentId')
final int studentId; int studentId;
/// //
@JsonKey(name: 'priority', defaultValue: false) @JsonKey(name: 'priority', defaultValue: false)
bool priority; bool priority;
/// @JsonKey(name: 'annotatedCount') //
@JsonKey(name: 'annotatedCount') int annotatedCount;
final int annotatedCount;
/// @JsonKey(name: 'submitCount') //
@JsonKey(name: 'submitCount') int submitCount;
final int submitCount;
/// @JsonKey(name: 'zgtAnswer') //
@JsonKey(name: 'zgtAnswer')
String zgtAnswer; String zgtAnswer;
/// @JsonKey(name: 'showZgtAnnotate') //
@JsonKey(name: 'showZgtAnnotate')
String? showZgtAnnotate; String? showZgtAnnotate;
/// @JsonKey(name: 'zgtAnnotate') //
@JsonKey(name: 'zgtAnnotate')
String? zgtAnnotate; String? zgtAnnotate;
/// @JsonKey(name: 'lastAnswerTime') //
@JsonKey(name: 'lastAnswerTime') String lastAnswerTime;
final String lastAnswerTime;
// //
@JsonKey(name: 'annotateTime') @JsonKey(name: 'annotateTime')
@ -77,6 +68,7 @@ class DoPaperDetailsResult {
@JsonKey(name: 'continuePage', toJson: _continuePageToJson) @JsonKey(name: 'continuePage', toJson: _continuePageToJson)
ContinuePage? continuePage; ContinuePage? continuePage;
@JsonKey(name: 'nextPage', toJson: _nextPageToJson) @JsonKey(name: 'nextPage', toJson: _nextPageToJson)
NextPage? nextPage; NextPage? nextPage;
@ -110,42 +102,35 @@ class DoPaperDetailsResult {
this.annotateTime, this.annotateTime,
this.showZgtAnnotate, this.showZgtAnnotate,
{this.needAnnotate = false}) { {this.needAnnotate = false}) {
// ID键列表和映射表 if (templateIds.keys.isNotEmpty) {
if (templateIds.isNotEmpty) { templateIdKeys = templateIds.keys.map((e) => int.parse(e)).toList();
templateIdKeys = templateIds.keys.map(int.parse).toList();
templateIdKeyMap = <int, int>{}; templateIdKeyMap = <int, int>{};
for (int i = 0; i < templateIdKeys!.length; i++) { for (var i = 1; i <= templateIdKeys!.length; i++) {
final templateId = templateIdKeys![i]; var theVal = templateIdKeys![i - 1];
templateIdKeyMap![i + 1] = templateId; templateIdKeyMap![i] = theVal;
templateIdKeyMap![templateId] = i + 1; templateIdKeyMap![theVal] = i;
} }
} }
// //
if (students.isNotEmpty) { if (students.isNotEmpty) {
try { var currentStudent = students.firstWhereOrNull((e) => e.id == studentId);
final currentStudent = students.firstWhere((e) => e.id == studentId); if (currentStudent != null) priority = currentStudent.isPriority;
priority = currentStudent.isPriority;
} catch (e) {
//
}
} }
// URL
if (!zgtAnswer.contains(RequestConfig.imgUrl)) { if (!zgtAnswer.contains(RequestConfig.imgUrl)) {
zgtAnswer = '${RequestConfig.imgUrl}$zgtAnswer?$lastAnswerTime'; zgtAnswer = '${RequestConfig.imgUrl}$zgtAnswer?$lastAnswerTime';
} }
// URL if (zgtAnnotate?.isNotEmpty ?? false) {
if (zgtAnnotate?.isNotEmpty == true) { showZgtAnnotate = RequestConfig.imgUrl + zgtAnnotate!; //
showZgtAnnotate = RequestConfig.imgUrl + zgtAnnotate!; if (annotateTime != null) showZgtAnnotate = '${showZgtAnnotate!}?$annotateTime';
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('学生作答图片:${annotatedCount}');
// print('老师批注图片提交数量:${submitCount}'); // print('老师批注图片提交数量:${submitCount}');
} }
@ -154,15 +139,14 @@ class DoPaperDetailsResult {
Map<String, dynamic> toJson() => _$DoPaperDetailsResultToJson(this); Map<String, dynamic> toJson() => _$DoPaperDetailsResultToJson(this);
static List<Map<String, dynamic>> _paperStudentsToJson(List<PaperStudents> examples) => static List<Map<String, dynamic>> _paperStudentsToJson(List<PaperStudents> examples) => examples.map((e) => e.toJson()).toList();
examples.map((e) => e.toJson()).toList();
static List<Map<String, dynamic>> _studentQuestionsToJson(List<StudentQuestions> examples) => static List<Map<String, dynamic>> _studentQuestionsToJson(List<StudentQuestions> examples) => examples.map((e) => e.toJson()).toList();
examples.map((e) => e.toJson()).toList();
static Map<String, dynamic>? _nextPageToJson(NextPage? example) => example?.toJson(); static Map<String, dynamic>? _nextPageToJson(NextPage? example) => example?.toJson();
static Map<String, dynamic>? _lastPageToJson(LastPage? example) => example?.toJson(); static Map<String, dynamic>? _lastPageToJson(LastPage? example) => example?.toJson();
static Map<String, dynamic>? _continuePageToJson(ContinuePage? example) => example?.toJson(); static Map<String, dynamic>? _continuePageToJson(ContinuePage? example) => example?.toJson();
} }
@JsonSerializable() @JsonSerializable()
@ -276,20 +260,22 @@ class NextPage extends Object {
Map<String, dynamic> toJson() => _$NextPageToJson(this); Map<String, dynamic> toJson() => _$NextPageToJson(this);
} }
@JsonSerializable() @JsonSerializable()
class ContinuePage extends Object { class ContinuePage extends Object {
@JsonKey(name: 'templateId') @JsonKey(name: 'templateId')
int templateId; int templateId;
@JsonKey(name: 'studentId') @JsonKey(name: 'studentId')
int studentId; int studentId;
ContinuePage( ContinuePage(this.templateId,this.studentId,);
this.templateId,
this.studentId,
);
factory ContinuePage.fromJson(Map<String, dynamic> srcJson) => _$ContinuePageFromJson(srcJson); factory ContinuePage.fromJson(Map<String, dynamic> srcJson) => _$ContinuePageFromJson(srcJson);
Map<String, dynamic> toJson() => _$ContinuePageToJson(this); 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:convert';
import 'dart:io'; import 'dart:io';
import 'package:dio/dio.dart';
import 'package:get/get.dart' as getx; 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/api/retrofit_client.dart';
import 'package:making_school_asignment_app/common/config/request_config.dart'; import 'package:making_school_asignment_app/common/config/request_config.dart';
import 'package:making_school_asignment_app/common/job/user_info.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/store/user_store.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/routes/app_pages.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 '../job/user_info_detail.dart';
import '../utils/storage.dart'; import '../utils/storage.dart';
@ -41,7 +40,7 @@ class RequestTool {
RequestTool._internal(this._client); RequestTool._internal(this._client);
static RequestTool get instance { static get instance {
if (_instance == null) { if (_instance == null) {
RetrofitClient client = _init(); RetrofitClient client = _init();
_instance = RequestTool._internal(client); _instance = RequestTool._internal(client);
@ -167,7 +166,7 @@ class TheError extends Interceptor {
var errorMap = response.data; var errorMap = response.data;
if (errorMap is String && errorMap.isNotEmpty) { if (errorMap is String && errorMap.length > 0) {
try { try {
var errorModel = jsonDecode(errorMap); var errorModel = jsonDecode(errorMap);
var error = errorModel['error']; var error = errorModel['error'];

View File

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

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,8 @@
import 'dart:io'; import 'dart:io';
import 'package:auto_updater/auto_updater.dart'; import 'package:auto_updater/auto_updater.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_localizations/flutter_localizations.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:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/config/app_config.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/storage.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart'; import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/routes/app_pages.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/config/request_config.dart';
import 'common/utils/app_upgrade/upgradeLogic.dart'; import 'common/utils/app_upgrade/upgradeLogic.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
void main() async { void main() async {
// Get // Get
Get.testMode = true; 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 /// UserStore
await Get.putAsync<UserStore>(() async => UserStore().init()); Get.put<UserStore>(UserStore().init());
Get.put(UpgradeLogic());
WidgetsFlutterBinding.ensureInitialized();
// Windows // Windows
if (Platform.isWindows) { if (Platform.isWindows) {
@ -41,11 +43,9 @@ void main() async {
statusBarColor: Colors.transparent, // statusBarColor: Colors.transparent, //
statusBarIconBrightness: Brightness.light // dark: light 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]); // await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); //
runApp(const MyApp()); runApp(const MyApp());
Future.delayed(const Duration(seconds: 3), () => FlutterNativeSplash.remove());
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
@ -121,13 +121,12 @@ class MyApp extends StatelessWidget {
initialRoute: Routes.startPage, initialRoute: Routes.startPage,
/// ///
initialBinding: MainBinding(),
getPages: AppPages.pages, getPages: AppPages.pages,
builder: EasyLoading.init( builder: EasyLoading.init(
builder: (context, child) { builder: (context, child) {
return MediaQuery( return MediaQuery(
//Setting font does not change with system font size //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( child: Scaffold(
body: GestureDetector(onTap: () => Utils.hideKeyboard(), child: child), 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( child: Container(
padding: EdgeInsets.only(right: 4.5.w), padding: EdgeInsets.only(right: 4.5.w),
alignment: Alignment.center, 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, FontWeight? fontWeight,
TextOverflow overflow = TextOverflow.ellipsis, TextOverflow overflow = TextOverflow.ellipsis,
int maxLines = 1, int maxLines = 1,
double? height,
TextDecoration decoration = TextDecoration.none}) { TextDecoration decoration = TextDecoration.none}) {
return Text( return Text(
text.toString(), text.toString(),
@ -31,7 +30,6 @@ Text quickText(text,
color: color, color: color,
fontWeight: fontWeight, fontWeight: fontWeight,
wordSpacing: wordSpacing, wordSpacing: wordSpacing,
height: height,
), ),
); );
} }

View File

@ -1,20 +1,21 @@
import 'dart:async'; 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:get/get.dart';
import 'package:making_school_asignment_app/common/job/user_info.dart'; import 'package:flutter/material.dart';
import 'package:making_school_asignment_app/common/job/user_info_detail.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; import 'package:flutter_native_splash/flutter_native_splash.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:making_school_asignment_app/routes/app_pages.dart'; import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'package:making_school_asignment_app/common/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 { class StartPage extends StatefulWidget {
const StartPage({super.key}); const StartPage({super.key});
@ -36,13 +37,14 @@ class _StartPageState extends State<StartPage> with RequestToolMixin {
void initState() { void initState() {
super.initState(); super.initState();
Future.delayed(const Duration(seconds: 3), () => FlutterNativeSplash.remove());
// const WorkPage(), // const WorkPage(),
_bodyList = [const HomePage(), const MyInfo()]; _bodyList = [const HomePage(), const MyInfo()];
// APP // APP
WidgetsBinding.instance.addPostFrameCallback((e) { WidgetsBinding.instance.addPostFrameCallback((e) {
/// 40APP /// 40APP
if (!_upgradeLogic.showUpgrade.value && UserStore.to.userDetailInfo.value != null) if (!_upgradeLogic.showUpgrade.value && UserStore.to.userDetailInfo.value != null) _upgradeLogic.getAppUpgrade(context);
_upgradeLogic.getAppUpgrade(context);
}); });
_timer?.cancel(); _timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 40), (e) { _timer = Timer.periodic(const Duration(seconds: 40), (e) {
@ -89,8 +91,7 @@ class _StartPageState extends State<StartPage> with RequestToolMixin {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return PopScope( return WillPopScope(
canPop: false,
child: Scaffold( child: Scaffold(
body: PageView( body: PageView(
controller: _pageController._pageIndexState.pageController, 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)) { if (lastPopTime == null || DateTime.now().difference(lastPopTime!) > const Duration(seconds: 1)) {
lastPopTime = DateTime.now(); lastPopTime = DateTime.now();
ToastUtils.getFluttertoast( ToastUtils.getFluttertoast(context: context, msg: '连续两次返回就退出');
context: context, return Future.value(false);
msg: '连续两次返回就退出',
gravity: ToastGravity.CENTER,
fontSize: 18,
);
} else { } else {
lastPopTime = DateTime.now(); lastPopTime = DateTime.now();
// 退app // 退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_easyloading/flutter_easyloading.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@ -37,7 +35,8 @@ class AnnotateClassLogic extends GetxController with RequestToolMixin {
} }
void getList() async { 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; 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}');*/ print('state.classList[1]=${state.classList[1].finishTime}');*/
@ -62,7 +61,9 @@ class AnnotateClassLogic extends GetxController with RequestToolMixin {
void getAllCorrect(classId) async { void getAllCorrect(classId) async {
EasyLoading.show(status: 'loading...'); EasyLoading.show(status: 'loading...');
try { try {
await getClient().getAllCorrect(state.homeworkId.value, classId).then((e) { await getClient()
.getAllCorrect(state.homeworkId.value, classId)
.then((e) {
getList(); getList();
}); });
} catch (e) { } catch (e) {
@ -107,25 +108,4 @@ class AnnotateClassLogic extends GetxController with RequestToolMixin {
super.dispose(); super.dispose();
refreshController.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/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/annotated_class.dart';
import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart';
import 'package:making_school_asignment_app/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/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/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/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/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/page/home_page/widget/progress_bar.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart'; import 'package:making_school_asignment_app/routes/app_pages.dart';
import 'package:percent_indicator/percent_indicator.dart';
class AnnotateItem extends StatefulWidget { class AnnotateItem extends StatefulWidget {
final String homeworkId; final String homeworkId;
@ -19,13 +20,7 @@ class AnnotateItem extends StatefulWidget {
final double font; final double font;
final String name; final String name;
final AnnotateClassLogic logic; final AnnotateClassLogic logic;
const AnnotateItem( const AnnotateItem({super.key, required this.homeworkId, required this.item, required this.font, required this.name, required this.logic});
{super.key,
required this.homeworkId,
required this.item,
required this.font,
required this.name,
required this.logic});
@override @override
State<AnnotateItem> createState() => _AnnotateItemState(); State<AnnotateItem> createState() => _AnnotateItemState();
@ -164,16 +159,10 @@ class _AnnotateItemState extends State<AnnotateItem> {
Expanded( Expanded(
flex: 4, flex: 4,
child: ItemBtn( child: ItemBtn(
title: title: "收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}",
"收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}",
font: widget.font - 2.sp, font: widget.font - 2.sp,
clickFunction: () { clickFunction: () {
Get.toNamed(Routes.favStudentPage, arguments: { Get.toNamed(Routes.favStudentPage, arguments: {'homeworkName': widget.name, 'classId': widget.item.classId, 'homeworkId': widget.logic.state.homeworkId.value, 'grade': widget.item.grade});
'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( Expanded(
flex: 4, flex: 4,
child: ItemBtn( child: ItemBtn(
title: title: "收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}",
"收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}",
font: widget.font - 2.sp, font: widget.font - 2.sp,
clickFunction: () { clickFunction: () {
Get.toNamed(Routes.favStudentPage, arguments: { Get.toNamed(Routes.favStudentPage, arguments: {'homeworkName': widget.name, 'classId': widget.item.classId, 'homeworkId': widget.logic.state.homeworkId.value, 'grade': widget.item.grade});
'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), padding: EdgeInsets.only(top: 10.r, left: 14.r, right: 14.r),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [quickText('批阅进度', size: widget.font - 2.sp, color: const Color(0xFF8E8E8E)), quickText('${widget.item.annotateRate}%', size: widget.font + 10.sp, color: const Color(0xFF464646))],
quickText('批阅进度', size: widget.font - 2.sp, color: const Color(0xFF8E8E8E)),
quickText('${widget.item.annotateRate}%', size: widget.font + 10.sp, color: const Color(0xFF464646))
],
), ),
), ),
Padding( Padding(
@ -269,27 +249,9 @@ class _AnnotateItemState extends State<AnnotateItem> {
barRadius: Radius.circular(10.r), barRadius: Radius.circular(10.r),
), ),
), ),
ProgressBar( 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),
title: '客观题正确率:', 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),
color: const Color(0xFFADDCA5), 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),
percent: widget.item.kgtCorrectRate / 100,
marginEdg: EdgeInsets.zero,
padingEdg: EdgeInsets.only(top: 8.h, left: 14.r, right: 14.r),
fontSize: widget.font - 2.sp),
ProgressBar(
title: '主观题正确率:',
color: const Color(0xFFADDCA5),
percent: widget.item.zgtCorrectRate / 100,
padingEdg: EdgeInsets.symmetric(horizontal: 10.r),
marginEdg: EdgeInsets.only(top: 8.h),
fontSize: widget.font - 2.sp),
ProgressBar(
title: '总正确率:',
color: const Color(0xFFADDCA5),
percent: widget.item.correctRate / 100,
padingEdg: EdgeInsets.symmetric(horizontal: 10.r),
marginEdg: EdgeInsets.only(top: 8.h),
fontSize: widget.font - 2.sp),
Container( Container(
margin: EdgeInsets.only(top: 10.r), margin: EdgeInsets.only(top: 10.r),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -315,9 +277,7 @@ class _AnnotateItemState extends State<AnnotateItem> {
}, },
child: Container( child: Container(
padding: EdgeInsets.symmetric(vertical: 10.r), padding: EdgeInsets.symmetric(vertical: 10.r),
decoration: BoxDecoration( decoration: BoxDecoration(border: Border(right: BorderSide(width: 1.r, color: const Color.fromRGBO(221, 221, 221, 1)))),
border: Border(
right: BorderSide(width: 1.r, color: const Color.fromRGBO(221, 221, 221, 1)))),
alignment: Alignment.center, alignment: Alignment.center,
child: quickText('数据快查', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font), child: quickText('数据快查', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font),
), ),
@ -338,20 +298,29 @@ class _AnnotateItemState extends State<AnnotateItem> {
: [ : [
Expanded( Expanded(
child: InkWell( child: InkWell(
onTap: () => easyThrottle('TO_GO_REVIEWHOMEWORK', () { onTap: () => easyThrottle('TO_GO_REVIEWHOMEWORK', () async {
/// await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
widget.logic.toGoReviewhomework( WidgetsBinding.instance.addPostFrameCallback((_) {
homeworkId: widget.homeworkId, Future.delayed(const Duration(milliseconds: 300), () {
homeworkName: widget.name, Get.toNamed(Routes.reviewHomework, arguments: {
classId: itemData.classId, 'homeworkId': widget.homeworkId,
subject: widget.logic.state.subject, '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( child: Container(
padding: EdgeInsets.symmetric(vertical: 10.r), padding: EdgeInsets.symmetric(vertical: 10.r),
decoration: BoxDecoration( decoration: BoxDecoration(border: Border(right: BorderSide(width: 1.r, color: const Color.fromRGBO(221, 221, 221, 1)))),
border: Border(
right: BorderSide(width: 1.r, color: const Color.fromRGBO(221, 221, 221, 1)))),
alignment: Alignment.center, alignment: Alignment.center,
child: quickText('批阅', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font), child: quickText('批阅', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font),
), ),

View File

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

View File

@ -8,7 +8,7 @@ class ClassStudentState {
late RxString title = ''.obs; late RxString title = ''.obs;
late final String classId; late final String classId;
late final int? subject; late final int subject;
late RxList<StudentItem> studentList = RxList(); late RxList<StudentItem> studentList = RxList();
late String page = ''; late String page = '';
late bool isClicking = true; 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'; import 'fav_student_logic.dart';
class FavStudentPage extends StatefulWidget { class FavStudentPage extends StatefulWidget {
const FavStudentPage({super.key}); const FavStudentPage({Key? key}) : super(key: key);
@override @override
State<FavStudentPage> createState() => _FavStudentPageState(); State<FavStudentPage> createState() => _FavStudentPageState();
@ -20,7 +20,9 @@ class FavStudentPage extends StatefulWidget {
class _FavStudentPageState extends State<FavStudentPage> { class _FavStudentPageState extends State<FavStudentPage> {
final logic = Get.find<FavStudentLogic>(); 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) { void showStudentDialog(BuildContext context, HomeworkFavs item, List groups) {
showDialog( showDialog(
@ -29,13 +31,16 @@ class _FavStudentPageState extends State<FavStudentPage> {
return AlertDialog( return AlertDialog(
insetPadding: EdgeInsets.all(25.r), insetPadding: EdgeInsets.all(25.r),
content: FavoriteStudentDialog( 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), 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 { Future<bool> confirmDialog() async {
return await showDialog( return await showDialog(
context: context, context: context,
@ -88,7 +93,6 @@ class _FavStudentPageState extends State<FavStudentPage> {
), ),
); );
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -109,7 +113,8 @@ class _FavStudentPageState extends State<FavStudentPage> {
ReturnToHomepage(), ReturnToHomepage(),
], ],
), ),
body: OrientationBuilder(builder: (BuildContext context, Orientation orientation) { body:OrientationBuilder(
builder: (BuildContext context, Orientation orientation){
return Column( return Column(
children: [ children: [
Padding( Padding(
@ -122,17 +127,16 @@ class _FavStudentPageState extends State<FavStudentPage> {
child: Obx(() { child: Obx(() {
return Text( return Text(
state.homeworkName.value, state.homeworkName.value,
style: TextStyle( style:
fontSize: 14.sp, TextStyle(fontSize: 14.sp, color: const Color(0xFF3C3C3C),),
color: const Color(0xFF3C3C3C),
),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
); );
}), }),
), ),
// //
Container( Container(
padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 10.w), padding: EdgeInsets.symmetric(
vertical: 10.h, horizontal: 10.w),
child: Row( child: Row(
children: [ children: [
Obx(() { Obx(() {
@ -140,7 +144,7 @@ class _FavStudentPageState extends State<FavStudentPage> {
bgColor: Colors.white, bgColor: Colors.white,
involveClasses: state.involveClasses.value, involveClasses: state.involveClasses.value,
classData: state.classData.value, classData: state.classData.value,
onClassSelected: (AnnotatedClass item) { call: (AnnotatedClass item) {
state.classData.value = item; state.classData.value = item;
if (item.grade == -1) state.classData.value = state.defaultClass; if (item.grade == -1) state.classData.value = state.defaultClass;
logic.getList(); logic.getList();
@ -153,74 +157,105 @@ class _FavStudentPageState extends State<FavStudentPage> {
), ),
), ),
Container( Container(
width: MediaQuery.of(context).size.width, width: MediaQuery
.of(context)
.size
.width,
height: 1.r, height: 1.r,
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: Color(0xFFEEEEEE), color: Color(0xFFEEEEEE),
), ),
), ),
Obx(() { Obx((){
return state.favList.isNotEmpty return state.favList.isNotEmpty
? Expanded( ? Expanded(
child: Utils.isPad() child: Utils.isPad()
? Padding( ? Padding(
padding: EdgeInsets.only(top: 10.r, bottom: 8.r, left: 14.r, right: 14.r), padding: EdgeInsets.only(
top: 10.r,
bottom: 8.r,
left: 14.r,
right: 14.r),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(state.favList.length, (index) { children:
List.generate(state.favList.length, (index) {
var item = state.favList[index]; var item = state.favList[index];
return Padding( return Padding(
padding: EdgeInsets.only(bottom: 8.r), padding: EdgeInsets.only(bottom: 8.r),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
CrossAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: EdgeInsets.only(bottom: 5.r), padding:
EdgeInsets.only(bottom: 5.r),
child: Text( child: Text(
'${item['questionPage']}', '${item['questionPage']}',
style: style: TextStyle(
TextStyle(fontSize: 12.sp, color: Theme.of(context).primaryColor), fontSize: 12.sp,
color:Theme.of(context).primaryColor),
), ),
), ),
GridView( GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, crossAxisCount: 2,
mainAxisSpacing: 8.r, mainAxisSpacing: 8.r,
crossAxisSpacing: 10.r, crossAxisSpacing: 10.r,
childAspectRatio: 556 / 112, childAspectRatio: 556 / 112,
), ),
shrinkWrap: true, shrinkWrap: true,
children: List.generate(item['list'].length, (i) { children: List.generate(
item['list'].length, (i) {
HomeworkFavs student = item['list'][i]; HomeworkFavs student = item['list'][i];
return Container( return Container(
padding: EdgeInsets.symmetric(vertical: 5.r, horizontal: 10.r), padding: EdgeInsets.symmetric(
vertical: 5.r,
horizontal: 10.r),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(6.r)), borderRadius:
BorderRadius.all(
Radius.circular(
6.r)),
), ),
child: InkWell( child: InkWell(
onTap: () { onTap: () {
showStudentDialog(context, student, state.favList); showStudentDialog(context,
student, state.favList);
}, },
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [ children: [
quickText(student.studentName, quickText(
color: const Color(0xFF333333), size: 12.sp), student.studentName,
Expanded(child: Container()), color: const Color(
0xFF333333),
size: 12.sp),
Expanded(
child: Container()),
Padding( Padding(
padding: EdgeInsets.only(right: 8.r), padding:
EdgeInsets.only(
right: 8.r),
child: Text( child: Text(
student.className!, student.className!,
style: TextStyle( style: TextStyle(
fontSize: 12.sp, color: const Color(0xFF666666)), fontSize: 12.sp,
color: const Color(
0xFF666666)),
), ),
), ),
InkWell( InkWell(
onTap: () async { onTap: () async {
var confim = await confirmDialog(); var confim =
await confirmDialog();
if (confim) { if (confim) {
logic.getDelete(student); logic.getDelete(
student);
} }
}, },
child: Image.asset( child: Image.asset(
@ -244,15 +279,22 @@ class _FavStudentPageState extends State<FavStudentPage> {
itemBuilder: (context, index) { itemBuilder: (context, index) {
var item = state.favList[index]; var item = state.favList[index];
return Padding( return Padding(
padding: EdgeInsets.only(top: 10.r, bottom: 8.r, left: 14.r, right: 14.r), padding: EdgeInsets.only(
top: 10.r,
bottom: 8.r,
left: 14.r,
right: 14.r),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment:
CrossAxisAlignment.start,
children: [ children: [
Padding( Padding(
padding: EdgeInsets.only(bottom: 5.r), padding: EdgeInsets.only(bottom: 5.r),
child: Text( child: Text(
'${item['questionPage']}', '${item['questionPage']}',
style: TextStyle(fontSize: 14.sp, color: Theme.of(context).primaryColor), style: TextStyle(
fontSize: 14.sp,
color:Theme.of(context).primaryColor),
), ),
), ),
ListView.builder( ListView.builder(
@ -260,32 +302,43 @@ class _FavStudentPageState extends State<FavStudentPage> {
HomeworkFavs student = item['list'][i]; HomeworkFavs student = item['list'][i];
return InkWell( return InkWell(
onTap: () { onTap: () {
showStudentDialog(context, student, state.favList); showStudentDialog(
context, student, state.favList);
}, },
child: Container( child: Container(
padding: EdgeInsets.symmetric(vertical: 5.r, horizontal: 10.r), padding: EdgeInsets.symmetric(
vertical: 5.r,
horizontal: 10.r),
margin: EdgeInsets.only(top: 5.r), margin: EdgeInsets.only(top: 5.r),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(6.r)), borderRadius: BorderRadius.all(
Radius.circular(6.r)),
), ),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [ children: [
quickText(student.studentName, quickText(student.studentName,
color: const Color(0xFF333333), size: 14.sp), color: const Color(0xFF333333),
size: 14.sp),
Expanded(child: Container()), Expanded(child: Container()),
Padding( Padding(
padding: EdgeInsets.only(right: 8.r), padding: EdgeInsets.only(
right: 8.r),
child: Text( child: Text(
student.className!, student.className!,
style: style: TextStyle(
TextStyle(fontSize: 14.sp, color: const Color(0xFF666666)), fontSize: 14.sp,
color: const Color(
0xFF666666)),
), ),
), ),
InkWell( InkWell(
onTap: () async { onTap: () async {
var confim = await confirmDialog(); var confim =
await confirmDialog();
if (confim) { if (confim) {
logic.getDelete(student); logic.getDelete(student);
} }
@ -312,13 +365,20 @@ class _FavStudentPageState extends State<FavStudentPage> {
), ),
) )
: Padding( : Padding(
padding: EdgeInsets.only(top: MediaQuery.of(context).size.height / 2 - 200.r), padding: EdgeInsets.only(
top: MediaQuery
.of(context)
.size
.height / 2 - 200.r),
child: const MyEmptyWidget(), child: const MyEmptyWidget(),
); );
}), }),
], ],
); );
})); }
)
);
} }
@override @override

View File

@ -1,5 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:ffi';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@ -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/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/anti_shake_throttling.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart'; import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import '../configuration_files/index.dart'; import '../configuration_files/index.dart';
@ -18,8 +19,7 @@ class BottomAnnotationSwitch extends StatefulWidget {
State<BottomAnnotationSwitch> createState() => _BottomAnnotationSwitchJobState(); State<BottomAnnotationSwitch> createState() => _BottomAnnotationSwitchJobState();
} }
class _BottomAnnotationSwitchJobState extends State<BottomAnnotationSwitch> class _BottomAnnotationSwitchJobState extends State<BottomAnnotationSwitch> with SingleTickerProviderStateMixin, EventBusMixin<BottomOperationBar> {
with SingleTickerProviderStateMixin, EventBusMixin<BottomOperationBar> {
late AnimationController _animationController; // late AnimationController _animationController; //
final _homeworkLogic = Get.find<HomeworkReviewLogic>(); final _homeworkLogic = Get.find<HomeworkReviewLogic>();
final _logicControl = Get.find<HomeworkReviewLogic>().annotationState; final _logicControl = Get.find<HomeworkReviewLogic>().annotationState;
@ -61,23 +61,15 @@ class _BottomAnnotationSwitchJobState extends State<BottomAnnotationSwitch>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SafeArea( double iconSize = 18.sp;
left: false, Color actionColor = Colors.white;
right: false, Color defaultColor = const Color.fromRGBO(132, 146, 163, 1);
top: false,
child: Container( return Container(
width: double.infinity, width: double.infinity,
height: _animationController.value * 70.h, height: _animationController.value * 64.h,
decoration: BoxDecoration(
color: const Color.fromRGBO(83, 83, 83, 1), color: const Color.fromRGBO(83, 83, 83, 1),
boxShadow: [ // padding: EdgeInsets.symmetric(vertical: 1.h),
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
offset: const Offset(0, -2),
),
],
),
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
@ -90,83 +82,105 @@ class _BottomAnnotationSwitchJobState extends State<BottomAnnotationSwitch>
children: [ children: [
// //
Expanded( Expanded(
child: _buildActionButton( child: SizedBox(
'全对', width: double.infinity,
Icons.check_circle_outline, height: double.infinity,
() => easyThrottle('homework_bottom_operation_bar_scoring_related', child: TextButton(
() => _homeworkLogic.allPairs(context)), child: quickText('全 对', color: Colors.white, size: 12.sp),
isEnabled: !_homeworkLogic.state.submitLoading.value, onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.allPairs(context)),
isPrimary: true,
), ),
), ),
Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)), ),
Container(width: 0.3.w, height: double.infinity, color: Colors.white),
// //
Expanded( Expanded(
child: Obx(() => _buildIconButton( child: SizedBox(
width: double.infinity,
height: double.infinity,
child: IconButton(
icon: Obx(() {
return Icon(
const IconData(0xe635, fontFamily: "AlibabaIcon"), const IconData(0xe635, fontFamily: "AlibabaIcon"),
() => easyThrottle('homework_bottom_action_bar_annotations', () { size: iconSize,
// color: _logicControl.pen.value ? Theme.of(context).primaryColor : defaultColor,
_logicControl.gestureMove.value = false; );
_logicControl.pen.value = true; }),
onPressed: () => easyThrottle('homework_bottom_action_bar_annotations', () {
_logicControl.gestureMove.value = false;
_logicControl.pen.value = !_logicControl.pen.value;
}), }),
isActive: _logicControl.pen.value,
tooltip: '注解笔',
)),
), ),
Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)), ),
),
Container(width: 0.3.w, height: double.infinity, color: Colors.white),
// //
Expanded( Expanded(
child: Obx(() => _buildIconButton( child: SizedBox(
width: double.infinity,
height: double.infinity,
child: IconButton(
icon: Obx(
() {
return Icon(
const IconData(0xe636, fontFamily: "AlibabaIcon"), const IconData(0xe636, fontFamily: "AlibabaIcon"),
() => easyThrottle('homework_bottom_action_bar_annotations', () { size: iconSize,
// color: _logicControl.gestureMove.value ? actionColor : defaultColor,
);
},
),
onPressed: () => easyThrottle('homework_bottom_action_bar_annotations', () {
_logicControl.pen.value = false; _logicControl.pen.value = false;
_logicControl.gestureMove.value = true; _logicControl.gestureMove.value = !_logicControl.gestureMove.value;
}), }),
isActive: _logicControl.gestureMove.value, ),
tooltip: '滑动试题', ),
)),
), ),
], ],
), ),
), ),
Container(width: double.infinity, color: Colors.white.withOpacity(0.3), height: 0.5.h), Container(width: double.infinity, color: Colors.white, height: 0.35.h),
Expanded( Expanded(
child: Row( child: Row(
children: [ children: [
// //
Expanded( Expanded(
child: _buildActionButton( child: SizedBox(
'全错', width: double.infinity,
Icons.cancel_outlined, height: double.infinity,
() => easyThrottle('homework_bottom_operation_bar_scoring_related', child: TextButton(
() => _homeworkLogic.allWrongRating(context)), onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.allWrongRating(context)),
isEnabled: !_homeworkLogic.state.submitLoading.value, child: quickText('全 错', color: Colors.white, size: 12.sp),
isPrimary: false,
), ),
), ),
Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)), ),
Container(width: 0.3.w, height: double.infinity, color: Colors.white),
// //
Expanded( Expanded(
child: _buildIconButton( child: SizedBox(
const IconData(0xe638, fontFamily: "AlibabaIcon"), width: double.infinity,
() => easyThrottle( height: double.infinity,
child: IconButton(
onPressed: () => easyThrottle(
'homework_bottom_action_bar_annotations', 'homework_bottom_action_bar_annotations',
() => eventFire(model: BottomOperationBar(revokeAll: false, revokePreStep: true)), () => eventFire(model: BottomOperationBar(revokeAll: false, revokePreStep: true)),
), ),
tooltip: '撤销上一步', icon: Icon(const IconData(0xe638, fontFamily: "AlibabaIcon"), size: iconSize, color: defaultColor),
), ),
), ),
Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)), ),
Container(width: 0.3.w, height: double.infinity, color: Colors.white),
// //
Expanded( Expanded(
child: _buildIconButton( child: SizedBox(
const IconData(0xe637, fontFamily: "AlibabaIcon"), width: double.infinity,
() => easyThrottle( height: double.infinity,
child: IconButton(
icon: Icon(const IconData(0xe637, fontFamily: "AlibabaIcon"), size: iconSize, color: defaultColor),
onPressed: () => easyThrottle(
'homework_bottom_action_bar_annotations', 'homework_bottom_action_bar_annotations',
() => eventFire(model: BottomOperationBar(revokeAll: true, revokePreStep: false)), () => eventFire(model: BottomOperationBar(revokeAll: true, revokePreStep: false)),
), ),
tooltip: '全部撤销', ),
), ),
), ),
], ],
@ -175,161 +189,51 @@ class _BottomAnnotationSwitchJobState extends State<BottomAnnotationSwitch>
], ],
), ),
), ),
Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)), Container(width: 0.3.w, height: double.infinity, color: Colors.white),
Expanded( Expanded(
flex: 3, flex: 3,
child: Row( child: Row(
children: [ children: [
Expanded( Expanded(
child: _buildActionButton( child: SizedBox(
'取消', width: double.infinity,
Icons.clear, height: double.infinity,
() => easyThrottle( child: TextButton(
'homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.cancelAllRatings()), onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.cancelAllRatings()),
isEnabled: true, child: quickText('取 消', size: 14.sp, color: Colors.white),
isPrimary: false,
isSecondary: true,
), ),
), ),
Container(width: 0.5.w, height: double.infinity, color: Colors.white.withOpacity(0.3)), ),
Container(width: 0.3.w, height: double.infinity, color: Colors.white),
Expanded( Expanded(
child: Obx(() { child: SizedBox(
final submitLoading = _homeworkLogic.state.submitLoading.value; width: double.infinity,
return _buildActionButton( height: double.infinity,
'提交', child: TextButton(
Icons.send, onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.submit(context)),
() => easyThrottle( child: Row(
'homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.submit(context)), mainAxisAlignment: MainAxisAlignment.center,
isEnabled: !submitLoading, crossAxisAlignment: CrossAxisAlignment.center,
isPrimary: true, children: [
isLoading: submitLoading, 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),
],
),
),
],
),
));
}
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:functional_widget_annotation/functional_widget_annotation.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart'; import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart';
import 'package:making_school_asignment_app/common/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/anti_shake_throttling.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/common/utils/utils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart'; import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart'; import 'package:making_school_asignment_app/routes/app_pages.dart';
@ -61,8 +61,7 @@ class DropdownSwitchStudentsType extends StatelessWidget {
items: sateData.value?.templateIdKeys?.map((e) { items: sateData.value?.templateIdKeys?.map((e) {
return DropdownMenuItem( return DropdownMenuItem(
value: e, value: e,
child: quickText('${sateData.value!.templateIdKeyMap![e]}', child: quickText('${sateData.value!.templateIdKeyMap![e]}', color: const Color.fromRGBO(79, 79, 79, 1), size: 14.sp),
color: const Color.fromRGBO(79, 79, 79, 1), size: 14.sp),
); );
}).toList(), }).toList(),
onChanged: (value) { onChanged: (value) {
@ -78,14 +77,7 @@ class DropdownSwitchStudentsType extends StatelessWidget {
final students = sateData.value?.students ?? []; final students = sateData.value?.students ?? [];
// //
PaperStudents? currentStudent; final currentStudent = currentStudentId != null ? students.firstWhereOrNull((e) => e.id == currentStudentId) : null;
if (currentStudentId != null) {
try {
currentStudent = students.firstWhere((e) => e.id == currentStudentId);
} catch (e) {
currentStudent = null;
}
}
final studentName = currentStudent?.name ?? '当前学生'; final studentName = currentStudent?.name ?? '当前学生';
final questionNumber = templateIdKeyMap?[value] ?? '当前选择页'; final questionNumber = templateIdKeyMap?[value] ?? '当前选择页';
@ -103,7 +95,7 @@ class DropdownSwitchStudentsType extends StatelessWidget {
}), }),
), ),
), ),
SizedBox(width: 8.w), const Expanded(flex: 1, child: SizedBox()),
Expanded( Expanded(
flex: 3, flex: 3,
child: Stack( child: Stack(
@ -128,9 +120,7 @@ class DropdownSwitchStudentsType extends StatelessWidget {
alignment: const FractionalOffset(0, 0.62), alignment: const FractionalOffset(0, 0.62),
children: [ children: [
Container( Container(
padding: sateData.value?.studentId != e.id && e.isPriority padding: sateData.value?.studentId != e.id && e.isPriority ? EdgeInsets.only(left: 14.w) : null,
? EdgeInsets.only(left: 14.w)
: null,
child: quickText( child: quickText(
e.name, e.name,
size: 14.sp, size: 14.sp,
@ -144,9 +134,7 @@ class DropdownSwitchStudentsType extends StatelessWidget {
Icon( Icon(
const IconData(0xe63d, fontFamily: "AlibabaIcon"), const IconData(0xe63d, fontFamily: "AlibabaIcon"),
size: 12.sp, size: 12.sp,
color: e.isPriority color: e.isPriority ? Theme.of(context).primaryColor : const Color.fromRGBO(164, 164, 164, 1),
? Theme.of(context).primaryColor
: const Color.fromRGBO(164, 164, 164, 1),
), ),
quickText('优先', size: 4.sp, color: Colors.white), quickText('优先', size: 4.sp, color: Colors.white),
], ],
@ -173,9 +161,7 @@ class DropdownSwitchStudentsType extends StatelessWidget {
return Icon( return Icon(
const IconData(0xe63d, fontFamily: "AlibabaIcon"), const IconData(0xe63d, fontFamily: "AlibabaIcon"),
size: 12.sp, size: 12.sp,
color: sateData.value?.priority ?? false color: sateData.value?.priority ?? false ? Theme.of(context).primaryColor : const Color.fromRGBO(164, 164, 164, 1),
? Theme.of(context).primaryColor
: const Color.fromRGBO(164, 164, 164, 1),
); );
}), }),
quickText('优先', size: 4.sp, color: Colors.white), quickText('优先', size: 4.sp, color: Colors.white),
@ -187,9 +173,9 @@ class DropdownSwitchStudentsType extends StatelessWidget {
), ),
// const Expanded(flex: 1, child: SizedBox()), // const Expanded(flex: 1, child: SizedBox()),
SizedBox(width: 8.w), SizedBox(width: 8.w),
const Expanded( Expanded(
flex: 5, flex: isPad() ? 4 : 5,
child: Row( child: const Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ children: [
@ -222,8 +208,7 @@ Widget $studentHandwriting(BuildContext context) {
if (templateIdKeyMap != null && templateId != null) { if (templateIdKeyMap != null && templateId != null) {
pageNum = templateIdKeyMap[templateId]; pageNum = templateIdKeyMap[templateId];
} }
await showAnswerHandwriting(context, await showAnswerHandwriting(context, homeworkId: homeworkId, studentId: studentId, templateId: templateId, pageNum: pageNum);
homeworkId: homeworkId, studentId: studentId, templateId: templateId, pageNum: pageNum);
ToastUtils.dismiss(); ToastUtils.dismiss();
}, },
), ),
@ -253,10 +238,7 @@ Widget $continueToReview(BuildContext context, {bool isFloatingAction = false})
int? annotatedCount = data?.annotatedCount; // int? annotatedCount = data?.annotatedCount; //
// || (submitCount == annotatedCount || (param.templateId == null && param.studentId == null)) // || (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 ? true : data.totalUnAnnotateCount <= 0) ) return const SizedBox();
if (data == null || if (data == null || (data.needAnnotate ? (data.continuePage == null ? true : data.continuePage!.templateId == data.templateId) : data.totalUnAnnotateCount <= 0)) return const SizedBox();
(data.needAnnotate
? (data.continuePage == null ? true : data.continuePage!.templateId == data.templateId)
: data.totalUnAnnotateCount <= 0)) return const SizedBox();
callFun() => easyThrottle( callFun() => easyThrottle(
'DO_PAPERS_JOB_CONTINUE_TO_REVIEW', 'DO_PAPERS_JOB_CONTINUE_TO_REVIEW',
() { () {
@ -307,18 +289,10 @@ Widget $historyHomework(BuildContext context) {
int? studentId = sateData.value?.studentId; int? studentId = sateData.value?.studentId;
if (kDebugMode) print(studentId); if (kDebugMode) print(studentId);
if (studentId == null || (sateData.value?.students.isEmpty ?? true)) return; if (studentId == null || (sateData.value?.students.isEmpty ?? true)) return;
PaperStudents? currentStudent; var currentStudent = sateData.value!.students.firstWhereOrNull((e) => e.id == studentId);
try { if (currentStudent == null) return;
currentStudent = sateData.value!.students.firstWhere((e) => e.id == studentId);
} catch (e) {
return;
}
var theState = Get.find<HomeworkReviewLogic>().state; var theState = Get.find<HomeworkReviewLogic>().state;
Get.toNamed(Routes.studentWorkDetailPage, arguments: { Get.toNamed(Routes.studentWorkDetailPage, arguments: {'studentId': studentId, 'studentName': currentStudent.name, 'subject': theState.param.value.subject});
'studentId': studentId,
'studentName': currentStudent.name,
'subject': theState.param.value.subject
});
}), }),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,

View File

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

View File

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

View File

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

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:async';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:device_info_plus/device_info_plus.dart'; 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/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.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/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_param.dart';
import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_result.dart'; import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_result.dart';
@ -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/permission_describe_util.dart';
import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; import 'package:making_school_asignment_app/common/utils/toast_utils.dart';
import 'package:making_school_asignment_app/common/utils/upload_oss_img_utils.dart'; import 'package:making_school_asignment_app/common/utils/upload_oss_img_utils.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:zoom_widget/zoom_widget.dart' as zoomWidget;
import 'zoom_logic.dart'; import 'zoom_logic.dart';
@ -34,7 +35,7 @@ class HomeworkReviewState {
late Rx<DoPaperDetailsResult?> data = Rx<DoPaperDetailsResult?>(null); late Rx<DoPaperDetailsResult?> data = Rx<DoPaperDetailsResult?>(null);
late Rx<List<StudentQuestions>?> studentQuestions = Rx<List<StudentQuestions>?>(null); late Rx<List<StudentQuestions>?> studentQuestions = Rx<List<StudentQuestions>?>(null);
late Rx<double> slide = 0.0.obs; // late Rx<double> slide = 0.0.obs; //
bool? panQuestView; bool? panQuestView = null;
// late Rx<TestQuestionsImageInfo?> imageScale; // late Rx<TestQuestionsImageInfo?> imageScale;
// late Rx<TestQuestionsImageInfo?> imageScaleZoom = Rx<TestQuestionsImageInfo?>(null); // late Rx<TestQuestionsImageInfo?> imageScaleZoom = Rx<TestQuestionsImageInfo?>(null);
@ -79,19 +80,18 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
late StreamSubscription<DoPaperDetailsResult?> _dataListen; late StreamSubscription<DoPaperDetailsResult?> _dataListen;
final HomeworkReviewState state = HomeworkReviewState(); final HomeworkReviewState state = HomeworkReviewState();
final HomeworkReviewAnnotationsControlState annotationState = HomeworkReviewAnnotationsControlState(); final HomeworkReviewAnnotationsControlState annotationState = HomeworkReviewAnnotationsControlState();
double appBarHeight = kToolbarHeight; double appBarHeight = 56;
StreamSubscription<TestQuestionsImageInfo?>? imageScaleZoomStream; StreamSubscription<TestQuestionsImageInfo?>? imageScaleZoomStream;
late final zoomWidget.TransformationController zoomController;
@override @override
void onInit() { void onInit() {
appBarHeight = MediaQuery.of(Get.context!).padding.top; appBarHeight = MediaQuery.of(Get.context!).padding.top;
print("appBarHeight $appBarHeight");
// WidgetsFlutterBinding.ensureInitialized(); // WidgetsFlutterBinding.ensureInitialized();
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); // // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); //
zoomController = zoomWidget.TransformationController();
state.param = DoPaperDetailsParam( state.param = DoPaperDetailsParam(
homeworkId: Get.arguments['homeworkId'], homeworkId: Get.arguments['homeworkId'],
homeworkName: Get.arguments['homeworkName'], homeworkName: Get.arguments['homeworkName'],
@ -107,6 +107,8 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
if (e == null) return; if (e == null) return;
var zoomState = zoomLogic.zoomState; var zoomState = zoomLogic.zoomState;
final currentTemplateId = zoomState.zoomFile.value?.templateId; // ID final currentTemplateId = zoomState.zoomFile.value?.templateId; // ID
if (currentTemplateId != null && currentTemplateId != e.templateId) { if (currentTemplateId != null && currentTemplateId != e.templateId) {
// zoom zoom文件 // zoom zoom文件
@ -131,10 +133,9 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
void onReady() { void onReady() {
Future.delayed(Duration.zero, () { Future.delayed(Duration.zero, () {
DeviceInfoPlugin().androidInfo.then((androidInfo) { DeviceInfoPlugin().androidInfo.then((androidInfo) {
Permission storagePermission = Permission storagePermission = androidInfo.version.sdkInt >= 33 ? Permission.manageExternalStorage : Permission.storage;
androidInfo.version.sdkInt >= 33 ? Permission.manageExternalStorage : Permission.storage;
PermissionDescribeUtil.instance.toLaunchPermissionRequest( PermissionDescribeUtil.instance.toLaunchPermissionRequest(
Get.context!, Get.context,
title: '储存权限请求', title: '储存权限请求',
describe: "为了提供更好的服务,需要获取到存储权限用于保存批阅痕迹并上传", describe: "为了提供更好的服务,需要获取到存储权限用于保存批阅痕迹并上传",
permissions: [storagePermission], permissions: [storagePermission],
@ -147,8 +148,7 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
@override @override
void onClose() { void onClose() {
zoomController.dispose(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top]); //
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top]); //
eventCancel(); eventCancel();
_dataListen.cancel(); _dataListen.cancel();
_paramListen.cancel(); _paramListen.cancel();
@ -157,13 +157,17 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
} }
void getData() async { void getData() async {
//
if (state.submitLoading.value) return;
var timerControl = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading()); var timerControl = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading());
try { try {
DoPaperDetailsResult data = await getClient().getDoPaperDetails(state.param.value); DoPaperDetailsResult data = await getClient().getDoPaperDetails(state.param.value);
// var studentQuestions = data.studentQuestions;
// // 0
// for (var i = 0; i < studentQuestions.length; i++) {
// var item = studentQuestions[i];
// item.topHeight = itemPre.height;
// }
state.getDataError.value = false; state.getDataError.value = false;
state.handwritings = []; state.handwritings = [];
@ -174,8 +178,8 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
state.data.value = data; state.data.value = data;
} catch (e) { } catch (e) {
print('获取数据报错了:$e'); print('获取数据报错了:$e');
// ToastUtils.showError('未获取到试题数据,请重试');
state.getDataError.value = true; state.getDataError.value = true;
ToastUtils.showError('获取试题数据失败,请检查网络连接后重试');
} finally { } finally {
if (timerControl.isActive) timerControl.cancel(); if (timerControl.isActive) timerControl.cancel();
ToastUtils.dismiss(); ToastUtils.dismiss();
@ -229,8 +233,7 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
if (data == null) return null; if (data == null) return null;
// OSS url // OSS url
String imgKey = UploadOssImgUtils.getInstance() String imgKey = UploadOssImgUtils.getInstance().setImgKey(param.homeworkId, data.studentId.toString(), data.templateId.toString());
.setImgKey(param.homeworkId, data.studentId.toString(), data.templateId.toString());
var resUrl = await getClient().getOssPresignedUri(imgKey); var resUrl = await getClient().getOssPresignedUri(imgKey);
if (resUrl == null) return null; if (resUrl == null) return null;
@ -273,27 +276,17 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
ToastUtils.showInfo("正在提交批阅数据,请勿重复操作"); ToastUtils.showInfo("正在提交批阅数据,请勿重复操作");
return; return;
} }
state.submitLoading.value = true; state.submitLoading.value = true;
var data = state.data.value; var data = state.data.value;
if (data == null) { if (data == null) return;
ToastUtils.showError('数据异常,请重新加载');
return;
}
if ((state.data.value?.studentQuestions.isEmpty ?? true) || (state.studentQuestions.value?.isEmpty ?? true)) {
ToastUtils.showError('没有可批阅的试题');
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(); var studentQuestions = state.studentQuestions.value!.where((e) => e.useTime != null && e.useTime! > 0).toList();
// //
try { var noRatingElement = studentQuestions.firstWhereOrNull((e) => e.studentScore == null);
var noRatingElement = studentQuestions.firstWhere((e) => e.studentScore == null); if (noRatingElement != null) {
ToastUtils.showInfo('${noRatingElement.questionNo}题请评分'); ToastUtils.showInfo('${noRatingElement.questionNo}题请评分');
return; return;
} catch (e) {
//
} }
// //
@ -323,13 +316,35 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
if (totalUnAnnotateCount <= 0) { if (totalUnAnnotateCount <= 0) {
// //
if (!state.lastQuestionPrompt) { 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 { } else {
ToastUtils.showSuccess("批阅已提交", duration: const Duration(milliseconds: 800)); ToastUtils.showSuccess("提交", duration: const Duration(milliseconds: 800));
} }
return; return;
} }
var newParams = DoPaperDetailsParam.fromJson(state.param.value.toJson()); var newParams = DoPaperDetailsParam.fromJson(state.param.value.toJson());
if (totalUnAnnotateCount > 0) { if (totalUnAnnotateCount > 0) {
// //
@ -337,52 +352,14 @@ class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBus
newParams.studentId = null; newParams.studentId = null;
} }
state.param.value = newParams; state.param.value = newParams;
ToastUtils.showSuccess("批阅已提交");
}); });
} catch (e) { } catch (_) {
print("批阅提交报错 $e"); print("批阅提交报错 $_");
ToastUtils.showError('提交失败,请检查网络连接后重试');
} finally { } finally {
state.submitLoading.value = false; 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 { Future<void> toFavorite() async {
try { try {
var data = state.data.value!; var data = state.data.value!;

View File

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

View File

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

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/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/MyEmptyWidget.dart';
import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart';
import 'package:making_school_asignment_app/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/page/home_page/children/job_report/widget/dropdown_selection.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/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/personnel_data_overview.dart';
import 'package:making_school_asignment_app/page/home_page/children/job_report/widget/top_count.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( return DropdownSelection(
involveClasses: state.involveClasses.value, involveClasses: state.involveClasses.value,
classData: state.classData.value, classData: state.classData.value,
onClassSelected: (AnnotatedClass item) { call: (AnnotatedClass item) {
state.classData.value = item; state.classData.value = item;
if (item.grade == -1) state.classData.value = state.defaultClass; if (item.grade == -1) state.classData.value = state.defaultClass;
logic.getWorkData(); logic.getWorkData();
@ -75,8 +75,7 @@ class _JobReportPageState extends State<JobReportPage> {
), ),
), ),
// //
TopCount( TopCount(state.dataCount, state.classData == null ? '' : state.classData.value.className, state.homeworkId.value, state.subject),
state.dataCount, state.classData.value.className ?? '', state.homeworkId.value, state.subject),
// //
KgtZgtTable( KgtZgtTable(
studentCount: state.dataCount.studentCount!, studentCount: state.dataCount.studentCount!,
@ -95,7 +94,7 @@ class _JobReportPageState extends State<JobReportPage> {
child: KnowledgePoint( child: KnowledgePoint(
knowsList: state.knowsList, knowsList: state.knowsList,
data: state.homeData, data: state.homeData,
className: state.classData.value.className ?? '', className: state.classData.value.className,
homeworkId: state.homeworkId.value, homeworkId: state.homeworkId.value,
subject: state.subject, subject: state.subject,
)), )),
@ -108,9 +107,7 @@ class _JobReportPageState extends State<JobReportPage> {
margin: EdgeInsets.symmetric(horizontal: 10.r), margin: EdgeInsets.symmetric(horizontal: 10.r),
child: $UnitTimeAnsweringSituation(widget.id, data.questionAnswerInfos)),*/ child: $UnitTimeAnsweringSituation(widget.id, data.questionAnswerInfos)),*/
// //
Container( Container(margin: EdgeInsets.symmetric(horizontal: 10.r), child: PersonnelDataOverview(studentList: state.studentList.value)),
margin: EdgeInsets.symmetric(horizontal: 10.r),
child: PersonnelDataOverview(studentList: state.studentList.value)),
SizedBox( SizedBox(
height: 30.r, height: 30.r,
@ -119,9 +116,7 @@ class _JobReportPageState extends State<JobReportPage> {
), ),
); );
} else { } else {
return Padding( return Padding(padding: EdgeInsets.only(top: MediaQuery.of(context).size.height / 2 - 200.r), child: const MyEmptyWidget());
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 { class DropdownSelection extends StatefulWidget {
final List<AnnotatedClass>? involveClasses; final List<AnnotatedClass>? involveClasses;
final AnnotatedClass? classData; final AnnotatedClass? classData;
final void Function(AnnotatedClass) onClassSelected; final Function(AnnotatedClass) call;
final Color? bgColor; final Color? bgColor;
const DropdownSelection({Key? key, required this.involveClasses, required this.classData, required this.call,this.bgColor}) : super(key: key);
const DropdownSelection(
{super.key, required this.involveClasses, required this.classData, required this.onClassSelected, this.bgColor});
@override @override
State<DropdownSelection> createState() => _DropdownSelectionState(); State<DropdownSelection> createState() => _DropdownSelectionState();
@ -31,27 +29,18 @@ class _DropdownSelectionState extends State<DropdownSelection> {
)), )),
child: DropdownButton( child: DropdownButton(
value: widget.classData?.classId ?? '-1', 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(), underline: Container(),
// isExpanded:true, // isExpanded:true,
items: widget.involveClasses?.map((classItem) { items: widget.involveClasses?.map((e) {
return DropdownMenuItem<String>( return DropdownMenuItem(
value: classItem.classId, value: e.classId!,
child: quickText( child: quickText(e.classId == '-1' ? '全部' : ' ${EnumUtils.formatGrade(e.grade)}${e.className}', size: 12.sp, color: Colors.black),
classItem.classId == '-1' ? '全部' : ' ${EnumUtils.formatGrade(classItem.grade)}${classItem.className}',
size: 12.sp,
color: Colors.black),
); );
}).toList(), }).toList(),
onChanged: (String? value) { onChanged: (value) {
if (value == null || widget.involveClasses == null) return; if (value == null) return;
widget.call(widget.involveClasses!.firstWhere((element) => element.classId == value));
try {
final selectedClass = widget.involveClasses!.firstWhere((element) => element.classId == value);
widget.onClassSelected(selectedClass);
} catch (e) {
//
}
}, },
), ),
); );

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

View File

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

View File

@ -81,6 +81,7 @@ class _MyInfoState extends State<MyInfo> with AutomaticKeepAliveClientMixin {
fontSize: 13.sp, fontSize: 13.sp,
); );
return OrientationBuilder(builder: (BuildContext context, Orientation orientation) {
return Stack( return Stack(
children: [ children: [
SizedBox( SizedBox(
@ -133,8 +134,7 @@ class _MyInfoState extends State<MyInfo> with AutomaticKeepAliveClientMixin {
margin: EdgeInsets.only(top: 0.h), margin: EdgeInsets.only(top: 0.h),
child: Text( child: Text(
userInfo.value?.name ?? '请前往登录', userInfo.value?.name ?? '请前往登录',
style: style: TextStyle(fontSize: 16.sp, color: const Color(0xFF332A2A), fontWeight: FontWeight.w500),
TextStyle(fontSize: 16.sp, color: const Color(0xFF332A2A), fontWeight: FontWeight.w500),
), ),
), ),
), ),
@ -149,7 +149,7 @@ class _MyInfoState extends State<MyInfo> with AutomaticKeepAliveClientMixin {
color: const Color.fromRGBO(255, 255, 255, 1), color: const Color.fromRGBO(255, 255, 255, 1),
borderRadius: BorderRadius.circular(50.r), 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),
), ),
) )
], ],
@ -174,10 +174,7 @@ class _MyInfoState extends State<MyInfo> with AutomaticKeepAliveClientMixin {
), ),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [Text('账号', style: personalInfoTitleStly), Text(userInfo.value?.name ?? '请前往登录', style: personalInfoValStly)],
Text('账号', style: personalInfoTitleStly),
Text(userInfo.value?.name ?? '请前往登录', style: personalInfoValStly)
],
), ),
), ),
Container( Container(
@ -198,10 +195,7 @@ class _MyInfoState extends State<MyInfo> with AutomaticKeepAliveClientMixin {
), ),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [Text('所在学校', style: personalInfoTitleStly), Text(userInfo.value?.schoolName ?? '', style: personalInfoValStly)],
Text('所在学校', style: personalInfoTitleStly),
Text(userInfo.value?.schoolName ?? '', style: personalInfoValStly)
],
), ),
), ),
Container( Container(
@ -243,5 +237,6 @@ class _MyInfoState extends State<MyInfo> with AutomaticKeepAliveClientMixin {
), ),
], ],
); );
});
} }
} }

View File

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

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

View File

@ -1,12 +1,15 @@
import 'package:badges/badges.dart' as badges;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:functional_widget_annotation/functional_widget_annotation.dart'; import 'package:functional_widget_annotation/functional_widget_annotation.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/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/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/page/global_widget/my_text.dart';
import 'package:making_school_asignment_app/routes/app_pages.dart'; import 'package:making_school_asignment_app/routes/app_pages.dart';
@ -14,266 +17,165 @@ import 'home_logic.dart';
part 'home_view.g.dart'; part 'home_view.g.dart';
class HomePage extends GetxKeepAliveWidget<HomeLogic> { class HomePage extends StatefulWidget {
const HomePage({super.key}); 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 @override
void initState() { void initState() {
super.initState();
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
statusBarColor: Colors.transparent, // statusBarColor: Colors.transparent, //
statusBarIconBrightness: Brightness.light, statusBarIconBrightness: Brightness.light,
systemStatusBarContrastEnforced: false, systemStatusBarContrastEnforced: false,
)); ));
super.initState();
} }
@override @override
Widget buildContent(context, controller) { Widget build(BuildContext context) {
super.build(context);
var spaceWidth = SizedBox(height: ScreenUtil().screenWidth / 30);
return Scaffold( return Scaffold(
backgroundColor: Colors.white, backgroundColor: Colors.white,
body: OrientationBuilder( body: OrientationBuilder(
builder: (BuildContext context, Orientation orientation) { builder: (BuildContext context, Orientation orientation) {
final state = controller.state;
return EasyRefresh( return EasyRefresh(
firstRefresh: false, firstRefresh: false,
taskIndependence: true, taskIndependence: true,
enableControlFinishLoad: true, enableControlFinishLoad: true,
controller: controller.refreshController, controller: logic.refreshController,
header: MaterialHeader(), header: MaterialHeader(),
// footer: TaurusFooter(),
onRefresh: () async { onRefresh: () async {
state.pageNumber = 1; state.pageNumber = 1;
return controller.getList(); return logic.getList();
}, },
child: CustomScrollView( // onLoad: () async {
slivers: [ // if (state.workList.length < state.totalCount.value) {
// // state.pageNumber++;
SliverAppBar( // return logic.getList();
expandedHeight: 300.h, // }
floating: false, // },
pinned: false, child: Stack(
backgroundColor: Colors.transparent, children: [
flexibleSpace: FlexibleSpaceBar( Image.asset(
background: Image.asset(
'assets/images/home_banner.png', 'assets/images/home_banner.png',
width: Get.width, width: Get.width,
fit: BoxFit.cover, fit: BoxFit.fill,
), ),
), Container(
), margin: EdgeInsets.only(top: 300.h),
//
SliverToBoxAdapter(
child: Container(
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20.r), padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20.r),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white, borderRadius: BorderRadius.only(topLeft: Radius.circular(30.r), topRight: Radius.circular(30.r))),
borderRadius: BorderRadius.only(topLeft: Radius.circular(30.r), topRight: Radius.circular(30.r)),
),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 20.r), SizedBox(
// height: 15.r,
Row(
children: [
Icon(
Icons.assignment_outlined,
size: 24.sp,
color: const Color(0xFF4F4F4F),
), ),
SizedBox(width: 8.r),
Text( Text(
'我的作业管理', '我的作业管理',
style: TextStyle( style: TextStyle(fontSize: 20.sp, color: const Color(0xFF676666), fontWeight: FontWeight.w600),
fontSize: 22.sp, color: const Color(0xFF2C2C2C), fontWeight: FontWeight.w700),
), ),
const Spacer(), SizedBox(
// height: 15.r,
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),
],
),
),
),
],
),
);
},
),
);
}
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( Row(
children: [ children: [
Expanded( Expanded(
child: Obx(() => $MenuItem( child: Obx(() {
return menuItem(
bgImg: 'assets/images/home_bg_01.png', bgImg: 'assets/images/home_bg_01.png',
name: '作业批阅', name: '作业批阅',
value: state.totalCount.value > 0 ? state.totalCount.value.toString() : null, value: state.totalCount.value.toString(),
url: Routes.readOverPage, url: Routes.readOverPage,
isPrimary: true, );
)), }),
), ),
SizedBox(width: 16.r), SizedBox(
const Expanded( width: 20.r,
child: $MenuItem(
bgImg: 'assets/images/home_bg_02.png',
name: '知识点掌握',
url: Routes.studentHistoryWorkPage,
page: 'points',
), ),
Expanded(
child: menuItem(bgImg: 'assets/images/home_bg_02.png', name: '知识点掌握', url: Routes.studentHistoryWorkPage, page: 'points'),
), ),
], ],
), ),
SizedBox(height: 16.r), SizedBox(
// height: 20.r,
),
Row( Row(
children: [ children: [
const Expanded( Expanded(
child: $MenuItem( child:
bgImg: 'assets/images/home_bg_03.png', menuItem(bgImg: 'assets/images/home_bg_03.png', name: '学生历史作业', url: Routes.studentHistoryWorkPage, page: 'history'),
name: '学生历史作业',
url: Routes.studentHistoryWorkPage,
page: 'history',
), ),
SizedBox(
width: 20.r,
), ),
SizedBox(width: 16.r), Expanded(
const Expanded( child: menuItem(bgImg: 'assets/images/home_bg_04.png', name: '答题轨迹', url: Routes.answerTrajectoryPage),
child: $MenuItem(bgImg: 'assets/images/home_bg_04.png', name: '答题轨迹', url: Routes.answerTrajectoryPage),
), ),
], ],
), ),
SizedBox(height: 16.r), SizedBox(
// height: 20.r,
),
Row( Row(
children: [ children: [
const Expanded( menuItem(
child: $MenuItem(
bgImg: 'assets/images/home_bg_05.png', bgImg: 'assets/images/home_bg_05.png',
name: '优先批阅设定', name: '优先批阅设定',
url: Routes.studentHistoryWorkPage, url: Routes.studentHistoryWorkPage,
page: 'set', page: 'set',
), ),
), SizedBox(
SizedBox(width: 16.r), width: 20.r,
//
const Expanded(child: SizedBox()),
],
), ),
], ],
),
SizedBox(height: 15.h),
],
),
)
],
),
); );
},
),
);
}
@override
void dispose() {
Get.delete<HomeLogic>();
super.dispose();
} }
} }
@swidget Widget menuItem({required String bgImg, required String name, String? value, required String url, String? page}) {
Widget $menuItem({ return InkWell(
required String bgImg,
required String name,
String? value,
required String url,
String? page,
bool isPrimary = false,
}) {
return Material(
color: Colors.transparent,
child: InkWell(
onTap: () { onTap: () {
Get.toNamed(url, arguments: {'page': page ?? ''}); Get.toNamed(url, arguments: {'page': page ?? ''});
}, },
borderRadius: BorderRadius.circular(12.r),
child: Semantics(
label: '$name${value != null ? ',待处理数量:$value' : ''}',
hint: '点击进入$name页面',
button: true,
child: Container( child: Container(
width: (Get.width - 60.r) / 2, width: (Get.width - 60.r) / 2,
height: (Get.width - 60.r) / 2 * 86 / 164, height: (Get.width - 60.r) / 2 * 86 / 164,
padding: EdgeInsets.all(16.r), padding: EdgeInsets.symmetric(vertical: 15.r, horizontal: 15.r),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.r), image: DecorationImage(
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), image: AssetImage(bgImg),
fit: BoxFit.cover, fit: BoxFit.contain,
colorFilter: ColorFilter.mode(
Colors.white.withOpacity(0.8),
BlendMode.srcATop,
), ),
)
: null,
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -282,64 +184,40 @@ Widget $menuItem({
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Expanded( Text(
child: Text(
name, name,
style: TextStyle( style: TextStyle(fontSize: 14.sp, color: const Color(0xFF4F4F4F), fontWeight: FontWeight.w600),
fontSize: 14.sp,
color: isPrimary ? Colors.white : const Color(0xFF2C2C2C),
fontWeight: FontWeight.w600,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
), ),
if (value != null && value != '') if (value != null && value != '')
Semantics( Container(
label: '待处理数量:$value', width: 18.r,
child: Container( height: 18.r,
width: 20.r,
height: 20.r,
alignment: Alignment.center, alignment: Alignment.center,
decoration: BoxDecoration( decoration: BoxDecoration(
color: isPrimary ? Colors.white : const Color(0xFFFF6969), color: const Color(0xFFFF6969),
borderRadius: BorderRadius.all(Radius.circular(10.r)), borderRadius: BorderRadius.all(Radius.circular(9.r)),
), ),
child: Text( child: Text(
value, value!,
style: TextStyle( style: TextStyle(fontSize: 10.sp, color: Colors.white, fontWeight: FontWeight.w600),
fontSize: 10.sp,
color: isPrimary ? const Color(0xFFFF6969) : Colors.white,
fontWeight: FontWeight.w600),
),
), ),
) )
], ],
), ),
const Spacer(), const Spacer(),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
if (isPrimary)
Icon(
Icons.arrow_forward_ios,
size: 14.sp,
color: Colors.white,
)
else
Image.asset( Image.asset(
'assets/images/home_right_icon.png', 'assets/images/home_right_icon.png',
width: 16.r, width: 16.r,
height: 16.r, height: 16.r,
semanticLabel: '进入图标',
), ),
], ],
), ),
], ],
), ),
), ),
),
),
); );
} }
@ -365,7 +243,7 @@ Widget $termRow(BuildContext context, List<EntranceModel> items, int? data) {
Expanded(flex: 9, child: $TermItem(items[0], data!)), Expanded(flex: 9, child: $TermItem(items[0], data!)),
// const Expanded(flex: 1, child: SizedBox()), // const Expanded(flex: 1, child: SizedBox()),
SizedBox(width: ScreenUtil().screenWidth / 30), SizedBox(width: ScreenUtil().screenWidth / 30),
Expanded(flex: 9, child: $TermItem(items[1], data)), Expanded(flex: 9, child: $TermItem(items[1], data!)),
]); ]);
break; break;
case 3: case 3:
@ -426,8 +304,7 @@ Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHe
badgeStyle: badges.BadgeStyle( badgeStyle: badges.BadgeStyle(
badgeColor: const Color.fromRGBO(255, 105, 105, 1), badgeColor: const Color.fromRGBO(255, 105, 105, 1),
shape: badges.BadgeShape.square, shape: badges.BadgeShape.square,
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(topLeft: Radius.circular(10.r), topRight: Radius.circular(8.5.r), bottomRight: Radius.circular(8.5.r)),
topLeft: Radius.circular(10.r), topRight: Radius.circular(8.5.r), bottomRight: Radius.circular(8.5.r)),
// borderSide: BorderSide(color: Colors.white, width: 2), // borderSide: BorderSide(color: Colors.white, width: 2),
elevation: 1, elevation: 1,
padding: EdgeInsets.symmetric(horizontal: Utils.isPad() ? 11.w : 16.w, vertical: 2.h), padding: EdgeInsets.symmetric(horizontal: Utils.isPad() ? 11.w : 16.w, vertical: 2.h),
@ -455,8 +332,7 @@ Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHe
children: [ children: [
Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover), Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover),
SizedBox(height: 6.r), SizedBox(height: 6.r),
quickText(e.title, quickText(e.title, size: 12.sp, color: const Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500),
size: 12.sp, color: const Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500),
], ],
) )
: Row( : Row(
@ -464,8 +340,7 @@ Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHe
children: [ children: [
Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover), Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover),
SizedBox(width: 6.r), SizedBox(width: 6.r),
quickText(e.title, quickText(e.title, size: 12.sp, color: const Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500),
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 Function goNextPage;
final Widget? rightBtn; 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Obx(() { return Obx(() {
return studentGroups.isNotEmpty return studentGroups != null && studentGroups.isNotEmpty
? Utils.isPad() ? Utils.isPad()
? GridView( ? GridView(
shrinkWrap: true, shrinkWrap: true,
@ -45,12 +45,12 @@ class StudentGroupList extends StatelessWidget {
padding: EdgeInsets.only(right: 8.r), padding: EdgeInsets.only(right: 8.r),
child: Text( child: Text(
'${EnumUtils.formatGrade(item.grade)}${item.className}', '${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( Text(
EnumUtils.formatSubject(item.subject!), EnumUtils.formatSubject(item.subject!),
style: TextStyle(fontSize: 10.sp, color: const Color(0xFF8B8B8B)), style: TextStyle(fontSize: 10.sp, color: Color(0xFF8B8B8B)),
), ),
const Spacer(), const Spacer(),
/*Expanded( /*Expanded(
@ -114,7 +114,7 @@ class StudentGroupList extends StatelessWidget {
), ),
Text( Text(
EnumUtils.formatSubject(item.subject!), EnumUtils.formatSubject(item.subject!),
style: TextStyle(fontSize: 10.sp, color: const Color(0xFF8B8B8B)), style: TextStyle(fontSize: 10.sp, color: Color(0xFF8B8B8B)),
), ),
const Spacer(), const Spacer(),
/* Expanded( /* Expanded(

View File

@ -1,22 +1,47 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:making_school_asignment_app/common/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/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/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:making_school_asignment_app/routes/app_pages.dart';
import 'package:syncfusion_flutter_datepicker/datepicker.dart';
import 'work_logic.dart'; import 'work_logic.dart';
class WorkPage extends GetxKeepAliveWidget<WorkLogic> { class WorkPage extends StatefulWidget {
const WorkPage({super.key}); const WorkPage({super.key});
@override @override
Widget buildContent(BuildContext context, WorkLogic controller) { State<WorkPage> createState() => _WorkPageState();
final state = controller.state; }
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( return Scaffold(
backgroundColor: const Color.fromRGBO(244, 244, 244, 1), backgroundColor: const Color.fromRGBO(244, 244, 244, 1),
body: Column( body: OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
return Column(
children: <Widget>[ children: <Widget>[
Container( Container(
color: Colors.white, color: Colors.white,
@ -45,7 +70,7 @@ class WorkPage extends GetxKeepAliveWidget<WorkLogic> {
indicatorPadding: EdgeInsets.zero, indicatorPadding: EdgeInsets.zero,
indicatorWeight: 0, indicatorWeight: 0,
labelPadding: EdgeInsets.symmetric(horizontal: 2.w), labelPadding: EdgeInsets.symmetric(horizontal: 2.w),
controller: controller.tabController, controller: logic.tabController,
unselectedLabelStyle: TextStyle( unselectedLabelStyle: TextStyle(
fontSize: 14.sp, fontSize: 14.sp,
color: const Color.fromRGBO(69, 83, 100, 1), color: const Color.fromRGBO(69, 83, 100, 1),
@ -79,9 +104,7 @@ class WorkPage extends GetxKeepAliveWidget<WorkLogic> {
child: quickText( child: quickText(
'待批阅', '待批阅',
size: 14.sp, size: 14.sp,
color: state.tabIndex.value == 0 color: state.tabIndex.value == 0 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1),
? Theme.of(context).primaryColor
: const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null, fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null,
), ),
); );
@ -101,9 +124,7 @@ class WorkPage extends GetxKeepAliveWidget<WorkLogic> {
child: quickText( child: quickText(
'已批阅', '已批阅',
size: 14.sp, size: 14.sp,
color: state.tabIndex.value == 1 color: state.tabIndex.value == 1 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1),
? Theme.of(context).primaryColor
: const Color.fromRGBO(80, 94, 110, 1),
fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null, fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null,
), ),
); );
@ -119,8 +140,7 @@ class WorkPage extends GetxKeepAliveWidget<WorkLogic> {
onTap: () { onTap: () {
Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'}); Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'});
}, },
child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"), child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"), color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp),
color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp),
), ),
), ),
], ],
@ -135,7 +155,15 @@ class WorkPage extends GetxKeepAliveWidget<WorkLogic> {
}), }),
), ),
], ],
);
},
), ),
); );
} }
@override
void dispose() {
Get.delete<WorkLogic>();
super.dispose();
}
} }

View File

@ -12,9 +12,8 @@ import connectivity_plus
import device_info_plus import device_info_plus
import package_info_plus import package_info_plus
import path_provider_foundation import path_provider_foundation
import sqflite_darwin import sqflite
import url_launcher_macos import url_launcher_macos
import webview_flutter_wkwebview
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AppInstallerPlugin.register(with: registry.registrar(forPlugin: "AppInstallerPlugin")) AppInstallerPlugin.register(with: registry.registrar(forPlugin: "AppInstallerPlugin"))
@ -26,5 +25,4 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 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 fluttertoast: ^8.0.9
# #
functional_widget_annotation: ^0.10.0 functional_widget_annotation: ^0.10.0
flutter_widget_from_html_core: ^0.17.0 flutter_widget_from_html_core: ^0.14.12
# APP内存及本地存储插件 # APP内存及本地存储插件
get_storage: ^2.0.3 get_storage: ^2.0.3
# zoom_widget: ^2.0.1 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
# start retrofit请求封装 # start retrofit请求封装
retrofit: ^4.1.0 retrofit: ^4.1.0
json_annotation: 4.9.0 json_annotation: ^4.9.0
# end retrofit请求封装 # end retrofit请求封装
# 进度条 # 进度条
percent_indicator: ^4.2.3 percent_indicator: ^4.2.3
@ -83,7 +79,7 @@ dependencies:
data_table_2: 2.5.10 data_table_2: 2.5.10
flutter_staggered_grid_view: ^0.7.0 flutter_staggered_grid_view: ^0.7.0
dropdown_button2: ^2.3.9 dropdown_button2: ^2.3.9
syncfusion_flutter_datepicker: ^30.2.7 syncfusion_flutter_datepicker: ^25.2.5
easy_debounce: ^2.0.3 # 防抖节流 easy_debounce: ^2.0.3 # 防抖节流
flutter_hooks: ^0.20.5 flutter_hooks: ^0.20.5
flutter_spinkit: ^5.2.1 flutter_spinkit: ^5.2.1
@ -97,26 +93,24 @@ dependencies:
app_installer: ^1.1.0 app_installer: ^1.1.0
auto_updater: ^0.2.1 auto_updater: ^0.2.1
permission_handler: ^11.3.1 permission_handler: ^11.3.1
flutter_distributor: 0.6.5 flutter_distributor: ^0.4.5
# fastforge: ^0.6.5 flutter_native_splash: ^2.4.1
flutter_native_splash: ^2.4.6
icons_launcher: ^2.1.7 icons_launcher: ^2.1.7
app_settings: ^5.1.1 app_settings: ^5.1.1
device_info_plus: ^11.1.0 device_info_plus: ^11.1.0
auto_size_text: ^3.0.0 auto_size_text: ^3.0.0
dependency_overrides: # dependency_overrides:
archive: ^4.0.2
# meta: ^1.15.0 # meta: ^1.15.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
retrofit_generator: 9.6.0 retrofit_generator: ^8.1.0
build_runner: 2.5.4 build_runner: ^2.4.10
json_serializable: 6.9.5 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 # The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is # 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 # 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/material.dart';
import 'package:flutter_test/flutter_test.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() { void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async { testWidgets('Counter increments smoke test', (WidgetTester tester) async {

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 KiB