diff --git a/.gitignore b/.gitignore index 6956094..d077d2e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,20 +3,18 @@ *.log *.pyc *.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ +**/.DS_Store +**/.atom/ +**/.buildlog/ +**/.history +**/.svn/ +**/migrate_working_dir/ # IntelliJ related *.iml *.ipr *.iws .idea/ - -# 编译文件不上传 *.g.dart # The .vscode folder contains launch configuration and tasks you configure in @@ -27,13 +25,13 @@ migrate_working_dir/ # Flutter/Dart/Pub related **/doc/api/ **/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.packages -.pub-cache/ -.pub/ -/build/ +**/.dart_tool/ +**/.flutter-plugins +**/.flutter-plugins-dependencies +**/.pub-cache/ +**/.pub/ +**/build/ +**/lib/*.g.dart # Symbolication related app.*.symbols @@ -42,21 +40,18 @@ app.*.symbols app.*.map.json # Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release -/.fvm/flutter_sdk -lib/common/api/retrofit_client.g.dart -lib/common/job/user_info.g.dart -lib/common/job/user_info.g.dart -lib/common/job/user_login.g.dart -lib/common/job/common/upload_img_secret_key.g.dart -lib/common/job/common/base_structure_result.g.dart -lib/common/job/common/base_page.g.dart -lib/common/job/common/base_page_report.g.dart -lib/common/job/common/base_page_data.g.dart -lib/common/job/common/base_page_data_report.g.dart -/.fvm/flutter_sdk -.fvm/fvm_config.json -pubspec.lock -pubspec.lock +**/android/app/debug +**/android/app/profile +**/android/app/release +making_school_asignment_app/*.g.dart +making_school_asignment_app/pubspec.lock +making_school_asignment_app/lib/common/api/retrofit_client.g.dart +making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.g.dart +making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.g.dart +making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.g.dart +making_school_asignment_app/lib/common/api/retrofit_client.g.dart +making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.g.dart +.vscode/settings.json +.vscode/launch.json +making_school_asignment_app/.fvm/fvm_config.json +making_school_asignment_app/.fvm/flutter_sdk diff --git a/.metadata b/.metadata deleted file mode 100644 index 14f5fc9..0000000 --- a/.metadata +++ /dev/null @@ -1,33 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled. - -version: - revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 - channel: stable - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 - base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 - - platform: android - create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 - base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 - - platform: ios - create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 - base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/android/app/build.gradle b/android/app/build.gradle deleted file mode 100644 index 69c3399..0000000 --- a/android/app/build.gradle +++ /dev/null @@ -1,73 +0,0 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - -android { - namespace "com.example.school_asignment_app" - compileSdkVersion flutter.compileSdkVersion - ndkVersion flutter.ndkVersion - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.school_asignment_app" - // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. -// minSdkVersion flutter.minSdkVersion - minSdkVersion 21 - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index a36daaf..0000000 --- a/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - diff --git a/android/app/src/main/kotlin/com/example/school_asignment_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/school_asignment_app/MainActivity.kt deleted file mode 100644 index bee54ec..0000000 --- a/android/app/src/main/kotlin/com/example/school_asignment_app/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.school_asignment_app - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f..0000000 --- a/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f..0000000 --- a/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4..0000000 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b7..0000000 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 09d4391..0000000 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d..0000000 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372e..0000000 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 399f698..0000000 --- a/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/android/build.gradle b/android/build.gradle deleted file mode 100644 index f7eb7f6..0000000 --- a/android/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext.kotlin_version = '1.7.10' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/android/gradle.properties b/android/gradle.properties deleted file mode 100644 index 94adc3a..0000000 --- a/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true diff --git a/android/settings.gradle b/android/settings.gradle deleted file mode 100644 index 44e62bc..0000000 --- a/android/settings.gradle +++ /dev/null @@ -1,11 +0,0 @@ -include ':app' - -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() - -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } - -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/assets/icons/iconfont.js b/assets/icons/iconfont.js deleted file mode 100644 index 79e8e53..0000000 --- a/assets/icons/iconfont.js +++ /dev/null @@ -1 +0,0 @@ -window._iconfont_svg_string_3423846='',function(c){var a=(a=document.getElementsByTagName("script"))[a.length-1],l=a.getAttribute("data-injectcss"),a=a.getAttribute("data-disable-injectsvg");if(!a){var h,i,t,o,m,v=function(a,l){l.parentNode.insertBefore(a,l)};if(l&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(a){console&&console.log(a)}}h=function(){var a,l=document.createElement("div");l.innerHTML=c._iconfont_svg_string_3423846,(l=l.getElementsByTagName("svg")[0])&&(l.setAttribute("aria-hidden","true"),l.style.position="absolute",l.style.width=0,l.style.height=0,l.style.overflow="hidden",l=l,(a=document.body).firstChild?v(l,a.firstChild):a.appendChild(l))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(h,0):(i=function(){document.removeEventListener("DOMContentLoaded",i,!1),h()},document.addEventListener("DOMContentLoaded",i,!1)):document.attachEvent&&(t=h,o=c.document,m=!1,F(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,e())})}function e(){m||(m=!0,t())}function F(){try{o.documentElement.doScroll("left")}catch(a){return void setTimeout(F,50)}e()}}(window); \ No newline at end of file diff --git a/assets/icons/iconfont.woff b/assets/icons/iconfont.woff deleted file mode 100644 index 3f5f987..0000000 Binary files a/assets/icons/iconfont.woff and /dev/null differ diff --git a/assets/icons/iconfont.woff2 b/assets/icons/iconfont.woff2 deleted file mode 100644 index 70e83d1..0000000 Binary files a/assets/icons/iconfont.woff2 and /dev/null differ diff --git a/assets/images/2.0x/ic_home_normal.png b/assets/images/2.0x/ic_home_normal.png deleted file mode 100644 index 64354dc..0000000 Binary files a/assets/images/2.0x/ic_home_normal.png and /dev/null differ diff --git a/assets/images/2.0x/ic_home_press.png b/assets/images/2.0x/ic_home_press.png deleted file mode 100644 index 4d1cefb..0000000 Binary files a/assets/images/2.0x/ic_home_press.png and /dev/null differ diff --git a/assets/images/2.0x/ic_mine_normal.png b/assets/images/2.0x/ic_mine_normal.png deleted file mode 100644 index 719e115..0000000 Binary files a/assets/images/2.0x/ic_mine_normal.png and /dev/null differ diff --git a/assets/images/2.0x/ic_mine_press.png b/assets/images/2.0x/ic_mine_press.png deleted file mode 100644 index 5ada58e..0000000 Binary files a/assets/images/2.0x/ic_mine_press.png and /dev/null differ diff --git a/assets/images/2.0x/ic_work_normal.png b/assets/images/2.0x/ic_work_normal.png deleted file mode 100644 index cd54b72..0000000 Binary files a/assets/images/2.0x/ic_work_normal.png and /dev/null differ diff --git a/assets/images/2.0x/ic_work_press.png b/assets/images/2.0x/ic_work_press.png deleted file mode 100644 index 23d22f2..0000000 Binary files a/assets/images/2.0x/ic_work_press.png and /dev/null differ diff --git a/assets/images/2.0x/login_bgi.png b/assets/images/2.0x/login_bgi.png deleted file mode 100644 index 87f7580..0000000 Binary files a/assets/images/2.0x/login_bgi.png and /dev/null differ diff --git a/assets/images/2.0x/logo.png b/assets/images/2.0x/logo.png deleted file mode 100644 index ad38e5a..0000000 Binary files a/assets/images/2.0x/logo.png and /dev/null differ diff --git a/assets/images/2.0x/personal_bgi.png b/assets/images/2.0x/personal_bgi.png deleted file mode 100644 index f633bd6..0000000 Binary files a/assets/images/2.0x/personal_bgi.png and /dev/null differ diff --git a/assets/images/3.0x/ic_home_normal.png b/assets/images/3.0x/ic_home_normal.png deleted file mode 100644 index 44b7e1c..0000000 Binary files a/assets/images/3.0x/ic_home_normal.png and /dev/null differ diff --git a/assets/images/3.0x/ic_home_press.png b/assets/images/3.0x/ic_home_press.png deleted file mode 100644 index 19ab970..0000000 Binary files a/assets/images/3.0x/ic_home_press.png and /dev/null differ diff --git a/assets/images/3.0x/ic_mine_normal.png b/assets/images/3.0x/ic_mine_normal.png deleted file mode 100644 index e410817..0000000 Binary files a/assets/images/3.0x/ic_mine_normal.png and /dev/null differ diff --git a/assets/images/3.0x/ic_mine_press.png b/assets/images/3.0x/ic_mine_press.png deleted file mode 100644 index 512e001..0000000 Binary files a/assets/images/3.0x/ic_mine_press.png and /dev/null differ diff --git a/assets/images/3.0x/ic_work_normal.png b/assets/images/3.0x/ic_work_normal.png deleted file mode 100644 index deb6e0d..0000000 Binary files a/assets/images/3.0x/ic_work_normal.png and /dev/null differ diff --git a/assets/images/3.0x/ic_work_press.png b/assets/images/3.0x/ic_work_press.png deleted file mode 100644 index ca13777..0000000 Binary files a/assets/images/3.0x/ic_work_press.png and /dev/null differ diff --git a/assets/images/3.0x/login_bgi.png b/assets/images/3.0x/login_bgi.png deleted file mode 100644 index d91ff82..0000000 Binary files a/assets/images/3.0x/login_bgi.png and /dev/null differ diff --git a/assets/images/3.0x/logo.png b/assets/images/3.0x/logo.png deleted file mode 100644 index 620ccc7..0000000 Binary files a/assets/images/3.0x/logo.png and /dev/null differ diff --git a/assets/images/3.0x/personal_bgi.png b/assets/images/3.0x/personal_bgi.png deleted file mode 100644 index 83e7ee9..0000000 Binary files a/assets/images/3.0x/personal_bgi.png and /dev/null differ diff --git a/assets/images/4.0x/ic_home_normal.png b/assets/images/4.0x/ic_home_normal.png deleted file mode 100644 index d12ff70..0000000 Binary files a/assets/images/4.0x/ic_home_normal.png and /dev/null differ diff --git a/assets/images/4.0x/ic_home_press.png b/assets/images/4.0x/ic_home_press.png deleted file mode 100644 index fd6267a..0000000 Binary files a/assets/images/4.0x/ic_home_press.png and /dev/null differ diff --git a/assets/images/4.0x/ic_mine_normal.png b/assets/images/4.0x/ic_mine_normal.png deleted file mode 100644 index eeed1a9..0000000 Binary files a/assets/images/4.0x/ic_mine_normal.png and /dev/null differ diff --git a/assets/images/4.0x/ic_mine_press.png b/assets/images/4.0x/ic_mine_press.png deleted file mode 100644 index b994e8e..0000000 Binary files a/assets/images/4.0x/ic_mine_press.png and /dev/null differ diff --git a/assets/images/4.0x/ic_work_normal.png b/assets/images/4.0x/ic_work_normal.png deleted file mode 100644 index 29bd81d..0000000 Binary files a/assets/images/4.0x/ic_work_normal.png and /dev/null differ diff --git a/assets/images/4.0x/ic_work_press.png b/assets/images/4.0x/ic_work_press.png deleted file mode 100644 index 431435f..0000000 Binary files a/assets/images/4.0x/ic_work_press.png and /dev/null differ diff --git a/assets/images/4.0x/login_bgi.png b/assets/images/4.0x/login_bgi.png deleted file mode 100644 index 64bf904..0000000 Binary files a/assets/images/4.0x/login_bgi.png and /dev/null differ diff --git a/assets/images/4.0x/logo.png b/assets/images/4.0x/logo.png deleted file mode 100644 index a1a62e0..0000000 Binary files a/assets/images/4.0x/logo.png and /dev/null differ diff --git a/assets/images/4.0x/personal_bgi.png b/assets/images/4.0x/personal_bgi.png deleted file mode 100644 index a15351f..0000000 Binary files a/assets/images/4.0x/personal_bgi.png and /dev/null differ diff --git a/assets/images/check_icon.png b/assets/images/check_icon.png deleted file mode 100644 index 6737f02..0000000 Binary files a/assets/images/check_icon.png and /dev/null differ diff --git a/assets/images/ic_home_normal.png b/assets/images/ic_home_normal.png deleted file mode 100644 index 3b81a93..0000000 Binary files a/assets/images/ic_home_normal.png and /dev/null differ diff --git a/assets/images/ic_home_press.png b/assets/images/ic_home_press.png deleted file mode 100644 index b292be5..0000000 Binary files a/assets/images/ic_home_press.png and /dev/null differ diff --git a/assets/images/ic_mine_normal.png b/assets/images/ic_mine_normal.png deleted file mode 100644 index 1e5dd34..0000000 Binary files a/assets/images/ic_mine_normal.png and /dev/null differ diff --git a/assets/images/ic_mine_press.png b/assets/images/ic_mine_press.png deleted file mode 100644 index 03a2784..0000000 Binary files a/assets/images/ic_mine_press.png and /dev/null differ diff --git a/assets/images/ic_work_normal.png b/assets/images/ic_work_normal.png deleted file mode 100644 index 565db6d..0000000 Binary files a/assets/images/ic_work_normal.png and /dev/null differ diff --git a/assets/images/ic_work_press.png b/assets/images/ic_work_press.png deleted file mode 100644 index f7d035c..0000000 Binary files a/assets/images/ic_work_press.png and /dev/null differ diff --git a/assets/images/icon_back_green.png b/assets/images/icon_back_green.png deleted file mode 100644 index 3df3757..0000000 Binary files a/assets/images/icon_back_green.png and /dev/null differ diff --git a/assets/images/job_data_right_icon.png b/assets/images/job_data_right_icon.png deleted file mode 100644 index 7c7edf4..0000000 Binary files a/assets/images/job_data_right_icon.png and /dev/null differ diff --git a/assets/images/job_report_class_icon.png b/assets/images/job_report_class_icon.png deleted file mode 100644 index 525b1d5..0000000 Binary files a/assets/images/job_report_class_icon.png and /dev/null differ diff --git a/assets/images/login_account.png b/assets/images/login_account.png deleted file mode 100644 index 9a17d64..0000000 Binary files a/assets/images/login_account.png and /dev/null differ diff --git a/assets/images/login_bg.png b/assets/images/login_bg.png deleted file mode 100644 index b199639..0000000 Binary files a/assets/images/login_bg.png and /dev/null differ diff --git a/assets/images/login_logo.png b/assets/images/login_logo.png deleted file mode 100644 index 1b083fe..0000000 Binary files a/assets/images/login_logo.png and /dev/null differ diff --git a/assets/images/login_pwd.png b/assets/images/login_pwd.png deleted file mode 100644 index 3a0efc5..0000000 Binary files a/assets/images/login_pwd.png and /dev/null differ diff --git a/assets/images/no_check_icon.png b/assets/images/no_check_icon.png deleted file mode 100644 index aa55131..0000000 Binary files a/assets/images/no_check_icon.png and /dev/null differ diff --git a/assets/images/personal_bgi.png b/assets/images/personal_bgi.png deleted file mode 100644 index a83ea12..0000000 Binary files a/assets/images/personal_bgi.png and /dev/null differ diff --git a/assets/images/youx_icon_active.png b/assets/images/youx_icon_active.png deleted file mode 100644 index 9a75b84..0000000 Binary files a/assets/images/youx_icon_active.png and /dev/null differ diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig deleted file mode 100644 index 592ceee..0000000 --- a/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig deleted file mode 100644 index 592ceee..0000000 --- a/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fa..0000000 --- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 7353c41..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 797d452..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 6ed2d93..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cd7b00..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index fe73094..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index 321773c..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 797d452..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 502f463..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index 0ec3034..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 0ec3034..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index e9f5fea..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 84ac32a..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 8953cba..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 0467bf1..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19ea..0000000 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19ea..0000000 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19ea..0000000 Binary files a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725..0000000 --- a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist deleted file mode 100644 index c47d46a..0000000 --- a/ios/Runner/Info.plist +++ /dev/null @@ -1,51 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - School Asignment App - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - school_asignment_app - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - - diff --git a/lib/common/api/retrofit_client.dart b/lib/common/api/retrofit_client.dart deleted file mode 100644 index b47492e..0000000 --- a/lib/common/api/retrofit_client.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:dio/dio.dart' hide Headers; -import 'package:retrofit/retrofit.dart'; -import 'package:school_asignment_app/common/job/annotated_class.dart'; -import 'package:school_asignment_app/common/job/class_item.dart'; -import 'package:school_asignment_app/common/job/common/app_version_model.dart'; -import 'package:school_asignment_app/common/job/common/base_app_version.dart'; -import 'package:school_asignment_app/common/job/common/base_page_data.dart'; -import 'package:school_asignment_app/common/job/enum_subject.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/common/job/knowledge_points_grasp.dart'; -import 'package:school_asignment_app/common/job/knowledge_report_detail.dart'; -import 'package:school_asignment_app/common/job/student_history.dart'; -import 'package:school_asignment_app/common/job/student_history_params.dart'; -import 'package:school_asignment_app/common/job/student_item.dart'; -import 'package:school_asignment_app/common/job/student_personal_info.dart'; -import 'package:school_asignment_app/common/job/user_info_detail.dart'; -import 'package:school_asignment_app/common/job/work_student.dart'; -import 'package:school_asignment_app/common/job/work_student_params.dart'; - -part 'retrofit_client.g.dart'; - -@RestApi(parser: Parser.JsonSerializable) -@Headers({"Content-Type": "application/json"}) -abstract class RetrofitClient { - factory RetrofitClient(Dio dio, {String? baseUrl}) = _RetrofitClient; - - /* start 系统系列接口 */ - @POST("/api/infra/AppVersion/GetList") - Future?> getAppVersions(@Body() BaseAppVersion appVersion); - - /* start 系统系列接口 */ - - @POST("/api/rbac/Auth/DcLogin") - Future toLogin(@Field() String account, @Field() String password); - - @GET("/api/rbac/User/GetUser") - Future getUser(@Query('userId') String userId); - - //未批阅,已批阅列表 - @GET("/api/hms/Homework/GetList") - Future getWorkList(@Queries() WorkStudentParams params); - - //获取科目,年级 - @GET("/api/app/Common/GetEnumInfos") - Future>> getEnumSubjectList(@Query('enumNames') List enumNames); - - //学生班级 - @GET("/api/rbac/SchoolUser/GetTeacherClassSubject") - Future> getStudentClass(); - - //获取优先批阅状态学生列表 - @GET("/api/rbac/Student/GetPriorityAnnotateStudents") - Future> getStudentList(@Query('ClassId') String classId,@Query('Subject') int subject ); - - //待批阅列表 - @GET("/api/hms/Annotate/GetUnAnnotateList") - Future getUnAnnotateList(@Queries() WorkStudentParams params); - - //已批阅列表 - @GET("/api/hms/Annotate/GetAnnotatedList") - Future getAnnotatedList(@Queries() WorkStudentParams params); - - //获取批阅班级 - @GET("/api/hms/Annotate/Get") - Future> getAnnotatedClassList(@Query('homeworkId') String homeworkId); - - //作业明细 - @GET("/api/hms/HmsReport/GetHomeworkDtls") - Future getHomeworkDetails(@Query('homeworkId') String homeworkId,@Query('classId') String classId); - - //学生历史作业 - @GET("/api/hms/HmsReport/GetStudentHistory") - Future getStudentHistory(@Queries() StudentHistoryParams params); - - //修改学生优先批阅状态 - @POST("/api/rbac/Student/PriorityAnnotateStudent") - Future getAnnotateStudent(@Field() String classId, @Field() int studentId,@Field() bool priorityAnnotate,@Field() int subject); - - //学生作业信息 - @GET("/api/hms/HmsReport/GetStudentHomework") - Future getStudentHomework(@Query('HomeworkId') String homeworkId,@Query('StudentId') int studentId); - - //知识点掌握 - @GET("/api/hms/HmsReport/GetKnowledgeReport") - Future> getKnowledgeReport(@Query('DateStart') String dateStart,@Query('DateEnd') String dateEnd,@Query('KnowledgeName') String knowledgeName); - - //知识点掌握详情 - @GET("/api/hms/HmsReport/GetKnowledgeReportDetail") - Future> getKnowledgeReportDetail(@Query('DateStart') String dateStart,@Query('DateEnd') String dateEnd,@Query('KnowledgeId') int knowledgeId); - - //学生 - @GET("/api/hms/HmsReport/GetQuestionStudentState") - Future> getQuestionStudentState(@Query('HomeworkId') String homeworkId,@Query('TemplateId') int templateId,@Query('QuestionNo') int questionNo); - - - //收集订正 - @POST("/api/hms/Homework/Collect") - Future getCollect(@Field() String homeworkId); - - -} diff --git a/lib/common/mixins/request_tool_mixin.dart b/lib/common/mixins/request_tool_mixin.dart deleted file mode 100644 index 2b35b5c..0000000 --- a/lib/common/mixins/request_tool_mixin.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:school_asignment_app/common/request/rest_dio.dart'; -import 'package:school_asignment_app/common/api/retrofit_client.dart'; - -mixin RequestToolMixin { - RetrofitClient getClient() => RequestTool.instance.getClient(); -} diff --git a/lib/common/utils/utils.dart b/lib/common/utils/utils.dart deleted file mode 100644 index 5e4d237..0000000 --- a/lib/common/utils/utils.dart +++ /dev/null @@ -1,205 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_state.dart'; - -class Utils{ - Utils._internal(); - - /// 关闭键盘 - static void hideKeyboard() { - FocusScopeNode? currentFocus = Get.focusScope?.nearestScope; - if (currentFocus == null) { - return; - } - if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) { - FocusManager.instance.primaryFocus?.unfocus(); - } - } - - // 是否是平板 - static bool isPad([double mobilePhoneScale = 1.2]) { - return ScreenUtil().scaleWidth > mobilePhoneScale; - } - - static String getDoubleRemoveZero(double? val, [String? defaultVal]) { - try { - if (val == null) throw Exception('数据为空'); - List _valArr = val.toString().split('.'); - if (_valArr.length >= 2) { - if (int.parse(_valArr[1]) == 0) { - return val.toInt().toString(); - } - return val.toString(); - } - return val.toInt().toString(); - } catch (e) { - return defaultVal ?? ''; - } - } - - /// 去除小数点 - static String doubleToStringAsFixed(double val, {int fractionDigits = 2}) { - return val.toStringAsFixed(fractionDigits).replaceAll(RegExp(r'\.0*$'), ''); - } - - static calcRate (int divisor, int dividend) { - if(dividend != 0){ - return ((100 * divisor) / dividend); - // return ((100 * divisor) / dividend).toStringAsFixed(0); - }else{ - return 0.0; - } - - } - - /// 秒转时分秒 - static String second2HMS(int sec, {bool isEasy = false}) { - String hms = "0"; - if (!isEasy) hms = "0秒"; - if (sec > 0) { - int h = sec ~/ 3600; - int m = (sec % 3600) ~/ 60; - int s = sec % 60; - if(h>0){ - hms = "$h时$m分$s秒"; - }else{ - if(m>0){ - hms = "$m分$s秒"; - }else{ - hms = "$s秒"; - } - } - } - return hms; - } - - static getHomeworkData(HomeworkDetails data){ - - CountData dataCount = CountData(); - List kgt = data.dtls.where((w) => w.questionType == 1).toList(); - dataCount.kgtAnswerCount = kgt.where((w) => w.state != 0).length; - dataCount.kgtOkCount = kgt.where((w) => w.state == 3).length; - dataCount.kgtDtlCount = kgt.length; - dataCount.kgtAnswerRate = Utils.calcRate(dataCount.kgtAnswerCount!, dataCount.kgtDtlCount!); - dataCount.kgtOkRate = Utils.calcRate(dataCount.kgtOkCount!, dataCount.kgtDtlCount!); - dataCount.kgtCount = data.questions.where((w) => w.questionType == 1).length; - - List zgt = data.dtls.where((w) => w.questionType == 2).toList(); - dataCount.zgtAnswerCount = zgt.where((w) => w.state != 0).length; - dataCount.zgtOkCount = zgt.where((w) => w.state == 3).length; - dataCount.zgtDtlCount = zgt.length; - dataCount.zgtAnswerRate = Utils.calcRate(dataCount.zgtAnswerCount!, dataCount.zgtDtlCount!); - dataCount.zgtOkRate = Utils.calcRate(dataCount.zgtOkCount!, dataCount.zgtDtlCount!); - dataCount.zgtCount = data.questions.where((w) => w.questionType == 2).length; - dataCount.studentCount = data.students.length; - dataCount.priorityStudents = data.students.where((w) => w.priorityAnnotate!).toList(); - - - for(var que in data.questions){ - List ques = data.dtls.where((w) => w.templateId == que.templateId && w.questionNo == que.questionNo).toList(); - que.answerCount = ques.where((w) => w.state != 0).length; - que.answerRate = Utils.calcRate(que.answerCount!, dataCount.studentCount!); - int okCount = ques.where((w) => w.state == 3).length; - que.okRate = Utils.calcRate(okCount, dataCount.studentCount!) ; - que.priorityInfo = ques.where((w) { - return dataCount.priorityStudents!.indexWhere((s) { - w.studentName = s.studentName; - return s.studentId == w.studentId; - }) > -1 && w.state != 3; - }).toList(); - - que.answerNgStudents = ques.where((w) { - w.studentName = data.students.firstWhere((s) => s.studentId == w.studentId).studentName; - return w.state == 2; - }).toList(); - - que.noAnswerStudents = ques.where((w) { - return w.state == 0; - }).toList(); - que.answerOkStudents = ques.where((w) { - return w.state == 3; - }).toList(); - - } - - dataCount.studentSubmitCount = data.students.where((s) => s.state != 0).length; - - for(var stu in data.students){ - stu.kgtStu = kgt.where((w) => w.studentId == stu.studentId).toList(); - stu.kgtStu!.sort((a, b) => a.questionNo.compareTo(b.questionNo)); - stu.kgtOkCount = stu.kgtStu!.where((w) => w.state == 3).length; - stu.kgtErrorCount = stu.kgtStu!.where((w) => w.state == 2).length; - stu.kgtAnswerCount = stu.kgtStu!.where((w) => w.state != 0).length; - - stu.zgtStu = zgt.where((w) => w.studentId == stu.studentId).toList(); - stu.zgtStu!.sort((a, b) => a.questionNo.compareTo(b.questionNo)); - stu.zgtOkCount = stu.zgtStu!.where((w) => w.state == 3).length; - stu.zgtErrorCount = stu.zgtStu!.where((w) => w.state == 2).length; - stu.zgtUnrated = stu.zgtStu!.where((w) => w.state == 1).length; - stu.zgtAnswerCount = stu.zgtStu!.where((w) => w.state != 0).length; - stu.allOk = data.dtls.where((w) { - if(stu.studentId == w.studentId){ - stu.useTime = w.useTime; - } - for(var que in data.questions){ - if(w.templateId == que.templateId && w.questionNo == que.questionNo){ - w.answer = que.answer; - w.questionPicture = que.questionPicture; - } - } - return w.studentId == stu.studentId && w.state != 3; - } ).length??0; - if( (stu.kgtStu!.length - stu.kgtAnswerCount!) + (stu.zgtStu!.length-stu.zgtAnswerCount!) == (stu.kgtStu!.length + stu.zgtStu!.length)){ - stu.allNotDone = true; - }else{ - stu.allNotDone = false; - } - stu.noAnswerCount = data.dtls.where((w) => w.state == 0 && stu.studentId == w.studentId).length; - - List ques = data.questions; - stu.queDtls =data.dtls.where((w) => w.studentId == stu.studentId && ques.indexWhere((q) => w.templateId == q.templateId && w.questionNo == q.questionNo) > -1).toList(); - int okCount = stu.queDtls!.where((w) => w.state == 3).length; - int ttlCount = stu.queDtls!.length; - stu.okRate = Utils.calcRate(okCount, ttlCount); - - } - - data.students.sort((a, b) { - int num1 = a.state; - int num2 = b.state; - return num2.compareTo(num1); - }); - - for(var know in data.knows){ - List ques = data.questions.where((w) => w.knows.indexWhere((k) => k.knowledgeId == know.knowledgeId) > -1).toList(); - List queDtls = data.dtls.where((w) => ques.indexWhere((q) => w.templateId == q.templateId && w.questionNo == q.questionNo) > -1).toList(); - know.okCount = queDtls.where((w) => w.state == 3).length; - know.ttlCount = queDtls.length; - know.okRate = Utils.calcRate(know.okCount!, know.ttlCount!); - } - - return dataCount; - } - - static DateTime getWeekStartDate() { - DateTime now = DateTime.now(); - int dayOfWeek = now.weekday; // 获取今天是周几(1代表周一,7代表周日) - int diff = dayOfWeek - 1; // 计算今天距离周一的天数差 - if (diff < 0) { - diff += 7; // 如果是周日,则需要加上一周的天数 - } - return now.subtract(Duration(days: diff)); // 减去天数差,得到本周一的时间 - } - - static DateTime getWeekEndDate() { - DateTime now = DateTime.now(); - int dayOfWeek = now.weekday; // 获取今天是周几 - int diff = 7 - dayOfWeek; // 计算今天距离周日的天数差 - if (diff == 0) { - diff = 7; // 如果是周日,则加上一周的天数 - } - return now.add(Duration(days: diff)); // 加上天数差减一,得到本周日的时间 - } -} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart deleted file mode 100644 index e6cad94..0000000 --- a/lib/main.dart +++ /dev/null @@ -1,93 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/config/app_config.dart'; -import 'package:school_asignment_app/common/config/colorUtils.dart'; -import 'package:school_asignment_app/common/store/user_store.dart'; -import 'package:school_asignment_app/common/utils/storage.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; - -void main() async { -// 在测试模式下运行Get - Get.testMode = true; - - /// 初始化本地存储 - await Get.putAsync(() => StorageService().init()); - - /// 初始化UserStore - Get.put(UserStore().init()); - - SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]); // 屏幕刘海 - SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); // 屏幕强制竖屏 - runApp(const MyApp()); -} - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - // This widget is the root of your application. - @override - Widget build(BuildContext context) { - return ScreenUtilInit( - designSize: const Size(AppConfig.UI_WIDTH, AppConfig.UI_HEIGHT), - minTextAdapt: true, - splitScreenMode: true, - builder: (BuildContext context, Widget? child) => GetMaterialApp( - title: '作业', - theme: ThemeData( - brightness: Brightness.light, - primarySwatch: createMaterialColor(const Color.fromRGBO(46, 91, 255, 1)), - primaryColor: const Color.fromRGBO(46, 91, 255, 1), - // textTheme: Typography.englishLike2018.apply(fontSizeFactor: 1.sp,), - primaryTextTheme: TextTheme( - bodyLarge: TextStyle(fontSize: 14.sp, color: Colors.black87), - ), - useMaterial3: true, - ), - enableLog: true, - logWriterCallback: (text, {bool isError = false}) { - // isError ? LoggerUtils.e(text) : LoggerUtils.i(text); - }, - // 这里是国际化支持,确保添加flutter_localizations依赖 - supportedLocales: const [ - Locale('zh', 'CN'), // 中文简体 - // 其他支持的locale可以在这里添加 - ], - localizationsDelegates: const [ - // ...其他delegates - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, // 如果你使用了Cupertino风格的组件 - // ...添加其他必要的delegates - ], - localeResolutionCallback: (locale, supportedLocales) { - // 在这里可以实现自定义的locale解析逻辑 - // 如果需要,返回你想要的Locale对象 - return locale; - }, - //默认专场动画 - defaultTransition: Transition.fade, - //初始化路由页面 - initialRoute: Routes.startPage, - /// 路由表 - getPages: AppPages.pages, - builder: EasyLoading.init( - builder: (context, child) { - return MediaQuery( - //Setting font does not change with system font size - data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), - child: Scaffold( - body: GestureDetector(onTap: () => Utils.hideKeyboard(), child: child), - ), - ); - }, - ), - // home: const MyHomePage(title: 'Flutter Demo Home Page'), - ), - ); - } -} diff --git a/lib/page/global_widget/other_page.dart b/lib/page/global_widget/other_page.dart deleted file mode 100644 index 018e405..0000000 --- a/lib/page/global_widget/other_page.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:package_info/package_info.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -// 其他页面 - -class OhterPage extends StatefulWidget { - const OhterPage({super.key}); - - @override - State createState() => _OhterPageState(); -} - -class _OhterPageState extends State { - RxString localVersion = ''.obs; - - @override - void initState() { - super.initState(); - getPageInfo(); - } - - // 获取当前版本号 - getPageInfo() async { - PackageInfo packageInfo = await PackageInfo.fromPlatform(); - localVersion.value = packageInfo.version; - } - - @override - Widget build(BuildContext context) { - final personalInfoTitleStly = TextStyle( - color: const Color.fromRGBO(80, 87, 103, 1), - fontSize: 16.sp, - ); - final personalInfoValStly = TextStyle( - color: const Color.fromRGBO(148, 163, 182, 1), - fontSize: 16.sp, - ); - - return Scaffold( - backgroundColor: const Color.fromRGBO(248, 248, 248, 1), - appBar: AppBar( - backgroundColor: Theme.of(context).primaryColor, - title: quickText('其他', color: Colors.white), - ), - body: Stack( - alignment: const FractionalOffset(0.5, 0.98), - children: [ - ListView( - children: [ - Container( - margin: EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w), - padding: EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w), - height: 130.h, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(6.w)), - color: Colors.white, - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(46, 91, 255, 0.1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 20, //阴影模糊程度 - spreadRadius: 10, //阴影扩散程度 - ) - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - InkWell( - onTap: () { - /* RouterManager.router.navigateTo( - context, - transition: TransitionType.fadeIn, - '${RouterManager.agreementPath}?type=${AGREEMENT_KEY.PRIVACY_GREEMENT.name}', - );*/ - }, - child: Container( - padding: EdgeInsets.only(bottom: 4.h), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('用户隐私协议', style: personalInfoTitleStly), - Icon( - Icons.arrow_forward_ios, - color: const Color.fromRGBO(80, 87, 103, 1), - size: 16.sp, - ) - ], - ), - ), - ), - Container( - height: 1.w, - color: const Color.fromRGBO(240, 243, 255, 1), - ), - SizedBox(height: 8.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('APP版本', style: personalInfoTitleStly), - Obx(() { - return quickText(localVersion); - }) - ], - ) - ], - ), - ), - ], - ), - Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [Text('APP备案号: ', style: personalInfoTitleStly), quickText('渝ICP备17007225号-3A', size: 14.sp)], - ), - ], - )); - } -} diff --git a/lib/page/home_page/children/annotate_class/annotate_class_logic.dart b/lib/page/home_page/children/annotate_class/annotate_class_logic.dart deleted file mode 100644 index 6f2b47c..0000000 --- a/lib/page/home_page/children/annotate_class/annotate_class_logic.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:get/get.dart'; -import 'package:get_storage/get_storage.dart'; -import 'package:school_asignment_app/common/job/annotated_class.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; - -import 'annotate_class_state.dart'; - -class AnnotateClassLogic extends GetxController with RequestToolMixin{ - final AnnotateClassState state = AnnotateClassState(); - - @override - void onInit(){ - super.onInit(); - state.homeworkId.value = Get.arguments['id']??''; - state.name.value = Get.arguments['name']??''; - state.grade = Get.arguments['grade']; - state.completed.value = Get.arguments['completed']??false; - EasyLoading.show(status: 'loading...'); - getList(); - } - - void getList() async{ - List data = await getClient(). getAnnotatedClassList(state.homeworkId.value); - state.classList.value = data; - - for (var element in state.classList.value) { - int commitStudentCount = 0; - int noCommitStudentCount = 0; - for (var student in element.students) { - if(student.state == 0){ - noCommitStudentCount ++; - }else{ - commitStudentCount ++; - } - } - element.commitStudentCount = commitStudentCount; - element.noCommitStudentCount = noCommitStudentCount; - } - -EasyLoading.dismiss(); - } - - void goQuickDataCheck(item){ - Get.toNamed(Routes.quickDataCheckPage,arguments: {'homeworkId':state.homeworkId.value,'classId':item.classId,'grade':state.grade,'className':item.className - }); - } - - void gojobReport(item){ - Get.toNamed(Routes.jobReportPage,arguments: {'title':state.name.value,'homeworkId':state.homeworkId.value,'grade':state.grade,'className':item.className}); - } - - -} diff --git a/lib/page/home_page/children/annotate_class/annotate_class_view.dart b/lib/page/home_page/children/annotate_class/annotate_class_view.dart deleted file mode 100644 index afa3aa3..0000000 --- a/lib/page/home_page/children/annotate_class/annotate_class_view.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; -import 'package:get/get.dart'; -import 'package:percent_indicator/percent_indicator.dart'; -import 'package:school_asignment_app/common/job/annotated_class.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/ReturnToHomepage.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -import 'package:school_asignment_app/page/home_page/children/annotate_class/widget/annotate_item.dart'; -import 'package:school_asignment_app/page/home_page/widget/progress_bar.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; -import 'annotate_class_logic.dart'; -import 'widget/completed_annotate_item.dart'; - -class AnnotateClassPage extends StatefulWidget { - const AnnotateClassPage({Key? key}) : super(key: key); - - @override - State createState() => _AnnotateClassPageState(); -} - -class _AnnotateClassPageState extends State { - final logic = Get.find(); - final state = Get.find().state; - - @override - Widget build(BuildContext context) { - - return Scaffold( - backgroundColor: const Color.fromRGBO(245, 245, 245, 1), - appBar: AppBar( - backgroundColor: Colors.white, - title: Obx(() { - return Text(state.name.value, - style: - TextStyle(fontSize: 14.sp, color: const Color(0xFF333333))); - }), - centerTitle: true, - leading: IconButton( - icon: const Icon(Icons.arrow_back_ios, color: Colors.black), - onPressed: () => Navigator.of(context).pop(), - ), - actions: const [ - ReturnToHomepage(), - ], - ), - body: Padding( - padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r), - child: Obx(() { - return - state.completed.value? Utils.isPad()?GridView( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, //横轴三个子widget - mainAxisSpacing: 10.h, - crossAxisSpacing: 6.w, - childAspectRatio: 1.48 //宽高比为1时,子widget - ), - children: state.classList.map((taskItem) { - return CompletedAnnotateItem(taskItem:taskItem,logic: logic,); - }).toList(), - ):ListView.builder( - itemCount: state.classList.length, - itemBuilder: (context, index) { - AnnotatedClass taskItem = state.classList[index]; - return CompletedAnnotateItem(taskItem:taskItem,logic: logic,); - }): - - Utils.isPad()?MasonryGridView.count( - crossAxisCount: 2, //几列 - mainAxisSpacing: 4.w, // 间距 - crossAxisSpacing: 4.h, // 纵向间距? - itemCount: state.classList.length, - itemBuilder: (context, index) { - AnnotatedClass item = state.classList[index]; - return AnnotateItem(item: item,font: 8.sp,name: state.name.value,logic: logic,); - }, - ): - ListView.builder( - itemCount: state.classList.length, - itemBuilder: (context, index) { - AnnotatedClass item = state.classList[index]; - return AnnotateItem(item: item,font: 12.sp,name: state.name.value,logic: logic,); - }); - }), - ), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} diff --git a/lib/page/home_page/children/annotate_class/widget/annotate_item.dart b/lib/page/home_page/children/annotate_class/widget/annotate_item.dart deleted file mode 100644 index 17658fa..0000000 --- a/lib/page/home_page/children/annotate_class/widget/annotate_item.dart +++ /dev/null @@ -1,241 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:percent_indicator/percent_indicator.dart'; -import 'package:school_asignment_app/common/job/annotated_class.dart'; -import 'package:school_asignment_app/common/utils/enum_untils.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -import 'package:school_asignment_app/page/home_page/children/annotate_class/annotate_class_logic.dart'; -import 'package:school_asignment_app/page/home_page/children/annotate_class/annotate_class_state.dart'; -import 'package:school_asignment_app/page/home_page/children/annotate_class/widget/item_btn.dart'; -import 'package:school_asignment_app/page/home_page/widget/progress_bar.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; - -class AnnotateItem extends StatefulWidget { -final AnnotatedClass item; -final double font; -final String name; -final AnnotateClassLogic logic; - const AnnotateItem({Key? key, required this.item,required this.font,required this.name,required this.logic}) : super(key: key); - - @override - State createState() => _AnnotateItemState(); -} - -class _AnnotateItemState extends State { - @override - Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.only(top: 10.r), - margin: EdgeInsets.only(bottom: 10.r), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadiusDirectional.circular(4.r), - boxShadow: const [BoxShadow(color: Color.fromRGBO(0, 0, 0, 0.15), blurRadius: 10)], - ), - child: Column( - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.r), - child: Row( - children: [ - Text( - '${EnumUtils.formatGrade(widget.item.grade)}${widget.item.className}', - style: TextStyle( - fontSize: widget.font, - color: const Color(0xFF000000)), - ), - const Spacer(), - Text( - '已交:${widget.item.commitStudentCount}', - style: TextStyle( - fontSize: widget.font - 2.sp, - color: const Color(0xFF6888FD)), - ), - SizedBox( - width: 20.r, - ), - Text( - '未交:${widget.item.noCommitStudentCount}', - style: TextStyle( - fontSize: widget.font - 2.sp, - color: const Color(0xFFFF5656)), - ), - ], - ), - ), - SizedBox( - height: 10.r, - ), - Padding( - padding: EdgeInsets.symmetric(horizontal: 8.r), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: - widget.item.finishTime != null ? - [ - Expanded( - flex:4, - child:ItemBtn(title: "收藏夹",font: widget.font - 2.sp, - clickFunction: (){ - - },), - ), - const Expanded(flex: 1, child: SizedBox()), - const Expanded(flex: 4, child: SizedBox()), - const Expanded(flex: 1, child: SizedBox()), - const Expanded(flex: 4, child: SizedBox()), - - ]:[ - Expanded( - flex: 4, - child: ItemBtn(title: "一键批阅",font: widget.font - 2.sp, - clickFunction: (){ - - },), - ), - const Expanded(flex: 1,child: Text(''),), - Expanded( - flex:4, - child: ItemBtn(title: "数据快查",font: widget.font - 2.sp,clickFunction: (){ - widget.logic.goQuickDataCheck(widget.item); - },), - ), - const Expanded(flex: 1,child: Text(''),), - Expanded( - flex:4, - child: ItemBtn(title: "收藏夹",font: widget.font - 2.sp, - clickFunction: (){ - - },), - ), - ], - ), - ), - Padding( - padding: EdgeInsets.symmetric(vertical: 10.r,horizontal: 14.r), - child: Row( - children: [ - Expanded( - child: LinearPercentIndicator( - padding: EdgeInsets.zero, - animation: true, - lineHeight: 8.h, - animationDuration: 2500, - - percent: widget.item.annotateRate / 100, - linearGradient: LinearGradient( - tileMode: TileMode.mirror, - stops: const [0.0, 1.0], - colors: widget.item.annotateRate / 100 != 1 - ? [Theme.of(context).primaryColor.withOpacity(0.1), Theme.of(context).primaryColor] - : [ - const Color.fromRGBO(144, 224, 190, 1).withOpacity(0.1), - const Color.fromRGBO(144, 224, 190, 1), - ], - ), - // linearStrokeCap: LinearStrokeCap.butt, - // progressColor: Theme.of(context).primaryColor, - backgroundColor: const Color.fromRGBO(232, 232, 232, 1), - barRadius: Radius.circular(10.r), - ), - ), - SizedBox(width: 7.w), - quickText('${widget.item.annotateRate}%', - size: widget.font - 2.sp, color: const Color.fromRGBO(70, 70, 70, 1)) - ], - ), - ), - ProgressBar( - title: '客观题正确率:', - color: const Color(0xFFB8C7FF), - 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(0xFFB8C7FF), - 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(0xFFB8C7FF), - percent: widget.item.correctRate / 100, - padingEdg: EdgeInsets.symmetric(horizontal: 10.r), - marginEdg: EdgeInsets.only(top: 8.h), - fontSize:widget.font - 2.sp), - - Container( - margin: EdgeInsets.only(top: 10.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.only(bottomLeft: Radius.circular(4.r), bottomRight: Radius.circular(4.r)), - color: Colors.white, - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(0, 0, 0, 0.15), - offset: Offset(0, -0.0001), //阴影y轴偏移量 - blurRadius: 4, //阴影模糊程度 - spreadRadius: 0, //阴影扩散程度 - ) - ], - ), - - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: - widget.item.finishTime != null ? - [ - Expanded( - child: InkWell( - onTap: () { - widget.logic.goQuickDataCheck(widget.item); - }, - child: Container( - alignment: Alignment.center, - child: quickText('数据快查', color: Color.fromRGBO(118, 118, 118, 1), size: widget.font), - ), - ), - ), - Container(width: 1.w, height: 30.h, color: const Color.fromRGBO(221, 221, 221, 1)), - Expanded( - child: InkWell( - onTap: () { - widget.logic.gojobReport(widget.item); - }, - child: Container( - alignment: Alignment.center, - child: quickText('查看报告', color: Color.fromRGBO(118, 118, 118, 1), size: widget.font), - ), - )), - ] - : - [ - Expanded( - child: InkWell( - onTap: () {}, - child: Container( - alignment: Alignment.center, - child: quickText('批阅', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font), - ), - ), - ), - Container(width: 1.w, height: 30.h, color: const Color.fromRGBO(221, 221, 221, 1)), - Expanded( - child: InkWell( - onTap: () {}, - child: Container( - alignment: Alignment.center, - child: quickText('结束批阅', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font), - ), - )), - ], - ), - ) - ], - ), - ); - } -} diff --git a/lib/page/home_page/children/class_student/class_student_view.dart b/lib/page/home_page/children/class_student/class_student_view.dart deleted file mode 100644 index fc3f928..0000000 --- a/lib/page/home_page/children/class_student/class_student_view.dart +++ /dev/null @@ -1,353 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:flutter_easyrefresh/easy_refresh.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/student_item.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; -import 'package:school_asignment_app/page/global_widget/ReturnToHomepage.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; - -import 'class_student_logic.dart'; - -class ClassStudentPage extends StatefulWidget { - const ClassStudentPage({Key? key}) : super(key: key); - - @override - State createState() => _ClassStudentPageState(); -} - -class _ClassStudentPageState extends State { - final logic = Get.find(); - final state = Get - .find() - .state; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color.fromRGBO(245, 245, 245, 1), - appBar: AppBar( - backgroundColor: Colors.white, - title: Obx(() { - return Text( - state.title.value, - style: TextStyle(fontSize: 14.sp, color: const Color(0xFF333333)), - ); - }), - centerTitle: true, - leading: IconButton( - icon: const Icon(Icons.arrow_back_ios, color: Colors.black), - onPressed: () => Navigator.of(context).pop(), - ), - actions: const [ - ReturnToHomepage(), - ], - ), - body: Padding( - padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r), - child: Obx(() { - return EasyRefresh( - firstRefresh: false, - taskIndependence: true, - controller: logic.refreshController, - header: MaterialHeader(), - footer: TaurusFooter(), - onRefresh: () async { - logic.getList(); - }, - child: state.studentList.isNotEmpty - ? Utils.isPad() - ? GridView( - shrinkWrap: true, - gridDelegate: - SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - mainAxisSpacing: 10.r, - crossAxisSpacing: 10.r, - childAspectRatio: 556 / 112, - ), - children: List.generate(state.studentList.length, (index) { - StudentItem item = state.studentList[index]; - return InkWell( - onTap: () { - // RouterManager.router.navigateTo(context, - // '${RouterManager.jobPersonalDetailPath}?studentId=${item.studentId}&studentName=${Uri.encodeComponent(item.studentName)}'); - Get.toNamed(Routes.studentWorkDetailPage,arguments: {'studentName':item.name,'studentId':item.id}); - }, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 10.r), - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(10.r)), - color: Colors.white, - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - item.name, - style: TextStyle( - fontSize: 12.sp, - color: const Color(0xFF6888FD)), - )), - - state.page == 'answerTrajectory' ? Container( - height: 20.r, - width: 70.r, - decoration: BoxDecoration( - border: Border.all( - width: 1.r, color: const Color(0xFFFFA41E)), - borderRadius: BorderRadius.all( - Radius.circular(20.r)), - - ), - child: Center(child: Text('详情', style: TextStyle( - fontSize: 10.r, color: Color(0xFFFFA41E))), - )) : state.page == 'history' ? Container( - height: 20.r, - width: 70.r, - decoration: BoxDecoration( - color: const Color(0xFF6888FD), - borderRadius: BorderRadius.all( - Radius.circular(20.r)) - ), - child: Center(child: Text('历史作业', style: TextStyle( - fontSize: 10.r, color: Colors.white),)), - ) : - item.priorityAnnotate - ? - InkWell( - onTap: () { - logic.setJobReadLevel( - item.id, false); - EasyLoading.show( - status: 'loading...'); - }, - child: Container( - height: 20.r, - width: 80.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(4.r)), - color: const Color(0xFFB7FFE0), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(left: 3.r), - child: Image.asset( - 'assets/images/youx_icon_active.png', - width: 14.r, height: 14.r,), - ), - Padding( - padding: EdgeInsets.only( - top: 2.r, left: 4.r), - child: Text( - '优先批阅', - style: TextStyle( - fontSize: 10.sp, - color: const Color(0xFF4CC793)), - ), - ), - ], - ), - ), - ) - : InkWell( - onTap: () { - logic.setJobReadLevel( - item.id, true); - EasyLoading.show( - status: 'loading...'); - }, - child: Container( - height: 20.r, - width: 80.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(4.r)), - color: const Color(0xFFE1E1E1), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(left: 3.r), - child: Image.asset( - 'assets/images/youx_icon_default.png', - width: 14.r, height: 14.r,), - ), - Padding( - padding: EdgeInsets.only( - top: 2.r, left: 4.r), - child: Text( - '优先批阅', - style: TextStyle( - fontSize: 10.sp, - color: const Color(0xFF8A9691)), - ), - ), - ], - ), - ), - ), - ], - ), - ), - ); - }), - ) - : ListView.builder( - itemBuilder: (context, index) { - StudentItem item = state.studentList[index]; - return InkWell( - onTap: () { - // RouterManager.router.navigateTo(context, - // '${RouterManager.jobPersonalDetailPath}?studentId=${item.studentId}&studentName=${Uri.encodeComponent(item.studentName)}'); - Get.toNamed(Routes.studentWorkDetailPage,arguments: {'studentName':item.name,'studentId':item.id}); - }, - child: Container( - padding: EdgeInsets.symmetric( - vertical: 20.r, horizontal: 15.r), - margin: EdgeInsets.only(bottom: 15.r), - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(10.r)), - color: Colors.white, - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - item.name, - style: TextStyle( - fontSize: 12.sp, - color: Color(0xFF6888FD)), - )), - state.page == 'answerTrajectory' ? Container( - height: 24.r, - width: 72.r, - decoration: BoxDecoration( - border: Border.all( - width: 1.r, color: Color(0xFFFFA41E)), - borderRadius: BorderRadius.all( - Radius.circular(20.r)), - - ), - child: Center(child: Text('详情', style: TextStyle( - fontSize: 10.r, color: Color(0xFFFFA41E))), - )) : state.page == 'history' ? Container( - height: 24.r, - width: 82.r, - decoration: BoxDecoration( - color: Color(0xFF6888FD), - borderRadius: BorderRadius.all( - Radius.circular(20.r)) - ), - child: Center(child: Text('历史作业', style: TextStyle( - fontSize: 10.r, color: Colors.white),)), - ) : - item.priorityAnnotate - ? InkWell( - onTap: () { - logic.setJobReadLevel( - item.id, false); - EasyLoading.show( - status: 'loading...'); - }, - child: Container( - height: 24.r, - width: 82.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(4.r)), - color: Color(0xFFB7FFE0), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(left: 3.r), - child: Image.asset( - 'assets/images/youx_icon_active.png', - width: 14.r, height: 14.r,), - ), - Padding( - padding: EdgeInsets.only( - top: 2.r, left: 4.r), - child: Text( - '优先批阅', - style: TextStyle( - fontSize: 10.sp, - color: const Color(0xFF4CC793)), - ), - ), - ], - ), - ), - ) - : InkWell( - onTap: () { - logic.setJobReadLevel( - item.id, true); - EasyLoading.show( - status: 'loading...'); - }, - child: Container( - height: 24.r, - width: 82.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(4.r)), - color: const Color(0xFFE1E1E1), - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(left: 3.r), - child: Image.asset( - 'assets/images/youx_icon_default.png', - width: 14.r, height: 14.r,), - ), - Padding( - padding: EdgeInsets.only( - top: 2.r, left: 4.r), - child: Text( - '优先批阅', - style: TextStyle( - fontSize: 10.sp, - color: const Color(0xFF8A9691)), - ), - ), - ], - ), - ), - ), - ], - ), - ), - ); - }, - itemCount: state.studentList.length, - ) - : const MyEmptyWidget(), - ); - }), - ), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} \ No newline at end of file diff --git a/lib/page/home_page/children/job_report/job_report_logic.dart b/lib/page/home_page/children/job_report/job_report_logic.dart deleted file mode 100644 index fe483ab..0000000 --- a/lib/page/home_page/children/job_report/job_report_logic.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/annotated_class.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; - -import 'job_report_state.dart'; - -class JobReportLogic extends GetxController with RequestToolMixin { - final JobReportState state = JobReportState(); - - @override - void onInit(){ - super.onInit(); - state.title.value = Get.arguments['title']??''; - state.homeworkId.value = Get.arguments['homeworkId']??''; - state.classId.value = Get.arguments['classId']??''; - state.className.value = Get.arguments['className']??''; - state.grade = Get.arguments['grade']??''; - EasyLoading.show(status: 'loading...'); - getClass(); - } - void getClass() async{ - List data = await getClient(). getAnnotatedClassList(state.homeworkId.value); - state.involveClasses.value = data; - - state.involveClasses.value = [state.classData.value, ...(data ?? [])]; - for (var element in state.involveClasses) { - if (element.className == state.className.value && element.grade == state.grade ) { - state.classData.value = element; - } - } - getWorkData(); - } - void getWorkData() async{ - HomeworkDetails data = await getClient(). getHomeworkDetails(state.homeworkId.value,state.classData.value.classId != '-1' ? state.classData.value.classId : ''); - state.dataCount = Utils.getHomeworkData(data); - state.homeData = data; - state.kgReport.value = data.questions.where((w)=>w.questionType == 1).toList(); - state.zgReport.value = data.questions.where((w)=>w.questionType == 2).toList(); - state.studentList.value = [...data.students]; - state.knowsList.value = data.knows; - state.hasData.value = true; - EasyLoading.dismiss(); - - state.studentList.sort((a, b) { - int num1 = a.kgtOkCount!+a.zgtOkCount!; - int num2 = b.kgtOkCount!+b.zgtOkCount!; - return num2.compareTo(num1); - }); - - } -} diff --git a/lib/page/home_page/children/job_report/job_report_view.dart b/lib/page/home_page/children/job_report/job_report_view.dart deleted file mode 100644 index 21e53b1..0000000 --- a/lib/page/home_page/children/job_report/job_report_view.dart +++ /dev/null @@ -1,131 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/annotated_class.dart'; -import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; -import 'package:school_asignment_app/page/global_widget/ReturnToHomepage.dart'; -import 'package:school_asignment_app/page/home_page/children/job_report/widget/dropdown_selection.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -import 'package:school_asignment_app/page/home_page/children/job_report/widget/knowledge_point.dart'; -import 'package:school_asignment_app/page/home_page/children/job_report/widget/personnel_data_overview.dart'; -import 'package:school_asignment_app/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart'; - -import 'job_report_logic.dart'; - -class JobReportPage extends StatefulWidget { - const JobReportPage({Key? key}) : super(key: key); - - @override - State createState() => _JobReportPageState(); -} - -class _JobReportPageState extends State { - final logic = Get.find(); - final state = Get - .find() - .state; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color.fromRGBO(245, 245, 245, 1), - appBar: AppBar( - backgroundColor: Colors.white, - centerTitle: true, - title: Center( - child: Obx(() { - return quickText( - '${state.title.value}作业报告', - size: 14.sp, - color: const Color.fromRGBO(51, 51, 51, 1), - ); - })), - leading: IconButton( - icon: const Icon(Icons.arrow_back_ios, color: Colors.black), - onPressed: () => Navigator.of(context).pop(), - ), - actions: const [ - ReturnToHomepage(), - ], - ), - body: Obx(() { - if (state.hasData.value) { - return SingleChildScrollView( - child: Column( - children: [ - // 下拉框 - Container( - padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 10.w), - decoration: const BoxDecoration( - color: Colors.white, - ), - child: Row( - children: [ - Obx(() { - return DropdownSelection(involveClasses: state - .involveClasses.value, - classData: state.classData.value, - call: (AnnotatedClass item) { - state.classData.value = item; - if (item.grade == -1) state.classData.value = state.defaultClass; - logic.getWorkData(); - }); - }), - // Expanded(child: Text('')), - ], - ), - ), - //完成率、正确率 - /* TopCount( - data, classData == null ? '' : classData!.className, widget.id),*/ - //客观题、主观题 - KgtZgtTable(studentCount: state.dataCount.studentCount!, - homeworkId: state.homeworkId.value, - kgReport: state.kgReport, - zgReport: state.zgReport, - kgtOkRate: state.dataCount.kgtOkRate! - .toStringAsFixed(0), - zgtOkRate: state.dataCount.zgtOkRate! - .toStringAsFixed(0)), - // 掌握知识点的情况 - Container( - margin: EdgeInsets.symmetric(horizontal: 10.r), - child: KnowledgePoint( - knowsList:state.knowsList,data:state.homeData,className: state.classData.value.className,homeworkId:state.homeworkId.value)), - // 掌握知识点的情况 - /* Container( - margin: EdgeInsets.symmetric(horizontal: 10.r), - child: $OverallPerformance(data.studentCount, data.overallTitles)), - // 单位时间答题情况 - Container( - margin: EdgeInsets.symmetric(horizontal: 10.r), - child: $UnitTimeAnsweringSituation(widget.id, data.questionAnswerInfos)),*/ - // 人员数据概况 - Container( - margin: EdgeInsets.symmetric(horizontal: 10.r), - child: PersonnelDataOverview(studentList:state.studentList.value)), - - SizedBox(height: 30.r,), - ], - ), - ); - } else { - return Padding( - padding: EdgeInsets.only( - top: MediaQuery - .of(context) - .size - .height / 2 - 200.r), - child: const MyEmptyWidget() - ); - } - }), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} \ No newline at end of file diff --git a/lib/page/home_page/children/job_report/widget/knowledge_point.dart b/lib/page/home_page/children/job_report/widget/knowledge_point.dart deleted file mode 100644 index a81c401..0000000 --- a/lib/page/home_page/children/job_report/widget/knowledge_point.dart +++ /dev/null @@ -1,299 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:percent_indicator/linear_percent_indicator.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; - -class KnowledgePoint extends StatefulWidget { - final RxList knowsList; - final HomeworkDetails data; - final String className; - final String homeworkId; - KnowledgePoint({Key? key,required this.knowsList,required this.data,required this.className,required this.homeworkId}) : super(key: key); - - @override - State createState() => _KnowledgePointState(); -} - -class _KnowledgePointState extends State { - - void goQuickCheckPersonalPath(studentId) { - if (studentId != null) { - Get.toNamed(Routes.studentPersonalPage,arguments: {'studentId':studentId,'homeworkId':widget.homeworkId}); - } - } - - void showPeopleListDialog( - {required BuildContext context, - required String title, - required List arr,}) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - // insetPadding: EdgeInsets.symmetric(vertical: 20.r,horizontal: 20.r), - backgroundColor:const Color(0xFFFFFFFF), - contentPadding: EdgeInsets.all(20.r), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(15.r))), - content: SizedBox( - width: MediaQuery.of(context).size.width * 0.7, - height: MediaQuery.of(context).size.height * 0.7, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Center( - child: Text( - title, - style: TextStyle( - fontSize: 15.sp, - color: const Color(0xFF3C3C3C), - fontWeight: FontWeight.w500), - ), - ), - SizedBox( - height: 10.r, - ), - Row( - children: [ - Expanded( - flex: 2, - child: Center( - child: Text( - '姓名', - style: TextStyle( - fontSize: 12.sp, - color: const Color(0xFF6A6A6A)), - ))), - SizedBox(width: 10.r,), - Expanded( - flex: 1, - child: Center( - child: Text( - '班级', - style: TextStyle( - fontSize: 12.sp, - color: const Color(0xFF6A6A6A)), - ))), - SizedBox(width: 10.r,), - Expanded( - flex: 2, - child: Center( - child: Text( - '掌握度', - style: TextStyle( - fontSize: 12.sp, - color: const Color(0xFF6A6A6A)), - ))), - SizedBox(width: 10.r,), - Expanded( - flex: 3, - child: Center( - child: Text( - '掌握情况', - style: TextStyle( - fontSize: 12.sp, - color: const Color(0xFF6A6A6A)), - ))), - ], - ), - SizedBox( - height: 5.r, - ), - - arr.isNotEmpty? Expanded( - child: ListView.builder( - shrinkWrap: true, - itemBuilder: (context, index) { - var item = arr[index]; - return Container( - padding: EdgeInsets.symmetric(vertical: 5.r), - color: const Color(0xFFF0F0F0), - margin:EdgeInsets.only(bottom: 2.r), - child: Row( - children: [ - Expanded( - flex: 2, - child: InkWell( - onTap: () { - goQuickCheckPersonalPath( - item.studentId); - }, - child: Center( - child: Text( - item.studentName!, - style: TextStyle( - fontSize: 12.sp, - color: const Color(0xFF323232)), - )))), - SizedBox(width: 10.r,), - Expanded( - flex: 1, - child: Center( - child: Text( - widget.className == ''?'全部': widget.className, - style: TextStyle( - fontSize: 12.sp, - color: Color(0xFF323232)), - ))), - SizedBox(width: 10.r,), - Expanded( - flex: 2, - child: Center( - child: Text( - '${item.okRate!.toStringAsFixed(0)}%', - style: TextStyle( - fontSize: 12.sp, - color: Color(0xFF323232)), - ))), - SizedBox(width: 10.r,), - Expanded( - flex: 3, - child: Padding( - padding: EdgeInsets.symmetric(vertical: 2.r, horizontal: 5.r), - child: SingleChildScrollView( - child: Wrap( - direction: Axis.horizontal, - alignment: WrapAlignment.start, - spacing: 5, - runSpacing: 3, - children: List.generate(item.queDtls!.length, (index) { - Dtls kgInfo = item.queDtls![index]; - return Container( - width: 14.r, - height: 14.r, - decoration: BoxDecoration( - color: kgInfo.state == 0 - ? const Color(0xFFD3D3D3) - : kgInfo.state == 1?Colors.white:kgInfo.state == 2 - ? const Color(0xFFFF7474) - : const Color(0xFF4CC793), - borderRadius: BorderRadius.all(Radius.circular(7.r))), - child: Center( - child: Text( - kgInfo.questionNo.toString(), - style: TextStyle( - fontSize: 8.sp, - color: kgInfo.state == 1 - ? Color(0xFF525252) - : Colors.white), - )), - ); - })), - ), - ),), - ], - ), - ); - }, - itemCount: arr.length, - ), - ): const MyEmptyWidget() - ], - ), - ), - ); - }); - } - - @override - Widget build(BuildContext context) { - return Container( - margin: EdgeInsets.only(top: 10.h), - padding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 12.w), - constraints: BoxConstraints(maxHeight: 320.h), - decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(10.r)), - child: Column( - children: [ - Container( - margin: EdgeInsets.only(bottom: 24.h), - child: quickText('知识点掌握情况', color: const Color.fromRGBO(92, 92, 92, 1), size: 14.sp, fontWeight: FontWeight.bold), - ), - Expanded( - child: ListView(children: widget.knowsList.value.map((item) { - return Container( - margin: EdgeInsets.only(bottom: 15.h, left: 15.r, right: 15.r), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Expanded( - flex: 10, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - quickText(item.knowledgeName, - size: 12.sp, color: const Color.fromRGBO(152, 152, 152, 1)), - quickText('${item.okRate!.toStringAsFixed(0)}%', - size: 12.sp, color: const Color.fromRGBO(64, 64, 64, 1)), - ], - ), - ), - SizedBox(width: 10.w), - const Expanded(flex: 1, child: SizedBox()), - ], - ), - SizedBox(height: 3.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - flex: 10, - child: LinearPercentIndicator( - padding: EdgeInsets.zero, - animation: true, - lineHeight: 10.h, - animationDuration: 2500, - percent: item.okRate! / 100, - progressColor: Theme.of(context).primaryColor, - backgroundColor: const Color.fromRGBO(219, 224, 243, 1), - barRadius: Radius.circular(10.r), - )), - SizedBox(width: 10.w), - InkWell( - onTap: () { - List ques = widget.data.questions.where((w) => w.knows.indexWhere((k) => k.knowledgeId == item.knowledgeId) > -1).toList(); - List array2 = [...widget.data.students]; - for(var stu in array2){ - stu.queDtls = widget.data.dtls.where((w) => w.studentId == stu.studentId && ques.indexWhere((q) => w.templateId == q.templateId && w.questionNo == q.questionNo) > -1).toList(); - int okCount = stu.queDtls!.where((w) => w.state == 3).length; - int ttlCount = stu.queDtls!.length; - stu.okRate = Utils.calcRate(okCount, ttlCount); - stu.queDtls!.sort((a, b) { - int num1 = a.questionNo; - int num2 = b.questionNo; - return num1.compareTo(num2); - }); - } - - showPeopleListDialog( - context: context, - title: item.knowledgeName, - arr: array2,); - }, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - quickText('查看', size: 12.sp, color: const Color.fromRGBO(239, 135, 20, 1)), - Icon(Icons.arrow_forward_ios, size: 11.sp, color: const Color.fromRGBO(239, 135, 20, 1)), - ], - ), - ), - ], - ) - ], - ), - ); - }).toList()), - ), - ], - )); - } -} diff --git a/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_state.dart b/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_state.dart deleted file mode 100644 index a614247..0000000 --- a/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_state.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/knowledge_points_grasp.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; - -class KnowledgePointsGraspState { - KnowledgePointsGraspState() { - ///Initialize variables - } - - late int page = 1; - late int totalPages = 0; - late RxList dataList=RxList(); - late String dateStart = Utils.getWeekStartDate().toString().substring(0, 10); - late String dateEnd = Utils.getWeekEndDate().toString().substring(0, 10); - late RxString customTimeStr = '自定义'.obs; -} diff --git a/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_view.dart b/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_view.dart deleted file mode 100644 index 691f6b1..0000000 --- a/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_view.dart +++ /dev/null @@ -1,265 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:flutter_easyrefresh/easy_refresh.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/knowledge_points_grasp.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; -import 'package:school_asignment_app/page/global_widget/ReturnToHomepage.dart'; -import 'package:school_asignment_app/page/home_page/children/student_work_detail/widget/job_condition_filter.dart'; -import 'package:school_asignment_app/page/home_page/widget/progress_bar.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; -import 'package:syncfusion_flutter_datepicker/datepicker.dart'; - -import 'knowledge_points_grasp_logic.dart'; - -class KnowledgePointsGraspPage extends StatefulWidget { - const KnowledgePointsGraspPage({Key? key}) : super(key: key); - - @override - State createState() => - _KnowledgePointsGraspPageState(); -} - -class _KnowledgePointsGraspPageState extends State { - final logic = Get.find(); - final state = Get - .find() - .state; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color.fromRGBO(245, 245, 245, 1), - appBar: AppBar( - backgroundColor: Colors.white, - title: Text('知识点掌握', - style: TextStyle(fontSize: 14.sp, color: Color(0xFF333333))), - centerTitle: true, - leading: IconButton( - icon: Icon(Icons.arrow_back_ios, color: Colors.black), - onPressed: () => Navigator.of(context).pop(), - ), - actions: const [ - ReturnToHomepage(), - ], - elevation: 0, - ), - body: Column( - children: [ - Container( - margin: EdgeInsets.all(15.r), - height: 30.r, - child: Row( - children: [ - Expanded( - child: Container( - padding: EdgeInsets.only(left: 10.r, right: 10.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.r), - border: Border.all(width: 1.r, color: Color(0xFFDDDDDD)), - color: Colors.white, - ), - child: TextField( - controller: logic.textController, - textInputAction: TextInputAction.next, - style: TextStyle( - color: const Color.fromRGBO(80, 87, 103, 1), - fontSize: 10.sp, - ), - decoration: InputDecoration( - hintText: "请输入知识点名称", - hintStyle: TextStyle(fontSize: 10.sp, - color: const Color.fromRGBO(153, 153, 153, 1)), - labelStyle: TextStyle(fontSize: 10.sp, - color: const Color.fromRGBO(148, 163, 182, 1)), - border: InputBorder.none, - ), - ), - ), - ), - SizedBox(width: 10.r,), - InkWell( - onTap: () { - state.page = 1; - logic.getList(); - }, - child: Container( - width: 50.r, - height: 30.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4.r), - color: Color(0xFF6888FD), - ), - child: Center( - child: Text('查询', style: TextStyle( - fontSize: 12.sp, color: Colors.white),), - ), - ), - ) - ], - ), - ), - - - Obx(() { - return JobConditionFilter( - jobType: 1, - controller: logic.tabController, - customTimeStr: state.customTimeStr.value, - customTime: logic.tabController.index != 2 || - ((state.dateEnd == null || state.dateEnd == '') && - (state.dateStart == null || state.dateStart == '')) - ? null - : PickerDateRange( - state.dateStart == null || state.dateStart == '' - ? null - : DateTime - .parse(state.dateStart!), - state.dateEnd == null || state.dateEnd == '' ? null : DateTime - .parse(state.dateEnd!), - ), - onTimeFilter: (String? startTime, String? endTime) { - EasyLoading.show(status: 'loading...'); - if (startTime == null && endTime == null) { - if (logic.tabController.index == 2) { - logic.tabController.animateTo(0); - } - state.dateStart = Utils.getWeekStartDate().toString().substring(0, 10); - state.dateEnd = Utils.getWeekEndDate().toString().substring(0, 10); - state.customTimeStr.value = '自定义'; - } else { - state.dateStart = startTime ?? ''; - state.dateEnd = endTime ?? ''; - } - state.page = 1; - logic.getList(); - // _refreshController2.callRefresh(); - }, - refreshTime: (value) { - if (value != null && value.startDate != null) { - state.customTimeStr.value = - value.startDate?.toString().substring(0, 10) ?? ''; - if (value.endDate != null) { - if (!Utils.isPad() && - value.startDate!.year == value.endDate!.year) { - state.customTimeStr.value = - '${value.startDate.toString().substring(5, 10)}~${value - .endDate.toString().substring(5, 10)}'; - } else { - state.customTimeStr.value = - '${state.customTimeStr.value}~${value.endDate?.toString() - .substring(0, 10)}'; - } - } - } - },); - }), - Expanded( - child: Padding( - padding: EdgeInsets.symmetric(vertical: 10.r), - child: Obx(() { - return EasyRefresh( - firstRefresh: false, - taskIndependence: true, - controller: logic.refreshController, - header: MaterialHeader(), - footer: TaurusFooter(), - onRefresh: () async { - state.page = 1; - logic.getList(); - }, - onLoad: () async { - if (state.page < state.totalPages) { - state.page += 1; - logic.getList(); - } - }, - child: state.dataList.isNotEmpty - ? ListView.builder( - itemCount: state.dataList.value.length, - itemBuilder: (context, index) { - KnowledgePointsGrasp item = state.dataList[index]; - return InkWell( - onTap: () { - Get.toNamed(Routes.knowledgePointsGraspDetailPage,arguments: {'dateStart':state.dateStart,'dateEnd':state.dateEnd,'knowledgeId':item.knowledgeId,'knowledgeName':item.knowledgeName}); - }, - child: Container( - margin: EdgeInsets.symmetric( - vertical: 5.r, horizontal: 14.r), - padding: EdgeInsets.symmetric( - vertical: 14.r, horizontal: 10.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(10.r)), - color: Colors.white), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Expanded( - child: Text( - item.knowledgeName, - style: TextStyle(fontSize: 14.sp, - color: Color(0xFF505050)), - )), - - Container( - width: 49.r, - height: 22.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(20.r)), - border: Border.all(width: 1.r, - color: Color(0xFF6888FD)), - ), - child: Row( - mainAxisAlignment: MainAxisAlignment - .center, - children: [ - Text( - '${item.count}次', - style: TextStyle(fontSize: 10.sp, - color: Color(0xFF6888FD)), - ), - Image.asset( - 'assets/images/right_icon_blue.png', - width: 8.r, height: 8.r,), - ], - ), - ), - ], - ), - SizedBox(height: 10.r,), - ProgressBar( - title: '正确率:', - color: Color(0xFF90E0BE), - percent: item.correctRate / 100, - padingEdg: EdgeInsets.zero, - marginEdg: EdgeInsets.only(top: 8.h)), - ], - ), - ), - ); - }) - : const MyEmptyWidget(), - ); - }), - ), - ), - ], - ), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} \ No newline at end of file diff --git a/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_state.dart b/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_state.dart deleted file mode 100644 index 4406b97..0000000 --- a/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_state.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/common/job/knowledge_report_detail.dart'; - -class KnowledgePointsGraspDetailState { - KnowledgePointsGraspDetailState() { - ///Initialize variables - } - - late String dateStart = ''; - late String dateEnd = ''; - late int knowledgeId = 0; - late RxList dataList=RxList(); - late RxList studentList=RxList(); - late RxString knowledgeName=''.obs; -} diff --git a/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_view.dart b/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_view.dart deleted file mode 100644 index f53d850..0000000 --- a/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_view.dart +++ /dev/null @@ -1,293 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:flutter_easyrefresh/easy_refresh.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:percent_indicator/percent_indicator.dart'; -import 'package:school_asignment_app/common/job/knowledge_report_detail.dart'; -import 'package:school_asignment_app/common/utils/toast_utils.dart'; -import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; -import 'package:school_asignment_app/page/global_widget/ReturnToHomepage.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -import 'package:school_asignment_app/page/global_widget/show_student_list.dart'; - -import 'knowledge_points_grasp_detail_logic.dart'; - -class KnowledgePointsGraspDetailPage extends StatefulWidget { - const KnowledgePointsGraspDetailPage({Key? key}) : super(key: key); - - @override - State createState() => - _KnowledgePointsGraspDetailPageState(); -} - -class _KnowledgePointsGraspDetailPageState - extends State { - final logic = Get.find(); - final state = Get - .find() - .state; - - @override - Widget build(BuildContext context) { - void showImg(imgUrl, context) { - if (imgUrl != null && imgUrl != '') { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - insetPadding: - EdgeInsets.symmetric(vertical: 55.r, horizontal: 45.r), - contentPadding: EdgeInsets.all(0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(15.r))), - content: Container( - width: MediaQuery - .of(context) - .size - .width, - // height: MediaQuery.of(context).size.height, - child: Image.network(imgUrl), - ), - ); - }, - ); - } else { - ToastUtils.showError('暂无图片'); - } - - EasyLoading.dismiss(); - } - - void showStudent(homeworkId, templateId, questionNo, title) async { - logic.getStudents(homeworkId, templateId, questionNo); - - showDialog( - context: context, - builder: (BuildContext context) { - return Obx(() { - return ShowStudentList(title: title, - studentList: state.studentList.value, - homeworkId: homeworkId,); - }); - }, - ); - EasyLoading.dismiss(); - } - - return Scaffold( - backgroundColor: Color.fromRGBO(245, 245, 245, 1), - appBar: AppBar( - backgroundColor: Colors.white, - title: Obx(() { - return Text(state.knowledgeName.value, - style: TextStyle(fontSize: 14.sp, color: Color(0xFF333333))); - }), - centerTitle: true, - leading: IconButton( - icon: Icon(Icons.arrow_back_ios, color: Colors.black), - onPressed: () => Navigator.of(context).pop(), - ), - actions: const [ - ReturnToHomepage(), - ], - elevation: 0, - ), - body: Padding( - padding: EdgeInsets.symmetric(vertical: 10.r), - child: Obx(() { - return EasyRefresh( - firstRefresh: false, - taskIndependence: true, - controller: logic.refreshController, - header: MaterialHeader(), - footer: TaurusFooter(), - onRefresh: () async { - logic.getList(); - }, - onLoad: () async { - // getList(); - }, - child: state.dataList.isNotEmpty - ? ListView.builder( - itemCount: state.dataList.length, - itemBuilder: (context, index) { - KnowledgeReportDetail item = state.dataList[index]; - return InkWell( - onTap: () { - /* RouterManager.router.navigateTo( - context, - RouterManager.quickCheckPersonalPath + - '?jobId=${item.jobName}&studentId=$studentId', - transition: getTransition(), - );*/ - }, - child: Container( - margin: EdgeInsets.symmetric( - vertical: 5.r, horizontal: 14.r), - padding: EdgeInsets.symmetric( - vertical: 14.r, horizontal: 10.r), - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(10.r)), - color: Colors.white), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - item.publishTime.substring(0, 10), - style: TextStyle( - fontSize: 14.sp, - color: Color(0xFF505050)), - ), - SizedBox( - width: 10.r, - ), - Expanded( - child: Text( - item.homeworkName, - style: TextStyle( - fontSize: 14.sp, - color: Color(0xFF505050)), - )), - InkWell( - onTap: () { - EasyLoading.show(status: 'loading...'); - showImg(item.questionPicture, context); - }, - child: Container( - width: 49.r, - height: 22.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(20.r)), - border: Border.all( - width: 1.r, - color: Color(0xFF8B8B8B)), - ), - child: Center( - child: Text( - '第${item.questionNo}题', - style: TextStyle( - fontSize: 10.sp, - color: Color(0xFF8B8B8B)), - ), - ), - ), - ), - ], - ), - SizedBox( - height: 10.r, - ), - Container( - margin: EdgeInsets.only(top: 8.h), - padding: EdgeInsets.zero, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - InkWell( - onTap: () { - EasyLoading.show(status: 'loading...'); - showStudent( - item.homeworkId, item.templateId, - item.questionNo, item.homeworkName); - }, - child: Container( - margin: EdgeInsets.only(right: 6.r), - width: 56.r, - height: 20.r, - decoration: BoxDecoration( - color: Color(0xFFD4FFED), - borderRadius: - BorderRadius.circular(20.r), - ), - child: Row( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - quickText('正确率', - color: Color(0xFF4CC793), - size: 10.sp), - Image.asset( - 'assets/images/icon_back_green.png', - width: 8.r, - height: 8.r, - ) - ], - )), - ), - Expanded( - flex: 1, - child: Container( - child: Row( - children: [ - Expanded( - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.circular( - 10.r), - ), - child: LinearPercentIndicator( - padding: EdgeInsets.zero, - animation: true, - lineHeight: 8.h, - animationDuration: 2500, - percent: - item.correctRate / 100, - progressColor: - Color(0xFF90E0BE), - backgroundColor: - Color(0xFFE8E8E8), - barRadius: - Radius.circular(10.r), - ), - ), - ), - SizedBox(width: 4.w), - quickText( - '${item.correctRate.toStringAsFixed( - 0)}%', - size: 10.sp, - color: Color(0xFF606060)) - ], - ), - ), - ), - ], - ), - ), - /* progressBar(context, - title: '正确率 >', - color: Color(0xFF90E0BE), - percent: item.correctRate / 100, - padingEdg: EdgeInsets.zero, - marginEdg: EdgeInsets.only(top: 8.h), - studentCall:showStudent(item.questionId,item.jobName), - ),*/ - ], - ), - ), - ); - }) - : const MyEmptyWidget(), - ); - }), - ), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} diff --git a/lib/page/home_page/children/my_info.dart b/lib/page/home_page/children/my_info.dart deleted file mode 100644 index e8c474e..0000000 --- a/lib/page/home_page/children/my_info.dart +++ /dev/null @@ -1,317 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/user_info.dart'; -import 'package:school_asignment_app/common/job/user_info_detail.dart'; -import 'package:school_asignment_app/common/store/app_storage_key.dart'; -import 'package:school_asignment_app/common/store/user_store.dart'; -import 'package:school_asignment_app/common/utils/storage.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; - -class MyInfo extends StatefulWidget { - const MyInfo({super.key}); - - @override - State createState() => _MyInfoState(); -} - -class _MyInfoState extends State with AutomaticKeepAliveClientMixin { - late Rx userInfo = UserStore.to.userDetailInfo; - - // 确认对话框 - _showAlertDialog(context1) async { - await showDialog( - // 表示点击灰色背景的时候是否消失弹出框 - barrierDismissible: false, - context: context1, - builder: (context) { - return AlertDialog(title: quickText("提示信息"), content: quickText("您确定要退出登录吗?"), actions: [ - TextButton( - child: quickText("取消"), - onPressed: () { - Navigator.pop(context, 'Cancle'); - }, - ), - TextButton( - child: quickText("确定"), - onPressed: () { - /* ref.read(markingKeyboardProvider.notifier).clean(); - ref.read(markingSubtopicSwitchingProvider.notifier).clean(); - ref.read(userTokenProvider.notifier).clean(); - ref.read(userProvider.notifier).clean();*/ - StorageService.to.remove(AppStorageKey.token.value); - StorageService.to.remove(AppStorageKey.userInfo.value); - Navigator.pop(context, "Ok"); - Get.offAllNamed(Routes.login); - }) - ]); - }); - } - - @override - bool get wantKeepAlive => true; - - @override - Widget build(BuildContext context) { - super.build(context); - - final personalInfoTitleStly = TextStyle( - color: const Color.fromRGBO(80, 87, 103, 1), - fontSize: 16.sp, - ); - final personalInfoValStly = TextStyle( - color: const Color.fromRGBO(148, 163, 182, 1), - fontSize: 16.sp, - ); - - return AnnotatedRegion( - value: const SystemUiOverlayStyle( - statusBarColor: Colors.transparent, - systemNavigationBarIconBrightness: Brightness.light, - statusBarIconBrightness: Brightness.light, - statusBarBrightness: Brightness.dark, - ), - child: Stack( - children: [ - SizedBox( - height: double.infinity, - child: Column( - children: [ - Container( - height: 240.h, - width: double.infinity, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/personal_bgi.png'), - fit: BoxFit.cover, - ), - ), - ), - Expanded( - child: Container( - color: const Color.fromRGBO(248, 248, 248, 1), - )) - ], - ), - ), - SafeArea( - child: Scaffold( - backgroundColor: Colors.transparent, - body: Column( - children: [ - Stack( - alignment: const FractionalOffset(0.04, 0.1), - children: [ - Container( - height: 200.h, - alignment: Alignment.center, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(80.w), - child: Container( - width: 80.w, - height: 80.w, - padding: EdgeInsets.all(4.w), - decoration: BoxDecoration( - border: Border.all( - width: 1.w, - color: Colors.white, - ), - borderRadius: BorderRadius.all( - Radius.circular(40.w), - ), - boxShadow: [ - BoxShadow( - color: const Color.fromRGBO(46, 91, 255, 0.2), - offset: Offset(4.w, 6.h), //阴影y轴偏移量 - blurRadius: 8, //阴影模糊程度 - spreadRadius: 0.2, //阴影扩散程度 - ) - ], - ), - child: Image.asset('assets/images/default_user_dead.png') - - /* CachedNetworkImage( - fit: BoxFit.cover, - imageUrl:'', - placeholder: (context, url) => Image.asset('assets/images/default_user_dead.png'), - errorWidget: (context, url, error) => - Image.asset('assets/images/default_user_dead.png'), - ),*/ - ), - ), - InkWell( - onTap: () { - /*if (tokenState == '' || userState.id == '') { - toLoginPage(context); - }*/ - }, - child: Container( - margin: EdgeInsets.only(top: 16.h), - child: Text( - userInfo.value?.name ?? '请前往登录', - style: TextStyle(fontSize: 16.sp, color: Colors.white), - ), - ), - ), - ], - ), - ), - /* InkWell( - onTap: () => Get.back(), - child: Icon(Icons.arrow_back_ios_new_rounded, color: Colors.white, size: 24.sp), - ),*/ - ], - ), - SizedBox(height: 14.h), - Container( - margin: EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w), - padding: EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w), - height: 240.h, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(6.w)), - color: Colors.white, - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(46, 91, 255, 0.1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 20, //阴影模糊程度 - spreadRadius: 10, //阴影扩散程度 - ) - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [Text('账号', style: personalInfoTitleStly), Text(userInfo.value?.name ?? '请前往登录', style: personalInfoValStly)], - ), - Container( - height: 1.w, - color: const Color.fromRGBO(240, 243, 255, 1), - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [Text('所在学校', style: personalInfoTitleStly), Text(userInfo.value?.schoolName ?? '', style: personalInfoValStly)], - ), - /* Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('担任职位', style: personalInfoTitleStly), - SizedBox(width: 20.w), - Expanded( - child: Text( - userInfo.value?.gender??'', - maxLines: 2, - textAlign: TextAlign.right, - overflow: TextOverflow.ellipsis, - style: personalInfoValStly, - ), - ) - ], - ), - Container(height: 1.w, color: const Color.fromRGBO(240, 243, 255, 1)), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('所授科目', style: personalInfoTitleStly), - Expanded( - child: Text( - userState.subjectIds.map((e) => getSubjectEnumName(e)).toList().join(','), - maxLines: 2, - textAlign: TextAlign.right, - overflow: TextOverflow.ellipsis, - style: personalInfoValStly, - ), - ) - ], - ),*/ - Container(height: 1.w, color: const Color.fromRGBO(240, 243, 255, 1)), - Padding( - padding: EdgeInsets.only(top: 10.h), - child: InkWell( - onTap: () { - Get.toNamed(Routes.otherPage); - }, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('其他', style: personalInfoTitleStly), - Icon( - Icons.arrow_forward_ios, - color: const Color.fromRGBO(80, 87, 103, 1), - size: 16.sp, - ) - ], - ), - ), - ) - ], - ), - ), - Expanded( - child: Column( - children: [ - const Expanded(child: SizedBox()), - Container( - margin: EdgeInsets.only(bottom: 40.h), - alignment: Alignment.bottomCenter, - child: InkWell( - child: Container( - padding: EdgeInsets.symmetric(vertical: 14.h), - margin: EdgeInsets.only(right: 16.w, left: 16.w), - decoration: BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(6.w), - ), - color: Colors.white, - boxShadow: [ - BoxShadow( - color: const Color.fromRGBO(46, 91, 255, 0.2), - offset: Offset(2.w, 2.h), //阴影y轴偏移量 - blurRadius: 14, //阴影模糊程度 - spreadRadius: 0.5, //阴影扩散程度 - ) - ], - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.exit_to_app_outlined, - size: 16.sp, - color: const Color.fromRGBO(148, 163, 182, 1), - ), - Container( - width: 6.w, - ), - Text( - '退出登录', - style: TextStyle(color: const Color.fromRGBO(148, 163, 182, 1), fontSize: 16.sp), - ), - ], - ), - ), - onTap: () { - _showAlertDialog(context); - }, - ), - ), - ], - ), - ), - ], - ), - ), - ), - ], - ), - ); - } -} diff --git a/lib/page/home_page/children/quick_data_check/quick_data_check_logic.dart b/lib/page/home_page/children/quick_data_check/quick_data_check_logic.dart deleted file mode 100644 index e87d7bd..0000000 --- a/lib/page/home_page/children/quick_data_check/quick_data_check_logic.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; - -import 'quick_data_check_state.dart'; - -class QuickDataCheckLogic extends GetxController with RequestToolMixin{ - final QuickDataCheckState state = QuickDataCheckState(); - - @override - void onInit(){ - super.onInit(); - state.homeworkId.value = Get.arguments['homeworkId']??''; - state.classId.value = Get.arguments['classId']??''; - state.className.value = Get.arguments['className']??''; - state.grade = Get.arguments['grade']; - EasyLoading.show(status: 'loading...'); - getWorkData(); - } - - void getWorkData() async{ - HomeworkDetails data = await getClient(). getHomeworkDetails(state.homeworkId.value,state.classId.value); - state.dataCount = Utils.getHomeworkData(data); - state.homeData = data; - state.kgReport.value = data.questions.where((w)=>w.questionType == 1).toList(); - state.zgReport.value = data.questions.where((w)=>w.questionType == 2).toList(); - state.studentList.value = data.students; - state.hasData.value = true; - EasyLoading.dismiss(); - } - -} diff --git a/lib/page/home_page/children/quick_data_check/quick_data_check_state.dart b/lib/page/home_page/children/quick_data_check/quick_data_check_state.dart deleted file mode 100644 index e99610a..0000000 --- a/lib/page/home_page/children/quick_data_check/quick_data_check_state.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; - -class QuickDataCheckState { - QuickDataCheckState() { - ///Initialize variables - } - - late RxString homeworkId = ''.obs; - late RxString classId = ''.obs; - late RxString className = ''.obs; - late int grade; - late CountData dataCount = CountData(); - late RxBool hasData = false.obs; - late RxList kgReport = RxList(); - late RxList zgReport = RxList(); - late RxList studentList = RxList(); - late HomeworkDetails homeData; -} - -class CountData extends Object { - int? kgtOkCount = 0; - int? kgtDtlCount = 0; - double? kgtAnswerRate = 0; - double? kgtOkRate = 0; - int? kgtAnswerCount = 0; - int? kgtCount = 0; - int? zgtDtlCount = 0; - int? zgtOkCount = 0; - int? zgtAnswerCount = 0; - double? zgtAnswerRate = 0; - double? zgtOkRate = 0; - int? zgtCount = 0; - int? studentCount = 0; - List? priorityStudents = []; - int? studentSubmitCount = 0; - CountData({this.kgtOkCount, this.kgtDtlCount,this.kgtAnswerRate,this.kgtAnswerCount,this.kgtOkRate,this.studentCount, - this.kgtCount,this.zgtAnswerCount,this.zgtOkCount,this.zgtDtlCount,this.zgtAnswerRate,this.zgtOkRate,this.zgtCount,this.priorityStudents, - this.studentSubmitCount,}); -} diff --git a/lib/page/home_page/children/quick_data_check/quick_data_check_view.dart b/lib/page/home_page/children/quick_data_check/quick_data_check_view.dart deleted file mode 100644 index e9df1f5..0000000 --- a/lib/page/home_page/children/quick_data_check/quick_data_check_view.dart +++ /dev/null @@ -1,360 +0,0 @@ -import 'package:fl_chart/fl_chart.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:get_storage/get_storage.dart'; -import 'package:percent_indicator/percent_indicator.dart'; -import 'package:school_asignment_app/common/utils/enum_untils.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; -import 'package:school_asignment_app/page/global_widget/ReturnToHomepage.dart'; -import 'package:school_asignment_app/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart'; -import 'package:school_asignment_app/page/home_page/children/quick_data_check/widget/quick_data_check_bottom.dart'; -import 'package:school_asignment_app/page/home_page/children/quick_data_check/widget/report_table.dart'; - -import 'quick_data_check_logic.dart'; - -class QuickDataCheckPage extends StatefulWidget { - const QuickDataCheckPage({Key? key}) : super(key: key); - - @override - State createState() => _QuickDataCheckPageState(); -} - -class _QuickDataCheckPageState extends State { - final logic = Get.find(); - final state = Get - .find() - .state; - - @override - Widget build(BuildContext context) { - return AnnotatedRegion( - value: const SystemUiOverlayStyle( - statusBarColor: Colors.transparent, - systemNavigationBarIconBrightness: Brightness.light, - statusBarIconBrightness: Brightness.light, - statusBarBrightness: Brightness.dark, - ), - child: Container( - padding: EdgeInsets.only(top: MediaQuery - .of(context) - .padding - .top), - height: MediaQuery - .of(context) - .size - .height, - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Color(0xFF6889FD), - Color(0xFFF5F5F5), - ], - stops: [ - 0.09, - 0.3 - ])), - child: - - Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - IconButton( - icon: const Icon(Icons.arrow_back_ios, color: Colors.white), - onPressed: () => Navigator.of(context).pop(), - ), - Expanded( - child: Padding( - padding: EdgeInsets.only(right: 8.r), - child: Center( - child: Text( - '数据快查', - style: TextStyle( - fontSize: 14.sp, color: Colors.white), - )), - )), - const ReturnToHomepage(bgColor: Colors.white,), - ], - ), - SizedBox(height: 10.r), - Obx(() { - if (state.hasData.value) { - return Expanded( - child: SingleChildScrollView( - child: Column( - children: [ - Padding( - padding: EdgeInsets.only(left: 14.r, top: 2.r), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Image.asset( - 'assets/images/job_report_class_icon.png', - width: 22.r, - height: 22.r, - ), - SizedBox( - width: 6.r, - ), - Obx(() { - return Text( - '${EnumUtils.formatGrade( - state.grade)}${state.className.value}', - style: TextStyle( - fontSize: 14.r, color: Colors.white), - ); - }) - ], - ), - ), - Container( - padding: EdgeInsets.symmetric( - vertical: 15.r, horizontal: 15.r), - margin: EdgeInsets.symmetric( - vertical: 10.r, horizontal: 14.r), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: - BorderRadius.all(Radius.circular(6.r))), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - height: 2.r, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 12.r, - height: 12.r, - decoration: BoxDecoration( - color: const Color(0xFF4CC793), - borderRadius: BorderRadius.all( - Radius.circular(7.r))), - ), - SizedBox( - width: 6.r, - ), - Text( - '已提交', - style: TextStyle( - fontSize: 12.sp, - color: Color(0xFF333333)), - ), - SizedBox( - width: 35.r, - ), - Container( - width: 12.r, - height: 12.r, - decoration: BoxDecoration( - color: const Color(0xFF6888FD), - borderRadius: BorderRadius.all( - Radius.circular(7.r))), - ), - SizedBox( - width: 6.r, - ), - Text( - '未提交', - style: TextStyle( - fontSize: 12.sp, - color: const Color(0xFF333333)), - ) - ], - ), - SizedBox( - height: 2.r, - ), - //环形图 - SizedBox( - height: MediaQuery - .of(context) - .size - .width * 0.3, - child: PieChart( - PieChartData( - borderData: FlBorderData(show: false), - sectionsSpace: 0, - centerSpaceRadius: - MediaQuery - .of(context) - .size - .width * 0.06, - sections: [ - PieChartSectionData( - color: const Color(0xFF4CC793), - value: state.dataCount - .studentSubmitCount! / - state.dataCount.studentCount! * - 100, - radius: - MediaQuery - .of(context) - .size - .width * - 0.07 + - 5, - title: '${state.dataCount - .studentSubmitCount}人', - titleStyle: TextStyle( - fontSize: 14.sp, - color: Colors.white, - ), - ), - PieChartSectionData( - color: const Color(0xFF6888FD), - value: (state.dataCount - .studentCount! - state.dataCount - .studentSubmitCount!) / - state.dataCount.studentCount! * - 100, - radius: - MediaQuery - .of(context) - .size - .width * - 0.07, - title: '${state.dataCount - .studentCount! - state.dataCount - .studentSubmitCount!}人', - titleStyle: TextStyle( - fontSize: 14.sp, - color: Colors.white, - ), - ), - ], - ), - ), - ), - // 客观进度条 - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - '客观题答题进度', - style: TextStyle( - fontSize: 10.sp, - color: const Color(0xFF8B8B8B)), - ), - Text( - '${state.dataCount.kgtAnswerRate! - .toStringAsFixed(0)}%', - style: TextStyle( - fontSize: 10.sp, - color: const Color(0xFF333333)), - ), - ], - ), - SizedBox(height: 6.r), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Expanded( - flex: 10, - child: LinearPercentIndicator( - padding: EdgeInsets.zero, - animation: true, - lineHeight: 9.h, - animationDuration: 2500, - percent: state.dataCount - .kgtAnswerRate! / 100, - progressColor: const Color( - 0xFFFF7F22), - backgroundColor: const Color( - 0xFFEAEAEA), - barRadius: Radius.circular(10.r), - )), - ], - ), - SizedBox(height: 20.r), - // 主观进度条 - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - '主观题答题进度', - style: TextStyle( - fontSize: 10.sp, - color: const Color(0xFF8B8B8B)), - ), - Text( - '${state.dataCount.zgtAnswerRate! - .toStringAsFixed(0)}%', - style: TextStyle( - fontSize: 10.sp, - color: const Color(0xFF333333)), - ), - ], - ), - SizedBox(height: 6.r), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Expanded( - flex: 10, - child: LinearPercentIndicator( - padding: EdgeInsets.zero, - animation: true, - lineHeight: 9.h, - animationDuration: 2500, - percent: state.dataCount - .zgtAnswerRate! / 100, - progressColor: const Color( - 0xFFFF7F22), - backgroundColor: const Color( - 0xFFEAEAEA), - barRadius: Radius.circular(10.r), - )), - ], - ), - ], - ), - ), - QuickDataCheckBottom(jobData: state.studentList.value, - jobId: state.homeworkId.value, - kgCount: state.dataCount.kgtDtlCount!, - zgCount: state.dataCount.zgtDtlCount!,), - //客观题、主观题 - KgtZgtTable(studentCount:state.dataCount.studentCount!,homeworkId:state.homeworkId.value,kgReport: state.kgReport,zgReport: state.zgReport,kgtOkRate:state.dataCount.kgtOkRate! - .toStringAsFixed(0),zgtOkRate:state.dataCount.zgtOkRate! - .toStringAsFixed(0)), - ], - ), - )); - } else { - return Padding( - padding: EdgeInsets.only( - top: MediaQuery - .of(context) - .size - .height / 2 - 200.r), - child: const MyEmptyWidget() - ); - } - }) - - - ], - ), - ), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} \ No newline at end of file diff --git a/lib/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart b/lib/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart deleted file mode 100644 index 3694375..0000000 --- a/lib/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart +++ /dev/null @@ -1,155 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; -import 'package:school_asignment_app/page/home_page/children/quick_data_check/widget/report_table.dart'; - -class KgtZgtTable extends StatefulWidget { - final int studentCount; - final String homeworkId; - final List kgReport; - final List zgReport; - final String kgtOkRate; - final String zgtOkRate; - - const KgtZgtTable( - {Key? key, - required this.studentCount, - required this.homeworkId, - required this.kgReport, - required this.zgReport, - required this.kgtOkRate, - required this.zgtOkRate}) - : super(key: key); - - @override - State createState() => _KgtZgtTableState(); -} - -class _KgtZgtTableState extends State { - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Column( - children: [ - //客观题 - Container( - padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 10.r), - margin: EdgeInsets.symmetric(vertical: 10.r, horizontal: 14.r), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(6.r)), - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - '客观题', - style: TextStyle( - fontSize: 14.sp, - color: Color(0xFF5C5C5C), - fontWeight: FontWeight.w600), - ), - SizedBox( - width: 10.r, - ), - Text( - '${widget.kgtOkRate}%', - style: TextStyle( - fontSize: 14.sp, - color: Color(0xFF6888FD), - fontWeight: FontWeight.w600), - ), - ], - ), - SizedBox( - height: 6.r, - ), - SizedBox( - height: widget.kgReport.length > 10 - ? 300.r - : widget.kgReport.length * 40.r + - (Utils.isPad() == true ? 40.r : 65.r), - child: ReportTable( - headList: const ['题', '作答率', '作答人数', '正确率', '标准答案', '优先批阅概况'], - bodyList: widget.kgReport, - fixedCols: 1, - fixedRows: 1, - jobId: widget.homeworkId, - studentCount: widget.studentCount, - ), - ), - if(widget.kgReport.isEmpty) - MyEmptyWidget(imgWidth:100.r,imgHeight: 100.r,font:8.sp), - ], - ), - ), - //主观题 - Container( - padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 14.r), - margin: EdgeInsets.symmetric(vertical: 10.r, horizontal: 10.r), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(6.r)), - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - '主观题', - style: TextStyle( - fontSize: 14.sp, - color: const Color(0xFF5C5C5C), - fontWeight: FontWeight.w600), - ), - SizedBox( - width: 6.r, - ), - Text( - '${widget.zgtOkRate}%', - style: TextStyle( - fontSize: 14.sp, - color: const Color(0xFF6888FD), - fontWeight: FontWeight.w600), - ), - ], - ), - SizedBox( - height: 10.r, - ), - SizedBox( - height: widget.zgReport.length > 10 - ? 300.r - : widget.zgReport.length * 40.r + - (Utils.isPad() == true ? 40.r : 65.r), - child: ReportTable( - headList: const ['题', '作答率', '作答人数', '正确率', '查看原题', '优先批阅概况'], - bodyList: widget.zgReport, - fixedCols: 1, - fixedRows: 1, - isKG: true, - jobId: widget.homeworkId, - studentCount: widget.studentCount, - ), - ), - if(widget.zgReport.isEmpty) - MyEmptyWidget(imgWidth:100.r,imgHeight: 100.r,font:8.sp), - ], - ), - ), - ], - ); - } -} diff --git a/lib/page/home_page/children/quick_data_check/widget/report_table.dart b/lib/page/home_page/children/quick_data_check/widget/report_table.dart deleted file mode 100644 index 15487e0..0000000 --- a/lib/page/home_page/children/quick_data_check/widget/report_table.dart +++ /dev/null @@ -1,461 +0,0 @@ -import 'package:data_table_2/data_table_2.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/annotated_class.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/common/utils/toast_utils.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; -import 'package:school_asignment_app/page/global_widget/imgDialog.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; - - -class ReportTable extends StatefulWidget { - final List headList; - final List bodyList; - final int? fixedRows; - final int? fixedCols; - final bool? isKG; - final String jobId; - final int studentCount; - - const ReportTable({ - Key? key, - required this.headList, - required this.bodyList, - required this.jobId, - required this.studentCount, - this.fixedCols = 0, - this.fixedRows = 0, - this.isKG = false, - }) : super(key: key); - - @override - State createState() => _ReportTableState(); -} - -class _ReportTableState extends State { - final ScrollController _controller = ScrollController(); - int? _sortColumnIndex; - final bool _sortAscending = true; - - void showPeopleListDialog( - {required BuildContext context, - required String title, - required String questionNo, - required List arr, - List? dcList}) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - // insetPadding: EdgeInsets.symmetric(vertical: 20.r,horizontal: 20.r), - contentPadding: EdgeInsets.all(20.r), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(15.r))), - content: SizedBox( - width: MediaQuery.of(context).size.width * 0.7, - height: MediaQuery.of(context).size.height * 0.7, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Center( - child: Text( - title, - style: TextStyle( - fontSize: 15.sp, - color: const Color(0xFF3C3C3C), - fontWeight: FontWeight.w500), - ), - ), - SizedBox( - height: 5.r, - ), - Row( - children: [ - Text( - widget.isKG == true ? '主观题' : '客观题', - style: TextStyle( - fontSize: 14.sp, color: const Color(0xFF436CFF)), - ), - Text( - '―', - style: TextStyle( - fontSize: 14.sp, color: const Color(0xFF436CFF)), - ), - Text( - '第$questionNo题', - style: TextStyle( - fontSize: 14.sp, color: Color(0xFF436CFF)), - ), - ], - ), - SizedBox( - height: 15.r, - ), - dcList != null - ? Row( - children: [ - Expanded( - flex: 1, - child: Center( - child: Text( - '未作答人', - style: TextStyle( - fontSize: 12.sp, - color: Color(0xFF6A6A6A)), - ))), - Expanded( - flex: 1, - child: Center( - child: Text( - '答对人数', - style: TextStyle( - fontSize: 12.sp, - color: Color(0xFF6A6A6A)), - ))), - Expanded( - flex: 1, - child: Center( - child: Text( - '答错人', - style: TextStyle( - fontSize: 12.sp, - color: Color(0xFF6A6A6A)), - ))), - ], - ) - : Padding( - padding: EdgeInsets.only(left: 15.r), - child: Text( - title, - style: TextStyle( - fontSize: 12.sp, color: Color(0xFF6A6A6A)), - ), - ), - SizedBox( - height: 5.r, - ), - if (dcList != null) - Expanded( - child: ListView.builder( - shrinkWrap: true, - itemBuilder: (context, index) { - var item = arr[index]; - return Container( - padding: EdgeInsets.symmetric(vertical: 5.r), - color: - index.isOdd ? Colors.white : Color(0xFFF0F0F0), - child: Row( - children: [ - Expanded( - flex: 1, - child: InkWell( - onTap: () { - goQuickCheckPersonalPath( - item['noAnswerStudents'].studentId); - }, - child: Center( - child: Text( - item['noAnswerStudents']?.studentName??'--', - style: TextStyle( - fontSize: 12.sp, - color: Color(0xFF323232)), - )))), - Expanded( - flex: 1, - child: InkWell( - onTap: () { - goQuickCheckPersonalPath( - item['answerOkStudents'].studentId); - }, - child: Center( - child: Text( - item['answerOkStudents']?.studentName??'--', - style: TextStyle( - fontSize: 12.sp, - color: Color(0xFF323232)), - )))), - Expanded( - flex: 1, - child: InkWell( - onTap: () { - goQuickCheckPersonalPath( - item['answerNgStudents'].studentId); - }, - child: Center( - child: Text( - item['answerNgStudents']?.studentName??'--', - style: TextStyle( - fontSize: 12.sp, - color: Color(0xFF323232)), - )))), - ], - ), - ); - }, - itemCount: arr.length, - ), - ) - else - arr.isNotEmpty - ? Expanded( - child: ListView.builder( - shrinkWrap: true, - itemBuilder: (context, index) { - Dtls item = arr[index]; - return InkWell( - onTap: () { - goQuickCheckPersonalPath(item.studentId); - }, - child: Container( - padding: EdgeInsets.symmetric( - vertical: 5.r, horizontal: 15.r), - color: index.isOdd - ? Colors.white - : Color(0xFFF0F0F0), - child: Text( - item.studentName!??'--', - style: TextStyle( - fontSize: 12.sp, - color: Color(0xFF323232)), - ), - ), - ); - }, - itemCount: arr.length, - ), - ) - : const MyEmptyWidget() - ], - ), - ), - ); - }); - } - - void goQuickCheckPersonalPath(id) { - if (id != null) { - Get.toNamed(Routes.studentPersonalPage,arguments: {'studentId':id,'homeworkId':widget.jobId}); - } - } - - void zdHandle(BuildContext context, String title, String questionNo, - List noAnswerStudents, List answerNgStudents, List answerOkStudents) { - List list = []; - // Questions student = Questions('','',-1,-1,'',-1,'','',[],-1,-1,[] as double?); - if (noAnswerStudents.length > answerNgStudents.length && - noAnswerStudents.length > answerOkStudents.length) { - for (int i = 0; i < noAnswerStudents.length; i++) { - var obj = { - 'noAnswerStudents': noAnswerStudents[i], - 'answerNgStudents': - answerNgStudents.length > i ? answerNgStudents[i] : null, - 'answerOkStudents': - answerOkStudents.length > i ? answerOkStudents[i] : null - }; - list.add(obj); - } - } else if (answerNgStudents.length > noAnswerStudents.length && - answerNgStudents.length > answerOkStudents.length) { - for (int i = 0; i < answerNgStudents.length; i++) { - var obj = { - 'noAnswerStudents': - noAnswerStudents.length > i ? noAnswerStudents[i] : null, - 'answerNgStudents': answerNgStudents[i], - 'answerOkStudents': - answerOkStudents.length > i ? answerOkStudents[i] : null - }; - list.add(obj); - } - } else if (answerOkStudents.length > noAnswerStudents.length && - answerOkStudents.length > answerNgStudents.length) { - for (int i = 0; i < answerOkStudents.length; i++) { - var obj = { - 'noAnswerStudents': - noAnswerStudents.length > i ? noAnswerStudents[i] : null, - 'answerNgStudents': - answerNgStudents.length > i ? answerNgStudents[i] : null, - 'answerOkStudents': answerOkStudents[i] - }; - list.add(obj); - } - } - - showPeopleListDialog( - context: context, - title: title, - questionNo: questionNo, - arr: list, - dcList: []); - } - - void dcHandle( - BuildContext context, String title, String questionNo, List arr) { - showPeopleListDialog( - context: context, title: title, questionNo: questionNo, arr: arr); - } - - DataRow _getRow(int index, [Color? color]) { - assert(index >= 0); - var item = widget.bodyList[index]; - return DataRow2.byIndex( - index: index, - color: color != null ? MaterialStateProperty.all(color) : null, - cells: [ - DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.questionNo.toString(), - style: TextStyle(fontSize: 10.sp, color: const Color(0xFF525252))), - ), - )), - DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text('${item.answerRate.toStringAsFixed(0)}%', - style: TextStyle(fontSize: 10.sp, color: const Color(0xFF525252))), - ), - )), - DataCell(InkWell( - onTap: () { - zdHandle(context, '作答人数', item.questionNo.toString(), item.noAnswerStudents, - item.answerNgStudents, item.answerOkStudents); - }, - child: Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('${item.answerCount}/${widget.studentCount}', - style: - TextStyle(fontSize: 10.sp, color: const Color(0xFF4CC793))), - Image.asset( - 'assets/images/green_right_icon.png', - width: 12.r, - height: 12.r, - ), - ], - ), - ), - ), - )), - DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text('${item.okRate.toStringAsFixed(0)}%', - style: TextStyle(fontSize: 10.sp, color: Color(0xFF525252))), - ), - )), - DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: widget.isKG == true - ? InkWell( - onTap: () { - if (item.questionPicture == null) { - ToastUtils.showInfo('当前试题没有原题'); - }else{ - ImageDialog.showImgDialog(context,item.questionPicture); - } - }, - child: Text('原题', - style: TextStyle( - fontSize: 10.sp, - color: widget.isKG == true - ? const Color(0xFFFF8A00) - : const Color(0xFF4CC793))), - ) - : Text(item.answer, - style: TextStyle( - fontSize: 10.sp, - color: widget.isKG == true - ? const Color(0xFFFF8A00) - : const Color(0xFF4CC793))), - ), - )), - DataCell(InkWell( - onTap: () { - // List parts = item.priorityGeneral.split('人'); - dcHandle(context, '优先批阅答错人', item.questionNo.toString(), - item.priorityInfo); - }, - child: Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('${item.priorityInfo.length}人答错', - style: - TextStyle(fontSize: 10.sp, color: const Color(0xFF6888FD))), - Image.asset( - 'assets/images/job_data_right_icon.png', - width: 10.r, - height: 10.r, - ) - ], - ), - ), - ), - )), - ], - ); - } - - @override - Widget build(BuildContext context) { - bool isPadFlag = Utils.isPad(); - return DataTable2( - dividerThickness: 0, - scrollController: _controller, - columnSpacing: 0, - horizontalMargin: 0, - dataRowHeight: 40.r, - bottomMargin: 0, - border: const TableBorder( - horizontalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - bottom: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - verticalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid)), - headingRowColor: MaterialStateProperty.resolveWith((states) => - widget.fixedCols! > 0 ? Colors.white : Colors.transparent), - headingRowDecoration: BoxDecoration(color: Color(0xFFE6E6E6)), - fixedColumnsColor: Color(0xFFE6E6E6), - fixedCornerColor: Colors.grey[400], - minWidth: widget.headList.length > 6 - ? 80.r * widget.headList.length - : isPadFlag - ? MediaQuery.of(context).size.width - : 85.r * widget.headList.length, - fixedTopRows: widget.fixedRows!, - fixedLeftColumns: widget.fixedCols!, - sortColumnIndex: _sortColumnIndex, - sortAscending: _sortAscending, - // onSelectAll: (val) => setState(() => selectAll(val)), - columns: List.generate(widget.headList.length, (index) { - var item = widget.headList[index]; - return DataColumn2( - label: Center( - child: Text(item, - style: TextStyle(fontSize: 10.sp, color: Color(0xFF505767))), - ), - // size: ColumnSize.S, - fixedWidth: index == 0 - ? 40.r - : widget.headList.length > 6 - ? 80.r - : isPadFlag - ? (MediaQuery.of(context).size.width - 8.r) / - widget.headList.length - : 85.r, - ); - }), - rows: List.generate(widget.bodyList.length, - (index) => _getRow(index, Color(0xFFF5F5F5)))); - } -} diff --git a/lib/page/home_page/children/read_over/read_over_logic.dart b/lib/page/home_page/children/read_over/read_over_logic.dart deleted file mode 100644 index 819ba22..0000000 --- a/lib/page/home_page/children/read_over/read_over_logic.dart +++ /dev/null @@ -1,156 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:flutter_easyrefresh/easy_refresh.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/enum_subject.dart'; -import 'package:school_asignment_app/common/job/work_student.dart'; -import 'package:school_asignment_app/common/job/work_student_params.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:school_asignment_app/common/store/user_store.dart'; - -import 'read_over_state.dart'; - -class ReadOverLogic extends GetxController with RequestToolMixin, GetTickerProviderStateMixin{ - final ReadOverState state = ReadOverState(); - late TabController tabController; - late TabController tabController2; - /* 待阅卷 */ - late final EasyRefreshController refreshController1; - late final EasyRefreshController refreshController2; - - WorkStudentParams params = WorkStudentParams( - assessType: 0, - pageSize: 10, - ); - WorkStudentParams params2 = WorkStudentParams( - assessType: 0, - pageSize: 10, - ); - - @override - void onInit() { - super.onInit(); - refreshController1 = EasyRefreshController(); - refreshController2 = EasyRefreshController(); - tabController = TabController( - length: 2, - vsync: this, - ); - tabController2 = TabController(length: 4, vsync: this); - EasyLoading.show(status:'loading...'); - getList(); - } -//待批阅列表 - void getList() async { - WorkStudent data = WorkStudent([], 0); - if(state.tabIndex.value == 0){ - params.pageNumber = state.page; - data = await getClient().getUnAnnotateList(params); - }else{ - params2.pageNumber = state.page; - data = await getClient().getAnnotatedList(params2); - } - - state.workList.value = data.items; - refreshController1.finishRefresh(); - refreshController2.finishRefresh(); - EasyLoading.dismiss(); - print('state.workList.length=${state.workList.length}'); - } - /// 刷新方法 - Future onMyRefresh(EasyRefreshController controller, int tab) async { - /* params.page = RequestConfig.basePage.page; - List lists = await getData(controller, params, isReFresh: true); - try { - tab == 1 ? (markingDatas1 = lists) : (markingDatas2 = lists); - } catch (e) {} - toUpState(setState, () {}, mounted);*/ - getList(); - } - - void getCollect(item) async{ - await getClient().getCollect(item.id); - getList(); - } - - /// 加载方法 - Future onMyLoad(EasyRefreshController controller, int tab) async { - /*params.page++; - List lists = await getData(controller, params); - if (lists.isNotEmpty) { - tab == 1 ? markingDatas1.addAll(lists) : markingDatas2.addAll(lists); - toUpState(setState, () {}, mounted); - }*/ - } - - /* Future showStudents( - BuildContext context, [ - bool? submitted = false, - String? className, - ]) async { - ToastUtils.showLoading(); - List students = []; - - showModalBottomSheet( - context: context, - elevation: 10, - backgroundColor: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20.r), - topRight: Radius.circular(20.r), - ), - ), - builder: (BuildContext context) { - return Padding( - padding: EdgeInsets.symmetric(horizontal: 2.w), - child: Column( - children: [ - Container( - margin: EdgeInsets.only(top: 14.h), - child: quickText( - '${className ?? ''}${submitted! ? '已提交' : '未提交'}作业学生', - size: 18.sp, - fontWeight: FontWeight.bold, - color: Color.fromRGBO(60, 60, 60, 1), - ), - ), - Expanded( - child: ListView( - padding: EdgeInsets.symmetric(vertical: 8.h, horizontal: 4.w), - children: [ - Wrap( - spacing: 6.0, // 主轴(水平)方向间距 - runSpacing: 4.0, // 纵轴(垂直)方向间距 - alignment: WrapAlignment.spaceAround, //沿主轴方向居中 - children: students.map((e) { - return Chip( - backgroundColor: Color.fromRGBO(239, 242, 255, 1), - avatar: CircleAvatar( - backgroundColor: Colors.white, - child: quickText(e.studentName.substring(0, 1), - size: 12.sp, color: Theme.of(context).primaryColor), - ), - label: quickText(e.studentName, color: Color.fromRGBO(80, 94, 110, 1), size: 12.sp), - ); - }).toList(), - ), - ], - ), - ) - ], - ), - ); - }, - ); - }*/ - - @override - void dispose() { - super.dispose(); - tabController.dispose(); - tabController2.dispose(); - refreshController1.dispose(); - refreshController2.dispose(); - } -} diff --git a/lib/page/home_page/children/read_over/read_over_view.dart b/lib/page/home_page/children/read_over/read_over_view.dart deleted file mode 100644 index 4d28cef..0000000 --- a/lib/page/home_page/children/read_over/read_over_view.dart +++ /dev/null @@ -1,533 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:flutter_easyrefresh/easy_refresh.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:functional_widget_annotation/functional_widget_annotation.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/work_student.dart'; -import 'package:school_asignment_app/common/utils/enum_untils.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -import 'package:school_asignment_app/page/home_page/children/read_over/widget/task_list_item.dart'; -import 'package:school_asignment_app/page/home_page/children/student_work_detail/widget/job_condition_filter.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; -import 'package:syncfusion_flutter_datepicker/datepicker.dart'; - -import 'read_over_logic.dart'; - -class ReadOverPage extends StatefulWidget { - const ReadOverPage({Key? key}) : super(key: key); - - @override - State createState() => _ReadOverPageState(); -} - -class _ReadOverPageState extends State { - final logic = Get.find(); - final state = Get.find().state; - - @override - Widget build(BuildContext context) { - return AnnotatedRegion( - value: const SystemUiOverlayStyle( - systemNavigationBarColor: Color(0xFF000000), - systemNavigationBarDividerColor: null, - statusBarColor: Colors.white, - systemNavigationBarIconBrightness: Brightness.light, - statusBarIconBrightness: Brightness.dark, - statusBarBrightness: Brightness.light, - ), - child: Scaffold( - backgroundColor: const Color.fromRGBO(244, 244, 244, 1), - body: OrientationBuilder( - builder: (BuildContext context, Orientation orientation) { - return Column( - children: [ - Container( - color: Colors.white, - margin: - EdgeInsets.only(top: MediaQuery.of(context).padding.top), - padding: EdgeInsets.only(bottom: 9.h, top: 4.h), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - flex: 1, - child: Container( - alignment: Alignment.centerLeft, - padding: EdgeInsets.only(left: 10.w), - child: InkWell( - onTap: () { - Get.back(); - }, - child: Icon( - Icons.arrow_back_ios_sharp, - size: 16.sp, - ), - ), - )), - Expanded( - flex: 4, - child: Container( - padding: EdgeInsets.symmetric(vertical: 2.h), - alignment: Alignment.center, - decoration: BoxDecoration( - color: const Color.fromRGBO(243, 243, 243, 1), - borderRadius: BorderRadius.circular(8.r), - ), - child: TabBar( - padding: EdgeInsets.zero, - indicatorPadding: EdgeInsets.zero, - indicatorWeight: 0, - labelPadding: EdgeInsets.symmetric(horizontal: 2.w), - controller: logic.tabController, - unselectedLabelStyle: TextStyle( - fontSize: 14.sp, - color: const Color.fromRGBO(69, 83, 100, 1), - ), - labelStyle: TextStyle( - fontSize: 14.sp, - color: const Color.fromRGBO(104, 136, 253, 1), - ), - // labelColor: const Color.fromRGBO(45, 56, 76, 1), - indicator: const BoxDecoration(), - onTap: (index) { - state.tabIndex.value = index; - if (index == 1 && state.completedToRefresh) { - // 已阅卷 - // _refreshController2.callRefresh(); - state.completedToRefresh = false; - } - logic.getList(); - }, - tabs: [ - Tab( - iconMargin: EdgeInsets.zero, - height: 34.h, - child: Obx(() { - return Container( - width: 140.w, - alignment: Alignment.center, - decoration: BoxDecoration( - color: state.tabIndex.value == 0 - ? const Color.fromRGBO( - 255, 255, 255, 1) - : null, - borderRadius: BorderRadius.all( - Radius.circular(8.r)), - ), - child: quickText( - '待批阅', - size: 14.sp, - color: state.tabIndex.value == 0 - ? Theme.of(context).primaryColor - : const Color.fromRGBO( - 80, 94, 110, 1), - fontWeight: state.tabIndex.value == 0 - ? FontWeight.bold - : null, - ), - ); - }), - ), - Tab( - iconMargin: EdgeInsets.zero, - height: 34.h, - child: Obx(() { - return Container( - width: 140.w, - alignment: Alignment.center, - decoration: BoxDecoration( - color: state.tabIndex.value == 1 - ? const Color.fromRGBO( - 255, 255, 255, 1) - : null, - borderRadius: BorderRadius.all( - Radius.circular(8.r)), - ), - child: quickText( - '已批阅', - size: 14.sp, - color: state.tabIndex.value == 1 - ? Theme.of(context).primaryColor - : const Color.fromRGBO( - 80, 94, 110, 1), - fontWeight: state.tabIndex.value == 1 - ? FontWeight.bold - : null, - ), - ); - }), - ), - ], - ), - ), - ), - Expanded( - flex: 1, - child: InkWell( - onTap: () { - Get.toNamed(Routes.studentHistoryWorkPage, - arguments: {'page': 'set'}); - }, - child: Icon( - const IconData(0xe63e, fontFamily: "AlibabaIcon"), - color: const Color.fromRGBO(44, 48, 63, 1), - size: 24.sp), - ), - ), - ], - ), - ), - Obx(() { - return state.tabIndex.value == 1 - ? JobConditionFilter( - customTimeStr: state.customTimeStr.value, - controller: logic.tabController2, - hasAll: true, - jobType: 1, - customTime: logic.tabController2.index != 3 || - (logic.params2.startDate == null && - logic.params2.endDate == null) - ? null - : PickerDateRange( - logic.params2.startDate == null - ? null - : DateTime.parse( - logic.params2.startDate!), - logic.params2.endDate == null - ? null - : DateTime.parse(logic.params2.endDate!), - ), - onTimeFilter: (String? startTime, String? endTime) { - if (startTime == null && - endTime == null && - logic.tabController2.index == 3) { - logic.tabController2.animateTo(0); - } - logic.params2.endDate = endTime; - logic.params2.startDate = startTime; - state.page = 1; - logic.getList(); - // logic.refreshController2.callRefresh(); - }, - refreshTime: (value) { - if (value != null && value.startDate != null) { - state.customTimeStr.value = value.startDate - ?.toString() - .substring(0, 10) ?? - ''; - - if (value.endDate != null) { - if (!Utils.isPad() && - value.startDate!.year == - value.endDate!.year) { - state.customTimeStr.value = - '${value.startDate.toString().substring(5, 10)}~${value.endDate.toString().substring(5, 10)}'; - } else { - state.customTimeStr.value = - '${state.customTimeStr.value}~${value.endDate?.toString().substring(0, 10)}'; - } - } - } - }) - : Container(); - }), - Expanded(child: Obx(() { - return IndexedStack( - index: state.tabIndex.value, - children: [ - $easyRefresh( - controller: logic.refreshController1, - tab: 1, - type: state.active, - data: state.workList, - onLoad: logic.onMyLoad, - onRefresh: logic.onMyRefresh, - logic: logic), - $easyRefresh( - controller: logic.refreshController2, - tab: 2, - type: state.active, - data: state.workList, - onLoad: logic.onMyLoad, - onRefresh: logic.onMyRefresh, - logic: logic), - ], - ); - })), - ], - ); - }, - ), - ), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} - -/// 已阅卷 -/// OnRefreshCallback? onRefresh -/// -@swidget -Widget $easyRefresh({ - required EasyRefreshController controller, - required Future Function(EasyRefreshController controller, int tab) - onRefresh, - required Future Function(EasyRefreshController controller, int tab) - onLoad, - required List data, - required int tab, - required int type, - required ReadOverLogic logic, -}) { - bool completed = tab == 2; // 是否是待批阅 - bool isPadFlag = Utils.isPad(); - return Obx(() { - return EasyRefresh( - firstRefresh: false, - taskIndependence: true, - /*enableControlFinishLoad: true, - enableControlFinishRefresh: true,*/ - emptyWidget: data.isEmpty ? const MyEmptyWidget() : null, - controller: controller, - header: MaterialHeader(), - footer: TaurusFooter(), - child: completed && isPadFlag - ? GridView( - padding: EdgeInsets.only( - top: 11.h, bottom: 10.h, left: 12.w, right: 12.w), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, //横轴三个子widget - mainAxisSpacing: 10.h, - crossAxisSpacing: 6.w, - childAspectRatio: 1.81 //宽高比为1时,子widget - ), - children: List.generate(data.length, (index) { - Items item = data[index]; - String subjectName = EnumUtils.formatSubject(item.subject); - return $reviewedItem( - jobTaskItem: item, type: type, subjectName: subjectName,logic: logic); - }), - ) - : ListView.builder( - padding: EdgeInsets.only( - top: 11.h, bottom: 10.h, left: 12.w, right: 12.w), - itemBuilder: (context, index) { - Items item = data[index]; - return TaskListItem( - completed: completed, - jobTaskItem: item, - type: type, - logic: logic, - ); - }, - itemCount: data.length, - ), - onRefresh: () => onRefresh(controller, tab), - onLoad: () => onLoad(controller, tab), - ); - }); -} - -@swidget -Widget $reviewedItem( - {required Items jobTaskItem, - required int type, - required String subjectName, - required ReadOverLogic logic,}) { - EdgeInsets padEdg = EdgeInsets.symmetric(horizontal: 10.w); - - return InkWell( - onTap: () { - Get.toNamed(Routes.annotateClassPage, arguments: { - 'id': jobTaskItem.id, - 'name': jobTaskItem.name, - 'grade': jobTaskItem.grade, - 'completed': true - }); - }, - child: Container( - padding: EdgeInsets.only(top: 10.h), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.r), - color: Colors.white, - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(210, 216, 241, 1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 5.8, //阴影模糊程度 - spreadRadius: 0, //阴影扩散程度 - ) - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - // 顶部任务名称 - Padding( - padding: padEdg, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 32.w, - height: 18.h, - alignment: Alignment.center, - padding: EdgeInsets.only(left: 2.w), - decoration: BoxDecoration( - color: type == 1 - ? const Color.fromRGBO(104, 136, 253, 1) - : const Color.fromRGBO(255, 175, 56, 1), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(14.r), - topRight: Radius.circular(3.r), - bottomLeft: Radius.circular(4.r), - bottomRight: Radius.circular(4.r), - ), - ), - margin: EdgeInsets.only(right: 4.w), - child: quickText(type == 1 ? '作业' : '考试', - color: Colors.white, size: 10.sp), - ), - Expanded( - child: quickText(jobTaskItem.name, - size: 14.sp, - color: const Color.fromRGBO(70, 70, 70, 1), - maxLines: 2), - ) - ], - ), - ), - if(jobTaskItem.isFixed!) - Padding( - padding: padEdg, - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - '已订正', - style: TextStyle( - fontSize: 10.sp, color: const Color(0xFFF16262)), - ), - ], - ), - ), - Padding( - padding: padEdg, - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - quickText( - DateTime.parse(jobTaskItem.publishTime) - .toString() - .substring(0, 10), - color: const Color.fromRGBO(97, 97, 97, 1), - size: 10.sp, - fontWeight: FontWeight.w500, - ), - quickText(' / ', - color: const Color.fromRGBO(76, 199, 147, 1), - size: 10.sp, - fontWeight: FontWeight.w500), - quickText( - '参与班级:', - color: const Color.fromRGBO(76, 199, 147, 1), - size: 9.sp, - ), - quickText( - '${jobTaskItem.classCount}', - color: const Color.fromRGBO(76, 199, 147, 1), - size: 10.sp, - ), - quickText(' / ', - color: const Color.fromRGBO(116, 145, 253, 1), - size: 10.sp, - fontWeight: FontWeight.w500), - quickText( - '科目:$subjectName', - color: const Color.fromRGBO(116, 145, 253, 1), - size: 9.sp, - ), - ], - ), - ), - /*Padding( - padding: EdgeInsets.symmetric(horizontal: 10.w), - child: FavoriteButton( - jobTaskItem.id, - jobTaskItem.title, - margin: EdgeInsets.only(top: 4.h, bottom: 6.h), - ), - ),*/ - Container( - padding: EdgeInsets.symmetric(vertical: 6.h), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(6.r), - bottomRight: Radius.circular(6.r)), - color: Colors.white, - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(0, 0, 0, 0.15), - offset: Offset(0, -0.0001), //阴影y轴偏移量 - blurRadius: 4, //阴影模糊程度 - spreadRadius: 0, //阴影扩散程度 - ) - ], - ), - child: Row(children: [ - if (!jobTaskItem.isFixed!) - Expanded( - flex: 1, - child: InkWell( - onTap: (){ - if(!jobTaskItem.isFixed!){ - EasyLoading.show(status:'loading...'); - logic.getCollect(jobTaskItem); - } - }, - child: Container( - alignment: Alignment.center, - decoration: BoxDecoration( - border: Border( - right: BorderSide( - width: 1.r, color: const Color(0xFFDCDCDC))), - ), - child: quickText('收集订正', - color: const Color(0xFF4CC793), size: 11.sp), - ), - ), - ), - Expanded( - flex: 1, - child: InkWell( - onTap: () { - Get.toNamed(Routes.jobReportPage, arguments: { - 'title': jobTaskItem.name, - 'homeworkId': jobTaskItem.id, - 'grade': jobTaskItem.grade - }); - }, - child: Container( - alignment: Alignment.center, - child: quickText('查看报告', - color: const Color.fromRGBO(118, 118, 118, 1), - size: 11.sp), - ), - ), - ), - ]), - ), - ], - ), - ), - ); -} diff --git a/lib/page/home_page/children/read_over/widget/task_list_item.dart b/lib/page/home_page/children/read_over/widget/task_list_item.dart deleted file mode 100644 index d463bd9..0000000 --- a/lib/page/home_page/children/read_over/widget/task_list_item.dart +++ /dev/null @@ -1,311 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:percent_indicator/percent_indicator.dart'; -import 'package:school_asignment_app/common/job/work_student.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:school_asignment_app/common/utils/enum_untils.dart'; -import 'package:school_asignment_app/common/utils/toast_utils.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/home_page/children/read_over/read_over_logic.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; - -class TaskListItem extends StatefulWidget { - final bool completed; - final Items jobTaskItem; - final int type; - final ReadOverLogic logic; - - const TaskListItem({Key? key,required this.completed,required this.jobTaskItem,required this.type,required this.logic}) : super(key: key); - - @override - State createState() => _TaskListItemState(); -} - -class _TaskListItemState extends State{ - - @override - Widget build(BuildContext context) { - return widget.completed - ? InkWell( - onTap: () { - Get.toNamed(Routes.annotateClassPage,arguments: {'id': widget.jobTaskItem.id,'name': widget.jobTaskItem.name,'grade': widget.jobTaskItem.grade,'completed':true}); - }, - child: Container( - width: double.infinity, - padding: EdgeInsets.only(top: 20.h), - margin: EdgeInsets.only(bottom: 12.h), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.r), - color: const Color.fromRGBO(255, 255, 255, 1), - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(210, 216, 241, 1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 5.8, //阴影模糊程度 - spreadRadius: 0, //阴影扩散程度 - ) - ], - ), - child: Column( - children: [ - // 顶部任务名称 - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.w), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: Utils.isPad() ? 32.w : 36.w, - height: 18.h, - alignment: Alignment.center, - padding: EdgeInsets.only(left: Utils.isPad() ? 2.w : 3.w), - decoration: BoxDecoration( - color: const Color.fromRGBO(104, 136, 253, 1), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(14.r), - topRight: Radius.circular(3.r), - bottomLeft: Radius.circular(4.r), - bottomRight: Radius.circular(4.r), - ), - ), - margin: EdgeInsets.only(right: 4.w), - child: quickText('作业', color: Colors.white, size: 10.sp), - ), - Expanded( - child: quickText( - widget.jobTaskItem.name, - maxLines: 2, - size: 16.sp, - color: const Color.fromRGBO(70, 70, 70, 1), - fontWeight: FontWeight.bold, - ), - ) - ], - ), - ), - - SizedBox(height: 12.h), - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.w), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - quickText(DateTime.parse(widget.jobTaskItem.publishTime).toString().substring(0,10), - color: const Color.fromRGBO(97, 97, 97, 1), - size: 12.sp, - fontWeight: FontWeight.w500, - ), - quickText(' / ', color: const Color.fromRGBO(76, 199, 147, 1), size: 12.sp, fontWeight: FontWeight.w500), - quickText( - '参与班级:${widget.jobTaskItem.classCount}', - color: const Color.fromRGBO(76, 199, 147, 1), - size: 12.sp, - fontWeight: FontWeight.w600, - ), - quickText(' / ', color: const Color.fromRGBO(116, 145, 253, 1), size: 12.sp, fontWeight: FontWeight.w500), - quickText( - '科目:${EnumUtils.formatSubject(widget.jobTaskItem.subject)}' , - color: const Color.fromRGBO(116, 145, 253, 1), - size: 12.sp, - fontWeight: FontWeight.w600, - ), - const Expanded(child: SizedBox()), - /* FavoriteButton( - jobTaskItem.id, - jobTaskItem.title, - margin: EdgeInsets.zero, - isRow: false, - ),*/ - ], - ), - ), - - SizedBox(height: 20.h), - Container( - padding: EdgeInsets.symmetric(vertical: 10.h), - decoration: BoxDecoration( - borderRadius: BorderRadius.only(bottomLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)), - color: Colors.white, - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(0, 0, 0, 0.15), - offset: Offset(0, -0.0001), //阴影y轴偏移量 - blurRadius: 4, //阴影模糊程度 - spreadRadius: 0, //阴影扩散程度 - ) - ], - ), - child: Row(children: [ - Expanded( - child: InkWell( - onTap: (){}, - child: Container( - alignment: Alignment.center, - child: quickText('查看报告', color: const Color.fromRGBO(118, 118, 118, 1), size: 13.sp), - ), - )), - ]), - ), - ], - ), - ), - ) - : - InkWell( - onTap: () { - Get.toNamed(Routes.annotateClassPage,arguments: {'id':widget.jobTaskItem.id,'name':widget.jobTaskItem.name,'grade':widget.jobTaskItem.grade}); - }, - child: Stack( - alignment: const FractionalOffset(0.95, 0), - children: [ - Container( - margin: EdgeInsets.only(bottom: 16.h), - padding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 10.w), - width: double.infinity, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.r), - color: const Color.fromRGBO(255, 255, 255, 1), - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(210, 216, 241, 1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 5.8, //阴影模糊程度 - spreadRadius: 0, //阴影扩散程度 - ) - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox(height: 30.h), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: Utils.isPad() ? 32.w : 38.w, - height: 18.h, - alignment: Alignment.center, - padding: EdgeInsets.only(left: Utils.isPad() ? 2.w : 3.w), - decoration: BoxDecoration( - color: widget.type == 1 - ? const Color.fromRGBO(104, 136, 253, 1) - : const Color.fromRGBO(255, 175, 56, 1), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(14.r), - topRight: Radius.circular(3.r), - bottomLeft: Radius.circular(4.r), - bottomRight: Radius.circular(4.r), - ), - ), - margin: EdgeInsets.only(right: 4.w), - child: quickText(widget.type == 1?'作业':'考试', color: Colors.white, size: 10.sp), - ), - Expanded( - child: quickText( - widget.jobTaskItem.name, - maxLines: 2, - size: Utils.isPad() ? 14.sp : 16.sp, - color: const Color.fromRGBO(70, 70, 70, 1), - fontWeight: FontWeight.bold, - ), - ) - ], - ), - SizedBox(height: 10.h), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - quickText( - EnumUtils.formatSubject(widget.jobTaskItem.subject), - color: const Color.fromRGBO(97, 97, 97, 1), - size: 12.sp, - ), - quickText(' / ', - color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp, fontWeight: FontWeight.w500), - Container( - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - quickText('题量:', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp), - quickText( - '10', - color: const Color.fromRGBO(97, 97, 97, 1), - size: 13.sp, - ), - ], - ), - ), - quickText(' / ', - color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp, fontWeight: FontWeight.w500), - quickText(DateTime.parse(widget.jobTaskItem.publishTime).toString().substring(0,10), - color: const Color.fromRGBO(97, 97, 97, 1), size: 12.sp), - ], - ), - SizedBox(height: 10.h), - InkWell( - onTap: (){ - if(!widget.jobTaskItem.isFixed!){ - EasyLoading.show(status:'loading...'); - widget.logic.getCollect(widget.jobTaskItem); - } - }, - child: Container( - padding: EdgeInsets.symmetric(vertical: 4.r,horizontal: 20.r), - decoration: BoxDecoration( - color: widget.jobTaskItem.isFixed!?Color(0xFFF4F4F4):Color(0xFFF2FFFA), - border: Border.all(width: 1.r,color:widget.jobTaskItem.isFixed!?Colors.transparent:Color(0xFF4CC793)), - borderRadius: BorderRadius.all(Radius.circular(20.r)), - ), - child: Text(widget.jobTaskItem.isFixed!?'已订正':'收集订正',style: TextStyle(fontSize: 10.sp,color: const Color(0xFF4CC793)),), - ), - ), - // FavoriteButton(jobTaskItem.id, jobTaskItem.title), - ], - ), - ), - Container( - padding: EdgeInsets.all(9.r), - decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.white), - child: CircularPercentIndicator( - radius: 40.r, - lineWidth: 10.r, - animation: true, - percent: widget.jobTaskItem.annotateRate==null?0:widget.jobTaskItem.annotateRate! / 100, - center: Text.rich(TextSpan(children: [ - TextSpan( - text: Utils.getDoubleRemoveZero(widget.jobTaskItem.annotateRate, '0'), - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16.sp, - color: Theme.of(context).primaryColor, - ), - ), - TextSpan( - text: "%", - style: TextStyle(color: const Color.fromRGBO(70, 70, 70, 1), fontSize: 12.sp, fontWeight: FontWeight.bold), - ), - ])), - circularStrokeCap: CircularStrokeCap.round, - // progressColor: Theme.of(context).primaryColor, - linearGradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - tileMode: TileMode.clamp, - stops: const [0.0, 1.0], - colors: [ - Theme.of(context).primaryColor.withOpacity(0.1), - Theme.of(context).primaryColor, - ], - ), - backgroundColor: const Color.fromRGBO(244, 244, 244, 1), - ), - ), - ], - ), - ); - } -} diff --git a/lib/page/home_page/children/student_history_work/student_history_work_view.dart b/lib/page/home_page/children/student_history_work/student_history_work_view.dart deleted file mode 100644 index 0e8b497..0000000 --- a/lib/page/home_page/children/student_history_work/student_history_work_view.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_easyrefresh/easy_refresh.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/page/global_widget/ReturnToHomepage.dart'; -import 'package:school_asignment_app/page/home_page/widget/student_group_list.dart'; - -import 'student_history_work_logic.dart'; - -class StudentHistoryWorkPage extends StatefulWidget { - const StudentHistoryWorkPage({Key? key}) : super(key: key); - - @override - State createState() => _StudentHistoryWorkPageState(); -} - -class _StudentHistoryWorkPageState extends State { - final logic = Get.find(); - final state = Get.find().state; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color.fromRGBO(245, 245, 245, 1), - appBar: AppBar( - backgroundColor: Colors.white, - title: Text( - '我的班级 ', - style: TextStyle(fontSize: 14.sp, color: const Color(0xFF333333)), - ), - centerTitle: true, - leading: IconButton( - icon: const Icon(Icons.arrow_back_ios, color: Colors.black), - onPressed: () => Navigator.of(context).pop(), - ), - actions: const [ - ReturnToHomepage(), - ], - ), - body: Padding( - padding: EdgeInsets.only(top: 15.r, left: 14.r, right: 14.r), - child: EasyRefresh( - firstRefresh: false, - taskIndependence: true, - controller: logic.refreshController, - header: MaterialHeader(), - footer: TaurusFooter(), - onRefresh: () async{ - logic.getList(); - }, - child: StudentGroupList(state.clssList,logic.goNextPage), - ), - ), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} \ No newline at end of file diff --git a/lib/page/home_page/children/student_personal/student_personal_logic.dart b/lib/page/home_page/children/student_personal/student_personal_logic.dart deleted file mode 100644 index ad5d317..0000000 --- a/lib/page/home_page/children/student_personal/student_personal_logic.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/student_personal_info.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; - -import 'student_personal_state.dart'; - -class StudentPersonalLogic extends GetxController with RequestToolMixin{ - final StudentPersonalState state = StudentPersonalState(); - - @override - void onInit(){ - super.onInit(); - state.studentId = Get.arguments['studentId']; - state.homeworkId = Get.arguments['homeworkId']; - getInfo(); - } - - void getInfo() async{ - StudentPersonalInfo data = await getClient().getStudentHomework(state.homeworkId,state.studentId); - state.studentInfo.value = data; - - } -} diff --git a/lib/page/home_page/children/student_personal/student_personal_view.dart b/lib/page/home_page/children/student_personal/student_personal_view.dart deleted file mode 100644 index 19b4ae9..0000000 --- a/lib/page/home_page/children/student_personal/student_personal_view.dart +++ /dev/null @@ -1,232 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/ReturnToHomepage.dart'; -import 'package:school_asignment_app/page/home_page/children/student_personal/widget/student_kg_table.dart'; -import 'package:school_asignment_app/page/home_page/children/student_personal/widget/student_zg_table.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; - -import 'student_personal_logic.dart'; - -class StudentPersonalPage extends StatefulWidget { - const StudentPersonalPage({Key? key}) : super(key: key); - - @override - State createState() => _StudentPersonalPageState(); -} - -class _StudentPersonalPageState extends State { - final logic = Get.find(); - final state = Get - .find() - .state; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color.fromRGBO(245, 245, 245, 1), - appBar: AppBar( - backgroundColor: Colors.white, - title: Obx(() { - return Text( - state.studentInfo.value.studentName, - style: TextStyle(fontSize: 14.sp, color: Color(0xFF000000)), - ); - }), - centerTitle: true, - leading: IconButton( - icon: Icon(Icons.arrow_back_ios, color: Colors.black), - onPressed: () => Navigator.of(context).pop(), - ), - actions: const [ - ReturnToHomepage(), - ], - ), - body: SingleChildScrollView( - child: Column( - children: [ - Padding( - padding: EdgeInsets.only(top: 14.r, left: 14.r), - child: Row( - children: [ - InkWell( - onTap: () { - // RouterManager.router.navigateTo(context, - // '${RouterManager.jobPersonalDetailPath}?studentId=${widget.studentId}&studentName=${Uri.encodeComponent(state.studentInfo.studentName!)}'); - Get.toNamed(Routes.studentWorkDetailPage, arguments: { - 'studentId': state.studentInfo.value.studentId, - 'studentName': state.studentInfo.value.studentName - }); - }, - child: Container( - width: 93.r, - height: 28.r, - decoration: BoxDecoration( - color: Color(0xFFEAF3FF), - borderRadius: BorderRadius.circular(4.r), - ), - child: Center( - child: Text( - '历史作业', - style: TextStyle(fontSize: 10.r, - color: Color(0xFF2080F7)), - ), - ), - ), - ), - SizedBox( - width: 10.r, - ), - InkWell( - onTap: () { - /* showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId).then((value) { - ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); - });*/ - }, - child: Container( - width: 93.r, - height: 28.r, - decoration: BoxDecoration( - color: Color(0xFFEDFFF7), - borderRadius: BorderRadius.circular(4.r), - ), - child: Center( - child: Text( - '原稿笔迹', - style: TextStyle(fontSize: 10.r, - color: Color(0xFF4CC793)), - ), - ), - ), - ), - ], - ), - ), - //客观题 - Container( - padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 10.r), - margin: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(6.r)), - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - '客观题', - style: TextStyle(fontSize: 14.sp, - color: Color(0xFF5C5C5C), - fontWeight: FontWeight.w600), - ), - SizedBox( - width: 10.r, - ), - Obx(() { - return Text( - '${state.studentInfo.value.kgtCorrectRate}%', - style: TextStyle(fontSize: 14.sp, - color: Color(0xFF6888FD), - fontWeight: FontWeight.w600), - ); - }), - ], - ), - SizedBox( - height: 10.r, - ), - Obx(() { - return SizedBox( - height: state.studentInfo.value.kgtList.length > 8 - ? 300.r - : state - .studentInfo.value.kgtList.length * 40.r + 40.r, - child: StudentKgTable( - headList: ['题号', '学生答案', '标准答案'], - bodyList: state.studentInfo.value.kgtList, - questionNumCall: (no) { - // showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId, questionNo: int.parse(no)).then((value) { - // ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); - // }); - }, - ), - ); - }) - ], - ), - ), - SizedBox( - height: 15.r, - ), - //主观题 - Container( - padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 10.r), - margin: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(6.r)), - ), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - '主观题', - style: TextStyle(fontSize: 14.sp, - color: Color(0xFF5C5C5C), - fontWeight: FontWeight.w600), - ), - SizedBox( - width: 10.r, - ), - Obx(() { - return Text( - '${state.studentInfo.value.zgtCorrectRate}%', - style: TextStyle(fontSize: 14.sp, - color: Color(0xFF6888FD), - fontWeight: FontWeight.w600), - ); - }), - ], - ), - SizedBox( - height: 10.r, - ), - Obx(() { - return SizedBox( - height: state.studentInfo.value.zgtList.length > 8 - ? 300.r - : state - .studentInfo.value.zgtList.length * 40.r + 40.r, - child: StudentZgTable( - headList: ['题号', '用时', '批注结果', '答案'], - bodyList: state.studentInfo.value.zgtList, - questionNumCall: (no) { - /* showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId, questionNo: int.parse(no)).then((value) { - ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); - });*/ - }, - ), - ); - }) - ], - ), - ), - ], - ), - ), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} \ No newline at end of file diff --git a/lib/page/home_page/children/student_work_detail/student_work_detail_logic.dart b/lib/page/home_page/children/student_work_detail/student_work_detail_logic.dart deleted file mode 100644 index 74db89f..0000000 --- a/lib/page/home_page/children/student_work_detail/student_work_detail_logic.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:flutter_easyrefresh/easy_refresh.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/student_history.dart'; -import 'package:school_asignment_app/common/job/student_history_params.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; - -import 'student_work_detail_state.dart'; - -class StudentWorkDetailLogic extends GetxController with RequestToolMixin, GetSingleTickerProviderStateMixin{ - final StudentWorkDetailState state = StudentWorkDetailState(); - late TabController tabController; - late final EasyRefreshController refreshController; - - @override - void onInit() { - super.onInit(); - state.studentName.value = Get.arguments['studentName'] ?? ''; - state.studentId = Get.arguments['studentId'] ?? -1; - tabController = TabController(length: 3, vsync: this); - refreshController = EasyRefreshController(); - EasyLoading.show(status: 'loading...'); - getList(); - } - - void getList() async { - StudentHistoryParams params = StudentHistoryParams( - assessType: state.isJob.value?0:1, - studentId: state.studentId, - dateStart: state.dateStart, - dateEnd: state.dateEnd, - pageNumber: state.page, - pageSize: 10, - ); - StudentHistory data = await getClient().getStudentHistory(params); - state.studentData.value = data; - for(var element in state.studentData.value.items.items){ - int num = 0; - for (var item in element.kgtList) { - if (item.state == 0) { - num = num + 1; - } - } - for (var subject in element.zgtList) { - if (subject.state == 0) { - num = num + 1; - } - } - if (num == (element.kgtList.length + element.zgtList.length)) { - element.allNotDone = true; - } - - } - EasyLoading.dismiss(); - } - - @override - void dispose() { - super.dispose(); - tabController.dispose(); - refreshController.dispose(); - } -} diff --git a/lib/page/home_page/children/student_work_detail/student_work_detail_state.dart b/lib/page/home_page/children/student_work_detail/student_work_detail_state.dart deleted file mode 100644 index 09ca2f5..0000000 --- a/lib/page/home_page/children/student_work_detail/student_work_detail_state.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/student_history.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; - -class StudentWorkDetailState { - StudentWorkDetailState() { - ///Initialize variables - } - - late RxString studentName = ''.obs; - late int studentId = -1; - late RxBool isJob = true.obs; - late int page = 1; - late int totalPages = 0; - late String dateStart = Utils.getWeekStartDate().toString().substring(0, 10); - late String dateEnd = Utils.getWeekEndDate().toString().substring(0, 10); - late RxString customTimeStr = '自定义'.obs; - late Rx studentData = Rx(StudentHistory(0,0,Items([],0),0)); -} diff --git a/lib/page/home_page/children/student_work_detail/student_work_detail_view.dart b/lib/page/home_page/children/student_work_detail/student_work_detail_view.dart deleted file mode 100644 index acd3ea5..0000000 --- a/lib/page/home_page/children/student_work_detail/student_work_detail_view.dart +++ /dev/null @@ -1,598 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:flutter_easyrefresh/easy_refresh.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/student_history.dart'; -import 'package:school_asignment_app/common/utils/enum_untils.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; -import 'package:school_asignment_app/page/global_widget/ReturnToHomepage.dart'; -import 'package:school_asignment_app/page/home_page/children/student_work_detail/widget/job_condition_filter.dart'; -import 'package:school_asignment_app/page/home_page/widget/progress_bar.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; -import 'package:syncfusion_flutter_datepicker/datepicker.dart'; - -import 'student_work_detail_logic.dart'; - -class StudentWorkDetailPage extends StatefulWidget { - const StudentWorkDetailPage({Key? key}) : super(key: key); - - @override - State createState() => _StudentWorkDetailPageState(); -} - -class _StudentWorkDetailPageState extends State { - final logic = Get.find(); - final state = Get - .find() - .state; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color.fromRGBO(245, 245, 245, 1), - appBar: AppBar( - backgroundColor: Colors.white, - title: Text('${state.studentName}作业详情', - style: TextStyle(fontSize: 14.sp, color: Color(0xFF333333))), - centerTitle: true, - leading: IconButton( - icon: Icon(Icons.arrow_back_ios, color: Colors.black), - onPressed: () => Navigator.of(context).pop(), - ), - actions: const [ - ReturnToHomepage(), - ], - elevation: 0, - ), - body: Column( - children: [ - Container( - height: 1.r, - width: MediaQuery - .of(context) - .size - .width, - color: Color.fromRGBO(179, 179, 179, 0.3), - ), - Container( - color: Colors.white, - padding: EdgeInsets.symmetric(vertical: 2.r), - child: Row( - children: [ - InkWell( - onTap: () { - EasyLoading.show(status: 'loading...'); - state.page = 1; - state.totalPages = 0; - state.isJob.value = true; - logic.getList(); - }, - child: SizedBox( - width: (MediaQuery - .of(context) - .size - .width - 1.r) / 2, - height: 40.r, - child: Obx(() { - return Center( - child: Text( - '作业', - style: TextStyle(fontSize: 14.sp, - color: state.isJob.value - ? Color(0xFF7491FD) - : Color(0xFF505E6E)), - )); - }), - ), - ), - Container( - height: 40.r, - width: 1.r, - color: Color.fromRGBO(179, 179, 179, 0.3), - ), - InkWell( - onTap: () { - EasyLoading.show(status: 'loading...'); - state.isJob.value = false; - state.page = 1; - state.totalPages = 0; - logic.getList(); - }, - child: SizedBox( - width: (MediaQuery - .of(context) - .size - .width - 1.r) / 2, - height: 40.r, - child: Center( - child: Obx(() { - return Text( - '考试', - style: TextStyle( - fontSize: 14.sp, color: !state.isJob.value - ? Color(0xFF7491FD) - : Color(0xFF505E6E)), - ); - })), - ), - ), - ], - ), - ), - Obx(() { - return Container( - margin: EdgeInsets.symmetric(vertical: 10.r, horizontal: 14.r), - padding: EdgeInsets.only( - top: 10.r, left: 10.r, right: 10.r, bottom: 10.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(10.r)), - color: Colors.white), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '总览:', - style: TextStyle(fontSize: 12.sp, - color: Color(0xFF7491FD), - fontWeight: FontWeight.w600), - ), - ProgressBar( - title: '客观题正确率:', - color: Color(0xFFB8C7FF), - percent: state.studentData.value.kgtCorrectRate / 100, - padingEdg: EdgeInsets.zero, - marginEdg: EdgeInsets.only(top: 8.h)), - ProgressBar( - title: '主观题正确率:', - color: Color(0xFFB8C7FF), - percent: state.studentData.value.zgtCorrectRate / 100, - padingEdg: EdgeInsets.zero, - marginEdg: EdgeInsets.only(top: 8.h)), - ProgressBar( - title: '总正确率:', - color: Color(0xFFB8C7FF), - percent: state.studentData.value.correctRate / 100, - padingEdg: EdgeInsets.zero, - marginEdg: EdgeInsets.only(top: 8.h)), - ], - ), - ); - }), - - - Obx(() { - return JobConditionFilter( - controller: logic.tabController, - jobType: state.isJob.value ? 1 : 2, - customTimeStr: state.customTimeStr.value, - customTime: logic.tabController.index != 2 || - ((state.dateEnd == null || state.dateEnd == '') && - (state.dateStart == null || state.dateStart == '')) - ? null - : PickerDateRange( - state.dateStart == null || state.dateStart == '' - ? null - : DateTime - .parse(state.dateStart!), - state.dateEnd == null || state.dateEnd == '' ? null : DateTime - .parse(state.dateEnd!), - ), - onTimeFilter: (String? startTime, String? endTime) { - EasyLoading.show(status: 'loading...'); - if (startTime == null && endTime == null) { - if (logic.tabController.index == 2) { - logic.tabController.animateTo(0); - } - state.dateStart = - Utils.getWeekStartDate().toString().substring(0, 10); - state.dateEnd = - Utils.getWeekEndDate().toString().substring(0, 10); - state.customTimeStr.value = '自定义'; - } else { - state.dateStart = startTime ?? ''; - state.dateEnd = endTime ?? ''; - } - state.page = 1; - logic.getList(); - }, - refreshTime: (value) { - if (value != null && value.startDate != null) { - state.customTimeStr.value = - value.startDate?.toString().substring(0, 10) ?? ''; - - if (value.endDate != null) { - if (!Utils.isPad() && - value.startDate!.year == value.endDate!.year) { - state.customTimeStr.value = - '${value.startDate.toString().substring(5, 10)}~${value - .endDate.toString().substring(5, 10)}'; - } else { - state.customTimeStr.value = - '${state.customTimeStr.value}~${value.endDate - ?.toString() - .substring( - 0, 10)}'; - } - } - } - }); - }), - Padding( - padding: EdgeInsets.only(top: 14.r, right: 14.r), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - '注:', - style: TextStyle(fontSize: 8.sp, color: Color(0xFF8B8B8B)), - ), - Container( - width: 10.r, - height: 10.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(5.r)), - // color: Color(0xFF4CC793), - border: Border.all(width: 1.r, color: Color(0xFF4CC793)), - ), - ), - SizedBox( - width: 2.r, - ), - Text( - '正确', - style: TextStyle(fontSize: 8.sp, color: Color(0xFF8B8B8B)), - ), - SizedBox( - width: 15.r, - ), - Container( - width: 10.r, - height: 10.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(5.r)), - // color: Color(0xFFFF7474), - border: Border.all(width: 1.r, color: Color(0xFFFF7474)), - ), - ), - SizedBox( - width: 2.r, - ), - Text( - '错误', - style: TextStyle(fontSize: 8.sp, color: Color(0xFF8B8B8B)), - ), - SizedBox( - width: 15.r, - ), - Container( - width: 10.r, - height: 10.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(5.r)), - // color: Color(0xFF666666), - border: Border.all(width: 1.r, color: Color(0xFF666666)), - // border: Border.all(width: 1.r,color: Colors.grey), - /* boxShadow: [ - BoxShadow( - color: Colors.grey, - offset: Offset(1.w, 1.h), //阴影y轴偏移量 - blurRadius: 4, //阴影模糊程度 - spreadRadius: 0.1, //阴影扩散程度 - ) - ],*/ - ), - ), - SizedBox( - width: 2.r, - ), - Text( - '已作答未批阅', - style: TextStyle(fontSize: 8.sp, color: Color(0xFF8B8B8B)), - ), - SizedBox( - width: 15.r, - ), - Container( - width: 10.r, - height: 10.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(5.r)), - border: Border.all(width: 1.r, color: Color(0xFFDDDDDD)), - // color: Color(0xFFDDDDDD), - ), - ), - SizedBox( - width: 2.r, - ), - Text( - '未做', - style: TextStyle(fontSize: 8.sp, color: Color(0xFF8B8B8B)), - ), - ], - ), - ), - Expanded( - child: Padding( - padding: EdgeInsets.symmetric(vertical: 10.r), - child: Obx(() { - return EasyRefresh( - firstRefresh: false, - taskIndependence: true, - controller: logic.refreshController, - header: MaterialHeader(), - footer: TaurusFooter(), - onRefresh: () async { - state.page = 1; - logic.getList(); - }, - onLoad: () async { - if (state.page < state.totalPages) { - state.page += 1; - logic.getList(); - } - }, - child: state.studentData.value.items.items.isNotEmpty - ? ListView.builder( - itemCount: state.studentData.value.items.items.length, - itemBuilder: (context, index) { - StudentItems item = state.studentData.value.items - .items[index]; - return InkWell( - onTap: () { - Get.toNamed(Routes.studentPersonalPage, arguments: { - 'homeworkId': item.id, - 'studentId': state.studentId - }); - }, - child: Container( - margin: EdgeInsets.symmetric(vertical: 5.r, - horizontal: 14.r), - padding: EdgeInsets.symmetric(vertical: 14.r, - horizontal: 10.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(10.r)), - color: item.allNotDone - ? const Color(0xFFFFEDD3) - : Colors.white), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Container( - width: 32.w, - height: 18.h, - alignment: Alignment.center, - padding: EdgeInsets.only(left: 2.w), - decoration: BoxDecoration( - color: state.isJob.value ? const Color - .fromRGBO( - 104, 136, 253, 1) : const Color( - 0xFFFFA116), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(14.r), - topRight: Radius.circular(3.r), - bottomLeft: Radius.circular(4.r), - bottomRight: Radius.circular(4.r), - ), - ), - margin: EdgeInsets.only(right: 4.w), - child: Text( - state.isJob.value ? '作业' : '考试', - style: TextStyle( - fontSize: 10.sp, - color: Colors.white), - ), - ), - Expanded( - child: Text( - item.name, - style: TextStyle(fontSize: 12.sp, - color: Color(0xFF464646)), - )), - // SizedBox(width: 5.r,), - // Text('2024.1',style: TextStyle(fontSize: 12.sp,color: Color(0xFF5B5B5B)),), - - Container( - width: 40.r, - height: 20.r, - decoration: BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(4.r)), - border: Border.all( - width: 1.r, - color: Color(0xFF4CC793)), - ), - child: Center( - child: Text( - EnumUtils.formatSubject( - item.subject), - style: TextStyle(fontSize: 10.sp, - color: Color(0xFF4CC793)), - )), - ), - ], - ), - SizedBox( - height: 10.r, - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '客:', - style: TextStyle(fontSize: 12.sp, - color: Color(0xFF5B5B5B)), - ), - SizedBox( - width: 5.r, - ), - item.kgtList.isNotEmpty - ? Expanded( - child: Wrap( - direction: Axis.horizontal, - alignment: WrapAlignment.start, - spacing: 8, - runSpacing: 5, - children: List.generate( - item.kgtList.length, (i) { - KgtList subjective = item - .kgtList[i]; - return Container( - width: 20.r, - height: 20.r, - decoration: BoxDecoration( - color: Colors.transparent, - border: Border.all( - width: 1.r, - color: subjective.state == 0 - ? Color(0xFFDDDDDD) - : subjective.state == 3 - ? Color(0xFF4CC793) - : subjective.state == 2 - ? Color(0xFFFF7474) - : Color(0xFF666666)), - borderRadius: BorderRadius.all( - Radius.circular(10.r))), - child: Center( - child: Text( - subjective.questionNo - .toString(), - style: TextStyle( - fontSize: 10.r, - color: subjective.state == - 0 - ? Color(0xFFDDDDDD) - : subjective.state == - 3 - ? Color(0xFF4CC793) - : subjective.state == - 2 - ? Color(0xFFFF7474) - : Color(0xFF666666)), - )), - ); - }), - ), - ) - : Text( - '无', - style: TextStyle(fontSize: 12.sp, - color: Color(0xFF5B5B5B)), - ), - ], - ), - SizedBox( - height: 10.r, - ), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '主:', - style: TextStyle(fontSize: 12.sp, - color: Color(0xFF5B5B5B)), - ), - SizedBox( - width: 5.r, - ), - item.zgtList.isNotEmpty - ? Expanded( - child: Wrap( - direction: Axis.horizontal, - alignment: WrapAlignment.start, - spacing: 8, - runSpacing: 5, - children: List.generate( - item.zgtList.length, (i) { - ZgtList subjective = item - .zgtList[i]; - return Container( - width: 20.r, - height: 20.r, - decoration: BoxDecoration( - color: Colors.transparent, - border: Border.all( - width: 1.r, - color: subjective.state == 0 - ? Color(0xFFDDDDDD) - : subjective.state == 3 - ? Color(0xFF4CC793) - : subjective.state == 2 - ? Color(0xFFFF7474) - : Color(0xFF666666)), - borderRadius: BorderRadius.all( - Radius.circular(10.r))), - child: Center( - child: Text( - subjective.questionNo - .toString(), - style: TextStyle( - fontSize: 10.r, - color: subjective.state == - 0 - ? Color(0xFFDDDDDD) - : subjective.state == - 3 - ? Color(0xFF4CC793) - : subjective.state == - 2 - ? Color(0xFFFF7474) - : Color(0xFF666666)), - )), - ); - }), - ), - ) - : Text( - '无', - style: TextStyle(fontSize: 12.sp, - color: Color(0xFF5B5B5B)), - ), - ], - ), - ProgressBar( - title: '客观题正确率:', - color: Color(0xFF90E0BE), - percent: item.kgtCorrectRate / 100, - padingEdg: EdgeInsets.zero, - marginEdg: EdgeInsets.only(top: 8.h)), - ProgressBar( - title: '主观题正确率:', - color: Color(0xFF90E0BE), - percent: item.zgtCorrectRate / 100, - padingEdg: EdgeInsets.zero, - marginEdg: EdgeInsets.only(top: 8.h)), - ProgressBar( - title: '总正确率:', - color: Color(0xFF90E0BE), - percent: item.correctRate / 100, - padingEdg: EdgeInsets.zero, - marginEdg: EdgeInsets.only(top: 8.h)), - ], - ), - ), - ); - }) - : const MyEmptyWidget(), - ); - }), - ), - ), - ], - ), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} \ No newline at end of file diff --git a/lib/page/home_page/home_logic.dart b/lib/page/home_page/home_logic.dart deleted file mode 100644 index 26fc330..0000000 --- a/lib/page/home_page/home_logic.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter_easyrefresh/easy_refresh.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/work_student.dart'; -import 'package:school_asignment_app/common/job/work_student_params.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:school_asignment_app/common/store/user_store.dart'; - -import 'home_state.dart'; - -class HomeLogic extends GetxController with RequestToolMixin, GetTickerProviderStateMixin { - final HomeState state = HomeState(); - late final EasyRefreshController refreshController; - - @override - void onInit() { - super.onInit(); - refreshController = EasyRefreshController(); - getList(); - } - void getList() async { - WorkStudentParams params = WorkStudentParams( - assessType: 0, - ); - WorkStudent data = await getClient().getUnAnnotateList(params); - UserStore.to.readOver.value = data.items.length; - state.workList.value = data.items; - refreshController.finishRefresh(); - } - @override - void dispose() { - super.dispose(); - refreshController.dispose(); - } -} diff --git a/lib/page/home_page/home_state.dart b/lib/page/home_page/home_state.dart deleted file mode 100644 index 9b50314..0000000 --- a/lib/page/home_page/home_state.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/user_info.dart'; -import 'package:school_asignment_app/common/store/user_store.dart'; -import 'package:school_asignment_app/common/job/work_student.dart'; - -class HomeState { - HomeState() { - ///Initialize variables - } - - late Rx userInfo; - late RxInt readOver = UserStore.to.readOver; - late RxList workList = RxList(); - late int type = 1; -} diff --git a/lib/page/home_page/home_view.dart b/lib/page/home_page/home_view.dart deleted file mode 100644 index bfc59fb..0000000 --- a/lib/page/home_page/home_view.dart +++ /dev/null @@ -1,438 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_easyrefresh/easy_refresh.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:functional_widget_annotation/functional_widget_annotation.dart'; -import 'package:get/get.dart'; -import 'package:badges/badges.dart' as badges; -import 'package:percent_indicator/percent_indicator.dart'; -import 'package:school_asignment_app/common/job/work_student.dart'; -import 'package:school_asignment_app/common/utils/enum_untils.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; - -import 'home_logic.dart'; - -class HomePage extends StatefulWidget { - const HomePage({Key? key}) : super(key: key); - - @override - State createState() => _HomePageState(); -} - -class _HomePageState extends State - with AutomaticKeepAliveClientMixin { - final logic = Get.find(); - final state = Get.find().state; - - @override - bool get wantKeepAlive => true; - - @override - Widget build(BuildContext context) { - super.build(context); - var spaceWidth = SizedBox(height: ScreenUtil().screenWidth / 19); - return AnnotatedRegion( - value: const SystemUiOverlayStyle( - systemNavigationBarColor: Color(0xFF000000), - systemNavigationBarDividerColor: null, - statusBarColor: Colors.white, - systemNavigationBarIconBrightness: Brightness.light, - statusBarIconBrightness: Brightness.dark, - statusBarBrightness: Brightness.light, - ), - child: Column( - children: [ - Container( - height: 200.h, - width: double.infinity, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/job_home_top_bgm.png'), - fit: BoxFit.fill, // 完全填充 - ), - ), - ), - SizedBox(height: 30.h), - Obx(() { - return $TermRow( - context, - [ - EntranceModel( - title: '作业批阅', - image: 'assets/images/job_home_marking.png', - navigationUrl: Routes.readOverPage), - EntranceModel( - title: '学生历史作业', - image: 'assets/images/job_home_history.png', - navigationUrl: Routes.studentHistoryWorkPage, - page: 'history', - ), - EntranceModel( - title: '知识点点掌握', - image: 'assets/images/job_home_knowledge.png', - navigationUrl: Routes.knowledgePointsGraspPage) - ], - state.readOver.value); - }), - spaceWidth, - $TermRow( - context, - [ - EntranceModel( - title: '答题轨迹', - image: 'assets/images/job_home_answer_record.png', - navigationUrl: ''), - EntranceModel( - title: '优先批阅设定', - image: 'assets/images/job_home_youxian.png', - navigationUrl: Routes.studentHistoryWorkPage, - page: 'set', - ) - ], - 0), - - /* $TermRow( - context, - [ - EntranceModel( - title: '批阅设置', - image: 'assets/images/job_home_marking_set.png', - navigationUrl: '') - ], - 0),*/ - Expanded(child: Obx(() { - return EasyRefresh( - firstRefresh: false, - taskIndependence: true, - controller: logic.refreshController, - header: MaterialHeader(), - footer: TaurusFooter(), - child: ListView.builder( - padding: EdgeInsets.only( - top: 11.h, bottom: 10.h, left: 12.w, right: 12.w), - itemBuilder: (context, index) { - Items item = state.workList[index]; - return InkWell( - onTap: () { - Get.toNamed(Routes.annotateClassPage, arguments: { - 'id': item.id, - 'name': item.name, - 'grade': item.grade - }); - }, - child: Container( - margin: EdgeInsets.only(bottom: 16.h), - child: Column( - children: [ - SizedBox(height: 30.h), - Container( - padding: EdgeInsets.symmetric( - vertical: 16.h, horizontal: 10.w), - width: double.infinity, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.r), - color: const Color.fromRGBO(255, 255, 255, 1), - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(210, 216, 241, 1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 5.8, //阴影模糊程度 - spreadRadius: 0, //阴影扩散程度 - ) - ], - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: Utils.isPad() ? 32.w : 38.w, - height: 18.h, - alignment: Alignment.center, - padding: EdgeInsets.only( - left: Utils.isPad() ? 2.w : 3.w), - decoration: BoxDecoration( - color: state.type == 1 - ? const Color.fromRGBO( - 104, 136, 253, 1) - : const Color.fromRGBO( - 255, 175, 56, 1), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(14.r), - topRight: Radius.circular(3.r), - bottomLeft: Radius.circular(4.r), - bottomRight: Radius.circular(4.r), - ), - ), - margin: EdgeInsets.only(right: 4.w), - child: quickText( - state.type == 1 ? '作业' : '考试', - color: Colors.white, - size: 10.sp), - ), - Expanded( - child: quickText( - item.name, - maxLines: 2, - size: Utils.isPad() ? 14.sp : 16.sp, - color: - const Color.fromRGBO(70, 70, 70, 1), - fontWeight: FontWeight.bold, - ), - ) - ], - ), - SizedBox(height: 10.h), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - quickText( - EnumUtils.formatSubject(item.subject), - color: - const Color.fromRGBO(97, 97, 97, 1), - size: 12.sp, - ), - quickText(' / ', - color: const Color.fromRGBO( - 130, 130, 130, 1), - size: 11.sp, - fontWeight: FontWeight.w500), - Container( - child: Row( - crossAxisAlignment: - CrossAxisAlignment.end, - children: [ - quickText('题量:', - color: const Color.fromRGBO( - 130, 130, 130, 1), - size: 11.sp), - quickText( - '10', - color: const Color.fromRGBO( - 97, 97, 97, 1), - size: 13.sp, - ), - ], - ), - ), - quickText(' / ', - color: const Color.fromRGBO( - 130, 130, 130, 1), - size: 11.sp, - fontWeight: FontWeight.w500), - quickText( - DateTime.parse(item.publishTime) - .toString() - .substring(0, 10), - color: - const Color.fromRGBO(97, 97, 97, 1), - size: 12.sp), - ], - ), - SizedBox(height: 10.h), - Row( - children: [ - Expanded( - child: Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(10.r), - ), - child: LinearPercentIndicator( - padding: EdgeInsets.zero, - animation: true, - lineHeight: 8.h, - animationDuration: 2500, - percent: item.annotateRate == null?0:item.annotateRate! / 100, - progressColor: - const Color(0xFF6888FD), - backgroundColor: - const Color(0xFFE8E8E8), - barRadius: Radius.circular(10.r), - ), - ), - ), - SizedBox( - width: 10.r, - ), - quickText( - '${item.annotateRate!.toStringAsFixed(0)}%', - size: 10.sp, - color: const Color(0xFF464646)), - ], - ), - // FavoriteButton(jobTaskItem.id, jobTaskItem.title), - ], - ), - ), - ], - ), - ), - ); - }, - itemCount: state.workList.length, - ), - ); - })), - ], - ), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} - -class EntranceModel extends Object { - String title; - String image; - String navigationUrl; - String? page; - - EntranceModel( - {required this.title, - required this.image, - required this.navigationUrl, - this.page}); -} - -@swidget -Widget $TermRow(BuildContext context, List items, int? data) { - var leng = items.length; - Widget childWidget; - switch (leng) { - case 1: - childWidget = - Row(children: [Expanded(child: $TermItem(context, items[0], data!))]); - break; - case 2: - childWidget = Row(children: [ - Expanded(flex: 9, child: $TermItem(context, items[0], data!)), - const Expanded(flex: 1, child: SizedBox()), - Expanded(flex: 9, child: $TermItem(context, items[1], data!)), - ]); - break; - case 3: - double theHeight = ScreenUtil().screenWidth / 19 + 54.h * 2; - childWidget = Row( - children: [ - Expanded( - child: $TermItem(context, items[0], data!, theHeight: theHeight)), - SizedBox(width: ScreenUtil().screenWidth / 19), - Expanded( - child: SizedBox( - height: theHeight, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - $TermItem(context, items[1], data), - $TermItem(context, items[2], data), - ], - ), - ), - ), - ], - ); - break; - default: - childWidget = Container(); - } - - return Container( - padding: EdgeInsets.symmetric(horizontal: 14.w), child: childWidget); -} - -@swidget -Widget $TermItem(BuildContext context, EntranceModel e, int data, - {double? theHeight}) { - bool isJob = e.title == '作业批阅'; - - return Material( - color: Colors.white, - elevation: 3.r, - shadowColor: const Color.fromRGBO(231, 231, 231, 1), - borderRadius: BorderRadius.all(Radius.circular(8.r)), - child: InkWell( - onTap: () { - Get.toNamed(e.navigationUrl, arguments: {'page': e.page ?? ''}); - }, - - // splashColor: splashColor, - borderRadius: BorderRadius.all(Radius.circular(8.r)), - child: badges.Badge( - showBadge: isJob && data > 0, - ignorePointer: false, - badgeContent: quickText(data, color: Colors.white, size: 10.sp), - badgeAnimation: const badges.BadgeAnimation.rotation( - animationDuration: Duration(seconds: 1), - colorChangeAnimationDuration: Duration(seconds: 1), - loopAnimation: false, - curve: Curves.fastOutSlowIn, - colorChangeAnimationCurve: Curves.easeInCubic, - ), - badgeStyle: badges.BadgeStyle( - badgeColor: const Color.fromRGBO(255, 105, 105, 1), - shape: badges.BadgeShape.square, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(10.r), - topRight: Radius.circular(8.5.r), - bottomRight: Radius.circular(8.5.r)), - // borderSide: BorderSide(color: Colors.white, width: 2), - elevation: 1, - padding: EdgeInsets.symmetric( - horizontal: Utils.isPad() ? 11.w : 16.w, vertical: 2.h), - ), - position: badges.BadgePosition.topEnd(top: 10.r, end: 10.r), - child: Container( - height: theHeight, - padding: EdgeInsets.symmetric(vertical: 12.h), - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(8.r)), - // boxShadow: [ - // BoxShadow( - // color: const Color.fromRGBO(231, 231, 231, 1), - // offset: Offset(4.w, 6.h), //阴影y轴偏移量 - // blurRadius: 8, //阴影模糊程度 - // spreadRadius: 0.2, //阴影扩散程度 - // ) - // ], - // border: Border.all(width: 0.5.w, color: Color.fromARGB(255, 219, 226, 250)), - ), - alignment: Alignment.center, - child: isJob - ? Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset(e.image, - height: 32.r, width: 32.r, fit: BoxFit.cover), - SizedBox(height: 6.r), - quickText(e.title, - size: 12.sp, - color: const Color.fromRGBO(79, 79, 79, 1), - fontWeight: FontWeight.w500), - ], - ) - : Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset(e.image, - height: 32.r, width: 32.r, fit: BoxFit.cover), - SizedBox(width: 6.r), - quickText(e.title, - size: 12.sp, - color: const Color.fromRGBO(79, 79, 79, 1), - fontWeight: FontWeight.w500), - ], - ), - ), - )), - ); -} diff --git a/lib/page/home_page/widget/student_group_list.dart b/lib/page/home_page/widget/student_group_list.dart deleted file mode 100644 index 04f8007..0000000 --- a/lib/page/home_page/widget/student_group_list.dart +++ /dev/null @@ -1,163 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/class_item.dart'; -import 'package:school_asignment_app/common/utils/enum_untils.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/MyEmptyWidget.dart'; - -class StudentGroupList extends StatelessWidget { - final List studentGroups; - final Function goNextPage; - final Widget? rightBtn; - - const StudentGroupList(this.studentGroups, this.goNextPage, - {Key? key,this.rightBtn}) - : super(key: key); - - @override - Widget build(BuildContext context) { - return Obx(() { - return studentGroups != null && studentGroups.isNotEmpty - ? Utils.isPad() - ? GridView( - shrinkWrap: true, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - mainAxisSpacing: 10.r, - crossAxisSpacing: 10.r, - childAspectRatio: 556 / 112, - ), - children: List.generate(studentGroups.length, (index) { - ClassItem item = studentGroups[index]; - return InkWell( - onTap: () { - goNextPage(item.classId,'${EnumUtils.formatGrade(item.grade)}${item.className}',item.subject); - }, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 10.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(10.r)), - color: Colors.white, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(right: 8.r), - child: Text( - '${EnumUtils.formatGrade(item.grade)}${item.className}', - style: TextStyle( - fontSize: 10.sp, color: Color(0xFF6888FD)), - ), - ), - const Spacer(), - /*Expanded( - child: Text( - classNames, - style: TextStyle( - fontSize: 10.sp, - color: Color(0xFF999999), - overflow: TextOverflow.ellipsis, - ), - textAlign: TextAlign.end, - ), - ),*/ - rightBtn != null - ? rightBtn! - : Container( - margin: EdgeInsets.only(left: 5.r), - height: 20.r, - width: 55.r, - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(20.r)), - color: const Color(0xFF6888FD), - ), - child: Center( - child: Text( - '详情', - style: TextStyle( - fontSize: 10.sp, color: Colors.white), - ), - ), - ) - ], - ), - ), - ); - }), - ) - : ListView.builder( - shrinkWrap: true, - itemBuilder: (context, index) { - ClassItem item = studentGroups[index]; - return InkWell( - onTap: () { - goNextPage(item.classId,'${EnumUtils.formatGrade(item.grade)}${item.className}',item.subject); - }, - child: Container( - padding: - EdgeInsets.symmetric(vertical: 15.r, horizontal: 10.r), - margin: EdgeInsets.only(bottom: 10.r), - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(10.r)), - color: Colors.white, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(right: 8.r), - child: Text( - '${EnumUtils.formatGrade(item.grade)}${item.className}', - style: TextStyle( - fontSize: 14.sp, color: Color(0xFF6888FD)), - ), - ), - const Spacer(), - /* Expanded( - child: Text( - classNames, - style: TextStyle( - fontSize: 12.sp, - color: Color(0xFF999999), - overflow: TextOverflow.ellipsis, - ), - textAlign: TextAlign.end, - ), - ),*/ - rightBtn != null - ? rightBtn! - : Container( - margin: EdgeInsets.only(left: 5.r), - height: 24.r, - width: 55.r, - decoration: BoxDecoration( - borderRadius: - BorderRadius.all(Radius.circular(20.r)), - color: const Color(0xFF6888FD), - ), - child: Center( - child: Text( - '详情', - style: TextStyle( - fontSize: 10.sp, color: Colors.white), - ), - ), - ) - ], - ), - ), - ); - }, - itemCount: studentGroups.length, - ) - : Padding( - padding: EdgeInsets.only( - top: MediaQuery.of(context).size.height / 2 - 200.r), - child: const MyEmptyWidget(), - ); - }); - } -} diff --git a/lib/page/login_page/login_logic.dart b/lib/page/login_page/login_logic.dart deleted file mode 100644 index 6b4266b..0000000 --- a/lib/page/login_page/login_logic.dart +++ /dev/null @@ -1,138 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:school_asignment_app/common/store/user_store.dart'; -import 'package:school_asignment_app/common/utils/storage.dart'; -import 'package:school_asignment_app/common/utils/toast_utils.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; - -import 'login_state.dart'; - -class LoginLogic extends GetxController with RequestToolMixin { - final LoginState state = LoginState(); - - @override - void onReady() { - // TODO: implement onReady - super.onReady(); - } - - @override - void onInit() { - super.onInit(); - state.userNameController = TextEditingController(text: 'longyunfei')..addListener(userNameListener); - state.passwordController = TextEditingController(text: '123@abc'); - state.pwdFocus = FocusNode(); - state.theFocus = FocusNode(); - } - - void userNameListener() { - String userName = state.userNameController.text; - int useNameLength = userName.length; - bool hasNameValNew = useNameLength > 0; - if (hasNameValNew != state.hasNameVal) state.hasNameVal = hasNameValNew; - const isProd = bool.fromEnvironment('dart.vm.product'); - if (!isProd && useNameLength == 11) { - state.passwordController.text = userName.substring(useNameLength - 6); - } - } - - void showPassword() { - state.isShowPwd.value = !state.isShowPwd.value; - } - -// 前往登录 - void toLogin() async { - if (!state.canLogin.value) return; - - state.canLogin.value = false; - - void toMsg(msg) { - ToastUtils.showError(msg); - state.canLogin.value = true; - } - - Utils.hideKeyboard(); - - String userName = state.userNameController.text.trim(); - String userPwd = state.passwordController.text.trim(); - if (userName == '') return toMsg('请填写用户账号'); - if (userPwd == '') return toMsg('请填写密码再试'); - if (!state.readAgreement.value) return toMsg('请阅读用户协议'); - - EasyLoading.show(status: 'loading...'); - - try { - await getClient().toLogin(userName, userPwd); - String? nameidentifier = UserStore.to.userInfo.value?.nameidentifier; - if (nameidentifier == null) { - throw Exception('用户信息无效,请重试'); - } - var data = await getClient().getUser(nameidentifier); - if (data == null) { - throw Exception('用户信息获取失败'); - } - UserStore.to.setUserDetailInfo(data); - EasyLoading.dismiss(); - Get.offAllNamed(Routes.startPage); - // if (resultData.code != 200 || userData?.accessToken == null || userData?.accessToken == '') { - // return toMsg(resultData.message ?? '登录失败,请重试'); - // } - - // UserStore.to.setToken(userData!.accessToken); - // state.canLogin.value = true; - - // BaseStructureResult userRes = await UserApi.getUserInfo(); - // print('99999999999'); - // print(userRes.data!.userName); - // if (userRes.code != 200 || userRes.data == null) { - // throw Exception('登录失败,请重试'); - // } else { - // UserStore.to.setUserInfo(userRes.data!); - // Get.offAllNamed(Routes.home); - // } - - /* fastData.setUser(userRes.data!).then((value) { - // 记住密码 - if (keepPwd) { - fastData.setUserPwdAndAccount({'pwd': userPwd, 'account': userName}); - } - // 更新 - ref.read(userProvider.notifier).initUserInfo(); - ref.read(userTokenProvider.notifier).initToken(); - - // 跳转登录页 - Get.toNamed(Routes.login); - // RouterManager.router.navigateTo(context, RouterManager.root, clearStack: true, transition: getTransition()); - });*/ - } catch (e) { - print('进来异常'); - EasyLoading.dismiss(); - UserStore.to.erase(); - StorageService.to.erase(); - if (e is Exception) { - try { - toMsg(e.toString().split(":")[1]); - return; - // ignore: empty_catches - } catch (e) {} - } - toMsg('登录失败,请重试'); - } finally { - state.canLogin.value = true; - } - } - - @override - void dispose() { - super.dispose(); - state.userNameController - ..removeListener(userNameListener) - ..dispose(); - state.passwordController.dispose(); - state.pwdFocus.dispose(); - state.theFocus.dispose(); - } -} diff --git a/lib/page/login_page/login_view.dart b/lib/page/login_page/login_view.dart deleted file mode 100644 index 865a954..0000000 --- a/lib/page/login_page/login_view.dart +++ /dev/null @@ -1,329 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/common/const_text.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; - -import 'login_logic.dart'; - -class LoginPage extends StatefulWidget { - const LoginPage({Key? key}) : super(key: key); - - @override - State createState() => _LoginPageState(); -} - -class _LoginPageState extends State { - final logic = Get.find(); - final state = Get.find().state; - - @override - Widget build(BuildContext context) { - return GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () { - Utils.hideKeyboard(); - // FocusScope.of(context).requestFocus(state.theFocus); - }, - child: AnnotatedRegion( - value: const SystemUiOverlayStyle( - statusBarColor: Colors.transparent, - systemNavigationBarIconBrightness: Brightness.light, - statusBarIconBrightness: Brightness.light, - statusBarBrightness: Brightness.dark, - ), - child: Scaffold( - backgroundColor: Colors.transparent, - resizeToAvoidBottomInset: false, - body: Container( - width: double.infinity, - height: double.infinity, - alignment: Alignment.center, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/login_bg.png'), - fit: BoxFit.fill, // 完全填充 - ), - ), - child: SingleChildScrollView( - child: Column( - children: [ - Container( - width: 86.w, - height: 86.w, - alignment: Alignment.center, - child: SizedBox( - height: 86.w, - width: 86.w, - child: Image.asset('assets/images/login_logo.png', - fit: BoxFit.cover), - ), - ), - Container( - margin: EdgeInsets.symmetric( - horizontal: 32.w, vertical: 24.h), - padding: EdgeInsets.only( - top: 34.h, bottom: 16.h, left: 22.w, right: 22.w), - color: Colors.transparent, - /* decoration: BoxDecoration( - color: Colors.transparent, - border: Border.all(width: 1.w, color: Colors.white), - borderRadius: BorderRadius.all(Radius.circular(10.w)), - boxShadow: const [ - BoxShadow( - color: Color.fromRGBO(46, 91, 255, 0.1), - offset: Offset.zero, //阴影y轴偏移量 - blurRadius: 100, //阴影模糊程度 - spreadRadius: 100, //阴影扩散程度 - ) - ], - ),*/ - child: Column(children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 10.r), - decoration: BoxDecoration( - color: Colors.transparent, - border: Border.all(width: 1.w, color: const Color(0xFFAECBFF)), - borderRadius: BorderRadius.all(Radius.circular(17.w)), - ), - child: Center( - child: TextField( - controller: state.userNameController, - /* maxLines: 1, - maxLength: 20,*/ - textInputAction: TextInputAction.next, - onEditingComplete: () { - Get.focusScope?.nextFocus(); - // FocusScope.of(context).requestFocus(_pwdFocus); - }, - style: TextStyle( - color: Colors.white, - fontSize: 14.sp, - ), - decoration: InputDecoration( - hintText: "请输入账号", - hintStyle: TextStyle( - fontSize: 14.sp, - color: Colors.white,), - // labelText: "账号", - labelStyle: TextStyle( - fontSize: 14.sp, - color: Colors.white,), - border: InputBorder.none, - prefixIcon:Image.asset('assets/images/login_account.png',width: 20.r,height: 20.r,), - /* suffixIcon: !state.hasNameVal - ? null - : Transform.translate( - offset: - Offset(10, 10), // 根据原始组件的padding值来设置偏移量 - child: IconButton( - alignment: Alignment.center, - padding: EdgeInsets.zero, - icon: Icon( - Icons.highlight_off_sharp, - color: Colors.grey, - size: 16.r, - ), - onPressed: () { - state.userNameController - .clear(); // 清空文本框内容 - state.passwordController.clear(); - }, - ), - ),*/ - ), - ), - ), - ), - SizedBox(height: 15.r,), - Obx(() { - return Container( - padding: EdgeInsets.symmetric(horizontal: 10.r), - decoration: BoxDecoration( - color: Colors.transparent, - border: Border.all(width: 1.w, color: const Color(0xFFAECBFF)), - borderRadius: BorderRadius.all(Radius.circular(17.w)), - ), - child: TextField( - focusNode: state.pwdFocus, - controller: state.passwordController, - keyboardType: TextInputType.number, - maxLines: 1, - obscureText: state.isShowPwd.value, - //隐藏密码显示 - textInputAction: TextInputAction.go, - // onSubmitted: (val) => toLogin(), - style: TextStyle( - color: Colors.white, - fontSize: 14.sp, - ), - decoration: InputDecoration( - hintText: "请输入密码", - /* suffix: GestureDetector( - onTap: logic.showPassword, - child: Icon( - Icons.remove_red_eye, - color: state.isShowPwd.value - ? Theme.of(context).primaryColor - : Colors.grey, - ), - ),*/ - prefixIcon: Image.asset('assets/images/login_pwd.png',width: 20.r,height: 20.r,), - hintStyle: TextStyle( - fontSize: 14.sp, - color: Colors.white,), - border: InputBorder.none, - // labelText: "密码", - isDense: true, - labelStyle: TextStyle( - fontSize: 14.sp, - color: Colors.white,), - ), - ), - ); - }), - SizedBox( - height: 22.h, - ), - /* Row( - children: [ - Container( - width: 30.w, - padding: EdgeInsets.only(right: 10.w), - child: Obx(() { - return Checkbox( - activeColor: Theme.of(context).primaryColor, - checkColor: Colors.white, - value: state.keepPwd.value, - onChanged: (value) { - Get.focusScope?.nextFocus(); - *//* FocusScope.of(context).requestFocus( - state.pwdFocus); - FocusScope.of(context).requestFocus( - state.theFocus);*//* - state.keepPwd.value = value ?? false; - }, - ); - }), - ), - InkWell( - onTap: () { - Utils.hideKeyboard(); - *//*Get.focusScope?.nextFocus(); - Get.focusScope?.nextFocus();*//* - - *//* FocusScope.of(context).requestFocus( - state.pwdFocus); - FocusScope.of(context).requestFocus( - state.theFocus);*//* - state.keepPwd.value = !state.keepPwd.value; - }, - child: Text( - '记住密码', - style: TextStyle( - fontSize: 14.sp, - color: Colors.white, - ), - ), - ), - ], - ),*/ - InkWell( - onTap: () { - logic.toLogin(); - // Get.toNamed(Routes.home); - }, - child: Obx(() { - return Container( - margin: EdgeInsets.symmetric(vertical: 10.h), - decoration: BoxDecoration( - color: state.canLogin.value - ? const Color.fromRGBO(107, 104, 252, 1) - : const Color(0xFFdddddd), - boxShadow: [ - BoxShadow( - color: - const Color.fromRGBO(46, 91, 255, 0.5), - offset: Offset(6.w, 10.h), //阴影y轴偏移量 - blurRadius: 14, //阴影模糊程度 - spreadRadius: 0.5, //阴影扩散程度 - ) - ], - borderRadius: BorderRadius.all( - Radius.circular(17.w), - ), - ), - alignment: Alignment.center, - width: double.infinity, - height: 50.h, - child: Text( - '登 录', - style: TextStyle( - fontSize: 16.sp, color: Colors.white), - ), - ); - }), - ), - Row( - children: [ - Container( - width: 30.w, - padding: EdgeInsets.only(right: 10.w), - child: Obx(() { - return Checkbox( - activeColor: Theme.of(context).primaryColor, - checkColor: Colors.white, - value: state.readAgreement.value, - onChanged: (value) { - Utils.hideKeyboard(); - /* FocusScope.of(context).requestFocus( - state.pwdFocus); - FocusScope.of(context).requestFocus( - state.theFocus);*/ - state.readAgreement.value = value ?? false; - }, - ); - }), - ), - InkWell( - onTap: () { - Get.toNamed(Routes.agreementPage, arguments: { - "type": AGREEMENT_KEY.USER_AGREEMENT.name - }); - }, - child: quickText('请仔细阅读', size: 13.sp), - ), - InkWell( - onTap: () { - Get.toNamed(Routes.agreementPage, arguments: { - "type": AGREEMENT_KEY.USER_AGREEMENT.name - }); - }, - child: Text( - '《用户协议》', - style: TextStyle( - fontSize: 14.r, - color: Colors.deepOrangeAccent), - ), - ), - ], - ), - ]), - ) - ], - ), - )), - ), - ), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} diff --git a/lib/page/work_page/work_logic.dart b/lib/page/work_page/work_logic.dart deleted file mode 100644 index ee7a8d5..0000000 --- a/lib/page/work_page/work_logic.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:get/get.dart'; - -import 'work_state.dart'; - -class WorkLogic extends GetxController { - final WorkState state = WorkState(); -} diff --git a/lib/page/work_page/work_state.dart b/lib/page/work_page/work_state.dart deleted file mode 100644 index a1046e9..0000000 --- a/lib/page/work_page/work_state.dart +++ /dev/null @@ -1,5 +0,0 @@ -class WorkState { - WorkState() { - ///Initialize variables - } -} diff --git a/lib/page/work_page/work_view.dart b/lib/page/work_page/work_view.dart deleted file mode 100644 index a48e23b..0000000 --- a/lib/page/work_page/work_view.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; - -import 'work_logic.dart'; - -class WorkPage extends StatefulWidget { - const WorkPage({Key? key}) : super(key: key); - - @override - State createState() => _WorkPageState(); -} - -class _WorkPageState extends State with AutomaticKeepAliveClientMixin { - final logic = Get.find(); - final state = Get.find().state; - - @override - bool get wantKeepAlive => true; - - @override - Widget build(BuildContext context) { - super.build(context); - return Scaffold( - body: Container( - alignment: Alignment.center, - child: quickText('考试页面'), - ), - ); - } - - @override - void dispose() { - Get.delete(); - super.dispose(); - } -} diff --git a/lib/routes/app_pages.dart b/lib/routes/app_pages.dart deleted file mode 100644 index 8923402..0000000 --- a/lib/routes/app_pages.dart +++ /dev/null @@ -1,55 +0,0 @@ -import 'package:get/get.dart'; -import 'package:school_asignment_app/page/global_widget/other_page.dart'; -import 'package:school_asignment_app/page/global_widget/start_page.dart'; -import 'package:school_asignment_app/page/home_page/children/annotate_class/annotate_class_binding.dart'; -import 'package:school_asignment_app/page/home_page/children/annotate_class/annotate_class_view.dart'; -import 'package:school_asignment_app/page/home_page/children/class_student/class_student_binding.dart'; -import 'package:school_asignment_app/page/home_page/children/class_student/class_student_view.dart'; -import 'package:school_asignment_app/page/home_page/children/job_report/job_report_binding.dart'; -import 'package:school_asignment_app/page/home_page/children/job_report/job_report_view.dart'; -import 'package:school_asignment_app/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_binding.dart'; -import 'package:school_asignment_app/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_view.dart'; -import 'package:school_asignment_app/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_binding.dart'; -import 'package:school_asignment_app/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_view.dart'; -import 'package:school_asignment_app/page/home_page/children/my_info.dart'; -import 'package:school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_binding.dart'; -import 'package:school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_view.dart'; -import 'package:school_asignment_app/page/home_page/children/read_over/read_over_binding.dart'; -import 'package:school_asignment_app/page/home_page/children/read_over/read_over_view.dart'; -import 'package:school_asignment_app/page/home_page/children/student_history_work/student_history_work_binding.dart'; -import 'package:school_asignment_app/page/home_page/children/student_history_work/student_history_work_view.dart'; -import 'package:school_asignment_app/page/home_page/children/student_personal/student_personal_binding.dart'; -import 'package:school_asignment_app/page/home_page/children/student_personal/student_personal_view.dart'; -import 'package:school_asignment_app/page/home_page/children/student_work_detail/student_work_detail_binding.dart'; -import 'package:school_asignment_app/page/home_page/children/student_work_detail/student_work_detail_view.dart'; -import 'package:school_asignment_app/page/home_page/home_binding.dart'; -import 'package:school_asignment_app/page/home_page/home_view.dart'; -import 'package:school_asignment_app/page/login_page/children/agreement_page.dart'; -import 'package:school_asignment_app/page/login_page/login_binding.dart'; -import 'package:school_asignment_app/page/login_page/login_view.dart'; -import 'package:school_asignment_app/page/work_page/work_binding.dart'; -import 'package:school_asignment_app/page/work_page/work_view.dart'; -part 'app_routes.dart'; - -abstract class AppPages { - static final pages = [ - GetPage(name: Routes.login, page: () => const LoginPage(), binding: LoginBinding(), transition: Transition.noTransition), - GetPage(name: Routes.agreementPage, page: () => const AgreementPage(), binding: LoginBinding(), transition: Transition.noTransition), - GetPage(name: Routes.home, page: () => const HomePage(), binding: HomeBinding(), transition: Transition.noTransition), - GetPage(name: Routes.startPage, page: () => const StartPage(), binding: StartPageIndexBinding(), transition: Transition.noTransition), - GetPage(name: Routes.myInfo, page: () => const MyInfo(), transition: Transition.noTransition), - GetPage(name: Routes.work, page: () => const WorkPage(), binding: WorkBinding(), transition: Transition.noTransition), - GetPage(name: Routes.otherPage, page: () => const OhterPage(), transition: Transition.noTransition), - GetPage(name: Routes.readOverPage, page: () => const ReadOverPage(), binding: ReadOverBinding(), transition: Transition.noTransition), - GetPage(name: Routes.studentHistoryWorkPage, page: () => const StudentHistoryWorkPage(), binding: StudentHistoryWorkBinding(), transition: Transition.noTransition), - GetPage(name: Routes.classStudentPage, page: () => const ClassStudentPage(), binding: ClassStudentBinding(), transition: Transition.noTransition), - GetPage(name: Routes.annotateClassPage, page: () => const AnnotateClassPage(), binding: AnnotateClassBinding(), transition: Transition.noTransition), - GetPage(name: Routes.quickDataCheckPage, page: () => const QuickDataCheckPage(), binding: QuickDataCheckBinding(), transition: Transition.noTransition), - GetPage(name: Routes.jobReportPage, page: () => const JobReportPage(), binding: JobReportBinding(), transition: Transition.noTransition), - GetPage(name: Routes.studentPersonalPage, page: () => const StudentPersonalPage(), binding: StudentPersonalBinding(), transition: Transition.noTransition), - GetPage(name: Routes.studentWorkDetailPage, page: () => const StudentWorkDetailPage(), binding: StudentWorkDetailBinding(), transition: Transition.noTransition), - GetPage(name: Routes.knowledgePointsGraspPage, page: () => const KnowledgePointsGraspPage(), binding: KnowledgePointsGraspBinding(), transition: Transition.noTransition), - GetPage(name: Routes.knowledgePointsGraspDetailPage, page: () => const KnowledgePointsGraspDetailPage(), binding: KnowledgePointsGraspDetailBinding(), transition: Transition.noTransition), - - ]; -} diff --git a/making_school_asignment_app/.gitignore b/making_school_asignment_app/.gitignore new file mode 100644 index 0000000..93abda3 --- /dev/null +++ b/making_school_asignment_app/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ +/lib/*.g.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/making_school_asignment_app/.metadata b/making_school_asignment_app/.metadata new file mode 100644 index 0000000..cbf1dc0 --- /dev/null +++ b/making_school_asignment_app/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "a14f74ff3a1cbd521163c5f03d68113d50af93d3" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + - platform: android + create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + - platform: ios + create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + - platform: linux + create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + - platform: macos + create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + - platform: web + create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + - platform: windows + create_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + base_revision: a14f74ff3a1cbd521163c5f03d68113d50af93d3 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/README.md b/making_school_asignment_app/README.md similarity index 94% rename from README.md rename to making_school_asignment_app/README.md index 4e3f781..bbc93bd 100644 --- a/README.md +++ b/making_school_asignment_app/README.md @@ -1,4 +1,4 @@ -# school_asignment_app +# making_school_asignment_app A new Flutter project. diff --git a/analysis_options.yaml b/making_school_asignment_app/analysis_options.yaml similarity index 93% rename from analysis_options.yaml rename to making_school_asignment_app/analysis_options.yaml index 61b6c4d..0d29021 100644 --- a/analysis_options.yaml +++ b/making_school_asignment_app/analysis_options.yaml @@ -13,8 +13,7 @@ linter: # The lint rules applied to this project can be customized in the # section below to disable rules from the `package:flutter_lints/flutter.yaml` # included above or to enable additional rules. A list of all available lints - # and their documentation is published at - # https://dart-lang.github.io/linter/lints/index.html. + # and their documentation is published at https://dart.dev/lints. # # Instead of disabling a lint rule for the entire project in the # section below, it can also be suppressed for a single line of code diff --git a/android/.gitignore b/making_school_asignment_app/android/.gitignore similarity index 100% rename from android/.gitignore rename to making_school_asignment_app/android/.gitignore diff --git a/making_school_asignment_app/android/app/build.gradle b/making_school_asignment_app/android/app/build.gradle new file mode 100644 index 0000000..abf5b83 --- /dev/null +++ b/making_school_asignment_app/android/app/build.gradle @@ -0,0 +1,87 @@ +plugins { + id "com.android.application" + id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file("local.properties") +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader("UTF-8") { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty("flutter.versionCode") +if (flutterVersionCode == null) { + flutterVersionCode = "1" +} + +def flutterVersionName = localProperties.getProperty("flutter.versionName") +if (flutterVersionName == null) { + flutterVersionName = "1.0" +} + +def keystorePropertiesFile = rootProject.file("key.properties") +def keystoreProperties = new Properties() +keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) + +android { + namespace = "com.yuanxuan.making_school_asignment_app" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile file(keystoreProperties['storeFile']) + storePassword keystoreProperties['storePassword'] + } + debug { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile file(keystoreProperties['storeFile']) + storePassword keystoreProperties['storePassword'] + } + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.yuanxuan.making_school_asignment_app" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutterVersionCode.toInteger() + versionName = flutterVersionName + } + + buildTypes { + // release { + // // TODO: Add your own signing config for the release build. + // // Signing with the debug keys for now, so `flutter run --release` works. + // signingConfig = signingConfigs.debug + // } + release { + signingConfig signingConfigs.release + minifyEnabled false //删除无用代码 + shrinkResources false //删除无用资源 + } + debug { + signingConfig signingConfigs.debug + minifyEnabled false //删除无用代码 + shrinkResources false //删除无用资源 + } + } +} + +flutter { + source = "../.." +} diff --git a/making_school_asignment_app/android/app/keys/key.jks b/making_school_asignment_app/android/app/keys/key.jks new file mode 100644 index 0000000..4be0358 Binary files /dev/null and b/making_school_asignment_app/android/app/keys/key.jks differ diff --git a/android/app/src/debug/AndroidManifest.xml b/making_school_asignment_app/android/app/src/debug/AndroidManifest.xml similarity index 100% rename from android/app/src/debug/AndroidManifest.xml rename to making_school_asignment_app/android/app/src/debug/AndroidManifest.xml diff --git a/making_school_asignment_app/android/app/src/main/AndroidManifest.xml b/making_school_asignment_app/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a54c890 --- /dev/null +++ b/making_school_asignment_app/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/making_school_asignment_app/android/app/src/main/kotlin/com/yuanxuan/making_school_asignment_app/MainActivity.kt b/making_school_asignment_app/android/app/src/main/kotlin/com/yuanxuan/making_school_asignment_app/MainActivity.kt new file mode 100644 index 0000000..84fff45 --- /dev/null +++ b/making_school_asignment_app/android/app/src/main/kotlin/com/yuanxuan/making_school_asignment_app/MainActivity.kt @@ -0,0 +1,5 @@ +package com.yuanxuan.making_school_asignment_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-hdpi/android12splash.png b/making_school_asignment_app/android/app/src/main/res/drawable-hdpi/android12splash.png new file mode 100644 index 0000000..c37ef58 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/drawable-hdpi/android12splash.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-mdpi/android12splash.png b/making_school_asignment_app/android/app/src/main/res/drawable-mdpi/android12splash.png new file mode 100644 index 0000000..397dc9b Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/drawable-mdpi/android12splash.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-night-hdpi/android12splash.png b/making_school_asignment_app/android/app/src/main/res/drawable-night-hdpi/android12splash.png new file mode 100644 index 0000000..c37ef58 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/drawable-night-hdpi/android12splash.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-night-mdpi/android12splash.png b/making_school_asignment_app/android/app/src/main/res/drawable-night-mdpi/android12splash.png new file mode 100644 index 0000000..397dc9b Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/drawable-night-mdpi/android12splash.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-night-v21/launch_background.xml b/making_school_asignment_app/android/app/src/main/res/drawable-night-v21/launch_background.xml new file mode 100644 index 0000000..f88598c --- /dev/null +++ b/making_school_asignment_app/android/app/src/main/res/drawable-night-v21/launch_background.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-night-xhdpi/android12splash.png b/making_school_asignment_app/android/app/src/main/res/drawable-night-xhdpi/android12splash.png new file mode 100644 index 0000000..be1739b Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/drawable-night-xhdpi/android12splash.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png b/making_school_asignment_app/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png new file mode 100644 index 0000000..734cbfb Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png b/making_school_asignment_app/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png new file mode 100644 index 0000000..3c1a620 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-night/launch_background.xml b/making_school_asignment_app/android/app/src/main/res/drawable-night/launch_background.xml new file mode 100644 index 0000000..f88598c --- /dev/null +++ b/making_school_asignment_app/android/app/src/main/res/drawable-night/launch_background.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-v21/background.png b/making_school_asignment_app/android/app/src/main/res/drawable-v21/background.png new file mode 100644 index 0000000..f3dd603 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/drawable-v21/background.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-v21/launch_background.xml b/making_school_asignment_app/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f88598c --- /dev/null +++ b/making_school_asignment_app/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-xhdpi/android12splash.png b/making_school_asignment_app/android/app/src/main/res/drawable-xhdpi/android12splash.png new file mode 100644 index 0000000..be1739b Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/drawable-xhdpi/android12splash.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-xxhdpi/android12splash.png b/making_school_asignment_app/android/app/src/main/res/drawable-xxhdpi/android12splash.png new file mode 100644 index 0000000..734cbfb Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/drawable-xxhdpi/android12splash.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/drawable-xxxhdpi/android12splash.png b/making_school_asignment_app/android/app/src/main/res/drawable-xxxhdpi/android12splash.png new file mode 100644 index 0000000..3c1a620 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/drawable-xxxhdpi/android12splash.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/drawable/background.png b/making_school_asignment_app/android/app/src/main/res/drawable/background.png new file mode 100644 index 0000000..f3dd603 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/drawable/background.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/drawable/launch_background.xml b/making_school_asignment_app/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..f88598c --- /dev/null +++ b/making_school_asignment_app/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/making_school_asignment_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/making_school_asignment_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..d188848 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/mipmap-hdpi/launch_image.png b/making_school_asignment_app/android/app/src/main/res/mipmap-hdpi/launch_image.png new file mode 100644 index 0000000..63e4839 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/mipmap-hdpi/launch_image.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/mipmap-ldpi/ic_launcher.png b/making_school_asignment_app/android/app/src/main/res/mipmap-ldpi/ic_launcher.png new file mode 100644 index 0000000..e3b3df8 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/mipmap-ldpi/ic_launcher.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/making_school_asignment_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..6bd5e0b Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/mipmap-mdpi/launch_image.png b/making_school_asignment_app/android/app/src/main/res/mipmap-mdpi/launch_image.png new file mode 100644 index 0000000..63e4839 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/mipmap-mdpi/launch_image.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/making_school_asignment_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..a1379b2 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/mipmap-xhdpi/launch_image.png b/making_school_asignment_app/android/app/src/main/res/mipmap-xhdpi/launch_image.png new file mode 100644 index 0000000..63e4839 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/mipmap-xhdpi/launch_image.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/making_school_asignment_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..b049db5 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/mipmap-xxhdpi/launch_image.png b/making_school_asignment_app/android/app/src/main/res/mipmap-xxhdpi/launch_image.png new file mode 100644 index 0000000..63e4839 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/mipmap-xxhdpi/launch_image.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/making_school_asignment_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..f3ab3ed Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/mipmap-xxxhdpi/launch_image.png b/making_school_asignment_app/android/app/src/main/res/mipmap-xxxhdpi/launch_image.png new file mode 100644 index 0000000..63e4839 Binary files /dev/null and b/making_school_asignment_app/android/app/src/main/res/mipmap-xxxhdpi/launch_image.png differ diff --git a/making_school_asignment_app/android/app/src/main/res/values-night-v31/styles.xml b/making_school_asignment_app/android/app/src/main/res/values-night-v31/styles.xml new file mode 100644 index 0000000..4dc9ba4 --- /dev/null +++ b/making_school_asignment_app/android/app/src/main/res/values-night-v31/styles.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/android/app/src/main/res/values-night/styles.xml b/making_school_asignment_app/android/app/src/main/res/values-night/styles.xml similarity index 78% rename from android/app/src/main/res/values-night/styles.xml rename to making_school_asignment_app/android/app/src/main/res/values-night/styles.xml index 06952be..dbc9ea9 100644 --- a/android/app/src/main/res/values-night/styles.xml +++ b/making_school_asignment_app/android/app/src/main/res/values-night/styles.xml @@ -5,6 +5,10 @@ @drawable/launch_background + false + false + false + shortEdges + + + + diff --git a/android/app/src/main/res/values/styles.xml b/making_school_asignment_app/android/app/src/main/res/values/styles.xml similarity index 78% rename from android/app/src/main/res/values/styles.xml rename to making_school_asignment_app/android/app/src/main/res/values/styles.xml index cb1ef88..0d1fa8f 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/making_school_asignment_app/android/app/src/main/res/values/styles.xml @@ -5,6 +5,10 @@ @drawable/launch_background + false + false + false + shortEdges + + + + + + + + + + + + + + + + + + + + + + + diff --git a/making_school_asignment_app/android/build.gradle b/making_school_asignment_app/android/build.gradle new file mode 100644 index 0000000..d2ffbff --- /dev/null +++ b/making_school_asignment_app/android/build.gradle @@ -0,0 +1,18 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = "../build" +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/making_school_asignment_app/android/gradle.properties b/making_school_asignment_app/android/gradle.properties new file mode 100644 index 0000000..3b5b324 --- /dev/null +++ b/making_school_asignment_app/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/making_school_asignment_app/android/gradle/wrapper/gradle-wrapper.properties similarity index 61% rename from android/gradle/wrapper/gradle-wrapper.properties rename to making_school_asignment_app/android/gradle/wrapper/gradle-wrapper.properties index 3c472b9..a28a56b 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/making_school_asignment_app/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip +distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-7.6.3-all.zip \ No newline at end of file diff --git a/making_school_asignment_app/android/key.properties b/making_school_asignment_app/android/key.properties new file mode 100644 index 0000000..7563432 --- /dev/null +++ b/making_school_asignment_app/android/key.properties @@ -0,0 +1,4 @@ +storePassword= Woshiren.123 +keyPassword= Woshiren.123 +keyAlias=sign +storeFile=./keys/key.jks \ No newline at end of file diff --git a/making_school_asignment_app/android/settings.gradle b/making_school_asignment_app/android/settings.gradle new file mode 100644 index 0000000..536165d --- /dev/null +++ b/making_school_asignment_app/android/settings.gradle @@ -0,0 +1,25 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.3.0" apply false + id "org.jetbrains.kotlin.android" version "1.7.10" apply false +} + +include ":app" diff --git a/making_school_asignment_app/appcast.xml b/making_school_asignment_app/appcast.xml new file mode 100644 index 0000000..8b1b01e --- /dev/null +++ b/making_school_asignment_app/appcast.xml @@ -0,0 +1,56 @@ + + + + auto_updater_example + Most recent updates to auto_updater_example + en + + + Version 1.0.3+4 + #发行说明-读取html方式(2选1) + + #发行说明-写死方式(2选1) + + +
  • 1、修复已知BUG
  • +
  • 2、优化操作布局
  • + + ]]> +
    + Fri, 14 Mar 2025 12:00:00 +0800 + #你更新程序的地址 + +
    +
    +
    \ No newline at end of file diff --git a/assets/icons/demo.css b/making_school_asignment_app/assets/icons/demo.css similarity index 100% rename from assets/icons/demo.css rename to making_school_asignment_app/assets/icons/demo.css diff --git a/assets/icons/demo_index.html b/making_school_asignment_app/assets/icons/demo_index.html similarity index 87% rename from assets/icons/demo_index.html rename to making_school_asignment_app/assets/icons/demo_index.html index d81cd85..7b89818 100644 --- a/assets/icons/demo_index.html +++ b/making_school_asignment_app/assets/icons/demo_index.html @@ -54,6 +54,60 @@
      +
    • + +
      Frame-1
      +
      &#xe62c;
      +
    • + +
    • + +
      Frame-2
      +
      &#xe62a;
      +
    • + +
    • + +
      Frame
      +
      &#xe62b;
      +
    • + +
    • + +
      Frame 2223726
      +
      &#xe63f;
      +
    • + +
    • + +
      Frame 2223727
      +
      &#xe640;
      +
    • + +
    • + +
      Frame 2223723
      +
      &#xe641;
      +
    • + +
    • + +
      Frame 2223725
      +
      &#xe642;
      +
    • + +
    • + +
      Frame 2223728
      +
      &#xe643;
      +
    • + +
    • + +
      Frame 2223724
      +
      &#xe644;
      +
    • +
    • Frame
      @@ -414,9 +468,9 @@
      @font-face {
         font-family: 'iconfont';
      -  src: url('iconfont.woff2?t=1710142362036') format('woff2'),
      -       url('iconfont.woff?t=1710142362036') format('woff'),
      -       url('iconfont.ttf?t=1710142362036') format('truetype');
      +  src: url('iconfont.woff2?t=1718091057560') format('woff2'),
      +       url('iconfont.woff?t=1718091057560') format('woff'),
      +       url('iconfont.ttf?t=1718091057560') format('truetype');
       }
       

      第二步:定义使用 iconfont 的样式

      @@ -442,6 +496,87 @@
        +
      • + +
        + Frame-1 +
        +
        .icon-Frame-114 +
        +
      • + +
      • + +
        + Frame-2 +
        +
        .icon-Frame-25 +
        +
      • + +
      • + +
        + Frame +
        +
        .icon-Frame15 +
        +
      • + +
      • + +
        + Frame 2223726 +
        +
        .icon-a-Frame2223726 +
        +
      • + +
      • + +
        + Frame 2223727 +
        +
        .icon-a-Frame2223727 +
        +
      • + +
      • + +
        + Frame 2223723 +
        +
        .icon-a-Frame2223723 +
        +
      • + +
      • + +
        + Frame 2223725 +
        +
        .icon-a-Frame2223725 +
        +
      • + +
      • + +
        + Frame 2223728 +
        +
        .icon-a-Frame2223728 +
        +
      • + +
      • + +
        + Frame 2223724 +
        +
        .icon-a-Frame2223724 +
        +
      • +
      • @@ -982,6 +1117,78 @@
          +
        • + +
          Frame-1
          +
          #icon-Frame-114
          +
        • + +
        • + +
          Frame-2
          +
          #icon-Frame-25
          +
        • + +
        • + +
          Frame
          +
          #icon-Frame15
          +
        • + +
        • + +
          Frame 2223726
          +
          #icon-a-Frame2223726
          +
        • + +
        • + +
          Frame 2223727
          +
          #icon-a-Frame2223727
          +
        • + +
        • + +
          Frame 2223723
          +
          #icon-a-Frame2223723
          +
        • + +
        • + +
          Frame 2223725
          +
          #icon-a-Frame2223725
          +
        • + +
        • + +
          Frame 2223728
          +
          #icon-a-Frame2223728
          +
        • + +
        • + +
          Frame 2223724
          +
          #icon-a-Frame2223724
          +
        • +
        • 本软件尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、 - 更有个性化的服务,本软件会按照本隐私权政策的规定使用和披露您的个人信息。但本软件将以高度的勤勉、审慎义务对待这些信息。 - 除本隐私权政策另有规定外,在未征得您事先许可的情况下,本软件不会将这些信息对外披露或向第三方提供。本软件会不时更新本隐私权政策。 - 您在同意本软件服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私权政策属于本软件服务使用协议不可分割的一部分。 -

          1.适用范围

          a)在您使用本软件网络服务,本软件自动接收并记录的您的手机上的信息,包括但不限于您的健康数据、使用的语言、 - 访问日期和时间、软硬件特征信息及您需求的网页记录等数据;

          2.信息的使用

          a)在获得您的数据之后,本软件会将其上传至服务器, - 以生成您的排行榜数据,以便您能够更好地使用服务。

          3.信息披露

          a)本软件不会将您的信息披露给不受信任的第三方。 -

          b)根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露;

          c)如您出现违反中国有关法律、 - 法规或者相关规则的情况,需要向第三方披露;

          4.信息存储和交换

          本软件收集的有关您的信息和资料将保存在本软件及(或)其关联公司的服务器上, - 这些信息和资料可能传送至您所在国家、地区或本软件收集信息和资料所在地的境外并在境外被访问、存储和展示。 -

          5.信息安全

          a)在使用本软件网络服务进行网上交易时,您不可避免的要向交易对方或潜在的交易对方披露自己的个人信息,如联络方式或者邮政地址。 - 请您妥善保护自己的个人信息,仅在必要的情形下向他人提供。如您发现自己的个人信息泄密,请您立即联络本软件客服,以便本软件采取相应措施。 -


          ''', + richText: ''' + + + + + + Privacy Policy + + +

          隐私政策

          +
          更新日期:2024/8/1
          +
          生效日期:2024/8/1
          +

          导言

          +

          + 点智学 是一款由 重庆智学力人工智能科技有限公司 (以下简称“我们”)提供的产品。 + 您在使用我们的服务时,我们可能会收集和使用您的相关信息。我们希望通过本《隐私政策》向您说明,在使用我们的服务时,我们如何收集、使用、储存和分享这些信息,以及我们为您提供的访问、更新、控制和保护这些信息的方式。 + 本《隐私政策》与您所使用的 点智学 服务息息相关,希望您仔细阅读,在需要时,按照本《隐私政策》的指引,作出您认为适当的选择。本《隐私政策》中涉及的相关技术词汇,我们尽量以简明扼要的表述,并提供进一步说明的链接,以便您的理解。 +

          +

          您使用或继续使用我们的服务,即意味着同意我们按照本《隐私政策》收集、使用、储存和分享您的相关信息。

          +

          如对本《隐私政策》或相关事宜有任何问题,请通过 yq0826@dingtalk.com 与我们联系。

          + +

          1. 我们收集的信息

          +

          我们或我们的第三方合作伙伴提供服务时,可能会收集、储存和使用下列与您有关的信息。如果您不提供相关信息,可能无法注册成为我们的用户或无法享受我们提供的某些服务,或者无法达到相关服务拟达到的效果。

          + +
            +
          • 位置信息,指您开启设备定位功能并使用我们基于位置提供的相关服务时,收集的有关您位置的信息,包括:
            • 您通过具有定位功能的移动设备使用我们的服务时,通过GPS或WiFi等方式收集的您的地理位置信息;
            • 您可以通过关闭定位功能,停止对您的地理位置信息的收集。
          • +
          • 个人信息,您在注册账户或使用我们的服务时,向我们提供的相关个人信息,例如电话号码、电子邮件等。
          • +
          • 日志信息,指您使用我们的服务时,系统可能通过cookies、标识符及相关技术收集的信息,包括您的设备信息浏览信息点击信息,并将该等信息储存为日志信息,为您提供保障服务安全。您可以通过浏览器设置拒绝或管理cookie、标识符或相关技术的使用。
          • +
          + + + + +
        + +

        2. 信息的存储

        +2.1 信息存储的方式和期限 +
          +
        • 我们会通过安全的方式存储您的信息,包括本地存储(例如利用APP进行数据缓存)、数据库和服务器日志。
        • +
        • 一般情况下,我们只会在为实现服务目的所必需的时间内或法律法规规定的条件下存储您的个人信息。
        • +
        + +2.2 信息存储的地域 +
          +
        • 我们会按照法律法规规定,将境内收集的用户个人信息存储于中国境内。
        • +
        • 目前我们不会跨境传输或存储您的个人信息。将来如需跨境传输或存储的,我们会向您告知信息出境的目的、接收方、安全保证措施和安全风险,并征得您的同意。
        • +
        + +2.3 产品或服务停止运营时的通知 +
          +
        • 当我们的产品或服务发生停止运营的情况时,我们将以推送通知、公告等形式通知您,并在合理期限内删除您的个人信息或进行匿名化处理,法律法规另有规定的除外。
        • +
        + +

        3. 信息安全

        +

        +我们使用各种安全技术和程序,以防信息的丢失、不当使用、未经授权阅览或披露。例如,在某些服务中,我们将利用加密技术(例如SSL)来保护您提供的个人信息。但请您理解,由于技术的限制以及可能存在的各种恶意手段,在互联网行业,即便竭尽所能加强安全措施,也不可能始终保证信息百分之百的安全。您需要了解,您接入我们的服务所用的系统和通讯网络,有可能因我们可控范围外的因素而出现问题。 +

        + +

        4. 我们如何使用信息

        +

        我们可能将在向您提供服务的过程之中所收集的信息用作下列用途:

        +
          +
        • 向您提供服务;
        • +
        • 在我们提供服务时,用于身份验证、客户服务、安全防范、诈骗监测、存档和备份用途,确保我们向您提供的产品和服务的安全性;
        • +
        • 帮助我们设计新服务,改善我们现有服务;
        • +
        • 向您提供与您更加相关的广告以替代普遍投放的广告;
        • +
        • 评估我们服务中的广告和其他促销及推广活动的效果,并加以改善;
        • +
        • 软件认证或管理软件升级;
        • +
        • 让您参与有关我们产品和服务的调查。
        • +
        + +

        5. 信息共享

        +

        +目前,我们不会主动共享或转让您的个人信息至第三方,如存在其他共享或转让您的个人信息或您需要我们将您的个人信息共享或转让至第三方情形时,我们会直接或确认第三方征得您对上述行为的明示同意。 +

        +

        +为了投放广告,评估、优化广告投放效果等目的,我们需要向广告主及其代理商等第三方合作伙伴共享您的部分数据,要求其严格遵守我们关于数据隐私保护的措施与要求,包括但不限于根据数据保护协议、承诺书及相关数据处理政策进行处理,避免识别出个人身份,保障隐私安全。 +

        +

        +我们不会向合作伙伴分享可用于识别您个人身份的信息(例如您的姓名或电子邮件地址),除非您明确授权。 +

        +

        +我们不会对外公开披露所收集的个人信息,如必须公开披露时,我们会向您告知此次公开披露的目的、披露信息的类型及可能涉及的敏感信息,并征得您的明示同意。 +

        +

        +随着我们业务的持续发展,我们有可能进行合并、收购、资产转让等交易,我们将告知您相关情形,按照法律法规及不低于本《隐私政策》所要求的标准继续保护或要求新的控制者继续保护您的个人信息。 +

        + +

        6. 注销权

        +

        +另外,根据相关法律法规及国家标准,以下情形中,我们可能会共享、转让、公开披露个人信息无需事先征得您的授权同意: +

        +
          +
        • 与国家安全、国防安全直接相关的;
        • +
        • 与公共安全、公共卫生、重大公共利益直接相关的;
        • +
        • 犯罪侦查、起诉、审判和判决执行等直接相关的;
        • +
        • 出于维护个人信息主体或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;
        • +
        • 个人信息主体自行向社会公众公开个人信息的;
        • +
        • 从合法公开披露的信息中收集个人信息的,如合法的新闻报道、政府信息公开等渠道。
        • +
        + +

        6. 您的权利

        + + + + + +

        (一)访问权

        + +

        原则上您可以通过如下方式访问您的个人信息:

        + +

        1、账号信息:您可以随时登录您的账号,访问或编辑您账号中的资料信息、更改您的密码、添加安全信息、进行账号关联或身份认证等。

        + +

        2、使用信息:您可以在我们的网站、客户端等服务中查阅订单信息等,您也可通过本隐私政策文末提供的方式联系我们删除这些信息,我们将在核实您的身份后提供,但法律法规另有约定的除外。

        + +

        3、其他信息:如您在此访问过程中遇到操作问题的或如需获取其他前述无法获知的信息内容,您可通过本隐私政策文末提供的方式联系我们,我们将在核实您的身份后提供,但法律法规另有约定的除外。

        + +

        (二)删除权

        + +

        您可以通过本隐私政策文末提供的联系方式向我们提出删除您信息的请求,例如您不再需要我们继续为您提供服务,但已做数据匿名化处理或法律法规另有规定的除外。

        + +

        (三)索取权

        + +

        如您需要您数据的副本,您可以通过本隐私政策文末提供的方式联系我们,在核实您的身份后,我们将向您提供您在我们的服务中的信息副本(例如基本资料、身份信息),但法律法规另有规定的除外。

        + +

        (四)撤回同意权

        + +

        如您想更改相关功能的授权范围,您可以在我们的产品或服务中的相关功能设置界面进行操作处理。如您在此过程中遇到操作问题的,可以通过本隐私政策文末提供的方式联系我们。

        + +

        当您取消相关信息收集的授权后,我们将不再收集该信息,也无法再为您提供上述与之对应的服务;但您知悉并同意,除非您行使前述“删除权”,否则您的该行为不会影响我们基于您之前的授权进行的信息的处理、存储。

        + +

        (五)注销权

        + +

        您可以通过联系我们的客服或通过其他我们公示的方式注销您的账号(但法律法规另有规定的除外),一旦您注销账号,将无法使用我们提供的全线用户产品的服务,因此请您谨慎操作。我们为了保护您或他人的合法权益会结合您对我们提供的各产品或服务的使用情况判断是否支持您的注销请求。除法律法规另有规定外,注销账号之后,您该账户内的所有信息将被清空,并根据您的要求删除您的信息。您通过第三方账号(如微信等)授权登录我们的服务时,需要向第三方申请注销账号。

        + +

        (六)例外情形

        + +

        在以下情形中,按照法律法规要求,我们将无法响应您的请求:

        + +

        (1)与个人信息控制者履行法律法规规定的义务相关的;

        + +

        (2)与国家安全、国防安全有关的;

        + +

        (3)与公共安全、公共卫生、重大公共利益有关的;

        + +

        (4)与刑事侦查、起诉、审判和执行判决等有关的;

        + +

        (5)有充分证据表明您存在主观恶意或滥用权利的;

        + +

        (6)出于维护个人信息主体或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;

        + +

        (7)响应您的请求将导致您或其他个人、组织的合法权益受到严重损害的;

        + +

        (8)涉及商业秘密的。

        + +

        7. 变更

        +

        +我们可能适时修订本《隐私政策》的条款。当变更发生时,我们会在版本更新时向您提示新的《隐私政策》,并向您说明生效日期。请您仔细阅读变更后的《隐私政策》内容,若您继续使用我们的服务,即表示您同意我们按照更新后的《隐私政策》处理您的个人信息。 +

        + +

        8. 未成年人保护

        +

        +我们鼓励父母或监护人指导未满十八岁的未成年人使用我们的服务。我们建议未成年人鼓励他们的父母或监护人阅读本《隐私政策》,并建议未成年人在提交的个人信息之前寻求父母或监护人的同意和指导。 +

        + +

        用户协议

        +

        重庆智学力人工智能科技有限公司(以下简称“我们”)依据本协议为用户(以下简称“你”)提供点智学服务。本协议对你和我们均具有法律约束力。

        +

        一、本服务的功能

        +

        你可以使用本服务网络阅卷。

        +

        二、责任范围及限制

        +

        你使用本服务得到的结果仅供参考,实际情况以官方为准。

        +

        三、隐私保护

        +

        我们重视对你隐私的保护,你的个人隐私信息将根据《隐私政策》受到保护与规范,详情请参阅《隐私政策》。

        +

        四、其他条款

        +

        4.1 本协议所有条款的标题仅为阅读方便,本身并无实际涵义,不能作为本协议涵义解释的依据。

        +

        4.2 本协议条款无论因何种原因部分无效或不可执行,其余条款仍有效,对双方具有约束力。

        + + + +''', ), AGREEMENT_KEY.USER_AGREEMENT: AgreementClass( title: '用户协议', diff --git a/making_school_asignment_app/lib/common/job/annotate_list_to_refresh.dart b/making_school_asignment_app/lib/common/job/annotate_list_to_refresh.dart new file mode 100644 index 0000000..73dfb10 --- /dev/null +++ b/making_school_asignment_app/lib/common/job/annotate_list_to_refresh.dart @@ -0,0 +1,17 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'annotate_list_to_refresh.g.dart'; + + +@JsonSerializable() + class AnnotateListToRefresh extends Object { + + AnnotateListToRefresh(); + + factory AnnotateListToRefresh.fromJson(Map srcJson) => _$AnnotateListToRefreshFromJson(srcJson); + + Map toJson() => _$AnnotateListToRefreshToJson(this); + +} + + diff --git a/lib/common/job/annotated_class.dart b/making_school_asignment_app/lib/common/job/annotated_class.dart similarity index 91% rename from lib/common/job/annotated_class.dart rename to making_school_asignment_app/lib/common/job/annotated_class.dart index 2483b53..528a8d0 100644 --- a/lib/common/job/annotated_class.dart +++ b/making_school_asignment_app/lib/common/job/annotated_class.dart @@ -114,42 +114,45 @@ class AnnotatedStudents extends Object { class HomeworkFavs extends Object { @JsonKey(name: 'id') - String id; + String? id; @JsonKey(name: 'homeworkId') - String homeworkId; + String? homeworkId; @JsonKey(name: 'homeworkName') - String homeworkName; + String? homeworkName; @JsonKey(name: 'grade') - int grade; + int? grade; @JsonKey(name: 'subject') - int subject; + int? subject; @JsonKey(name: 'classId') - String classId; + String? classId; @JsonKey(name: 'className') - String className; + String? className; @JsonKey(name: 'studentId') - int studentId; + int? studentId; @JsonKey(name: 'studentName') - String studentName; + String? studentName; @JsonKey(name: 'templateId') - String templateId; + int templateId; @JsonKey(name: 'questionNo') - int questionNo; + String? questionNo; @JsonKey(name: 'subjectiveAnswer') - String subjectiveAnswer; + String? subjectiveAnswer; - HomeworkFavs(this.id,this.homeworkId,this.homeworkName,this.grade,this.subject,this.classId,this.className,this.studentId,this.studentName,this.templateId,this.questionNo,this.subjectiveAnswer,); + @JsonKey(name: 'zgtAnswer') + String? zgtAnswer; + + HomeworkFavs(this.id,this.homeworkId,this.homeworkName,this.grade,this.subject,this.classId,this.className,this.studentId,this.studentName,this.templateId,this.questionNo,this.subjectiveAnswer,this.zgtAnswer); factory HomeworkFavs.fromJson(Map srcJson) => _$HomeworkFavsFromJson(srcJson); diff --git a/making_school_asignment_app/lib/common/job/app_version.dart b/making_school_asignment_app/lib/common/job/app_version.dart new file mode 100644 index 0000000..776fbb9 --- /dev/null +++ b/making_school_asignment_app/lib/common/job/app_version.dart @@ -0,0 +1,56 @@ +import 'package:json_annotation/json_annotation.dart'; + +import '../config/request_config.dart'; + +part 'app_version.g.dart'; + +@JsonSerializable() +class AppVersion extends Object { + // @JsonKey(name: 'id') + // String id; + + // @JsonKey(name: 'creatorId') + // int creatorId; + + // @JsonKey(name: 'creatorName') + // String creatorName; + + // @JsonKey(name: 'creationTime') + // String creationTime; + + @JsonKey(name: 'appName') + String appName; + + @JsonKey(name: 'version') + String version; + + @JsonKey(name: 'ftuType') + int ftuType; + + @JsonKey(name: 'appFileUrl') + String? appFileUrl; + + @JsonKey(name: 'description') + String? description; + + AppVersion( + // this.id, + // this.creatorId, + // this.creatorName, + // this.creationTime, + this.appName, + this.version, + this.ftuType, + this.appFileUrl, + this.description, + ) { + if (appFileUrl != null && ftuType != 2) { + appFileUrl = RequestConfig.imgUrl + appFileUrl!; + } + } + + factory AppVersion.fromJson(Map srcJson) => + _$AppVersionFromJson(srcJson); + + Map toJson() => _$AppVersionToJson(this); +} diff --git a/lib/common/job/class_item.dart b/making_school_asignment_app/lib/common/job/class_item.dart similarity index 100% rename from lib/common/job/class_item.dart rename to making_school_asignment_app/lib/common/job/class_item.dart diff --git a/lib/common/job/common/app_version_model.dart b/making_school_asignment_app/lib/common/job/common/app_version_model.dart similarity index 100% rename from lib/common/job/common/app_version_model.dart rename to making_school_asignment_app/lib/common/job/common/app_version_model.dart diff --git a/lib/common/job/common/base_app_version.dart b/making_school_asignment_app/lib/common/job/common/base_app_version.dart similarity index 86% rename from lib/common/job/common/base_app_version.dart rename to making_school_asignment_app/lib/common/job/common/base_app_version.dart index a9283e2..008608a 100644 --- a/lib/common/job/common/base_app_version.dart +++ b/making_school_asignment_app/lib/common/job/common/base_app_version.dart @@ -1,5 +1,5 @@ import 'package:json_annotation/json_annotation.dart'; -import 'package:school_asignment_app/common/job/common/base_page.dart'; +import 'package:making_school_asignment_app/common/job/common/base_page.dart'; part 'base_app_version.g.dart'; diff --git a/lib/common/job/common/base_page.dart b/making_school_asignment_app/lib/common/job/common/base_page.dart similarity index 100% rename from lib/common/job/common/base_page.dart rename to making_school_asignment_app/lib/common/job/common/base_page.dart diff --git a/lib/common/job/common/base_page_data.dart b/making_school_asignment_app/lib/common/job/common/base_page_data.dart similarity index 100% rename from lib/common/job/common/base_page_data.dart rename to making_school_asignment_app/lib/common/job/common/base_page_data.dart diff --git a/lib/common/job/common/base_structure_result.dart b/making_school_asignment_app/lib/common/job/common/base_structure_result.dart similarity index 93% rename from lib/common/job/common/base_structure_result.dart rename to making_school_asignment_app/lib/common/job/common/base_structure_result.dart index a5bbd49..5cc8159 100644 --- a/lib/common/job/common/base_structure_result.dart +++ b/making_school_asignment_app/lib/common/job/common/base_structure_result.dart @@ -7,7 +7,7 @@ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ import 'package:json_annotation/json_annotation.dart'; -import 'package:school_asignment_app/common/config/request_config.dart'; +import 'package:making_school_asignment_app/common/config/request_config.dart'; part 'base_structure_result.g.dart'; diff --git a/lib/common/job/common/upload_img_secret_key.dart b/making_school_asignment_app/lib/common/job/common/upload_img_secret_key.dart similarity index 100% rename from lib/common/job/common/upload_img_secret_key.dart rename to making_school_asignment_app/lib/common/job/common/upload_img_secret_key.dart diff --git a/lib/common/job/enum_subject.dart b/making_school_asignment_app/lib/common/job/enum_subject.dart similarity index 100% rename from lib/common/job/enum_subject.dart rename to making_school_asignment_app/lib/common/job/enum_subject.dart diff --git a/lib/common/job/homework_details.dart b/making_school_asignment_app/lib/common/job/homework_details.dart similarity index 75% rename from lib/common/job/homework_details.dart rename to making_school_asignment_app/lib/common/job/homework_details.dart index c7c1908..54f0fca 100644 --- a/lib/common/job/homework_details.dart +++ b/making_school_asignment_app/lib/common/job/homework_details.dart @@ -18,7 +18,10 @@ class HomeworkDetails extends Object { @JsonKey(name: 'dtls') List dtls; - HomeworkDetails(this.questions,this.knows,this.students,this.dtls); + @JsonKey(name: 'subject') + int? subject; + + HomeworkDetails(this.questions,this.knows,this.students,this.dtls,this.subject); factory HomeworkDetails.fromJson(Map srcJson) => _$HomeworkDetailsFromJson(srcJson); @@ -37,7 +40,7 @@ class Questions extends Object { int templateId; @JsonKey(name: 'questionNo') - int questionNo; + String questionNo; @JsonKey(name: 'questionType') int questionType; @@ -66,6 +69,9 @@ class Questions extends Object { @JsonKey(name: 'okRate') double? okRate; + @JsonKey(name: 'correctRate') + double? correctRate; + @JsonKey(name: 'priorityInfo') List? priorityInfo; @@ -78,8 +84,15 @@ class Questions extends Object { @JsonKey(name: 'answerNgStudents') List? answerNgStudents; + @JsonKey(name: 'overallTitles') + List? overallTitles; + + @JsonKey(name: 'options') + List? options; + Questions(this.id,this.templateId,this.questionNo,this.questionType,this.answer,this.score,this.questionPicture,this.subjectivePicture,this.knows,this.answerCount, - this.answerRate,this.okRate,this.priorityInfo,this.noAnswerStudents,this.answerOkStudents,this.answerNgStudents); + this.answerRate,this.okRate,this.priorityInfo,this.noAnswerStudents,this.answerOkStudents,this.answerNgStudents,this.correctRate, + this.overallTitles,this.options); factory Questions.fromJson(Map srcJson) => _$QuestionsFromJson(srcJson); @@ -117,7 +130,6 @@ class Knows extends Object { } - @JsonSerializable() class Students extends Object { @@ -166,19 +178,31 @@ class Students extends Object { @JsonKey(name: 'allNotDone') bool? allNotDone; + @JsonKey(name: 'isAllCorrect') + bool? isAllCorrect; + @JsonKey(name: 'queDtls') List? queDtls; @JsonKey(name: 'okRate') double? okRate; + @JsonKey(name: 'answerRate') + double? answerRate; + @JsonKey(name: 'noAnswerCount') int? noAnswerCount; @JsonKey(name: 'useTime') int? useTime; - Students(this.studentId,this.studentName,this.state,this.priorityAnnotate,this.kgtStu,this.kgtOkCount,this.kgtAnswerCount,this.zgtStu,this.zgtAnswerCount,this.zgtOkCount,this.allOk,this.kgtErrorCount,this.zgtErrorCount,this.zgtUnrated,this.allNotDone,this.queDtls,this.okRate,this.noAnswerCount,this.useTime); + @JsonKey(name: 'ttlSec') + String? ttlSec; + + @JsonKey(name: 'allTime') + int? allTime; + + Students(this.studentId,this.studentName,this.state,this.priorityAnnotate,this.kgtStu,this.kgtOkCount,this.kgtAnswerCount,this.zgtStu,this.zgtAnswerCount,this.zgtOkCount,this.allOk,this.kgtErrorCount,this.zgtErrorCount,this.zgtUnrated,this.allNotDone,this.queDtls,this.okRate,this.noAnswerCount,this.useTime,this.isAllCorrect,this.answerRate,this.allTime); factory Students.fromJson(Map srcJson) => _$StudentsFromJson(srcJson); @@ -206,7 +230,7 @@ class Dtls extends Object { int? templateId; @JsonKey(name: 'questionNo') - int questionNo; + String questionNo; @JsonKey(name: 'questionType') int questionType; @@ -220,6 +244,9 @@ class Dtls extends Object { @JsonKey(name: 'useTime') int useTime; + @JsonKey(name: 'lastAnswerTime') + String? lastAnswerTime; + @JsonKey(name: 'annotatePicture') String? annotatePicture; @@ -237,4 +264,42 @@ class Dtls extends Object { } +@JsonSerializable() +class OverallTitles extends Object { + @JsonKey(name: 'title') + String title; + + @JsonKey(name: 'count') + int count; + + OverallTitles(this.title,this.count); + + factory OverallTitles.fromJson(Map srcJson) => _$OverallTitlesFromJson(srcJson); + + Map toJson() => _$OverallTitlesToJson(this); + +} + +@JsonSerializable() +class SelectionRate extends Object { + + @JsonKey(name: 'optionName') + String optionName; + + @JsonKey(name: 'rate') + int rate; + + @JsonKey(name: 'isCheck') + bool isCheck; + + @JsonKey(name: 'currentOptionStudents') + List currentOptionStudents; + + SelectionRate(this.optionName,this.rate,this.isCheck,this.currentOptionStudents,); + + factory SelectionRate.fromJson(Map srcJson) => _$SelectionRateFromJson(srcJson); + + Map toJson() => _$SelectionRateToJson(this); + +} \ No newline at end of file diff --git a/lib/common/job/knowledge_points_grasp.dart b/making_school_asignment_app/lib/common/job/knowledge_points_grasp.dart similarity index 100% rename from lib/common/job/knowledge_points_grasp.dart rename to making_school_asignment_app/lib/common/job/knowledge_points_grasp.dart diff --git a/lib/common/job/knowledge_report_detail.dart b/making_school_asignment_app/lib/common/job/knowledge_report_detail.dart similarity index 97% rename from lib/common/job/knowledge_report_detail.dart rename to making_school_asignment_app/lib/common/job/knowledge_report_detail.dart index aa06f5c..d328df1 100644 --- a/lib/common/job/knowledge_report_detail.dart +++ b/making_school_asignment_app/lib/common/job/knowledge_report_detail.dart @@ -19,7 +19,7 @@ class KnowledgeReportDetail extends Object { int templateId; @JsonKey(name: 'questionNo') - int questionNo; + String questionNo; @JsonKey(name: 'questionType') int questionType; diff --git a/making_school_asignment_app/lib/common/job/marking_models/do_paper_bus.dart b/making_school_asignment_app/lib/common/job/marking_models/do_paper_bus.dart new file mode 100644 index 0000000..4a1ec84 --- /dev/null +++ b/making_school_asignment_app/lib/common/job/marking_models/do_paper_bus.dart @@ -0,0 +1,37 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'do_paper_bus.g.dart'; + +// 批阅页面底部操作栏BUG +@JsonSerializable() +class BottomOperationBar extends Object { + @JsonKey(name: 'revoke_pre_step') // 撤销上一步 + bool revokePreStep; + + @JsonKey(name: 'revoke_all') // 撤销全部 + bool revokeAll; + + BottomOperationBar({ + required this.revokePreStep, + required this.revokeAll, + }); + + factory BottomOperationBar.fromJson(Map srcJson) => _$BottomOperationBarFromJson(srcJson); + + Map toJson() => _$BottomOperationBarToJson(this); +} + + + +@JsonSerializable() + class ZoomKey extends Object { + + ZoomKey(); + + factory ZoomKey.fromJson(Map srcJson) => _$ZoomKeyFromJson(srcJson); + + Map toJson() => _$ZoomKeyToJson(this); + +} + + diff --git a/making_school_asignment_app/lib/common/job/marking_models/do_paper_details_param.dart b/making_school_asignment_app/lib/common/job/marking_models/do_paper_details_param.dart new file mode 100644 index 0000000..ad211c1 --- /dev/null +++ b/making_school_asignment_app/lib/common/job/marking_models/do_paper_details_param.dart @@ -0,0 +1,47 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'do_paper_details_param.g.dart'; + +@JsonSerializable(includeIfNull: false) +class DoPaperDetailsParam extends Object { + // 作业ID + @JsonKey(name: 'homeworkId') + String homeworkId; + + @JsonKey(name: 'homeworkName') + String homeworkName; + + // 班级ID + @JsonKey(name: 'classId') + String classId; + + // 0 作业 1 考试 + @JsonKey(name: 'assessType', defaultValue: 0) + int? assessType; + + // 科目 + @JsonKey(name: 'subject') + int subject; + + // 题型ID + @JsonKey(name: 'templateId') + int? templateId; + + // 学生ID + @JsonKey(name: 'studentId') + int? studentId; + + DoPaperDetailsParam({ + required this.homeworkId, + required this.homeworkName, + required this.classId, + required this.subject, + this.assessType, + this.templateId, + this.studentId, + }); + + factory DoPaperDetailsParam.fromJson(Map srcJson) => _$DoPaperDetailsParamFromJson(srcJson); + + Map toJson() => _$DoPaperDetailsParamToJson(this); +} diff --git a/making_school_asignment_app/lib/common/job/marking_models/do_paper_details_result.dart b/making_school_asignment_app/lib/common/job/marking_models/do_paper_details_result.dart new file mode 100644 index 0000000..3cb579e --- /dev/null +++ b/making_school_asignment_app/lib/common/job/marking_models/do_paper_details_result.dart @@ -0,0 +1,281 @@ +import 'package:get/get.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:making_school_asignment_app/common/config/request_config.dart'; + +part 'do_paper_details_result.g.dart'; + +@JsonSerializable(checked: true, includeIfNull: false) +class DoPaperDetailsResult extends Object { + @JsonKey(name: 'templateIds') + Map templateIds; + + // 自定义字段 + @JsonKey(name: 'templateIdKeys') + List? templateIdKeys; + + // 自定义字段 + @JsonKey(name: 'templateIdKeyMap') + Map? templateIdKeyMap; + + @JsonKey(name: 'submitStudents', toJson: _paperStudentsToJson) // 当前页 总提交学生集合 + List students; + + @JsonKey(name: 'templateId') + int templateId; + + @JsonKey(name: 'studentId') + int studentId; + + // 自定义字段 + @JsonKey(name: 'priority', defaultValue: false) + bool priority; + + @JsonKey(name: 'annotatedCount') // 当前试题批阅数量 + int annotatedCount; + + @JsonKey(name: 'submitCount') // 当前试题提交数量 + int submitCount; + + @JsonKey(name: 'zgtAnswer') // 主观题作答图片 + String zgtAnswer; + + @JsonKey(name: 'showZgtAnnotate') // 主观题老师批注图片 + String? showZgtAnnotate; + + @JsonKey(name: 'zgtAnnotate') // 主观题老师批注图片 + String? zgtAnnotate; + + @JsonKey(name: 'lastAnswerTime') // 学生提交作答试题时间 + String lastAnswerTime; + + // 批注时间 + @JsonKey(name: 'annotateTime') + String? annotateTime; + + @JsonKey(name: 'isFav') + bool isFav; + + @JsonKey(name: 'studentQuestions', toJson: _studentQuestionsToJson) + List studentQuestions; + + // 当前页 未提交学生集合 + @JsonKey(name: 'unSubmitStudents', toJson: _paperStudentsToJson) + List unSubmitStudents; + + @JsonKey(name: 'lastPage', toJson: _lastPageToJson) + LastPage? lastPage; + + @JsonKey(name: 'continuePage', toJson: _continuePageToJson) + ContinuePage? continuePage; + + + @JsonKey(name: 'nextPage', toJson: _nextPageToJson) + NextPage? nextPage; + + // 所有页 总待提交数量 + @JsonKey(name: 'totalUnAnnotateCount') + int totalUnAnnotateCount; + + @JsonKey(name: 'needAnnotate') // 是否需要批阅 + bool needAnnotate; + + DoPaperDetailsResult( + this.totalUnAnnotateCount, + this.templateIds, + this.students, + this.templateId, + this.studentId, + this.annotatedCount, + this.submitCount, + this.zgtAnswer, + this.zgtAnnotate, + this.lastAnswerTime, + this.isFav, + this.studentQuestions, + this.unSubmitStudents, + this.lastPage, + this.nextPage, + this.continuePage, + this.templateIdKeys, + this.templateIdKeyMap, + this.priority, + this.annotateTime, + this.showZgtAnnotate, + {this.needAnnotate = false}) { + if (templateIds.keys.isNotEmpty) { + templateIdKeys = templateIds.keys.map((e) => int.parse(e)).toList(); + templateIdKeyMap = {}; + for (var i = 1; i <= templateIdKeys!.length; i++) { + var theVal = templateIdKeys![i - 1]; + templateIdKeyMap![i] = theVal; + templateIdKeyMap![theVal] = i; + } + } + + // 找到当前学生是否是优先批阅 + if (students.isNotEmpty) { + var currentStudent = students.firstWhereOrNull((e) => e.id == studentId); + if (currentStudent != null) priority = currentStudent.isPriority; + } + + if (!zgtAnswer.contains(RequestConfig.imgUrl)) { + zgtAnswer = '${RequestConfig.imgUrl}$zgtAnswer?$lastAnswerTime'; + } + + if (zgtAnnotate?.isNotEmpty ?? false) { + showZgtAnnotate = RequestConfig.imgUrl + zgtAnnotate!; // 批注图片地址赋值 + if (annotateTime != null) showZgtAnnotate = '${showZgtAnnotate!}?$annotateTime'; + } + + // 判断当前试题是否需要批阅 + if (annotateTime == null || studentQuestions.indexWhere((e) => e.studentScore == null) != -1) { + needAnnotate = true; + } + // print('学生作答图片:${annotatedCount}'); + // print('老师批注图片提交数量:${submitCount}'); + } + + factory DoPaperDetailsResult.fromJson(Map srcJson) => _$DoPaperDetailsResultFromJson(srcJson); + + Map toJson() => _$DoPaperDetailsResultToJson(this); + + static List> _paperStudentsToJson(List examples) => examples.map((e) => e.toJson()).toList(); + + static List> _studentQuestionsToJson(List examples) => examples.map((e) => e.toJson()).toList(); + + static Map? _nextPageToJson(NextPage? example) => example?.toJson(); + static Map? _lastPageToJson(LastPage? example) => example?.toJson(); + static Map? _continuePageToJson(ContinuePage? example) => example?.toJson(); + +} + +@JsonSerializable() +class PaperStudents extends Object { + @JsonKey(name: 'id') + int id; + + @JsonKey(name: 'name') + String name; + + // 优先批阅 + @JsonKey(name: 'isPriority') + bool isPriority; + + PaperStudents( + this.id, + this.name, + this.isPriority, + ); + + factory PaperStudents.fromJson(Map srcJson) => _$PaperStudentsFromJson(srcJson); + + Map toJson() => _$PaperStudentsToJson(this); +} + +@JsonSerializable() +class StudentQuestions extends Object { + @JsonKey(name: 'questionNo') + String questionNo; + + // 总分 + @JsonKey(name: 'score') + int? score; + + // 分值步长 + @JsonKey(name: 'scoreStep') + int? scoreStep; + + // 是否已经批阅 + @JsonKey(name: 'isNeedAnnotate') + bool isNeedAnnotate; + + // 学生得分 + @JsonKey(name: 'studentScore') + int? studentScore; + + // 是否正确 + @JsonKey(name: 'isCorrect') + bool? isCorrect; + + // 正确率 + @JsonKey(name: 'correctRate') + int correctRate; + + @JsonKey(name: 'height') + double? height; + + @JsonKey(name: 'useTime') + int? useTime; + + StudentQuestions({ + required this.height, + required this.questionNo, + required this.correctRate, + required this.isNeedAnnotate, + this.score, + this.scoreStep, + this.studentScore, + this.isCorrect, + this.useTime, + }); + + factory StudentQuestions.fromJson(Map srcJson) => _$StudentQuestionsFromJson(srcJson); + + Map toJson() => _$StudentQuestionsToJson(this); +} + +@JsonSerializable() +class LastPage extends Object { + @JsonKey(name: 'templateId') + int templateId; + + @JsonKey(name: 'studentId') + int studentId; + + LastPage( + this.templateId, + this.studentId, + ); + + factory LastPage.fromJson(Map srcJson) => _$LastPageFromJson(srcJson); + + Map toJson() => _$LastPageToJson(this); +} + +@JsonSerializable() +class NextPage extends Object { + @JsonKey(name: 'templateId') + int templateId; + + @JsonKey(name: 'studentId') + int studentId; + + NextPage( + this.templateId, + this.studentId, + ); + + factory NextPage.fromJson(Map srcJson) => _$NextPageFromJson(srcJson); + + Map toJson() => _$NextPageToJson(this); +} + + +@JsonSerializable() + class ContinuePage extends Object { + + @JsonKey(name: 'templateId') + int templateId; + + @JsonKey(name: 'studentId') + int studentId; + + ContinuePage(this.templateId,this.studentId,); + + factory ContinuePage.fromJson(Map srcJson) => _$ContinuePageFromJson(srcJson); + + Map toJson() => _$ContinuePageToJson(this); + +} + + diff --git a/making_school_asignment_app/lib/common/job/marking_models/do_test_questions_image_info.dart b/making_school_asignment_app/lib/common/job/marking_models/do_test_questions_image_info.dart new file mode 100644 index 0000000..d548e47 --- /dev/null +++ b/making_school_asignment_app/lib/common/job/marking_models/do_test_questions_image_info.dart @@ -0,0 +1,75 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'do_test_questions_image_info.g.dart'; + +@JsonSerializable() +class TestQuestionsImageInfo extends Object { + @JsonKey(name: 'templateId') + int? templateId; + + @JsonKey(name: 'boxHeight') + double boxHeight; + + @JsonKey(name: 'boxWidth') + double boxWidth; + + @JsonKey(name: 'imageWidth') // 图片原始宽 + double imageWidth; + + @JsonKey(name: 'imageHeight') // 图片原始高 + double imageHeight; + + @JsonKey(name: 'url') + String url; + + @JsonKey(name: 'actualImgWidth') // 实际展示图片宽度 + double actualImgWidth; + + @JsonKey(name: 'actualImgHeight') // 实际展示图片高度 + double actualImgHeight; + + @JsonKey(name: 'remainingHeight') // 视图剩余高度 实际展示图片展示高度下 剩余高度.(若为负数就是超出视图的高度值) + double remainingHeight; + + @JsonKey(name: 'imageHeightOffsetStart') // 顶部坐标Y + double imageHeightOffsetStart; + + @JsonKey(name: 'imageHeightOffsetend') // 底部坐标Y + double imageHeightOffsetend; + + // 基准 + @JsonKey(name: 'scaleRatio') + double scaleRatio; + + // 缩放比例 + @JsonKey(name: 'zoom') + double zoom; + + TestQuestionsImageInfo({ + required this.url, + required this.boxWidth, + required this.boxHeight, + required this.imageWidth, + required this.imageHeight, + this.templateId, + this.scaleRatio = 1, + this.zoom = 1, + this.actualImgWidth = 0, + this.actualImgHeight = 0, + this.remainingHeight = 0, + this.imageHeightOffsetStart = 0, + this.imageHeightOffsetend = 0, + }) { + // 图片已视图宽为基准,高度自适应可滑动 图片的实际宽高都需要乘此基准值 + scaleRatio = boxWidth / imageWidth; + actualImgWidth = imageWidth * scaleRatio * zoom; + actualImgHeight = imageHeight * scaleRatio * zoom; + remainingHeight = boxHeight - actualImgHeight; + imageHeightOffsetStart = remainingHeight / 2; + imageHeightOffsetend = imageHeightOffsetStart + actualImgHeight; + } + + factory TestQuestionsImageInfo.fromJson(Map srcJson) => _$TestQuestionsImageInfoFromJson(srcJson); + + Map toJson() => _$TestQuestionsImageInfoToJson(this); +} diff --git a/making_school_asignment_app/lib/common/job/marking_models/favor_param.dart b/making_school_asignment_app/lib/common/job/marking_models/favor_param.dart new file mode 100644 index 0000000..d81a41b --- /dev/null +++ b/making_school_asignment_app/lib/common/job/marking_models/favor_param.dart @@ -0,0 +1,33 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'favor_param.g.dart'; + +@JsonSerializable() +class FavorParam extends Object { + @JsonKey(name: 'homeworkId') + String homeworkId; + + @JsonKey(name: 'studentId') + int studentId; + + @JsonKey(name: 'templateId') + int templateId; + + @JsonKey(name: 'questionNo') + String questionNo; + + @JsonKey(name: 'isFav') + bool isFav; + + FavorParam({ + required this.homeworkId, + required this.studentId, + required this.templateId, + required this.questionNo, + required this.isFav, + }); + + factory FavorParam.fromJson(Map srcJson) => _$FavorParamFromJson(srcJson); + + Map toJson() => _$FavorParamToJson(this); +} diff --git a/making_school_asignment_app/lib/common/job/marking_models/original_manuscript_handwriting_params.dart b/making_school_asignment_app/lib/common/job/marking_models/original_manuscript_handwriting_params.dart new file mode 100644 index 0000000..6dd4be2 --- /dev/null +++ b/making_school_asignment_app/lib/common/job/marking_models/original_manuscript_handwriting_params.dart @@ -0,0 +1,35 @@ +// 原稿笔迹参数 + +import 'package:json_annotation/json_annotation.dart'; + +part 'original_manuscript_handwriting_params.g.dart'; + +@JsonSerializable(checked: true, includeIfNull: false) +class OriginalManuscriptHandwritingParams extends Object { + @JsonKey(name: 'homeworkId') + String homeworkId; + + @JsonKey(name: 'studentId') + int studentId; + + @JsonKey(name: 'templateId') + int? templateId; + + @JsonKey(name: 'questionNo') + String? questionNo; + + @JsonKey(name: 'pageNum') + int? pageNum; + + OriginalManuscriptHandwritingParams({ + required this.homeworkId, + required this.studentId, + this.templateId, + this.pageNum, + this.questionNo, + }); + + factory OriginalManuscriptHandwritingParams.fromJson(Map srcJson) => _$OriginalManuscriptHandwritingParamsFromJson(srcJson); + + Map toJson() => _$OriginalManuscriptHandwritingParamsToJson(this); +} diff --git a/making_school_asignment_app/lib/common/job/marking_models/review_submission_params.dart b/making_school_asignment_app/lib/common/job/marking_models/review_submission_params.dart new file mode 100644 index 0000000..97dd4fc --- /dev/null +++ b/making_school_asignment_app/lib/common/job/marking_models/review_submission_params.dart @@ -0,0 +1,55 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'review_submission_params.g.dart'; + +@JsonSerializable(includeIfNull: false) +class ReviewSubmissionParams extends Object { + @JsonKey(name: 'homeworkId') + String homeworkId; + + @JsonKey(name: 'templateId') + int templateId; + + @JsonKey(name: 'studentId') + int studentId; + + @JsonKey(name: 'studentScores') + List studentScores; + + @JsonKey(name: 'zgtAnnotate') + String? zgtAnnotate; + + ReviewSubmissionParams({ + required this.homeworkId, + required this.templateId, + required this.studentId, + required this.studentScores, + this.zgtAnnotate, + }); + + factory ReviewSubmissionParams.fromJson(Map srcJson) => _$ReviewSubmissionParamsFromJson(srcJson); + + Map toJson() => _$ReviewSubmissionParamsToJson(this); +} + +@JsonSerializable() +class StudentScores extends Object { + @JsonKey(name: 'questionNo') + String questionNo; + + @JsonKey(name: 'studentScore') + int studentScore; + + @JsonKey(name: 'isCorrect') + bool isCorrect; + + StudentScores({ + required this.questionNo, + required this.studentScore, + required this.isCorrect, + }); + + factory StudentScores.fromJson(Map srcJson) => _$StudentScoresFromJson(srcJson); + + Map toJson() => _$StudentScoresToJson(this); +} diff --git a/lib/common/job/student_history.dart b/making_school_asignment_app/lib/common/job/student_history.dart similarity index 98% rename from lib/common/job/student_history.dart rename to making_school_asignment_app/lib/common/job/student_history.dart index d13941c..6285f69 100644 --- a/lib/common/job/student_history.dart +++ b/making_school_asignment_app/lib/common/job/student_history.dart @@ -105,7 +105,7 @@ class KgtList extends Object { String id; @JsonKey(name: 'questionNo') - int questionNo; + String questionNo; @JsonKey(name: 'questionType') int questionType; @@ -135,7 +135,7 @@ class ZgtList extends Object { String id; @JsonKey(name: 'questionNo') - int questionNo; + String questionNo; @JsonKey(name: 'questionType') int questionType; diff --git a/lib/common/job/student_history_params.dart b/making_school_asignment_app/lib/common/job/student_history_params.dart similarity index 100% rename from lib/common/job/student_history_params.dart rename to making_school_asignment_app/lib/common/job/student_history_params.dart diff --git a/lib/common/job/student_item.dart b/making_school_asignment_app/lib/common/job/student_item.dart similarity index 100% rename from lib/common/job/student_item.dart rename to making_school_asignment_app/lib/common/job/student_item.dart diff --git a/lib/common/job/student_personal_info.dart b/making_school_asignment_app/lib/common/job/student_personal_info.dart similarity index 98% rename from lib/common/job/student_personal_info.dart rename to making_school_asignment_app/lib/common/job/student_personal_info.dart index 4009ff9..5a77607 100644 --- a/lib/common/job/student_personal_info.dart +++ b/making_school_asignment_app/lib/common/job/student_personal_info.dart @@ -43,7 +43,7 @@ class KgtList extends Object { int templateId; @JsonKey(name: 'questionNo') - int questionNo; + String questionNo; @JsonKey(name: 'answer') String? answer; @@ -76,7 +76,7 @@ class ZgtList extends Object { int templateId; @JsonKey(name: 'questionNo') - int questionNo; + String questionNo; @JsonKey(name: 'answer') String? answer; diff --git a/lib/common/job/user_info.dart b/making_school_asignment_app/lib/common/job/user_info.dart similarity index 100% rename from lib/common/job/user_info.dart rename to making_school_asignment_app/lib/common/job/user_info.dart diff --git a/lib/common/job/user_info_detail.dart b/making_school_asignment_app/lib/common/job/user_info_detail.dart similarity index 100% rename from lib/common/job/user_info_detail.dart rename to making_school_asignment_app/lib/common/job/user_info_detail.dart diff --git a/lib/common/job/user_login.dart b/making_school_asignment_app/lib/common/job/user_login.dart similarity index 100% rename from lib/common/job/user_login.dart rename to making_school_asignment_app/lib/common/job/user_login.dart diff --git a/making_school_asignment_app/lib/common/job/user_register_params.dart b/making_school_asignment_app/lib/common/job/user_register_params.dart new file mode 100644 index 0000000..f3cc543 --- /dev/null +++ b/making_school_asignment_app/lib/common/job/user_register_params.dart @@ -0,0 +1,21 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'user_register_params.g.dart'; + +@JsonSerializable() +class UserRegisterParams extends Object { + @JsonKey(name: 'account') + String account; + + @JsonKey(name: 'password') + String password; + + UserRegisterParams({ + required this.account, + required this.password, + }); + + factory UserRegisterParams.fromJson(Map srcJson) => _$UserRegisterParamsFromJson(srcJson); + + Map toJson() => _$UserRegisterParamsToJson(this); +} diff --git a/lib/common/job/work_student.dart b/making_school_asignment_app/lib/common/job/work_student.dart similarity index 100% rename from lib/common/job/work_student.dart rename to making_school_asignment_app/lib/common/job/work_student.dart diff --git a/lib/common/job/work_student_params.dart b/making_school_asignment_app/lib/common/job/work_student_params.dart similarity index 100% rename from lib/common/job/work_student_params.dart rename to making_school_asignment_app/lib/common/job/work_student_params.dart diff --git a/making_school_asignment_app/lib/common/mixins/event_bus_mixin.dart b/making_school_asignment_app/lib/common/mixins/event_bus_mixin.dart new file mode 100644 index 0000000..9aeb50e --- /dev/null +++ b/making_school_asignment_app/lib/common/mixins/event_bus_mixin.dart @@ -0,0 +1,33 @@ +// event_bus 混入类 +import 'dart:async'; + +import 'package:event_bus/event_bus.dart'; +import 'package:making_school_asignment_app/common/utils/event_bus_utils.dart'; + +mixin EventBusMixin { + late final StreamSubscription? _subscription; + static final EventBusUtils _exampleUtil = EventBusUtils(); + static final EventBus _eBus = _exampleUtil.getEventBus(); + + /* + * 发起事件总线监听 + * @param {Function} callback 回调函数 + */ + /// 发起事件总线监听 @param {Function} callback 回调函数 + StreamSubscription eventOn({required void Function(T) callback}) { + _subscription = _eBus.on().listen(callback); + return _subscription!; + } + + // 触发事件总线 + void eventFire({required T model}) { + _exampleUtil.toFire(model); + } + + // 关闭监听总线事件 + void eventCancel() { + try{ + _subscription?.cancel(); + }catch(_){} + } +} diff --git a/making_school_asignment_app/lib/common/mixins/request_tool_mixin.dart b/making_school_asignment_app/lib/common/mixins/request_tool_mixin.dart new file mode 100644 index 0000000..b1a27a9 --- /dev/null +++ b/making_school_asignment_app/lib/common/mixins/request_tool_mixin.dart @@ -0,0 +1,10 @@ +import 'package:dio/dio.dart'; +import 'package:making_school_asignment_app/common/request/rest_dio.dart'; +import 'package:making_school_asignment_app/common/api/retrofit_client.dart'; + +mixin RequestToolMixin { + // 获取DIO + Dio getClientDio() => RequestTool.instance.getDio(); + // 获取Client + RetrofitClient getClient() => RequestTool.instance.getClient(); +} diff --git a/lib/common/request/rest_dio.dart b/making_school_asignment_app/lib/common/request/rest_dio.dart similarity index 69% rename from lib/common/request/rest_dio.dart rename to making_school_asignment_app/lib/common/request/rest_dio.dart index 36fcb60..c057fd4 100644 --- a/lib/common/request/rest_dio.dart +++ b/making_school_asignment_app/lib/common/request/rest_dio.dart @@ -2,15 +2,20 @@ import 'dart:convert'; import 'dart:io'; import 'package:get/get.dart' as getx; import 'package:dio/dio.dart'; -import 'package:package_info/package_info.dart'; -import 'package:school_asignment_app/common/api/retrofit_client.dart'; -import 'package:school_asignment_app/common/config/request_config.dart'; -import 'package:school_asignment_app/common/job/user_info.dart'; -import 'package:school_asignment_app/common/store/user_store.dart'; -import 'package:school_asignment_app/common/utils/toast_utils.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:making_school_asignment_app/common/api/retrofit_client.dart'; +import 'package:making_school_asignment_app/common/config/request_config.dart'; +import 'package:making_school_asignment_app/common/job/user_info.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import '../job/user_info_detail.dart'; +import '../utils/storage.dart'; class RequestTool { + static late Dio _dio; // 初始化请求配置 static _init() { BaseOptions options = BaseOptions( @@ -18,17 +23,18 @@ class RequestTool { connectTimeout: const Duration(milliseconds: RequestConfig.connectTimeout), receiveTimeout: const Duration(milliseconds: RequestConfig.receiveTimeout), ); - Dio dio = Dio(options); - dio.interceptors.add(AuthInterceptor()); // 添加 token - dio.interceptors.add(ResponseHandle()); // 添加 数据返回拦截 - dio.interceptors.add(TheError()); // 添加 数据返回拦截 + _dio = Dio(options); + _dio.interceptors.add(AuthInterceptor()); // 添加 token + _dio.interceptors.add(ResponseHandle()); // 添加 数据返回拦截 + _dio.interceptors.add(TheError()); // 添加 数据返回拦截 const isProd = bool.fromEnvironment('dart.vm.product'); if (!isProd && RequestConfig.requestDataPrinting) { - dio.interceptors.add(LogInterceptor(responseBody: true, requestBody: true)); //添加日志 + _dio.interceptors.add(LogInterceptor(responseBody: true, requestBody: true)); //添加日志 } - return RetrofitClient(dio, baseUrl: RequestConfig().baseUrl); + return RetrofitClient(_dio, baseUrl: RequestConfig().baseUrl); } + final RetrofitClient _client; static RequestTool? _instance; @@ -42,6 +48,9 @@ class RequestTool { return _instance!; } + // DIO + Dio getDio() => _dio; + RetrofitClient getClient() => _client; } @@ -90,9 +99,9 @@ class AuthInterceptor extends Interceptor { headers["x-Authorization"] = xToken!; } - if ((userInfo?.isExpired() ?? false) && userInfo?.termYear != '') { + /* if ((userInfo?.isExpired() ?? false) && userInfo?.termYear != '') { headers["term-year"] = userInfo!.termYear; - } + }*/ options.headers = headers; return super.onRequest(options, handler); @@ -106,6 +115,10 @@ class AuthInterceptor extends Interceptor { class ResponseHandle extends Interceptor { @override void onResponse(Response response, ResponseInterceptorHandler handler) { + const isProd = bool.fromEnvironment('dart.vm.product'); + if (!isProd && RequestConfig.requestDataPrinting) { + toPrint(val: response.data, toPrintJson: true); + } if (RequestConfig.successCode.contains(response.statusCode)) { // String? token = response.headers.value('access-token'); @@ -125,11 +138,10 @@ class ResponseHandle extends Interceptor { } class TheError extends Interceptor { + late getx.Rx userInfo = UserStore.to.userDetailInfo; + @override void onError(DioException error, ErrorInterceptorHandler handler) { - print('----------------'); - print(error); - print('*************'); var message = '请求错误,请重试'; switch (error.type) { case DioExceptionType.connectionTimeout: @@ -142,7 +154,7 @@ class TheError extends Interceptor { message = '请求发送超时'; break; case DioExceptionType.receiveTimeout: - message = '接收超时时发生'; + message = '接收超时'; break; case DioExceptionType.badResponse: if (error.response == null) { @@ -153,6 +165,16 @@ class TheError extends Interceptor { int? statusCode = response.statusCode; var errorMap = response.data; + + if (errorMap is String && errorMap.length > 0) { + try { + var errorModel = jsonDecode(errorMap); + var error = errorModel['error']; + if (error != null && error["message"] != null) { + message = error["message"]; + } + } catch (e) {} + } // var runtimeType = errorMap.runtimeType; if (errorMap is Map && errorMap['error'] != null) { message = errorMap['error']?['message'] ?? '请求错误,请重试'; @@ -161,7 +183,14 @@ class TheError extends Interceptor { switch (statusCode) { case 401: message = '用户登录失效,请重新登录'; - Future.delayed(const Duration(seconds: 2), () => getx.Get.offAllNamed(Routes.login)); + + Future.delayed(const Duration(seconds: 2), () { + if (getx.Get.currentRoute != Routes.login) { + UserStore.to.erase(); + StorageService.to.erase(); + getx.Get.offAllNamed(Routes.login); + } + }); break; case 404: // message = '用户登录失效,请重新登录'; @@ -183,7 +212,10 @@ class TheError extends Interceptor { default: message = '请求错误'; } - ToastUtils.showError(message); + if (message == '用户登录失效,请重新登录' && userInfo.value?.id == null) { + return handler.next(error); + } + Future.delayed(const Duration(milliseconds: 600), () => ToastUtils.showError(message)); return handler.next(error); } } diff --git a/lib/common/store/app_storage_key.dart b/making_school_asignment_app/lib/common/store/app_storage_key.dart similarity index 74% rename from lib/common/store/app_storage_key.dart rename to making_school_asignment_app/lib/common/store/app_storage_key.dart index b9029b3..97347e9 100644 --- a/lib/common/store/app_storage_key.dart +++ b/making_school_asignment_app/lib/common/store/app_storage_key.dart @@ -5,7 +5,10 @@ enum AppStorageKey { xToken(value: 'XTOKEN', label: "登录用户的Xtoken,刷新token信息"), userMobile(value: 'USERMOBILE', label: "用户输入过的手机号码"), userInfo(value: 'USERINFO', label: "登录用户的基本信息 及 token过期时间"), - userDetailInfo(value: 'USERDETAILINFO', label: "用户的详细信息"); + userDetailInfo(value: 'USERDETAILINFO', label: "用户的详细信息"), + account(value: 'ACCOUNT', label: "用户名"), + pwd(value: 'PWD', label: "密码"), + privacyAgreement(value: 'PRIVACYAGREEMENT', label: "用户同意隐私协议"); final String label; final String value; diff --git a/lib/common/store/user_store.dart b/making_school_asignment_app/lib/common/store/user_store.dart similarity index 80% rename from lib/common/store/user_store.dart rename to making_school_asignment_app/lib/common/store/user_store.dart index 451d009..b9cf327 100644 --- a/lib/common/store/user_store.dart +++ b/making_school_asignment_app/lib/common/store/user_store.dart @@ -1,13 +1,13 @@ import 'dart:convert'; import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/enum_subject.dart'; -import 'package:school_asignment_app/common/job/user_info.dart'; -import 'package:school_asignment_app/common/job/user_info_detail.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:school_asignment_app/common/utils/storage.dart'; -import 'package:school_asignment_app/common/store/app_storage_key.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/job/enum_subject.dart'; +import 'package:making_school_asignment_app/common/job/user_info.dart'; +import 'package:making_school_asignment_app/common/job/user_info_detail.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/storage.dart'; +import 'package:making_school_asignment_app/common/store/app_storage_key.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; class UserStore extends GetxController with RequestToolMixin { static UserStore get to => Get.find(); @@ -28,8 +28,6 @@ class UserStore extends GetxController with RequestToolMixin { //年级 RxList gradeList = RxList(); - RxInt readOver = 0.obs; - UserStore init() { token = StorageService.to.read(AppStorageKey.token.value); xToken = StorageService.to.read(AppStorageKey.xToken.value); @@ -45,11 +43,11 @@ class UserStore extends GetxController with RequestToolMixin { } var _userDetail = StorageService.to.read(AppStorageKey.userDetailInfo.value); if (_userDetail != null) { - print(_userDetail); + // print(_userDetail); userDetailInfo.value = UserInfoDetail.fromJson(_userDetail); } } catch (err) { - print('LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL${err}'); + // print('LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL${err}'); StorageService.to.remove(AppStorageKey.userInfo.value); StorageService.to.remove(AppStorageKey.userDetailInfo.value); } @@ -61,8 +59,8 @@ class UserStore extends GetxController with RequestToolMixin { return this; } - void getEnum() async{ - await getGradeList(); + void getEnum() async { + await getGradeList(); } /// 保存 token @@ -99,18 +97,15 @@ class UserStore extends GetxController with RequestToolMixin { //获取科目 getSubjectList() async { // var res = await getClient().getEnumSubjectList(); - } //获取年级 getGradeList() async { - - var res = await getClient().getEnumSubjectList(['EnumGrade','EnumSubject']); + var res = await getClient().getEnumSubjectList(['EnumGrade', 'EnumSubject']); gradeList.value = res['EnumGrade']!; subjectList.value = res['EnumSubject']!; } - // 用户信息更新 updateUserInfo() async { UserInfo? userInfo = UserStore.to.userInfo.value; diff --git a/lib/common/the_global.dart b/making_school_asignment_app/lib/common/the_global.dart similarity index 100% rename from lib/common/the_global.dart rename to making_school_asignment_app/lib/common/the_global.dart diff --git a/making_school_asignment_app/lib/common/utils/anti_shake_throttling.dart b/making_school_asignment_app/lib/common/utils/anti_shake_throttling.dart new file mode 100644 index 0000000..142b4e9 --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/anti_shake_throttling.dart @@ -0,0 +1,52 @@ +// debounce.dart + +import 'dart:async'; + +import 'package:easy_debounce/easy_throttle.dart'; +import 'package:flutter/material.dart'; + +/// 函数防抖 +/// +/// [func]: 要执行的方法 +/// [delay]: 要迟延的时长 +VoidCallback debounce(Function func, [Duration delay = const Duration(milliseconds: 2000)]) { + Timer? timer; + target() { + timer?.cancel(); + timer = Timer(delay, () { + func.call(); + }); + } + + return target; +} + +/// 函数节流 +/// +/// [func]: 要执行的方法 +VoidCallback throttle(Future Function() func) { + bool enable = true; + target() { + if (enable == true) { + enable = false; + func().whenComplete(() { + enable = true; + }); + } + } + + return target; +} + +/// 函数节流 +/// +/// [func]: 要执行的方法 +bool easyThrottle(String tagId, EasyThrottleCallback onExecute, + {Duration duration = const Duration(milliseconds: 300), EasyThrottleCallback? onAfter}) { + return EasyThrottle.throttle( + tagId, // <-- An ID for this particular throttler + duration, // <-- The throttle duration + onExecute, // <-- The target method + onAfter: onAfter // <-- Optional callback, called after the duration has passed + ); +} diff --git a/making_school_asignment_app/lib/common/utils/app_upgrade/DownloadApk.dart b/making_school_asignment_app/lib/common/utils/app_upgrade/DownloadApk.dart new file mode 100644 index 0000000..1b472af --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/app_upgrade/DownloadApk.dart @@ -0,0 +1,159 @@ +/* + * @Descripttion: 下载APK + * @version: DownloadApk + * @Author: wy + * @Date: 2020-07-30 15:54:40 + * @LastEditors: wangyang 1147192855@qq.com + * @LastEditTime: 2022-08-02 15:12:21 + */ +import 'dart:io'; + +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:app_installer/app_installer.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import 'UpgradePermission.dart'; +import 'model/UpdateAppEvent.dart'; +import 'upgradeLogic.dart'; + +class DownloadApk { + /// 下载安卓更新包 + static Future _downloadAndroid( + context, UpdateAppEvent event, UpgradeLogic logic) async { + /// 创建存储文件 + Directory? storageDir = await getExternalStorageDirectory(); + final storagePath = storageDir?.path ?? '/'; + String version = event.version.replaceAll(".", "-"); + File file = new File('$storagePath/${event.appName}v$version.apk'); + if (await file.exists()) await file.delete(); + if (!file.existsSync()) file.createSync(); + try { + /// 发起下载请求 + Response response = await Dio().get( + event.link, + onReceiveProgress: (num received, num total) { + showDownloadProgress(context, received, total, logic); + }, + options: Options( + responseType: ResponseType.bytes, + followRedirects: false, + ), + ); + file.writeAsBytesSync(response.data); + return file; + } catch (e) { + print(e); + // toPrint(val: e); + } + return null; + } + + // 安装apk + static Future installApk( + context, UpdateAppEvent event, UpgradeLogic logic) async { + try { + logic.loadingApk.value = true; + File? _apkFile = await _downloadAndroid(context, event, logic); + if (_apkFile == null) return false; + String _apkFilePath = _apkFile.path; + if (_apkFilePath.isEmpty) { + debugPrint('make sure the apk file is set'); + return false; + } + + await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text("未知应用安装权限提示", + style: TextStyle( + fontWeight: FontWeight.bold, + )), + content: const Text("请注意:更新时若出现需要同意“安装未知应用权限”,请同意!!!"), + actions: [ + MaterialButton( + color: Theme.of(context).primaryColor, + child: const Text("我已知晓", + style: TextStyle( + color: Colors.white, fontWeight: FontWeight.bold)), + onPressed: () => Navigator.of(context).pop(), + ), + ], + ); + }, + ); + await AppInstaller.installApk(_apkFilePath); // 安装APK + // 如果2秒还没有进入安装引导页面 一律视为更新失败,弹出其他方式更新 + Utils.getInstance().setTimeOut(1, () async { + try { + // 其他方式下载 + // await SystemNavigator.pop(); // 退出APP + var options = ['应用市场更新APP', '浏览器下载并安装APP']; + var uri = + Uri.parse('market://details?id=${event.packageName}'); // 应用市场URI + if (!await canLaunchUrl(uri)) + options.removeAt(0); // 如果不能打开应用市场 就屏蔽掉 这个安装方式 + String? option = await UpgradePermission.showCustomModalBottomSheet( + context, options); + if (option == '应用市场更新APP') await launchUrl(uri); + if (option == '浏览器下载并安装APP') await launchUrl(Uri.parse(event.link)); + } catch (_) {} + }); + + print('安装执行完成了..............0.0'); + } catch (e) { + print('安装进入报错....'); + print(e); + } finally { + logic.loadingApk.value = false; + } + + return false; + } + + /// 展示下载进度 + static void showDownloadProgress( + context, num received, num total, UpgradeLogic logic) { + if (total != -1) { + double progress = double.parse((received / total).toStringAsFixed(2)); + // debugPrint('下载进度$progress'); + logic.downloadRatio.value = progress; + } + } +} + +class RestartWidget extends StatefulWidget { + final Widget child; + + const RestartWidget({super.key, required this.child}); + + static restartApp(BuildContext context) { + final _RestartWidgetState? state = + context.findAncestorStateOfType<_RestartWidgetState>(); + state?.restartApp(); + } + + @override + State createState() => _RestartWidgetState(); +} + +class _RestartWidgetState extends State { + Key key = UniqueKey(); + + void restartApp() { + setState(() { + key = UniqueKey(); + }); + } + + @override + Widget build(BuildContext context) { + return KeyedSubtree( + key: key, + child: widget.child, + ); + } +} diff --git a/making_school_asignment_app/lib/common/utils/app_upgrade/UpdateDialog.dart b/making_school_asignment_app/lib/common/utils/app_upgrade/UpdateDialog.dart new file mode 100644 index 0000000..8b60c11 --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/app_upgrade/UpdateDialog.dart @@ -0,0 +1,223 @@ +/* + * @Author: wangyang 1147192855@qq.com + * @Date: + * @LastEditors: wangyang 1147192855@qq.com + * @LastEditTime: 2022-09-29 10:11:54 + * @FilePath: \marking_app\lib\utils\app_upgrade\UpdateDialog.dart + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/* + * @Descripttion: 版本更新提示弹窗 + * @version: + * @Author: wy + * @Date: 2020-07-30 14:03:28 + * @LastEditors: Please set LastEditors + * @LastEditTime: 2021-01-12 15:08:43 + */ +import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/utils/app_upgrade/DownloadApk.dart'; +import 'package:making_school_asignment_app/common/utils/app_upgrade/UpgradePermission.dart'; +import 'package:making_school_asignment_app/common/utils/app_upgrade/upgradeLogic.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:percent_indicator/linear_percent_indicator.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:url_launcher/url_launcher_string.dart'; + +import '../anti_shake_throttling.dart'; +import 'model/UpdateAppEvent.dart'; + +class UpdateDialog extends Dialog { + final UpdateAppEvent updateAppEvent; + final String deviceInfo; + + const UpdateDialog({super.key, required this.updateAppEvent, required this.deviceInfo}); + + @override + Widget build(BuildContext context) { + return Center( + child: Container( + width: isPad() ? ScreenUtil().screenWidth * 0.62 : 319.w, + height: 440.h, + padding: EdgeInsets.symmetric(vertical: 8.h), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(18.sp), + image: const DecorationImage( + alignment: Alignment.topCenter, + image: AssetImage("assets/images/upgrade_dialog_bgc.png"), + fit: BoxFit.fitWidth, + ), + ), + child: Column( + children: [ + Expanded( + child: ListView( + physics: const BouncingScrollPhysics(), + padding: EdgeInsets.fromLTRB(16.w, 0, 16.w, 0), + children: [ + Container( + alignment: Alignment.center, + margin: EdgeInsets.only(top:isPad()? 136.h : 128.h, bottom: 10.h), + child: quickText( + updateAppEvent.title, + size: 18.sp, + fontWeight: FontWeight.w600, + color: const Color.fromRGBO(58, 90, 159, 1), + ), + ), + HtmlWidget( + updateAppEvent.description, + customStylesBuilder: (element) { + return {'color': '#666666', 'font-weight': 'normal', 'text-decoration': 'none'}; + }, + onLoadingBuilder: (context, element, loadingProgress) => const CircularProgressIndicator(), + renderMode: RenderMode.column, + textStyle: TextStyle(fontSize: 14.sp, color: Colors.black87), + ) + ], + ), + ), + DownloadProgress(), + DownloadButton(updateAppEvent, deviceInfo: deviceInfo), + ], + ), + ), + ); + } + + // 调起 + static showUpdateDialog(BuildContext context, UpdateAppEvent updateAppEvent) { + return showDialog( + barrierDismissible: false, + context: context, + builder: (BuildContext context) { + return WillPopScope( + onWillPop: () async => false, + child: UpdateDialog(updateAppEvent: updateAppEvent, deviceInfo: updateAppEvent.deviceInfo), + ); + }, + ); + } +} + +// 进度条 +class DownloadProgress extends StatelessWidget { + DownloadProgress({super.key}); + final logic = Get.find(); + + @override + Widget build(BuildContext context) { + return Obx(() { + var str = (logic.downloadRatio.value * 100).toString().split('.')[0]; + if (logic.downloadRatio.value <= 0) return Container(); + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + LinearPercentIndicator( + alignment: MainAxisAlignment.center, + width: isPad() ? ScreenUtil().screenWidth * 0.55 : 245.w, + animation: false, + lineHeight: 20.0.h, + percent: logic.downloadRatio.value, + center: quickText( + "$str%", + size: 14.sp, + align: TextAlign.center, + color: Colors.white, + ), + linearStrokeCap: LinearStrokeCap.roundAll, + progressColor: Theme.of(context).primaryColor, + ), + Container( + height: 6.h, + ), + quickText('更新中...', size: 12.sp, fontWeight: FontWeight.w500, color: const Color.fromRGBO(90, 90, 90, 1)) + ], + ); + }); + } +} + +// 点击下载按钮 +class DownloadButton extends StatelessWidget { + final UpdateAppEvent updateAppEvent; + final String deviceInfo; + DownloadButton(this.updateAppEvent, {required this.deviceInfo, super.key}); + final logic = Get.find(); + + // 打开浏览器或者对应的对应市场进行下载 + Future toLaunch(UpdateAppEvent data) async { + var uri = Uri.parse('market://details?id=${updateAppEvent.packageName}'); + if (await canLaunchUrl(uri)) { + // 跳进对应的应用市场进行更新操作 + return await launchUrl(uri); + } + // 无法进入应用市场就打开浏览器进行下载 + uri = Uri.parse(data.link); + if (await canLaunchUrl(uri)) return await launchUrl(uri); + return false; + } + + @override + Widget build(BuildContext context) { + return Obx(() { + final count = logic.downloadRatio.value; + if (count > 0) return Container(); + var primaryColor = Theme.of(context).primaryColor; + + if (updateAppEvent.equipment == Equipment.windows) { + return SizedBox( + child: quickText('若没有弹出更新弹框,可关闭APP重新打开执行更新...', size: 16.sp), + ); + } + + return Container( + height: 38.h, + width: isPad() ? ScreenUtil().screenWidth * 0.45 : 245.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(42.h)), + gradient: LinearGradient(colors: [primaryColor, primaryColor.withOpacity(0.7)]), + ), + child: MaterialButton( + onPressed: () => easyThrottle('DownloadButton_App_Upgrade', duration: const Duration(milliseconds: 1000), () async { + if (deviceInfo == "android" && updateAppEvent.equipment == Equipment.android) { + // 权限检查 判断是否有读写内存的权限 + bool flag = await UpgradePermission(updateAppEvent.deviceInfo).checkPermission(context, updateAppEvent); + if (flag) { + flag = await DownloadApk.installApk(context, updateAppEvent, logic); + if (!flag) { + print('执行到了重置更新按钮的地方....'); + logic.downloadRatio.value = 0.0; // 更新失败重置 更新按钮 + } else { + print('更新成功重新打开APP..............'); + RestartWidget.restartApp(context); // 安装成功 重启APP + } + return; + } + // await FlutterClipboard.copy(updateAppEvent.link); + // setTimeOut(1000, () => ToastUtils.showInfo('下载链接已经复制到设备,可前往浏览器下载安装')); + } else if (deviceInfo == "ios" && updateAppEvent.equipment == Equipment.ios) { + try { + print(updateAppEvent.link); + await launchUrlString(updateAppEvent.link); + } catch (e) { + print('进来更新报错$e'); + } + } + // else if (deviceInfo == 'windows' && updateAppEvent.equipment == Equipment.windows) { + // await autoUpdater.setFeedURL(updateAppEvent.link); + // await autoUpdater.checkForUpdates(); + // await autoUpdater.setScheduledCheckInterval(0); + // } + }), + child: quickText(!logic.loadingApk.value ? '立即体验' : '正在下载...', size: 16.sp, color: Colors.white, fontWeight: FontWeight.w500), + ), + ); + }); + } +} diff --git a/making_school_asignment_app/lib/common/utils/app_upgrade/UpgradePermission.dart b/making_school_asignment_app/lib/common/utils/app_upgrade/UpgradePermission.dart new file mode 100644 index 0000000..eb95444 --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/app_upgrade/UpgradePermission.dart @@ -0,0 +1,143 @@ +/* + * @Descripttion: 获取本地权限 + * @version: UpgradePermission + * @Author: wy + * @Date: 2020-07-30 15:41:39 + * @LastEditors: wangyang 1147192855@qq.com + * @LastEditTime: 2022-08-01 14:08:57 + */ +import 'package:app_installer/app_installer.dart'; +import 'package:flutter/material.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import 'model/UpdateAppEvent.dart'; + +class UpgradePermission { + final String _flatform; + const UpgradePermission(this._flatform); + + /// 检查是否有权限,用于安卓 + /// noExecutions 执行次数 + Future checkPermission(BuildContext context, UpdateAppEvent updateAppEvent, [int? noExecutions]) async { + noExecutions ??= 1; + if (_flatform != 'android') return true; // 非安卓 + var status = await Permission.storage.request(); + if (status.isGranted) return true; + + if (status.isDenied) { + // 普通拒绝 可以再进行提示 + + await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: const Text("权限提示"), + content: const Text("无法获取存储权限,请同意获取设备存储权限"), + actions: [ + MaterialButton( + color: Theme.of(context).primaryColor, + child: const Text("同意", style: TextStyle(color: Colors.white)), + onPressed: () => Navigator.of(context).pop(), + ), + ], + ); + }, + ); + + if (noExecutions < 2) return checkPermission(context, updateAppEvent, ++noExecutions); + // 执行次数大于2次,就不再询问直接打开设置权限页面(防止某些机型不会弹起权限询问交互弹框) + } + + // 拒绝并不再提示 + bool? res = await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: const Text("权限提示"), + content: const Text("储存权限被永久拒绝,并且不再提示。请前往设置页面同意储存权限"), + actions: [ + MaterialButton( + color: Colors.green.shade900, + child: const Text("其它方式更新", style: TextStyle(color: Colors.white)), + onPressed: () => Navigator.of(context).pop(false), + ), + MaterialButton( + color: Theme.of(context).primaryColor, + child: const Text("前往设置", style: TextStyle(color: Colors.white)), + onPressed: () => Navigator.of(context).pop(true), + ), + ], + ); + }, + ); + if (res == null || !res) { + // 其他方式下载 + // await SystemNavigator.pop(); // 退出APP + var options = ['应用市场更新APP', '浏览器下载并安装APP']; + var uri = Uri.parse('market://details?id=${updateAppEvent.packageName}'); // 应用市场URI + // if (!await canLaunchUrl(uri)) options.removeAt(0); // 如果不能打开应用市场 就屏蔽掉 这个安装方式 + String? option = await showCustomModalBottomSheet(context, options); + if (option == '应用市场更新APP') { + if (await canLaunchUrl(uri)) { + await launchUrl(uri); + } else { + await AppInstaller.goStore(updateAppEvent.packageName, 'iOSAppId'); + } + } + if (option == '浏览器下载并安装APP') await launchUrl(Uri.parse(updateAppEvent.link)); + } else + await openAppSettings(); + return false; + } + + // 其他方式下载选择 + static Future showCustomModalBottomSheet(context, List options) async { + return showModalBottomSheet( + backgroundColor: Colors.transparent, + isScrollControlled: true, + context: context, + builder: (BuildContext context) { + return Container( + clipBehavior: Clip.antiAlias, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: const Radius.circular(20.0), + topRight: const Radius.circular(20.0), + ), + ), + height: MediaQuery.of(context).size.height / 4.0, + child: Column(children: [ + SizedBox( + height: 50, + child: Stack( + textDirection: TextDirection.rtl, + children: [ + Center(child: Text('选择其它方式更新APP', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0))), + IconButton(icon: Icon(Icons.close), onPressed: () => Navigator.of(context).pop()), + ], + ), + ), + Divider(height: 1.0), + Expanded( + child: ListView.builder( + itemCount: options.length, + itemBuilder: (BuildContext context, int index) { + var name = options[index]; + return ListTile( + title: Text(name), + trailing: Icon(name.contains('浏览器') ? Icons.browser_updated_outlined : Icons.local_grocery_store_outlined), + onTap: () => Navigator.of(context).pop(name), + ); + }, + ), + ), + ]), + ); + }, + ); + } +} diff --git a/making_school_asignment_app/lib/common/utils/app_upgrade/model/UpdateAppEvent.dart b/making_school_asignment_app/lib/common/utils/app_upgrade/model/UpdateAppEvent.dart new file mode 100644 index 0000000..da3fbf3 --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/app_upgrade/model/UpdateAppEvent.dart @@ -0,0 +1,83 @@ +/* + * @Descripttion: + * @version: + * @Author: wy + * @Date: 2020-07-30 14:10:44 + * @LastEditors: wangyang 1147192855@qq.com + * @LastEditTime: 2022-09-28 18:20:11 + */ + +class UpdateAppEvent { + final String version; + final String title; + final String description; + final String link; + final bool upgrade; + final String deviceInfo; + final String appName; + final String packageName; + final Equipment equipment; + num? v; + num? lv; + + UpdateAppEvent({ + required this.version, + required this.title, + required this.description, + required this.link, + required this.upgrade, + required this.deviceInfo, + required this.appName, + required this.packageName, + this.v, + this.lv, + int type = 0, + }) : equipment = Equipment.values[type]; + + factory UpdateAppEvent.fromJson(Map json, String localVersion, String deviceInfo, String appName, String packageName, + {String keyStr = "version", String typeName = "packageNameType"}) { + String version = json[keyStr]; // 版本号 + String? descriptionStr = json["description"]; + + String newDescription = '系统有更新,请立即下载'; + bool upgrade = false; + num? v; + num? lv; + // 版本号 + if (version != '') { + v = num.parse(version.replaceAll(".", "")); + lv = num.parse(localVersion.replaceAll(".", "")); + + // if (lv < v) upgrade = true; + //当前版本不等于线上版本更新为线上版本 + if (lv != v) upgrade = true; + } + + // 升级说明 + if (descriptionStr != null && descriptionStr.isNotEmpty) { + newDescription = descriptionStr; + } + + return UpdateAppEvent( + version: version, // 版本号 + title: json["title"] ?? "发现新版本", // title + description: newDescription, //说明 + link: json["downloadPath"]??'', // 链接地址 + upgrade: upgrade, + deviceInfo: deviceInfo, + appName: appName, + packageName: packageName, + type: json[typeName] ?? 0, + v: v, + lv: lv, + ); + } + + @override + String toString() { + return "UpdateAppEvent { version: $version, title: $title, description: $description, link: $link}"; + } +} + +// 设备枚举 +enum Equipment { other, android, ios, windows } diff --git a/making_school_asignment_app/lib/common/utils/app_upgrade/upgradeLogic.dart b/making_school_asignment_app/lib/common/utils/app_upgrade/upgradeLogic.dart new file mode 100644 index 0000000..34ab6aa --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/app_upgrade/upgradeLogic.dart @@ -0,0 +1,156 @@ +import 'dart:io'; +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter/widgets.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/app_version.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/common/utils/permission_describe_util.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:permission_handler/permission_handler.dart'; + +import 'UpdateDialog.dart'; +import 'model/UpdateAppEvent.dart'; + +class UpgradeLogic extends GetxController with RequestToolMixin { + Rx showUpgrade = false.obs; // 是否已经显示升级弹窗 + Rx loadingApk = false.obs; // 是否已经显示升级弹窗 + Rx downloadRatio = 0.0.obs; // 下载比例 + + // @override + // void onInit() { + + // super.onInit(); + // } + + Future getUpdateAppEvent() async { + // 获取设备信息 + String deviceInfo; + int deviceType; + if (Platform.isAndroid) { + deviceInfo = "android"; + deviceType = 1; + } else if (Platform.isIOS) { + deviceInfo = "ios"; + deviceType = 2; + } else if (Platform.isWindows) { + deviceInfo = "windows"; + deviceType = 3; + } else { + return null; + } + + AppVersion? result = await getClient().getLastAppVersion('making_school_asignment_app', deviceType); + if (result == null) return null; + + //获取当前版本 + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + //获取当前版本 + String localVersion = packageInfo.version; + String appName = packageInfo.appName; //应用名称 + String packageName = packageInfo.packageName; //包名称 + // String buildNumber = packageInfo.buildNumber; //小版本号 + + Map json = { + 'downloadPath': Platform.isWindows ? '' : result.appFileUrl, + 'version': result.version, + 'systemType': deviceType, + 'description': result.description ?? 'APP新版本更新', + }; + return UpdateAppEvent.fromJson(json, localVersion, deviceInfo, appName, packageName, typeName: 'systemType'); + } + + Future getAppUpgrade(BuildContext context) async { + if (!const bool.fromEnvironment('dart.vm.product')) return; + + try { + showUpgrade.value = true; + + final names = [ + UserStore.to.userDetailInfo.value?.name, + UserStore.to.userDetailInfo.value?.account, + ].whereType().where((name) => name.isNotEmpty).toList(); + if (names.contains('AppleTester')) return; + + UpdateAppEvent? updateAppEvent = await getUpdateAppEvent(); + if (updateAppEvent != null && updateAppEvent.upgrade) { + if (Platform.isAndroid) { + DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); + AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo; + Permission storagePermission; + if (androidInfo.version.sdkInt >= 33) { + storagePermission = Permission.manageExternalStorage; + } else { + storagePermission = Permission.storage; + } + await PermissionDescribeUtil.instance.toLaunchPermissionRequest( + Get.context ?? context, + title: '储存权限请求', + describe: "为了提供更好的服务,需要获取到存储权限用于保存APP升级文件APK,进行升级", + permissions: [storagePermission], + ); + } + + await UpdateDialog.showUpdateDialog( + Get.context ?? context, + updateAppEvent, + ); + } + /** + // 获取设备信息 + String deviceInfo; + int deviceType; + if (Platform.isAndroid) { + deviceInfo = "android"; + deviceType = 1; + } else if (Platform.isIOS) { + deviceInfo = "ios"; + deviceType = 2; + } else if (Platform.isWindows) { + deviceInfo = "windows"; + deviceType = 3; + } else { + return false; + } + + if (result != null) { + //获取当前版本 + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + //获取当前版本 + String localVersion = packageInfo.version; + String appName = packageInfo.appName; //应用名称 + String packageName = packageInfo.packageName; //包名称 + // String buildNumber = packageInfo.buildNumber; //小版本号 + + Map json = {'downloadPath': Platform.isWindows ? '' : result.appFileUrl, 'version': result.version, 'systemType': deviceType, 'description': result.description ?? 'APP新版本更新'}; + UpdateAppEvent updateAppEvent = UpdateAppEvent.fromJson(json, localVersion, deviceInfo, appName, packageName, typeName: 'systemType'); + if (updateAppEvent.upgrade) { + if (Platform.isAndroid) { + DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); + AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo; + Permission storagePermission; + if (androidInfo.version.sdkInt >= 33) { + storagePermission = Permission.manageExternalStorage; + } else { + storagePermission = Permission.storage; + } + await PermissionDescribeUtil.instance.toLaunchPermissionRequest( + Get.context ?? context, + title: '储存权限请求', + describe: "为了提供更好的服务,需要获取到存储权限用于保存APP升级文件APK,进行升级", + permissions: [storagePermission], + ); + } + + await UpdateDialog.showUpdateDialog( + Get.context ?? context, + updateAppEvent, + ); + } + } + */ + } finally { + showUpgrade.value = false; + } + } +} diff --git a/making_school_asignment_app/lib/common/utils/cached_network_img.dart b/making_school_asignment_app/lib/common/utils/cached_network_img.dart new file mode 100644 index 0000000..36616c0 --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/cached_network_img.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; + +part 'cached_network_img.g.dart'; + +@hwidget +Widget $theCachedNetworkImage(ImageWidgetBuilder imageBuilder, {required String imageUrl, double? imgWidth}) { + UseCachedImgRefresh useImgRefsh = UseCachedImgRefresh.use(); + + return CachedNetworkImage( + key: useImgRefsh.imageKey.value, + cacheKey: imageUrl, + fit: BoxFit.fitWidth, + width: imgWidth ?? double.infinity, + imageUrl: imageUrl, + imageBuilder: imageBuilder, + placeholder: (context, url) => Center(child: SpinKitWave(color: Theme.of(context).primaryColor, size: 50.r)), + errorListener: (e) { + // print('图片报错.............$e'); + }, + errorWidget: (context, url, error) { + return GestureDetector( + onTap: () => (useImgRefsh.imageKey.value = UniqueKey()), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset('assets/images/test_paper_loading_failed.png'), + quickText('加载失败,点击重试', color: const Color.fromRGBO(148, 163, 182, 1), size: 12.sp), + ], + ), + ); + }, + ); +} + +// CachedNetworkImage 重新加载图片 +class UseCachedImgRefresh { + ValueNotifier refreshNumber; + ValueNotifier imageKey; + + UseCachedImgRefresh._({required this.refreshNumber, required this.imageKey}); + + // 工厂构造函数 + factory UseCachedImgRefresh.use() { + return UseCachedImgRefresh._(refreshNumber: useState(0), imageKey: useState(UniqueKey())); + } +} diff --git a/lib/common/utils/enum_untils.dart b/making_school_asignment_app/lib/common/utils/enum_untils.dart similarity index 74% rename from lib/common/utils/enum_untils.dart rename to making_school_asignment_app/lib/common/utils/enum_untils.dart index ff01799..106832b 100644 --- a/lib/common/utils/enum_untils.dart +++ b/making_school_asignment_app/lib/common/utils/enum_untils.dart @@ -1,7 +1,7 @@ -import 'package:school_asignment_app/common/job/enum_subject.dart'; -import 'package:school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/common/job/enum_subject.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; -class EnumUtils{ +class EnumUtils { static String formatSubject(int id) { if (UserStore.to.subjectList.isEmpty || id == null) { return ''; @@ -17,4 +17,4 @@ class EnumUtils{ EnumSubject item = UserStore.to.gradeList.firstWhere((element) => element.id == id); return item.name ?? ''; } -} \ No newline at end of file +} diff --git a/making_school_asignment_app/lib/common/utils/event_bus_utils.dart b/making_school_asignment_app/lib/common/utils/event_bus_utils.dart new file mode 100644 index 0000000..b7451d1 --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/event_bus_utils.dart @@ -0,0 +1,26 @@ +import 'package:event_bus/event_bus.dart'; + +//订阅者回调签名 +typedef EventCallback = void Function(dynamic arg); + +///事件总线 +class EventBusUtils { + late final EventBus _eventBus; + + // 单例模式 + static final EventBusUtils _instance = EventBusUtils._internal(); + factory EventBusUtils() => _instance; + EventBusUtils._internal() { + _eventBus = EventBus(); + } + + // 获取实例 + EventBus getEventBus() { + return _eventBus; + } + + // 发起事件 + void toFire(T model) { + _eventBus.fire(model); + } +} diff --git a/making_school_asignment_app/lib/common/utils/my_time_util.dart b/making_school_asignment_app/lib/common/utils/my_time_util.dart new file mode 100644 index 0000000..237cfbd --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/my_time_util.dart @@ -0,0 +1,65 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'my_time_util.g.dart'; + +// 毫秒转小时、分钟、秒的函数 +TimeUnitModel? convertMilliseconds(int milliseconds) { + try { + int hours = milliseconds ~/ (1000 * 60 * 60); + int minutes = (milliseconds % (1000 * 60 * 60)) ~/ (1000 * 60); + int seconds = (milliseconds % (1000 * 60)) ~/ 1000; + + if ((milliseconds % 1000) > 500) seconds += 1; + + return TimeUnitModel(hours, minutes, seconds); + } catch (e) { + print('时间转换报错'); + } + return null; +} + +// 毫秒转小时、分钟、秒的函数 +TimeUnitModel? convertSeconds(int totalSeconds) { + try { + int hours = totalSeconds ~/ 3600; // 整除3600得到小时数 + int remainingSeconds = totalSeconds % 3600; // 取模3600得到剩余的秒数 + int minutes = remainingSeconds ~/ 60; // 整除60得到分钟数 + int seconds = remainingSeconds % 60; // 取模60得到最终的秒数 + + return TimeUnitModel(hours, minutes, seconds); + } catch (e) { + print('时间转换报错'); + } + return null; +} + +@JsonSerializable() +class TimeUnitModel extends Object { + int hours; + int minutes; + int seconds; + TimeUnitModel(this.hours, this.minutes, this.seconds); + + factory TimeUnitModel.fromJson(Map srcJson) => _$TimeUnitModelFromJson(srcJson); + + Map toJson() => _$TimeUnitModelToJson(this); + + @override + String toString() { + var timeStr = ''; + if (hours > 0) { + timeStr += '${hours > 9 ? hours : '0' + hours.toString()} '; + } + if (minutes > 0) { + timeStr += '${minutes > 9 ? minutes : '0' + minutes.toString()}'; + } + + if (timeStr.length > 0) { + timeStr += ':${seconds > 9 ? seconds : '0' + seconds.toString()}'; + } else { + timeStr += '00:${seconds > 9 ? seconds : '0' + seconds.toString()}'; + } + + return timeStr; + } +} diff --git a/making_school_asignment_app/lib/common/utils/permission_describe_util.dart b/making_school_asignment_app/lib/common/utils/permission_describe_util.dart new file mode 100644 index 0000000..4c90103 --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/permission_describe_util.dart @@ -0,0 +1,301 @@ +import 'dart:async'; + +import 'package:app_settings/app_settings.dart'; +import 'package:flutter/material.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:permission_handler/permission_handler.dart'; + +class PermissionDescribePage extends StatefulWidget { + final String title; + final String describe; + final List permissions; + + const PermissionDescribePage( + {required this.title, + required this.describe, + required this.permissions, + super.key}); + + @override + State createState() => _PermissionDescribePageState(); +} + +class _PermissionDescribePageState extends State + with WidgetsBindingObserver { + Timer? _timerPermission; + bool theOpenAppSettings = false; + int theExecutionFrequency = 0; + + @override + void initState() { + WidgetsBinding.instance.addObserver(this); + + Future.delayed(const Duration(seconds: 3), () { + getCheckPermission(context); + }); + super.initState(); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + print("-didChangeAppLifecycleState-" + state.toString()); + switch (state) { + case AppLifecycleState.inactive: // 处于这种状态的应用程序应该假设它们可能在任何时候暂停。 + break; + case AppLifecycleState.resumed: //从后台切换前台,界面可见 + if (theOpenAppSettings) { + getCheckPermission(context); + } + break; + case AppLifecycleState.paused: // 界面不可见,后台 + break; + case AppLifecycleState.detached: // APP结束时调用 + break; + case AppLifecycleState.hidden: + // TODO: Handle this case. + } + } + + @override + void dispose() { + _timerPermission?.cancel(); + WidgetsBinding.instance.removeObserver(this); + super.dispose(); + } + + void getCheckPermission(BuildContext context) async { + theOpenAppSettings = false; + theExecutionFrequency++; + + List permissions = []; // 普通拒绝 + List permanentRefusal = []; // 永久拒绝 + for (var i = 0; i < widget.permissions.length; i++) { + var p = widget.permissions[i]; + var status = await p.status; + var shouldShowRequestRationale = await p.shouldShowRequestRationale; + if (!status.isGranted) { + if (status.isDenied) { + if (shouldShowRequestRationale) { + /// 说明情况,再次發起权限请求(已经拒绝一次了) + await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: quickText(widget.title, fontWeight: FontWeight.bold), + content: quickText(widget.describe, maxLines: 20), + actions: [ + ElevatedButton( + onPressed: () async => Navigator.of(context).pop(), + child: const Text('我已知晓'), + ) + ], + ); + }, + ); + } + permissions.add(p); + } else if (await status.isPermanentlyDenied) { + permanentRefusal.add(p); + } + } + } + + if (permissions.isNotEmpty) { + // 普通拒绝 + permanentRefusal.addAll(await getStoragePermission(context, permissions)); + } + + if (permanentRefusal.isNotEmpty) { + /// 被永久拒绝了 需要弹出对话框说明 使用户自行操作 + await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + content: quickText(widget.describe, maxLines: 20), + title: quickText(widget.title, fontWeight: FontWeight.bold), + actions: [ + ElevatedButton( + onPressed: () async { + Navigator.of(context).pop(); + theOpenAppSettings = true; + await AppSettings.openAppSettings(asAnotherTask: true); + }, + child: const Text('前往APP权限设置'), + ) + ], + ); + }, + ); + } else { + Navigator.of(Get.context ?? context).pop(); + } + } + + /// 权限发起请求 + /// @param List permissions 权限集合 + Future> getStoragePermission( + BuildContext context, List permissions, + [int executionFrequency = 0]) async { + Map statusRes = await permissions.request(); + + List permanentRefusal = []; // 永久拒绝 + + List keys = statusRes.keys.toList(); + + for (var i = 0; i < keys.length; i++) { + Permission key = keys[i]; + PermissionStatus status = statusRes[key]!; + if (status.isPermanentlyDenied) { + /// 添加永久拒绝的权限集合 + permanentRefusal.add(key); + } else if (status.isDenied) { + /// 如果权限被永久拒绝,我们可能需要引导用户到应用设置中手动开启权限,显示一个对话框,解释为什么需要这个权限 + /// 应用之前已经请求过该权限,并且用户选择了“拒绝”,但没有选择“不再询问”(即没有永久拒绝)。 + /// 系统认为向用户显示一个权限请求的说明是合适的,以便用户理解为什么应用需要这个权限。 + if (await key.shouldShowRequestRationale) { + /// 说明情况,再次發起权限请求(已经拒绝一次了) + /// TODO 对话框 说明情况 再发发起请求 + await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: quickText(widget.title, fontWeight: FontWeight.bold), + content: quickText(widget.describe, maxLines: 20), + actions: [ + ElevatedButton( + onPressed: () async => Navigator.of(context).pop(), + child: const Text('我已知晓'), + ) + ], + ); + }, + ); + } + if (permissions.length == 1 && key == permissions[0]) { + executionFrequency++; + } + if (executionFrequency <= 1) { + var res = + await getStoragePermission(context, [key], executionFrequency); + permanentRefusal.addAll(res); + } else { + permanentRefusal.add(key); + } + + // break; + } + } + return permanentRefusal; + } + + @override + Widget build(BuildContext context) { + return PopScope( + canPop: false, + child: Container( + width: ScreenUtil().screenWidth, + height: ScreenUtil().screenHeight, + decoration: const BoxDecoration(color: Colors.transparent), + child: Column( + children: [ + SizedBox(height: ScreenUtil().screenHeight * 0.1), + Container( + width: ScreenUtil().screenWidth * 0.9, + padding: EdgeInsets.symmetric(vertical: 20.h, horizontal: 20.w), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.r), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.5), // 阴影颜色 + spreadRadius: 2, // 水平和垂直方向上扩展范围 + blurRadius: 4, // 模糊半径 + offset: Offset(0, 3), // X 和 Y 的偏移量 + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + quickText(widget.title, size: 24.sp), + quickText(widget.describe, maxLines: 20), + ], + ), + ), + const Expanded(child: SizedBox()), + ], + ), + )); + } +} + +class PermissionDescribeUtil { + static PermissionDescribeUtil? _instance; + + PermissionDescribeUtil._internal(); + + static get instance => _instance ??= PermissionDescribeUtil._internal(); + + /// 发起权限请求 + Future toLaunchPermissionRequest( + BuildContext context, { + required String title, + required String describe, + required List permissions, + }) async { + var isGranted = false; + for (var i = 0; i < permissions.length; i++) { + var p = permissions[i]; + if (!(await p.status.isGranted)) { + isGranted = true; + break; + } + } + if (isGranted) { + Navigator.of(Get.context ?? context).push(PageRouteBuilder( + opaque: false, + pageBuilder: (context, animation, secondaryAnimation) { + return PermissionDescribePage( + title: title, + describe: describe, + permissions: permissions, + ); + })); + } + + // await Navigator.of(context).push( + // transparentRoute( + // builder: (context) => PermissionDescribePage( + // title: title, + // describe: describe, + // permissions: permissions, + // ), + // ), + // ); + } +} + +// Route transparentRoute({ +// required WidgetBuilder builder, +// RouteSettings? settings, +// }) { +// return PageRouteBuilder( +// pageBuilder: ( +// BuildContext context, +// Animation animation, +// Animation secondaryAnimation, +// ) { +// return builder(context); +// }, +// transitionsBuilder: (_, Animation animation, Animation secondaryAnimation, Widget child) { +// return child; +// }, +// barrierDismissible: false, // 允许点击返回按钮关闭页面 +// // barrierColor: Colors.transparent, // 透明屏障颜色 +// ); +// } diff --git a/lib/common/utils/storage.dart b/making_school_asignment_app/lib/common/utils/storage.dart similarity index 100% rename from lib/common/utils/storage.dart rename to making_school_asignment_app/lib/common/utils/storage.dart diff --git a/lib/common/utils/toast_utils.dart b/making_school_asignment_app/lib/common/utils/toast_utils.dart similarity index 100% rename from lib/common/utils/toast_utils.dart rename to making_school_asignment_app/lib/common/utils/toast_utils.dart diff --git a/making_school_asignment_app/lib/common/utils/upload_oss_img_utils.dart b/making_school_asignment_app/lib/common/utils/upload_oss_img_utils.dart new file mode 100644 index 0000000..415379f --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/upload_oss_img_utils.dart @@ -0,0 +1,19 @@ +import '../mixins/request_tool_mixin.dart'; + +// OSS 图片上传 +class UploadOssImgUtils with RequestToolMixin { + static UploadOssImgUtils? _singleton; + static UploadOssImgUtils getInstance() => _singleton ??= UploadOssImgUtils._internal(); + + UploadOssImgUtils._internal(); + + Future getPresignedUri(String key) async { + var res = await getClient().getOssPresignedUri(key); + print(res); + } + + String setImgKey(String homeworkId, String studentId, String templateId) { + // $"hms-annotate/{input.HomeworkId}/{input.StudentId}/{input.TemplateId}.png"6月12日 13:54 + return 'hms-annotate/$homeworkId/$studentId/$templateId.png'; + } +} diff --git a/making_school_asignment_app/lib/common/utils/utils.dart b/making_school_asignment_app/lib/common/utils/utils.dart new file mode 100644 index 0000000..24d3a47 --- /dev/null +++ b/making_school_asignment_app/lib/common/utils/utils.dart @@ -0,0 +1,460 @@ +import 'dart:convert'; + +import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_state.dart'; +import 'dart:math'; + +import '../config/request_config.dart'; + +class Utils { + static Utils? _instance; + + Utils._internal(); + + static Utils getInstance() { + _instance ??= Utils._internal(); + + return _instance!; + } + + /// 关闭键盘 + static void hideKeyboard() { + FocusScopeNode? currentFocus = Get.focusScope?.nearestScope; + if (currentFocus == null) { + return; + } + if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) { + FocusManager.instance.primaryFocus?.unfocus(); + } + } + + void setTimeOut(int seconds, call) => + Future.delayed(Duration(seconds: seconds), call); + + // 是否是平板 + static bool isPad([double mobilePhoneScale = 1.2]) { + return ScreenUtil().scaleWidth > mobilePhoneScale; + } + + static String getDoubleRemoveZero(double? val, [String? defaultVal]) { + try { + if (val == null) throw Exception('数据为空'); + List _valArr = val.toString().split('.'); + if (_valArr.length >= 2) { + if (int.parse(_valArr[1]) == 0) { + return val.toInt().toString(); + } + return val.toString(); + } + return val.toInt().toString(); + } catch (e) { + return defaultVal ?? ''; + } + } + + /// 去除小数点 + static String doubleToStringAsFixed(double val, {int fractionDigits = 2}) { + return val.toStringAsFixed(fractionDigits).replaceAll(RegExp(r'\.0*$'), ''); + } + + static calcRate(int divisor, int dividend) { + if (dividend != 0) { + return ((100 * divisor) / dividend); + // return ((100 * divisor) / dividend).toStringAsFixed(0); + } else { + return 0.0; + } + } + + /// 秒转时分秒 + static String second2HMS(int sec, {bool isEasy = false}) { + String hms = "0"; + if (!isEasy) hms = "0秒"; + if (sec > 0) { + int h = sec ~/ 3600; + int m = (sec % 3600) ~/ 60; + int s = sec % 60; + if (h > 0) { + hms = "$h时$m分$s秒"; + } else { + if (m > 0) { + hms = "$m分$s秒"; + } else { + hms = "$s秒"; + } + } + } + return hms; + } + + static getHomeworkData(HomeworkDetails data) { + CountData dataCount = CountData(); + List kgt = data.dtls.where((w) => w.questionType == 1).toList(); + dataCount.kgtAnswerCount = kgt.where((w) => w.state != 0).length; + dataCount.kgtOkCount = kgt.where((w) => w.state == 3).length; + dataCount.kgtDtlCount = kgt.length; + dataCount.kgtAnswerRate = + Utils.calcRate(dataCount.kgtAnswerCount!, dataCount.kgtDtlCount!); + dataCount.kgtOkRate = + Utils.calcRate(dataCount.kgtOkCount!, dataCount.kgtDtlCount!); + + dataCount.kgtCorrectRate = + Utils.calcRate(dataCount.kgtOkCount!, dataCount.kgtAnswerCount!); + dataCount.kgtCount = + data.questions.where((w) => w.questionType == 1).length; + + List zgt = data.dtls.where((w) => w.questionType == 2).toList(); + dataCount.zgtAnswerCount = zgt.where((w) => w.state != 0).length; + dataCount.zgtOkCount = zgt.where((w) => w.state == 3).length; + dataCount.zgtDtlCount = zgt.length; + dataCount.zgtAnswerRate = + Utils.calcRate(dataCount.zgtAnswerCount!, dataCount.zgtDtlCount!); + dataCount.zgtOkRate = + Utils.calcRate(dataCount.zgtOkCount!, dataCount.zgtDtlCount!); + + dataCount.zgtCorrectRate = + Utils.calcRate(dataCount.zgtOkCount!, dataCount.zgtAnswerCount!); + dataCount.zgtCount = + data.questions.where((w) => w.questionType == 2).length; + dataCount.studentCount = data.students.length; + dataCount.priorityStudents = + data.students.where((w) => w.priorityAnnotate!).toList(); + +//已提交学生数 + dataCount.studentSubmitCount = + data.students.where((s) => s.state != 0).length; + dataCount.studentSubmitStudents = + data.students.where((s) => s.state != 0).toList(); +//未提交学生数 + dataCount.noAnswerCount = + data.students.length - dataCount.studentSubmitCount!; + dataCount.noAnswerStudents = + data.students.where((s) => s.state == 0).toList(); + + for (var stu in data.students) { + stu.kgtStu = kgt.where((w) => w.studentId == stu.studentId).toList(); + // 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) { + try { + if (RegExp(r'^\d*\.?\d+$').hasMatch(a.questionNo) && + RegExp(r'^\d*\.?\d+$').hasMatch(b.questionNo)) { + return num.parse(a.questionNo).compareTo(num.parse(b.questionNo)); + } else { + throw Exception(); + } + } catch (e) { + return a.questionNo + .toLowerCase() + .compareTo(b.questionNo.toLowerCase()); + } + }); + stu.kgtOkCount = stu.kgtStu!.where((w) => w.state == 3).length; + stu.kgtErrorCount = stu.kgtStu!.where((w) => w.state == 2).length; + stu.kgtAnswerCount = stu.kgtStu!.where((w) => w.state != 0).length; + + stu.zgtStu = zgt.where((w) => w.studentId == stu.studentId).toList(); + // stu.zgtStu!.sort((a, b) => num.parse(a.questionNo).compareTo(num.parse(b.questionNo))); + stu.zgtStu!.sort((a, b) { + try { + if (RegExp(r'^\d*\.?\d+$').hasMatch(a.questionNo) && + RegExp(r'^\d*\.?\d+$').hasMatch(b.questionNo)) { + return num.parse(a.questionNo).compareTo(num.parse(b.questionNo)); + } else { + throw Exception(); + } + } catch (e) { + return a.questionNo + .toLowerCase() + .compareTo(b.questionNo.toLowerCase()); + } + }); + //正确 + stu.zgtOkCount = stu.zgtStu!.where((w) => w.state == 3).length; + //错误 + stu.zgtErrorCount = stu.zgtStu!.where((w) => w.state == 2).length; + //待批阅 + stu.zgtUnrated = stu.zgtStu!.where((w) => w.state == 1).length; + //未做 + stu.zgtAnswerCount = stu.zgtStu!.where((w) => w.state != 0).length; + stu.isAllCorrect = + stu.kgtOkCount! + stu.zgtOkCount! == kgt.length + zgt.length + ? true + : false; + stu.allOk = data.dtls.where((w) { + if (stu.studentId == w.studentId) { + stu.useTime = w.useTime; + } + for (var que in data.questions) { + if (w.templateId == que.templateId && + w.questionNo == que.questionNo) { + w.answer = que.answer; + w.questionPicture = que.questionPicture; + } + } + return w.studentId == stu.studentId && w.state != 3; + }).length ?? + 0; + if ((stu.kgtStu!.length - stu.kgtAnswerCount!) + + (stu.zgtStu!.length - stu.zgtAnswerCount!) == + (stu.kgtStu!.length + stu.zgtStu!.length)) { + stu.allNotDone = true; + } else { + stu.allNotDone = false; + } + stu.noAnswerCount = data.dtls + .where((w) => w.state == 0 && stu.studentId == w.studentId) + .length; + + List ques = data.questions; + stu.queDtls = data.dtls + .where((w) => + w.studentId == stu.studentId && + ques.indexWhere((q) => + w.templateId == q.templateId && + w.questionNo == q.questionNo) > + -1) + .toList(); + int okCount = stu.queDtls!.where((w) => w.state == 3).length; + int ttlCount = stu.queDtls!.length; + stu.okRate = Utils.calcRate(okCount, ttlCount); + + //完成率 + int answerCount = stu.queDtls!.where((w) => w.state != 0).length; + stu.answerRate = Utils.calcRate(answerCount, ttlCount); + + var stuDtls = data.dtls.where((w) => w.studentId == stu.studentId); + var secList = []; + for (var sec in stuDtls) { + if (sec.useTime >= 1) { + var date = DateTime.parse(sec.lastAnswerTime!); + var lastSec = (date.difference(DateTime(1970)).inSeconds).floor(); + + secList.add(lastSec); + secList.add(lastSec - sec.useTime); + } + } + secList.sort(); + /* var maxSec = secList.isNotEmpty ? secList.last : 0; + var minSec = secList.isNotEmpty ? secList.first : 0;*/ + var maxSec = secList.isNotEmpty + ? secList + .reduce((value, element) => value > element ? value : element) + : 0; + var minSec = secList.isNotEmpty + ? secList + .reduce((value, element) => value < element ? value : element) + : 0; + var secTime = secList.isNotEmpty ? maxSec - minSec : 0; + stu.allTime = secTime; + stu.ttlSec = second2HMS(secTime); + } + + data.students.sort((a, b) { + int num1 = a.state; + int num2 = b.state; + return num2.compareTo(num1); + }); +//全对 + dataCount.allCorrect = + data.students.where((w) => w.isAllCorrect == true).length; + dataCount.allCorrectStudents = + data.students.where((w) => w.isAllCorrect == true).toList(); + //优 + dataCount.levelOneCount = + data.students.where((s) => s.okRate! >= 85).length; + dataCount.levelOneStudents = + data.students.where((s) => s.okRate! >= 85).toList(); + + //良 + dataCount.levelTwoCount = + data.students.where((s) => s.okRate! < 85 && s.okRate! >= 55).length; + dataCount.levelTwoStudents = + data.students.where((s) => s.okRate! < 85 && s.okRate! >= 55).toList(); + + //中 + dataCount.levelThreeCount = + data.students.where((s) => s.okRate! < 55 && s.okRate! >= 25).length; + dataCount.levelThreeStudents = + data.students.where((s) => s.okRate! < 55 && s.okRate! >= 25).toList(); + + //差 + dataCount.levelFourCount = + data.students.where((s) => s.okRate! < 25).length; + dataCount.levelFourStudents = + data.students.where((s) => s.okRate! < 25).toList(); + + for (var que in data.questions) { + List ques = data.dtls + .where((w) => + w.templateId == que.templateId && w.questionNo == que.questionNo) + .toList(); + que.answerCount = ques.where((w) => w.state != 0).length; + que.answerRate = + Utils.calcRate(que.answerCount!, dataCount.studentCount!); + int okCount = ques.where((w) => w.state == 3).length; + que.okRate = Utils.calcRate(okCount, dataCount.studentCount!); + que.priorityInfo = ques.where((w) { + return dataCount.priorityStudents!.indexWhere((s) { + w.studentName = s.studentName; + return s.studentId == w.studentId; + }) > + -1 && + w.state != 3; + }).toList(); + que.correctRate = Utils.calcRate(okCount, que.answerCount!); + que.answerNgStudents = ques.where((w) { + w.studentName = data.students + .firstWhere((s) => s.studentId == w.studentId) + .studentName; + return w.state == 2; + }).toList(); + + que.noAnswerStudents = ques.where((w) { + return w.state == 0; + }).toList(); + que.answerOkStudents = ques.where((w) { + return w.state == 3; + }).toList(); + + //作答效率 + int middleTime = 0; + if (ques.length % 2 == 0) { + int index = (ques.length / 2).ceil(); + middleTime = + ((ques[index].useTime + ques[index - 1].useTime) / 2).ceil(); + } else { + int index = ((ques.length + 1) / 2).ceil(); + middleTime = ques[index - 1].useTime; + } + + var excellent = + ques.where((w) => w.state == 3 && w.useTime <= middleTime).length; + var good = + ques.where((w) => w.state == 3 && w.useTime > middleTime).length; + var middle = + ques.where((w) => w.state != 3 && w.useTime <= middleTime).length; + var differ = + ques.where((w) => w.state != 3 && w.useTime > middleTime).length; + + que.overallTitles = [ + OverallTitles('优秀', excellent), + OverallTitles('良好', good), + OverallTitles('中', middle), + OverallTitles('差', differ) + ]; + + Map optInfos = {}; + for (var d in ques + .where((w) => w.questionType == 1 && w.studentAnswer != null)) { + final key = d.studentAnswer!; + if (optInfos[key] != null) { + optInfos[key] = optInfos[key]! + 1; + } else { + optInfos[key] = 1; + } + } + List student = []; + optInfos.forEach((key, value) { + // optInfos[key] = Utils.calcRate(value, ques.length).round(); + List currentOptionStudents = data.students + .where((s) => ques + .where( + (w) => w.studentAnswer == key && w.studentId == s.studentId) + .isNotEmpty) + .toList(); + //字母排序 + String upStr = key.toUpperCase(); + List chars = upStr.split('')..sort(); + String sortedStr = chars.join(); + + student.add(SelectionRate( + sortedStr, + Utils.calcRate(value, ques.length).round(), + false, + currentOptionStudents)); + }); + /* print('optitems=$optInfos'); + var ARate = Utils.calcRate( + ques.where((w) => w.studentAnswer == "A").length, ques.length);*/ + que.options = student; + } + + for (var know in data.knows) { + List ques = data.questions + .where((w) => + w.knows.indexWhere((k) => k.knowledgeId == know.knowledgeId) > -1) + .toList(); + List queDtls = data.dtls + .where((w) => + ques.indexWhere((q) => + w.templateId == q.templateId && + w.questionNo == q.questionNo) > + -1) + .toList(); + know.okCount = queDtls.where((w) => w.state == 3).length; + know.ttlCount = queDtls.length; + know.okRate = Utils.calcRate(know.okCount!, know.ttlCount!); + } + + return dataCount; + } + + static DateTime getWeekStartDate() { + // DateTime now = DateTime.now(); + // int dayOfWeek = now.weekday; // 获取今天是周几(1代表周一,7代表周日) + // int diff = dayOfWeek - 1; // 计算今天距离周一的天数差 + // if (diff < 0) { + // diff += 7; // 如果是周日,则需要加上一周的天数 + // } + // return now.subtract(Duration(days: diff)); // 减去天数差,得到本周一的时间 + DateTime now = DateTime.now(); + return now.subtract(const Duration(days: 6)); + } + + static DateTime getWeekEndDate() { + // DateTime now = DateTime.now(); + // int dayOfWeek = now.weekday; // 获取今天是周几 + // int diff = 7 - dayOfWeek; // 计算今天距离周日的天数差 + // if (diff == 0) { + // diff = 7; // 如果是周日,则加上一周的天数 + // } + // return now.add(Duration(days: diff)); // 加上天数差减一,得到本周日的时间 + return DateTime.now(); + } +} + +// 是否是平板 +bool isPad([double mobilePhoneScale = 1.2]) { + return ScreenUtil().scaleWidth > mobilePhoneScale; +} + +void toUpState( + Function(void Function()) setState, VoidCallback fn, bool mounted) { + if (mounted) setState(fn); +} + +void toPrint({required dynamic val, bool toPrintJson = false}) { + bool printSwitch = RequestConfig.printSwitch; + if (printSwitch && val != null) toPrintJson ? printJson(val) : print(val); +} + +/// 单纯的Json格式输出打印 +void printJson(Object object) { + try { + JsonEncoder encoder = const JsonEncoder.withIndent(' '); + var encoderString = encoder.convert(object); + // print(encoderString); + // 不使用print()方法是因为这是单条输出,如果过长无法显示全 + // 所以使用debugPrint() + debugPrint(encoderString); + // 下面这语句的效果与debugPrint 相同 + //encoderString.split('\n').forEach((element) => print(element)); + } catch (e) { + toPrint(val: e); + } +} diff --git a/making_school_asignment_app/lib/main.dart b/making_school_asignment_app/lib/main.dart new file mode 100644 index 0000000..033f5f8 --- /dev/null +++ b/making_school_asignment_app/lib/main.dart @@ -0,0 +1,140 @@ +import 'dart:io'; +import 'package:auto_updater/auto_updater.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_screenutil/flutter_screenutil.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/colorUtils.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/common/utils/storage.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; + +import 'common/config/request_config.dart'; +import 'common/utils/app_upgrade/upgradeLogic.dart'; +import 'package:flutter_native_splash/flutter_native_splash.dart'; + +void main() async { +// 在测试模式下运行Get + Get.testMode = true; + WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); + FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); + + /// 初始化本地存储 + await Get.putAsync(() => StorageService().init()); + + /// 初始化UserStore + Get.put(UserStore().init()); + Get.put(UpgradeLogic()); + WidgetsFlutterBinding.ensureInitialized(); + + // Windows + if (Platform.isWindows) { + String feedURL = '${RequestConfig.imgUrl}infra-app/making_school_asignment_app/3/appcast.xml'; + await autoUpdater.setFeedURL(feedURL); + await autoUpdater.checkForUpdates(); + await autoUpdater.setScheduledCheckInterval(3600); + } + + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, //状态栏背景颜色 + statusBarIconBrightness: Brightness.light // dark:一般显示黑色 light:一般显示白色 + )); + SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top]); // 屏幕刘海 + await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); // 屏幕强制竖屏 + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + // This widget is the root of your application. + + @override + Widget build(BuildContext context) { + // String? oldRouter; + return ScreenUtilInit( + designSize: const Size(AppConfig.UI_WIDTH, AppConfig.UI_HEIGHT), + /* minTextAdapt: true, + splitScreenMode: true,*/ + builder: () => GetMaterialApp( + title: '点智学', + debugShowCheckedModeBanner: false, + theme: ThemeData( + brightness: Brightness.light, + primarySwatch: createMaterialColor(const Color(0xFF8C68FF)), + primaryColor: const Color(0xFF8C68FF), + // textTheme: Typography.englishLike2018.apply(fontSizeFactor: 1.sp,), + primaryTextTheme: TextTheme( + bodyLarge: TextStyle(fontSize: 14.sp, color: Colors.black87), + ), + useMaterial3: false, + colorScheme: const ColorScheme.light( + // 修改亮色主题的主题颜色 + primary: Color(0xFF8C68FF), + )), + enableLog: true, + logWriterCallback: (text, {bool isError = false}) { + // isError ? LoggerUtils.e(text) : LoggerUtils.i(text); + }, + routingCallback: (routing) { + String? currentRouter = routing?.current; + // print("当前页面 ${currentRouter}"); + // print("当前路由:${currentRouter}"); + // if ([Routes.home, Routes.myInfo].contains(currentRouter)) { + // SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + // statusBarIconBrightness: Brightness.light, + // systemStatusBarContrastEnforced: false, + // )); + // } + + // if (Routes.reviewHomework == currentRouter) { + // // SystemChrome.setEnabledSystemUIMode(SystemUiMode.leanBack, overlays: []); + // } else if (oldRouter == Routes.reviewHomework) { + // // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]); // 屏幕刘海 + // } + // oldRouter = currentRouter; + }, + // 这里是国际化支持,确保添加flutter_localizations依赖 + supportedLocales: const [ + Locale('zh', 'CN'), // 中文简体 + // 其他支持的locale可以在这里添加 + ], + localizationsDelegates: const [ + // ...其他delegates + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, // 如果你使用了Cupertino风格的组件 + // ...添加其他必要的delegates + ], + localeResolutionCallback: (locale, supportedLocales) { + // 在这里可以实现自定义的locale解析逻辑 + // 如果需要,返回你想要的Locale对象 + return locale; + }, + //默认专场动画 + defaultTransition: getTransition(), + //初始化路由页面 + initialRoute: Routes.startPage, + + /// 路由表 + getPages: AppPages.pages, + builder: EasyLoading.init( + builder: (context, child) { + return MediaQuery( + //Setting font does not change with system font size + data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), + child: Scaffold( + body: GestureDetector(onTap: () => Utils.hideKeyboard(), child: child), + ), + ); + }, + ), + // home: const MyHomePage(title: 'Flutter Demo Home Page'), + ), + ); + } +} diff --git a/lib/page/global_widget/MyEmptyWidget.dart b/making_school_asignment_app/lib/page/global_widget/MyEmptyWidget.dart similarity index 100% rename from lib/page/global_widget/MyEmptyWidget.dart rename to making_school_asignment_app/lib/page/global_widget/MyEmptyWidget.dart diff --git a/lib/page/global_widget/ReturnToHomepage.dart b/making_school_asignment_app/lib/page/global_widget/ReturnToHomepage.dart similarity index 78% rename from lib/page/global_widget/ReturnToHomepage.dart rename to making_school_asignment_app/lib/page/global_widget/ReturnToHomepage.dart index bbc065f..5460ce8 100644 --- a/lib/page/global_widget/ReturnToHomepage.dart +++ b/making_school_asignment_app/lib/page/global_widget/ReturnToHomepage.dart @@ -1,17 +1,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; // 返回首页 class ReturnToHomepage extends StatelessWidget { final Color? bgColor; - const ReturnToHomepage({super.key,this.bgColor = const Color.fromRGBO(135, 135, 135, 1)}); + const ReturnToHomepage({super.key, this.bgColor = const Color.fromRGBO(135, 135, 135, 1)}); @override Widget build(BuildContext context) { return InkWell( - onTap: (){ + onTap: () { // Navigator.of(context).popUntil(ModalRoute.withName(Routes.startPage)); Get.until((route) => route.settings.name == Routes.startPage); }, diff --git a/lib/page/global_widget/bottom_navigation_bar.dart b/making_school_asignment_app/lib/page/global_widget/bottom_navigation_bar.dart similarity index 85% rename from lib/page/global_widget/bottom_navigation_bar.dart rename to making_school_asignment_app/lib/page/global_widget/bottom_navigation_bar.dart index af49ca9..69da1e8 100644 --- a/lib/page/global_widget/bottom_navigation_bar.dart +++ b/making_school_asignment_app/lib/page/global_widget/bottom_navigation_bar.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/common/store/user_store.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; const _items = [ { @@ -41,7 +41,7 @@ class MyBottomNavigationBar extends StatelessWidget { height: 50.r, margin: EdgeInsets.only(bottom: Get.mediaQuery.padding.bottom), decoration: const BoxDecoration( - color:Colors.white, + color: Colors.white, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, @@ -51,7 +51,7 @@ class MyBottomNavigationBar extends StatelessWidget { if (active == e['id']) { return; } - Get.offAllNamed(e['route'] as String,arguments: e['id']); + Get.offAllNamed(e['route'] as String, arguments: e['id']); }, child: Container( width: 60.r, @@ -73,8 +73,9 @@ class MyBottomNavigationBar extends StatelessWidget { Text( e['title'] as String, style: TextStyle( - color: active == (e['id'] as int) ? const Color(0xFF6888FD) : const Color(0xFF767676), - fontSize: 11.sp,), + color: active == (e['id'] as int) ? const Color(0xFFE8E8E8) : const Color(0xFF767676), + fontSize: 11.sp, + ), strutStyle: StrutStyle(fontSize: 16.sp), ) ], diff --git a/lib/page/global_widget/global_scaffold.dart b/making_school_asignment_app/lib/page/global_widget/global_scaffold.dart similarity index 86% rename from lib/page/global_widget/global_scaffold.dart rename to making_school_asignment_app/lib/page/global_widget/global_scaffold.dart index 458838b..27fc7b4 100644 --- a/lib/page/global_widget/global_scaffold.dart +++ b/making_school_asignment_app/lib/page/global_widget/global_scaffold.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/common/utils/toast_utils.dart'; -import 'package:school_asignment_app/page/global_widget/bottom_navigation_bar.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/bottom_navigation_bar.dart'; class GlobalScaffold extends StatelessWidget { final AppBar? appBar; diff --git a/lib/page/global_widget/imgDialog.dart b/making_school_asignment_app/lib/page/global_widget/imgDialog.dart similarity index 56% rename from lib/page/global_widget/imgDialog.dart rename to making_school_asignment_app/lib/page/global_widget/imgDialog.dart index 0464844..96518cd 100644 --- a/lib/page/global_widget/imgDialog.dart +++ b/making_school_asignment_app/lib/page/global_widget/imgDialog.dart @@ -1,26 +1,32 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:school_asignment_app/common/config/request_config.dart'; +import 'package:making_school_asignment_app/common/config/request_config.dart'; -class ImageDialog{ - static void showImgDialog(BuildContext context,String imgUrl) { +class ImageDialog { + static void showImgDialog(BuildContext context, String imgUrl) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( // insetPadding: EdgeInsets.symmetric(vertical: 10.r,horizontal: 45.r), backgroundColor: Colors.transparent, - contentPadding: EdgeInsets.all(0), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(15.r))), + contentPadding: EdgeInsets.zero, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15.r))), content: Container( width: MediaQuery.of(context).size.width - 48.r, // height: MediaQuery.of(context).size.height * 0.4, color: Colors.white, // child: PhotoView(imageProvider: NetworkImage(imgUrl),backgroundDecoration: BoxDecoration(color: Colors.transparent),)), - child: Image.network(RequestConfig.imgUrl+imgUrl)), + child: ListView( + children: [ + Image.network( + RequestConfig.imgUrl + imgUrl, + fit: BoxFit.fitWidth, + ), + ], + )), ); }, ); } -} \ No newline at end of file +} diff --git a/lib/page/global_widget/my_text.dart b/making_school_asignment_app/lib/page/global_widget/my_text.dart similarity index 87% rename from lib/page/global_widget/my_text.dart rename to making_school_asignment_app/lib/page/global_widget/my_text.dart index dd62894..4f05931 100644 --- a/lib/page/global_widget/my_text.dart +++ b/making_school_asignment_app/lib/page/global_widget/my_text.dart @@ -7,11 +7,12 @@ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ import 'package:flutter/cupertino.dart'; -import 'package:school_asignment_app/common/config/colorUtils.dart'; +import 'package:making_school_asignment_app/common/config/colorUtils.dart'; // 快捷Text使用 Text quickText(text, {double? size, + double? wordSpacing, Color color = CommonColors.defaultColor, TextAlign? align, FontWeight? fontWeight, @@ -28,6 +29,7 @@ Text quickText(text, fontSize: size, color: color, fontWeight: fontWeight, + wordSpacing: wordSpacing, ), ); } diff --git a/making_school_asignment_app/lib/page/global_widget/other_page.dart b/making_school_asignment_app/lib/page/global_widget/other_page.dart new file mode 100644 index 0000000..dcde7de --- /dev/null +++ b/making_school_asignment_app/lib/page/global_widget/other_page.dart @@ -0,0 +1,199 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; +import 'package:making_school_asignment_app/common/job/user_info_detail.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/common/utils/storage.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +// 其他页面 + +class OhterPage extends StatefulWidget { + const OhterPage({super.key}); + + @override + State createState() => _OhterPageState(); +} + +class _OhterPageState extends State with RequestToolMixin { + late Rx userInfo = UserStore.to.userDetailInfo; + RxString localVersion = ''.obs; + + @override + void initState() { + super.initState(); + getPageInfo(); + } + + // 获取当前版本号 + getPageInfo() async { + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + localVersion.value = packageInfo.version; + } + + // 确认对话框 + _showAlertDialog(context1) async { + await showDialog( + // 表示点击灰色背景的时候是否消失弹出框 + barrierDismissible: false, + context: context1, + builder: (context) { + return AlertDialog(title: quickText("提示信息"), content: quickText("账户注销无法恢复,您确定要注销账户吗?"), actions: [ + TextButton( + child: quickText("取消"), + onPressed: () { + Navigator.pop(context, 'Cancle'); + }, + ), + TextButton( + child: quickText("确定"), + onPressed: () async { + /* ref.read(markingKeyboardProvider.notifier).clean(); + ref.read(markingSubtopicSwitchingProvider.notifier).clean(); + ref.read(userTokenProvider.notifier).clean(); + ref.read(userProvider.notifier).clean();*/ + await getClient().toUserLogout(userInfo.value!.id); + try { + UserStore.to.erase(); + var msg = await StorageService.to.erase(); + print(msg); + Navigator.pop(context, "Ok"); + Get.offAllNamed(Routes.login); + } catch (e) { + print(e); + } + }) + ]); + }); + } + + @override + Widget build(BuildContext context) { + final personalInfoTitleStly = TextStyle( + color: const Color.fromRGBO(80, 87, 103, 1), + fontSize: 16.sp, + ); + + return Scaffold( + backgroundColor: const Color.fromRGBO(248, 248, 248, 1), + appBar: AppBar( + backgroundColor: Theme.of(context).primaryColor, + title: quickText('其他', color: Colors.white), + ), + body: Stack( + alignment: const FractionalOffset(0.5, 0.98), + children: [ + ListView( + children: [ + Container( + margin: EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w), + padding: EdgeInsets.symmetric(vertical: 22.h, horizontal: 16.w), + height: 130.h, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.w)), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(46, 91, 255, 0.1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 20, //阴影模糊程度 + spreadRadius: 10, //阴影扩散程度 + ) + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); + }, + child: Container( + padding: EdgeInsets.only(bottom: 4.h), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('用户隐私协议', style: personalInfoTitleStly), + Icon( + Icons.arrow_forward_ios, + color: const Color.fromRGBO(80, 87, 103, 1), + size: 16.sp, + ) + ], + ), + ), + ), + Container( + height: 1.w, + color: const Color.fromRGBO(240, 243, 255, 1), + ), + SizedBox(height: 8.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('APP版本', style: personalInfoTitleStly), + Obx(() { + return quickText(localVersion); + }) + ], + ) + ], + ), + ), + ], + ), + Positioned( + bottom: 50.h, + child: InkWell( + child: Container( + height: 46.h, + width: ScreenUtil().screenWidth - 60.w, + padding: EdgeInsets.symmetric(vertical: 14.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.all( + Radius.circular(6.w), + ), + color: Colors.white, + boxShadow: [ + BoxShadow( + color: const Color.fromRGBO(46, 91, 255, 0.2), + offset: Offset(2.w, 2.h), //阴影y轴偏移量 + blurRadius: 14, //阴影模糊程度 + spreadRadius: 0.5, //阴影扩散程度 + ) + ], + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.exit_to_app_outlined, + size: 13.sp, + color: const Color.fromRGBO(148, 163, 182, 1), + ), + Container( + width: 6.w, + ), + Text( + '账户注销', + style: TextStyle(color: const Color.fromRGBO(148, 163, 182, 1), fontSize: 13.sp), + ), + ], + ), + ), + onTap: () => _showAlertDialog(context), + ), + ), + Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [Text('APP备案号: ', style: personalInfoTitleStly), quickText('渝ICP备17007225号-4A', size: 14.sp)], + ), + ], + )); + } +} diff --git a/lib/page/global_widget/show_student_list.dart b/making_school_asignment_app/lib/page/global_widget/show_student_list.dart similarity index 66% rename from lib/page/global_widget/show_student_list.dart rename to making_school_asignment_app/lib/page/global_widget/show_student_list.dart index f4bbe4e..84af488 100644 --- a/lib/page/global_widget/show_student_list.dart +++ b/making_school_asignment_app/lib/page/global_widget/show_student_list.dart @@ -1,15 +1,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; class ShowStudentList extends StatelessWidget { final String title; final String homeworkId; final List studentList; - const ShowStudentList({Key? key,required this.title,required this.studentList,required this.homeworkId}) : super(key: key); + final int subject; + const ShowStudentList({Key? key, required this.title, required this.studentList, required this.homeworkId,required this.subject}) : super(key: key); @override Widget build(BuildContext context) { @@ -30,7 +31,7 @@ class ShowStudentList extends StatelessWidget { title, size: 18.sp, fontWeight: FontWeight.bold, - color: Color.fromRGBO(60, 60, 60, 1), + color: const Color.fromRGBO(60, 60, 60, 1), ), ), Expanded( @@ -43,22 +44,16 @@ class ShowStudentList extends StatelessWidget { alignment: WrapAlignment.spaceAround, //沿主轴方向居中 children: studentList.map((e) { return InkWell( - onTap: (){ - Get.toNamed(Routes.studentPersonalPage,arguments: {'studentId':e.studentId,'homeworkId':homeworkId}); + onTap: () { + Get.toNamed(Routes.studentPersonalPage, arguments: {'studentId': e.studentId, 'homeworkId': homeworkId,'subject':subject}); }, child: Container( - padding: EdgeInsets.symmetric( - vertical: 4.r, horizontal: 8.r), + padding: EdgeInsets.symmetric(vertical: 4.r, horizontal: 8.r), decoration: BoxDecoration( - color: e.state == 3 - ? Color(0xFF4CC793) - : Color(0xFFE2E2E2), + color: e.state == 3 ? Color(0xFF4CC793) : Color(0xFFF0ECFF), borderRadius: BorderRadius.circular(4.r), ), - child: quickText(e.studentName, - color: - e.state == 3 ? Colors.white : Color(0xFF505E6E), - size: 10.sp), + child: quickText(e.studentName, color: e.state == 3 ? Colors.white : Color(0xFF505E6E), size: 10.sp), ), ); }).toList(), diff --git a/lib/page/global_widget/start_page.dart b/making_school_asignment_app/lib/page/global_widget/start_page.dart similarity index 50% rename from lib/page/global_widget/start_page.dart rename to making_school_asignment_app/lib/page/global_widget/start_page.dart index 6dac3e7..9f4f192 100644 --- a/lib/page/global_widget/start_page.dart +++ b/making_school_asignment_app/lib/page/global_widget/start_page.dart @@ -1,50 +1,56 @@ -import 'dart:convert'; -import 'dart:io'; +import 'dart:async'; +import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:package_info/package_info.dart'; -import 'package:school_asignment_app/common/config/app_config.dart'; -import 'package:school_asignment_app/common/job/common/app_version_model.dart'; -import 'package:school_asignment_app/common/job/common/base_app_version.dart'; -import 'package:school_asignment_app/common/job/common/base_page_data.dart'; -import 'package:school_asignment_app/common/job/user_info.dart'; -import 'package:school_asignment_app/common/job/user_info_detail.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:school_asignment_app/common/store/app_storage_key.dart'; -import 'package:school_asignment_app/common/store/user_store.dart'; -import 'package:school_asignment_app/common/utils/toast_utils.dart'; -import 'package:school_asignment_app/page/home_page/children/my_info.dart'; -import 'package:school_asignment_app/page/home_page/home_logic.dart'; -import 'package:school_asignment_app/page/home_page/home_view.dart'; -import 'package:school_asignment_app/page/work_page/work_logic.dart'; -import 'package:school_asignment_app/page/work_page/work_view.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; +import 'package:flutter_native_splash/flutter_native_splash.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/job/user_info.dart'; +import 'package:making_school_asignment_app/common/utils/storage.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/home_page/home_view.dart'; +import 'package:making_school_asignment_app/page/home_page/home_logic.dart'; +import 'package:making_school_asignment_app/page/work_page/work_logic.dart'; +import 'package:making_school_asignment_app/common/job/user_info_detail.dart'; +import 'package:making_school_asignment_app/page/home_page/children/my_info.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/app_upgrade/upgradeLogic.dart'; class StartPage extends StatefulWidget { - const StartPage({Key? key}) : super(key: key); + const StartPage({super.key}); @override State createState() => _StartPageState(); } -class _StartPageState extends State { +class _StartPageState extends State with RequestToolMixin { + Timer? _timer; + Timer? _timerPermission; DateTime? lastPopTime; final _pageController = Get.find(); + final _upgradeLogic = Get.find(); + late final List _bodyList; @override void initState() { super.initState(); - Get.put(HomeLogic()); - Get.put(WorkLogic()); - _bodyList = [ - const HomePage(), - const WorkPage(), - const MyInfo(), - ]; + Future.delayed(const Duration(seconds: 3), () => FlutterNativeSplash.remove()); + + // const WorkPage(), + _bodyList = [const HomePage(), const MyInfo()]; + // APP 启动后就直接更新 + WidgetsBinding.instance.addPostFrameCallback((e) { + /// 首页用户未更新不进行更新判断,没有登陆的用户在登陆页面和40秒回调中检查弹出更新APP + if (!_upgradeLogic.showUpgrade.value && UserStore.to.userDetailInfo.value != null) _upgradeLogic.getAppUpgrade(context); + }); + _timer?.cancel(); + _timer = Timer.periodic(const Duration(seconds: 40), (e) { + if (Get.currentRoute == Routes.login) return; // 在登录页面不更新APP + if (!_upgradeLogic.showUpgrade.value) _upgradeLogic.getAppUpgrade(context); + }); String? token = UserStore.to.token; UserInfo? userInfo = UserStore.to.userInfo.value; @@ -57,13 +63,19 @@ class _StartPageState extends State { // 更新用户信息 if (userInfoDetail == null) UserStore.to.updateUserInfo(); } else { - Future.delayed(const Duration(milliseconds: 100)).then((e) => Get.offAllNamed(Routes.login)); + Future.delayed(const Duration(milliseconds: 100)).then((e) { + UserStore.to.erase(); + StorageService.to.erase(); + Get.offAllNamed(Routes.login); + }); } } @override void dispose() { Get.delete(); + _timer?.cancel(); + _timerPermission?.cancel(); super.dispose(); } @@ -86,35 +98,44 @@ class _StartPageState extends State { physics: const BouncingScrollPhysics(), onPageChanged: (index) { _pageController._pageIndexState.pageIndex.value = index; + // if (index == 2) { + // SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(statusBarIconBrightness: Brightness.light)); + // } else { + // SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(statusBarIconBrightness: Brightness.dark)); + // } }, children: _bodyList, ), bottomNavigationBar: Obx(() { return BottomNavigationBar( + backgroundColor: Colors.white, items: [ BottomNavigationBarItem( label: '作业', icon: getItemIcon('assets/images/ic_home_normal.png'), - activeIcon: getItemIcon('assets/images/ic_home_press.png'), - ), - BottomNavigationBarItem( - label: '考试', - icon: getItemIcon('assets/images/ic_work_normal.png'), - activeIcon: getItemIcon('assets/images/ic_work_press.png'), + activeIcon: getItemIcon('assets/images/ic_home_active.png'), ), + // BottomNavigationBarItem( + // label: '考试', + // icon: getItemIcon('assets/images/ic_work_normal.png'), + // activeIcon: getItemIcon('assets/images/ic_work_active.png'), + // ), BottomNavigationBarItem( label: '我的', icon: getItemIcon('assets/images/ic_mine_normal.png'), - activeIcon: getItemIcon('assets/images/ic_mine_press.png'), + activeIcon: getItemIcon('assets/images/ic_mine_active.png'), ), ], //设置显示的模式 type: BottomNavigationBarType.fixed, + fixedColor: Theme.of(context).primaryColor, + unselectedItemColor: Colors.grey, + // unselectedItemColor: const Color.fromRGBO(80, 87, 103, 1), + // backgroundColor: Colors.white, //设置当前的索引 currentIndex: _pageController._pageIndexState.pageIndex.value, //tabBottom的点击监听 onTap: (index) { - print('appbar下标:${index}'); _pageController._pageIndexState.pageController.jumpToPage(index); }, ); @@ -148,44 +169,6 @@ class PageIndexState { class PageIndexController extends GetxController with RequestToolMixin { late PageIndexState _pageIndexState; - void getAppUpgrade(UserInfoDetail user) async { - try { - _pageIndexState.showUpgrade = true; - if (user.name == AppConfig.SKIP_UPDATING_USER) return; - // 获取设备信息 - String deviceInfo = "android"; - int deviceType; - if (Platform.isAndroid) { - deviceType = 1; - } else if (Platform.isIOS) { - deviceInfo = "ios"; - deviceType = 2; - } else { - return; - } - var params = BaseAppVersion(AppConfig.APP_NAME, deviceType, 1, 1); - BasePageData? result = await getClient().getAppVersions(params); - if (result != null && result.total == 1) { - //获取当前版本 - PackageInfo packageInfo = await PackageInfo.fromPlatform(); - //获取当前版本 - String localVersion = packageInfo.version; - String appName = packageInfo.appName; //应用名称 - String packageName = packageInfo.packageName; //包名称 - // String buildNumber = packageInfo.buildNumber; //小版本号 - AppVersionModel data = result.items[0]; - // Map json = {'downloadPath': data.apkUrl, 'version': data.version, 'systemType': deviceType, 'description': data.description}; - // UpdateAppEvent updateAppEvent = UpdateAppEvent.fromJson(json, localVersion, deviceInfo, appName, packageName, typeName: 'systemType'); - // if (updateAppEvent.upgrade) { - // await UpdateDialog.showUpdateDialog(context, updateAppEvent); - // } - } - } catch (e) { - } finally { - _pageIndexState.showUpgrade = false; - } - } - @override void onInit() { _pageIndexState = PageIndexState(pageController: PageController()); diff --git a/lib/page/home_page/children/annotate_class/annotate_class_binding.dart b/making_school_asignment_app/lib/page/home_page/children/annotate_class/annotate_class_binding.dart similarity index 100% rename from lib/page/home_page/children/annotate_class/annotate_class_binding.dart rename to making_school_asignment_app/lib/page/home_page/children/annotate_class/annotate_class_binding.dart diff --git a/making_school_asignment_app/lib/page/home_page/children/annotate_class/annotate_class_logic.dart b/making_school_asignment_app/lib/page/home_page/children/annotate_class/annotate_class_logic.dart new file mode 100644 index 0000000..aa4d9e2 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/annotate_class/annotate_class_logic.dart @@ -0,0 +1,111 @@ +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/read_over_logic.dart'; +import 'package:making_school_asignment_app/page/home_page/home_logic.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'annotate_class_state.dart'; + +class AnnotateClassLogic extends GetxController with RequestToolMixin { + final AnnotateClassState state = AnnotateClassState(); + late final EasyRefreshController refreshController; + final HomeLogic homeController = Get.find(); + late ReadOverLogic readOverController; + + @override + void onInit() { + super.onInit(); + state.preIndex = Get.arguments['tabIndex'] ?? 3; + if (state.preIndex != 3) { + // readOverController = Get.find(); + } + refreshController = EasyRefreshController(); + state.homeworkId.value = Get.arguments['id'] ?? ''; + state.name.value = Get.arguments['name'] ?? ''; + state.grade = Get.arguments['grade']; + state.subject = Get.arguments['subject']; + state.completed.value = Get.arguments['completed'] ?? false; + + EasyLoading.show(status: 'loading...'); + getList(); + } + + void getList() async { + List data = + await getClient().getAnnotatedClassList(state.homeworkId.value); + state.classList.value = data; + /* print('state.classList[0]=${state.classList[0].finishTime}'); + print('state.classList[1]=${state.classList[1].finishTime}');*/ + for (var element in state.classList.value) { + int commitStudentCount = 0; + int noCommitStudentCount = 0; + for (var student in element.students) { + if (student.state == 0) { + noCommitStudentCount++; + } else { + commitStudentCount++; + } + } + element.commitStudentCount = commitStudentCount; + element.noCommitStudentCount = noCommitStudentCount; + } + + EasyLoading.dismiss(); + } + + //一键批阅 + void getAllCorrect(classId) async { + EasyLoading.show(status: 'loading...'); + try { + await getClient() + .getAllCorrect(state.homeworkId.value, classId) + .then((e) { + getList(); + }); + } catch (e) { + EasyLoading.dismiss(); + ToastUtils.showError('操作失败,请重试'); + } + } + +//结束批阅 + void getOverAnnotate(classId) async { + EasyLoading.show(status: 'loading...'); + try { + await getClient().overAnnotate(state.homeworkId.value, classId).then((e) { + getList(); + }); + } catch (e) { + EasyLoading.dismiss(); + ToastUtils.showError('操作失败,请重试'); + } + } + + void goQuickDataCheck(item) { + Get.toNamed(Routes.quickDataCheckPage, arguments: { + 'homeworkId': state.homeworkId.value, + 'classId': item.classId, + 'grade': state.grade, + 'className': item.className + }); + } + + void gojobReport(item) { + Get.toNamed(Routes.jobReportPage, arguments: { + 'title': state.name.value, + 'homeworkId': state.homeworkId.value, + 'grade': state.grade, + 'className': item.className + }); + } + + @override + void dispose() { + super.dispose(); + refreshController.dispose(); + } +} diff --git a/lib/page/home_page/children/annotate_class/annotate_class_state.dart b/making_school_asignment_app/lib/page/home_page/children/annotate_class/annotate_class_state.dart similarity index 63% rename from lib/page/home_page/children/annotate_class/annotate_class_state.dart rename to making_school_asignment_app/lib/page/home_page/children/annotate_class/annotate_class_state.dart index 1b079ae..815d8ad 100644 --- a/lib/page/home_page/children/annotate_class/annotate_class_state.dart +++ b/making_school_asignment_app/lib/page/home_page/children/annotate_class/annotate_class_state.dart @@ -1,14 +1,16 @@ import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/annotated_class.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.dart'; class AnnotateClassState { AnnotateClassState() { ///Initialize variables } - late RxString name = ''.obs; + late RxString name = ''.obs; late RxList classList = RxList(); late RxString homeworkId = ''.obs; late RxBool completed = false.obs; late int grade; + late int subject; + late int preIndex = 3; } diff --git a/making_school_asignment_app/lib/page/home_page/children/annotate_class/annotate_class_view.dart b/making_school_asignment_app/lib/page/home_page/children/annotate_class/annotate_class_view.dart new file mode 100644 index 0000000..638eb68 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/annotate_class/annotate_class_view.dart @@ -0,0 +1,145 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.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/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; +import 'package:making_school_asignment_app/page/home_page/children/annotate_class/widget/annotate_item.dart'; +import 'annotate_class_logic.dart'; +import 'widget/completed_annotate_item.dart'; + +class AnnotateClassPage extends StatefulWidget { + const AnnotateClassPage({super.key}); + + @override + State createState() => _AnnotateClassPageState(); +} + +class _AnnotateClassPageState extends State { + final logic = Get.find(); + final state = Get.find().state; + + @override + Widget build(BuildContext context) { + String homeworkId = state.homeworkId.value; + return AnnotatedRegion( + value: const SystemUiOverlayStyle( + systemNavigationBarColor:Colors.transparent, + systemNavigationBarDividerColor: null, + statusBarColor: Colors.transparent, + systemNavigationBarIconBrightness: Brightness.light, + statusBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.light, + ), + child: OrientationBuilder( + builder: (BuildContext context, Orientation orientation) { + return Scaffold( + backgroundColor: const Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + backgroundColor: Colors.white, + title: Obx(() { + return Text(state.name.value, + style: + TextStyle(fontSize: 14.sp, color: const Color(0xFF333333))); + }), + centerTitle: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () { + Get.back(); + }, + ), + actions: const [ + ReturnToHomepage(), + ], + ), + body: Padding( + padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r), + child: Obx(() { + return EasyRefresh( + firstRefresh: false, + taskIndependence: true, + controller: logic.refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + return logic.getList(); + }, + child: state.completed.value + ? Utils.isPad() + ? GridView( + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, //横轴三个子widget + mainAxisSpacing: 10.h, + crossAxisSpacing: 6.w, + childAspectRatio: 1.48 //宽高比为1时,子widget + ), + children: state.classList.map((taskItem) { + return CompletedAnnotateItem( + taskItem: taskItem, + logic: logic, + name: state.name.value, + ); + }).toList(), + ) + : ListView.builder( + itemCount: state.classList.length, + itemBuilder: (context, index) { + AnnotatedClass taskItem = state.classList[index]; + return CompletedAnnotateItem( + taskItem: taskItem, + logic: logic, + name: state.name.value, + ); + }) + : Utils.isPad() + ? MasonryGridView.count( + crossAxisCount: 2, //几列 + mainAxisSpacing: 4.w, // 间距 + crossAxisSpacing: 4.h, // 纵向间距? + itemCount: state.classList.length, + itemBuilder: (context, index) { + AnnotatedClass item = state.classList[index]; + return AnnotateItem( + homeworkId: homeworkId, + item: item, + font: 11.sp, + name: state.name.value, + logic: logic, + ); + }, + ) + : ListView.builder( + itemCount: state.classList.length, + itemBuilder: (context, index) { + AnnotatedClass item = state.classList[index]; + return AnnotateItem( + homeworkId: homeworkId, + item: item, + font: 12.sp, + name: state.name.value, + logic: logic, + ); + })); + }), + ), + ); + }), + ); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + if (state.preIndex != 3) { + // logic.readOverController.state.tabIndex.value = state.preIndex; + } else { + // logic.homeController.getList(); + } + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/annotate_class/widget/annotate_item.dart b/making_school_asignment_app/lib/page/home_page/children/annotate_class/widget/annotate_item.dart new file mode 100644 index 0000000..bed359a --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/annotate_class/widget/annotate_item.dart @@ -0,0 +1,350 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; +import 'package:making_school_asignment_app/page/global_widget/show_student_list.dart'; +import 'package:percent_indicator/percent_indicator.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.dart'; +import 'package:making_school_asignment_app/common/utils/enum_untils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/home_page/children/annotate_class/annotate_class_logic.dart'; +import 'package:making_school_asignment_app/page/home_page/children/annotate_class/widget/item_btn.dart'; +import 'package:making_school_asignment_app/page/home_page/widget/progress_bar.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +class AnnotateItem extends StatefulWidget { + final String homeworkId; + final AnnotatedClass item; + final double font; + final String name; + final AnnotateClassLogic logic; + const AnnotateItem({super.key, required this.homeworkId, required this.item, required this.font, required this.name, required this.logic}); + + @override + State createState() => _AnnotateItemState(); +} + +class _AnnotateItemState extends State { + Future confirmDialog(String text) async { + return await showDialog( + context: context, + builder: (context) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), // 设置圆角大小 + ), + actionsPadding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 10.r), + content: SizedBox( + width: 200.r, + child: Text( + text, + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF505E6E)), + ), + ), + actionsAlignment: MainAxisAlignment.center, + actions: [ + InkWell( + child: Container( + width: 97.r, + height: 27.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.r)), + color: Theme.of(context).primaryColor, + ), + child: const Center( + child: Text( + '确定', + style: TextStyle(color: Colors.white), + ))), + onTap: () { + // 执行操作 + Get.back(result: true); + }, + ), + InkWell( + onTap: () { + Get.back(result: false); + }, + child: Container( + width: 97.r, + height: 27.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.r)), + color: const Color(0xFFF4F4F4), + ), + child: const Center( + child: Text( + '取消', + style: TextStyle(color: Color(0xFF666666)), + ))), + ), + ], + ), + ); + } + + void showStudentList(context, List students, [bool submitted = false]) async { + showDialog( + context: context, + builder: (BuildContext context) { + return ShowStudentList( + title: '${widget.item.className ?? ''} ${submitted ? '已提交' : '未提交'}作业学生', + studentList: students, + homeworkId: widget.homeworkId, + subject: widget.logic.state.subject, + ); + }, + ); + EasyLoading.dismiss(); + } + + @override + Widget build(BuildContext context) { + AnnotatedClass itemData = widget.item; + return Container( + padding: EdgeInsets.only(top: 10.r), + margin: EdgeInsets.only(bottom: 10.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadiusDirectional.circular(4.r), + boxShadow: const [BoxShadow(color: Color.fromRGBO(0, 0, 0, 0.15), blurRadius: 10)], + ), + child: Column( + children: [ + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.r), + child: Row( + children: [ + Text( + '${EnumUtils.formatGrade(widget.item.grade)}${widget.item.className}', + style: TextStyle(fontSize: widget.font, color: const Color(0xFF000000)), + ), + const Spacer(), + InkWell( + onTap: () { + EasyLoading.show(status: 'loading...'); + showStudentList(context, widget.item.commitStudent!, true); + }, + child: Text( + '已交:${widget.item.commitStudentCount}', + style: TextStyle(fontSize: widget.font - 2.sp, color: const Color(0xFF4CC793)), + ), + ), + SizedBox( + width: 20.r, + ), + InkWell( + onTap: () { + EasyLoading.show(status: 'loading...'); + showStudentList(context, widget.item.noCommitStudent!, true); + }, + child: Text( + '未交:${widget.item.noCommitStudentCount}', + style: TextStyle(fontSize: widget.font - 2.sp, color: const Color(0xFFFF5656)), + ), + ), + ], + ), + ), + SizedBox( + height: 10.r, + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 8.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: widget.item.finishTime != null + ? [ + Expanded( + flex: 4, + child: ItemBtn( + title: "收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}", + font: widget.font - 2.sp, + clickFunction: () { + Get.toNamed(Routes.favStudentPage, arguments: {'homeworkName': widget.name, 'classId': widget.item.classId, 'homeworkId': widget.logic.state.homeworkId.value, 'grade': widget.item.grade}); + }, + ), + ), + const Expanded(flex: 1, child: SizedBox()), + const Expanded(flex: 4, child: SizedBox()), + const Expanded(flex: 1, child: SizedBox()), + const Expanded(flex: 4, child: SizedBox()), + ] + : [ + Expanded( + flex: 4, + child: ItemBtn( + title: "一键批阅", + font: widget.font - 2.sp, + clickFunction: () async { + var confim = await confirmDialog('一键批阅后,默认学生答题结果全部正确, 是否进行此操作?'); + if (confim) { + widget.logic.getAllCorrect(widget.item.classId); + } + }, + bgColor: Theme.of(context).primaryColor, + ), + ), + const Expanded( + flex: 1, + child: Text(''), + ), + Expanded( + flex: 4, + child: ItemBtn( + title: "数据快查", + font: widget.font - 2.sp, + clickFunction: () { + widget.logic.goQuickDataCheck(widget.item); + }, + ), + ), + const Expanded( + flex: 1, + child: Text(''), + ), + Expanded( + flex: 4, + child: ItemBtn( + title: "收藏夹${widget.item.homeworkFavs.isNotEmpty ? '(${widget.item.homeworkFavs.length})' : ''}", + font: widget.font - 2.sp, + clickFunction: () { + Get.toNamed(Routes.favStudentPage, arguments: {'homeworkName': widget.name, 'classId': widget.item.classId, 'homeworkId': widget.logic.state.homeworkId.value, 'grade': widget.item.grade}); + }, + ), + ), + ], + ), + ), + Padding( + padding: EdgeInsets.only(top: 10.r, left: 14.r, right: 14.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [quickText('批阅进度', size: widget.font - 2.sp, color: const Color(0xFF8E8E8E)), quickText('${widget.item.annotateRate}%', size: widget.font + 10.sp, color: const Color(0xFF464646))], + ), + ), + Padding( + padding: EdgeInsets.only(top: 0.r, left: 14.r, right: 14.r, bottom: 10.r), + child: LinearPercentIndicator( + padding: EdgeInsets.zero, + animation: true, + lineHeight: 8.h, + animationDuration: 2500, + + percent: widget.item.annotateRate / 100, + linearGradient: LinearGradient( + tileMode: TileMode.mirror, + stops: const [0.0, 1.0], + colors: widget.item.annotateRate / 100 != 1 + ? [Theme.of(context).primaryColor.withOpacity(0.1), Theme.of(context).primaryColor] + : [ + const Color.fromRGBO(144, 224, 190, 1).withOpacity(0.1), + const Color.fromRGBO(144, 224, 190, 1), + ], + ), + // linearStrokeCap: LinearStrokeCap.butt, + // progressColor: Theme.of(context).primaryColor, + backgroundColor: const Color.fromRGBO(232, 232, 232, 1), + barRadius: Radius.circular(10.r), + ), + ), + ProgressBar(title: '客观题正确率:', color: const Color(0xFFADDCA5), percent: widget.item.kgtCorrectRate / 100, marginEdg: EdgeInsets.zero, padingEdg: EdgeInsets.only(top: 8.h, left: 14.r, right: 14.r), fontSize: widget.font - 2.sp), + ProgressBar(title: '主观题正确率:', color: const Color(0xFFADDCA5), percent: widget.item.zgtCorrectRate / 100, padingEdg: EdgeInsets.symmetric(horizontal: 10.r), marginEdg: EdgeInsets.only(top: 8.h), fontSize: widget.font - 2.sp), + ProgressBar(title: '总正确率:', color: const Color(0xFFADDCA5), percent: widget.item.correctRate / 100, padingEdg: EdgeInsets.symmetric(horizontal: 10.r), marginEdg: EdgeInsets.only(top: 8.h), fontSize: widget.font - 2.sp), + Container( + margin: EdgeInsets.only(top: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.only(bottomLeft: Radius.circular(4.r), bottomRight: Radius.circular(4.r)), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.15), + offset: Offset(0, -0.0001), //阴影y轴偏移量 + blurRadius: 4, //阴影模糊程度 + spreadRadius: 0, //阴影扩散程度 + ) + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: widget.item.finishTime != null + ? [ + Expanded( + child: InkWell( + onTap: () { + widget.logic.goQuickDataCheck(widget.item); + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 10.r), + decoration: BoxDecoration(border: Border(right: BorderSide(width: 1.r, color: const Color.fromRGBO(221, 221, 221, 1)))), + alignment: Alignment.center, + child: quickText('数据快查', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font), + ), + ), + ), + // Container(width: 1.w, height: 30.h, color: const Color.fromRGBO(221, 221, 221, 1)), + Expanded( + child: InkWell( + onTap: () { + widget.logic.gojobReport(widget.item); + }, + child: Container( + alignment: Alignment.center, + child: quickText('查看报告', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font), + ), + )), + ] + : [ + Expanded( + child: InkWell( + onTap: () => easyThrottle('TO_GO_REVIEWHOMEWORK', () async { + await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); + WidgetsBinding.instance.addPostFrameCallback((_) { + Future.delayed(const Duration(milliseconds: 300), () { + Get.toNamed(Routes.reviewHomework, arguments: { + 'homeworkId': widget.homeworkId, + 'homeworkName': widget.name, + 'classId': itemData.classId, + 'subject': widget.logic.state.subject, + }); + }); + }); + + // Get.toNamed(Routes.reviewHomework, arguments: { + // 'homeworkId': widget.homeworkId, + // 'homeworkName': widget.name, + // 'classId': itemData.classId, + // 'subject': widget.logic.state.subject, + // }); + }), + child: Container( + padding: EdgeInsets.symmetric(vertical: 10.r), + decoration: BoxDecoration(border: Border(right: BorderSide(width: 1.r, color: const Color.fromRGBO(221, 221, 221, 1)))), + alignment: Alignment.center, + child: quickText('批阅', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font), + ), + ), + ), + // Container(width: 1.w, height: 30.h, color: const Color.fromRGBO(221, 221, 221, 1)), + Expanded( + child: InkWell( + onTap: () async { + var confim = await confirmDialog('当前批阅任务未完成,请确认需要结束此任务?'); + if (confim) { + widget.logic.getOverAnnotate(widget.item.classId); + } + }, + child: Container( + alignment: Alignment.center, + child: quickText('结束批阅', color: const Color.fromRGBO(118, 118, 118, 1), size: widget.font), + ), + )), + ], + ), + ) + ], + ), + ); + } +} diff --git a/lib/page/home_page/children/annotate_class/widget/completed_annotate_item.dart b/making_school_asignment_app/lib/page/home_page/children/annotate_class/widget/completed_annotate_item.dart similarity index 68% rename from lib/page/home_page/children/annotate_class/widget/completed_annotate_item.dart rename to making_school_asignment_app/lib/page/home_page/children/annotate_class/widget/completed_annotate_item.dart index c657bb7..a71bbc3 100644 --- a/lib/page/home_page/children/annotate_class/widget/completed_annotate_item.dart +++ b/making_school_asignment_app/lib/page/home_page/children/annotate_class/widget/completed_annotate_item.dart @@ -2,23 +2,30 @@ import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/annotated_class.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; -import 'package:school_asignment_app/page/global_widget/show_student_list.dart'; -import 'package:school_asignment_app/page/home_page/children/annotate_class/annotate_class_logic.dart'; -import 'package:school_asignment_app/page/home_page/widget/progress_bar.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.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/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/widget/progress_bar.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; class CompletedAnnotateItem extends StatelessWidget { final AnnotatedClass taskItem; final AnnotateClassLogic logic; - const CompletedAnnotateItem({Key? key,required this.taskItem,required this.logic}) : super(key: key); + final String name; + const CompletedAnnotateItem({Key? key, required this.taskItem, required this.logic,required this.name}) : super(key: key); - void showStudentList(context,List students,[bool submitted = false]) async { + void showStudentList(context, List students, [bool submitted = false]) async { showDialog( context: context, builder: (BuildContext context) { - return ShowStudentList(title:'${taskItem.className ?? ''} ${submitted ? '已提交' : '未提交'}作业学生',studentList:students,homeworkId: logic.state.homeworkId.value,); + return ShowStudentList( + title: '${taskItem.className ?? ''} ${submitted ? '已提交' : '未提交'}作业学生', + studentList: students, + homeworkId: logic.state.homeworkId.value, + subject:logic.state.subject, + ); }, ); EasyLoading.dismiss(); @@ -37,23 +44,23 @@ class CompletedAnnotateItem extends StatelessWidget { decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Color.fromRGBO(238, 238, 238, 1), width: 0.5.r)), ), - child: quickText(taskItem.className, color: Color.fromRGBO(104, 136, 253, 1), size: 12.sp), + child: quickText(taskItem.className, color: Theme.of(context).primaryColor, size: 12.sp), ), Column( mainAxisSize: MainAxisSize.min, children: [ ProgressBar( - color: Color.fromRGBO(76, 199, 147, 1), - percent: taskItem.kgtCorrectRate/100, + color: const Color(0xFFADDCA5), + percent: taskItem.kgtCorrectRate / 100, title: '客观题正确率:', - padingEdg: EdgeInsets.only(left: 10.w, right: 10.w), + padingEdg: EdgeInsets.only(left: 10.w, right: 10.w), fontSize: 8.sp, lineHeight: 5.h, marginEdg: EdgeInsets.only(top: 5.h), ), ProgressBar( - color: Color.fromRGBO(76, 199, 147, 1), - percent: taskItem.zgtCorrectRate / 100, + color: const Color(0xFFADDCA5), + percent: taskItem.zgtCorrectRate / 100, title: '主观题正确率:', fontSize: 8.sp, lineHeight: 5.h, @@ -61,7 +68,7 @@ class CompletedAnnotateItem extends StatelessWidget { marginEdg: EdgeInsets.only(top: 5.h), ), ProgressBar( - color: Color.fromRGBO(76, 199, 147, 1), + color: const Color(0xFFADDCA5), percent: taskItem.correctRate / 100, title: '总正确率:', fontSize: 8.sp, @@ -71,7 +78,7 @@ class CompletedAnnotateItem extends StatelessWidget { ), ], ), - SizedBox(height: Utils.isPad()?4.h:10.h), + SizedBox(height: Utils.isPad() ? 4.h : 10.h), Padding( padding: EdgeInsets.only(left: 10.w, right: 10.w), child: Row( @@ -80,12 +87,12 @@ class CompletedAnnotateItem extends StatelessWidget { Expanded( flex: 4, child: Material( - color: Color.fromRGBO(244, 244, 244, 1), + color: Theme.of(context).primaryColor, borderRadius: BorderRadius.circular(16.r), child: InkWell( - onTap: (){ + onTap: () { EasyLoading.show(status: 'loading...'); - showStudentList(context,taskItem.commitStudent!,true); + showStudentList(context, taskItem.commitStudent!, true); }, borderRadius: BorderRadius.circular(8.r), splashColor: Theme.of(context).primaryColor, @@ -95,8 +102,7 @@ class CompletedAnnotateItem extends StatelessWidget { decoration: BoxDecoration( borderRadius: BorderRadius.circular(20.r), ), - child: quickText('已提交:${taskItem.commitStudentCount}', - size: 8.sp, color: Color.fromRGBO(102, 102, 102, 1)), + child: quickText('已提交:${taskItem.commitStudentCount}', size: 8.sp, color: Colors.white), ), ), ), @@ -110,7 +116,7 @@ class CompletedAnnotateItem extends StatelessWidget { child: InkWell( onTap: () { EasyLoading.show(status: 'loading...'); - showStudentList(context,taskItem.noCommitStudent!); + showStudentList(context, taskItem.noCommitStudent!); }, splashColor: Theme.of(context).primaryColor, borderRadius: BorderRadius.circular(8.r), @@ -118,8 +124,7 @@ class CompletedAnnotateItem extends StatelessWidget { alignment: Alignment.center, padding: EdgeInsets.symmetric(vertical: 4.h), decoration: BoxDecoration(borderRadius: BorderRadius.circular(20.r)), - child: quickText('未提交:${taskItem.noCommitStudentCount}', - size: 8.sp, color: Color.fromRGBO(102, 102, 102, 1)), + child: quickText('未提交:${taskItem.noCommitStudentCount}', size: 8.sp, color: Color.fromRGBO(102, 102, 102, 1)), ), ), ), @@ -132,7 +137,7 @@ class CompletedAnnotateItem extends StatelessWidget { borderRadius: BorderRadius.circular(20.r), child: InkWell( onTap: () { - + Get.toNamed(Routes.favStudentPage,arguments: {'homeworkName':name,'classId':taskItem.classId,'homeworkId':logic.state.homeworkId.value,'grade':taskItem.grade}); }, splashColor: Theme.of(context).primaryColor, borderRadius: BorderRadius.circular(8.r), @@ -140,15 +145,14 @@ class CompletedAnnotateItem extends StatelessWidget { alignment: Alignment.center, padding: EdgeInsets.symmetric(vertical: 4.h), decoration: BoxDecoration(borderRadius: BorderRadius.circular(20.r)), - child: quickText('收藏夹', - size: 8.sp, color: Color.fromRGBO(102, 102, 102, 1)), + child: quickText('收藏夹${taskItem.homeworkFavs.isNotEmpty?'(${taskItem.homeworkFavs.length})':''}', size: 8.sp, color: Color.fromRGBO(102, 102, 102, 1)), ), ), )), ], ), ), - SizedBox(height: Utils.isPad()?4.h:10.h), + SizedBox(height: Utils.isPad() ? 4.h : 10.h), Container( decoration: BoxDecoration( borderRadius: BorderRadius.only( @@ -169,7 +173,7 @@ class CompletedAnnotateItem extends StatelessWidget { Expanded( child: InkWell( onTap: () { - logic.goQuickDataCheck(taskItem); + logic.goQuickDataCheck(taskItem); }, child: Container( alignment: Alignment.center, @@ -180,14 +184,14 @@ class CompletedAnnotateItem extends StatelessWidget { Container(width: 1.w, height: 26.h, color: Color.fromRGBO(221, 221, 221, 1)), Expanded( child: InkWell( - onTap: (){ - logic.gojobReport(taskItem); - }, - child: Container( - alignment: Alignment.center, - child: quickText('查看报告', color: Color.fromRGBO(118, 118, 118, 1), size: 10.sp), - ), - )), + onTap: () { + logic.gojobReport(taskItem); + }, + child: Container( + alignment: Alignment.center, + child: quickText('查看报告', color: Color.fromRGBO(118, 118, 118, 1), size: 10.sp), + ), + )), ]), ), ], diff --git a/lib/page/home_page/children/annotate_class/widget/item_btn.dart b/making_school_asignment_app/lib/page/home_page/children/annotate_class/widget/item_btn.dart similarity index 63% rename from lib/page/home_page/children/annotate_class/widget/item_btn.dart rename to making_school_asignment_app/lib/page/home_page/children/annotate_class/widget/item_btn.dart index fa50059..0577a75 100644 --- a/lib/page/home_page/children/annotate_class/widget/item_btn.dart +++ b/making_school_asignment_app/lib/page/home_page/children/annotate_class/widget/item_btn.dart @@ -4,29 +4,33 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; class ItemBtn extends StatelessWidget { final String title; final double font; + final Color? bgColor; final Function? clickFunction; - const ItemBtn({Key? key,required this.title,required this.font,this.clickFunction}) : super(key: key); + const ItemBtn({Key? key,required this.title,required this.font,this.clickFunction,this.bgColor}) : super(key: key); @override Widget build(BuildContext context) { return SizedBox( - height:20.r, + height:25.r, child: ElevatedButton( + style: ButtonStyle( - overlayColor:MaterialStateProperty.all( - const Color(0xFF6888FD)), + overlayColor:WidgetStateProperty.all( + const Color(0xFFE8E8E8)), backgroundColor: - MaterialStateProperty.all( - const Color(0xFFF4F4F4)), + WidgetStateProperty.all( + bgColor??const Color(0xFFF4F4F4)), // foregroundColor: MaterialStateProperty.all(Colors.red.shade200),//文字颜色 - shape: MaterialStateProperty.all( + shape: WidgetStateProperty.all( RoundedRectangleBorder( borderRadius: BorderRadius.circular(22), //设置圆角 )), - padding: MaterialStateProperty.all( + padding: WidgetStateProperty.all( EdgeInsets.zero, - )), + ), + elevation: WidgetStateProperty.all(0), + ), onPressed: () { clickFunction!(); }, @@ -34,7 +38,7 @@ class ItemBtn extends StatelessWidget { title, style: TextStyle( fontSize: font, - color: const Color(0xFF666666)), + color: bgColor != null?Colors.white:const Color(0xFF666666)), )), ); } diff --git a/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/answer_trajectory_binding.dart b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/answer_trajectory_binding.dart new file mode 100644 index 0000000..014d7c6 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/answer_trajectory_binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; + +import 'answer_trajectory_logic.dart'; + +class AnswerTrajectoryBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => AnswerTrajectoryLogic()); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/answer_trajectory_logic.dart b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/answer_trajectory_logic.dart new file mode 100644 index 0000000..e97dd17 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/answer_trajectory_logic.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/class_item.dart'; +import 'package:making_school_asignment_app/common/job/work_student.dart'; +import 'package:making_school_asignment_app/common/job/work_student_params.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'answer_trajectory_state.dart'; + +class AnswerTrajectoryLogic extends GetxController with RequestToolMixin, GetTickerProviderStateMixin{ + final AnswerTrajectoryState state = AnswerTrajectoryState(); + late TabController tabController; + late final EasyRefreshController refreshController; + late final EasyRefreshController refreshController2; + @override + void onInit(){ + super.onInit(); + refreshController = EasyRefreshController(); + refreshController2 = EasyRefreshController(); + tabController = + TabController(initialIndex: state.tabIndex.value, length: 2, vsync: this); + getStudentGroups(); + getWorkList(); + } + + goNextPage(id, title,subject) { + Get.toNamed(Routes.classStudentPage,arguments: {'title':title,'classId':id,'page':'answerTrajectory','subject':subject}); + } + + void getStudentGroups() async{ + List data = await getClient().getStudentClass(); + state.studentGroups.value = data; + EasyLoading.dismiss(); + refreshController.finishRefresh(); + } + + void getWorkList() async{ + WorkStudentParams params = WorkStudentParams( + assessType: 0, + pageSize: 10, + ); + params.pageNumber = state.page; + WorkStudent data = await getClient().getAnnotatedList(params); + state.jobList.value = data.items; + EasyLoading.dismiss(); + refreshController2.finishRefresh(); + } + + @override + void dispose(){ + super.dispose(); + tabController.dispose(); + refreshController.dispose(); + refreshController2.dispose(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/answer_trajectory_state.dart b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/answer_trajectory_state.dart new file mode 100644 index 0000000..c8e7c1f --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/answer_trajectory_state.dart @@ -0,0 +1,15 @@ +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/class_item.dart'; +import 'package:making_school_asignment_app/common/job/work_student.dart'; + +class AnswerTrajectoryState { + AnswerTrajectoryState() { + ///Initialize variables + } + + late RxInt tabIndex = 0.obs; + late RxList studentGroups = RxList(); + late RxList jobList = RxList(); + late int page = 1; + late int total = 0; +} diff --git a/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/answer_trajectory_view.dart b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/answer_trajectory_view.dart new file mode 100644 index 0000000..a6f5606 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/answer_trajectory_view.dart @@ -0,0 +1,181 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; +import 'package:making_school_asignment_app/page/home_page/children/answer_trajectory/widget/answer_trajectory_job.dart'; +import 'package:making_school_asignment_app/page/home_page/widget/student_group_list.dart'; + +import 'answer_trajectory_logic.dart'; + +class AnswerTrajectoryPage extends StatefulWidget { + const AnswerTrajectoryPage({Key? key}) : super(key: key); + + @override + State createState() => _AnswerTrajectoryPageState(); +} + +class _AnswerTrajectoryPageState extends State { + final logic = Get.find(); + final state = Get + .find() + .state; + + @override + Widget build(BuildContext context) { + return OrientationBuilder( + builder: (BuildContext context, Orientation orientation){ + return Scaffold( + backgroundColor: Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + backgroundColor: Colors.white, + title: Text( + '答题轨迹', + style: TextStyle(fontSize: 14.sp, color: Color(0xFF333333)), + ), + centerTitle: true, + leading: IconButton( + icon: Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Get.back(), + ), + actions: const [ + ReturnToHomepage(), + ], + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 10.r, + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 14.r), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide(width: 1.r, color: Color(0xFFCCCCCC)))), + child: TabBar( + dividerHeight: 0, + tabAlignment: TabAlignment.start, + indicator: const UnderlineTabIndicator( + borderSide: BorderSide( + color: Color(0xFF8C68FF), + ), + + ), + onTap: (int val) { + state.tabIndex.value = val; + // EasyLoading.show(status: 'loading...'); + /* if(val == 0){ + logic.getStudentGroups(); + }else{ + logic.getWorkList(); + }*/ + }, + tabs: [ + SizedBox( + width: (MediaQuery + .of(context) + .size + .width - 28.r) / 2, + child: const Tab( + text: '按学生', + ), + ), + SizedBox( + width: (MediaQuery + .of(context) + .size + .width - 28.r) / 2, + child: const Tab( + text: '按作业', + ), + ) + ], + controller: logic.tabController, + unselectedLabelStyle: + TextStyle(fontSize: 14.sp, color: Color(0xFF666666)), + labelStyle: TextStyle( + fontSize: 14.sp, + color: Color(0xFF8C68FF), + ), + isScrollable: true, + labelColor: Color(0xFF8C68FF), + unselectedLabelColor: Color(0xFF666666), + indicatorSize: TabBarIndicatorSize.label, + labelPadding: const EdgeInsets.all(0), + ), + ), + Obx(() { + return Expanded( + child: Padding( + padding: + EdgeInsets.only(top: 15.r, left: 14.r, right: 14.r), + child: + state.tabIndex.value == 0 + ? + EasyRefresh( + firstRefresh: false, + taskIndependence: true, + controller: logic.refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + logic.getStudentGroups(); + }, + child: StudentGroupList( + state.studentGroups, logic.goNextPage, + rightBtn: Container( + margin: EdgeInsets.only(left: 5.r), + height: 20.r, + width: 55.r, + decoration: BoxDecoration( + borderRadius: + BorderRadius.all(Radius.circular(20.r)), + border: Border.all( + width: 1.r, color: Color(0xFF7EB752)), + ), + child: Center( + child: Text( + '详情', + style: TextStyle( + fontSize: 10.sp, color: Color(0xFF7EB752)), + ), + ), + )), + ) : EasyRefresh( + firstRefresh: false, + taskIndependence: true, + controller: logic.refreshController2, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + state.page = 1; + logic.getWorkList(); + }, + onLoad: () async { + if (state.jobList.length < state.total) { + EasyLoading.show(status: 'loading...'); + state.page = state.page + 1; + logic.getWorkList(); + } + }, + child: AnswerTrajectoryJob(state.jobList.value)), + ), + ); + }) + ], + ), + ); + } + ); + + + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} \ No newline at end of file diff --git a/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/widget/answer_trajectory_job.dart b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/widget/answer_trajectory_job.dart new file mode 100644 index 0000000..2b8b756 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory/widget/answer_trajectory_job.dart @@ -0,0 +1,291 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/work_student.dart'; +import 'package:making_school_asignment_app/common/utils/enum_untils.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +class AnswerTrajectoryJob extends StatelessWidget { + final List jobList; + + const AnswerTrajectoryJob(this.jobList, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return jobList != null && jobList.isNotEmpty + ? Utils.isPad() + ? GridView( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, //横轴三个子widget + mainAxisSpacing: 10.h, + crossAxisSpacing: 6.w, + childAspectRatio: 2.4 //宽高比为1时,子widget + ), + children: List.generate(jobList.length, (index) { + Items item = jobList[index]; + return InkWell( + onTap: () { + Get.toNamed(Routes.answerTrajectoryDetailPage,arguments: {'homeworkId':item.id,'title':item.name,'grade':item.grade,'subject':item.subject}); + }, + child: Container( + padding: EdgeInsets.only(top: 10.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.r), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(210, 216, 241, 1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 5.8, //阴影模糊程度 + spreadRadius: 0, //阴影扩散程度 + ) + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 顶部任务名称 + Padding( + padding: EdgeInsets.symmetric(horizontal: 6.w), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 32.w, + height: 22.h, + alignment: Alignment.center, + // padding: EdgeInsets.only(left: 2.w), + decoration: BoxDecoration( + color:Theme.of(context).primaryColor, + borderRadius: BorderRadius.all( + Radius.circular(5.r) + ), + ), + margin: EdgeInsets.only(top:3.h,right: 4.w), + child: quickText( + item.assessType == 0 ? '作业' : '考试', + color: Colors.white, + size: 10.sp), + ), + Expanded( + child: quickText(item.name, + size: 12.sp, + color: Color.fromRGBO(70, 70, 70, 1), + maxLines: 2), + ), + SizedBox( + width: 5.r, + ), + Container( + padding: EdgeInsets.symmetric( + vertical: 1.r, horizontal: 5.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4.r), + border: Border.all( + width: 1.r, color: Theme.of(context).primaryColor), + ), + child: Center( + child: Text( + EnumUtils.formatSubject(item.subject), + style: TextStyle( + fontSize: 8.r, + color: Theme.of(context).primaryColor), + ), + ), + ) + ], + ), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 6.r), + child: Text( + '时间:${item.publishTime.substring(0, 10)}', + style: TextStyle(fontSize: 10.sp), + ), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 6.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(6.r), + bottomRight: Radius.circular(6.r)), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.15), + offset: Offset(0, -0.0001), //阴影y轴偏移量 + blurRadius: 4, //阴影模糊程度 + spreadRadius: 0, //阴影扩散程度 + ) + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + alignment: Alignment.center, + child: quickText('详情', + color: Color(0xFFFFA115), size: 10.sp), + ), + Image.asset( + 'assets/images/icon_back_orange.png', + width: 8.r, + height: 8.r, + ), + ]), + ), + ], + ), + ), + ); + }), + ) + : ListView.builder( + shrinkWrap: true, + physics: ClampingScrollPhysics(), + itemBuilder: (context, index) { + Items item = jobList[index]; + return InkWell( + onTap: () { + /* RouterManager.router.navigateTo(context, + '${RouterManager.answerTrajectoryJobDetailPath}?&jobId=${item.id}&jobName=${Uri.encodeComponent(item.title)}&genderName=${Uri.encodeComponent(item.genderName)}', + transition: getTransition());*/ + }, + child: Container( + margin: EdgeInsets.symmetric(vertical: 10.r), + padding: EdgeInsets.only(top: 10.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.r), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(210, 216, 241, 1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 5.8, //阴影模糊程度 + spreadRadius: 0, //阴影扩散程度 + ) + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 顶部任务名称 + Padding( + padding: EdgeInsets.symmetric( + vertical: 14.r, horizontal: 14.r), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 32.w, + height: 22.h, + alignment: Alignment.center, + // padding: EdgeInsets.only(left: 2.w), + decoration: BoxDecoration( + color:Theme.of(context).primaryColor, + borderRadius: BorderRadius.all( + Radius.circular(5.r) + ), + ), + margin: EdgeInsets.only(top:3.h,right: 4.w), + child: quickText( + item.assessType == 0 ? '作业' : '考试', + color: Colors.white, + size: 10.sp), + ), + Expanded( + child: quickText(item.name, + size: 14.sp, + color: Color.fromRGBO(70, 70, 70, 1), + maxLines: 2), + ), + SizedBox( + width: 5.r, + ), + Container( + padding: EdgeInsets.symmetric( + vertical: 1.r, horizontal: 5.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4.r), + border: Border.all( + width: 1.r, color: Theme.of(context).primaryColor), + ), + child: Center( + child: Text( + EnumUtils.formatSubject(item.subject), + style: TextStyle( + fontSize: 12.r, + color: Theme.of(context).primaryColor), + ), + ), + ) + ], + ), + ), + SizedBox( + height: 5.r, + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 14.r), + child: Text( + '时间:${item.publishTime.substring(0, 10)}', + style: TextStyle(fontSize: 10.sp), + ), + ), + SizedBox( + height: 10.r, + ), + Container( + height: 1.r, + color: Color(0xFFF5F5F5), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(6.r), + bottomRight: Radius.circular(6.r)), + color: Colors.white, + /*boxShadow: [ + BoxShadow( + color: const Color.fromRGBO(0, 0, 0, 0.15), + offset: Offset(0, -0.0001), //阴影y轴偏移量 + blurRadius: 4, //阴影模糊程度 + spreadRadius: 0, //阴影扩散程度 + ) + ],*/ + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + alignment: Alignment.center, + child: quickText('详情', + color: Color(0xFFFFA115), size: 10.sp), + ), + Image.asset( + 'assets/images/icon_back_orange.png', + width: 8.r, + height: 8.r, + ), + ]), + ), + ], + ), + ), + ); + }, + itemCount: jobList.length, + ) + : const MyEmptyWidget(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_binding.dart b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_binding.dart new file mode 100644 index 0000000..a87bb20 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; + +import 'answer_trajectory_detail_logic.dart'; + +class AnswerTrajectoryDetailBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => AnswerTrajectoryDetailLogic()); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_logic.dart b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_logic.dart new file mode 100644 index 0000000..097855f --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_logic.dart @@ -0,0 +1,38 @@ +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; + +import 'answer_trajectory_detail_state.dart'; + +class AnswerTrajectoryDetailLogic extends GetxController with RequestToolMixin{ + final AnswerTrajectoryDetailState state = AnswerTrajectoryDetailState(); + late final EasyRefreshController refreshController; + @override + void onInit(){ + super.onInit(); + state.homeworkId.value = Get.arguments['homeworkId'] ?? ''; + state.title.value = Get.arguments['title'] ?? ''; + state.grade = Get.arguments['grade'] ?? -1; + state.subject = Get.arguments['subject'] ?? -1; + refreshController = EasyRefreshController(); + EasyLoading.show(status: 'loading...'); + getList(); + } + + void getList() async{ + List data = await getClient().getAnnotatedClassList(state.homeworkId.value); + state.classList.value = data; + if( state.classList.isNotEmpty){ + state.currentClass.value = state.classList[0]; + } + EasyLoading.dismiss(); + } + + @override + void dispose(){ + super.dispose(); + refreshController.dispose(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_state.dart b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_state.dart new file mode 100644 index 0000000..3b1c603 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_state.dart @@ -0,0 +1,15 @@ +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.dart'; + +class AnswerTrajectoryDetailState { + AnswerTrajectoryDetailState() { + ///Initialize variables + } + + late RxString homeworkId = ''.obs; + late RxString title = ''.obs; + late int grade = -1; + late int subject = -1; + late RxList classList = RxList(); + late Rx currentClass=Rx(AnnotatedClass('',-1,'','','',-1,-1,-1,-1,-1,[],[],-1,-1,-1,-1,-1,[],[])); +} diff --git a/making_school_asignment_app/lib/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_view.dart b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_view.dart new file mode 100644 index 0000000..f5af960 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_view.dart @@ -0,0 +1,251 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.dart'; +import 'package:making_school_asignment_app/common/utils/enum_untils.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'answer_trajectory_detail_logic.dart'; + +class AnswerTrajectoryDetailPage extends StatefulWidget { + const AnswerTrajectoryDetailPage({Key? key}) : super(key: key); + + @override + State createState() => + _AnswerTrajectoryDetailPageState(); +} + +class _AnswerTrajectoryDetailPageState + extends State { + final logic = Get.find(); + final state = Get + .find() + .state; + + @override + Widget build(BuildContext context) { + return OrientationBuilder( + builder: (BuildContext context, Orientation orientation){ + return Scaffold( + backgroundColor: Color(0xFFF5F5F5), + appBar: AppBar( + centerTitle: true, + backgroundColor: Colors.white, + title: Obx(() { + return Text( + state.title.value, + style: TextStyle(fontSize: 14.sp, color: Color(0xFF333333)), + overflow: TextOverflow.ellipsis, + ); + }), + leading: IconButton( + icon: Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Get.back(), + ), + actions: const [ + ReturnToHomepage(), + ], + ), + body: Column( + children: [ + SizedBox( + height: 10.r, + ), + Obx(() { + return state.classList.isNotEmpty?Padding( + padding: EdgeInsets.symmetric(horizontal: 14.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: List.generate(state.classList.length, ( + index) { + AnnotatedClass item = state.classList[index]; + return InkWell( + onTap: () { + if (state.currentClass.value.classId != + item.classId) { + state.currentClass.value = item; + } + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 5.r, horizontal: 10.r), + margin: EdgeInsets.only( + right: index < state.classList.length + ? 8.r + : 0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(4.r), + ), + child: Center( + child: Text( + '${EnumUtils.formatGrade(state.grade)}${item + .className}', + style: TextStyle( + fontSize: 10.sp, + color: state.currentClass.value + .classId == item.classId + ? Theme.of(context).primaryColor + : Color(0xFF686868)), + ), + ), + ), + ); + })), + ), + ], + ), + ):Container(); + }), + SizedBox( + height: 10.r, + ), + Container( + height: 1.r, + color: const Color(0xFFCCCCCC), + ), + Obx((){ + return state.currentClass.value.students.isNotEmpty ? Expanded( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r), + child: EasyRefresh( + firstRefresh: true, + taskIndependence: true, + controller: logic.refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + // getStudentList(); + }, + child: state.currentClass.value.students.isNotEmpty + ? Utils.isPad() + ? GridView( + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + mainAxisSpacing: 10.r, + crossAxisSpacing: 10.r, + childAspectRatio: 556 / 112, + ), + children: List.generate( + state.currentClass.value.students.length, (index) { + AnnotatedStudents item = state.currentClass.value.students[index]; + return InkWell( + onTap: () { + Get.toNamed(Routes.studentPersonalPage, arguments: {'studentId': item.studentId, 'homeworkId': state.homeworkId.value,'subject':state.subject}); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10.r), + decoration: BoxDecoration( + borderRadius: + BorderRadius.all(Radius.circular(10.r)), + color: Colors.white, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + item.studentName, + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF5E5E5E)), + )), + + Container( + height: 20.r, + width: 70.r, + decoration: BoxDecoration( + border: Border.all( + width: 1.r, color: Color(0xFFB2DA93)), + borderRadius: BorderRadius.all( + Radius.circular(20.r)), + + ), + child: Center(child: Text('详情', + style: TextStyle(fontSize: 10.r, + color: Color(0xFFB2DA93))), + )), + ], + ), + ), + ); + }), + ) + : ListView.builder( + itemBuilder: (context, index) { + AnnotatedStudents item = state.currentClass.value + .students[index]; + return InkWell( + onTap: () { + Get.toNamed(Routes.studentPersonalPage, arguments: {'studentId': item.studentId, 'homeworkId': state.homeworkId.value,'subject':state.subject}); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 20.r, horizontal: 15.r), + margin: EdgeInsets.only(bottom: 15.r), + decoration: BoxDecoration( + borderRadius: + BorderRadius.all(Radius.circular(10.r)), + color: Colors.white, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + item.studentName, + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF5E5E5E)), + )), + Container( + height: 24.r, + width: 72.r, + decoration: BoxDecoration( + border: Border.all( + width: 1.r, color: Color(0xFFB2DA93)), + borderRadius: BorderRadius.all( + Radius.circular(20.r)), + + ), + child: Center(child: Text('详情', + style: TextStyle(fontSize: 10.r, + color: Color(0xFFB2DA93))), + )), + ], + ), + ), + ); + }, + itemCount: state.currentClass.value.students.length, + ) + : const MyEmptyWidget(), + ), + ), + ) : const MyEmptyWidget(); + }), + ], + ), + ); + } + ); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} \ No newline at end of file diff --git a/lib/page/home_page/children/class_student/class_student_binding.dart b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_binding.dart similarity index 100% rename from lib/page/home_page/children/class_student/class_student_binding.dart rename to making_school_asignment_app/lib/page/home_page/children/class_student/class_student_binding.dart diff --git a/lib/page/home_page/children/class_student/class_student_logic.dart b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_logic.dart similarity index 57% rename from lib/page/home_page/children/class_student/class_student_logic.dart rename to making_school_asignment_app/lib/page/home_page/children/class_student/class_student_logic.dart index 41822f8..1efc3d5 100644 --- a/lib/page/home_page/children/class_student/class_student_logic.dart +++ b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_logic.dart @@ -2,39 +2,39 @@ import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; -import 'package:school_asignment_app/common/job/student_item.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.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 'class_student_state.dart'; -class ClassStudentLogic extends GetxController with RequestToolMixin{ +class ClassStudentLogic extends GetxController with RequestToolMixin { final ClassStudentState state = ClassStudentState(); late final EasyRefreshController refreshController; @override void onInit() { super.onInit(); - state.title.value = Get.arguments['title']??''; - state.classId = Get.arguments['classId']??''; - state.subject = Get.arguments['subject']??-1; - state.page = Get.arguments['page']??''; + state.title.value = Get.arguments['title'] ?? ''; + state.classId = Get.arguments['classId'] ?? ''; + state.subject = Get.arguments['subject'] ?? -1; + state.page = Get.arguments['page'] ?? ''; EasyLoading.show(status: 'loading...'); refreshController = EasyRefreshController(); getList(); } - void getList() async{ - List res = await getClient().getStudentList(state.classId,state.subject); + void getList() async { + List res = await getClient().getStudentList(state.classId, state.subject); state.studentList.value = res; - state.studentList.sort((a, b) => a.priorityAnnotate?-1:1); + state.studentList.sort((a, b) => a.priorityAnnotate ? -1 : 1); EasyLoading.dismiss(); refreshController.finishRefresh(); } - void setJobReadLevel(studentId,priorityAnnotate) async{ - if(state.isClicking){ + void setJobReadLevel(studentId, priorityAnnotate) async { + if (state.isClicking) { state.isClicking = false; - await getClient().getAnnotateStudent(state.classId,studentId,priorityAnnotate,state.subject); + await getClient().getAnnotateStudent(state.classId, studentId, priorityAnnotate, state.subject); state.isClicking = true; getList(); } diff --git a/lib/page/home_page/children/class_student/class_student_state.dart b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_state.dart similarity index 72% rename from lib/page/home_page/children/class_student/class_student_state.dart rename to making_school_asignment_app/lib/page/home_page/children/class_student/class_student_state.dart index d786f5a..bb2e695 100644 --- a/lib/page/home_page/children/class_student/class_student_state.dart +++ b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_state.dart @@ -1,12 +1,12 @@ import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/student_item.dart'; +import 'package:making_school_asignment_app/common/job/student_item.dart'; class ClassStudentState { ClassStudentState() { ///Initialize variables } - late RxString title = ''.obs; + late RxString title = ''.obs; late final String classId; late final int subject; late RxList studentList = RxList(); diff --git a/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_view.dart b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_view.dart new file mode 100644 index 0000000..88af4f0 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/class_student/class_student_view.dart @@ -0,0 +1,437 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/student_item.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/ReturnToHomepage.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'class_student_logic.dart'; + +class ClassStudentPage extends StatefulWidget { + const ClassStudentPage({Key? key}) : super(key: key); + + @override + State createState() => _ClassStudentPageState(); +} + +class _ClassStudentPageState extends State { + final logic = Get.find(); + final state = Get.find().state; + + @override + Widget build(BuildContext context) { + return OrientationBuilder( + builder: (BuildContext context, Orientation orientation){ + return Scaffold( + backgroundColor: const Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + backgroundColor: Colors.white, + title: Obx(() { + return Text( + state.title.value, + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF333333)), + ); + }), + centerTitle: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Get.back(), + ), + actions: const [ + ReturnToHomepage(), + ], + elevation: 0, + ), + body: Obx(() { + return EasyRefresh( + firstRefresh: false, + taskIndependence: true, + controller: logic.refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + logic.getList(); + }, + child: state.studentList.isNotEmpty + ? Utils.isPad() + ? GridView( + shrinkWrap: true, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + mainAxisSpacing: 0.r, + crossAxisSpacing: 0.r, + childAspectRatio: 556 / 90, + ), + children: + List.generate(state.studentList.length, (index) { + StudentItem item = state.studentList[index]; + return InkWell( + onTap: () { + // RouterManager.router.navigateTo(context, + // '${RouterManager.jobPersonalDetailPath}?studentId=${item.studentId}&studentName=${Uri.encodeComponent(item.studentName)}'); + Get.toNamed(Routes.studentWorkDetailPage, + arguments: { + 'studentName': item.name, + 'studentId': item.id, + 'subject':state.subject, + }); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10.r), + decoration: BoxDecoration( + borderRadius: + BorderRadius.all(Radius.circular(0.r)), + color: Colors.transparent, + border: Border(left: BorderSide(width: + (index + 1)%2 == 0? 1.r:0,color: const Color(0xFFA5A5A5)),bottom: BorderSide(width: 1.r,color: const Color(0xFFA5A5A5))) + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + item.name, + style: TextStyle( + fontSize: 12.sp, + color: Theme.of(context).primaryColor), + )), + state.page == 'answerTrajectory' + ? Container( + height: 20.r, + width: 70.r, + decoration: BoxDecoration( + border: Border.all( + width: 1.r, + color: const Color(0xFFB2DA93)), + borderRadius: BorderRadius.all( + Radius.circular(20.r)), + ), + child: Center( + child: Text('详情', + style: TextStyle( + fontSize: 10.r, + color: Color(0xFFB2DA93))), + )) + : state.page == 'history' + ? Container( + height: 20.r, + width: 70.r, + decoration: BoxDecoration( + color: + Theme.of(context).primaryColor, + borderRadius: + BorderRadius.all( + Radius.circular( + 20.r))), + child: Center( + child: Text( + '历史作业', + style: TextStyle( + fontSize: 10.r, + color: Colors.white), + )), + ) + : item.priorityAnnotate + ? InkWell( + onTap: () { + logic.setJobReadLevel( + item.id, false); + EasyLoading.show( + status: 'loading...'); + }, + child: Container( + height: 20.r, + width: 80.r, + decoration: BoxDecoration( + borderRadius: + BorderRadius.all( + Radius.circular( + 4.r)), + color: const Color( + 0xFFEBE4FF), + ), + child: Row( + crossAxisAlignment: + CrossAxisAlignment + .start, + children: [ + Padding( + padding: + EdgeInsets.only( + left: 3.r), + child: Image.asset( + 'assets/images/youx_icon_active.png', + width: 14.r, + height: 14.r, + ), + ), + Padding( + padding: + EdgeInsets.only( + top: 2.r, + left: 4.r), + child: Text( + '优先批阅', + style: TextStyle( + fontSize: 10.sp, + color: Theme.of(context).primaryColor), + ), + ), + ], + ), + ), + ) + : InkWell( + onTap: () { + logic.setJobReadLevel( + item.id, true); + EasyLoading.show( + status: 'loading...'); + }, + child: Container( + height: 20.r, + width: 80.r, + decoration: BoxDecoration( + borderRadius: + BorderRadius.all( + Radius.circular( + 4.r)), + color: const Color( + 0xFFE1E1E1), + ), + child: Row( + crossAxisAlignment: + CrossAxisAlignment + .start, + children: [ + Padding( + padding: + EdgeInsets.only( + left: 3.r), + child: Image.asset( + 'assets/images/youx_icon_default.png', + width: 14.r, + height: 14.r, + ), + ), + Padding( + padding: + EdgeInsets.only( + top: 2.r, + left: 4.r), + child: Text( + '优先批阅', + style: TextStyle( + fontSize: 10.sp, + color: const Color( + 0xFF8A9691)), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + }), + ) + : Padding( + padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r), + child: ListView.builder( + itemBuilder: (context, index) { + StudentItem item = state.studentList[index]; + return InkWell( + onTap: () { + // RouterManager.router.navigateTo(context, + // '${RouterManager.jobPersonalDetailPath}?studentId=${item.studentId}&studentName=${Uri.encodeComponent(item.studentName)}'); + Get.toNamed(Routes.studentWorkDetailPage, + arguments: { + 'studentName': item.name, + 'studentId': item.id, + 'subject':state.subject, + }); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 20.r, horizontal: 15.r), + margin: EdgeInsets.only(bottom: 15.r), + decoration: BoxDecoration( + borderRadius: + BorderRadius.all(Radius.circular(10.r)), + color: Colors.white, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + item.name, + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF4CC793)), + )), + state.page == 'answerTrajectory' + ? Container( + height: 24.r, + width: 72.r, + decoration: BoxDecoration( + border: Border.all( + width: 1.r, + color: const Color(0xFFB2DA93)), + borderRadius: BorderRadius.all( + Radius.circular(20.r)), + ), + child: Center( + child: Text('详情', + style: TextStyle( + fontSize: 10.r, + color: Color(0xFFB2DA93))), + )) + : state.page == 'history' + ? Container( + height: 24.r, + width: 82.r, + decoration: BoxDecoration( + color: Color(0xFF4CC793), + borderRadius: + BorderRadius.all( + Radius.circular( + 20.r))), + child: Center( + child: Text( + '历史作业', + style: TextStyle( + fontSize: 10.r, + color: Colors.white), + )), + ) + : item.priorityAnnotate + ? InkWell( + onTap: () { + logic.setJobReadLevel( + item.id, false); + EasyLoading.show( + status: 'loading...'); + }, + child: Container( + height: 24.r, + width: 82.r, + decoration: BoxDecoration( + borderRadius: + BorderRadius.all( + Radius.circular( + 4.r)), + color: Color(0xFFB7FFE0), + ), + child: Row( + crossAxisAlignment: + CrossAxisAlignment + .start, + children: [ + Padding( + padding: + EdgeInsets.only( + left: 3.r), + child: Image.asset( + 'assets/images/youx_icon_active.png', + width: 14.r, + height: 14.r, + ), + ), + Padding( + padding: + EdgeInsets.only( + top: 5.r, + left: 4.r), + child: Text( + '优先批阅', + style: TextStyle( + fontSize: 10.sp, + color: const Color( + 0xFF4CC793)), + ), + ), + ], + ), + ), + ) + : InkWell( + onTap: () { + logic.setJobReadLevel( + item.id, true); + EasyLoading.show( + status: 'loading...'); + }, + child: Container( + height: 24.r, + width: 82.r, + decoration: BoxDecoration( + borderRadius: + BorderRadius.all( + Radius.circular( + 4.r)), + color: const Color( + 0xFFE1E1E1), + ), + child: Row( + crossAxisAlignment: + CrossAxisAlignment + .start, + children: [ + Padding( + padding: + EdgeInsets.only( + left: 3.r), + child: Image.asset( + 'assets/images/youx_icon_default.png', + width: 14.r, + height: 14.r, + ), + ), + Padding( + padding: + EdgeInsets.only( + top: 5.r, + left: 4.r), + child: Text( + '优先批阅', + style: TextStyle( + fontSize: 10.sp, + color: const Color( + 0xFF8A9691)), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + }, + itemCount: state.studentList.length, + ), + ) + : const MyEmptyWidget(), + ); + }), + ); + } + ); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/fav_student/fav_student_binding.dart b/making_school_asignment_app/lib/page/home_page/children/fav_student/fav_student_binding.dart new file mode 100644 index 0000000..a5fa24f --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/fav_student/fav_student_binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; + +import 'fav_student_logic.dart'; + +class FavStudentBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => FavStudentLogic()); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/fav_student/fav_student_logic.dart b/making_school_asignment_app/lib/page/home_page/children/fav_student/fav_student_logic.dart new file mode 100644 index 0000000..e7c3827 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/fav_student/fav_student_logic.dart @@ -0,0 +1,80 @@ +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.dart'; +import 'package:making_school_asignment_app/common/job/common/base_page_data.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/favor_param.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/home_page/children/annotate_class/annotate_class_logic.dart'; + +import 'fav_student_state.dart'; + +class FavStudentLogic extends GetxController with RequestToolMixin { + final FavStudentState state = FavStudentState(); + final AnnotateClassLogic controller = Get.find(); + + @override + void onInit() { + super.onInit(); + state.homeworkName.value = Get.arguments['homeworkName']; + state.homeworkId = Get.arguments['homeworkId']; + state.grade = Get.arguments['grade']; + state.classId = Get.arguments['classId']; + EasyLoading.show(status: 'loading...'); + getClass(); + } + + void getClass() async { + List data = await getClient().getAnnotatedClassList(state.homeworkId); + state.involveClasses.value = data; + + state.involveClasses.value = [state.classData.value, ...(data ?? [])]; + for (var element in state.involveClasses) { + if (element.classId == state.classId && element.grade == state.grade) { + state.classData.value = element; + } + } + getList(); + } + + void getList() async { + BasePageData data = + await getClient().getFavList(state.homeworkName.value, state.classData.value.classId != '-1' ? state.classData.value.classId : ''); + List arr = []; + List groupList = []; + if(data.items.isNotEmpty){ + for(var item in data.items){ + arr.add(item.questionNo); + } + state.pageList.value = arr.toSet().toList(); + for(var page in state.pageList.value){ + var printList = data.items + .where((element) => element.questionNo == page) + .toList(); + groupList.add({"questionPage": page, "list": printList}); + } + groupList + .sort((a, b) => a['questionPage'].compareTo(b['questionPage'])); + } + state.favList.value = [...groupList]; + EasyLoading.dismiss(); + } + + void getDelete(student) async { + EasyLoading.show(status: 'loading...'); + try { + await getClient().toFavStudent(FavorParam( + homeworkId: state.homeworkId, + studentId: student.studentId, + templateId: student.templateId, + questionNo: student.questionNo, + isFav: false, + )); + getList(); + } catch (e) { + EasyLoading.dismiss(); + ToastUtils.showError('操作失败,请重试'); + } + } + +} diff --git a/making_school_asignment_app/lib/page/home_page/children/fav_student/fav_student_state.dart b/making_school_asignment_app/lib/page/home_page/children/fav_student/fav_student_state.dart new file mode 100644 index 0000000..89a5534 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/fav_student/fav_student_state.dart @@ -0,0 +1,18 @@ +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.dart'; + +class FavStudentState { + FavStudentState() { + ///Initialize variables + } + + late RxString homeworkName = ''.obs; + late String homeworkId = ''; + late int grade; + late String classId = ''; + late RxList favList = RxList(); + late RxList pageList = RxList(); + late RxList involveClasses = RxList(); + late AnnotatedClass defaultClass = AnnotatedClass('', -1, '-1', '', '', -1, -1, -1, -1, -1, [], [], -1, -1, -1, -1, -1, [], []); + late Rx classData = defaultClass.obs; +} diff --git a/making_school_asignment_app/lib/page/home_page/children/fav_student/fav_student_view.dart b/making_school_asignment_app/lib/page/home_page/children/fav_student/fav_student_view.dart new file mode 100644 index 0000000..e49e1fd --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/fav_student/fav_student_view.dart @@ -0,0 +1,390 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.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/ReturnToHomepage.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/home_page/children/fav_student/widget/favorite_student_dialog.dart'; +import 'package:making_school_asignment_app/page/home_page/children/job_report/widget/dropdown_selection.dart'; + +import 'fav_student_logic.dart'; + +class FavStudentPage extends StatefulWidget { + const FavStudentPage({Key? key}) : super(key: key); + + @override + State createState() => _FavStudentPageState(); +} + +class _FavStudentPageState extends State { + final logic = Get.find(); + final state = Get + .find() + .state; + + void showStudentDialog(BuildContext context, HomeworkFavs item, List groups) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + insetPadding: EdgeInsets.all(25.r), + content: FavoriteStudentDialog( + item: item, + group: groups, + deleteFav: logic.getDelete, + confirmDialog: confirmDialog), + contentPadding: const EdgeInsets.all(0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(15.r)))); + }, + ); + } + Future confirmDialog() async { + return await showDialog( + context: context, + builder: (context) => AlertDialog( + actionsPadding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 10.r), + content: Text( + '确定删除吗?', + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF505E6E)), + ), + actionsAlignment: MainAxisAlignment.center, + actions: [ + InkWell( + child: Container( + width: 97.r, + height: 27.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.r)), + color: Theme.of(context).primaryColor, + ), + child: const Center( + child: Text( + '确定', + style: TextStyle(color: Colors.white), + ))), + onTap: () { + // 执行操作 + // Navigator.of(context).pop(true); + Get.back(result: true); + }, + ), + InkWell( + onTap: () { + // Navigator.of(context).pop(false); + Get.back(result: false); + }, + child: Container( + width: 97.r, + height: 27.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.r)), + color: const Color(0xFFF4F4F4), + ), + child: const Center( + child: Text( + '取消', + style: TextStyle(color: Color(0xFF666666)), + ))), + ), + ], + ), + ); + } + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + // titleSpacing: 0, + elevation: 0.0, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios), + onPressed: () { + Get.back(); + }), + iconTheme: const IconThemeData(color: Colors.black), + title: quickText('收藏夹'), + centerTitle: true, + backgroundColor: Colors.white, + actions: const [ + ReturnToHomepage(), + ], + ), + body:OrientationBuilder( + builder: (BuildContext context, Orientation orientation){ + return Column( + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: 0.r, horizontal: 14.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Obx(() { + return Text( + state.homeworkName.value, + style: + TextStyle(fontSize: 14.sp, color: const Color(0xFF3C3C3C),), + overflow: TextOverflow.ellipsis, + ); + }), + ), + // 下拉框 + Container( + padding: EdgeInsets.symmetric( + vertical: 10.h, horizontal: 10.w), + child: Row( + children: [ + Obx(() { + return DropdownSelection( + bgColor: Colors.white, + involveClasses: state.involveClasses.value, + classData: state.classData.value, + call: (AnnotatedClass item) { + state.classData.value = item; + if (item.grade == -1) state.classData.value = state.defaultClass; + logic.getList(); + }); + }), + ], + ), + ), + ], + ), + ), + Container( + width: MediaQuery + .of(context) + .size + .width, + height: 1.r, + decoration: const BoxDecoration( + color: Color(0xFFEEEEEE), + ), + ), + Obx((){ + return state.favList.isNotEmpty + ? Expanded( + child: Utils.isPad() + ? Padding( + padding: EdgeInsets.only( + top: 10.r, + bottom: 8.r, + left: 14.r, + right: 14.r), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: + List.generate(state.favList.length, (index) { + var item = state.favList[index]; + return Padding( + padding: EdgeInsets.only(bottom: 8.r), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Padding( + padding: + EdgeInsets.only(bottom: 5.r), + child: Text( + '第${item['questionPage']}页', + style: TextStyle( + fontSize: 12.sp, + color:Theme.of(context).primaryColor), + ), + ), + GridView( + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + mainAxisSpacing: 8.r, + crossAxisSpacing: 10.r, + childAspectRatio: 556 / 112, + ), + shrinkWrap: true, + children: List.generate( + item['list'].length, (i) { + HomeworkFavs student = item['list'][i]; + return Container( + padding: EdgeInsets.symmetric( + vertical: 5.r, + horizontal: 10.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: + BorderRadius.all( + Radius.circular( + 6.r)), + ), + child: InkWell( + onTap: () { + showStudentDialog(context, + student, state.favList); + }, + child: Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + quickText( + student.studentName, + color: const Color( + 0xFF333333), + size: 12.sp), + Expanded( + child: Container()), + Padding( + padding: + EdgeInsets.only( + right: 8.r), + child: Text( + student.className!, + style: TextStyle( + fontSize: 12.sp, + color: const Color( + 0xFF666666)), + ), + ), + InkWell( + onTap: () async { + var confim = + await confirmDialog(); + if (confim) { + logic.getDelete( + student); + } + }, + child: Image.asset( + 'assets/images/favorite_delete_icon.png', + width: 24.r, + height: 24.r, + ), + ), + ], + ), + ), + ); + })), + ], + ), + ); + })), + ) + : ListView.builder( + shrinkWrap: true, + itemBuilder: (context, index) { + var item = state.favList[index]; + return Padding( + padding: EdgeInsets.only( + top: 10.r, + bottom: 8.r, + left: 14.r, + right: 14.r), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 5.r), + child: Text( + '第${item['questionPage']}页', + style: TextStyle( + fontSize: 14.sp, + color:Theme.of(context).primaryColor), + ), + ), + ListView.builder( + itemBuilder: (context, i) { + HomeworkFavs student = item['list'][i]; + return InkWell( + onTap: () { + showStudentDialog( + context, student, state.favList); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 5.r, + horizontal: 10.r), + margin: EdgeInsets.only(top: 5.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all( + Radius.circular(6.r)), + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + quickText(student.studentName, + color: const Color(0xFF333333), + size: 14.sp), + Expanded(child: Container()), + Padding( + padding: EdgeInsets.only( + right: 8.r), + child: Text( + student.className!, + style: TextStyle( + fontSize: 14.sp, + color: const Color( + 0xFF666666)), + ), + ), + InkWell( + onTap: () async { + var confim = + await confirmDialog(); + if (confim) { + logic.getDelete(student); + } + }, + child: Image.asset( + 'assets/images/favorite_delete_icon.png', + width: 32.r, + height: 32.r, + ), + ), + ], + ), + ), + ); + }, + itemCount: item['list'].length, + shrinkWrap: true, + ), + ], + ), + ); + }, + itemCount: state.favList.length, + ), + ) + : Padding( + padding: EdgeInsets.only( + top: MediaQuery + .of(context) + .size + .height / 2 - 200.r), + child: const MyEmptyWidget(), + ); + }), + + ], + ); + } + ) + ); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + logic.controller.getList(); + } +} \ No newline at end of file diff --git a/making_school_asignment_app/lib/page/home_page/children/fav_student/widget/favorite_student_dialog.dart b/making_school_asignment_app/lib/page/home_page/children/fav_student/widget/favorite_student_dialog.dart new file mode 100644 index 0000000..61cf1a8 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/fav_student/widget/favorite_student_dialog.dart @@ -0,0 +1,246 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:get/get_rx/get_rx.dart'; +import 'package:making_school_asignment_app/common/config/request_config.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:photo_view/photo_view.dart'; +import 'package:photo_view/photo_view_gallery.dart'; + +class FavoriteStudentDialog extends StatefulWidget { + final HomeworkFavs item; + final List group; + final Function deleteFav; + final Future Function() confirmDialog; + + const FavoriteStudentDialog({Key? key, + required this.item, + required this.group, + required this.deleteFav, + required this.confirmDialog}) + : super(key: key); + + @override + State createState() => _FavoriteStudentDialogState(); +} + +class _FavoriteStudentDialogState extends State { + RxInt defaultIndex = 0.obs; + RxList imageList = RxList(); + late PageController pageController; + late Rx currentStudent = Rx(HomeworkFavs('','','',-1,-1,'','',-1,'',-1,'-1','','')); + + @override + void initState() { + super.initState(); + currentStudent.value = widget.item; + List list = []; + for (var element in widget.group) { + for (var item in element['list']) { + list.add(item); + } + } + imageList.value = list; + defaultIndex.value = + list.indexWhere((element) => element.id == widget.item.id); + + pageController = PageController(initialPage: defaultIndex.value); + } + + @override + void dispose() { + super.dispose(); + pageController.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + width: MediaQuery + .of(context) + .size + .width, + height: MediaQuery + .of(context) + .size + .height, + padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 14.r), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Obx(() { + return Text( + '${currentStudent.value.className} ${currentStudent.value + .studentName}', + style: TextStyle(fontSize: 12.sp, color: Theme.of(context).primaryColor), + ); + }), + Expanded(child: Container()), + Text( + '第${currentStudent.value.questionNo}页', + style: TextStyle(fontSize: 12.sp, color: Color(0xFF868686)), + ), + InkWell( + onTap: () async { + bool confim = await widget.confirmDialog(); + if (confim) { + widget.deleteFav(currentStudent.value); + imageList.removeAt(defaultIndex.value); + if (imageList.isNotEmpty) { + if (defaultIndex.value < imageList.length) { + currentStudent.value = imageList[defaultIndex.value]; + } else { + currentStudent.value = + imageList[defaultIndex.value - 1]; + defaultIndex = defaultIndex - 1; + } + } else { + currentStudent.value.className = ''; + currentStudent.value.studentName = ''; + } + } + }, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 8.r), + child: Image.asset( + 'assets/images/favorite_delete_icon.png', + width: 22.r, + height: 22.r, + ), + ), + ), + InkWell( + onTap: () { + Navigator.pop(context); + }, + child: Image.asset( + 'assets/images/favorite_dialog_close.png', + width: 22.r, + height: 22.r, + ), + ), + ], + ), + SizedBox( + height: 10.r, + ), + Obx(() { + return imageList.isNotEmpty + ? Expanded( + child: Container( + color: Colors.white, + width: MediaQuery + .of(context) + .size + .width, + child: PhotoViewGallery.builder( + scrollPhysics: const BouncingScrollPhysics(), + builder: (BuildContext context, int index) { + final HomeworkFavs item = imageList[index]; + return PhotoViewGalleryPageOptions( + imageProvider: NetworkImage(RequestConfig.imgUrl + item.zgtAnswer!), + heroAttributes: PhotoViewHeroAttributes(tag: item.id!), + ); + }, + itemCount: imageList.length, + pageController: pageController, + onPageChanged: (index) { + defaultIndex.value = index; + currentStudent.value = imageList[index]; + }, + scrollDirection: Axis.horizontal, + ), + ), + ) + : Padding( + padding: EdgeInsets.only( + top: MediaQuery + .of(context) + .size + .height / 2 - 200.r), + child: const MyEmptyWidget(), + ); + }), + Obx(() { + return imageList.isNotEmpty?Padding( + padding: EdgeInsets.symmetric(vertical: 15.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () { + if (defaultIndex.value > 0) { + defaultIndex.value = defaultIndex.value - 1; + pageController.jumpToPage(defaultIndex.value); + } + }, + child: Container( + width: + (MediaQuery + .of(context) + .size + .width - 78.r) / 2 - 10.r, + height: 28.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.r)), + border: Border.all( + width: 1.r, + color: Color(0xFFCACACA), + style: BorderStyle.solid), + ), + child: Center( + child: Text( + '上一页', + style: TextStyle( + fontSize: 10.r, + color: defaultIndex == 0 + ? Color(0xFFCACACA) + : Color(0xFF505E6E)), + )), + ), + ), + InkWell( + onTap: () { + if (defaultIndex.value < imageList.length - 1) { + defaultIndex.value = defaultIndex.value + 1; + pageController.jumpToPage(defaultIndex.value); + } + }, + child: Container( + width: + (MediaQuery + .of(context) + .size + .width - 78.r) / 2 - 10.r, + height: 28.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.r)), + border: Border.all( + width: 1.r, + color: Color(0xFFCACACA), + style: BorderStyle.solid), + ), + child: Center( + child: Text( + '下一页', + style: TextStyle( + fontSize: 10.r, + color: defaultIndex == imageList.length - 1 + ? Color(0xFFCACACA) + : Color(0xFF505E6E)), + )), + ), + ), + ], + ), + ):Container(); + }) + ], + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/bottom_operation_bar.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/bottom_operation_bar.dart new file mode 100644 index 0000000..ade8cd1 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/bottom_operation_bar.dart @@ -0,0 +1,240 @@ +import 'dart:async'; +import 'dart:ffi'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/do_paper_bus.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/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; + +import '../configuration_files/index.dart'; + +// 底部操作栏 +class BottomAnnotationSwitch extends StatefulWidget { + const BottomAnnotationSwitch({super.key}); + + @override + State createState() => _BottomAnnotationSwitchJobState(); +} + +class _BottomAnnotationSwitchJobState extends State with SingleTickerProviderStateMixin, EventBusMixin { + late AnimationController _animationController; // 动画 + final _homeworkLogic = Get.find(); + final _logicControl = Get.find().annotationState; + StreamSubscription? _opControllisten; + + @override + void initState() { + _animationController = AnimationController( + vsync: this, + value: 1, // 设置默认值 + lowerBound: 0, + upperBound: 1, + duration: const Duration(milliseconds: 300), + )..addListener(toUp); + + _opControllisten = _logicControl.opControl.listen((e) { + if (e) { + _animationController.forward(); + } else { + _animationController.reverse(); + } + }); + + super.initState(); + } + + @override + void dispose() { + _animationController + ..removeListener(toUp) + ..dispose(); + _opControllisten?.cancel(); + + eventCancel(); + super.dispose(); + } + + void toUp() => toUpState(setState, () {}, mounted); + + @override + Widget build(BuildContext context) { + double iconSize = 18.sp; + Color actionColor = Colors.white; + Color defaultColor = const Color.fromRGBO(132, 146, 163, 1); + + return Container( + width: double.infinity, + height: _animationController.value * 64.h, + color: const Color.fromRGBO(83, 83, 83, 1), + // padding: EdgeInsets.symmetric(vertical: 1.h), + child: Row( + children: [ + Expanded( + flex: 7, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Row( + children: [ + // 全对按钮 + Expanded( + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: TextButton( + child: quickText('全 对', color: Colors.white, size: 12.sp), + onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.allPairs(context)), + ), + ), + ), + Container(width: 0.3.w, height: double.infinity, color: Colors.white), + // 注解笔 + Expanded( + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: IconButton( + icon: Obx(() { + return Icon( + const IconData(0xe635, fontFamily: "AlibabaIcon"), + size: iconSize, + color: _logicControl.pen.value ? Theme.of(context).primaryColor : defaultColor, + ); + }), + onPressed: () => easyThrottle('homework_bottom_action_bar_annotations', () { + _logicControl.gestureMove.value = false; + _logicControl.pen.value = !_logicControl.pen.value; + }), + ), + ), + ), + Container(width: 0.3.w, height: double.infinity, color: Colors.white), + // 滑动试题 + Expanded( + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: IconButton( + icon: Obx( + () { + return Icon( + const IconData(0xe636, fontFamily: "AlibabaIcon"), + size: iconSize, + color: _logicControl.gestureMove.value ? actionColor : defaultColor, + ); + }, + ), + onPressed: () => easyThrottle('homework_bottom_action_bar_annotations', () { + _logicControl.pen.value = false; + _logicControl.gestureMove.value = !_logicControl.gestureMove.value; + }), + ), + ), + ), + ], + ), + ), + Container(width: double.infinity, color: Colors.white, height: 0.35.h), + Expanded( + child: Row( + children: [ + // 全错按钮 + Expanded( + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: TextButton( + onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.allWrongRating(context)), + child: quickText('全 错', color: Colors.white, size: 12.sp), + ), + ), + ), + Container(width: 0.3.w, height: double.infinity, color: Colors.white), + // 撤销上一步 + Expanded( + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: IconButton( + onPressed: () => easyThrottle( + 'homework_bottom_action_bar_annotations', + () => eventFire(model: BottomOperationBar(revokeAll: false, revokePreStep: true)), + ), + icon: Icon(const IconData(0xe638, fontFamily: "AlibabaIcon"), size: iconSize, color: defaultColor), + ), + ), + ), + Container(width: 0.3.w, height: double.infinity, color: Colors.white), + // 全部撤销 + Expanded( + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: IconButton( + icon: Icon(const IconData(0xe637, fontFamily: "AlibabaIcon"), size: iconSize, color: defaultColor), + onPressed: () => easyThrottle( + 'homework_bottom_action_bar_annotations', + () => eventFire(model: BottomOperationBar(revokeAll: true, revokePreStep: false)), + ), + ), + ), + ), + ], + ), + ), + ], + ), + ), + Container(width: 0.3.w, height: double.infinity, color: Colors.white), + Expanded( + flex: 3, + child: Row( + children: [ + Expanded( + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: TextButton( + onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.cancelAllRatings()), + child: quickText('取 消', size: 14.sp, color: Colors.white), + ), + ), + ), + Container(width: 0.3.w, height: double.infinity, color: Colors.white), + Expanded( + child: SizedBox( + width: double.infinity, + height: double.infinity, + child: TextButton( + onPressed: () => easyThrottle('homework_bottom_operation_bar_scoring_related', () => _homeworkLogic.submit(context)), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + 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), + ], + ), + ), + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/button_floating_action.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/button_floating_action.dart new file mode 100644 index 0000000..1b1eb24 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/button_floating_action.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart'; + +// 底部状态栏隐藏后的开关 +class ButtonFloatingAction extends GetView { + const ButtonFloatingAction({super.key}); + + @override + Widget build(BuildContext context) { + return Obx(() { + if (controller.annotationState.opControl.value) return const SizedBox(); + + return FloatingActionButton( + elevation: 8, + tooltip: "点击打开工具栏", + backgroundColor: Colors.white, + onPressed: () => controller.annotationState.opControl.value = true, + child: Icon(Icons.edit, size: 20.sp, color: Theme.of(context).primaryColor), + ); + }); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/dropdown_switch_students_type.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/dropdown_switch_students_type.dart new file mode 100644 index 0000000..191a0ed --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/dropdown_switch_students_type.dart @@ -0,0 +1,313 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart'; +import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'original_manuscript_handwriting/answer_handwriting_view.dart'; + +part 'dropdown_switch_students_type.g.dart'; + +/// 学生和页码切换 +/// + +class DropdownSwitchStudentsType extends StatelessWidget { + const DropdownSwitchStudentsType({super.key}); + + @override + Widget build(BuildContext context) { + final logic = Get.find(); + final sateData = logic.state.data; + + return Container( + height: 30.h, + padding: EdgeInsets.only(bottom: 2.r, left: 12.r, right: 12.r), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: const Color.fromRGBO(46, 91, 255, 0.2), + offset: Offset(2.w, 2.h), //阴影y轴偏移量 + blurRadius: 14, //阴影模糊程度 + spreadRadius: 0.5, //阴影扩散程度 + ) + ], + ), + child: Row( + children: [ + Expanded( + flex: 2, + child: Container( + padding: EdgeInsets.only(left: 10.w), + decoration: BoxDecoration( + color: const Color.fromRGBO(244, 244, 244, 1), + borderRadius: BorderRadius.circular(4.r), + ), + child: Obx(() { + return DropdownButton( + isExpanded: true, + underline: Container(), + padding: EdgeInsets.only(right: 4.w), + icon: const Icon(Icons.keyboard_arrow_down_rounded), + value: sateData.value?.templateId, + hint: const Text('请选择作业页码'), // 锚点的显示文本 + items: sateData.value?.templateIdKeys?.map((e) { + return DropdownMenuItem( + value: e, + child: quickText('${sateData.value!.templateIdKeyMap![e]}页', color: const Color.fromRGBO(79, 79, 79, 1), size: 14.sp), + ); + }).toList(), + onChanged: (value) { + if (logic.state.param.value.templateId == value) return; + var templateIds = logic.state.data.value?.templateIds; + + if (value != null && templateIds != null) { + final templateIdKeyMap = logic.state.data.value?.templateIdKeyMap; + + var answeredAlready = templateIds[value.toString()]; + if (answeredAlready != null && !answeredAlready) { + final currentStudentId = sateData.value?.studentId; + final students = sateData.value?.students ?? []; + + // 获取当前学生姓名 + final currentStudent = currentStudentId != null ? students.firstWhereOrNull((e) => e.id == currentStudentId) : null; + + final studentName = currentStudent?.name ?? '当前学生'; + final questionNumber = templateIdKeyMap?[value] ?? '当前选择页'; + + ToastUtils.showInfo("$studentName第$questionNumber页,未作答 无需批阅"); + return; + } + } + + logic.state.param.value.templateId = value; + logic.state.param.value = DoPaperDetailsParam.fromJson(logic.state.param.value.toJson()); + // _useSwitchStudentAndType.currentTab.value = _useSwitchStudentAndType.tabs.value.firstWhere((element) => element.pageIndex == value); + }, + ); + }), + ), + ), + const Expanded(flex: 1, child: SizedBox()), + Expanded( + flex: 3, + child: Stack( + children: [ + Container( + padding: EdgeInsets.only(left: 13.w), + decoration: BoxDecoration( + color: const Color.fromRGBO(244, 244, 244, 1), + borderRadius: BorderRadius.circular(4.r), + ), + child: Obx(() { + return DropdownButton( + padding: EdgeInsets.only(right: 4.w), + icon: const Icon(Icons.keyboard_arrow_down_rounded), + value: sateData.value?.studentId, + underline: Container(), + isExpanded: true, + items: sateData.value?.students.map((e) { + return DropdownMenuItem( + value: e.id, + child: Stack( + alignment: const FractionalOffset(0, 0.62), + children: [ + Container( + padding: sateData.value?.studentId != e.id && e.isPriority ? EdgeInsets.only(left: 14.w) : null, + child: quickText( + e.name, + size: 14.sp, + color: const Color.fromRGBO(79, 79, 79, 1), + ), + ), + if (e.isPriority && sateData.value?.studentId != e.id) + Stack( + alignment: const FractionalOffset(0.52, 0.24), + children: [ + Icon( + const IconData(0xe63d, fontFamily: "AlibabaIcon"), + size: 12.sp, + color: e.isPriority ? Theme.of(context).primaryColor : const Color.fromRGBO(164, 164, 164, 1), + ), + quickText('优先', size: 4.sp, color: Colors.white), + ], + ), + ], + ), + ); + }).toList(), + hint: const Text('请选择学生'), // 锚点的显示文本 + onChanged: (value) { + if (logic.state.param.value.studentId == value) return; + logic.state.param.value.studentId = value; + logic.state.param.value = DoPaperDetailsParam.fromJson(logic.state.param.value.toJson()); + }, + ); + }), + ), + Positioned( + left: 2.w, + child: Stack( + alignment: const FractionalOffset(0.52, 0.24), + children: [ + Obx(() { + return Icon( + const IconData(0xe63d, fontFamily: "AlibabaIcon"), + size: 12.sp, + color: sateData.value?.priority ?? false ? Theme.of(context).primaryColor : const Color.fromRGBO(164, 164, 164, 1), + ); + }), + quickText('优先', size: 4.sp, color: Colors.white), + ], + ), + ), + ], + ), + ), + // const Expanded(flex: 1, child: SizedBox()), + SizedBox(width: 8.w), + Expanded( + flex: isPad() ? 4 : 5, + child: const Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + $ContinueToReview(), // 继续批阅 + $HistoryHomework(), // 学生历史作业 + $StudentHandwriting(), // 学生笔迹 + ], + ), + ), + ], + ), + ); + } +} + +@swidget +Widget $studentHandwriting(BuildContext context) { + final logic = Get.find(); + final sateData = Get.find().state.data; + return InkWell( + onTap: () => easyThrottle( + 'SHOW_ANSWER_HANDWRITING', + () async { + var homeworkId = logic.state.param.value.homeworkId; + var studentId = sateData.value?.studentId; + if (studentId == null) return; + var templateIdKeyMap = sateData.value?.templateIdKeyMap; + int? pageNum; + var templateId = sateData.value?.templateId; + if (templateIdKeyMap != null && templateId != null) { + pageNum = templateIdKeyMap[templateId]; + } + await showAnswerHandwriting(context, homeworkId: homeworkId, studentId: studentId, templateId: templateId, pageNum: pageNum); + ToastUtils.dismiss(); + }, + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.edit_outlined, size: 12.sp, color: Theme.of(context).primaryColor.withOpacity(0.8)), + SizedBox(width: 1.w), + quickText( + '学生笔迹', + size: 12.sp, + decoration: TextDecoration.underline, + color: Theme.of(context).primaryColor.withOpacity(0.9), + ), + ], + )); +} + +@swidget +Widget $continueToReview(BuildContext context, {bool isFloatingAction = false}) { + final logic = Get.find(); + final sateData = Get.find().state.data; + return Obx(() { + var data = sateData.value; + var param = logic.state.param.value; + int? submitCount = data?.submitCount; // 提交数量 + int? annotatedCount = data?.annotatedCount; // 批阅数量 + // || (submitCount == annotatedCount || (param.templateId == null && param.studentId == null)) + // if (data == null || (data.needAnnotate ? true : data.totalUnAnnotateCount <= 0) ) return const SizedBox(); + if (data == null || (data.needAnnotate ? (data.continuePage == null ? true : data.continuePage!.templateId == data.templateId) : data.totalUnAnnotateCount <= 0)) return const SizedBox(); + callFun() => easyThrottle( + 'DO_PAPERS_JOB_CONTINUE_TO_REVIEW', + () { + var param = logic.state.param.value; + param.templateId = null; + param.studentId = null; + logic.state.param.value = DoPaperDetailsParam.fromJson(param.toJson()); + }, + ); + if (isFloatingAction) { + return FloatingActionButton( + elevation: 8, + tooltip: "继续批阅", + backgroundColor: Colors.white, + onPressed: callFun, + child: Icon(Icons.flip_camera_android_outlined, size: 20.sp, color: Theme.of(context).primaryColor), + ); + } + return SizedBox( + child: InkWell( + onTap: callFun, + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(Icons.flip_camera_android_outlined, size: 12.sp, color: Theme.of(context).primaryColor.withOpacity(0.8)), + SizedBox(width: 1.w), + quickText( + '继续批阅', + size: 12.sp, + decoration: TextDecoration.underline, + color: Theme.of(context).primaryColor.withOpacity(0.9), + ), + SizedBox(width: 2.w), + ], + ), + )); + }); +} + +// 学生历史作业 +@swidget +Widget $historyHomework(BuildContext context) { + final sateData = Get.find().state.data; + return SizedBox( + child: InkWell( + onTap: () => easyThrottle('DO_PAPERS_JOB_HISTORICAL_HOMEWORK', () { + int? studentId = sateData.value?.studentId; + if (kDebugMode) print(studentId); + if (studentId == null || (sateData.value?.students.isEmpty ?? true)) return; + var currentStudent = sateData.value!.students.firstWhereOrNull((e) => e.id == studentId); + if (currentStudent == null) return; + var theState = Get.find().state; + Get.toNamed(Routes.studentWorkDetailPage, arguments: {'studentId': studentId, 'studentName': currentStudent.name, 'subject': theState.param.value.subject}); + }), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.location_history, size: 12.sp, color: const Color.fromRGBO(104, 103, 103, 1)), + SizedBox(width: 1.w), + quickText( + '历史作业', + size: 12.sp, + decoration: TextDecoration.underline, + color: Theme.of(context).primaryColor.withOpacity(0.8), + ), + ], + ), + ), + ); +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/favorite_widget.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/favorite_widget.dart new file mode 100644 index 0000000..21f3562 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/favorite_widget.dart @@ -0,0 +1,49 @@ +import 'package:get/get.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.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'; + +/// 自定义收藏组件 +/// isFavorite 默认是否收藏 +/// favoriteNum 默认收藏次数 + +class FavoriteWidget extends StatelessWidget { + const FavoriteWidget({super.key}); + + @override + Widget build(BuildContext context) { + final logic = Get.find(); + final sateData = logic.state; + + return Container( + padding: EdgeInsets.symmetric(horizontal: 4.r), + child: InkWell( + onTap: () => easyThrottle('homework_review_collect_btn', () => logic.toFavorite(), duration: const Duration(milliseconds: 500)), + splashColor: Colors.transparent, + highlightColor: Colors.transparent, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Obx(() { + return Icon( + const IconData(0xe63c, fontFamily: "AlibabaIcon"), + size: 18.sp, + color: sateData.favorite.value ? const Color.fromRGBO(255, 172, 48, 1) : const Color.fromRGBO(164, 164, 164, 1), + ); + }), + SizedBox(width: 6.w), + ], + ), + ), + ); + } +} + +class JobQuestionsSwitch extends Object { + final int taskId; + final int studentId; + final int paperId; + + JobQuestionsSwitch(this.taskId, this.studentId, this.paperId); +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/job_handwriting.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/job_handwriting.dart new file mode 100644 index 0000000..2cdf7d9 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/job_handwriting.dart @@ -0,0 +1,62 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'job_handwriting.g.dart'; + +@JsonSerializable() +class JobHandwriting extends Object { + @JsonKey(name: 'lattices') + List lattices; + + @JsonKey(name: 'paperPicture') + String paperPicture; + + @JsonKey(name: 'pageNum') + int pageNum; + + @JsonKey(name: 'pageCount') + int pageCount; + + JobHandwriting(this.lattices, this.paperPicture, this.pageNum, this.pageCount); + + factory JobHandwriting.fromJson(Map srcJson) => _$JobHandwritingFromJson(srcJson); + + Map toJson() => _$JobHandwritingToJson(this); +} + +@JsonSerializable() +class Lattices extends Object { + // 笔画 + @JsonKey(name: 'stroke') + int stroke; + + @JsonKey(name: 'x') + double x; + + @JsonKey(name: 'y') + double y; + + @JsonKey(name: 'time') + int time; + + @JsonKey(name: 'intervalTime') + int intervalTime; + + @JsonKey(name: 'initialization') + bool initialization; + + Lattices(this.stroke, this.x, this.y, this.time, [this.intervalTime = 0, this.initialization = false]); + + factory Lattices.fromJson(Map srcJson) => _$LatticesFromJson(srcJson); + + Map toJson() => _$LatticesToJson(this); + + /** + * 根据基准初始化坐标数据 + * @param double scaleRatio + */ + void toInitialization(double scaleRatio) { + x = x * scaleRatio; + y = y * scaleRatio; + initialization = true; + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/original_manuscript_handwriting/answer_handwriting_view.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/original_manuscript_handwriting/answer_handwriting_view.dart new file mode 100644 index 0000000..2ef8818 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/original_manuscript_handwriting/answer_handwriting_view.dart @@ -0,0 +1,1090 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/do_test_questions_image_info.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/original_manuscript_handwriting_params.dart'; +import 'package:making_school_asignment_app/common/mixins/event_bus_mixin.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; +import 'package:making_school_asignment_app/common/utils/cached_network_img.dart'; +import 'package:making_school_asignment_app/common/utils/my_time_util.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/job_handwriting.dart'; + +import 'configuration_files/logic.dart'; +import 'configuration_files/states.dart'; + +part 'answer_handwriting_view.g.dart'; + +/// 学生答题轨迹 +class AnswerHandwriting extends Dialog { + final String homeworkId; + final int studentId; + final int? templateId; + final int? pageNum; + final String? questionNo; + final Function closeCall; + AnswerHandwriting( + {super.key, + required this.homeworkId, + required this.studentId, + required this.closeCall, + this.templateId, + this.pageNum, + this.questionNo}); + final _handwritingLogic = Get.find(); + @override + Widget build(BuildContext context) { + return OrientationBuilder( + builder: (BuildContext context, Orientation orientation) { + var boxHeight = ScreenUtil().screenHeight / 1.168; // 盒子高度 + var boxWidth = ScreenUtil().screenWidth - + (ScreenUtil().scaleWidth < 1.5 ? 40.r : 40.r); // 盒子宽度 + + return Center( + child: Container( + height: boxHeight, + width: boxWidth, + alignment: Alignment.center, + child: AnswerHandwritingMainBox( + handwritingLogic: _handwritingLogic, + boxHeight: boxHeight, + boxWidth: boxWidth, + homeworkId: homeworkId, + templateId: templateId, + studentId: studentId, + pageNum: pageNum, + questionNo: questionNo, + closeCall: closeCall, + ), + ), + ); + }); + } +} + +Future showAnswerHandwriting( + BuildContext context, { + required String homeworkId, + required int studentId, + int? templateId, + int? pageNum, + String? questionNo, +}) async { + backCall() { + Navigator.of(context).pop(); + } + + Get.put(HandwritingLogic(backCall)); + Get.find().params.value = + OriginalManuscriptHandwritingParams( + homeworkId: homeworkId, + studentId: studentId, + templateId: templateId, + pageNum: pageNum, + questionNo: questionNo, + ); + await showDialog( + context: context, + builder: (BuildContext context) => AnswerHandwriting( + homeworkId: homeworkId, + templateId: templateId, + studentId: studentId, + pageNum: pageNum, + questionNo: questionNo, + closeCall: backCall, + ), + ).then((e) => Get.delete()); +} + +// 主图 +class AnswerHandwritingMainBox extends HookWidget with EventBusMixin { + AnswerHandwritingMainBox({ + required this.handwritingLogic, + required this.homeworkId, + required this.studentId, + required this.closeCall, + required this.boxHeight, + required this.boxWidth, + this.templateId, + this.pageNum, + this.questionNo, + super.key, + }); + + final HandwritingLogic handwritingLogic; + + final String homeworkId; + final double boxHeight; + final double boxWidth; + final int? templateId; + final int studentId; + final int? pageNum; + final String? questionNo; + final Function closeCall; + + @override + Widget build(BuildContext context) { + var _useStateModel = UseMainBoxState.use( + homeworkId, studentId, pageNum, questionNo, templateId); + double barHeight = 62.h; + double imageHeight = boxHeight - barHeight; + useValueChanged(_useStateModel.handwritingData.value, + (_, __) { + var theData = _useStateModel.handwritingData.value; + _useStateModel.pageNum.value = theData?.pageNum; + _useStateModel.pageCount.value = theData?.pageCount ?? 0; + _useStateModel.playPause.value = false; + _useStateModel.constantFastSpeed.value = false; + // Future.delayed(Duration.zero, () { + // _useStateModel.handwritingKey.currentState?.ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); + // }); + // _useStateModel.handwritingDetail.value = _useStateModel.getHandwritingDetail(theData); + }); + + useValueChanged(_useStateModel.pageNum.value, (oldVal, __) { + if (oldVal != null && oldVal != _useStateModel.pageNum.value) { + _useStateModel.questionNo = null; + // _useStateModel.getData().catchError((e) => closeCall()); + } + }); + + JobHandwriting? data = _useStateModel.handwritingData.value; + HandwritingInfo? dataDetail = _useStateModel.handwritingDetail.value; + + // if (data == null || dataDetail == null) return Container(); + + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + height: imageHeight, + width: boxWidth, + child: Stack( + alignment: const FractionalOffset(0, 0.5), + children: [ + // 图片展示主框 + SingleChildScrollView( + child: HandwritingDrawBox( + boxWidth: boxWidth, + boxHeight: boxHeight, + key: _useStateModel.handwritingKey, + ), + ), + PageNumberBox(), + PreviousNutton(), // 上一页按钮 + NextPageButton(), // 下一题按钮 + ], + ), + ), + $BottomPlaybar(barHeight, handwritingLogic), + ], + ); + } +} + +class UseMainBoxState with RequestToolMixin { + final String homeworkId; + final int studentId; + final int? templateId; + String? questionNo; + final ValueNotifier pageNum; + final ValueNotifier pageCount; + final ValueNotifier handwritingData; + final ValueNotifier handwritingDetail; + + final ValueNotifier playPause; // 播放暂停 + final ValueNotifier constantFastSpeed; // 原速、快速 默认原速 + + GlobalKey<_HandwritingDrawBoxState> handwritingKey; + + UseMainBoxState._({ + required this.homeworkId, + required this.templateId, + required this.studentId, + required this.pageNum, + required this.handwritingData, + required this.questionNo, + required this.pageCount, + required this.playPause, + required this.constantFastSpeed, + required this.handwritingDetail, + required this.handwritingKey, + }); + + // 工厂构造函数 + factory UseMainBoxState.use(String homeworkId, int studentId, + [int? pageNum, String? questionNo, int? templateId]) { + return UseMainBoxState._( + homeworkId: homeworkId, + templateId: templateId, + studentId: studentId, + questionNo: questionNo, + pageNum: useState(pageNum), + handwritingData: useState(null), + handwritingDetail: useState(null), + pageCount: useState(0), + playPause: useState(false), + constantFastSpeed: useState(false), + handwritingKey: GlobalKey(), + ); + } +} + +/// 上一页 +class PreviousNutton extends StatelessWidget { + PreviousNutton({super.key}); + + final HandwritingLogic handwritingLogic = Get.find(); + + @override + Widget build(BuildContext context) { + return Obx(() { + if (handwritingLogic.resultData.value?.pageNum != null && + handwritingLogic.resultData.value!.pageNum > 1) { + return Positioned( + left: 3.w, + child: FloatingActionButton( + heroTag: '点击前往上一题', + tooltip: '点击前往上一题', + focusColor: Theme.of(context).primaryColor, + backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), + elevation: 6.r, + onPressed: () => easyThrottle('answer_handwriting_previous', () { + var resultData = handwritingLogic.resultData.value; + var params = handwritingLogic.params.value; + if (resultData == null || params == null) return; + params.pageNum = resultData.pageNum - 1; + params.templateId = null; + params.questionNo = null; + handwritingLogic.params.value = + OriginalManuscriptHandwritingParams.fromJson(params.toJson()); + // handwritingLogic.params.value = params; + }), + child: Icon(Icons.arrow_back_ios, color: Colors.white, size: 22.sp), + ), + ); + } + + return const SizedBox(); + }); + } +} + +/// 下一页 +class NextPageButton extends StatelessWidget { + final HandwritingLogic handwritingLogic = Get.find(); + + NextPageButton({super.key}); + + @override + Widget build(BuildContext context) { + return Obx(() { + if (handwritingLogic.resultData.value?.pageNum != null && + handwritingLogic.resultData.value!.pageNum < + handwritingLogic.resultData.value!.pageCount) { + return Positioned( + right: 3.w, + child: FloatingActionButton( + heroTag: '点击前往下一题', + tooltip: '点击前往下一题', + elevation: 6.r, + backgroundColor: const Color.fromRGBO(24, 32, 32, 0.1), + onPressed: () => easyThrottle('answer_handwriting_next', () { + var resultData = handwritingLogic.resultData.value; + var params = handwritingLogic.params.value; + if (resultData == null || params == null) return; + params.pageNum = resultData.pageNum + 1; + params.templateId = null; + params.questionNo = null; + handwritingLogic.params.value = + OriginalManuscriptHandwritingParams.fromJson(params.toJson()); + }), + child: + Icon(Icons.arrow_forward_ios, color: Colors.white, size: 22.sp), + ), + ); + } + + return const SizedBox(); + }); + } +} + +// 笔记还原主框 +class HandwritingDrawBox extends StatefulWidget { + final double boxWidth; + final double boxHeight; + const HandwritingDrawBox( + {required this.boxWidth, required this.boxHeight, super.key}); + + @override + State createState() => _HandwritingDrawBoxState(); +} + +class _HandwritingDrawBoxState extends State + with EventBusMixin { + HandwritingLogic handwritingLogic = Get.find(); // 学生答题笔迹逻辑层 + + ImageStream? imageStream; // 图片监听数据 + late ImageStreamListener theImageStreamListener; // 试题图片数据 + + late ValueNotifier> _vnHandWritings; + late ValueNotifier> _vnPrimaryHandWritings; + + late StreamSubscription showManuscriptStream; + late StreamSubscription executionDataStream; + + List> _packagedHandwritingDatas = []; + List _packagedHandwritingDataAll = []; // 总数据 + List pendingData = []; // 待执行数据 + List timers = []; + int handwritingTime = 0; + int handwritingDuration = 0; + double speed = 2.0; // 播放速度 + + @override + void initState() { + super.initState(); /* */ + + theImageStreamListener = ImageStreamListener((ImageInfo info, bool _) { + // 获取图片的宽高 + WidgetsBinding.instance.addPostFrameCallback((_) { + //需要创建的小组件 + handwritingLogic.imagInfoModel.value = TestQuestionsImageInfo( + url: handwritingLogic.resultData.value!.paperPicture, + boxWidth: widget.boxWidth, + boxHeight: widget.boxHeight, + imageWidth: info.image.width.toDouble(), + imageHeight: info.image.height.toDouble(), + ); + }); + }); + + _vnHandWritings = ValueNotifier>([]); + _vnPrimaryHandWritings = ValueNotifier>( + _packagedHandwritingDataAll); + + handwritingLogic.toolbar.initialization.listen((e) { + // 数据初始化完成赋值数据 + if (e) { + _packagedHandwritingDatas = + handwritingLogic.packagedHandwritingDatas.value; + _packagedHandwritingDataAll = + handwritingLogic.packagedHandwritingDataAll.value; + } else { + _packagedHandwritingDatas = []; + _packagedHandwritingDataAll = []; + } + + // _vnPrimaryHandWritings.is + try { + _vnPrimaryHandWritings.value = [..._packagedHandwritingDataAll]; // 总体数据 + } catch (e) { + _vnPrimaryHandWritings = + ValueNotifier>( + _packagedHandwritingDataAll); + } + // eventFire(model: JobHandwritingPlaybarBus); + }); + showManuscriptStream = handwritingLogic.toolbar.showManuscript.listen((e) { + // 查看原稿控制 + if (e) { + // 查看原稿 + eventFire(model: JobHandwritingPlaybarBus(false)); // 暂停 + _vnPrimaryHandWritings.value = [..._packagedHandwritingDataAll]; + } else { + // 清空原稿数据 + _vnPrimaryHandWritings.value = []; + } + }); + + executionDataStream = handwritingLogic.toolbar.executionData.listen((e) { + try { + _vnHandWritings.value = e; + } catch (e1) { + _vnHandWritings = ValueNotifier>(e); + } + }); + + eventOn(callback: (e) { + switch (e.runtimeType) { + case JobHandwritingRunTimeBus: + var _model = (e as JobHandwritingRunTimeBus); + var _runtime = _model.runTimeVal; + handwritingDuration = _model.totalVal; + handwritingTime = _runtime; + if (_runtime <= 0) { + pendingData.clear(); + } + break; + case JobHandwritingDragProgressBarBus: + var _model = (e as JobHandwritingDragProgressBarBus); + dragProgressBarInitData(_model.changeVal, _model.totalVal); + break; + case JobHandwritingPlaybarBus: + // 播放 暂停 + var _val = e as JobHandwritingPlaybarBus; + if (_val.play) { + // 播放 + toGoPlay(); + } else { + // 暂停 + toGoPause(_val.recalculate); + } + break; + case PlaybackSpeedBus: + // 播放速度 + var _model = (e as PlaybackSpeedBus); + speed = _model.speed; + dragProgressBarInitData( + handwritingDuration - handwritingTime, handwritingDuration); + break; + default: + } + }); + } + + @override + void dispose() { + imageStream?.removeListener(theImageStreamListener); + _vnHandWritings.dispose(); + _vnPrimaryHandWritings.dispose(); + showManuscriptStream.cancel(); + executionDataStream.cancel(); + eventCancel(); + super.dispose(); + } + + // 暂停播放 + Future toGoPause(bool recalculate) async { + timers.forEach((e) { + if (e.isActive) e.cancel(); + }); + timers = []; + // 总时间-剩余时间=已经执行时间 + if (recalculate && + pendingData.isNotEmpty && + handwritingTime > 0 && + (handwritingDuration - handwritingTime > 0)) { + // 待执行的数据不等于空 每个数据都需要减去当前暂停已经执行的时间 + pendingData = pendingData.map((e) { + return GestureHandwritingRecording( + stroke: e.stroke, + data: e.data, + usageTime: e.usageTime, + intervalTime: + e.intervalTime - (handwritingDuration - handwritingTime) * 1000, + ); + }).toList(); + } + } + + /// 开始播放 + Future toGoPlay() async { + try { + var executableData = _packagedHandwritingDataAll; + if (pendingData.isNotEmpty) { + // 待执行的数据没有执行完成 就继续执行待执行数据 + executableData = pendingData; + } else { + // 需要重新添加所有数据进行播放 + pendingData.addAll(_packagedHandwritingDataAll); + handwritingLogic.toolbar.executionData.value = []; // 重置已经执行的数据 + } + handwritingLogic.toolbar.showManuscript.value = false; + executableData.forEach((e) { + var ter = Timer(Duration(milliseconds: e.intervalTime ~/ speed), + () => zhixinCall(e)); + timers.add(ter); + }); + } catch (e) { + print('播放报错:$e'); + } + } + + Future zhixinCall(GestureHandwritingRecording e) async { + if (mounted) { + List trajectorys = + handwritingLogic.toolbar.executionData.value..add(e); + handwritingLogic.toolbar.executionData.value = List.from(trajectorys); + pendingData.remove(e); // 执行后删除容器中的当前动作 + } + } + + /// 拖动进度条后重新初始化数据 + /// @param startTime 起始时间 单位秒 + Future dragProgressBarInitData(int startTime, int totalDuration) async { + eventFire(model: JobHandwritingPlaybarBus(false, false)); + timers.forEach((e) { + if (e.isActive) e.cancel(); + }); + timers = []; + pendingData.clear(); + + if (startTime == 0) { + handwritingLogic.toolbar.executionData.value = []; // 重置已经执行的数据 + pendingData.addAll(_packagedHandwritingDataAll); + } else { + // 待执行的数据不等于空 每个数据都需要减去当前暂停已经执行的时间 + startTime = startTime * 1000; // 转为毫秒 + List executeImmediately = []; // 立即执行数据 + List waitingExecution = []; // 等待执行数据 + + for (var i = 0; i < _packagedHandwritingDataAll.length; i++) { + var item = _packagedHandwritingDataAll[i]; + + if (item.intervalTime < startTime) { + // 需要直接装配到直接打印的容器 + executeImmediately.add(item); + } else { + var intervalTime = item.intervalTime - startTime; + // 需要等待的数据 + waitingExecution.add(GestureHandwritingRecording( + stroke: item.stroke, + data: item.data, + usageTime: item.usageTime, + intervalTime: intervalTime, + )); + } + } + + pendingData = waitingExecution; + handwritingLogic.toolbar.executionData.value = executeImmediately; + } + eventFire(model: JobHandwritingPlaybarBus(true)); + } + + @override + Widget build(BuildContext context) { + return Obx(() { + print('进入了....................'); + var paperPicture = handwritingLogic.resultData.value?.paperPicture; + if (paperPicture == null) return const SizedBox(); + + print( + '显示原稿:${handwritingLogic.toolbar.showManuscript.value} 数据:${_vnPrimaryHandWritings.value.length}'); + return RepaintBoundary( + child: CustomPaint( + foregroundPainter: HandWritingDrawingPainter( + ctrl: handwritingLogic.toolbar.showManuscript.value + ? _vnPrimaryHandWritings + : _vnHandWritings, + ), + child: $TheCachedNetworkImage( + imageUrl: paperPicture, + (context, imageProvider) { + Image imageWidget = + Image(image: imageProvider, fit: BoxFit.contain); + var imagInfoModel = handwritingLogic.imagInfoModel.value; + if (imagInfoModel == null || + imagInfoModel.boxWidth != widget.boxWidth) { + imageStream?.removeListener(theImageStreamListener); + imageStream = + imageWidget.image.resolve(const ImageConfiguration()); + imageStream?.addListener(theImageStreamListener); + } + return imageWidget; + }, + ), + ), + ); + }); + } +} + +class HandWritingDrawingPainter extends CustomPainter { + final ValueNotifier> ctrl; + HandWritingDrawingPainter({required this.ctrl}) : super(repaint: ctrl); + //[定义画笔] + final Paint paintBrush = Paint() + //画笔颜色 + ..color = Colors.black + //画笔笔触类型 + ..strokeCap = StrokeCap.round + //是否启动抗锯齿 + ..isAntiAlias = true + //绘画风格,默认为填充 + // ..style = PaintingStyle.fill + //画笔的宽度 + ..style = PaintingStyle.stroke + ..strokeWidth = 0.5.r; + + @override + void paint(Canvas canvas, Size size) { + // canvas.drawPoints(PointMode.points, thePoints, paintBrush); + canvas.save(); + + var points = ctrl.value; + var _length = points.length; + for (int i = 0; i < _length; i++) { + GestureHandwritingRecording item = points[i]; + GestureHandwritingRecording? nextItem = + i + 1 < _length ? points[i + 1] : null; + + Offset offsetData = item.data; + Offset? nextOffsetData = nextItem?.data; + if (nextOffsetData != null && item.stroke == nextItem?.stroke) { + canvas.drawLine(offsetData, nextOffsetData, paintBrush); + } + } + canvas.restore(); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + if (oldDelegate is HandWritingDrawingPainter) { + var repaint = ctrl.value.length != oldDelegate.ctrl.value.length || + oldDelegate.ctrl.value != ctrl.value; + print('调用是否绘制:$repaint'); + return repaint; + } + return true; // 如果 oldDelegate 不是 MyCustomPainter 的实例,则总是重绘 + } +} + +// 页码 +class PageNumberBox extends StatelessWidget { + PageNumberBox({super.key}); + + final HandwritingLogic handwritingLogic = + Get.find(); // 学生答题笔迹逻辑层 + + @override + Widget build(BuildContext context) { + return Positioned( + top: 6.h, + right: 4.w, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h), + decoration: BoxDecoration( + color: const Color.fromRGBO(0, 0, 0, 0.47), + borderRadius: BorderRadius.circular(5.r), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Obx(() { + return quickText( + '${handwritingLogic.resultData.value?.pageNum ?? 0}', + color: Colors.white, + size: 11.sp, + align: TextAlign.end); + }), + quickText('/', + color: Colors.white, size: 10.sp, align: TextAlign.end), + Obx(() { + return quickText( + '${handwritingLogic.resultData.value?.pageCount ?? 0}', + color: Colors.white, + size: 8.sp, + align: TextAlign.end); + }), + ], + )), + ); + } +} + +@hwidget +Widget $bottomPlaybar( + BuildContext context, double barHeight, HandwritingLogic handwritingLogic) { + var timeConsuming = useState(0); + var handwritingInfo = useState(null); + + var usePlaybar = UseBottomPlaybar.use(timeConsuming.value); + useValueChanged(timeConsuming.value, (_, __) { + usePlaybar.playTimingSuspend(); + usePlaybar.playPause.value = false; + var seds = timeConsuming.value ~/ 1000; + if ((timeConsuming.value % 1000) > 500) seds += 1; + usePlaybar.handwritingDuration.value = seds; + usePlaybar.constantFastSpeed.value = PlaybackSpeed.DOUBLE_SPEED; + }); + + useValueChanged(usePlaybar.handwritingDuration.value, (_, __) { + usePlaybar.useTime.value = usePlaybar.handwritingDuration.value; + }); + // 播放速度 + useValueChanged(usePlaybar.constantFastSpeed.value, + (_, __) { + usePlaybar.eventFire( + model: PlaybackSpeedBus(usePlaybar.constantFastSpeed.value.speed)); + // 播放速度变化 + usePlaybar.playTimingSuspend(); + usePlaybar.playTimingStarts(); + }); + // 计时结束监听 + useValueChanged(usePlaybar.useTime.value, (_, __) { + var _runtime = usePlaybar.useTime.value; + if (_runtime <= 0 || usePlaybar.handwritingDuration.value == _runtime) { + Future.delayed( + Duration.zero, () => (usePlaybar.playPause.value = false)); // 初始化播放按钮 + } + usePlaybar.eventFire( + model: JobHandwritingRunTimeBus( + _runtime, usePlaybar.handwritingDuration.value)); + }); + + useEffect(() { + // 初始化 + var initialization = handwritingLogic.toolbar.initialization.listen((e) { + usePlaybar.handWritingReady.value = e; + }); + var handwritingInfoStream = handwritingLogic.handwritingInfo.listen((e) { + // 笔迹数据 + if (e == null) return; + handwritingInfo.value = e; + timeConsuming.value = e.timeConsuming; + }); + usePlaybar.eventOn(callback: (e) { + switch (e.runtimeType) { + case JobHandwritingPlaybarBus: + // 出发播放暂停 + var _val = e as JobHandwritingPlaybarBus; + if (_val.play) { + // 开始播放 + usePlaybar.playTimingStarts(); + if (!usePlaybar.playPause.value) usePlaybar.playPause.value = true; + } else { + // 暂停播放 + usePlaybar.playTimingSuspend(); + if (usePlaybar.playPause.value) usePlaybar.playPause.value = false; + } + break; + case JobHandwritingGetReadyBus: + // 作业笔迹已经计算好坐标 可以开始播放 + Future.delayed( + Duration.zero, () => (usePlaybar.handWritingReady.value = true)); + break; + default: + } + }); + + return () { + try { + initialization.cancel(); + usePlaybar.eventCancel(); + handwritingInfoStream.cancel(); + usePlaybar.timer.value?.cancel(); + } catch (e) { + print(e); + } + }; + }, []); + + return Container( + height: barHeight, + padding: EdgeInsets.symmetric(horizontal: 10.w), + alignment: Alignment.center, + color: const Color.fromRGBO(0, 0, 0, 0.4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (usePlaybar.handWritingReady.value) + InkWell( + onTap: () => easyThrottle('job_handwriting_play_pause', () { + if (usePlaybar.handwritingDuration.value == 0) + return ToastUtils.showInfo('没有笔迹'); + + usePlaybar.playPause.value = !usePlaybar.playPause.value; + usePlaybar.eventFire( + model: JobHandwritingPlaybarBus(usePlaybar.playPause.value)); + }), + child: Icon( + !usePlaybar.playPause.value + ? Icons.play_circle_outline + : Icons.pause_circle_outline, + color: Colors.white, + size: 28.r, + ), + ) + else + SpinKitPouringHourGlassRefined(size: 40.sp, color: Colors.white), + SizedBox(width: 6.w), + Expanded( + child: LayoutBuilder(builder: (context, constraints) { + final double containerWidth = constraints.maxWidth; // 展示区域总宽度 + var unitScale = containerWidth / timeConsuming.value; // 单位刻度 + var pauseIntervalsLength = + handwritingInfo.value?.pauseInterval.length ?? 0; + + List pauseTickMarks = + handwritingInfo.value?.pauseInterval.asMap().keys.map((e) { + bool isLast = e == pauseIntervalsLength - 1; + bool isFirst = e == 0; + var item = handwritingInfo.value!.pauseInterval[e]; + return Positioned( + top: 0, + left: unitScale * item.startTime, + child: Container( + width: unitScale * (item.apart ?? 0), + height: 10.h, + decoration: BoxDecoration( + color: Color.fromRGBO(202, 201, 201, 1), + borderRadius: isFirst + ? BorderRadius.only( + topLeft: Radius.circular(8.r), + bottomLeft: Radius.circular(10.r)) + : (isLast + ? BorderRadius.only( + topRight: Radius.circular(8.r), + bottomRight: Radius.circular(10.r)) + : null), + ), + ), + ); + }).toList() ?? + []; + + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Stack( + children: [ + Container( + height: 10.h, + width: containerWidth, + decoration: BoxDecoration( + // color: Color.fromRGBO(146, 146, 146, 1), + color: Colors.white, + borderRadius: BorderRadius.circular(50.r), + ), + ), + ...pauseTickMarks, + Container( + height: 10.h, + width: containerWidth, + // color: Theme.of(context).primaryColor, + child: SliderTheme( + data: SliderTheme.of(context).copyWith( + trackHeight: 10.h, // 轨道高度 + trackShape: + RoundedRectSliderTrackShape(), // 轨道形状,可以自定义 + activeTrackColor: + Theme.of(context).primaryColor, // 激活的轨道颜色 + inactiveTrackColor: Colors.transparent, // 未激活的轨道颜色 + thumbShape: RoundSliderThumbShape( + enabledThumbRadius: 0, disabledThumbRadius: 0), + thumbColor: Colors.white, // 滑块颜色 + overlayShape: + RoundSliderOverlayShape(overlayRadius: 0), + overlayColor: Colors.black54, // 滑块外圈颜色 + // valueIndicatorShape: PaddleSliderValueIndicatorShape(), // 标签形状,可以自定义 + ), + child: Slider( + value: (usePlaybar.handwritingDuration.value - + usePlaybar.useTime.value) + .toDouble(), + min: 0.0, + max: usePlaybar.handwritingDuration.value.toDouble(), + inactiveColor: Colors.transparent, + onChangeEnd: (value) { + if (!usePlaybar.handWritingReady.value) return; + usePlaybar.playTimingSuspend(); // 暂停计时器得暂停 + usePlaybar.eventFire( + model: JobHandwritingDragProgressBarBus( + value.toInt(), + usePlaybar.handwritingDuration.value)); + usePlaybar.useTime.value = + usePlaybar.handwritingDuration.value - + value.toInt(); + }, + onChanged: (double value) { + if (!usePlaybar.handWritingReady.value) return; + usePlaybar.useTime.value = + usePlaybar.handwritingDuration.value - + value.toInt(); + }, + ), + ), + ), + ], + ), + SizedBox(height: 8.h), + SizedBox( + width: containerWidth, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + quickText( + '累计停顿:${handwritingInfo.value?.pauseCount ?? 0}次', + color: Colors.white, + size: 7.sp), + quickText( + convertSeconds(usePlaybar.useTime.value) + ?.toString() ?? + '', + color: Colors.white, + size: 7.sp), + ], + ), + ) + ], + ); + }), + ), + SizedBox(width: 16.w), + Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InkWell( + onTap: () => easyThrottle('job_handwriting_speed', () { + var theIndex = PlaybackSpeed.values + .indexOf(usePlaybar.constantFastSpeed.value); + if (theIndex == PlaybackSpeed.values.length - 1) { + theIndex = -1; + } + usePlaybar.constantFastSpeed.value = + PlaybackSpeed.values[theIndex + 1]; + }, duration: Duration(milliseconds: 500)), + child: Container( + // alignment: Alignment., + padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h), + decoration: BoxDecoration( + color: Color.fromRGBO(182, 197, 250, 1), + borderRadius: BorderRadius.circular(4.r)), + child: quickText( + '${usePlaybar.constantFastSpeed.value.name}', + color: Color.fromRGBO(79, 114, 244, 1), + size: 8.sp, + align: TextAlign.center, + ), + ), + ), + SizedBox(height: 7.h), + StudentManuscriptBtn(handwritingLogic), + ], + ), + ], + ), + ); +} + +// 学生原稿按钮视图 +class StudentManuscriptBtn extends StatelessWidget { + final HandwritingLogic handwritingLogic; + const StudentManuscriptBtn(this.handwritingLogic, {super.key}); + + @override + Widget build(BuildContext context) { + return Obx(() { + return InkWell( + onTap: () => easyThrottle('job_handwriting_udent_manuscript', () { + var showManuscript = handwritingLogic.toolbar.showManuscript.value; + handwritingLogic.toolbar.showManuscript.value = !showManuscript; + }), + child: Container( + padding: EdgeInsets.symmetric(horizontal: 3.w, vertical: 1.5.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4.r), + color: handwritingLogic.toolbar.showManuscript.value + ? Theme.of(context).primaryColor + : Colors.grey, + ), + child: quickText('学生原稿', + color: Colors.white, size: 8.sp, align: TextAlign.center), + ), + ); + }); + } +} + +class SysjTime extends StatefulWidget { + const SysjTime({super.key}); + + @override + State createState() => _SysjTimeState(); +} + +class _SysjTimeState extends State + with EventBusMixin { + int useTime = 0; + @override + void initState() { + super.initState(); + // eventOn(callback: (JobHandwritingRunTimeBus e) { + // useTime = e.runTimeVal; + // toUpState(setState, () {}, mounted); + // }); + } + + @override + void dispose() { + eventCancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return quickText(convertSeconds(useTime)?.toString() ?? '', + color: Colors.white, size: 7.sp); + } +} + +class UseBottomPlaybar with EventBusMixin { + final ValueNotifier handwritingDuration; // 笔迹总时长 + final ValueNotifier playPause; // 播放暂停 + final ValueNotifier constantFastSpeed; // 播放速度 + final ValueNotifier handWritingReady; + + final ValueNotifier useTime; // 耗时 单位:(秒) + + final ValueNotifier timer; + + UseBottomPlaybar._( + {required this.handWritingReady, + required this.handwritingDuration, + required this.playPause, + required this.constantFastSpeed, + required this.useTime, + required this.timer}); + + // 工厂构造函数 + factory UseBottomPlaybar.use(int milliseconds) { + int handwritingDuration = milliseconds ~/ 1000; + if ((milliseconds % 1000) > 500) handwritingDuration += 1; + return UseBottomPlaybar._( + playPause: useState(false), + constantFastSpeed: useState(PlaybackSpeed.DOUBLE_SPEED), // 默认两倍速 + useTime: useState(handwritingDuration), + timer: useState(null), + handwritingDuration: useState(handwritingDuration), + handWritingReady: useState(false), + ); + } + + /// 开始计时 + void playTimingStarts() { + if (useTime.value > 0) { + timer.value?.cancel(); + + timer.value = Timer.periodic( + Duration(milliseconds: 1000 ~/ constantFastSpeed.value.speed), + (theTime) { + useTime.value -= 1; + if (useTime.value < 0) { + theTime.cancel(); + timer.value?.cancel(); + timer.value = null; + useTime.value = handwritingDuration.value; + } + }); + } + } + + /// 暂停 + void playTimingSuspend() { + timer.value?.cancel(); + timer.value = null; + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/original_manuscript_handwriting/configuration_files/logic.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/original_manuscript_handwriting/configuration_files/logic.dart new file mode 100644 index 0000000..9b0b16a --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/original_manuscript_handwriting/configuration_files/logic.dart @@ -0,0 +1,181 @@ +// 逻辑文件 +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/config/request_config.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/do_test_questions_image_info.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/original_manuscript_handwriting_params.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/job_handwriting.dart'; +import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/original_manuscript_handwriting/configuration_files/states.dart'; + +class HandwritingLogic extends GetxController with RequestToolMixin { + Rx resultData = Rx(null); // 笔迹数据 + Rx handwritingInfo = Rx(null); // 笔迹数据 + Rx>> packagedHandwritingDatas = Rx>>([]); + Rx> packagedHandwritingDataAll = Rx>([]); // 总数据 + Rx params = Rx(null); // 参数 + Rx imagInfoModel = Rx(null); // 图片加载后的数据 + + late ToolbarControl toolbar; + + final Function backCall; + HandwritingLogic(this.backCall); + + @override + void onInit() { + toolbar = ToolbarControl( + showManuscript: Rx(false), // 查看原卷 + initialization: Rx(false), // 初始化完成 + executionData: Rx>([]), // 执行数据 + ); + ever(params, (callback) => getData()); + ever(imagInfoModel, (callback) { + // 图像数据初始化后 计算笔迹数据 + toolbar.initialization.value = false; + handwritingInfo.value = getHandwritingDetail(resultData.value); + getCalculatedSize(); + }); + super.onInit(); + } + + Future getData() async { + if (params.value == null) return; + var dio = getClientDio(); + try { + ToastUtils.showLoading(); + toolbar.initialization.value = false; + imagInfoModel.value = null; + // 设置时长 + + dio.options.receiveTimeout = const Duration(seconds: 20); + var res = await getClient().getOriginalManuscriptHandwriting(params.value!); + resultData.value = res; + } catch (e) { + ToastUtils.showError('获取笔迹数据报错,请重试'); + backCall(); + } finally { + dio.options.receiveTimeout = const Duration(milliseconds: RequestConfig.receiveTimeout); // 还原接收数据时长 + ToastUtils.dismiss(); + } + } + + // 计算尺寸 + Future getCalculatedSize() async { + if (imagInfoModel.value == null || handwritingInfo.value == null) return; + Map> mapData = handwritingInfo.value!.strokeMap; + double scaleRatio = imagInfoModel.value!.scaleRatio; + if (mapData.isNotEmpty) { + List keys = mapData.keys.toList(); + print('重新计算:${scaleRatio}'); + List> _packagedHandwritingDatas = []; + List _packagedHandwritingDataAll = []; + for (var i = 0; i < keys.length; i++) { + List newTrajectoryData = mapData[keys[i]]!.map((e) { + // double theX = e.x; + // double theY = e.y; + // if (!e.initialization) { + // // 未初始化基准 + // e.toInitialization(scaleRatio); + // theX = e.x; + // theY = e.y; + // } + return GestureHandwritingRecording( + stroke: e.stroke, + data: Offset(e.x * scaleRatio, e.y * scaleRatio), + // data: Offset(theX, theY), + usageTime: e.time.toInt(), + intervalTime: e.intervalTime, + ); + }).toList(); + + newTrajectoryData.sort((a, b) => a.usageTime.compareTo(b.usageTime)); + _packagedHandwritingDatas.add(newTrajectoryData); + _packagedHandwritingDataAll.addAll(newTrajectoryData); + } + packagedHandwritingDatas.value = _packagedHandwritingDatas; // 分组数据 + packagedHandwritingDataAll.value = _packagedHandwritingDataAll; // 不分组数据 + toolbar.showManuscript.value = true; // 默认原稿展示 + toolbar.initialization.value = true; // 数据初始化完成 + + // Future.delayed(Duration.zero, () => eventFire(model: JobHandwritingGetReadyBus())); // 通知外部可以播放笔迹 + } + } + + // 数据笔画处理计算 + HandwritingInfo? getHandwritingDetail(JobHandwriting? theData) { + if (theData == null) return null; + // 笔画分组 + // var lattices = Map>.fromIterable( + // theData.lattices, + // key: (key) => key.stroke, + // value: (value) { + // // return theData.lattices.where((item) => item.stroke == value.stroke).toList()..sort((a, b) => a.time.compareTo(b.time)); + // return theData.lattices.where((item) => item.stroke == value.stroke).toList(); + // }, + // ); + var lattices = >{}; + var theLattices = theData.lattices; + for (var i = 0; i < theLattices.length; i++) { + Lattices item = theLattices[i]; + if (!lattices.containsKey(item.stroke)) lattices[item.stroke] = []; + lattices[item.stroke]!.add(item); // 添加笔画数据 + } + + List latticeKeys = lattices.keys.toList(); // 笔画集合 + int timeConsuming = 0; + if (latticeKeys.isNotEmpty) { + // 计算总时长 + List? firstAction = lattices[latticeKeys[0]]; + List? lastAction = lattices[latticeKeys[latticeKeys.length - 1]]; + int firstTime = 0; + int lastTime = 0; + + if (firstAction?.isNotEmpty ?? false) { + // 第一个笔画集合 + firstTime = firstAction![0].time; + } + if (lastAction?.isNotEmpty ?? false) { + // 最后一笔画集合 + lastTime = lastAction![0].time; + } + timeConsuming = lastTime - firstTime; + } + var pauseCount = 0; // 停顿次数 + List pauseInterval = []; + for (var i = 0; i < latticeKeys.length; i++) { + var currentLattices = lattices[latticeKeys[i]]!; // 当前循环笔画集合 + var prevLattices = i == 0 ? null : lattices[latticeKeys[i - 1]]!; // 下一个笔画集合 + for (var j = 0; j < currentLattices.length; j++) { + var intervalTime = 0; + var lattice = currentLattices[j]; + + if (j != 0) { + var prevItem = currentLattices[j - 1]; + var adjacentSpacingTime = lattice.time - prevItem.time; + intervalTime = adjacentSpacingTime + prevItem.intervalTime; + if (adjacentSpacingTime > 5000) { + // 大于5秒算一次停顿 + pauseCount++; + pauseInterval.add(PauseIntervalTime(startTime: prevItem.intervalTime, endTime: intervalTime)); + } + } else { + if (i != 0 && prevLattices != null) { + var prevLatticeLastItem = prevLattices[prevLattices.length - 1]; + var adjacentSpacingTime = lattice.time - prevLatticeLastItem.time; + intervalTime = adjacentSpacingTime + prevLatticeLastItem.intervalTime; + if (adjacentSpacingTime > 5000) { + // 大于5秒算一次停顿 + pauseCount++; + pauseInterval.add(PauseIntervalTime(startTime: prevLatticeLastItem.intervalTime, endTime: intervalTime)); + } + } + } + lattice.intervalTime = intervalTime; + } + } + return HandwritingInfo(pauseCount, timeConsuming, lattices, pauseInterval); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/original_manuscript_handwriting/configuration_files/states.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/original_manuscript_handwriting/configuration_files/states.dart new file mode 100644 index 0000000..7cb1d34 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/original_manuscript_handwriting/configuration_files/states.dart @@ -0,0 +1,110 @@ +// 实体文件 + +import 'dart:ui'; + +import 'package:get/get.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/job_handwriting.dart'; + +part 'states.g.dart'; + +@JsonSerializable() +class HandwritingInfo extends Object { + int pauseCount; // 停顿次数 + List pauseInterval; + int timeConsuming; // 耗时(毫秒) + Map> strokeMap; // 笔画数据 + + HandwritingInfo(this.pauseCount, this.timeConsuming, this.strokeMap, this.pauseInterval); + + factory HandwritingInfo.fromJson(Map srcJson) => _$HandwritingInfoFromJson(srcJson); + + Map toJson() => _$HandwritingInfoToJson(this); +} + +class ToolbarControl { + Rx showManuscript; // 查看原稿 + Rx initialization; + Rx> executionData; + + ToolbarControl({ + required this.executionData, + required this.showManuscript, + required this.initialization, + }); +} + +// 播放倍速 +enum PlaybackSpeed { + ORIGINAL_SPEED(name: '原速播放', speed: 1), + ONE_POINT_FIVE_SPEED(name: '1.5x播放', speed: 1.5), + DOUBLE_SPEED(name: '2.0x播放', speed: 2), + TRIPLE_SPEED(name: '3.0x播放', speed: 3), + FOUR_SPEED(name: '4.0x播放', speed: 4), + FIVE_SPEED(name: '5.0x播放', speed: 5), + SIX_SPEED(name: '6.0x播放', speed: 6); + + const PlaybackSpeed({required this.name, required this.speed}); + final double speed; + final String name; +} + +@JsonSerializable() +class PauseIntervalTime extends Object { + int? apart; + int startTime; + int endTime; + PauseIntervalTime({required this.startTime, required this.endTime}) { + apart = endTime - startTime; + } + + factory PauseIntervalTime.fromJson(Map srcJson) => _$PauseIntervalTimeFromJson(srcJson); + + Map toJson() => _$PauseIntervalTimeToJson(this); +} + +// 播放按钮 +class JobHandwritingPlaybarBus { + bool play; + bool recalculate; + JobHandwritingPlaybarBus(this.play, [this.recalculate = true]); +} + +// 笔迹是否已经准备好(笔迹计算好坐标后通知通知栏可以开始播放) +class JobHandwritingGetReadyBus { + JobHandwritingGetReadyBus(); +} + +// 笔记运行时间 +class JobHandwritingRunTimeBus { + int runTimeVal; + int totalVal; + JobHandwritingRunTimeBus(this.runTimeVal, this.totalVal); +} + +// 拖动进度条 +class JobHandwritingDragProgressBarBus { + int changeVal; + int totalVal; + JobHandwritingDragProgressBarBus(this.changeVal, this.totalVal); +} + +// 播放速度 (原速播放/快速播放) +class PlaybackSpeedBus { + double speed; + PlaybackSpeedBus(this.speed); +} + +// 手势记录(原稿笔记还原) +class GestureHandwritingRecording { + int stroke; + int usageTime; // 用时 + Offset data; + int intervalTime; // 间隔时间 + GestureHandwritingRecording({ + required this.stroke, + required this.data, + required this.usageTime, + required this.intervalTime, + }); +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_number_view.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_number_view.dart new file mode 100644 index 0000000..085f3a2 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_number_view.dart @@ -0,0 +1,319 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_result.dart'; +import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:percent_indicator/linear_percent_indicator.dart'; + +import '../configuration_files/index.dart'; +import '../configuration_files/zoom_logic.dart'; + +part 'question_number_view.g.dart'; + +/// 试题题号 +class QuestionNumberView extends GetView { + const QuestionNumberView({super.key}); + + HomeworkReviewState get sateData => controller.state; + ZoomState get sateZoomData => controller.zoomLogic.zoomState; + + @override + Widget build(BuildContext context) { + return Container( + width: double.infinity, + height: double.infinity, + decoration: const BoxDecoration(color: Color.fromRGBO(159, 159, 159, 0.97)), + child: GestureDetector( + onPanDown: (_) => sateData.panQuestView = false, + child: Obx(() { + var zoomFile = sateZoomData.zoomFile.value; + var studentQuestions = sateData.studentQuestions.value ?? []; + + if (zoomFile == null || studentQuestions.isEmpty) return const SizedBox(); + + return $QuestionNumberScrollView(controller: controller, sateData: sateData, sateZoomData: sateZoomData, studentQuestions: studentQuestions); + }), + ), + ); + } +} + +// 试题题号视图 +@hwidget +Widget $questionNumberScrollView({ + required ZoomState sateZoomData, + required HomeworkReviewState sateData, + required HomeworkReviewLogic controller, + required List studentQuestions, +}) { + final scrollControllerNum = useScrollController(); // 试题题号区域 + // var studentQuestions = useState>(sateData.studentQuestions.value ?? []); + var useZoom = useState(sateZoomData.initScale.value ?? 1); + var usePiddingTop = useState(sateZoomData.zoomFile.value?.imageHeightOffsetStart ?? 0); + useValueChanged(sateZoomData.zoomFile.value?.imageHeightOffsetStart, (_, __) { + usePiddingTop.value = sateZoomData.zoomFile.value?.imageHeightOffsetStart ?? 0; + }); + useEffect(() { + // var studentQuestionsStream = sateData.studentQuestions.listen((e) { + // studentQuestions.value = e ?? []; + // }); + var sateDataDataStream = sateData.data.listen((e){ + scrollControllerNum.jumpTo(0); + }); + + + var stream = sateZoomData.initScale.listen((e) { + // print("initScale : $e"); + useZoom.value = e ?? 1; + var zoomFile = sateZoomData.zoomFile.value; + if (zoomFile?.actualHeight == null) return; + + // print(zoomFile?.toJson()); + // print("缩放基数:${useZoom.value}"); + // print("图片实际高度:${zoomFile!.actualHeight! * useZoom.value}"); + // print("视图剩余高度:${zoomFile.viewHeight - (zoomFile.actualHeight! * useZoom.value)}"); + // var topDistance = (zoomFile!.viewHeight - (zoomFile.actualHeight! * useZoom.value)) / 2; + var topDistance = zoomFile!.getZoomFileOffsetStart(useZoom.value); + // print("视图剩余高度/2:${max(0, topDistance)}"); + // 使用 max 函数确保 topDistance 不小于 0 + usePiddingTop.value = max(0, topDistance); + }); + + return () { + stream.cancel(); + sateDataDataStream.cancel(); + // studentQuestionsStream.cancel(); + }; + }, []); + + var actualImgHeight = useState(sateZoomData.zoomFile.value?.actualHeight); + useValueChanged(sateZoomData.zoomFile.value?.actualHeight, (_, __) { + actualImgHeight.value = sateZoomData.zoomFile.value?.actualHeight ?? 0; + }); + + useEffect(() { + scrollControllerNum.addListener(() { + /// 无法联动 + // if (sateData.panQuestView == false) sateData.slide.value = scrollControllerNum.offset; + }); + var listenVal = sateData.slide.listen((e) { + if (sateData.panQuestView != null && sateData.panQuestView == true && e != scrollControllerNum.offset) { + // print("进来了试题题号视图"); + scrollControllerNum.jumpTo(e); + } + }); + + return () { + listenVal.cancel(); + }; + }, []); + + // var actualImgHeight = useImageInfo.value?.actualImgHeight ?? 0; // 实际图片高度 + + // print("图片高度:$actualImgHeight"); + + print("FFFFFFFFF ${usePiddingTop.value}"); + + return SingleChildScrollView( + controller: scrollControllerNum, + physics: const BouncingScrollPhysics(), + padding: EdgeInsets.only(top: usePiddingTop.value > 0 ? usePiddingTop.value : 0), + scrollDirection: Axis.vertical, // 设置垂直滚动 + child: SizedBox( + height: (actualImgHeight.value ?? 0) * useZoom.value, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: studentQuestions + .map((e) => $ScoringQuestionsView( + key: Key('${sateData.data.value?.templateId}_${sateData.data.value?.studentId}_${e.questionNo}'), + sateData:sateData, + item:e, + logic:controller, + scaleRatio:sateZoomData.zoomFile.value!.scaleRatio, + initScale:useZoom.value, + )) + .toList(), + ), + ), + ); +} + +// 单道题得分框 +@hwidget +Widget $scoringQuestionsView( + BuildContext context, { + required HomeworkReviewState sateData, + required StudentQuestions item, + required HomeworkReviewLogic logic, + required double scaleRatio, + required double initScale, +}) { + var studentScore = useState(item.studentScore); + + useValueChanged(item.studentScore, (_, __) { + studentScore.value = item.studentScore; + }); + + // useValueChanged(item, (_, __) { + // studentScore.value = item.studentScore; + // }); + + useEffect(() { + /// 学生打分数据 + studentScoreListener() { + print(item.toJson()); + item.studentScore = studentScore.value; + var theVal = sateData.studentQuestions.value?.firstWhereOrNull((e) => e.questionNo == item.questionNo); + if (theVal != null) theVal.studentScore = studentScore.value; + + var studentQuestions = sateData.studentQuestions.value; + if (item.studentScore == null) return; + + // 校验是否自动提交 对于已经批阅过的试题 不重复自动提交 + var annotateTime = logic.state.data.value?.annotateTime; + if (annotateTime == null) { + var noRatingGiven = studentQuestions!.firstWhereOrNull((e) => e.useTime != 0 && e.studentScore == null); + if (noRatingGiven == null) logic.submit(context); + } + } + + studentScore.addListener(studentScoreListener); + + var studentQuestionsStream = sateData.studentQuestions.listen((e) { + var itemVal = (e ?? []).firstWhereOrNull((e1) => e1.questionNo == item.questionNo); + if (itemVal != null && studentScore.value != itemVal.studentScore) { + studentScore.value = itemVal.studentScore; + } + }); + + return () { + studentQuestionsStream.cancel(); + studentScore.removeListener(studentScoreListener); + }; + }, []); + + var padinVal = item.correctRate > 0 ? EdgeInsets.only(top: 6.4.h) : EdgeInsets.symmetric(vertical: 2.h); + Color buttonColor = item.useTime == 0 ? Colors.grey : const Color.fromRGBO(237, 237, 237, 1); // 当前题没有作答背景色置灰 + return Container( + height: item.height! * scaleRatio * initScale, + padding: EdgeInsets.zero, + child: Stack( + alignment: const FractionalOffset(0, 0), + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 对 + Expanded( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + padding: EdgeInsets.zero, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + backgroundColor: buttonColor, // 设置背景色 + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), // 去除圆角 + ), + child: Padding( + padding: padinVal, + child: Icon( + size: 22.sp, + color: studentScore.value == 2 ? Colors.green : const Color.fromRGBO(114, 114, 114, 1), + const IconData(0xe62b, fontFamily: "AlibabaIcon"), + ), + ), + onPressed: () => easyThrottle('scoring_homework_questions', () { + if (item.useTime == 0) { + ToastUtils.showInfo("当前第${item.questionNo}题,学生未作答无需批阅此题"); + return; + } + studentScore.value = studentScore.value == 2 ? null : 2; + }, duration: const Duration(milliseconds: 222)), + ), + ), + // 半 + Expanded( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + padding: EdgeInsets.zero, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + backgroundColor: buttonColor, // 设置背景色 + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), // 去除圆角 + ), + child: Padding( + padding: padinVal, + child: Icon( + size: 22.sp, + color: studentScore.value == 1 ? Colors.green : const Color.fromRGBO(114, 114, 114, 1), + const IconData(0xe62c, fontFamily: "AlibabaIcon"), + ), + ), + onPressed: () => easyThrottle('scoring_homework_questions', () { + if (item.useTime == 0) { + ToastUtils.showInfo("当前第${item.questionNo}题,学生未作答无需批阅此题"); + return; + } + studentScore.value = studentScore.value == 1 ? null : 1; + }, duration: const Duration(milliseconds: 222)), + ), + ), + // 错 + Expanded( + child: ElevatedButton( + style: ElevatedButton.styleFrom( + padding: EdgeInsets.zero, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + backgroundColor: buttonColor, // 设置背景色 + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), // 去除圆角 + ), + child: Padding( + padding: padinVal, + child: Icon( + size: 22.sp, + color: studentScore.value == 0 ? Colors.green : const Color.fromRGBO(114, 114, 114, 1), + const IconData(0xe62a, fontFamily: "AlibabaIcon"), + ), + ), + onPressed: () => easyThrottle('scoring_homework_questions', () { + if (item.useTime == 0) { + ToastUtils.showInfo("当前第${item.questionNo}题,学生未作答无需批阅此题"); + return; + } + studentScore.value = studentScore.value == 0 ? null : 0; + }, duration: const Duration(milliseconds: 222)), + ), + ), + ], + ), + IgnorePointer( + // 事件穿透 + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(width: 1.1.w), + quickText(item.questionNo, color: Theme.of(context).primaryColor.withOpacity(0.7), size: 8.sp), + if (item.correctRate > 0) quickText(' 正确率', color: Colors.grey, size: 5.sp), + if (item.correctRate > 0) + Expanded( + child: LinearPercentIndicator( + lineHeight: 6.h, + percent: item.correctRate / 100, + barRadius: Radius.circular(1.2.r), + alignment: MainAxisAlignment.center, + progressColor: Theme.of(context).primaryColor, + backgroundColor: const Color(0xFFB8C7CB).withOpacity(0.35), + center: quickText("${item.correctRate}%", size: 5.sp, align: TextAlign.center, color: Colors.white), + ), + ) + ], + ), + ), + ], + ), + ); +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart new file mode 100644 index 0000000..a4689e3 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/components/question_paper_view.dart @@ -0,0 +1,727 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/do_paper_bus.dart'; +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/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/cached_network_img.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/home_page/children/homework_review/configuration_files/index.dart'; +import 'package:zoom_widget/zoom_widget.dart'; + +import '../configuration_files/zoom_logic.dart'; +import 'question_number_view.dart'; + +part 'question_paper_view.g.dart'; + +// 试题详情视图 +class QuestionPaperView extends GetView { + const QuestionPaperView({super.key}); + + HomeworkReviewState get sateData => controller.state; + ZoomState get zoomState => controller.zoomLogic.zoomState; + HomeworkReviewAnnotationsControlState get annotationState => + controller.annotationState; + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Row( + children: [ + // 试题图片视图 + Expanded( + flex: 7, + child: Obx(() { + ZoomFileModel? zoomFileModel = zoomState.zoomFile.value; + + if (zoomFileModel == null) { + /// 计算高度 + return LayoutBuilder(builder: + (BuildContext context, BoxConstraints constraints) { + WidgetsBinding.instance.addPostFrameCallback( + (_) => zoomState.zoomFile.value = ZoomFileModel( + viewWidth: constraints.maxWidth, + viewHeight: constraints.maxHeight, + )); + return const SizedBox(); + }); + } + + /// 文件未计算实际高度 + if (zoomFileModel.fileHeight == null) return const SizedBox(); + + var maxWidth = zoomFileModel.viewWidth; + var maxHeight = zoomFileModel.viewHeight; + return Stack( + children: [ + // 主图 + QuestionImageView( + maxWidth, maxHeight, annotationState, controller, + zoomState: zoomState, + sateData: sateData, + actualHeight: zoomFileModel.actualHeight!), + // 继续批阅按钮 + // Positioned(right: 3.w, bottom: 4.h, child: const $ContinueToReview(isFloatingAction: true)), + // 上一题按钮 + Positioned( + left: 2.w, + top: (maxHeight / 2) - 20.h, + child: Obx(() { + LastPage? lastPageVal = sateData.data.value?.lastPage; + if (lastPageVal == null) return const SizedBox(); + return FloatingActionButton( + heroTag: '点击前往上一题', + tooltip: '点击前往上一题', + focusColor: Theme.of(context).primaryColor, + backgroundColor: + const Color.fromRGBO(24, 32, 32, 0.05), + elevation: 10.r, + onPressed: () => + easyThrottle('TestQuestionSwitch', () { + var param = sateData.param.value; + param.studentId = lastPageVal.studentId; + param.templateId = lastPageVal.templateId; + sateData.param.value = + DoPaperDetailsParam.fromJson(param.toJson()); + }), + child: Icon(Icons.arrow_back_ios, + color: Colors.white, size: 22.sp), + ); + }), + ), + // 下一题按钮 + Positioned( + right: 2.w, + top: (maxHeight / 2) - 20.h, + child: Obx(() { + NextPage? nextPageVal = sateData.data.value?.nextPage; + if (nextPageVal == null) return const SizedBox(); + + return FloatingActionButton( + heroTag: '点击前往下一题', + tooltip: '点击前往下一题', + elevation: 10.r, + backgroundColor: + const Color.fromRGBO(24, 32, 32, 0.05), + onPressed: () => + easyThrottle('TestQuestionSwitch', () { + var param = sateData.param.value; + param.studentId = nextPageVal.studentId; + param.templateId = nextPageVal.templateId; + sateData.param.value = + DoPaperDetailsParam.fromJson(param.toJson()); + }), + child: Icon(Icons.arrow_forward_ios, + color: Colors.white, size: 22.sp), + ); + }), + ), + // 底部数据 + $TotalSubmitCountView(sateData) + ], + ); + }), + ), + // 试题题号视图 + const Expanded(flex: 2, child: QuestionNumberView()), + ], + ), + + /// 数据出错再次请求按钮 + const DataErrorThenRequestAgainButton(), + ], + ); + } +} + +/// 数据出错再次请求按钮 +class DataErrorThenRequestAgainButton extends StatelessWidget { + const DataErrorThenRequestAgainButton({super.key}); + + @override + Widget build(BuildContext context) { + return GetBuilder(builder: (logic) { + final sateData = logic.state; + + if (!sateData.getDataError.value) return const SizedBox(); + + return Center( + child: CupertinoButton( + color: Colors.grey[300], + onPressed: () => easyThrottle('home_work_reload_data', () { + sateData.param.value = + DoPaperDetailsParam.fromJson(sateData.param.value.toJson()); + }), + child: quickText('再次请求', color: Colors.black38), + ), + ); + }); + } +} + +// 底部已阅数量和待阅数量 +@swidget +Widget $totalSubmitCountView( + BuildContext context, HomeworkReviewState sateData) { + return Obx(() { + var data = sateData.data.value; + if (data == null) return Container(); + return Positioned( + bottom: 10.h, + right: 8.w, + child: InkWell( + onTap: () async { + var submitStudents = sateData.data.value?.students; // 已提交学生 + + showModalBottomSheet( + context: context, + elevation: 10, + backgroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10.r), + topRight: Radius.circular(10.r))), + builder: (BuildContext context) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 2.w), + child: Column( + children: [ + Container( + margin: EdgeInsets.only(top: 14.h), + child: quickText( + '第${sateData.data.value!.templateIdKeyMap?[sateData.data.value!.templateId]}页未提交学生名单', + size: 15.sp, + fontWeight: FontWeight.bold, + color: const Color.fromRGBO(60, 60, 60, 1), + ), + ), + SizedBox(height: 10.h), + Expanded( + child: ListView( + padding: EdgeInsets.symmetric( + vertical: 8.h, horizontal: 4.w), + children: [ + Wrap( + spacing: 7.2.w, // 主轴(水平)方向间距 + runSpacing: 12.h, // 纵轴(垂直)方向间距 + alignment: WrapAlignment.start, //沿主轴方向居中 + children: submitStudents!.map((e) { + return Stack( + alignment: const FractionalOffset(0.05, 0.09), + children: [ + Container( + padding: EdgeInsets.only( + top: 1.2.h, + bottom: 1.5.h, + left: 13.w, + right: 5.w), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4.r), + color: const Color.fromRGBO( + 239, 242, 255, 1), + ), + child: quickText( + e.name, + size: 12.sp, + wordSpacing: 2, + color: + const Color.fromRGBO(80, 94, 110, 1), + ), + ), + Stack( + alignment: + const FractionalOffset(0.52, 0.24), + children: [ + Icon( + const IconData(0xe63d, + fontFamily: "AlibabaIcon"), + size: 12.sp, + color: e.isPriority + ? Theme.of(context).primaryColor + : const Color.fromRGBO( + 164, 164, 164, 1), + ), + quickText('优先', + size: 4.sp, color: Colors.white), + ], + ), + ], + ); + }).toList(), + ), + ], + ), + ) + ], + ), + ); + }, + ); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 1.h), + child: quickText('已阅', + color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp), + ), + quickText(data.annotatedCount, + color: Theme.of(context).primaryColor, + size: 12.sp, + fontWeight: FontWeight.bold), + quickText('/', + color: const Color.fromRGBO(117, 117, 117, 1), size: 12.sp), + quickText(data.submitCount - data.annotatedCount, + color: const Color.fromRGBO(117, 117, 117, 1), size: 10.sp), + ], + ), + ), + ); + }); +} + +// 试题图片视图 +class QuestionImageView extends HookWidget + with EventBusMixin { + final double maxWidth; + final double maxHeight; + final double actualHeight; + final HomeworkReviewLogic logic; + final ZoomState zoomState; + final HomeworkReviewState sateData; + final HomeworkReviewAnnotationsControlState annotationState; + QuestionImageView( + this.maxWidth, this.maxHeight, this.annotationState, this.logic, + {required this.actualHeight, + required this.zoomState, + required this.sateData, + super.key}); + + /// 获取数组指定倒数具体值的下标 + int _findTargetIndex(List list, T target, [int reciprocal = 2]) { + List indexs = []; + for (int i = list.length - 1; i >= 0; i--) { + if (list[i] == target) { + indexs.add(i); + if (indexs.length == reciprocal) return i; + } + } + return -1; + } + + int _activePointers = 0; + + Timer? timer; + // 定时器超时时间,单位为毫秒 + static const int timeoutDuration = 300; + + /// 解决多指截屏问题后 无法进入手指抬起回调导致无法再次进行批注 + void toTimer(ValueNotifier> vnHandWritings) { + timer?.cancel(); + timer = Timer(const Duration(milliseconds: timeoutDuration), () { + if (_activePointers > 2) { + _activePointers = 0; + if (vnHandWritings.value.last != null) { + vnHandWritings.value.add(null); // 增加空点以分隔不同的线段 + sateData.handwritings = vnHandWritings.value; // 添加笔迹数据 + } + } + }); + } + + /// 获取最后一个点的坐标位置 + Offset? getLastDrop(List vals, int index) { + Offset? lastDrop; + if (vals.isNotEmpty) { + lastDrop = vals[index] as Offset?; + + /// 已经断行的不需要获取 + // if (lastDrop == null) { + // index -= 1; + // if (index > -1) { + // lastDrop = getLastDrop(vals, index); + // } + // } + } + return lastDrop; + } + + @override + Widget build(BuildContext context) { + final theMaxHeight = useState(maxHeight); + useValueChanged( + maxHeight, (oldValue, __) => theMaxHeight.value = maxHeight); + + var zoomKey = useState(GlobalKey()); + useValueChanged(zoomState.zoomFile.value?.templateId, + (old, __) { + zoomKey.value = GlobalKey(); + }); + + var vnHandWritings = useValueNotifier>([]); + + /// 滑动高度 + var initPosition = useState(null); + + // var customPaintSize = useState(Size.zero); + + useEffect(() { + var listenStream = sateData.data.listen((e) { + // 数据清空 + sateData.handwritings = []; + vnHandWritings.value = sateData.handwritings; + }); + + var streamSubscriptionSlide = sateData.slide.listen((e) { + if (sateData.panQuestView != null && + sateData.panQuestView == false && + initPosition.value?.dy.abs().toInt().toDouble() != + sateData.slide.value) { + if (sateData.zoomOffset != null) { + sateData.zoomOffset = + Offset(sateData.zoomOffset!.dx, -sateData.slide.value); + } + initPosition.value = sateData.zoomOffset; + } + }); + return () { + listenStream.cancel(); + streamSubscriptionSlide.cancel(); + }; + }, []); + + // 可选:添加滚动监听 + useEffect(() { + eventOn(callback: (BottomOperationBar e) async { + var annotationsData = vnHandWritings.value; // 批注数据 + if (e.revokeAll) { + // 情况全部 + if (annotationsData.isNotEmpty) { + bool? res = await showDialog( + context: Get.context ?? context, + builder: (context1) { + return AlertDialog( + content: quickText("是否撤销全部批注痕迹?"), + actions: [ + TextButton( + child: quickText("取消"), + onPressed: () => Navigator.pop(context1, false)), + TextButton( + child: quickText("确定", + color: Theme.of(context1).primaryColor), + onPressed: () => Navigator.pop(context1, true)) + ]); + }, + ); + if (res == true) vnHandWritings.value = []; + } else { + // 数据已经是空了 检查是否有上次批注图片 如果有就弹框询问清除 + if (sateData.data.value?.showZgtAnnotate != null) { + await showDialog( + context: Get.context ?? context, + builder: (context1) { + return AlertDialog( + content: quickText("是否撤销上次批阅批注痕迹?"), + actions: [ + TextButton( + child: quickText("取消"), + onPressed: () => Navigator.pop(context1, false)), + TextButton( + child: quickText("确定", + color: Theme.of(context1).primaryColor), + onPressed: () => easyThrottle( + 'REVOKE_THE_LAST_ANNOTATION_AND_SUBMIT', + () { + Navigator.pop(context1, true); + sateData.data.value?.zgtAnnotate = null; + sateData.data.value?.showZgtAnnotate = null; + if (sateData.data.value != null) { + sateData.data.update((_) { + var theStudentQuestions = + sateData.studentQuestions.value; + if (theStudentQuestions?.isNotEmpty ?? + false) { + var noMarking = + theStudentQuestions?.firstWhereOrNull( + (e) => e.studentScore == null); + if (noMarking != null) { + ToastUtils.showInfo( + "未提交!请为第${noMarking.questionNo}题打分,再手动提交"); + return; + } + } + logic.submit(Get.context ?? context); + }); + } + }, + ), + ) + ]); + }, + ); + } + } + return; + } + + // 返回上一步 + if (annotationsData.isEmpty) { + // 数据已经是空了 检查是否有上次批注图片 如果有就弹框询问清除 + if (sateData.data.value?.showZgtAnnotate != null) { + await showDialog( + context: context, + builder: (context1) { + return AlertDialog( + content: quickText("是否撤销上次批阅批注痕迹?"), + actions: [ + TextButton( + child: quickText("取消"), + onPressed: () => Navigator.pop(context1, false)), + TextButton( + child: quickText("确定", + color: Theme.of(context).primaryColor), + onPressed: () => easyThrottle( + 'REVOKE_THE_LAST_ANNOTATION_AND_SUBMIT', + () { + Navigator.pop(context1, true); + sateData.data.value?.zgtAnnotate = null; + sateData.data.value?.showZgtAnnotate = null; + if (sateData.data.value != null) { + sateData.data.update( + (_) => logic.submit(Get.context ?? context)); + } + }, + ), + ) + ]); + }, + ); + } + } else { + var index = _findTargetIndex(annotationsData, null); + if (index != -1) { + annotationsData = annotationsData.sublist(0, index + 1); + annotationsData = List.from(annotationsData); + } else { + annotationsData = []; + } + } + vnHandWritings.value = annotationsData; + }); + + return () { + _activePointers = 0; + eventCancel(); + }; + }, []); + + // print("++++++++++++++++++++++ ${theMaxHeight.value}"); + // print("+++++ 位置:${initPosition.value}"); + + return Listener( + behavior: HitTestBehavior.opaque, + onPointerDown: (PointerDownEvent event) { + // 判断当前是否已经有触摸点,如果有则忽略该触摸事件 + + // 处理单个触摸点按下的逻辑 + _activePointers = _activePointers + 1; + + /// 解决多指截屏问题后 无法进入手指抬起回调导致无法再次进行批注 + toTimer(vnHandWritings); + sateData.panQuestView = true; + }, + onPointerUp: (PointerUpEvent details) { + // 处理单个触摸点抬起的逻辑 + // activePointers--; + // globalPosition = null; + if (_activePointers > 0) { + _activePointers = _activePointers - 1; + } + print("---进入:onPointerUp $_activePointers"); + timer?.cancel(); + if (!annotationState.pen.value) return; + + vnHandWritings.value.add(null); // 增加空点以分隔不同的线段 + sateData.handwritings = vnHandWritings.value; // 添加笔迹数据 + }, + onPointerMove: (PointerMoveEvent event) { + print("进入:onPointerMove $_activePointers"); + if (_activePointers != 1) return; + toTimer(vnHandWritings); + if (!annotationState.pen.value) return; + + Offset localPosition = event.localPosition; // 相对 + var zoomFile = zoomState.zoomFile.value!; + // var imageHeightOffsetStart = zoomFile.imageHeightOffsetStart??0; + var imageHeightOffsetStart = zoomState.zoomFile.value! + .getZoomFileOffsetStart(zoomState.initScale.value ?? 1); + // print("位置:$localPosition; 图片所在位置:$imageHeightOffsetStart"); + if (imageHeightOffsetStart == 0) return; + + var dy = localPosition.dy; + // print(zoomFile.getZoomFileHeightOffsetEnd(zoomState.initScale.value ?? 1)); + if (dy < imageHeightOffsetStart || + dy > + zoomFile.getZoomFileHeightOffsetEnd( + zoomState.initScale.value ?? 1)) return; // 检查笔记是否超出图片范围 + + var theScale = zoomState.initScale.value ?? 1; + // if (theScale != 1) { + // print("PPPPPPPPPPPPPPPPPPPPPPPP ${(zoomFile.imageHeightOffsetStart ?? 0)}"); + // localPosition = Offset(localPosition.dx, localPosition.dy + (zoomFile.imageHeightOffsetStart ?? 0)); + + // // localPosition = Offset(localPosition.dx / theScale, localPosition.dy / theScale); + // // var theZoomOffset = sateData.zoomOffset; + // // if (theZoomOffset != null) { + // // var dx = theZoomOffset.dx; + // // var dy = theZoomOffset.dy; + // // localPosition = Offset(localPosition.dx + dx, localPosition.dy + dy); + // // } + // } + + // 说明:“- imageHeightOffsetStart” 由于显示笔记的位置是以图片的位置开始,手势坐标是以左上角开始 所以需要减去上面空白位置 + // if (theScale == 1) { + // } + // (dy / theScale) - (max(0, imageHeightOffsetStart) / theScale) + ((sateData.zoomOffset?.dy.abs() ?? 0) / theScale), + + var zoomWtdthSpaceVal = zoomFile + .getZoomFileOffsetStartWidth(zoomState.initScale.value ?? 1); + + localPosition = Offset( + (localPosition.dx - + zoomFile.getZoomFileOffsetStartWidth( + zoomState.initScale.value ?? 1) + + ((zoomWtdthSpaceVal <= 0.1) + ? (sateData.zoomOffset?.dx.abs() ?? 0) + : 0)) / + theScale, + (dy - + max(0, imageHeightOffsetStart) + + ((zoomFile.imageHeightOffsetStart == null || + zoomFile.imageHeightOffsetStart! <= 0.1) + ? (sateData.zoomOffset?.dy.abs() ?? 0) + : 0)) / + theScale, + ); + + /// 判断当前点和上一个点的距离 判断是否是多指 + if (Platform.isAndroid) { + var lastDrop = getLastDrop( + vnHandWritings.value, vnHandWritings.value.length - 1); + if (lastDrop != null && + ((lastDrop.dx - localPosition.dx).abs() > 65 || + (lastDrop.dy - localPosition.dy).abs() > 65)) { + /// 当前X点和上一个x点相差 大于10判定为多个手指 + return; + } + } + // print("最终位置 : $localPosition"); + vnHandWritings.value = List.from(vnHandWritings.value) + ..add(localPosition); + sateData.handwritings = vnHandWritings.value; + }, + child: Obx(() { + var isPen = annotationState.pen.value; + var showZgtAnnotate = sateData.data.value?.showZgtAnnotate; + + print(sateData.data.value!.zgtAnswer); + return Container( + height: double.infinity, + width: double.infinity, + alignment: Alignment.center, + child: IgnorePointer( + ignoring: isPen, + child: Zoom( + key: zoomKey.value, + // initTotalZoomOut: true, // 展示全部内容 初始化不产生滚动条 + zoomSensibility: 0.05, + scrollWeight: 4.r, + doubleTapAnimDuration: Duration.zero, + maxZoomWidth: maxWidth, + maxZoomHeight: actualHeight, + canvasColor: Colors.transparent, + // initPosition: initPosition.value, + // initScale: logic.zoomLogic.zoomState.initScale.value ?? 1, + backgroundColor: Colors.transparent, + onScaleUpdate: logic.zoomLogic.onScaleUpdate, + onPositionUpdate: logic.zoomLogic.onPanUpPosition, + child: Stack( + children: [ + $TheCachedNetworkImage( + imgWidth: maxWidth, + imageUrl: sateData.data.value!.zgtAnswer, + (_, imageProvider) => + Image(image: imageProvider, fit: BoxFit.fitWidth), + ), + RepaintBoundary( + key: logic.pictureOverviewKey, + child: CustomPaint( + // isComplex: true, + size: Size( + maxWidth, zoomState.zoomFile.value!.actualHeight!), + foregroundPainter: DrawingPainter(ctrl: vnHandWritings), + // child: $TheCachedNetworkImage( + // imgWidth: maxWidth, + // imageUrl: showZgtAnnotate ?? sateData.data.value!.zgtAnswer, + // (_, imageProvider) => Image(image: imageProvider, fit: BoxFit.fitWidth), + + // ), + child: showZgtAnnotate != null + ? $TheCachedNetworkImage( + imgWidth: maxWidth, + imageUrl: showZgtAnnotate, + (_, imageProvider) => Image( + image: imageProvider, fit: BoxFit.fitWidth)) + : null, + ), + ), + ], + ), + ), + ), + ); + }), + ); + } +} + +// 批注框 +class DrawingPainter extends CustomPainter { + final ValueNotifier> ctrl; + final Paint paintBrush = Paint() + ..color = Colors.red + ..strokeCap = StrokeCap.round + ..strokeWidth = 0.7.sp; + DrawingPainter({required this.ctrl}) : super(repaint: ctrl); + + @override + void paint(Canvas canvas, Size size) { + var points = ctrl.value; + var pointsLength = points.length; + for (int i = 0; i < pointsLength; i++) { + Offset? offsetData = points[i]; + Offset? nextOffsetData = pointsLength - 1 == i ? null : points[i + 1]; + if (offsetData != null && nextOffsetData != null) + canvas.drawLine(offsetData, nextOffsetData, paintBrush); + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; + + @override + bool shouldRebuildSemantics(CustomPainter oldDelegate) => false; +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart new file mode 100644 index 0000000..5830dd5 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/index.dart @@ -0,0 +1,380 @@ +import 'dart:async'; + +import 'dart:ui' as ui; + +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:get/get.dart'; +import 'package:get/get_rx/get_rx.dart'; +import 'package:making_school_asignment_app/common/job/annotate_list_to_refresh.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_param.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/do_paper_details_result.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/do_test_questions_image_info.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/favor_param.dart'; +import 'package:making_school_asignment_app/common/job/marking_models/review_submission_params.dart'; +import 'package:making_school_asignment_app/common/mixins/event_bus_mixin.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/permission_describe_util.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/common/utils/upload_oss_img_utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:permission_handler/permission_handler.dart'; + +import 'zoom_logic.dart'; + +// 数据 +class HomeworkReviewState { + HomeworkReviewState(); + + // late String homeworkId; + // late String homeworkName; + late Rx param; + late Rx data = Rx(null); + late Rx?> studentQuestions = Rx?>(null); + late Rx slide = 0.0.obs; // 滑动位置 + bool? panQuestView = null; + // late Rx imageScale; + // late Rx imageScaleZoom = Rx(null); + + /// 图片放大后的操作存放数据 + List handwritings = []; + bool needRefresh = false; + bool lastQuestionPrompt = false; // 最后一题提示 + Rx getDataError = false.obs; // 获取作业数据报错 + + Offset? zoomOffset; + RxBool favorite = false.obs; // 初始化数据 + RxBool submitLoading = false.obs; // 提交加载 + // late String dateEnd = ''; + // late int knowledgeId = 0; + // late RxList dataList = RxList(); + // late RxList studentList = RxList(); + // late RxString knowledgeName = ''.obs; +} + +// 批注控制器 +class HomeworkReviewAnnotationsControlState { + HomeworkReviewAnnotationsControlState(); + // late RxBool backStep = false.obs; // 返回上一步 + + RxBool pen = true.obs; // 笔 + RxBool gestureMove = false.obs; // 手势移动 + RxBool clearAll = false.obs; // 清空全部 + RxBool opControl = true.obs; // 批注控制器开关 +} + +class HomeworkReviewBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => HomeworkReviewLogic()); + } +} + +class HomeworkReviewLogic extends GetxController with RequestToolMixin, EventBusMixin { + final zoomLogic = Get.find(); + final GlobalKey pictureOverviewKey = GlobalKey(); + late StreamSubscription _paramListen; + late StreamSubscription _dataListen; + final HomeworkReviewState state = HomeworkReviewState(); + final HomeworkReviewAnnotationsControlState annotationState = HomeworkReviewAnnotationsControlState(); + double appBarHeight = 56; + + StreamSubscription? imageScaleZoomStream; + + @override + void onInit() { + appBarHeight = MediaQuery.of(Get.context!).padding.top; + print("appBarHeight :$appBarHeight"); + // WidgetsFlutterBinding.ensureInitialized(); + + // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); // 屏幕刘海 + + state.param = DoPaperDetailsParam( + homeworkId: Get.arguments['homeworkId'], + homeworkName: Get.arguments['homeworkName'], + classId: Get.arguments['classId'], + subject: Get.arguments['subject'], + ).obs; + // state.imageScale = Rx(null); + + // 参数变化更新作业详情 + _paramListen = state.param.listen((e) => getData()); + // 试题数据 + _dataListen = state.data.listen((e) { + if (e == null) return; + var zoomState = zoomLogic.zoomState; + + + + final currentTemplateId = zoomState.zoomFile.value?.templateId; // 获取旧题号ID + if (currentTemplateId != null && currentTemplateId != e.templateId) { + // zoom 题号判断是否有变 有变就需要清空 zoom文件 + zoomState.initScale.value = null; + zoomState.zoomFile.value!.clearZoomFile(e.templateId); + zoomState.zoomFile.update((_) {}); // 更新的是对象 需要执行此回调 + } + if (state.favorite.value != e.isFav) state.favorite.value = !state.favorite.value; + }); + + // imageScaleZoomStream = state.imageScale.listen((e) { + // // state.imageScaleZoom.value = theImageScale; + // var theImageScaleZoom = state.imageScaleZoom.value; + // if (theImageScaleZoom == null || theImageScaleZoom.url != e?.url) state.imageScaleZoom.value = e; + // }); + + WidgetsBinding.instance.addPostFrameCallback((_) => getData()); + super.onInit(); + } + + @override + void onReady() { + Future.delayed(Duration.zero, () { + DeviceInfoPlugin().androidInfo.then((androidInfo) { + Permission storagePermission = androidInfo.version.sdkInt >= 33 ? Permission.manageExternalStorage : Permission.storage; + PermissionDescribeUtil.instance.toLaunchPermissionRequest( + Get.context, + title: '储存权限请求', + describe: "为了提供更好的服务,需要获取到存储权限用于保存批阅痕迹并上传", + permissions: [storagePermission], + ); + }); + }); + + super.onReady(); + } + + @override + void onClose() { + SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.top]); // 屏幕刘海 + eventCancel(); + _dataListen.cancel(); + _paramListen.cancel(); + imageScaleZoomStream?.cancel(); + super.onClose(); + } + + void getData() async { + var timerControl = Timer(const Duration(milliseconds: 300), () => ToastUtils.showLoading()); + try { + DoPaperDetailsResult data = await getClient().getDoPaperDetails(state.param.value); + + // var studentQuestions = data.studentQuestions; + // // 第0个的下标数据不需要处理 + // for (var i = 0; i < studentQuestions.length; i++) { + // var item = studentQuestions[i]; + + // item.topHeight = itemPre.height; + // } + state.getDataError.value = false; + state.handwritings = []; + + state.param.value.templateId ??= data.templateId; + state.param.value.studentId ??= data.studentId; + + state.studentQuestions.value = data.studentQuestions; // 赋值试题集合 + state.data.value = data; + } catch (e) { + print('获取数据报错了:$e'); + // ToastUtils.showError('未获取到试题数据,请重试'); + state.getDataError.value = true; + } finally { + if (timerControl.isActive) timerControl.cancel(); + ToastUtils.dismiss(); + } + } + + // 取消全部评分 + void cancelAllRatings() { + var studentQuestions = state.studentQuestions.value; + if (state.data.value?.studentQuestions.isEmpty ?? true) return; + for (var e in studentQuestions!) { + if (e.studentScore != null) { + e.studentScore = null; + } + } + // state.studentQuestions.value = data; + // state.data.value?.studentQuestions = data; + state.studentQuestions.update((_) {}); + } + + // 全部统一打分 + void allRating(int score) { + var studentQuestions = state.studentQuestions.value; + if (state.data.value?.studentQuestions.isEmpty ?? true) return; + for (var e in studentQuestions!) { + e.studentScore = score; + } + // state.studentQuestions.value = data; + // state.data.value?.studentQuestions = data; + state.studentQuestions.update((_) {}); + } + + // 全对评分 + void allPairs(BuildContext context, [int score = 2]) async { + allRating(score); + await submit(context); + } + + // 全错评分 + void allWrongRating(BuildContext context, [int score = 0]) async { + allRating(score); + await submit(context); + } + + // 上传图片 + Future saveImage(context) async { + if (state.handwritings.isEmpty) return null; + try { + var data = state.data.value; + var param = state.param.value; + if (data == null) return null; + + // 获取OSS 图片url + String imgKey = UploadOssImgUtils.getInstance().setImgKey(param.homeworkId, data.studentId.toString(), data.templateId.toString()); + var resUrl = await getClient().getOssPresignedUri(imgKey); + if (resUrl == null) return null; + + // 没有图片就上传图片 + RenderRepaintBoundary? boundary = pictureOverviewKey.currentContext!.findRenderObject() as RenderRepaintBoundary?; + if (boundary == null) return null; + double dpr = MediaQuery.of(context).devicePixelRatio; + + /// 此图片在设备中的像素比例 + var pixelRatio = zoomLogic.zoomState.zoomFile.value?.pixelRatio; + ui.Image image = await boundary.toImage(pixelRatio: pixelRatio ?? dpr); + ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png); + if (byteData == null) return null; + + Dio dio = Dio(); + dio.options.contentType = null; + List bytes = byteData.buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes); + await dio.put( + resUrl, + data: Stream.fromIterable(bytes.map((e) => [e])), + options: Options(contentType: null, headers: {Headers.contentLengthHeader: bytes.length}), + ); + + return imgKey; + } catch (e) { + print('图片上传失败'); + print(e.toString()); + ToastUtils.getFluttertoast(msg: '图片上传失败', context: context); + } finally { + // ToastUtils.dismiss(); + } + return null; + } + + // 提交打分 + /// allPairs + Future submit(BuildContext context) async { + try { + if (state.submitLoading.value) { + ToastUtils.showInfo("正在提交批阅数据,请勿重复操作"); + return; + } + state.submitLoading.value = true; + var data = state.data.value; + if (data == null) return; + + if ((state.data.value?.studentQuestions.isEmpty ?? true) || (state.studentQuestions.value?.isEmpty ?? true)) return; + var studentQuestions = state.studentQuestions.value!.where((e) => e.useTime != null && e.useTime! > 0).toList(); + // 跳过学生未作答的题 + var noRatingElement = studentQuestions.firstWhereOrNull((e) => e.studentScore == null); + if (noRatingElement != null) { + ToastUtils.showInfo('${noRatingElement.questionNo}题请评分'); + return; + } + + // 图片上传 + String? zgtAnnotate = state.data.value?.zgtAnnotate; + String? newzgtAnnotate = await saveImage(context); + if (newzgtAnnotate != null) zgtAnnotate = newzgtAnnotate; + + await getClient() + .reviewSubmission(ReviewSubmissionParams( + homeworkId: state.param.value.homeworkId, + templateId: data.templateId, + studentId: data.studentId, + zgtAnnotate: zgtAnnotate, + studentScores: studentQuestions.map((e) { + var studentScore = e.studentScore!; + return StudentScores( + isCorrect: studentScore == 2, + questionNo: e.questionNo, + studentScore: studentScore, + ); + }).toList())) + .then((e) async { + state.needRefresh = true; + var totalUnAnnotateCount = data.totalUnAnnotateCount; + if (data.needAnnotate) totalUnAnnotateCount -= 1; // 是否需要批阅 + + if (totalUnAnnotateCount <= 0) { + // 批阅完成 + if (!state.lastQuestionPrompt) { + await showDialog( + context: Get.context ?? context, + builder: (BuildContext context1) { + return AlertDialog( + title: quickText('批阅已完成'), + content: const Text('暂无更多批阅项'), + actions: [ + TextButton( + child: const Text('继续'), + onPressed: () { + state.lastQuestionPrompt = true; + Navigator.of(context1).pop(); + }, + ), + TextButton( + child: const Text('退出批阅'), + onPressed: () { + Navigator.of(context1).pop(); + Get.back(); + }), + ], + ); + }, + ); + } else { + ToastUtils.showSuccess("已经提交", duration: const Duration(milliseconds: 800)); + } + return; + } + var newParams = DoPaperDetailsParam.fromJson(state.param.value.toJson()); + if (totalUnAnnotateCount > 0) { + // 当前批阅任务完成 重复提交后 停留在当前数据位置 + newParams.templateId = null; + newParams.studentId = null; + } + state.param.value = newParams; + }); + } catch (_) { + print("批阅提交报错 $_"); + } finally { + state.submitLoading.value = false; + } + } + + Future toFavorite() async { + try { + var data = state.data.value!; + var param = state.param.value; + await getClient().toFavStudent(FavorParam( + homeworkId: param.homeworkId, + studentId: data.studentId, + templateId: data.templateId, + questionNo: data.studentQuestions[0].questionNo, + isFav: !data.isFav, + )); + state.favorite.value = !data.isFav; + data.isFav = state.favorite.value; + } catch (e) { + ToastUtils.showError('操作失败,请重试'); + } + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/zoom_logic.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/zoom_logic.dart new file mode 100644 index 0000000..c3a3f46 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/configuration_files/zoom_logic.dart @@ -0,0 +1,266 @@ +import 'dart:ui' show ImmutableBuffer, ImageDescriptor; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart' as anti_shake_throttling; +import 'package:flutter/widgets.dart'; + +import 'dart:async'; + +import 'package:get/get.dart'; + +import 'package:json_annotation/json_annotation.dart'; + +import 'index.dart'; + +part 'zoom_logic.g.dart'; + +class ZoomLogic extends GetxController { + ZoomState zoomState = ZoomState( + initScale: Rx(null), + zoomFile: Rx(null), + ); + + var oldTemplateId; + late StreamSubscription _streamHomework; + late StreamSubscription _streamZoomState; + + StreamSubscription? initScaleStream; + + @override + void onInit() { + oldTemplateId = zoomState.zoomFile.value?.templateId; + + /// 根据第一次加载的试题题号 分析试题图片所占的宽高 + _streamZoomState = zoomState.zoomFile.listen((e) { + var templateId = e?.templateId; + if (templateId == null) return; + + var homeworkData = Get.find().state.data.value; + var zgtAnswer = homeworkData?.zgtAnswer; + if (zgtAnswer == null) return; + if (oldTemplateId == templateId) return; + + // getNetworkImageDimensions(zgtAnswer); + + // 第三方库网络图,图片会被解码并缓存于内存 + oldTemplateId = templateId; + CachedNetworkImageProvider(zgtAnswer).getImageSize().then((s) { + // 提取宽度和高度 + if (s == null) return; + var oldVal = zoomState.zoomFile.value!; + oldVal.fileWidth = s.width; + oldVal.fileHeight = s.height; + zoomState.zoomFile.value = ZoomFileModel.fromJson(oldVal.toJson()); + }); + }); + + WidgetsBinding.instance.addPostFrameCallback((e) { + /// 试题加载后更新尺寸对象(只要题号没有变就不更新尺寸对象) + _streamHomework = Get.find().state.data.listen((e) { + print("HOMEWORKSTATE 变化了"); + if (e == null || zoomState.zoomFile.value == null) return; + zoomState.zoomFile.value!.templateId = e.templateId; + print("666666 ${e.templateId}"); + zoomState.zoomFile.value = ZoomFileModel.fromJson(zoomState.zoomFile.value!.toJson()); + }); + }); + + /// 监听缩放 + initScaleStream = zoomState.initScale.listen((e) {}); + + super.onInit(); + } + + @override + void onClose() { + _streamHomework.cancel(); + _streamZoomState.cancel(); + super.onClose(); + } + + // 缩放组件 ==> 缩放监听 + void onScaleUpdate(double scale, double zoom) async { + print("$scale $zoom"); + + /// 防抖 + zoomState.initScale.value = zoom; + // anti_shake_throttling.debounce(() => zoomState.initScale.value = zoom, const Duration(milliseconds: 100))(); + } + + // 缩放组件 ==> 位置更新 + void onPanUpPosition(Offset val) async { + // 手指在移动 非物体移动的位置 + var state = Get.find().state; + if (state.zoomOffset?.dy.toStringAsFixed(2) != val.dy.toStringAsFixed(2) || + state.zoomOffset?.dx.toStringAsFixed(2) != val.dx.toStringAsFixed(2)) { + // print('**************** 正在移动位置 YYY:${val.dy}'); + // print('**************** 正在移动位置 XXX:${val.dx}'); + state.zoomOffset = val; + state.slide.value = val.dy.abs().toInt().toDouble(); + } + } +} + +class HomeworkReviewZoomBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => ZoomLogic()); + } +} + +class ZoomState { + final Rx initScale; + final Rx zoomFile; + + const ZoomState({required this.zoomFile, required this.initScale}); +} + +@JsonSerializable() +class ZoomFileModel extends Object { + double viewWidth; // 容器宽度 + double viewHeight; // 容器高度 + + double scaleRatio; // 基准 + + int? templateId; // 页码 + + double? pixelRatio; // 像素比率 + + double? fileWidth; // 文件宽度 + double? fileHeight; // 文件高度 + + double? actualWidth; // 实际展示宽度 + double? actualHeight; // 实际展示高度 + + double? remainingHeight; // 视图剩余高度 实际展示图片展示高度下 剩余高度.(若为负数就是超出视图的高度值) + double? imageHeightOffsetStart; // 顶部坐标Y + double? imageHeightOffsetend; // 底部坐标Y + + ZoomFileModel({ + required this.viewWidth, + required this.viewHeight, + this.scaleRatio = 1, + this.templateId, + this.fileWidth, + this.fileHeight, + this.actualWidth, + this.actualHeight, + this.remainingHeight, + this.imageHeightOffsetStart, + this.imageHeightOffsetend, + this.pixelRatio, + }) { + // 图片已视图宽为基准,高度自适应可滑动 图片的实际宽高都需要乘此基准值. + if (fileHeight == null || fileWidth == null) return; + + scaleRatio = viewWidth / fileWidth!; + actualWidth = fileWidth! * scaleRatio; + actualHeight = fileHeight! * scaleRatio; + + pixelRatio = fileWidth! / viewWidth; // 图片在此设备的像素比例 + + remainingHeight = viewHeight - actualHeight!; + imageHeightOffsetStart = remainingHeight! / 2; + imageHeightOffsetend = imageHeightOffsetStart! + actualHeight!; + } + + factory ZoomFileModel.fromJson(Map srcJson) => _$ZoomFileModelFromJson(srcJson); + + Map toJson() => _$ZoomFileModelToJson(this); + + // 清空zoom文件(templateId 页码变换清空试题图片信息) + ZoomFileModel clearZoomFile(int newTemplateId) { + templateId = newTemplateId; // 页码 + fileWidth = null; // 文件宽度 + fileHeight = null; // 文件高度 + actualWidth = null; // 实际展示宽度 + actualHeight = null; // 实际展示高度 + remainingHeight = null; // 视图剩余高度 实际展示图片展示高度下 剩余高度.(若为负数就是超出视图的高度值) + imageHeightOffsetStart = null; // 顶部坐标Y + imageHeightOffsetend = null; // 底部坐标Y + return this; + } + + /// 获取缩放比例后的空白距离 + /// zoom 缩放比例 + double getZoomFileOffsetStart(double zoom) { + if (zoom == 1 || actualHeight == null) return imageHeightOffsetStart ?? 0; + return (viewHeight - (actualHeight! * zoom)) / 2; + } + + /// 获取宽度的缩放后的空间距离 + /// zoom 缩放比例 + double getZoomFileOffsetStartWidth(double zoom) { + if (zoom >= 1 || actualWidth == null) return 0; + + return (viewWidth - (actualWidth! * zoom)) / 2; + } + + /// 获取缩放比例后的底部图片位置 + /// zoom 缩放比例 + double getZoomFileHeightOffsetEnd(double zoom) { + if (zoom == 1 || actualHeight == null) return imageHeightOffsetend ?? 0; + var topSpaceDimensions = getZoomFileOffsetStart(zoom); + return topSpaceDimensions + (actualHeight! * zoom); + } +} + +// 最终版 +extension GetImageSize on ImageProvider { + Future getImageSize({bool avoidDecode = false}) async { + if (avoidDecode) { + // 是否要免解码 + final cacheStatus = await obtainCacheStatus(configuration: const ImageConfiguration()); + final tracked = cacheStatus?.tracked ?? false; + // 内存缓存中存在时优先从缓存中取,不在内存缓存中时转换为 ImageDescriptor + if (!tracked) { + ImmutableBuffer? buffer; + if (this is AssetBundleImageProvider) { + final key = await obtainKey(const ImageConfiguration()) as AssetBundleImageKey; + buffer = await key.bundle.loadBuffer(key.name); + } else if (this is FileImage) { + final file = (this as FileImage).file; + final int lengthInBytes = await file.length(); + if (lengthInBytes > 0) { + buffer = await ImmutableBuffer.fromFilePath(file.path); + } + } else if (this is MemoryImage) { + final bytes = (this as MemoryImage).bytes; + buffer = await ImmutableBuffer.fromUint8List(bytes); + } + if (buffer != null) { + final descriptor = await ImageDescriptor.encoded(buffer); + final size = Size(descriptor.width.toDouble(), descriptor.height.toDouble()); + buffer.dispose(); + descriptor.dispose(); + if (!size.isEmpty) return size; + } + } + } + + // 免解码末开启或内存缓存已存在,最后再兜底上面未处理的情况 + final completer = Completer(); + ImageStream imageStream = resolve(const ImageConfiguration()); + + ImageStreamListener? listener; + listener = ImageStreamListener( + (imageInfo, synchronousCall) { + if (!completer.isCompleted) { + completer.complete(Size(imageInfo.image.width.toDouble(), imageInfo.image.height.toDouble())); + } + WidgetsBinding.instance.addPostFrameCallback((_) { + imageInfo.dispose(); + imageStream.removeListener(listener!); + }); + }, + onError: (exception, stackTrace) { + if (!completer.isCompleted) { + completer.complete(); + } + imageStream.removeListener(listener!); + }, + ); + imageStream.addListener(listener); + + return completer.future; + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/homework_review/index.dart b/making_school_asignment_app/lib/page/home_page/children/homework_review/index.dart new file mode 100644 index 0000000..05a4807 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/homework_review/index.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/annotate_list_to_refresh.dart'; +import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/home_page/children/annotate_class/annotate_class_logic.dart'; +import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/question_paper_view.dart'; +import 'package:making_school_asignment_app/page/home_page/home_logic.dart'; + +import 'components/bottom_operation_bar.dart'; +import 'components/dropdown_switch_students_type.dart'; +import 'components/favorite_widget.dart'; +import 'configuration_files/index.dart'; + +class HomeworkReview extends StatelessWidget { + const HomeworkReview({super.key}); + + @override + Widget build(BuildContext context) { + final logic = Get.find(); + final sateData = logic.state; + final AnnotateClassLogic controller = Get.find(); + final HomeLogic homeLogicController = Get.find(); + + return PopScope( + canPop: false, + onPopInvoked: (e) { + if (e && sateData.needRefresh) { + controller.getList(); + homeLogicController.getList(); + logic.eventFire(model: AnnotateListToRefresh()); + } + }, + child: Scaffold( + appBar: AppBar( + // titleSpacing: 0, + leading: IconButton(icon: const Icon(Icons.arrow_back_ios), onPressed: () => Get.back()), + iconTheme: const IconThemeData(color: Colors.black), + title: quickText(sateData.param.value.homeworkName), + backgroundColor: Colors.white, + elevation: 0, + actions: [const FavoriteWidget(), SizedBox(width: 5.w), const ReturnToHomepage()], + ), + body: const Column( + children: [ + // 下拉切换 + DropdownSwitchStudentsType(), + // SizedBox(height: 10), + // 试题展示区和打分区 + Expanded(child: QuestionPaperView()), + // 底部功能区 + BottomAnnotationSwitch() + ], + ), + ), + ); + } +} diff --git a/lib/page/home_page/children/job_report/job_report_binding.dart b/making_school_asignment_app/lib/page/home_page/children/job_report/job_report_binding.dart similarity index 100% rename from lib/page/home_page/children/job_report/job_report_binding.dart rename to making_school_asignment_app/lib/page/home_page/children/job_report/job_report_binding.dart diff --git a/making_school_asignment_app/lib/page/home_page/children/job_report/job_report_logic.dart b/making_school_asignment_app/lib/page/home_page/children/job_report/job_report_logic.dart new file mode 100644 index 0000000..3c8451c --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/job_report/job_report_logic.dart @@ -0,0 +1,67 @@ +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; + +import 'job_report_state.dart'; + +class JobReportLogic extends GetxController with RequestToolMixin { + final JobReportState state = JobReportState(); + + @override + void onInit() { + super.onInit(); + state.title.value = Get.arguments['title'] ?? ''; + state.homeworkId.value = Get.arguments['homeworkId'] ?? ''; + state.classId.value = Get.arguments['classId'] ?? ''; + state.className.value = Get.arguments['className'] ?? ''; + state.grade = Get.arguments['grade'] ?? ''; + EasyLoading.show(status: 'loading...'); + getClass(); + } + + void getClass() async { + List data = + await getClient().getAnnotatedClassList(state.homeworkId.value); + state.involveClasses.value = data; + + state.involveClasses.value = [state.classData.value, ...(data ?? [])]; + for (var element in state.involveClasses) { + if (element.className == state.className.value && + element.grade == state.grade) { + state.classData.value = element; + } + } + getWorkData(); + } + + void getWorkData() async { + HomeworkDetails data = await getClient().getHomeworkDetails( + state.homeworkId.value, + state.classData.value.classId != '-1' + ? state.classData.value.classId + : ''); + state.dataCount = Utils.getHomeworkData(data); + state.subject = data.subject!; + state.homeData = data; + state.kgReport.value = + data.questions.where((w) => w.questionType == 1).toList(); + state.zgReport.value = + data.questions.where((w) => w.questionType == 2).toList(); + state.studentList.value = [...data.students]; + state.knowsList.value = data.knows; + state.hasData.value = true; + EasyLoading.dismiss(); + + state.studentList.sort((a, b) { + int num1 = a.kgtOkCount! + a.zgtOkCount!; + int num2 = b.kgtOkCount! + b.zgtOkCount!; + if (num1 == num2) { + return a.allTime! > b.allTime! ? num1 : num2; + } + return num2.compareTo(num1); + }); + } +} diff --git a/lib/page/home_page/children/job_report/job_report_state.dart b/making_school_asignment_app/lib/page/home_page/children/job_report/job_report_state.dart similarity index 61% rename from lib/page/home_page/children/job_report/job_report_state.dart rename to making_school_asignment_app/lib/page/home_page/children/job_report/job_report_state.dart index cb642c9..e532728 100644 --- a/lib/page/home_page/children/job_report/job_report_state.dart +++ b/making_school_asignment_app/lib/page/home_page/children/job_report/job_report_state.dart @@ -1,7 +1,7 @@ import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/annotated_class.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_state.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.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'; class JobReportState { JobReportState() { @@ -21,6 +21,7 @@ class JobReportState { late RxList knowsList = RxList(); late HomeworkDetails homeData; late RxList involveClasses = RxList(); - late AnnotatedClass defaultClass = AnnotatedClass('',-1,'-1','','',-1,-1,-1,-1,-1,[],[],-1,-1,-1,-1,-1,[],[]); + late AnnotatedClass defaultClass = AnnotatedClass('', -1, '-1', '', '', -1, -1, -1, -1, -1, [], [], -1, -1, -1, -1, -1, [], []); late Rx classData = defaultClass.obs; + late int subject = -1; } diff --git a/making_school_asignment_app/lib/page/home_page/children/job_report/job_report_view.dart b/making_school_asignment_app/lib/page/home_page/children/job_report/job_report_view.dart new file mode 100644 index 0000000..00ccad4 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/job_report/job_report_view.dart @@ -0,0 +1,131 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; +import 'package:making_school_asignment_app/page/home_page/children/job_report/widget/dropdown_selection.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/home_page/children/job_report/widget/knowledge_point.dart'; +import 'package:making_school_asignment_app/page/home_page/children/job_report/widget/personnel_data_overview.dart'; +import 'package:making_school_asignment_app/page/home_page/children/job_report/widget/top_count.dart'; +import 'package:making_school_asignment_app/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart'; + +import 'job_report_logic.dart'; + +class JobReportPage extends StatefulWidget { + const JobReportPage({super.key}); + + @override + State createState() => _JobReportPageState(); +} + +class _JobReportPageState extends State { + final logic = Get.find(); + final state = Get.find().state; + + @override + Widget build(BuildContext context) { + return OrientationBuilder(builder: (BuildContext context, Orientation orientation) { + return Scaffold( + backgroundColor: const Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + backgroundColor: Colors.white, + centerTitle: true, + title: Center(child: Obx(() { + return quickText( + '${state.title.value}作业报告', + size: 14.sp, + color: const Color.fromRGBO(51, 51, 51, 1), + ); + })), + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Get.back(), + ), + actions: const [ + ReturnToHomepage(), + ], + ), + body: Obx(() { + if (state.hasData.value) { + return SingleChildScrollView( + child: Column( + children: [ + // 下拉框 + Container( + padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 10.w), + decoration: const BoxDecoration( + color: Colors.white, + ), + child: Row( + children: [ + Obx(() { + return DropdownSelection( + involveClasses: state.involveClasses.value, + classData: state.classData.value, + call: (AnnotatedClass item) { + state.classData.value = item; + if (item.grade == -1) state.classData.value = state.defaultClass; + logic.getWorkData(); + }); + }), + // Expanded(child: Text('')), + ], + ), + ), + //完成率、正确率 + TopCount(state.dataCount, state.classData == null ? '' : state.classData.value.className, state.homeworkId.value, state.subject), + //客观题、主观题 + KgtZgtTable( + studentCount: state.dataCount.studentCount!, + homeworkId: state.homeworkId.value, + kgReport: state.kgReport, + zgReport: state.zgReport, + kgtOkRate: state.dataCount.kgtOkRate!.toStringAsFixed(0), + zgtOkRate: state.dataCount.zgtOkRate!.toStringAsFixed(0), + kgtCorrectRate: state.dataCount.kgtCorrectRate!.toStringAsFixed(0), + zgtCorrectRate: state.dataCount.zgtCorrectRate!.toStringAsFixed(0), + subject: state.subject, + ), + // 掌握知识点的情况 + Container( + margin: EdgeInsets.symmetric(horizontal: 10.r), + child: KnowledgePoint( + knowsList: state.knowsList, + data: state.homeData, + className: state.classData.value.className, + homeworkId: state.homeworkId.value, + subject: state.subject, + )), + // 掌握知识点的情况 + /* Container( + margin: EdgeInsets.symmetric(horizontal: 10.r), + child: $OverallPerformance(data.studentCount, data.overallTitles)), + // 单位时间答题情况 + Container( + margin: EdgeInsets.symmetric(horizontal: 10.r), + child: $UnitTimeAnsweringSituation(widget.id, data.questionAnswerInfos)),*/ + // 人员数据概况 + Container(margin: EdgeInsets.symmetric(horizontal: 10.r), child: PersonnelDataOverview(studentList: state.studentList.value)), + + SizedBox( + height: 30.r, + ), + ], + ), + ); + } else { + return Padding(padding: EdgeInsets.only(top: MediaQuery.of(context).size.height / 2 - 200.r), child: const MyEmptyWidget()); + } + }), + ); + }); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} diff --git a/lib/page/home_page/children/job_report/widget/dropdown_selection.dart b/making_school_asignment_app/lib/page/home_page/children/job_report/widget/dropdown_selection.dart similarity index 56% rename from lib/page/home_page/children/job_report/widget/dropdown_selection.dart rename to making_school_asignment_app/lib/page/home_page/children/job_report/widget/dropdown_selection.dart index 094fd1a..3160499 100644 --- a/lib/page/home_page/children/job_report/widget/dropdown_selection.dart +++ b/making_school_asignment_app/lib/page/home_page/children/job_report/widget/dropdown_selection.dart @@ -1,14 +1,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:school_asignment_app/common/job/annotated_class.dart'; -import 'package:school_asignment_app/common/utils/enum_untils.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.dart'; +import 'package:making_school_asignment_app/common/utils/enum_untils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; class DropdownSelection extends StatefulWidget { - final List? involveClasses; - final AnnotatedClass? classData; - final Function(AnnotatedClass) call; - const DropdownSelection({Key? key,required this.involveClasses,required this.classData,required this.call}) : super(key: key); + final List? involveClasses; + final AnnotatedClass? classData; + final Function(AnnotatedClass) call; + final Color? bgColor; + const DropdownSelection({Key? key, required this.involveClasses, required this.classData, required this.call,this.bgColor}) : super(key: key); @override State createState() => _DropdownSelectionState(); @@ -17,12 +18,12 @@ class DropdownSelection extends StatefulWidget { class _DropdownSelectionState extends State { @override Widget build(BuildContext context) { - return Container( + return Container( // width: 200.r, padding: EdgeInsets.symmetric(horizontal: 10.r), - decoration: const BoxDecoration( - color: Color(0xFFF5F5F5), - borderRadius: BorderRadius.vertical( + decoration: BoxDecoration( + color: widget.bgColor ?? const Color(0xFFF5F5F5), + borderRadius: const BorderRadius.vertical( top: Radius.elliptical(10, 10), bottom: Radius.elliptical(10, 10), )), @@ -34,11 +35,7 @@ class _DropdownSelectionState extends State { items: widget.involveClasses?.map((e) { return DropdownMenuItem( value: e.classId!, - child: quickText( - e.classId == '-1' - ? '全部' - : - ' ${EnumUtils.formatGrade(e.grade)}${e.className}', size: 12.sp, color: Colors.black), + child: quickText(e.classId == '-1' ? '全部' : ' ${EnumUtils.formatGrade(e.grade)}${e.className}', size: 12.sp, color: Colors.black), ); }).toList(), onChanged: (value) { diff --git a/making_school_asignment_app/lib/page/home_page/children/job_report/widget/knowledge_point.dart b/making_school_asignment_app/lib/page/home_page/children/job_report/widget/knowledge_point.dart new file mode 100644 index 0000000..f1c64fd --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/job_report/widget/knowledge_point.dart @@ -0,0 +1,308 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:percent_indicator/linear_percent_indicator.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +class KnowledgePoint extends StatefulWidget { + final RxList knowsList; + final HomeworkDetails data; + final String className; + final String homeworkId; + final int subject; + const KnowledgePoint( + {super.key, required this.knowsList, required this.data, required this.className, required this.homeworkId, required this.subject}); + + @override + State createState() => _KnowledgePointState(); +} + +class _KnowledgePointState extends State { + void goQuickCheckPersonalPath(studentId) { + if (studentId != null) { + Get.toNamed(Routes.studentPersonalPage, arguments: {'studentId': studentId, 'homeworkId': widget.homeworkId, 'subject': widget.subject}); + } + } + + void showPeopleListDialog({ + required BuildContext context, + required String title, + required List arr, + }) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + // insetPadding: EdgeInsets.symmetric(vertical: 20.r,horizontal: 20.r), + backgroundColor: const Color(0xFFFFFFFF), + contentPadding: EdgeInsets.all(20.r), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15.r))), + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.7, + height: MediaQuery.of(context).size.height * 0.7, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Text( + title, + style: TextStyle(fontSize: 15.sp, color: const Color(0xFF3C3C3C), fontWeight: FontWeight.w500), + ), + ), + SizedBox( + height: 10.r, + ), + Row( + children: [ + Expanded( + flex: 2, + child: Center( + child: Text( + '姓名', + style: TextStyle(fontSize: 12.sp, color: const Color(0xFF6A6A6A)), + ))), + SizedBox( + width: 10.r, + ), + Expanded( + flex: 1, + child: Center( + child: Text( + '班级', + style: TextStyle(fontSize: 12.sp, color: const Color(0xFF6A6A6A)), + ))), + SizedBox( + width: 10.r, + ), + Expanded( + flex: 2, + child: Center( + child: Text( + '掌握度', + style: TextStyle(fontSize: 12.sp, color: const Color(0xFF6A6A6A)), + ))), + SizedBox( + width: 10.r, + ), + Expanded( + flex: 3, + child: Center( + child: Text( + '掌握情况', + style: TextStyle(fontSize: 12.sp, color: const Color(0xFF6A6A6A)), + ))), + ], + ), + SizedBox( + height: 5.r, + ), + arr.isNotEmpty + ? Expanded( + child: ListView.builder( + shrinkWrap: true, + itemBuilder: (context, index) { + var item = arr[index]; + return Container( + padding: EdgeInsets.symmetric(vertical: 5.r), + color: const Color(0xFFF0F0F0), + margin: EdgeInsets.only(bottom: 2.r), + child: Row( + children: [ + Expanded( + flex: 2, + child: InkWell( + onTap: () { + goQuickCheckPersonalPath(item.studentId); + }, + child: Center( + child: Text( + item.studentName!, + style: TextStyle(fontSize: 12.sp, color: const Color(0xFF323232)), + )))), + SizedBox( + width: 10.r, + ), + Expanded( + flex: 1, + child: Center( + child: Text( + widget.className == '' ? '全部' : widget.className, + style: TextStyle(fontSize: 12.sp, color: Color(0xFF323232)), + ))), + SizedBox( + width: 10.r, + ), + Expanded( + flex: 2, + child: Center( + child: Text( + '${item.okRate!.toStringAsFixed(0)}%', + style: TextStyle(fontSize: 12.sp, color: Color(0xFF323232)), + ))), + SizedBox( + width: 10.r, + ), + Expanded( + flex: 3, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 2.r, horizontal: 5.r), + child: SingleChildScrollView( + child: Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + spacing: 5, + runSpacing: 3, + children: List.generate(item.queDtls!.length, (index) { + Dtls kgInfo = item.queDtls![index]; + return Container( + width: 20.r, + height: 20.r, + decoration: BoxDecoration( + color: kgInfo.state == 0 + ? const Color(0xFFD3D3D3) + : kgInfo.state == 1 + ? Colors.white + : kgInfo.state == 2 + ? const Color(0xFFFF7474) + : Theme.of(context).primaryColor, + borderRadius: BorderRadius.all(Radius.circular(10.r))), + child: Center( + child: Text( + kgInfo.questionNo.toString(), + style: TextStyle(fontSize: 8.sp, color: kgInfo.state == 1 ? Color(0xFF525252) : Colors.white), + )), + ); + })), + ), + ), + ), + ], + ), + ); + }, + itemCount: arr.length, + ), + ) + : const MyEmptyWidget() + ], + ), + ), + ); + }); + } + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.only(top: 10.h), + padding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 12.w), + constraints: BoxConstraints(maxHeight: 320.h), + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(10.r)), + child: Column( + children: [ + Container( + margin: EdgeInsets.only(bottom: 24.h), + child: quickText('知识点掌握情况', color: const Color.fromRGBO(92, 92, 92, 1), size: 14.sp, fontWeight: FontWeight.bold), + ), + Expanded( + child: widget.knowsList.isNotEmpty + ? ListView( + children: widget.knowsList.value.map((item) { + return Container( + margin: EdgeInsets.only(bottom: 15.h, left: 15.r, right: 15.r), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Expanded( + flex: 10, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + quickText(item.knowledgeName, size: 12.sp, color: const Color.fromRGBO(152, 152, 152, 1)), + quickText('${item.okRate!.toStringAsFixed(0)}%', size: 12.sp, color: const Color.fromRGBO(64, 64, 64, 1)), + ], + ), + ), + SizedBox(width: 10.w), + const Expanded(flex: 1, child: SizedBox()), + ], + ), + SizedBox(height: 3.h), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + flex: 10, + child: LinearPercentIndicator( + padding: EdgeInsets.zero, + animation: true, + lineHeight: 10.h, + animationDuration: 2500, + percent: item.okRate! / 100, + progressColor: Theme.of(context).primaryColor, + backgroundColor: const Color.fromRGBO(219, 224, 243, 1), + barRadius: Radius.circular(10.r), + )), + SizedBox(width: 10.w), + InkWell( + onTap: () { + List ques = widget.data.questions + .where((w) => w.knows.indexWhere((k) => k.knowledgeId == item.knowledgeId) > -1) + .toList(); + List array2 = [...widget.data.students]; + for (var stu in array2) { + stu.queDtls = widget.data.dtls + .where((w) => + w.studentId == stu.studentId && + ques.indexWhere((q) => w.templateId == q.templateId && w.questionNo == q.questionNo) > -1) + .toList(); + int okCount = stu.queDtls!.where((w) => w.state == 3).length; + int ttlCount = stu.queDtls!.length; + stu.okRate = Utils.calcRate(okCount, ttlCount); + stu.queDtls!.sort((a, b) { + try { + if (RegExp(r'^\d*\.?\d+$').hasMatch(a.questionNo) && RegExp(r'^\d*\.?\d+$').hasMatch(b.questionNo)) { + return num.parse(a.questionNo).compareTo(num.parse(b.questionNo)); + } else { + throw Exception(); + } + } catch (e) { + return a.questionNo.toLowerCase().compareTo(b.questionNo.toLowerCase()); + } + }); + } + + showPeopleListDialog( + context: context, + title: item.knowledgeName, + arr: array2, + ); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + quickText('查看', size: 12.sp, color: const Color.fromRGBO(239, 135, 20, 1)), + Icon(Icons.arrow_forward_ios, size: 11.sp, color: const Color.fromRGBO(239, 135, 20, 1)), + ], + ), + ), + ], + ) + ], + ), + ); + }).toList()) + : MyEmptyWidget(imgWidth: 100.r, imgHeight: 100.r, font: 8.sp), + ), + ], + )); + } +} diff --git a/lib/page/home_page/children/job_report/widget/personnel_data_overview.dart b/making_school_asignment_app/lib/page/home_page/children/job_report/widget/personnel_data_overview.dart similarity index 58% rename from lib/page/home_page/children/job_report/widget/personnel_data_overview.dart rename to making_school_asignment_app/lib/page/home_page/children/job_report/widget/personnel_data_overview.dart index b3f6577..46c61a2 100644 --- a/lib/page/home_page/children/job_report/widget/personnel_data_overview.dart +++ b/making_school_asignment_app/lib/page/home_page/children/job_report/widget/personnel_data_overview.dart @@ -1,52 +1,54 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; class PersonnelDataOverview extends StatefulWidget { final List studentList; - const PersonnelDataOverview({Key? key,required this.studentList}) : super(key: key); + const PersonnelDataOverview({super.key, required this.studentList}); @override State createState() => _PersonnelDataOverviewState(); } class _PersonnelDataOverviewState extends State { - List names = []; List useTimes = []; List correctRates = []; List noAnswerCounts = []; List rankings = []; Map> mapData = {}; + final scrollController = ScrollController(); @override - void initState(){ + void initState() { super.initState(); - - for (var i = 0;i 0) timeerStr = timeUnits.hours.toString() + ':'; - if (timeUnits.minutes > 0) timeerStr += timeUnits.minutes.toString() + ':'; - timeerStr += timeUnits.seconds.toString(); + if (timeUnits.hours > 0) timeerStr = '${timeUnits.hours}:'; + if (timeUnits.minutes > 0) timeerStr += '${timeUnits.minutes}:'; + timeerStr += timeUnits.seconds.toString();*/ names.add(student.studentName); - useTimes.add(timeerStr); - correctRates.add(student.okRate!.toStringAsFixed(0) + '%'); + // useTimes.add(timeerStr); + useTimes.add(student.ttlSec!); + + correctRates.add('${student.okRate!.toStringAsFixed(0)}%'); noAnswerCounts.add(student.noAnswerCount.toString()); rankings.add('${i + 1}名'); - } - mapData = { - '姓名': names, - '答题时长': useTimes, - '正确率': correctRates, - '未答题数': noAnswerCounts, - '班级排名': rankings, - }; + + } + mapData = { + '姓名': names, + '答题时长': useTimes, + '正确率': correctRates, + '未答题数': noAnswerCounts, + '班级排名': rankings, + }; } @override @@ -62,17 +64,19 @@ class _PersonnelDataOverviewState extends State { children: [ Container( margin: EdgeInsets.only(bottom: 20.h), - child: quickText('人员数据概况', color: Color.fromRGBO(92, 92, 92, 1), size: 14.sp, fontWeight: FontWeight.bold), + child: quickText('人员数据概况', color: const Color.fromRGBO(92, 92, 92, 1), size: 14.sp, fontWeight: FontWeight.bold), ), Scrollbar( thickness: 8.w, thumbVisibility: true, - trackVisibility: true, + // trackVisibility: true, radius: Radius.circular(10.r), - controller: ScrollController(),//滑动条使用的控制器 + controller: scrollController, //滑动条使用的控制器 child: SingleChildScrollView( + controller: scrollController, scrollDirection: Axis.horizontal, - primary: true, + // primary: true, + // physics: const BouncingScrollPhysics(), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -83,37 +87,39 @@ class _PersonnelDataOverviewState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - width: 94.r, + width: 100.r, + height: 40.h, alignment: Alignment.center, color: const Color.fromRGBO(230, 230, 230, 1), margin: EdgeInsets.only(bottom: 1.h, right: 1.w), - padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 8.w), - child: quickText(entrie.key, color: Color.fromRGBO(24, 35, 77, 1), size: 12.sp, maxLines: 2), + // padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 8.w), + child: quickText(entrie.key, color: const Color.fromRGBO(24, 35, 77, 1), size: 12.sp, maxLines: 2), ), ...entrie.value.map((e) { bool isTransparentChineseNew = isTransparentChinese && (e?.length ?? 0) == 0; return Container( width: 100.r, + height: 40.h, alignment: Alignment.center, margin: EdgeInsets.only(bottom: 1.h, right: 1.w), - padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 8.w), - color: Color.fromRGBO(245, 245, 245, 1), + // padding: EdgeInsets.symmetric(vertical: 10.h, horizontal: 8.w), + color: const Color.fromRGBO(245, 245, 245, 1), child: isTransparentChineseNew ? quickText('透明', color: Colors.transparent, size: 12.sp) - :RegExp(r'^\d+$').hasMatch(e) || e.contains('%') - ? Row( - mainAxisSize: MainAxisSize.min, - children: [ - quickText(e, color: Color.fromRGBO(82, 82, 82, 1), size: 12.sp, maxLines: 2), - quickText('透', color: Colors.transparent, size: 12.sp), - ], - ) - : quickText(e, color: Color.fromRGBO(82, 82, 82, 1), size: 12.sp, maxLines: 2), + : RegExp(r'^\d+$').hasMatch(e) || e.contains(' %') + ? Row( + mainAxisSize: MainAxisSize.min, + children: [ + quickText(e, color: const Color.fromRGBO(82, 82, 82, 1), size: 12.sp, maxLines: 2), + quickText('透', color: Colors.transparent, size: 12.sp), + ], + ) + : quickText(e, color: const Color.fromRGBO(82, 82, 82, 1), size: 12.sp, maxLines: 2), ); - }).toList(), + }), ], ); - }).toList(), + }), ], ), ), @@ -123,6 +129,7 @@ class _PersonnelDataOverviewState extends State { ); } } + // 定义一个类来保存转换后的时间单位 class TimeUnits { int hours; @@ -131,6 +138,7 @@ class TimeUnits { TimeUnits(this.hours, this.minutes, this.seconds); } + // 毫秒转小时、分钟、秒的函数 TimeUnits convertMilliseconds(int totalSeconds) { int hours = totalSeconds ~/ 3600; // 整除得到小时数 @@ -139,5 +147,4 @@ TimeUnits convertMilliseconds(int totalSeconds) { int seconds = remainingSeconds % 60; // 求余得到秒数 return TimeUnits(hours, minutes, seconds); - -} \ No newline at end of file +} diff --git a/making_school_asignment_app/lib/page/home_page/children/job_report/widget/top_count.dart b/making_school_asignment_app/lib/page/home_page/children/job_report/widget/top_count.dart new file mode 100644 index 0000000..43b7ec2 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/job_report/widget/top_count.dart @@ -0,0 +1,311 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/show_student_list.dart'; +import 'package:making_school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_state.dart'; + +part 'top_count.g.dart'; + +class TopCount extends StatelessWidget { + final CountData data; + final String className; + final String jobId; + final int subject; + + const TopCount(this.data, this.className, this.jobId, this.subject,{Key? key}) : super(key: key); + + void showStudentListDialog({required BuildContext context, required String title, required List students}) { + showDialog( + context: context, + builder: (BuildContext context) { + return ShowStudentList( + title: title, + studentList: students, + homeworkId: jobId, + subject: subject, + ); + }, + ); + /*showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + // insetPadding: EdgeInsets.symmetric(vertical: 20.r,horizontal: 20.r), + contentPadding: EdgeInsets.all(20.r), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15.r))), + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.7, + height: MediaQuery.of(context).size.height * 0.7, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Text( + className + title, + style: TextStyle(fontSize: 15.sp, color: Color(0xFF3C3C3C), fontWeight: FontWeight.w500), + ), + ), + SizedBox( + height: 5.r, + ), + SizedBox( + height: 15.r, + ), + arr.length > 0 + ? Expanded( + child: ListView.builder( + shrinkWrap: true, + itemBuilder: (context, index) { + AnswerOkStudents item = arr[index]; + return InkWell( + onTap: () { + */ /*RouterManager.router.navigateTo( + context, + RouterManager.quickCheckPersonalPath + '?jobId=$jobId&studentId=${item.id}', + transition: getTransition(), + );*/ /* + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 5.r, horizontal: 15.r), + color: index.isOdd ? Colors.white : Color(0xFFF0F0F0), + child: Text( + item.name, + style: TextStyle(fontSize: 12.sp, color: Color(0xFF323232)), + ), + ), + ); + }, + itemCount: arr.length, + ), + ) + : const MyEmptyWidget() + ], + ), + ), + ); + });*/ + } + + @override + Widget build(BuildContext context) { + double leftWidth = (MediaQuery.of(context).size.width - 40.r) * 0.7 / 3; + double rightWidth = (MediaQuery.of(context).size.width - 40.r) * 0.3 / 2; + return Container( + padding: EdgeInsets.symmetric(vertical: 20.r, horizontal: 20.r), + margin: EdgeInsets.symmetric(vertical: 10.r, horizontal: 10.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(6.r)), + ), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () { + showStudentListDialog(context: context, title: '未提交作业学生', students: data.noAnswerStudents!); + }, + child: leftContainer(context, count: data.noAnswerCount!, name: '未提交', nameColor: Color(0xFF10978E), bgColor: Color(0xFFE8F8F7)), + ), + InkWell( + onTap: () { + showStudentListDialog(context: context, title: '已提交作业学生', students: data.studentSubmitStudents!); + }, + child: leftContainer(context, count: data.studentSubmitCount!, name: '已提交', nameColor: Color(0xFFEF5614), bgColor: Color(0xFFFCEFEA)), + ), + InkWell( + onTap: () { + showStudentListDialog(context: context, title: '全对作业学生', students: data.allCorrectStudents!); + }, + child: leftContainer(context, count: data.allCorrect!, name: '全对', nameColor: Color(0xFF8C68FF), bgColor: Color(0xFFE9EBFD)), + ), + + ], + ), + SizedBox(height: 15.r,), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () { + showStudentListDialog(context: context, title: '优等作业学生', students: data.levelOneStudents!); + }, + child: rightContainer( + context, + count: data.levelOneCount!, + bgColor: const Color(0xFFE8F8F7), + nameColor: const Color(0xFF009254), + borderColor: const Color(0xFF4CC793), + name: '优', + ), + ), + InkWell( + onTap: () { + showStudentListDialog(context: context, title: '良等作业学生', students: data.levelTwoStudents!); + }, + child: rightContainer(context,count: data.levelTwoCount!, bgColor: Color(0xFFFEF9F6), nameColor: Color(0xFFE87F0B), borderColor: const Color(0xFFFF9F46), name: '良'), + ) + ], + ), + SizedBox(height: 10.r,), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () { + showStudentListDialog(context: context, title: '中等作业学生', students: data.levelThreeStudents!); + }, + child: rightContainer(context,count: data.levelThreeCount!, bgColor: Color(0xFFFFF6F6), nameColor: Color(0xFFFF7474), borderColor: const Color(0xFFFFCACA),name: '中'), + ), + InkWell( + onTap: () { + showStudentListDialog(context: context, title: '差等作业学生', students: data.levelFourStudents!); + }, + child: rightContainer(context,count: data.levelFourCount!, bgColor: Color(0xFFECEFEF), nameColor: Color(0xFF5C5B59), borderColor: const Color(0xFFD8D8D8),name: '差'), + ) + ], + ), + /* Container( + height: 92.r, + width: rightWidth, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: InkWell( + onTap: () { + showStudentListDialog(context: context, title: '优等作业学生', students: data.levelOneStudents!); + }, + child: rightContainer( + count: data.levelOneCount!, + bgColor: Color(0xFF56FFB8), + nameColor: Color(0xFF009254), + name: '优', + ), + )), + Expanded( + child: InkWell( + onTap: () { + showStudentListDialog(context: context, title: '中等作业学生', students: data.levelThreeStudents!); + }, + child: rightContainer(count: data.levelThreeCount!, bgColor: Color(0xFFD3FF93), nameColor: Color(0xFF3F6605), name: '中'), + )), + ], + ), + ), + Container( + height: 92.r, + width: rightWidth, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: InkWell( + onTap: () { + showStudentListDialog(context: context, title: '良等作业学生', students: data.levelTwoStudents!); + }, + child: rightContainer(context,count: data.levelTwoCount!, bgColor: Color(0xFFFFC38C), nameColor: Color(0xFFD36500), name: '良'), + )), + Expanded( + child: InkWell( + onTap: () { + showStudentListDialog(context: context, title: '差等作业学生', students: data.levelFourStudents!); + }, + child: rightContainer(context,count: data.levelFourCount!, bgColor: Color(0xFFFF9D94), nameColor: Color(0xFFD12616), name: '差'), + )), + ], + ), + )*/ + ], + ), + ); + } +} + +@swidget +Widget leftContainer(context, {required int count, required String name, required Color nameColor, required Color bgColor}) { + double leftWidth = (MediaQuery.of(context).size.width - 100.r) / 3; + return Container( + width: leftWidth, + height: 108.r, + padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 6.r), + decoration: BoxDecoration( + color: bgColor, + borderRadius: BorderRadius.all(Radius.circular(10.r)), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + height: 5.r, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + count.toString(), + style: TextStyle(fontSize: 18.sp, color: Color(0xFF595959), fontWeight: FontWeight.w600), + ), + Text( + '人', + style: TextStyle(fontSize: 10.sp, color: Color(0xFF595959), fontWeight: FontWeight.w600), + ), + ], + ), + SizedBox( + height: 30.r, + ), + Text( + name, + style: TextStyle(fontSize: 12.sp, color: nameColor, fontWeight: FontWeight.w500), + ) + ], + ), + ); +} + +@swidget +Widget rightContainer(context,{required int count, required Color bgColor, required Color nameColor, required Color borderColor,required String name}) { + return Container( + width: (MediaQuery.of(context).size.width - 80.r) / 2, + height: 48.r, + decoration: BoxDecoration( + color: bgColor, + borderRadius: BorderRadius.all(Radius.circular(10.r)), + border: Border.all(color: borderColor,width: 1.r), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(width: 20.r,), +Expanded(child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + count.toString(), + style: TextStyle(fontSize: 24.sp, color: const Color(0xFF505251), fontWeight: FontWeight.w300), + ), + Padding( + padding: EdgeInsets.only(top: 3.r), + child: Text( + '人', + style: TextStyle(fontSize: 10.sp, color: const Color(0xFF505251), fontWeight: FontWeight.w300), + ), + ), + ], +)), + + + Text( + name, + style: TextStyle(fontSize: 12.sp, color: nameColor, fontWeight: FontWeight.w600), + ), + SizedBox(width: 20.r,), + ], + ), + ); +} diff --git a/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_binding.dart b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_binding.dart similarity index 100% rename from lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_binding.dart rename to making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_binding.dart diff --git a/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_logic.dart b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_logic.dart similarity index 52% rename from lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_logic.dart rename to making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_logic.dart index a7e810c..8bf9dea 100644 --- a/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_logic.dart +++ b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_logic.dart @@ -2,12 +2,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/knowledge_points_grasp.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/job/knowledge_points_grasp.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; import 'knowledge_points_grasp_state.dart'; -class KnowledgePointsGraspLogic extends GetxController with RequestToolMixin,GetSingleTickerProviderStateMixin { +class KnowledgePointsGraspLogic extends GetxController with RequestToolMixin, GetSingleTickerProviderStateMixin { final KnowledgePointsGraspState state = KnowledgePointsGraspState(); //文本输入框控制器 late final TextEditingController textController; @@ -15,8 +17,10 @@ class KnowledgePointsGraspLogic extends GetxController with RequestToolMixin,Get late TabController tabController; @override - void onInit(){ + void onInit() { super.onInit(); + state.subject = Get.arguments['subject'] ?? -1; + state.classId = Get.arguments['classId'] ?? ''; textController = TextEditingController(); refreshController = EasyRefreshController(); tabController = TabController(length: 3, vsync: this); @@ -24,14 +28,20 @@ class KnowledgePointsGraspLogic extends GetxController with RequestToolMixin,Get getList(); } - void getList() async{ - List data = await getClient().getKnowledgeReport(state.dateStart,state.dateEnd,textController.text); - state.dataList.value = data; - EasyLoading.dismiss(); + void getList() async { + try { + ToastUtils.showLoading(); + List data = + await getClient().getKnowledgeReport(state.dateStart, state.dateEnd, textController.text, state.classId, state.subject); + state.dataList.value = data; + } catch (_) { + } finally { + ToastUtils.dismiss(); + } } @override - void dispose(){ + void dispose() { super.dispose(); textController.dispose(); refreshController.dispose(); diff --git a/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_state.dart b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_state.dart new file mode 100644 index 0000000..65404c0 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_state.dart @@ -0,0 +1,19 @@ +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/knowledge_points_grasp.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; + +class KnowledgePointsGraspState { + KnowledgePointsGraspState() { + ///Initialize variables + } + + late int page = 1; + late int totalPages = 0; + late RxList dataList = RxList(); + late String dateStart = Utils.getWeekStartDate().toString().substring(0, 10); + late String dateEnd = Utils.getWeekEndDate().toString().substring(0, 10); + late RxString customTimeStr = '自定义'.obs; + late final int subject; + late final String classId; + +} diff --git a/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_view.dart b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_view.dart new file mode 100644 index 0000000..766bce8 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_view.dart @@ -0,0 +1,257 @@ +import 'package:easy_debounce/easy_throttle.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/knowledge_points_grasp.dart'; +import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.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/page/home_page/widget/progress_bar.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:syncfusion_flutter_datepicker/datepicker.dart'; + +import 'knowledge_points_grasp_logic.dart'; + +class KnowledgePointsGraspPage extends StatefulWidget { + const KnowledgePointsGraspPage({super.key}); + + @override + State createState() => _KnowledgePointsGraspPageState(); +} + +class _KnowledgePointsGraspPageState extends State { + final logic = Get.find(); + final state = Get.find().state; + + @override + Widget build(BuildContext context) { + return OrientationBuilder(builder: (BuildContext context, Orientation orientation) { + return Scaffold( + backgroundColor: const Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + backgroundColor: Colors.white, + title: Text('知识点掌握', style: TextStyle(fontSize: 14.sp, color: const Color(0xFF333333))), + centerTitle: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Get.back(), + ), + actions: const [ + ReturnToHomepage(), + ], + elevation: 0, + ), + body: Column( + children: [ + Container( + margin: EdgeInsets.all(15.r), + // height: 30.r, + child: Row( + children: [ + Expanded( + child: Container( + padding: EdgeInsets.only(left: 10.r, right: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.r), + border: Border.all(width: 1.r, color: const Color(0xFFDDDDDD)), + color: Colors.white, + ), + child: TextField( + controller: logic.textController, + textInputAction: TextInputAction.next, + style: TextStyle( + color: const Color.fromRGBO(80, 87, 103, 1), + fontSize: 10.sp, + ), + decoration: InputDecoration( + hintText: "请输入知识点名称", + hintStyle: TextStyle(fontSize: 10.sp, color: const Color.fromRGBO(153, 153, 153, 1)), + labelStyle: TextStyle(fontSize: 10.sp, color: const Color.fromRGBO(148, 163, 182, 1)), + border: InputBorder.none, + ), + ), + ), + ), + SizedBox( + width: 10.r, + ), + InkWell( + onTap: () => easyThrottle('zshi_shi_dian_cx', () { + Utils.hideKeyboard(); + logic.refreshController.callRefresh(); + }), + child: Container( + width: 50.r, + height: 30.r, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(4.r), color: Theme.of(context).primaryColor), + child: Center( + child: Text( + '查询', + style: TextStyle(fontSize: 12.sp, color: Colors.white), + ), + ), + ), + ) + ], + ), + ), + Obx(() { + return JobConditionFilter( + jobType: 1, + controller: logic.tabController, + customTimeStr: state.customTimeStr.value, + customTime: logic.tabController.index != 2 || + ((state.dateEnd == null || state.dateEnd == '') && (state.dateStart == null || state.dateStart == '')) + ? null + : PickerDateRange( + state.dateStart == null || state.dateStart == '' ? null : DateTime.parse(state.dateStart!), + state.dateEnd == null || state.dateEnd == '' ? null : DateTime.parse(state.dateEnd!), + ), + onTimeFilter: (String? startTime, String? endTime) { + EasyLoading.show(status: 'loading...'); + if (startTime == null && endTime == null) { + if (logic.tabController.index == 2) { + logic.tabController.animateTo(0); + } + state.dateStart = Utils.getWeekStartDate().toString().substring(0, 10); + state.dateEnd = Utils.getWeekEndDate().toString().substring(0, 10); + state.customTimeStr.value = '自定义'; + } else { + state.dateStart = startTime ?? ''; + state.dateEnd = endTime ?? ''; + } + state.page = 1; + logic.getList(); + // _refreshController2.callRefresh(); + }, + refreshTime: (value) { + if (value != null && value.startDate != null) { + state.customTimeStr.value = value.startDate?.toString().substring(0, 10) ?? ''; + if (value.endDate != null) { + if (!Utils.isPad() && value.startDate!.year == value.endDate!.year) { + state.customTimeStr.value = '${value.startDate.toString().substring(5, 10)}~${value.endDate.toString().substring(5, 10)}'; + } else { + state.customTimeStr.value = '${state.customTimeStr.value}~${value.endDate?.toString().substring(0, 10)}'; + } + } + } + }, + ); + }), + Expanded( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 10.r), + child: Obx(() { + return EasyRefresh( + firstRefresh: false, + taskIndependence: true, + controller: logic.refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + state.page = 1; + logic.getList(); + }, + onLoad: () async { + if (state.page < state.totalPages) { + state.page += 1; + logic.getList(); + } + }, + child: state.dataList.isNotEmpty + ? ListView.builder( + itemCount: state.dataList.value.length, + itemBuilder: (context, index) { + KnowledgePointsGrasp item = state.dataList[index]; + return InkWell( + onTap: () { + Get.toNamed(Routes.knowledgePointsGraspDetailPage, arguments: { + 'dateStart': state.dateStart, + 'dateEnd': state.dateEnd, + 'knowledgeId': item.knowledgeId, + 'knowledgeName': item.knowledgeName, + 'subject': state.subject + }); + }, + child: Container( + margin: EdgeInsets.symmetric(vertical: 5.r, horizontal: 14.r), + padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 10.r), + decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(10.r)), color: Colors.white), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: Text( + item.knowledgeName, + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF505050)), + )), + Container( + width: 49.r, + height: 22.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.r)), + border: Border.all(width: 1.r, color: Theme.of(context).primaryColor), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + '${item.count}次', + style: TextStyle(fontSize: 10.sp, color: Theme.of(context).primaryColor), + ), + SizedBox(width: 1.w), + Padding( + padding: EdgeInsets.only(top: 2.h), + child: Icon(Icons.chevron_right, size: 12.r, color: Theme.of(context).primaryColor), + ), + // Image.asset( + // 'assets/images/job_data_right_icon.png', + // width: 10.r, + // height: 10.r, + // ), + ], + ), + ), + ], + ), + SizedBox( + height: 10.r, + ), + ProgressBar( + title: '正确率:', + color: const Color(0xFFB2DA93), + percent: item.correctRate / 100, + padingEdg: EdgeInsets.zero, + marginEdg: EdgeInsets.only(top: 8.h)), + ], + ), + ), + ); + }) + : const MyEmptyWidget(), + ); + }), + ), + ), + ], + ), + ); + }); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} diff --git a/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_binding.dart b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_binding.dart similarity index 100% rename from lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_binding.dart rename to making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_binding.dart diff --git a/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_logic.dart b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_logic.dart similarity index 59% rename from lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_logic.dart rename to making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_logic.dart index 4e116e1..e637b4a 100644 --- a/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_logic.dart +++ b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_logic.dart @@ -1,41 +1,42 @@ import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/common/job/knowledge_report_detail.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/common/job/knowledge_report_detail.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; import 'knowledge_points_grasp_detail_state.dart'; -class KnowledgePointsGraspDetailLogic extends GetxController with RequestToolMixin{ +class KnowledgePointsGraspDetailLogic extends GetxController with RequestToolMixin { final KnowledgePointsGraspDetailState state = KnowledgePointsGraspDetailState(); late final EasyRefreshController refreshController; - @override - void onInit(){ + void onInit() { super.onInit(); state.dateStart = Get.arguments['dateStart']; state.dateEnd = Get.arguments['dateEnd']; state.knowledgeId = Get.arguments['knowledgeId']; state.knowledgeName.value = Get.arguments['knowledgeName']; + state.subject = Get.arguments['subject'] ?? -1; refreshController = EasyRefreshController(); EasyLoading.show(status: 'loading...'); getList(); } - void getList() async{ - List data = await getClient().getKnowledgeReportDetail(state.dateStart,state.dateEnd,state.knowledgeId); + void getList() async { + List data = await getClient().getKnowledgeReportDetail(state.dateStart, state.dateEnd, state.knowledgeId); state.dataList.value = data; EasyLoading.dismiss(); } - getStudents(homeworkId,templateId,questionNo) async{ - List data = await getClient().getQuestionStudentState(homeworkId,templateId,questionNo); - state.studentList.value = data; + getStudents(homeworkId, templateId, questionNo) async { + List data = await getClient().getQuestionStudentState(homeworkId, templateId, questionNo); + state.studentList.value = data; } + @override - void dispose(){ + void dispose() { super.dispose(); refreshController.dispose(); } diff --git a/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_state.dart b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_state.dart new file mode 100644 index 0000000..ad20dc6 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_state.dart @@ -0,0 +1,17 @@ +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/common/job/knowledge_report_detail.dart'; + +class KnowledgePointsGraspDetailState { + KnowledgePointsGraspDetailState() { + ///Initialize variables + } + + late String dateStart = ''; + late String dateEnd = ''; + late int knowledgeId = 0; + late int subject = -1; + late RxList dataList = RxList(); + late RxList studentList = RxList(); + late RxString knowledgeName = ''.obs; +} diff --git a/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_view.dart b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_view.dart new file mode 100644 index 0000000..e5c2de0 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_view.dart @@ -0,0 +1,258 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/config/request_config.dart'; +import 'package:percent_indicator/percent_indicator.dart'; +import 'package:making_school_asignment_app/common/job/knowledge_report_detail.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/global_widget/show_student_list.dart'; + +import 'knowledge_points_grasp_detail_logic.dart'; + +class KnowledgePointsGraspDetailPage extends StatefulWidget { + const KnowledgePointsGraspDetailPage({super.key}); + + @override + State createState() => _KnowledgePointsGraspDetailPageState(); +} + +class _KnowledgePointsGraspDetailPageState extends State { + final logic = Get.find(); + final state = Get.find().state; + + @override + Widget build(BuildContext context) { + void showImg(imgUrl, context) { + if (imgUrl != null && imgUrl != '') { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + insetPadding: EdgeInsets.symmetric(vertical: 55.r, horizontal: 45.r), + contentPadding: EdgeInsets.all(0), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15.r))), + content: Container( + width: MediaQuery.of(context).size.width, + // height: MediaQuery.of(context).size.height, + child: Image.network(RequestConfig.imgUrl + imgUrl), + ), + ); + }, + ); + } else { + ToastUtils.showError('暂无图片'); + } + + EasyLoading.dismiss(); + } + + void showStudent(homeworkId, templateId, questionNo, title) async { + logic.getStudents(homeworkId, templateId, questionNo); + + showDialog( + context: context, + builder: (BuildContext context) { + return Obx(() { + return ShowStudentList( + title: title, + studentList: state.studentList.value, + homeworkId: homeworkId, + subject: state.subject, + ); + }); + }, + ); + EasyLoading.dismiss(); + } + + return OrientationBuilder(builder: (BuildContext context, Orientation orientation) { + return Scaffold( + backgroundColor: const Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + backgroundColor: Colors.white, + title: Obx(() { + return Text(state.knowledgeName.value, style: TextStyle(fontSize: 14.sp, color: const Color(0xFF333333))); + }), + centerTitle: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Get.back(), + ), + actions: const [ + ReturnToHomepage(), + ], + elevation: 0, + ), + body: Padding( + padding: EdgeInsets.symmetric(vertical: 10.r), + child: Obx(() { + return EasyRefresh( + firstRefresh: false, + taskIndependence: true, + controller: logic.refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + logic.getList(); + }, + onLoad: () async { + // getList(); + }, + child: state.dataList.isNotEmpty + ? ListView.builder( + itemCount: state.dataList.length, + itemBuilder: (context, index) { + KnowledgeReportDetail item = state.dataList[index]; + return InkWell( + onTap: () { + /* RouterManager.router.navigateTo( + context, + RouterManager.quickCheckPersonalPath + + '?jobId=${item.jobName}&studentId=$studentId', + transition: getTransition(), + );*/ + }, + child: Container( + margin: EdgeInsets.symmetric(vertical: 5.r, horizontal: 14.r), + padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 10.r), + decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(10.r)), color: Colors.white), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + item.publishTime.substring(0, 10), + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF505050)), + ), + SizedBox( + width: 10.r, + ), + Expanded( + child: Text( + item.homeworkName, + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF505050)), + )), + InkWell( + onTap: () { + EasyLoading.show(status: 'loading...'); + showImg(item.questionPicture, context); + }, + child: Container( + height: 22.r, + padding: EdgeInsets.symmetric(horizontal: 4.w), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.r)), + border: Border.all(width: 1.r, color: const Color(0xFF8B8B8B)), + ), + child: Center( + child: Text( + '第${item.questionNo}题', + style: TextStyle(fontSize: 10.sp, color: const Color(0xFF8B8B8B)), + ), + ), + ), + ), + ], + ), + SizedBox( + height: 10.r, + ), + Container( + margin: EdgeInsets.only(top: 8.h), + padding: EdgeInsets.zero, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell( + onTap: () { + EasyLoading.show(status: 'loading...'); + showStudent(item.homeworkId, item.templateId, item.questionNo, item.homeworkName); + }, + child: Container( + margin: EdgeInsets.only(right: 6.r), + width: 56.r, + height: 20.r, + decoration: BoxDecoration( + color: const Color(0xFFE9FFD9), + borderRadius: BorderRadius.circular(20.r), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + quickText('正确率', color: const Color(0xFF313131), size: 10.sp), + Image.asset( + 'assets/images/job_data_right_icon.png', + width: 8.r, + height: 8.r, + ) + ], + )), + ), + Expanded( + flex: 1, + child: Container( + child: Row( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.r), + ), + child: LinearPercentIndicator( + padding: EdgeInsets.zero, + animation: true, + lineHeight: 8.h, + animationDuration: 2500, + percent: item.correctRate / 100, + progressColor: Color(0xFFB2DA93), + backgroundColor: Color(0xFFE8E8E8), + barRadius: Radius.circular(10.r), + ), + ), + ), + SizedBox(width: 4.w), + quickText('${item.correctRate.toStringAsFixed(0)}%', size: 10.sp, color: Color(0xFF606060)) + ], + ), + ), + ), + ], + ), + ), + /* progressBar(context, + title: '正确率 >', + color: Color(0xFF90E0BE), + percent: item.correctRate / 100, + padingEdg: EdgeInsets.zero, + marginEdg: EdgeInsets.only(top: 8.h), + studentCall:showStudent(item.questionId,item.jobName), + ),*/ + ], + ), + ), + ); + }) + : const MyEmptyWidget(), + ); + }), + ), + ); + }); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/my_info.dart b/making_school_asignment_app/lib/page/home_page/children/my_info.dart new file mode 100644 index 0000000..8d67c66 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/my_info.dart @@ -0,0 +1,242 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/user_info_detail.dart'; +import 'package:making_school_asignment_app/common/store/app_storage_key.dart'; +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/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +class MyInfo extends StatefulWidget { + const MyInfo({super.key}); + + @override + State createState() => _MyInfoState(); +} + +class _MyInfoState extends State with AutomaticKeepAliveClientMixin { + late Rx userInfo = UserStore.to.userDetailInfo; + + @override + void initState() { + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarIconBrightness: Brightness.light, + statusBarColor: Colors.transparent, //状态栏背景颜色 + // systemStatusBarContrastEnforced: false, + )); + super.initState(); + } + + // 确认对话框 + _showAlertDialog(context1) async { + await showDialog( + // 表示点击灰色背景的时候是否消失弹出框 + barrierDismissible: false, + context: context1, + builder: (context) { + return AlertDialog(title: quickText("提示信息"), content: quickText("您确定要退出登录吗?"), actions: [ + TextButton( + child: quickText("取消"), + onPressed: () { + Navigator.pop(context, 'Cancle'); + }, + ), + TextButton( + child: quickText("确定"), + onPressed: () async { + try { + var pwd = StorageService.to.read(AppStorageKey.pwd.value); + var account = StorageService.to.read(AppStorageKey.account.value); + + UserStore.to.erase(); + await StorageService.to.erase(); + StorageService.to.write(AppStorageKey.privacyAgreement.value, true); + StorageService.to.write(AppStorageKey.account.value, account); + StorageService.to.write(AppStorageKey.pwd.value, pwd); + Navigator.pop(context, "Ok"); + Get.offAllNamed(Routes.login); + } catch (e) { + print(e); + } + }) + ]); + }); + } + + @override + bool get wantKeepAlive => true; + + @override + Widget build(BuildContext context) { + super.build(context); + + final personalInfoTitleStly = TextStyle( + color: const Color.fromRGBO(80, 87, 103, 1), + fontSize: 13.sp, + ); + final personalInfoValStly = TextStyle( + color: const Color.fromRGBO(148, 163, 182, 1), + fontSize: 13.sp, + ); + + return OrientationBuilder(builder: (BuildContext context, Orientation orientation) { + return Stack( + children: [ + SizedBox( + height: double.infinity, + child: Column( + children: [ + Container( + height: 220.h, + width: double.infinity, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/personal_bg.png'), + fit: BoxFit.cover, + ), + ), + ), + Expanded( + child: Container( + color: const Color.fromRGBO(248, 248, 248, 1), + )) + ], + ), + ), + SafeArea( + child: Scaffold( + backgroundColor: Colors.transparent, + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + height: 150.h, + padding: EdgeInsets.only(left: 20.r, right: 20.r), + // alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Image.asset( + 'assets/images/default_user_dead.png', + ), + SizedBox( + width: 5.w, + ), + InkWell( + onTap: () { + /*if (tokenState == '' || userState.id == '') { + toLoginPage(context); + }*/ + }, + child: Container( + margin: EdgeInsets.only(top: 0.h), + child: Text( + userInfo.value?.name ?? '请前往登录', + style: TextStyle(fontSize: 16.sp, color: const Color(0xFF332A2A), fontWeight: FontWeight.w500), + ), + ), + ), + const Spacer(), + InkWell( + onTap: () { + _showAlertDialog(context); + }, + child: Container( + padding: EdgeInsets.all(2.r), + decoration: BoxDecoration( + color: const Color.fromRGBO(255, 255, 255, 1), + borderRadius: BorderRadius.circular(50.r), + ), + child: Image.asset('assets/images/out_icon.png',fit: BoxFit.cover), + ), + ) + ], + ), + ), + SizedBox(height: 14.h), + Container( + margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w), + padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.w)), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(46, 91, 255, 0.1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 20, //阴影模糊程度 + spreadRadius: 10, //阴影扩散程度 + ) + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [Text('账号', style: personalInfoTitleStly), Text(userInfo.value?.name ?? '请前往登录', style: personalInfoValStly)], + ), + ), + Container( + margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w), + padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.w)), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(46, 91, 255, 0.1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 20, //阴影模糊程度 + spreadRadius: 10, //阴影扩散程度 + ) + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [Text('所在学校', style: personalInfoTitleStly), Text(userInfo.value?.schoolName ?? '', style: personalInfoValStly)], + ), + ), + Container( + margin: EdgeInsets.symmetric(vertical: 5.h, horizontal: 16.w), + padding: EdgeInsets.symmetric(vertical: 15.h, horizontal: 16.w), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(6.w)), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(46, 91, 255, 0.1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 20, //阴影模糊程度 + spreadRadius: 10, //阴影扩散程度 + ) + ], + ), + child: InkWell( + onTap: () { + Get.toNamed(Routes.otherPage); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('其他', style: personalInfoTitleStly), + Icon( + Icons.arrow_forward_ios, + color: const Color.fromRGBO(80, 87, 103, 1), + size: 13.sp, + ) + ], + ), + ), + ), + ], + ), + ), + ), + ], + ); + }); + } +} diff --git a/lib/page/home_page/children/quick_data_check/quick_data_check_binding.dart b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/quick_data_check_binding.dart similarity index 100% rename from lib/page/home_page/children/quick_data_check/quick_data_check_binding.dart rename to making_school_asignment_app/lib/page/home_page/children/quick_data_check/quick_data_check_binding.dart diff --git a/making_school_asignment_app/lib/page/home_page/children/quick_data_check/quick_data_check_logic.dart b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/quick_data_check_logic.dart new file mode 100644 index 0000000..cd3e029 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/quick_data_check_logic.dart @@ -0,0 +1,35 @@ +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; + +import 'quick_data_check_state.dart'; + +class QuickDataCheckLogic extends GetxController with RequestToolMixin { + final QuickDataCheckState state = QuickDataCheckState(); + + @override + void onInit() { + super.onInit(); + state.homeworkId.value = Get.arguments['homeworkId'] ?? ''; + state.classId.value = Get.arguments['classId'] ?? ''; + state.className.value = Get.arguments['className'] ?? ''; + state.grade = Get.arguments['grade']; + EasyLoading.show(status: 'loading...'); + getWorkData(); + } + + void getWorkData() async { + HomeworkDetails data = await getClient().getHomeworkDetails(state.homeworkId.value, state.classId.value); + EasyLoading.dismiss(); + state.subject = data.subject!; + state.dataCount = Utils.getHomeworkData(data); + state.homeData = data; + state.kgReport.value = data.questions.where((w) => w.questionType == 1).toList(); + state.zgReport.value = data.questions.where((w) => w.questionType == 2).toList(); + state.studentList.value = data.students; + state.hasData.value = true; + + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/quick_data_check/quick_data_check_state.dart b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/quick_data_check_state.dart new file mode 100644 index 0000000..d872390 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/quick_data_check_state.dart @@ -0,0 +1,84 @@ +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; + +class QuickDataCheckState { + QuickDataCheckState() { + ///Initialize variables + } + + late RxString homeworkId = ''.obs; + late RxString classId = ''.obs; + late RxString className = ''.obs; + late int grade; + late CountData dataCount = CountData(); + late RxBool hasData = false.obs; + late RxList kgReport = RxList(); + late RxList zgReport = RxList(); + late RxList studentList = RxList(); + late HomeworkDetails homeData; + late int subject = -1; +} + +class CountData extends Object { + int? kgtOkCount = 0; + int? kgtDtlCount = 0; + double? kgtAnswerRate = 0; + double? kgtOkRate = 0; + double? kgtCorrectRate = 0; + int? kgtAnswerCount = 0; + int? kgtCount = 0; + int? zgtDtlCount = 0; + int? zgtOkCount = 0; + int? zgtAnswerCount = 0; + double? zgtAnswerRate = 0; + double? zgtCorrectRate = 0; + double? zgtOkRate = 0; + int? zgtCount = 0; + int? studentCount = 0; + List? priorityStudents = []; + List? noAnswerStudents = []; + List? studentSubmitStudents = []; + List? allCorrectStudents = []; + List? levelOneStudents = []; + List? levelTwoStudents = []; + List? levelThreeStudents = []; + List? levelFourStudents = []; + int? studentSubmitCount = 0; + int? noAnswerCount = 0; + int? allCorrect = 0; + int? levelOneCount = 0; + int? levelTwoCount = 0; + int? levelThreeCount = 0; + int? levelFourCount = 0; + CountData({ + this.kgtOkCount, + this.kgtDtlCount, + this.kgtAnswerRate, + this.kgtAnswerCount, + this.kgtOkRate, + this.studentCount, + this.kgtCount, + this.zgtAnswerCount, + this.zgtOkCount, + this.zgtDtlCount, + this.zgtAnswerRate, + this.zgtOkRate, + this.zgtCount, + this.priorityStudents, + this.studentSubmitCount, + this.noAnswerCount, + this.allCorrect, + this.noAnswerStudents, + this.studentSubmitStudents, + this.allCorrectStudents, + this.levelOneCount, + this.levelOneStudents, + this.levelTwoCount, + this.levelTwoStudents, + this.levelThreeCount, + this.levelThreeStudents, + this.levelFourCount, + this.levelFourStudents, + + }); +} diff --git a/making_school_asignment_app/lib/page/home_page/children/quick_data_check/quick_data_check_view.dart b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/quick_data_check_view.dart new file mode 100644 index 0000000..5864423 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/quick_data_check_view.dart @@ -0,0 +1,296 @@ +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:get_storage/get_storage.dart'; +import 'package:percent_indicator/percent_indicator.dart'; +import 'package:making_school_asignment_app/common/utils/enum_untils.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; +import 'package:making_school_asignment_app/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart'; +import 'package:making_school_asignment_app/page/home_page/children/quick_data_check/widget/quick_data_check_bottom.dart'; +import 'package:making_school_asignment_app/page/home_page/children/quick_data_check/widget/report_table.dart'; + +import 'quick_data_check_logic.dart'; + +class QuickDataCheckPage extends StatefulWidget { + const QuickDataCheckPage({Key? key}) : super(key: key); + + @override + State createState() => _QuickDataCheckPageState(); +} + +class _QuickDataCheckPageState extends State { + final logic = Get.find(); + final state = Get.find().state; + + @override + Widget build(BuildContext context) { + return AnnotatedRegion( + value: const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarIconBrightness: Brightness.light, + statusBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.dark, + ), + child: Container( + padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top), + height: MediaQuery.of(context).size.height, + decoration: const BoxDecoration( + gradient: LinearGradient(begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ + Color(0xFF8C68FF), + Color(0xFFF5F5F5), + ], stops: [ + 0.09, + 0.3 + ])), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + IconButton( + icon: const Icon(Icons.arrow_back_ios, color: Colors.white), + onPressed: () => Get.back(), + ), + Expanded( + child: Padding( + padding: EdgeInsets.only(right: 8.r), + child: Center( + child: Text( + '数据快查', + style: TextStyle(fontSize: 14.sp, color: Colors.white), + )), + )), + const ReturnToHomepage( + bgColor: Colors.white, + ), + ], + ), + SizedBox(height: 10.r), + Obx(() { + if (state.hasData.value) { + return Expanded( + child: SingleChildScrollView( + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(left: 14.r, top: 2.r), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image.asset( + 'assets/images/job_report_class_icon.png', + width: 22.r, + height: 22.r, + ), + SizedBox( + width: 6.r, + ), + Text( + '${EnumUtils.formatGrade(state.grade)}${state.className.value}', + style: TextStyle(fontSize: 14.r, color: Colors.white), + ), + ], + ), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 15.r, horizontal: 15.r), + margin: EdgeInsets.symmetric(vertical: 10.r, horizontal: 14.r), + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(6.r))), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + + children: [ + + Expanded(child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 12.r, + height: 12.r, + decoration: BoxDecoration(color: const Color(0xFF4CC793), borderRadius: BorderRadius.all(Radius.circular(7.r))), + ), + SizedBox( + width: 6.r, + ), + Text( + '已提交', + style: TextStyle(fontSize: 12.sp, color: Color(0xFF333333)), + ), + SizedBox( + width: 35.r, + ), + Container( + width: 12.r, + height: 12.r, + decoration: BoxDecoration(color: const Color(0xFF6888FD), borderRadius: BorderRadius.all(Radius.circular(7.r))), + ), + SizedBox( + width: 6.r, + ), + Text( + '未提交', + style: TextStyle(fontSize: 12.sp, color: const Color(0xFF333333)), + ) + ], + ), + SizedBox( + height: 2.r, + ), + //环形图 + SizedBox( + height: MediaQuery.of(context).size.width * 0.3, + // width: MediaQuery.of(context).size.width * 0.08, + child: PieChart( + PieChartData( + borderData: FlBorderData(show: false), + sectionsSpace: 0, + centerSpaceRadius: MediaQuery.of(context).size.width * 0.04, + sections: [ + PieChartSectionData( + color: const Color(0xFF4CC793), + value: state.dataCount.studentSubmitCount! / state.dataCount.studentCount! * 100, + radius: MediaQuery.of(context).size.width * 0.06 + 5, + title: '${state.dataCount.studentSubmitCount}人', + titleStyle: TextStyle( + fontSize: 14.sp, + color: Colors.white, + ), + ), + PieChartSectionData( + color: const Color(0xFF6888FD), + value: + (state.dataCount.studentCount! - state.dataCount.studentSubmitCount!) / state.dataCount.studentCount! * 100, + radius: MediaQuery.of(context).size.width * 0.06, + title: '${state.dataCount.studentCount! - state.dataCount.studentSubmitCount!}人', + titleStyle: TextStyle( + fontSize: 14.sp, + color: Colors.white, + ), + ), + ], + ), + ), + ), + ], + )), + SizedBox(width: 20.r,), + Expanded(child: Column( + + children: [ + // 客观进度条 + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '客观题答题进度', + style: TextStyle(fontSize: 10.sp, color: const Color(0xFF8B8B8B)), + ), + Text( + '${state.dataCount.kgtAnswerRate!.toStringAsFixed(0)}%', + style: TextStyle(fontSize: 10.sp, color: const Color(0xFF333333)), + ), + ], + ), + SizedBox(height: 6.r), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + flex: 10, + child: LinearPercentIndicator( + padding: EdgeInsets.zero, + animation: true, + lineHeight: 9.h, + animationDuration: 2500, + percent: state.dataCount.kgtAnswerRate! / 100, + progressColor: const Color(0xFFB2DA93), + backgroundColor: const Color(0xFFEAEAEA), + barRadius: Radius.circular(10.r), + )), + ], + ), + SizedBox(height: 20.r), + // 主观进度条 + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '主观题答题进度', + style: TextStyle(fontSize: 10.sp, color: const Color(0xFF8B8B8B)), + ), + Text( + '${state.dataCount.zgtAnswerRate!.toStringAsFixed(0)}%', + style: TextStyle(fontSize: 10.sp, color: const Color(0xFF333333)), + ), + ], + ), + SizedBox(height: 6.r), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + flex: 10, + child: LinearPercentIndicator( + padding: EdgeInsets.zero, + animation: true, + lineHeight: 9.h, + animationDuration: 2500, + percent: state.dataCount.zgtAnswerRate! / 100, + progressColor: const Color(0xFFB2DA93), + backgroundColor: const Color(0xFFEAEAEA), + barRadius: Radius.circular(10.r), + )), + ], + ), + + ],)) + + ], + ), + ), + QuickDataCheckBottom( + jobData: state.studentList.value, + jobId: state.homeworkId.value, + kgCount: state.dataCount.kgtDtlCount!, + zgCount: state.dataCount.zgtDtlCount!, + subject:state.subject, + ), + //客观题、主观题 + KgtZgtTable( + studentCount: state.dataCount.studentCount!, + homeworkId: state.homeworkId.value, + kgReport: state.kgReport, + zgReport: state.zgReport, + kgtOkRate: state.dataCount.kgtOkRate!.toStringAsFixed(0), + kgtCorrectRate: state.dataCount.kgtCorrectRate!.toStringAsFixed(0), + zgtOkRate: state.dataCount.zgtOkRate!.toStringAsFixed(0), + zgtCorrectRate: state.dataCount.zgtCorrectRate!.toStringAsFixed(0), + subject:state.subject), + ], + ), + )); + } else { + return Padding(padding: EdgeInsets.only(top: MediaQuery.of(context).size.height / 2 - 200.r), child: const MyEmptyWidget()); + } + }) + ], + ), + ), + ); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart new file mode 100644 index 0000000..d51e64a --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/widget/kgt_zgt_table.dart @@ -0,0 +1,156 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.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/home_page/children/quick_data_check/widget/report_table.dart'; +import 'package:making_school_asignment_app/page/home_page/widget/progress_bar.dart'; + +class KgtZgtTable extends StatefulWidget { + final int studentCount; + final String homeworkId; + final List kgReport; + final List zgReport; + final String kgtOkRate; + final String zgtOkRate; + final String kgtCorrectRate; + final String zgtCorrectRate; + final int subject; + + const KgtZgtTable( + {Key? key, + required this.studentCount, + required this.homeworkId, + required this.kgReport, + required this.zgReport, + required this.kgtOkRate, + required this.kgtCorrectRate, + required this.zgtOkRate, + required this.zgtCorrectRate, + required this.subject}) + : super(key: key); + + @override + State createState() => _KgtZgtTableState(); +} + +class _KgtZgtTableState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + //客观题 + Container( + padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 10.r), + margin: EdgeInsets.symmetric(vertical: 10.r, horizontal: 14.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(6.r)), + ), + child: Column( + children: [ + Text( + '客观题', + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF5C5C5C), fontWeight: FontWeight.w600), + ), + SizedBox(height: 20.r), + ProgressBar( + color: const Color.fromRGBO(76, 199, 147, 1), + percent: double.parse(widget.kgtCorrectRate) / 100, + title: '作答正确率:', + padingEdg: EdgeInsets.only(left: 5.w, right: 10.w), + fontSize: 10.sp, + lineHeight: 10.h, + marginEdg: EdgeInsets.only(top: 5.h), + ), + ProgressBar( + color: const Color.fromRGBO(76, 199, 147, 1), + percent: double.parse(widget.kgtOkRate) / 100, + title: '全班正确率:', + padingEdg: EdgeInsets.only(left: 5.w, right: 10.w), + fontSize: 10.sp, + lineHeight: 10.h, + marginEdg: EdgeInsets.only(top: 5.h), + ), + SizedBox(height: 10.r), + SizedBox( + height: widget.kgReport.length > 10 ? 300.h : widget.kgReport.length * 40.h + (Utils.isPad() == true ? 40.h : 65.h), + child: ReportTable( + headList: const ['题', '作答率', '作答人数', '作答正确率', '全班正确率', '标准答案', '优先批阅概况'], + bodyList: widget.kgReport, + fixedCols: 1, + fixedRows: 1, + jobId: widget.homeworkId, + studentCount: widget.studentCount, + subject: widget.subject, + ), + ), + if (widget.kgReport.isEmpty) MyEmptyWidget(imgWidth: 100.r, imgHeight: 100.r, font: 8.sp), + ], + ), + ), + //主观题 + Container( + padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 14.r), + margin: EdgeInsets.symmetric(vertical: 10.r, horizontal: 10.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(6.r)), + ), + child: Column( + children: [ + Text( + '主观题', + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF5C5C5C), fontWeight: FontWeight.w600), + ), + SizedBox( + height: 20.r, + ), + ProgressBar( + color: const Color.fromRGBO(76, 199, 147, 1), + percent: double.parse(widget.zgtCorrectRate) / 100, + title: '作答正确率:', + padingEdg: EdgeInsets.only(left: 5.w, right: 10.w), + fontSize: 10.sp, + lineHeight: 10.h, + marginEdg: EdgeInsets.only(top: 5.h), + ), + ProgressBar( + color: const Color.fromRGBO(76, 199, 147, 1), + percent: double.parse(widget.zgtOkRate) / 100, + title: '全班正确率:', + padingEdg: EdgeInsets.only(left: 5.w, right: 10.w), + fontSize: 10.sp, + lineHeight: 10.h, + marginEdg: EdgeInsets.only(top: 5.h), + ), + SizedBox( + height: 10.r, + ), + SizedBox( + height: widget.zgReport.length > 10 ? 300.h : widget.zgReport.length * 40.h + (Utils.isPad() == true ? 40.h : 65.h), + child: ReportTable( + headList: const ['题', '作答率', '作答人数', '作答正确率', '全班正确率', '查看原题', '优先批阅概况', '作答效率'], + bodyList: widget.zgReport, + fixedCols: 1, + fixedRows: 1, + isZG: true, + jobId: widget.homeworkId, + studentCount: widget.studentCount, + subject: widget.subject, + ), + ), + if (widget.zgReport.isEmpty) MyEmptyWidget(imgWidth: 100.r, imgHeight: 100.r, font: 8.sp), + ], + ), + ), + ], + ); + } +} diff --git a/lib/page/home_page/children/quick_data_check/widget/quick_data_check_bottom.dart b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/widget/quick_data_check_bottom.dart similarity index 61% rename from lib/page/home_page/children/quick_data_check/widget/quick_data_check_bottom.dart rename to making_school_asignment_app/lib/page/home_page/children/quick_data_check/widget/quick_data_check_bottom.dart index 563d5af..2506e98 100644 --- a/lib/page/home_page/children/quick_data_check/widget/quick_data_check_bottom.dart +++ b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/widget/quick_data_check_bottom.dart @@ -1,18 +1,19 @@ import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart'; class QuickDataCheckBottom extends StatefulWidget { final String jobId; final int kgCount; final int zgCount; + final int subject; final List? jobData; - const QuickDataCheckBottom( - {Key? key, required this.jobId, required this.jobData, required this.kgCount, required this.zgCount}) - : super(key: key); + const QuickDataCheckBottom({Key? key, required this.jobId, required this.jobData, required this.kgCount, required this.zgCount,required this.subject}) : super(key: key); @override State createState() => _QuickDataCheckBottomState(); @@ -23,13 +24,14 @@ class _QuickDataCheckBottomState extends State { RxList followList = RxList(); RxBool sortType = true.obs; RxBool sortLevel = false.obs; + RxBool sortCompleteRate = false.obs; @override void initState() { super.initState(); - showList.value = widget.jobData!; + showList.value = [...widget.jobData!]; for (var e in widget.jobData!) { - if(e.priorityAnnotate!){ + if (e.priorityAnnotate!) { followList.add(e); } } @@ -40,9 +42,7 @@ class _QuickDataCheckBottomState extends State { return Container( padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 10.r), margin: EdgeInsets.symmetric(vertical: 10.r, horizontal: 14.r), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(6.r))), + decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(6.r))), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -51,19 +51,22 @@ class _QuickDataCheckBottomState extends State { children: [ InkWell( onTap: () { - sortType.value = !sortType.value; - sortLevel.value = false; if (widget.jobData == null) return; + showList.value = [...widget.jobData!]; if (!sortType.value) { - showList.sort((a, b) { - return a.state.compareTo(b.state); - }); - } else { showList.sort((a, b) { return b.state.compareTo(a.state); }); + + } else { + showList.sort((a, b) { + return a.state.compareTo(b.state); + }); } + sortType.value = !sortType.value; + sortLevel.value = false; + sortCompleteRate.value = false; }, child: Obx(() { return Row( @@ -85,8 +88,7 @@ class _QuickDataCheckBottomState extends State { ), Text( sortType.value ? '已提交排序' : '未提交排序', - style: - TextStyle(fontSize: 12.sp, color: Color(0xFF707070)), + style: TextStyle(fontSize: 12.sp, color: Color(0xFF707070)), ), ], ); @@ -100,16 +102,17 @@ class _QuickDataCheckBottomState extends State { if (widget.jobData!.isEmpty) return; if (!sortLevel.value) { showList.value = followList.value; + sortType.value = false; } else { - widget.jobData!.sort((a, b) { - int num1 = a.state; - int num2 = b.state; - return num2.compareTo(num1); + showList.value = [...widget.jobData!]; + showList.sort((a, b) { + return b.state.compareTo(a.state); }); - showList.value = widget.jobData!; + + sortType.value = true; } + sortCompleteRate.value = false; sortLevel.value = !sortLevel.value; - sortType.value = false; }, child: Obx(() { return Row( @@ -131,8 +134,57 @@ class _QuickDataCheckBottomState extends State { ), Text( '看关注学生', - style: TextStyle( - fontSize: 12.sp, color: const Color(0xFF707070)), + style: TextStyle(fontSize: 12.sp, color: const Color(0xFF707070)), + ), + ], + ); + }), + ), + SizedBox( + width: 20.r, + ), + InkWell( + onTap: () { + if (widget.jobData!.isEmpty) return; + showList.value = [...widget.jobData!]; + if (!sortCompleteRate.value) { + showList.sort((a, b) { + return b.answerRate!.toInt().compareTo(a.answerRate!.toInt()); + }); + + sortType.value = false; + } else { + showList.value = [...widget.jobData!]; + showList.sort((a, b) { + return b.state.compareTo(a.state); + }); + + sortType.value = true; + } + sortLevel.value = false; + sortCompleteRate.value = !sortCompleteRate.value; + }, + child: Obx(() { + return Row( + children: [ + if (!sortCompleteRate.value) + Image.asset( + 'assets/images/no_check_icon.png', + width: 16.r, + height: 16.r, + ), + if (sortCompleteRate.value) + Image.asset( + 'assets/images/check_icon.png', + width: 16.r, + height: 16.r, + ), + SizedBox( + width: 5.r, + ), + Text( + '完成率排序', + style: TextStyle(fontSize: 12.sp, color: const Color(0xFF707070)), ), ], ); @@ -147,8 +199,7 @@ class _QuickDataCheckBottomState extends State { children: [ Text( '注:', - style: - TextStyle(fontSize: 8.sp, color: const Color(0xFF717171)), + style: TextStyle(fontSize: 8.sp, color: const Color(0xFF717171)), ), Container( width: 10.r, @@ -226,8 +277,7 @@ class _QuickDataCheckBottomState extends State { ), Text( '未做', - style: TextStyle( - fontSize: 8.sp, color: const Color(0xFF717171)), + style: TextStyle(fontSize: 8.sp, color: const Color(0xFF717171)), ), ], ), @@ -235,22 +285,29 @@ class _QuickDataCheckBottomState extends State { height: 10.r, ), Obx(() { - return SizedBox( - height: showList.value.length > 5 ? 350.r : showList.value - .length * 50.r + 40.r, - child: QuickStudentDataTable( - headList: ['学生姓名', '客观题', '主观题', '客观题状态', '主观题状态', '未批阅'], - bodyList: showList.value, - jobId: widget.jobId, - fixedRows: 1, - fixedCols: 0, - // hasUnrated: widget.jobData!.hasUnrated, - hasUnrated: false, - kgCount: widget.kgCount, - zgCount: widget.zgCount, - ), + return Column( + children: [ + SizedBox( + height: showList.value.length > 5 ? 350.r : showList.value.length * 50.r + 60.r, + child: QuickStudentDataTable( + headList: ['学生姓名', '总用时','客观题', '主观题', '客观题状态', '主观题状态', '未批阅'], + bodyList: showList.value, + jobId: widget.jobId, + fixedRows: 1, + fixedCols: 0, + // hasUnrated: widget.jobData!.hasUnrated, + hasUnrated: false, + kgCount: widget.kgCount, + zgCount: widget.zgCount, + subject:widget.subject, + ), + ), + if(showList.isEmpty) + MyEmptyWidget(imgWidth: 100.r,imgHeight: 100.r,font: 10.sp,), + ], ); - }) + }), + ], ), ); diff --git a/lib/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart similarity index 53% rename from lib/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart rename to making_school_asignment_app/lib/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart index 72042b0..1c35985 100644 --- a/lib/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart +++ b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/widget/quick_student_data_table.dart @@ -2,8 +2,8 @@ import 'package:data_table_2/data_table_2.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; class QuickStudentDataTable extends StatefulWidget { final List headList; @@ -14,6 +14,7 @@ class QuickStudentDataTable extends StatefulWidget { final bool hasUnrated; final int kgCount; final int zgCount; + final int subject; const QuickStudentDataTable({ Key? key, @@ -23,6 +24,7 @@ class QuickStudentDataTable extends StatefulWidget { required this.hasUnrated, required this.kgCount, required this.zgCount, + required this.subject, this.fixedCols = 0, this.fixedRows = 0, }) : super(key: key); @@ -36,7 +38,6 @@ class _QuickStudentDataTableState extends State { int? _sortColumnIndex; final bool _sortAscending = true; - DataRow _getRow(int index, [Color? color]) { assert(index >= 0); Students item = widget.bodyList[index]; @@ -44,13 +45,13 @@ class _QuickStudentDataTableState extends State { index: index, color: color != null ? item.allNotDone! - ? MaterialStateProperty.all(Color(0xFFFFD79C)) - : MaterialStateProperty.all(color) + ? WidgetStateProperty.all(const Color(0xFFFFD79C)) + : WidgetStateProperty.all(color) : null, cells: [ DataCell(InkWell( onTap: () { - Get.toNamed(Routes.studentPersonalPage,arguments: {'studentId':item.studentId,'homeworkId':widget.jobId}); + Get.toNamed(Routes.studentPersonalPage, arguments: {'studentId': item.studentId, 'homeworkId': widget.jobId,'subject':widget.subject}); }, child: Center( child: Padding( @@ -59,9 +60,7 @@ class _QuickStudentDataTableState extends State { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text(item.studentName!, - style: - TextStyle(fontSize: 10.sp, color: const Color(0xFF6888FD),overflow: TextOverflow.ellipsis)), + Text(item.studentName!, style: TextStyle(fontSize: 10.sp, color: const Color(0xFF4CC793), overflow: TextOverflow.ellipsis)), SizedBox( width: 5.r, ), @@ -75,21 +74,21 @@ class _QuickStudentDataTableState extends State { ), ), )), + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text(item.ttlSec.toString(), style: TextStyle(fontSize: 10.sp, color: const Color(0xFF525252), overflow: TextOverflow.ellipsis)), + ), + )), DataCell(Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - '${item.kgtOkCount}', - style: TextStyle(fontSize: 10.sp, color: Color(0xFF4CC793))), - Text( - '/', - style: TextStyle(fontSize: 10.sp, color: Color(0xFF525252))), - Text( - '${item.kgtErrorCount}', - style: TextStyle(fontSize: 10.sp, color: Color(0xFFFF7474))), + Text('${item.kgtOkCount}', style: TextStyle(fontSize: 10.sp, color: Color(0xFF4CC793))), + Text('/', style: TextStyle(fontSize: 10.sp, color: Color(0xFF525252))), + Text('${item.kgtErrorCount}', style: TextStyle(fontSize: 10.sp, color: Color(0xFFFF7474))), ], ), ), @@ -100,15 +99,9 @@ class _QuickStudentDataTableState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - '${item.zgtOkCount}', - style: TextStyle(fontSize: 10.sp, color: Color(0xFF4CC793))), - Text( - '/', - style: TextStyle(fontSize: 10.sp, color: Color(0xFF525252))), - Text( - '${item.zgtErrorCount}', - style: TextStyle(fontSize: 10.sp, color: Color(0xFFFF7474))), + Text('${item.zgtOkCount}', style: TextStyle(fontSize: 10.sp, color: Color(0xFF4CC793))), + Text('/', style: TextStyle(fontSize: 10.sp, color: Color(0xFF525252))), + Text('${item.zgtErrorCount}', style: TextStyle(fontSize: 10.sp, color: Color(0xFFFF7474))), ], ), ), @@ -125,23 +118,21 @@ class _QuickStudentDataTableState extends State { children: List.generate(item.kgtStu!.length, (index) { Dtls kgInfo = item.kgtStu![index]; return Container( - width: 14.r, - height: 14.r, + width: 20.r, + height: 20.r, decoration: BoxDecoration( color: kgInfo.state == 0 ? const Color(0xFFD3D3D3) - : kgInfo.state == 1?Colors.white:kgInfo.state == 2 - ? const Color(0xFFFF7474) - : const Color(0xFF4CC793), - borderRadius: BorderRadius.all(Radius.circular(7.r))), + : kgInfo.state == 1 + ? Colors.white + : kgInfo.state == 2 + ? const Color(0xFFFF7474) + : const Color(0xFF4CC793), + borderRadius: BorderRadius.all(Radius.circular(10.r))), child: Center( child: Text( kgInfo.questionNo.toString(), - style: TextStyle( - fontSize: 8.sp, - color: kgInfo.state == 1 - ? Color(0xFF525252) - : Colors.white), + style: TextStyle(fontSize: 8.sp, color: kgInfo.state == 1 ? Color(0xFF525252) : Colors.white), )), ); })), @@ -160,45 +151,41 @@ class _QuickStudentDataTableState extends State { children: List.generate(item.zgtStu!.length, (index) { Dtls kgInfo = item.zgtStu![index]; return Container( - width: 14.r, - height: 14.r, + width: 20.r, + height: 20.r, decoration: BoxDecoration( color: kgInfo.state == 0 ? const Color(0xFFD3D3D3) - : kgInfo.state == 1?Colors.white:kgInfo.state == 2 - ? const Color(0xFFFF7474) - : const Color(0xFF4CC793), - borderRadius: BorderRadius.all(Radius.circular(7.r))), + : kgInfo.state == 1 + ? Colors.white + : kgInfo.state == 2 + ? const Color(0xFFFF7474) + : const Color(0xFF4CC793), + borderRadius: BorderRadius.all(Radius.circular(10.r))), child: Center( child: Text( kgInfo.questionNo.toString(), - style: TextStyle( - fontSize: 8.sp, - color: kgInfo.state == 1 - ? Color(0xFF525252) - : Colors.white), + style: TextStyle(fontSize: 8.sp, color: kgInfo.state == 1 ? Color(0xFF525252) : Colors.white), )), ); })), ), ), ), - if(widget.hasUnrated) - DataCell(Center( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text('${item.zgtUnrated}', - style: - TextStyle(fontSize: 10.sp, color: const Color(0xFF6888FD))), - ), - )), + if (widget.hasUnrated) + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text('${item.zgtUnrated}', style: TextStyle(fontSize: 10.sp, color: const Color(0xFFE8E8E8))), + ), + )), ], ); } @override Widget build(BuildContext context) { - if(!widget.hasUnrated){ + if (!widget.hasUnrated) { widget.headList.removeLast(); } return DataTable2( @@ -209,14 +196,10 @@ class _QuickStudentDataTableState extends State { bottomMargin: 0, dataRowHeight: 50.r, border: const TableBorder( - horizontalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - bottom: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - verticalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid)), - headingRowColor: MaterialStateProperty.resolveWith((states) => - widget.fixedCols! > 0 ? Colors.white : Colors.transparent), + horizontalInside: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid), + bottom: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid), + verticalInside: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid)), + headingRowColor: MaterialStateProperty.resolveWith((states) => widget.fixedCols! > 0 ? Colors.white : Colors.transparent), headingRowDecoration: BoxDecoration(color: Color(0xFFE6E6E6)), fixedColumnsColor: Color(0xFFE6E6E6), fixedCornerColor: Colors.grey[400], @@ -228,42 +211,32 @@ class _QuickStudentDataTableState extends State { // onSelectAll: (val) => setState(() => selectAll(val)), columns: List.generate(widget.headList.length, (index) { var item = widget.headList[index]; - return index == 1?DataColumn2( - label: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text(item, - style: TextStyle(fontSize: 10.sp, color: Color(0xFF505767))), - Text('(${widget.kgCount})', - style: TextStyle(fontSize: 8.sp, color: Color(0xFF505767))), - ] - ), - // size: ColumnSize.S, - fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / widget.headList.length, - ):index == 2?DataColumn2( - label: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text(item, - style: TextStyle(fontSize: 10.sp, color: Color(0xFF505767))), - Text('(${widget.zgCount})', - style: TextStyle(fontSize: 8.sp, color: Color(0xFF505767))), - ] - ), - // size: ColumnSize.S, - fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / widget.headList.length, - ):DataColumn2( - label: Center( - child: Text(item, - style: TextStyle(fontSize: 10.sp, color: Color(0xFF505767))), - ), - // size: ColumnSize.S, - fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / widget.headList.length, - ); + return index == 2 + ? DataColumn2( + label: Row(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ + Text(item, style: TextStyle(fontSize: 10.sp, color: Color(0xFF505767))), + Text('(${widget.kgCount})', style: TextStyle(fontSize: 8.sp, color: Color(0xFF505767))), + ]), + // size: ColumnSize.S, + fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / widget.headList.length, + ) + : index == 3 + ? DataColumn2( + label: Row(mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ + Text(item, style: TextStyle(fontSize: 10.sp, color: Color(0xFF505767))), + Text('(${widget.zgCount})', style: TextStyle(fontSize: 8.sp, color: Color(0xFF505767))), + ]), + // size: ColumnSize.S, + fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / widget.headList.length, + ) + : DataColumn2( + label: Center( + child: Text(item, style: TextStyle(fontSize: 10.sp, color: Color(0xFF505767))), + ), + // size: ColumnSize.S, + fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / widget.headList.length, + ); }), - rows: List.generate(widget.bodyList.length, - (index) => _getRow(index, Color(0xFFF5F5F5)))); + rows: List.generate(widget.bodyList.length, (index) => _getRow(index, Color(0xFFF5F5F5)))); } } diff --git a/making_school_asignment_app/lib/page/home_page/children/quick_data_check/widget/report_table.dart b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/widget/report_table.dart new file mode 100644 index 0000000..ef4ff98 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/quick_data_check/widget/report_table.dart @@ -0,0 +1,1057 @@ +import 'package:data_table_2/data_table_2.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_echart/flutter_echart.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:get/get_rx/get_rx.dart'; +import 'package:making_school_asignment_app/common/job/annotated_class.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.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/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/imgDialog.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.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:auto_size_text/auto_size_text.dart'; + +class ReportTable extends StatefulWidget { + final List headList; + final List bodyList; + final int? fixedRows; + final int? fixedCols; + final bool? isZG; + final String jobId; + final int studentCount; + final int subject; + + const ReportTable({ + Key? key, + required this.headList, + required this.bodyList, + required this.jobId, + required this.studentCount, + required this.subject, + this.fixedCols = 0, + this.fixedRows = 0, + this.isZG = false, + }) : super(key: key); + + @override + State createState() => _ReportTableState(); +} + +class _ReportTableState extends State { + final ScrollController _controller = ScrollController(); + int? _sortColumnIndex; + final bool _sortAscending = true; + List colorMap = const [ + Color.fromRGBO(184, 161, 255, 1), + Color.fromRGBO(79, 199, 147, 1), + Color.fromRGBO(144, 224, 190, 1), + Color.fromRGBO(255, 107, 107, 1), + Color.fromRGBO(211, 211, 211, 1), + ]; + + void showAnswerEfficiency(overallTitles) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + contentPadding: EdgeInsets.all(20.r), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(15.r))), + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.5, + height: MediaQuery.of(context).size.height * 0.4, + child: Column( + children: [ + Text( + '作答效率', + style: TextStyle( + fontSize: 15.sp, + color: const Color(0xFF3C3C3C), + fontWeight: FontWeight.w500), + ), + Padding( + padding: + EdgeInsets.symmetric(vertical: 20.r, horizontal: 10.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + mapIcon(const Color(0xFFB8A1FF)), + SizedBox( + width: 5.r, + ), + mapTxt('优'), + const Spacer(), + mapIcon(const Color(0xFF4CC793)), + SizedBox( + width: 5.r, + ), + mapTxt('良'), + const Spacer(), + mapIcon(const Color(0xFF90E0BE)), + SizedBox( + width: 5.r, + ), + mapTxt('中'), + const Spacer(), + mapIcon(const Color(0xFFFF6B6B)), + SizedBox( + width: 5.r, + ), + mapTxt('差'), + ], + ), + ), + Expanded( + child: PieChart( + PieChartData( + borderData: FlBorderData(show: true), + sectionsSpace: 0, + centerSpaceRadius: 0, + sections: List.generate(overallTitles.length, (index) { + var e = overallTitles[index]; + return PieChartSectionData( + color: colorMap[index], + value: e.count / widget.studentCount * 100, + radius: 110, + // borderSide:BorderSide(color: const Color(0xFF273366),width: 0.5.r), + // title: e.title + (Utils.doubleToStringAsFixed(e.count / widget.studentCount * 100) + '%'), + title: e.count.toString(), + titleStyle: TextStyle( + fontSize: 12.sp, + color: const Color(0xFFFFFFFF)), + ); + }), + ), + ), + + /*PieChatWidget( + dataList: List.generate(overallTitles.length, (index) { + var e = overallTitles[index]; + return EChartPieBean( + title: e.title, + number: e.count, + color: colorMap[index]); + }), + //是否需要背景 + isBackground: false, + //是否画直线 + isLineText: true, + //背景 + bgColor: Colors.white, + //是否显示最前面的内容 + isFrontgText: false, + //默认选择放大的块 + initSelect: 1, + //初次显示以动画方式展开 + openType: OpenType.ANI, + //旋转类型 + loopType: LoopType.DOWN_LOOP, + //点击回调 + clickCallBack: (int value) { + print("当前点击显示 $value"); + }, + ),*/ + ), + ], + ), + ), + ); + }); + } + + void showPeopleListDialog( + {required BuildContext context, + required String title, + required String questionNo, + required List arr, + List? dcList}) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + // insetPadding: EdgeInsets.symmetric(vertical: 20.r,horizontal: 20.r), + contentPadding: EdgeInsets.all(20.r), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(15.r))), + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.7, + height: MediaQuery.of(context).size.height * 0.7, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Text( + title, + style: TextStyle( + fontSize: 15.sp, + color: const Color(0xFF3C3C3C), + fontWeight: FontWeight.w500), + ), + ), + SizedBox( + height: 5.r, + ), + Row( + children: [ + Text( + widget.isZG == true ? '主观题' : '客观题', + style: TextStyle( + fontSize: 14.sp, + color: Theme.of(context).primaryColor), + ), + Text( + '―', + style: TextStyle( + fontSize: 14.sp, + color: Theme.of(context).primaryColor), + ), + Text( + '第$questionNo题', + style: TextStyle( + fontSize: 14.sp, + color: Theme.of(context).primaryColor), + ), + ], + ), + SizedBox( + height: 15.r, + ), + dcList != null + ? Row( + children: [ + Expanded( + flex: 1, + child: Center( + child: Text( + '未作答人', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF6A6A6A)), + ))), + Expanded( + flex: 1, + child: Center( + child: Text( + '答对人数', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF6A6A6A)), + ))), + Expanded( + flex: 1, + child: Center( + child: Text( + '答错人', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF6A6A6A)), + ))), + ], + ) + : Padding( + padding: EdgeInsets.only(left: 15.r), + child: Text( + title, + style: TextStyle( + fontSize: 12.sp, color: Color(0xFF6A6A6A)), + ), + ), + SizedBox( + height: 5.r, + ), + if (dcList != null) + Expanded( + child: ListView.builder( + shrinkWrap: true, + itemBuilder: (context, index) { + var item = arr[index]; + return Container( + padding: EdgeInsets.symmetric(vertical: 5.r), + color: + index.isOdd ? Colors.white : Color(0xFFF0F0F0), + child: Row( + children: [ + Expanded( + flex: 1, + child: InkWell( + onTap: () { + goQuickCheckPersonalPath( + item['noAnswerStudents'] + .studentId); + }, + child: Center( + child: Text( + item['noAnswerStudents'] + ?.studentName ?? + '--', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF323232)), + )))), + Expanded( + flex: 1, + child: InkWell( + onTap: () { + goQuickCheckPersonalPath( + item['answerOkStudents'] + .studentId); + }, + child: Center( + child: Text( + item['answerOkStudents'] + ?.studentName ?? + '--', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF323232)), + )))), + Expanded( + flex: 1, + child: InkWell( + onTap: () { + goQuickCheckPersonalPath( + item['answerNgStudents'] + .studentId); + }, + child: Center( + child: Text( + item['answerNgStudents'] + ?.studentName ?? + '--', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF323232)), + )))), + ], + ), + ); + }, + itemCount: arr.length, + ), + ) + else + arr.isNotEmpty + ? Expanded( + child: ListView.builder( + shrinkWrap: true, + itemBuilder: (context, index) { + Dtls item = arr[index]; + return InkWell( + onTap: () { + goQuickCheckPersonalPath(item.studentId); + }, + child: Container( + padding: EdgeInsets.symmetric( + vertical: 5.r, horizontal: 15.r), + color: index.isOdd + ? Colors.white + : Color(0xFFF0F0F0), + child: Text( + item.studentName! ?? '--', + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF323232)), + ), + ), + ); + }, + itemCount: arr.length, + ), + ) + : const MyEmptyWidget() + ], + ), + ), + ); + }); + } + + void goQuickCheckPersonalPath(id) { + if (id != null) { + Get.toNamed(Routes.studentPersonalPage, arguments: { + 'studentId': id, + 'homeworkId': widget.jobId, + 'subject': widget.subject + }); + } + } + + void zdHandle(BuildContext context, String title, String questionNo, + List noAnswerStudents, List answerNgStudents, List answerOkStudents) { + List list = []; + // Questions student = Questions('','',-1,-1,'',-1,'','',[],-1,-1,[] as double?); + if (noAnswerStudents.length > answerNgStudents.length && + noAnswerStudents.length > answerOkStudents.length) { + for (int i = 0; i < noAnswerStudents.length; i++) { + var obj = { + 'noAnswerStudents': noAnswerStudents[i], + 'answerNgStudents': + answerNgStudents.length > i ? answerNgStudents[i] : null, + 'answerOkStudents': + answerOkStudents.length > i ? answerOkStudents[i] : null + }; + list.add(obj); + } + } else if (answerNgStudents.length > noAnswerStudents.length && + answerNgStudents.length > answerOkStudents.length) { + for (int i = 0; i < answerNgStudents.length; i++) { + var obj = { + 'noAnswerStudents': + noAnswerStudents.length > i ? noAnswerStudents[i] : null, + 'answerNgStudents': answerNgStudents[i], + 'answerOkStudents': + answerOkStudents.length > i ? answerOkStudents[i] : null + }; + list.add(obj); + } + } else if (answerOkStudents.length > noAnswerStudents.length && + answerOkStudents.length > answerNgStudents.length) { + for (int i = 0; i < answerOkStudents.length; i++) { + var obj = { + 'noAnswerStudents': + noAnswerStudents.length > i ? noAnswerStudents[i] : null, + 'answerNgStudents': + answerNgStudents.length > i ? answerNgStudents[i] : null, + 'answerOkStudents': answerOkStudents[i] + }; + list.add(obj); + } + } else { + for (int i = 0; i < answerOkStudents.length; i++) { + var obj = { + 'noAnswerStudents': + noAnswerStudents.length > i ? noAnswerStudents[i] : null, + 'answerNgStudents': + answerNgStudents.length > i ? answerNgStudents[i] : null, + 'answerOkStudents': answerOkStudents[i] + }; + list.add(obj); + } + } + + showPeopleListDialog( + context: context, + title: title, + questionNo: questionNo, + arr: list, + dcList: []); + } + + void dcHandle( + BuildContext context, String title, String questionNo, List arr) { + showPeopleListDialog( + context: context, title: title, questionNo: questionNo, arr: arr); + } + + DataRow _getRow(int index, [Color? color]) { + assert(index >= 0); + var item = widget.bodyList[index]; + return DataRow2.byIndex( + index: index, + color: color != null ? WidgetStateProperty.all(color) : null, + cells: [ + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text(item.questionNo.toString(), + style: + TextStyle(fontSize: 10.sp, color: const Color(0xFF525252))), + ), + )), + DataCell(InkWell( + onTap: () { + if (widget.isZG == false) { + showSelectRate( + questionNo: item.questionNo.toString(), + options: item.options, + answer: item.answer, + ); + } + }, + child: Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text('${item.answerRate.toStringAsFixed(0)}%', + style: TextStyle( + fontSize: 10.sp, + color: widget.isZG == false + ? Theme.of(context).primaryColor + : const Color(0xFF525252))), + ), + ), + )), + DataCell(InkWell( + onTap: () { + zdHandle( + context, + '作答人数', + item.questionNo.toString(), + item.noAnswerStudents, + item.answerNgStudents, + item.answerOkStudents); + }, + child: Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('${item.answerCount}/${widget.studentCount}', + style: TextStyle( + fontSize: 10.sp, + color: Theme.of(context).primaryColor)), + Image.asset( + 'assets/images/green_right_icon.png', + width: 12.r, + height: 12.r, + ), + ], + ), + ), + ), + )), + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text('${item.correctRate.toStringAsFixed(0)}%', + style: + TextStyle(fontSize: 10.sp, color: const Color(0xFF525252))), + ), + )), + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Text('${item.okRate.toStringAsFixed(0)}%', + style: + TextStyle(fontSize: 10.sp, color: const Color(0xFF525252))), + ), + )), + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: widget.isZG == true + ? InkWell( + onTap: () { + if (item.questionPicture == null) { + ToastUtils.showInfo('当前试题没有原题'); + } else { + ImageDialog.showImgDialog( + context, item.questionPicture); + } + }, + child: Text('原题', + style: TextStyle( + fontSize: 10.sp, + color: widget.isZG == true + ? const Color(0xFFFF8A00) + : Theme.of(context).primaryColor)), + ) + : Text(item.answer, + style: TextStyle( + fontSize: 10.sp, + color: widget.isZG == true + ? const Color(0xFFFF8A00) + : Theme.of(context).primaryColor)), + ), + )), + DataCell(InkWell( + onTap: () { + // List parts = item.priorityGeneral.split('人'); + dcHandle(context, '优先批阅答错人', item.questionNo.toString(), + item.priorityInfo); + }, + child: Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('${item.priorityInfo.length}人答错', + style: TextStyle( + fontSize: 10.sp, + color: Theme.of(context).primaryColor)), + Image.asset( + 'assets/images/green_right_icon.png', + width: 12.r, + height: 12.r, + ) + ], + ), + ), + ), + )), + if (widget.isZG == true) + DataCell(Center( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 5.r), + child: widget.isZG == true + ? InkWell( + onTap: () { + showAnswerEfficiency(item.overallTitles); + }, + child: Text('查看', + style: TextStyle( + fontSize: 10.sp, + color: widget.isZG == true + ? const Color(0xFFFF8A00) + : Theme.of(context).primaryColor)), + ) + : Text(item.answer, + style: TextStyle( + fontSize: 10.sp, + color: widget.isZG == true + ? const Color(0xFFFF8A00) + : Theme.of(context).primaryColor)), + ), + )), + ], + ); + } + + void showSelectRate( + {required String questionNo, + required List options, + required String answer}) { + RxList students = RxList(); + students.value = options; + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + // insetPadding: EdgeInsets.symmetric(vertical: 20.r,horizontal: 20.r), + contentPadding: EdgeInsets.all(0.r), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(15.r))), + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.7, + height: MediaQuery.of(context).size.height * 0.7, + child: Column( + children: [ + Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10.r), + topRight: Radius.circular(10.r), + )), + width: double.infinity, + child: Container( + alignment: Alignment.center, + padding: EdgeInsets.symmetric(vertical: 8.h), + child: Text( + '第$questionNo题', + style: + TextStyle(fontSize: 16.sp, color: Colors.white), + )), + ), + Expanded( + child: Padding( + padding: + EdgeInsets.symmetric(vertical: 5.h, horizontal: 10.w), + child: Column( + children: [ + SizedBox( + height: 10.h, + ), + Row( + children: [ + Text( + '标准答案:', + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF000101)), + ), + SizedBox( + width: 5.w, + ), + Container( + width: 20.r, + height: 20.r, + alignment: Alignment.center, + decoration: BoxDecoration( + color: const Color(0xFF4BC793), + borderRadius: + BorderRadius.all(Radius.circular(10.r)), + ), + child: AutoSizeText( + answer, + style: TextStyle( + fontSize: 12.sp, color: Colors.white), + maxLines: 1, + minFontSize: 10, + )) + ], + ), + SizedBox( + height: 10.h, + ), + Row( + children: [ + Text('选项', + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF000101), + )), + SizedBox( + width: 10.w, + ), + Text('选择率', + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF000101), + )), + ], + ), + SizedBox( + height: 5.h, + ), + Obx(() { + return Expanded( + child: students.isNotEmpty + ? ListView.builder( + // shrinkWrap: true, + // physics: NeverScrollableScrollPhysics(), + itemCount: students.length, + itemBuilder: (context, index) { + SelectionRate item = students[index]; + + return Container( + margin: EdgeInsets.only(bottom: 5.h), + decoration: BoxDecoration( + color: const Color(0xFFFAFAFA), + borderRadius: BorderRadius.all( + Radius.circular(5.r)), + ), + child: Column( + children: [ + SizedBox( + height: 5.h, + ), + Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + item.optionName == answer + ? Container( + width: 20.r, + height: 20.r, + margin: + EdgeInsets.only( + left: 4.r), + alignment: + Alignment.center, + decoration: + BoxDecoration( + color: const Color( + 0xFF4BC793), + borderRadius: + BorderRadius.all( + Radius.circular( + 10.r)), + ), + child: AutoSizeText( + item.optionName, + style: TextStyle( + fontSize: 12.sp, + color: Colors + .white), + maxLines: 1, + minFontSize: 10, + )) + : Padding( + padding: + EdgeInsets.only( + left: 8.r), + child: Text( + item.optionName, + style: TextStyle( + fontSize: 12.sp, + color: const Color( + 0xFF000101), + ), + ), + ), + SizedBox( + width: 10.w, + ), + Expanded( + child: ProgressBar( + color: Theme.of(context) + .primaryColor, + percent: item.rate / 100, + title: '', + padingEdg: + EdgeInsets.only( + left: 5.w, + right: 10.w), + fontSize: 10.sp, + lineHeight: 6.h, + marginEdg: + EdgeInsets.only( + top: 0.h), + ), + ), + SizedBox( + width: 15.w, + ), + InkWell( + onTap: () { + item.isCheck = + !item.isCheck; + students[index] = item; + }, + child: item.isCheck + ? const Icon( + Icons + .arrow_drop_down_rounded, + size: 30, + color: Color( + 0xFF000101), + ) + : const Icon( + Icons + .arrow_right_rounded, + size: 30, + color: Color( + 0xFF000101), + ), + ), + ], + ), + SizedBox( + height: 5.h, + ), + item.isCheck + ? Container( + width: double.infinity, + height: 120.h, + decoration: BoxDecoration( + color: const Color( + 0xFFF2F2F2), + borderRadius: + BorderRadius.only( + bottomLeft: + Radius.circular( + 5.r), + bottomRight: + Radius.circular( + 5.r), + )), + padding: + EdgeInsets.symmetric( + vertical: 5.h, + horizontal: 10.w), + child: Column( + crossAxisAlignment: + CrossAxisAlignment + .start, + children: [ + Text( + '选择的学生(${item.currentOptionStudents.length})', + style: TextStyle( + fontSize: 12.sp, + color: const Color( + 0xFF000101)), + ), + SizedBox( + height: 5.h, + ), + Expanded( + child: + SingleChildScrollView( + child: Wrap( + spacing: 6.r, + // 主轴(水平)方向间距 + runSpacing: 4.r, + // 纵轴(垂直)方向间距 + alignment: + WrapAlignment + .start, + //沿主轴方向居中 + children: item + .currentOptionStudents + .map((e) { + return InkWell( + onTap: () { + Get.toNamed( + Routes + .studentPersonalPage, + arguments: { + 'studentId': + e.studentId, + 'homeworkId': + widget.jobId, + 'subject': + widget.subject + }); + }, + child: + Container( + padding: EdgeInsets.symmetric( + vertical: 4 + .r, + horizontal: + 8.r), + color: const Color( + 0xFFF0ECFF), + child: quickText( + e + .studentName, + color: const Color( + 0xFF505E6E), + size: + 10.sp), + ), + ); + }).toList(), + ), + ), + ), + ], + ), + ) + : Container() + ], + ), + ); + }) + : const MyEmptyWidget(), + ); + }) + ], + ), + ), + ) + ], + ), + ), + ); + }); + } + + @override + Widget build(BuildContext context) { + bool isPadFlag = Utils.isPad(); + return DataTable2( + dividerThickness: 0, + scrollController: _controller, + columnSpacing: 0, + horizontalMargin: 0, + dataRowHeight: 40.h, + bottomMargin: 0, + headingRowHeight: 40.h, + border: const TableBorder( + horizontalInside: BorderSide( + width: 1, color: Colors.white, style: BorderStyle.solid), + bottom: BorderSide( + width: 1, color: Colors.white, style: BorderStyle.solid), + verticalInside: BorderSide( + width: 1, color: Colors.white, style: BorderStyle.solid)), + headingRowColor: MaterialStateProperty.resolveWith((states) => + widget.fixedCols! > 0 ? Colors.white : Colors.transparent), + headingRowDecoration: const BoxDecoration(color: Color(0xFFE6E6E6)), + fixedColumnsColor: const Color(0xFFE6E6E6), + fixedCornerColor: Colors.grey[400], + minWidth: widget.headList.length > 6 + ? 80.r * widget.headList.length + : isPadFlag + ? MediaQuery.of(context).size.width + : 85.r * widget.headList.length, + fixedTopRows: widget.fixedRows!, + fixedLeftColumns: widget.fixedCols!, + sortColumnIndex: _sortColumnIndex, + sortAscending: _sortAscending, + // onSelectAll: (val) => setState(() => selectAll(val)), + columns: List.generate(widget.headList.length, (index) { + var item = widget.headList[index]; + return DataColumn2( + label: index == 3 + ? Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text(item, + style: TextStyle( + fontSize: 10.sp, color: const Color(0xFF505767))), + SizedBox( + width: 2.r, + ), + const Tooltip( + message: '答对人数/作答人数', + triggerMode: TooltipTriggerMode.tap, + preferBelow: false, + child: Icon( + Icons.info_outline_rounded, + color: Colors.grey, + )), + ], + ) + : index == 4 + ? Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text(item, + style: TextStyle( + fontSize: 10.sp, + color: const Color(0xFF505767))), + SizedBox( + width: 2.r, + ), + const Tooltip( + message: '答对人数/总人数', + triggerMode: TooltipTriggerMode.tap, + preferBelow: false, + child: Icon( + Icons.info_outline_rounded, + color: Colors.grey, + )), + ], + ) + : Center( + child: Text(item, + style: TextStyle( + fontSize: 10.sp, + color: const Color(0xFF505767))), + ), + // size: ColumnSize.S, + fixedWidth: index == 0 + ? 40.r + : widget.headList.length > 6 + ? 80.r + : isPadFlag + ? (MediaQuery.of(context).size.width - 8.r) / + widget.headList.length + : 85.r, + ); + }), + rows: List.generate(widget.bodyList.length, + (index) => _getRow(index, const Color(0xFFF5F5F5)))); + } +} + +Widget mapIcon(Color bgColor) { + return Container( + width: 12.r, + height: 12.r, + decoration: BoxDecoration( + color: bgColor, + borderRadius: BorderRadius.all(Radius.circular(6.r)), + ), + ); +} + +Widget mapTxt(String title) { + return Text( + title, + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF525252), + fontWeight: FontWeight.w400), + ); +} diff --git a/lib/page/home_page/children/read_over/read_over_binding.dart b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_binding.dart similarity index 100% rename from lib/page/home_page/children/read_over/read_over_binding.dart rename to making_school_asignment_app/lib/page/home_page/children/read_over/read_over_binding.dart diff --git a/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_logic.dart b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_logic.dart new file mode 100644 index 0000000..0be5e84 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_logic.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/page/home_page/home_logic.dart'; + +import 'read_over_state.dart'; + +class ReadOverLogic extends GetxController with RequestToolMixin, GetTickerProviderStateMixin { + final ReadOverState state = ReadOverState(); + late TabController tabController; + final HomeLogic homeController = Get.find(); + + @override + void onInit() { + super.onInit(); + state.tabIndex.value = 0; + tabController = TabController( + length: 2, + vsync: this, + ); + } + + + @override + void dispose() { + super.dispose(); + tabController.dispose(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_state.dart b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_state.dart new file mode 100644 index 0000000..efeac22 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_state.dart @@ -0,0 +1,14 @@ +import 'package:get/get.dart'; + +class ReadOverState { + ReadOverState() { + ///Initialize variables + } + + + + late RxInt tabIndex = 2.obs; + late bool completedToRefresh = true; + late RxString customTimeStr = '自定义'.obs; + +} diff --git a/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.dart b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.dart new file mode 100644 index 0000000..f12cded --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/read_over/read_over_view.dart @@ -0,0 +1,189 @@ +import 'package:get/get.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/widget/annotate_list.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'read_over_logic.dart'; + +class ReadOverPage extends StatefulWidget { + const ReadOverPage({super.key}); + + @override + State createState() => _ReadOverPageState(); +} + +class _ReadOverPageState extends State { + final logic = Get.find(); + final state = Get.find().state; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return AnnotatedRegion( + value: const SystemUiOverlayStyle( + /* systemNavigationBarColor: Color(0xFF000000), + systemNavigationBarDividerColor: null,*/ + statusBarColor: Colors.white, + systemNavigationBarDividerColor: null, + systemNavigationBarIconBrightness: Brightness.light, + statusBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.light, + ), + child: Scaffold( + backgroundColor: const Color.fromRGBO(244, 244, 244, 1), + body: OrientationBuilder( + builder: (BuildContext context, Orientation orientation) { + return Column( + children: [ + Container( + color: Colors.white, + margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top), + padding: EdgeInsets.only(bottom: 9.h, top: 4.h), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + flex: 1, + child: InkWell( + onTap: () { + Get.back(); + }, + child: Container( + height: 30.h, + alignment: Alignment.centerLeft, + padding: EdgeInsets.only(left: 10.w), + child: Icon( + Icons.arrow_back_ios_sharp, + size: 16.sp, + ), + ), + )), + Expanded( + flex: 4, + child: Container( + padding: EdgeInsets.symmetric(vertical: 2.h), + alignment: Alignment.center, + decoration: BoxDecoration( + color: const Color.fromRGBO(243, 243, 243, 1), + borderRadius: BorderRadius.circular(8.r), + ), + child: TabBar( + padding: EdgeInsets.zero, + indicatorPadding: EdgeInsets.zero, + indicatorWeight: 0, + labelPadding: EdgeInsets.symmetric(horizontal: 2.w), + controller: logic.tabController, + unselectedLabelStyle: TextStyle( + fontSize: 14.sp, + color: const Color.fromRGBO(69, 83, 100, 1), + ), + labelStyle: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF8C68FF), + ), + // labelColor: const Color.fromRGBO(45, 56, 76, 1), + indicator: const UnderlineTabIndicator( + borderSide: BorderSide( + width: 0, // 设置边界宽度为0,从而去除下划线 + color: Colors.transparent), + ), + onTap: (index) { + state.tabIndex.value = index; + if (index == 1 && state.completedToRefresh) { + // 已阅卷 + // _refreshController2.callRefresh(); + state.completedToRefresh = false; + } + }, + tabs: [ + Tab( + iconMargin: EdgeInsets.zero, + height: 34.h, + child: Obx(() { + return Container( + width: 140.w, + alignment: Alignment.center, + decoration: BoxDecoration( + color: state.tabIndex.value == 0 ? const Color.fromRGBO(255, 255, 255, 1) : null, + borderRadius: BorderRadius.all(Radius.circular(8.r)), + ), + child: quickText( + '待批阅', + size: 14.sp, + color: state.tabIndex.value == 0 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1), + fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null, + ), + ); + }), + ), + Tab( + iconMargin: EdgeInsets.zero, + height: 34.h, + child: Obx(() { + return Container( + width: 140.w, + alignment: Alignment.center, + decoration: BoxDecoration( + color: state.tabIndex.value == 1 ? const Color.fromRGBO(255, 255, 255, 1) : null, + borderRadius: BorderRadius.all(Radius.circular(8.r)), + ), + child: quickText( + '已批阅', + size: 14.sp, + color: state.tabIndex.value == 1 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1), + fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null, + ), + ); + }), + ), + ], + ), + ), + ), + Expanded( + flex: 1, + child: InkWell( + onTap: () { + Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'}); + }, + child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"), color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp), + ), + ), + ], + ), + ), + Expanded( + child: Obx(() { + return AnnotateList( + tabIndex: state.tabIndex.value, + assessType: 0, + ); + }), + ), + ], + ); + }, + ), + ), + ); + } + + @override + void dispose() { + Get.delete(); + logic.homeController.getList(); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, //状态栏背景颜色 + statusBarIconBrightness: Brightness.light, + systemStatusBarContrastEnforced: false, + )); + super.dispose(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/read_over/widget/annotate_list.dart b/making_school_asignment_app/lib/page/home_page/children/read_over/widget/annotate_list.dart new file mode 100644 index 0000000..ee7eb7f --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/read_over/widget/annotate_list.dart @@ -0,0 +1,518 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/annotate_list_to_refresh.dart'; +import 'package:making_school_asignment_app/common/job/work_student_params.dart'; +import 'package:making_school_asignment_app/common/mixins/event_bus_mixin.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/enum_untils.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/widget/task_list_item.dart'; +import 'package:making_school_asignment_app/page/home_page/children/student_work_detail/widget/job_condition_filter.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:syncfusion_flutter_datepicker/datepicker.dart'; +import 'package:making_school_asignment_app/common/job/work_student.dart'; + +part 'annotate_list.g.dart'; + +class AnnotateList extends StatefulWidget { + final int tabIndex; + final int assessType; + + const AnnotateList( + {super.key, required this.tabIndex, required this.assessType}); + + @override + State createState() => _AnnotateListState(); +} + +class _AnnotateListState extends State + with RequestToolMixin, SingleTickerProviderStateMixin,EventBusMixin{ + late RxString customTimeStr = '自定义'.obs; + int active = 1; + late RxList unAnnotateList = RxList(); + late RxList annotateList = RxList(); + + // late int page = 1; + + late TabController tabController2; + + /* 待阅卷 */ + late final EasyRefreshController refreshController1; + late final EasyRefreshController refreshController2; + WorkStudentParams params = WorkStudentParams( + assessType: 0, + pageSize: 10, + pageNumber: 1, + ); + WorkStudentParams params2 = WorkStudentParams( + assessType: 0, + pageSize: 10, + pageNumber: 1, + startDate: Utils.getWeekStartDate().toString().substring(0, 10), + endDate: Utils.getWeekEndDate().toString().substring(0, 10), + ); + + @override + void initState() { + super.initState(); + params.assessType = widget.assessType; + params2.assessType = widget.assessType; + refreshController1 = EasyRefreshController(); + refreshController2 = EasyRefreshController(); + + eventOn(callback: (e){ + refreshController1.callRefresh(); + }); + tabController2 = TabController(length: 4, vsync: this); + EasyLoading.show(status: 'loading...'); + getUnAnnotateList(); + getAnnotateList(); + } + + @override + void dispose() { + refreshController1.dispose(); + refreshController2.dispose(); + tabController2.dispose(); + eventCancel(); + super.dispose(); + } + +//待批阅列表 + void getUnAnnotateList() async { + WorkStudent data = WorkStudent([], 0); + data = await getClient().getUnAnnotateList(params); + if (params.pageNumber == 1) { + unAnnotateList.value = data.items; + } else { + List list = unAnnotateList.value; + unAnnotateList.value = [...list,...data.items]; + } + refreshController1.finishRefresh(); + refreshController2.finishRefresh(); + EasyLoading.dismiss(); + // print('state.unAnnotateList.length=${unAnnotateList.length}'); + } + +//已批阅列表 + void getAnnotateList() async { + WorkStudent data = WorkStudent([], 0); + data = await getClient().getAnnotatedList(params2); + if (params2.pageNumber == 1) { + annotateList.value = data.items; + } else { + List list = annotateList.value; + annotateList.value = [...list,...data.items]; + } + + refreshController1.finishRefresh(); + refreshController2.finishRefresh(); + EasyLoading.dismiss(); + // print('state.annotateList.length=${annotateList.length}'); + } + + /// 刷新方法 + Future onMyRefresh(EasyRefreshController controller, int tab) async { + /* params.page = RequestConfig.basePage.page; + List lists = await getData(controller, params, isReFresh: true); + try { + tab == 1 ? (markingDatas1 = lists) : (markingDatas2 = lists); + } catch (e) {} + toUpState(setState, () {}, mounted);*/ + if (widget.tabIndex == 0) { + params.pageNumber = 1; + getUnAnnotateList(); + } else { + params2.pageNumber = 1; + getAnnotateList(); + } + } + + Future getCollect(item) async { + await getClient().getCollect(item.id); + if (widget.tabIndex == 0) { + getUnAnnotateList(); + } else { + getAnnotateList(); + } + } + + /// 加载方法 + Future onMyLoad(EasyRefreshController controller, int tab) async { + /*params.page++; + List lists = await getData(controller, params); + if (lists.isNotEmpty) { + tab == 1 ? markingDatas1.addAll(lists) : markingDatas2.addAll(lists); + toUpState(setState, () {}, mounted); + }*/ + if (widget.tabIndex == 0) { + params.pageNumber++; + getUnAnnotateList(); + } else { + params2.pageNumber++; + getAnnotateList(); + } + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + if (widget.tabIndex == 1) + Obx(() { + return JobConditionFilter( + customTimeStr: customTimeStr.value, + controller: tabController2, + hasAll: true, + jobType: 1, + customTime: tabController2.index != 2 || + (params2.startDate == null && params2.endDate == null) + ? null + : PickerDateRange( + params2.startDate == null + ? null + : DateTime.parse(params2.startDate!), + params2.endDate == null + ? null + : DateTime.parse(params2.endDate!), + ), + onTimeFilter: (String? startTime, String? endTime) { + if (startTime == null && + endTime == null && + tabController2.index == 2) { + tabController2.animateTo(0); + params2.endDate = + Utils.getWeekEndDate().toString().substring(0, 10); + params2.startDate = + Utils.getWeekStartDate().toString().substring(0, 10); + customTimeStr.value = '自定义'; + } else { + params2.endDate = endTime; + params2.startDate = startTime; + } + params2.pageNumber = 1; + EasyLoading.show(status: 'loading...'); + if (widget.tabIndex == 0) { + getUnAnnotateList(); + } else { + getAnnotateList(); + } + // refreshController2.callRefresh(); + }, + refreshTime: (value) { + if (value != null && value.startDate != null) { + customTimeStr.value = + value.startDate?.toString().substring(0, 10) ?? ''; + + if (value.endDate != null) { + if (!Utils.isPad() && + value.startDate!.year == value.endDate!.year) { + customTimeStr.value = + '${value.startDate.toString().substring(5, 10)}~${value.endDate.toString().substring(5, 10)}'; + } else { + customTimeStr.value = + '${customTimeStr.value}~${value.endDate?.toString().substring(0, 10)}'; + } + } + } + }); + }), + Expanded( + child: IndexedStack( + index: widget.tabIndex, + children: [ + $EasyRefresh( + controller: refreshController1, + tab: 1, + type: active, + data: unAnnotateList, + onLoad: onMyLoad, + onRefresh: onMyRefresh, + collectFun: getCollect), + $EasyRefresh( + controller: refreshController2, + tab: 2, + type: active, + data: annotateList, + onLoad: onMyLoad, + onRefresh: onMyRefresh, + collectFun: getCollect), + ], + )), + ], + ); + } +} + +/// 已阅卷 +/// OnRefreshCallback? onRefresh +/// +@swidget +Widget $easyRefresh({ + required EasyRefreshController controller, + required Future Function(EasyRefreshController controller, int tab) + onRefresh, + required Future Function(EasyRefreshController controller, int tab) + onLoad, + required List data, + required int tab, + required int type, + required Future Function(Items item) collectFun, +}) { + bool completed = tab == 2; // 是否是待批阅 + bool isPadFlag = Utils.isPad(); + return Obx(() { + return EasyRefresh( + firstRefresh: false, + taskIndependence: true, + /*enableControlFinishLoad: true, + enableControlFinishRefresh: true,*/ + emptyWidget: data.isEmpty ? const MyEmptyWidget() : null, + controller: controller, + header: MaterialHeader(), + // footer: MaterialFooter(), + footer: TaurusFooter(), + child: completed && isPadFlag + ? GridView( + padding: EdgeInsets.only( + top: 11.h, bottom: 10.h, left: 12.w, right: 12.w), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, //横轴三个子widget + mainAxisSpacing: 10.h, + crossAxisSpacing: 6.w, + childAspectRatio: 1.81 //宽高比为1时,子widget + ), + children: List.generate(data.length, (index) { + Items item = data[index]; + String subjectName = EnumUtils.formatSubject(item.subject); + return $reviewedItem( + jobTaskItem: item, + type: type, + subjectName: subjectName, + collectFun: collectFun, + tabIndex: tab - 1); + }), + ) + : ListView.builder( + padding: EdgeInsets.only( + top: 11.h, bottom: 10.h, left: 12.w, right: 12.w), + itemBuilder: (context, index) { + Items item = data[index]; + return TaskListItem( + completed: completed, + jobTaskItem: item, + type: type, + collectFun: collectFun, + tabIndex: tab - 1); + }, + itemCount: data.length, + ), + onRefresh: () => onRefresh(controller, tab), + onLoad: () => onLoad(controller, tab), + ); + }); +} + +@swidget +Widget $reviewedItem({ + required Items jobTaskItem, + required int type, + required int tabIndex, + required String subjectName, + required Future Function(Items item) collectFun, +}) { + EdgeInsets padEdg = EdgeInsets.symmetric(horizontal: 10.w); + + return InkWell( + onTap: () { + Get.toNamed(Routes.annotateClassPage, arguments: { + 'id': jobTaskItem.id, + 'name': jobTaskItem.name, + 'grade': jobTaskItem.grade, + 'subject': jobTaskItem.subject, + 'completed': true, + 'tabIndex': tabIndex + }); + }, + child: Container( + padding: EdgeInsets.only(top: 10.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.r), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(210, 216, 241, 1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 5.8, //阴影模糊程度 + spreadRadius: 0, //阴影扩散程度 + ) + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // 顶部任务名称 + Padding( + padding: padEdg, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 32.w, + height: 18.h, + alignment: Alignment.center, + padding: EdgeInsets.only(left: 2.w), + decoration: BoxDecoration( + color: type == 1 + ? const Color(0xFF4CC793) + : const Color.fromRGBO(255, 175, 56, 1), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(14.r), + topRight: Radius.circular(3.r), + bottomLeft: Radius.circular(4.r), + bottomRight: Radius.circular(4.r), + ), + ), + margin: EdgeInsets.only(top: 3.h, right: 4.w), + child: quickText(type == 1 ? '作业' : '考试', + color: Colors.white, size: 10.sp), + ), + Expanded( + child: quickText(jobTaskItem.name, + size: 14.sp, + color: const Color.fromRGBO(70, 70, 70, 1), + maxLines: 2), + ), + if (jobTaskItem.isFixed!) + Padding( + padding: EdgeInsets.only(top: 3.r), + child: Text( + '已订正', + style: TextStyle( + fontSize: 10.sp, color: const Color(0xFFF16262)), + ), + ), + ], + ), + ), + + Padding( + padding: padEdg, + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + quickText( + DateTime.parse(jobTaskItem.publishTime) + .toString() + .substring(0, 10), + color: const Color.fromRGBO(97, 97, 97, 1), + size: 10.sp, + fontWeight: FontWeight.w500, + ), + quickText(' / ', + color: const Color.fromRGBO(76, 199, 147, 1), + size: 10.sp, + fontWeight: FontWeight.w500), + quickText( + '参与班级:', + color: const Color.fromRGBO(76, 199, 147, 1), + size: 9.sp, + ), + quickText( + '${jobTaskItem.classCount}', + color: const Color.fromRGBO(76, 199, 147, 1), + size: 10.sp, + ), + quickText(' / ', + color: const Color.fromRGBO(116, 145, 253, 1), + size: 10.sp, + fontWeight: FontWeight.w500), + quickText( + '科目:$subjectName', + color: const Color.fromRGBO(116, 145, 253, 1), + size: 9.sp, + ), + ], + ), + ), + /*Padding( + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: FavoriteButton( + jobTaskItem.id, + jobTaskItem.title, + margin: EdgeInsets.only(top: 4.h, bottom: 6.h), + ), + ),*/ + Container( + padding: EdgeInsets.symmetric(vertical: 6.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(6.r), + bottomRight: Radius.circular(6.r)), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.15), + offset: Offset(0, -0.0001), //阴影y轴偏移量 + blurRadius: 4, //阴影模糊程度 + spreadRadius: 0, //阴影扩散程度 + ) + ], + ), + child: Row(children: [ + if (!jobTaskItem.isFixed!) + Expanded( + flex: 1, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + if (!jobTaskItem.isFixed!) { + EasyLoading.show(status: 'loading...'); + collectFun(jobTaskItem); + } + }, + child: Container( + alignment: Alignment.center, + decoration: BoxDecoration( + border: Border( + right: BorderSide( + width: 1.r, color: const Color(0xFFDCDCDC))), + ), + child: quickText('收集订正', + color: const Color(0xFF4CC793), size: 11.sp), + ), + ), + ), + Expanded( + flex: 1, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + Get.toNamed(Routes.jobReportPage, arguments: { + 'title': jobTaskItem.name, + 'homeworkId': jobTaskItem.id, + 'grade': jobTaskItem.grade + }); + }, + child: Container( + alignment: Alignment.center, + child: quickText('查看报告', + color: const Color.fromRGBO(118, 118, 118, 1), + size: 11.sp), + ), + ), + ), + ]), + ), + ], + ), + ), + ); +} diff --git a/making_school_asignment_app/lib/page/home_page/children/read_over/widget/task_list_item.dart b/making_school_asignment_app/lib/page/home_page/children/read_over/widget/task_list_item.dart new file mode 100644 index 0000000..db0a13d --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/read_over/widget/task_list_item.dart @@ -0,0 +1,327 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +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/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/enum_untils.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/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/read_over_logic.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +class TaskListItem extends StatefulWidget { + final bool completed; + final Items jobTaskItem; + final int type; + final int tabIndex; + final Function(Items item) collectFun; + + const TaskListItem({Key? key, required this.completed, required this.jobTaskItem, required this.type, required this.collectFun, required this.tabIndex}) : super(key: key); + + @override + State createState() => _TaskListItemState(); +} + +class _TaskListItemState extends State { + @override + Widget build(BuildContext context) { + return widget.completed + ? InkWell( + onTap: () { + Get.toNamed(Routes.annotateClassPage, arguments: {'id': widget.jobTaskItem.id, 'name': widget.jobTaskItem.name, 'grade': widget.jobTaskItem.grade, 'subject': widget.jobTaskItem.subject, 'completed': true, 'tabIndex': widget.tabIndex}); + }, + child: Container( + width: double.infinity, + padding: EdgeInsets.only(top: 20.h), + margin: EdgeInsets.only(bottom: 12.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.r), + color: const Color.fromRGBO(255, 255, 255, 1), + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(210, 216, 241, 1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 5.8, //阴影模糊程度 + spreadRadius: 0, //阴影扩散程度 + ) + ], + ), + child: Column( + children: [ + // 顶部任务名称 + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: Utils.isPad() ? 32.w : 36.w, + height: 18.h, + alignment: Alignment.center, + padding: EdgeInsets.only(left: Utils.isPad() ? 2.w : 3.w), + decoration: BoxDecoration( + color: const Color(0xFFB2DA93), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(14.r), + topRight: Radius.circular(3.r), + bottomLeft: Radius.circular(4.r), + bottomRight: Radius.circular(4.r), + ), + ), + margin: EdgeInsets.only(right: 4.w), + child: quickText(widget.jobTaskItem.assessType == 0 ? '作业' : '考试', color: Colors.white, size: 10.sp), + ), + Expanded( + child: quickText( + widget.jobTaskItem.name, + maxLines: 2, + size: 16.sp, + color: const Color.fromRGBO(70, 70, 70, 1), + fontWeight: FontWeight.bold, + ), + ) + ], + ), + ), + + SizedBox(height: 12.h), + Padding( + padding: EdgeInsets.symmetric(horizontal: 10.w), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + quickText( + DateTime.parse(widget.jobTaskItem.publishTime).toString().substring(0, 10), + color: const Color.fromRGBO(97, 97, 97, 1), + size: 12.sp, + fontWeight: FontWeight.w500, + ), + quickText(' / ', color: const Color.fromRGBO(76, 199, 147, 1), size: 12.sp, fontWeight: FontWeight.w500), + quickText( + '参与班级:${widget.jobTaskItem.classCount}', + color: const Color.fromRGBO(76, 199, 147, 1), + size: 12.sp, + fontWeight: FontWeight.w600, + ), + quickText(' / ', color: const Color.fromRGBO(116, 145, 253, 1), size: 12.sp, fontWeight: FontWeight.w500), + quickText( + '科目:${EnumUtils.formatSubject(widget.jobTaskItem.subject)}', + color: const Color.fromRGBO(116, 145, 253, 1), + size: 12.sp, + fontWeight: FontWeight.w600, + ), + const Expanded(child: SizedBox()), + /* FavoriteButton( + jobTaskItem.id, + jobTaskItem.title, + margin: EdgeInsets.zero, + isRow: false, + ),*/ + ], + ), + ), + + SizedBox(height: 20.h), + Container( + padding: EdgeInsets.symmetric(vertical: 10.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.only(bottomLeft: Radius.circular(6.r), bottomRight: Radius.circular(6.r)), + color: Colors.white, + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(0, 0, 0, 0.15), + offset: Offset(0, -0.0001), //阴影y轴偏移量 + blurRadius: 4, //阴影模糊程度 + spreadRadius: 0, //阴影扩散程度 + ) + ], + ), + child: Row(children: [ + Expanded( + child: InkWell( + onTap: () { + Get.toNamed(Routes.jobReportPage, arguments: { + 'title': widget.jobTaskItem.name, + 'homeworkId': widget.jobTaskItem.id, + 'grade': widget.jobTaskItem.grade, + }); + }, + child: Container( + alignment: Alignment.center, + child: quickText('查看报告', color: const Color.fromRGBO(118, 118, 118, 1), size: 13.sp), + ), + )), + ]), + ), + ], + ), + ), + ) + : Padding( + padding: EdgeInsets.only(top: 10.r), + child: InkWell( + onTap: () { + Get.toNamed(Routes.annotateClassPage, arguments: {'id': widget.jobTaskItem.id, 'name': widget.jobTaskItem.name, 'grade': widget.jobTaskItem.grade, 'subject': widget.jobTaskItem.subject, 'tabIndex': widget.tabIndex}); + }, + child: Container( + margin: EdgeInsets.only(bottom: 16.h), + width: Get.width, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.r), + color: const Color.fromRGBO(255, 255, 255, 1), + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(210, 216, 241, 1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 5.8, //阴影模糊程度 + spreadRadius: 0, //阴影扩散程度 + ) + ], + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: Utils.isPad() ? 32.w : 38.w, + height: 18.h, + alignment: Alignment.center, + padding: EdgeInsets.only(left: Utils.isPad() ? 2.w : 3.w), + decoration: BoxDecoration( + color: widget.type == 1 ? const Color(0xFFB2DA93) : const Color(0xFFEF8714), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(6.r), + topRight: Radius.circular(0.r), + bottomLeft: Radius.circular(0.r), + bottomRight: Radius.circular(12.r), + ), + ), + margin: EdgeInsets.only(top: 0.h, right: 4.w), + child: quickText(widget.jobTaskItem.assessType == 0 ? '作业' : '考试', color: Colors.white, size: 10.sp), + ), + Expanded( + child: Padding( + padding: EdgeInsets.only(top: 2.r), + child: quickText( + widget.jobTaskItem.name, + maxLines: 2, + size: Utils.isPad() ? 14.sp : 16.sp, + color: const Color.fromRGBO(70, 70, 70, 1), + fontWeight: FontWeight.bold, + ), + ), + ) + ], + ), + SizedBox(height: 10.h), + Padding( + padding: EdgeInsets.only(left: 20.r), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + quickText( + EnumUtils.formatSubject(widget.jobTaskItem.subject), + color: const Color.fromRGBO(97, 97, 97, 1), + size: 12.sp, + ), + quickText(' / ', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp, fontWeight: FontWeight.w500), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + quickText('题量:', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp), + quickText( + '${widget.jobTaskItem.questionCount! - widget.jobTaskItem.annotateCount!}', + color: const Color.fromRGBO(97, 97, 97, 1), + size: 13.sp, + ), + ], + ), + quickText(' / ', color: const Color.fromRGBO(130, 130, 130, 1), size: 11.sp, fontWeight: FontWeight.w500), + quickText(DateTime.parse(widget.jobTaskItem.publishTime).toString().substring(0, 10), color: const Color.fromRGBO(97, 97, 97, 1), size: 12.sp), + ], + ), + ), + SizedBox(height: 10.h), + InkWell( + onTap: () { + if (!widget.jobTaskItem.isFixed!) { + EasyLoading.show(status: 'loading...'); + widget.collectFun(widget.jobTaskItem); + } + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 4.r, horizontal: 20.r), + margin: EdgeInsets.only(left: 20.r), + decoration: BoxDecoration( + color: widget.jobTaskItem.isFixed! ? Color(0xFFF4F4F4) : Color(0xFFF2EEFF), + border: Border.all(width: 1.r, color: widget.jobTaskItem.isFixed! ? Colors.transparent : const Color(0xFF8C68FF)), + borderRadius: BorderRadius.all(Radius.circular(20.r)), + ), + child: Text( + widget.jobTaskItem.isFixed! ? '已订正' : '收集订正', + style: TextStyle(fontSize: 10.sp, color: widget.jobTaskItem.isFixed! ? const Color(0xFFF16262) : const Color(0xFF8C68FF)), + ), + ), + ), + // FavoriteButton(jobTaskItem.id, jobTaskItem.title), + ], + ), + ), + SizedBox( + width: 10.r, + ), + Container( + padding: EdgeInsets.symmetric(vertical: 10.r, horizontal: 9.r), + decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.white), + child: CircularPercentIndicator( + radius: 50.r, + lineWidth: 10.r, + animation: true, + reverse: true, + percent: widget.jobTaskItem.annotateRate == null ? 0 : widget.jobTaskItem.annotateRate! / 100, + center: Text.rich(TextSpan(children: [ + TextSpan( + text: Utils.getDoubleRemoveZero(widget.jobTaskItem.annotateRate, '0'), + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16.sp, + color: Theme.of(context).primaryColor, + ), + ), + TextSpan( + text: "%", + style: TextStyle(color: Theme.of(context).primaryColor, fontSize: 12.sp, fontWeight: FontWeight.bold), + ), + ])), + circularStrokeCap: CircularStrokeCap.round, + // progressColor: Theme.of(context).primaryColor, + linearGradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + tileMode: TileMode.clamp, + stops: const [0.0, 1.0], + colors: [ + Theme.of(context).primaryColor.withOpacity(0.1), + Theme.of(context).primaryColor, + ], + ), + backgroundColor: const Color.fromRGBO(244, 244, 244, 1), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/page/home_page/children/read_over/widget/top_user_info.dart b/making_school_asignment_app/lib/page/home_page/children/read_over/widget/top_user_info.dart similarity index 79% rename from lib/page/home_page/children/read_over/widget/top_user_info.dart rename to making_school_asignment_app/lib/page/home_page/children/read_over/widget/top_user_info.dart index 64fd320..16e188c 100644 --- a/lib/page/home_page/children/read_over/widget/top_user_info.dart +++ b/making_school_asignment_app/lib/page/home_page/children/read_over/widget/top_user_info.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/page/home_page/home_logic.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/page/home_page/home_logic.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; class TopUserInfo extends StatelessWidget { TopUserInfo({Key? key}) : super(key: key); @@ -16,11 +16,7 @@ class TopUserInfo extends StatelessWidget { }, child: Container( color: Colors.white, - padding: EdgeInsets.only( - top: MediaQuery.of(context).padding.top + 4.h, - left: 14.w, - right: 14.w, - bottom: 19.h), + padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top + 4.h, left: 14.w, right: 14.w, bottom: 19.h), child: Row( children: [ Container( @@ -38,17 +34,14 @@ class TopUserInfo extends StatelessWidget { alignment: Alignment.center, color: const Color.fromRGBO(163, 211, 255, 1), padding: EdgeInsets.all(1.r), - child: Image.asset('assets/images/login_logo.png', - width: 32.w, height: 32.w), + child: Image.asset('assets/images/login_logo_icon.png', width: 32.w, height: 32.w), ), ), Container( margin: EdgeInsets.only(left: 10.h), child: Text( state.userInfo.value!.givenname, - style: TextStyle( - fontSize: 15.sp, - color: const Color.fromRGBO(45, 56, 76, 0.9)), + style: TextStyle(fontSize: 15.sp, color: const Color.fromRGBO(45, 56, 76, 0.9)), ), ), Container( diff --git a/lib/page/home_page/children/student_history_work/student_history_work_binding.dart b/making_school_asignment_app/lib/page/home_page/children/student_history_work/student_history_work_binding.dart similarity index 100% rename from lib/page/home_page/children/student_history_work/student_history_work_binding.dart rename to making_school_asignment_app/lib/page/home_page/children/student_history_work/student_history_work_binding.dart diff --git a/lib/page/home_page/children/student_history_work/student_history_work_logic.dart b/making_school_asignment_app/lib/page/home_page/children/student_history_work/student_history_work_logic.dart similarity index 59% rename from lib/page/home_page/children/student_history_work/student_history_work_logic.dart rename to making_school_asignment_app/lib/page/home_page/children/student_history_work/student_history_work_logic.dart index d218e59..3c1f983 100644 --- a/lib/page/home_page/children/student_history_work/student_history_work_logic.dart +++ b/making_school_asignment_app/lib/page/home_page/children/student_history_work/student_history_work_logic.dart @@ -2,9 +2,9 @@ import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; -import 'package:school_asignment_app/common/job/class_item.dart'; -import 'package:school_asignment_app/common/mixins/request_tool_mixin.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/job/class_item.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; import 'student_history_work_state.dart'; @@ -15,7 +15,7 @@ class StudentHistoryWorkLogic extends GetxController with RequestToolMixin { @override void onInit() { super.onInit(); - nextPage = Get.arguments['page']??''; + nextPage = Get.arguments['page'] ?? ''; EasyLoading.show(status: 'loading...'); refreshController = EasyRefreshController(); getList(); @@ -28,8 +28,13 @@ class StudentHistoryWorkLogic extends GetxController with RequestToolMixin { refreshController.finishRefresh(); } - void goNextPage(String id,String title,int subject) { - Get.toNamed(Routes.classStudentPage,arguments: {'title':title,'classId':id,'page':nextPage,'subject':subject}); + void goNextPage(String id, String title, int subject) { + if(nextPage == 'points'){ + Get.toNamed(Routes.knowledgePointsGraspPage, arguments: {'classId': id, 'page': nextPage, 'subject': subject}); + }else{ + Get.toNamed(Routes.classStudentPage, arguments: {'title': title, 'classId': id, 'page': nextPage, 'subject': subject}); + } + } @override diff --git a/lib/page/home_page/children/student_history_work/student_history_work_state.dart b/making_school_asignment_app/lib/page/home_page/children/student_history_work/student_history_work_state.dart similarity index 70% rename from lib/page/home_page/children/student_history_work/student_history_work_state.dart rename to making_school_asignment_app/lib/page/home_page/children/student_history_work/student_history_work_state.dart index e7dd14d..6beac18 100644 --- a/lib/page/home_page/children/student_history_work/student_history_work_state.dart +++ b/making_school_asignment_app/lib/page/home_page/children/student_history_work/student_history_work_state.dart @@ -1,5 +1,5 @@ import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/class_item.dart'; +import 'package:making_school_asignment_app/common/job/class_item.dart'; class StudentHistoryWorkState { StudentHistoryWorkState() { diff --git a/making_school_asignment_app/lib/page/home_page/children/student_history_work/student_history_work_view.dart b/making_school_asignment_app/lib/page/home_page/children/student_history_work/student_history_work_view.dart new file mode 100644 index 0000000..2de48e1 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/student_history_work/student_history_work_view.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; +import 'package:making_school_asignment_app/page/home_page/widget/student_group_list.dart'; + +import 'student_history_work_logic.dart'; + +class StudentHistoryWorkPage extends StatefulWidget { + const StudentHistoryWorkPage({Key? key}) : super(key: key); + + @override + State createState() => _StudentHistoryWorkPageState(); +} + +class _StudentHistoryWorkPageState extends State { + final logic = Get.find(); + final state = Get.find().state; + + @override + Widget build(BuildContext context) { + return OrientationBuilder( + builder: (BuildContext context, Orientation orientation){ + return Scaffold( + backgroundColor: const Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + backgroundColor: Colors.white, + title: Text( + '我的班级 ', + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF333333)), + ), + centerTitle: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Get.back(), + ), + actions: const [ + ReturnToHomepage(), + ], + ), + body: Padding( + padding: EdgeInsets.only(top: 15.r, left: 14.r, right: 14.r), + child: EasyRefresh( + firstRefresh: false, + taskIndependence: true, + controller: logic.refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + logic.getList(); + }, + child: StudentGroupList(state.clssList, logic.goNextPage), + ), + ), + ); + }); + + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} diff --git a/lib/page/home_page/children/student_personal/student_personal_binding.dart b/making_school_asignment_app/lib/page/home_page/children/student_personal/student_personal_binding.dart similarity index 100% rename from lib/page/home_page/children/student_personal/student_personal_binding.dart rename to making_school_asignment_app/lib/page/home_page/children/student_personal/student_personal_binding.dart diff --git a/making_school_asignment_app/lib/page/home_page/children/student_personal/student_personal_logic.dart b/making_school_asignment_app/lib/page/home_page/children/student_personal/student_personal_logic.dart new file mode 100644 index 0000000..4120d9d --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/student_personal/student_personal_logic.dart @@ -0,0 +1,45 @@ +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/student_personal_info.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; + +import 'student_personal_state.dart'; + +class StudentPersonalLogic extends GetxController with RequestToolMixin { + final StudentPersonalState state = StudentPersonalState(); + + @override + void onInit() { + super.onInit(); + state.studentId = Get.arguments['studentId']; + state.subject = Get.arguments['subject'] ?? -1; + state.homeworkId = Get.arguments['homeworkId']; + getInfo(); + } + + void getInfo() async { + StudentPersonalInfo data = await getClient().getStudentHomework(state.homeworkId, state.studentId); + data.kgtList.sort((a, b) { + try { + if (RegExp(r'^\d*\.?\d+$').hasMatch(a.questionNo) && RegExp(r'^\d*\.?\d+$').hasMatch(b.questionNo)) { + return num.parse(a.questionNo).compareTo(num.parse(b.questionNo)); + } else { + throw Exception(); + } + } catch (e) { + return a.questionNo.toLowerCase().compareTo(b.questionNo.toLowerCase()); + } + }); + data.zgtList.sort((a, b) { + try { + if (RegExp(r'^\d*\.?\d+$').hasMatch(a.questionNo) && RegExp(r'^\d*\.?\d+$').hasMatch(b.questionNo)) { + return num.parse(a.questionNo).compareTo(num.parse(b.questionNo)); + } else { + throw Exception(); + } + } catch (e) { + return a.questionNo.toLowerCase().compareTo(b.questionNo.toLowerCase()); + } + }); + state.studentInfo.value = data; + } +} diff --git a/lib/page/home_page/children/student_personal/student_personal_state.dart b/making_school_asignment_app/lib/page/home_page/children/student_personal/student_personal_state.dart similarity index 52% rename from lib/page/home_page/children/student_personal/student_personal_state.dart rename to making_school_asignment_app/lib/page/home_page/children/student_personal/student_personal_state.dart index 89b4b56..3c8735e 100644 --- a/lib/page/home_page/children/student_personal/student_personal_state.dart +++ b/making_school_asignment_app/lib/page/home_page/children/student_personal/student_personal_state.dart @@ -1,13 +1,13 @@ import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/common/job/student_personal_info.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/common/job/student_personal_info.dart'; class StudentPersonalState { StudentPersonalState() { ///Initialize variables } - late Rx studentInfo = Rx(StudentPersonalInfo(0,'',0,0,[],0,[])); + late Rx studentInfo = Rx(StudentPersonalInfo(0, '', 0, 0, [], 0, [])); late int studentId; + late int subject; late String homeworkId; - } diff --git a/making_school_asignment_app/lib/page/home_page/children/student_personal/student_personal_view.dart b/making_school_asignment_app/lib/page/home_page/children/student_personal/student_personal_view.dart new file mode 100644 index 0000000..faa4a47 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/student_personal/student_personal_view.dart @@ -0,0 +1,221 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.dart'; +import 'package:making_school_asignment_app/page/home_page/children/homework_review/components/original_manuscript_handwriting/answer_handwriting_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/student_personal/widget/student_kg_table.dart'; +import 'package:making_school_asignment_app/page/home_page/children/student_personal/widget/student_zg_table.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'student_personal_logic.dart'; + +class StudentPersonalPage extends StatefulWidget { + const StudentPersonalPage({super.key}); + + @override + State createState() => _StudentPersonalPageState(); +} + +class _StudentPersonalPageState extends State { + final logic = Get.find(); + final state = Get.find().state; + + @override + Widget build(BuildContext context) { + return OrientationBuilder(builder: (BuildContext context, Orientation orientation) { + return Scaffold( + backgroundColor: const Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + backgroundColor: Colors.white, + title: Obx(() { + return Text( + state.studentInfo.value.studentName, + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF000000)), + ); + }), + centerTitle: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Get.back(), + ), + actions: const [ + ReturnToHomepage(), + ], + ), + body: SingleChildScrollView( + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(top: 14.r, left: 14.r), + child: Row( + children: [ + InkWell( + onTap: () { + // RouterManager.router.navigateTo(context, + // '${RouterManager.jobPersonalDetailPath}?studentId=${widget.studentId}&studentName=${Uri.encodeComponent(state.studentInfo.studentName!)}'); + Get.toNamed(Routes.studentWorkDetailPage, arguments: { + 'studentId': state.studentInfo.value.studentId, + 'studentName': state.studentInfo.value.studentName, + 'subject': state.subject + }); + }, + child: Container( + width: 93.r, + height: 28.r, + decoration: BoxDecoration( + color: const Color(0xFFEAF3FF), + borderRadius: BorderRadius.circular(4.r), + ), + child: Center( + child: Text( + '历史作业', + style: TextStyle(fontSize: 10.r, color: const Color(0xFF2080F7)), + ), + ), + ), + ), + SizedBox( + width: 10.r, + ), + InkWell( + onTap: () => + showAnswerHandwriting(context, homeworkId: state.homeworkId, studentId: state.studentId).then((e) => ToastUtils.dismiss()), + child: Container( + width: 93.r, + height: 28.r, + decoration: BoxDecoration( + color: const Color(0xFFEDFFF7), + borderRadius: BorderRadius.circular(4.r), + ), + child: Center( + child: Text( + '原稿笔迹', + style: TextStyle(fontSize: 10.r, color: const Color(0xFF4CC793)), + ), + ), + ), + ), + ], + ), + ), + //客观题 + Container( + padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 10.r), + margin: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(6.r)), + ), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + '客观题', + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF5C5C5C), fontWeight: FontWeight.w600), + ), + SizedBox( + width: 10.r, + ), + Obx(() { + return Text( + '${state.studentInfo.value.kgtCorrectRate}%', + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF4CC793), fontWeight: FontWeight.w600), + ); + }), + ], + ), + SizedBox( + height: 10.r, + ), + Obx(() { + return SizedBox( + height: state.studentInfo.value.kgtList.length > 8 ? 300.r : state.studentInfo.value.kgtList.length * 40.r + 40.r, + child: StudentKgTable( + headList: const ['题号', '学生答案', '标准答案'], + bodyList: state.studentInfo.value.kgtList, + questionNumCall: (questionNo, templateId) { + showAnswerHandwriting(context, + homeworkId: state.homeworkId, studentId: state.studentId, questionNo: questionNo, templateId: templateId) + .then((e) => ToastUtils.dismiss()); + // showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId, questionNo: int.parse(no)).then((value) { + // ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); + // }); + }, + ), + ); + }) + ], + ), + ), + SizedBox( + height: 15.r, + ), + //主观题 + Container( + padding: EdgeInsets.symmetric(vertical: 14.r, horizontal: 10.r), + margin: EdgeInsets.symmetric(vertical: 14.r, horizontal: 14.r), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(6.r)), + ), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + '主观题', + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF5C5C5C), fontWeight: FontWeight.w600), + ), + SizedBox( + width: 10.r, + ), + Obx(() { + return Text( + '${state.studentInfo.value.zgtCorrectRate}%', + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF4CC793), fontWeight: FontWeight.w600), + ); + }), + ], + ), + SizedBox( + height: 10.r, + ), + Obx(() { + return SizedBox( + height: state.studentInfo.value.zgtList.length > 8 ? 300.r : state.studentInfo.value.zgtList.length * 40.r + 40.r, + child: StudentZgTable( + headList: const ['题号', '用时', '批注结果', '答案'], + bodyList: state.studentInfo.value.zgtList, + questionNumCall: (questionNo, templateId) { + /* showAnswerHandwriting(context, jobId: widget.jobId, studentId: widget.studentId, questionNo: int.parse(no)).then((value) { + ref.read(jobHandwritingDrawingTrajectoryProvider.notifier).setVal([]); + });*/ + showAnswerHandwriting(context, + homeworkId: state.homeworkId, studentId: state.studentId, questionNo: questionNo, templateId: templateId) + .then((e) => ToastUtils.dismiss()); + }, + ), + ); + }) + ], + ), + ), + ], + ), + ), + ); + }); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} diff --git a/lib/page/home_page/children/student_personal/widget/student_kg_table.dart b/making_school_asignment_app/lib/page/home_page/children/student_personal/widget/student_kg_table.dart similarity index 92% rename from lib/page/home_page/children/student_personal/widget/student_kg_table.dart rename to making_school_asignment_app/lib/page/home_page/children/student_personal/widget/student_kg_table.dart index 5d129eb..bc2efa9 100644 --- a/lib/page/home_page/children/student_personal/widget/student_kg_table.dart +++ b/making_school_asignment_app/lib/page/home_page/children/student_personal/widget/student_kg_table.dart @@ -1,15 +1,15 @@ import 'package:data_table_2/data_table_2.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/common/job/student_personal_info.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/common/job/student_personal_info.dart'; class StudentKgTable extends StatefulWidget { final List headList; final List bodyList; final int? fixedRows; final int? fixedCols; - final Function(String)? questionNumCall; + final Function(String, int)? questionNumCall; const StudentKgTable({ Key? key, @@ -44,13 +44,13 @@ class _StudentKgTableState extends State { InkWell( onTap: () { if (widget.questionNumCall != null) { - widget.questionNumCall!(item.questionNo.toString()); + widget.questionNumCall!(item.questionNo, item.templateId); } }, child: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.questionNo.toString(), style: TextStyle(fontSize: 12.sp, color: Color(0xFF6888FD))), + child: Text(item.questionNo.toString(), style: TextStyle(fontSize: 12.sp, color: Color(0xFF4CC793))), ), ), ), diff --git a/lib/page/home_page/children/student_personal/widget/student_zg_table.dart b/making_school_asignment_app/lib/page/home_page/children/student_personal/widget/student_zg_table.dart similarity index 71% rename from lib/page/home_page/children/student_personal/widget/student_zg_table.dart rename to making_school_asignment_app/lib/page/home_page/children/student_personal/widget/student_zg_table.dart index cdcc303..ba519fa 100644 --- a/lib/page/home_page/children/student_personal/widget/student_zg_table.dart +++ b/making_school_asignment_app/lib/page/home_page/children/student_personal/widget/student_zg_table.dart @@ -1,17 +1,17 @@ import 'package:data_table_2/data_table_2.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:school_asignment_app/common/job/homework_details.dart'; -import 'package:school_asignment_app/common/job/student_personal_info.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/imgDialog.dart'; +import 'package:making_school_asignment_app/common/job/homework_details.dart'; +import 'package:making_school_asignment_app/common/job/student_personal_info.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/imgDialog.dart'; class StudentZgTable extends StatefulWidget { final List headList; final List bodyList; final int? fixedRows; final int? fixedCols; - final Function(String)? questionNumCall; + final Function(String, int)? questionNumCall; const StudentZgTable({ Key? key, @@ -41,22 +41,20 @@ class _StudentZgTableState extends State { DataCell(InkWell( onTap: () { if (widget.questionNumCall != null) { - widget.questionNumCall!(item.questionNo.toString()); + widget.questionNumCall!(item.questionNo, item.templateId); } }, child: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(item.questionNo.toString(), - style: TextStyle(fontSize: 12.sp, color: Color(0xFF6888FD))), + child: Text(item.questionNo.toString(), style: TextStyle(fontSize: 12.sp, color: Color(0xFF4CC793))), ), ), )), DataCell(Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text(Utils.second2HMS(item.useTime!), - style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), + child: Text(Utils.second2HMS(item.useTime!), style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))), ), )), /* DataCell(InkWell( @@ -76,8 +74,7 @@ class _StudentZgTableState extends State { child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), child: item.isCorrect == null - ? Text('', - style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))) + ? Text('', style: TextStyle(fontSize: 12.sp, color: Color(0xFF525252))) : item.isCorrect! ? Image.asset( 'assets/images/job_personal_correct_icon.png', @@ -98,8 +95,7 @@ class _StudentZgTableState extends State { child: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 5.r), - child: Text('查看', - style: TextStyle(fontSize: 12.sp, color: Color(0xFF3661FE))), + child: Text('查看', style: TextStyle(fontSize: 12.sp, color: Color(0xFF3661FE))), ), ), )), @@ -118,14 +114,10 @@ class _StudentZgTableState extends State { headingRowHeight: 40.r, dataRowHeight: 40.r, border: TableBorder( - horizontalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - bottom: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid), - verticalInside: BorderSide( - width: 1, color: Colors.white, style: BorderStyle.solid)), - headingRowColor: MaterialStateProperty.resolveWith((states) => - widget.fixedCols! > 0 ? Colors.white : Colors.transparent), + horizontalInside: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid), + bottom: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid), + verticalInside: BorderSide(width: 1, color: Colors.white, style: BorderStyle.solid)), + headingRowColor: MaterialStateProperty.resolveWith((states) => widget.fixedCols! > 0 ? Colors.white : Colors.transparent), headingRowDecoration: BoxDecoration(color: Color(0xFFE6E6E6)), fixedColumnsColor: Color(0xFFE6E6E6), fixedCornerColor: Colors.grey[400], @@ -139,14 +131,12 @@ class _StudentZgTableState extends State { var item = widget.headList[index]; return DataColumn2( label: Center( - child: Text(item, - style: TextStyle(fontSize: 12.sp, color: Color(0xFF505767))), + child: Text(item, style: TextStyle(fontSize: 12.sp, color: Color(0xFF505767))), ), // size: ColumnSize.S, fixedWidth: (MediaQuery.of(context).size.width - 20.r - 28.r) / 4, ); }), - rows: List.generate(widget.bodyList.length, - (index) => _getRow(index, Color(0xFFF5F5F5)))); + rows: List.generate(widget.bodyList.length, (index) => _getRow(index, Color(0xFFF5F5F5)))); } } diff --git a/lib/page/home_page/children/student_work_detail/student_work_detail_binding.dart b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/student_work_detail_binding.dart similarity index 100% rename from lib/page/home_page/children/student_work_detail/student_work_detail_binding.dart rename to making_school_asignment_app/lib/page/home_page/children/student_work_detail/student_work_detail_binding.dart diff --git a/making_school_asignment_app/lib/page/home_page/children/student_work_detail/student_work_detail_logic.dart b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/student_work_detail_logic.dart new file mode 100644 index 0000000..ee13754 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/student_work_detail_logic.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:get/get.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/mixins/request_tool_mixin.dart'; + +import 'student_work_detail_state.dart'; + +class StudentWorkDetailLogic extends GetxController with RequestToolMixin, GetSingleTickerProviderStateMixin { + final StudentWorkDetailState state = StudentWorkDetailState(); + late TabController tabController; + late final EasyRefreshController refreshController; + + @override + void onInit() { + super.onInit(); + state.studentName.value = Get.arguments['studentName'] ?? ''; + state.studentId = Get.arguments['studentId'] ?? -1; + state.subject = Get.arguments['subject'] ?? -1; + tabController = TabController(length: 3, vsync: this); + refreshController = EasyRefreshController(); + EasyLoading.show(status: 'loading...'); + getList(); + } + + void getList() async { + StudentHistoryParams params = StudentHistoryParams( + assessType: state.isJob.value ? 0 : 1, + studentId: state.studentId, + dateStart: state.dateStart, + dateEnd: state.dateEnd, + subject: state.subject, + pageNumber: state.page, + pageSize: 10, + ); + StudentHistory data = await getClient().getStudentHistory(params); + data.items.items.forEach((e) { + e.kgtList.sort((a, b) { + try { + if (RegExp(r'^\d*\.?\d+$').hasMatch(a.questionNo) && RegExp(r'^\d*\.?\d+$').hasMatch(b.questionNo)) { + return num.parse(a.questionNo).compareTo(num.parse(b.questionNo)); + } else { + throw Exception(); + } + } catch (e) { + return a.questionNo.toLowerCase().compareTo(b.questionNo.toLowerCase()); + } + }); + e.zgtList.sort((a, b) { + try { + if (RegExp(r'^\d*\.?\d+$').hasMatch(a.questionNo) && RegExp(r'^\d*\.?\d+$').hasMatch(b.questionNo)) { + return num.parse(a.questionNo).compareTo(num.parse(b.questionNo)); + } else { + throw Exception(); + } + } catch (e) { + return a.questionNo.toLowerCase().compareTo(b.questionNo.toLowerCase()); + } + }); + }); + state.studentData.value = data; + /* state.kgtLine.value = [{'id':0,'rate':0}]; + state.zgtLine.value = [{'id':0,'rate':0}]; + state.allLine.value = [{'id':0,'rate':0}];*/ + state.kgtLine.value = []; + state.zgtLine.value = []; + state.allLine.value = []; + for (var i = 0; i < state.studentData.value.items.items.length; i++) { + var element = state.studentData.value.items.items[i]; + int num = 0; + for (var item in element.kgtList) { + if (item.state == 0) { + num = num + 1; + } + } + for (var subject in element.zgtList) { + if (subject.state == 0) { + num = num + 1; + } + } + if (num == (element.kgtList.length + element.zgtList.length)) { + element.allNotDone = true; + } + + state.kgtLine.add({'id': i + 1, 'rate': (element.kgtCorrectRate / 100 * 5).toStringAsFixed(2)}); + state.zgtLine.add({'id': i + 1, 'rate': (element.zgtCorrectRate / 100 * 5).toStringAsFixed(2)}); + state.allLine.add({'id': i + 1, 'rate': (element.correctRate / 100 * 5).toStringAsFixed(2)}); + } + + EasyLoading.dismiss(); + } + + @override + void dispose() { + super.dispose(); + tabController.dispose(); + refreshController.dispose(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/children/student_work_detail/student_work_detail_state.dart b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/student_work_detail_state.dart new file mode 100644 index 0000000..f7a9b80 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/student_work_detail_state.dart @@ -0,0 +1,23 @@ +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/student_history.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; + +class StudentWorkDetailState { + StudentWorkDetailState() { + ///Initialize variables + } + + late RxString studentName = ''.obs; + late int studentId = -1; + late RxBool isJob = true.obs; + late int page = 1; + late int totalPages = 0; + late String dateStart = Utils.getWeekStartDate().toString().substring(0, 10); + late String dateEnd = Utils.getWeekEndDate().toString().substring(0, 10); + late RxString customTimeStr = '自定义'.obs; + late Rx studentData = Rx(StudentHistory(0, 0, Items([], 0), 0)); + late final int subject; + late RxList kgtLine = [].obs; + late RxList zgtLine = [].obs; + late RxList allLine = [].obs; +} diff --git a/making_school_asignment_app/lib/page/home_page/children/student_work_detail/student_work_detail_view.dart b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/student_work_detail_view.dart new file mode 100644 index 0000000..09492cb --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/student_work_detail_view.dart @@ -0,0 +1,618 @@ +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/student_history.dart'; +import 'package:making_school_asignment_app/common/utils/enum_untils.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/ReturnToHomepage.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/page/home_page/children/student_work_detail/widget/line_chart.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:syncfusion_flutter_datepicker/datepicker.dart'; + +import 'student_work_detail_logic.dart'; + +class StudentWorkDetailPage extends StatefulWidget { + const StudentWorkDetailPage({super.key}); + + @override + State createState() => _StudentWorkDetailPageState(); +} + +class _StudentWorkDetailPageState extends State { + final logic = Get.find(); + final state = Get.find().state; + + @override + Widget build(BuildContext context) { + return OrientationBuilder( + builder: (BuildContext context, Orientation orientation) { + return Scaffold( + backgroundColor: const Color.fromRGBO(245, 245, 245, 1), + appBar: AppBar( + backgroundColor: Colors.white, + title: Text('${state.studentName}作业详情', + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF333333))), + centerTitle: true, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: Colors.black), + onPressed: () => Get.back(), + ), + actions: const [ + ReturnToHomepage(), + ], + elevation: 0, + ), + body: Column( + children: [ + Container( + height: 1.r, + width: MediaQuery.of(context).size.width, + color: const Color.fromRGBO(179, 179, 179, 0.3), + ), + Container( + color: Colors.white, + padding: EdgeInsets.symmetric(vertical: 2.r), + child: Row( + children: [ + InkWell( + onTap: () { + EasyLoading.show(status: 'loading...'); + state.page = 1; + state.totalPages = 0; + state.isJob.value = true; + logic.getList(); + }, + child: SizedBox( + width: (MediaQuery.of(context).size.width - 1.r) / 2, + height: 40.r, + child: Obx(() { + return Center( + child: Text( + '作业', + style: TextStyle( + fontSize: 14.sp, + color: state.isJob.value + ? Theme.of(context).primaryColor + : const Color(0xFF505E6E)), + )); + }), + ), + ), + Container( + height: 40.r, + width: 1.r, + color: const Color.fromRGBO(179, 179, 179, 0.3), + ), + InkWell( + onTap: () { + EasyLoading.show(status: 'loading...'); + state.isJob.value = false; + state.page = 1; + state.totalPages = 0; + logic.getList(); + }, + child: SizedBox( + width: (MediaQuery.of(context).size.width - 1.r) / 2, + height: 40.r, + child: Center(child: Obx(() { + return Text( + '考试', + style: TextStyle( + fontSize: 14.sp, + color: !state.isJob.value + ? Theme.of(context).primaryColor + : const Color(0xFF505E6E)), + ); + })), + ), + ), + ], + ), + ), + Obx(() { + return Container( + margin: EdgeInsets.symmetric(vertical: 10.r, horizontal: 14.r), + padding: EdgeInsets.only( + top: 10.r, left: 10.r, right: 10.r, bottom: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10.r)), + color: Colors.white), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + /* Text( + '总览:', + style: TextStyle( + fontSize: 12.sp, + color: Theme.of(context).primaryColor, + fontWeight: FontWeight.w600), + ),*/ + SizedBox(height: 10.r,), + SizedBox( + height: 200.r, + child: LineChartCon(isShowingMainData: true,lineNum: 3,line1:state.kgtLine.value,line2: state.zgtLine.value,line3: state.allLine.value,), + ), + SizedBox(height: 20.r,), + ProgressBar( + title: '客观题正确率:', + color:const Color(0xFF4DE6BF), + percent: state.studentData.value.kgtCorrectRate / 100, + padingEdg: EdgeInsets.zero, + marginEdg: EdgeInsets.only(top: 8.h)), + ProgressBar( + title: '主观题正确率:', + color: Theme.of(context).primaryColor, + percent: state.studentData.value.zgtCorrectRate / 100, + padingEdg: EdgeInsets.zero, + marginEdg: EdgeInsets.only(top: 8.h)), + ProgressBar( + title: '总正确率:', + color: const Color(0xFF1890FF), + percent: state.studentData.value.correctRate / 100, + padingEdg: EdgeInsets.zero, + marginEdg: EdgeInsets.only(top: 8.h)), + ], + ), + ); + }), + + Obx(() { + return JobConditionFilter( + controller: logic.tabController, + jobType: state.isJob.value ? 1 : 2, + customTimeStr: state.customTimeStr.value, + customTime: logic.tabController.index != 2 || + ((state.dateEnd == null || state.dateEnd == '') && + (state.dateStart == null || + state.dateStart == '')) + ? null + : PickerDateRange( + state.dateStart == null || state.dateStart == '' + ? null + : DateTime.parse(state.dateStart!), + state.dateEnd == null || state.dateEnd == '' + ? null + : DateTime.parse(state.dateEnd!), + ), + onTimeFilter: (String? startTime, String? endTime) { + EasyLoading.show(status: 'loading...'); + if (startTime == null && endTime == null) { + if (logic.tabController.index == 2) { + logic.tabController.animateTo(0); + } + state.dateStart = + Utils.getWeekStartDate().toString().substring(0, 10); + state.dateEnd = + Utils.getWeekEndDate().toString().substring(0, 10); + state.customTimeStr.value = '自定义'; + } else { + state.dateStart = startTime ?? ''; + state.dateEnd = endTime ?? ''; + } + state.page = 1; + logic.getList(); + }, + refreshTime: (value) { + if (value != null && value.startDate != null) { + state.customTimeStr.value = + value.startDate?.toString().substring(0, 10) ?? ''; + + if (value.endDate != null) { + if (!Utils.isPad() && + value.startDate!.year == value.endDate!.year) { + state.customTimeStr.value = + '${value.startDate.toString().substring(5, 10)}~${value.endDate.toString().substring(5, 10)}'; + } else { + state.customTimeStr.value = + '${state.customTimeStr.value}~${value.endDate?.toString().substring(0, 10)}'; + } + } + } + }); + }), + Padding( + padding: EdgeInsets.only(top: 14.r, right: 14.r), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + '注:', + style: TextStyle(fontSize: 8.sp, color: const Color(0xFF8B8B8B)), + ), + Container( + width: 10.r, + height: 10.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.r)), + color: const Color(0xFF00B386), + border: Border.all(width: 1.r, color: const Color(0xFF00B386)), + ), + ), + SizedBox( + width: 2.r, + ), + Text( + '正确', + style: TextStyle(fontSize: 8.sp, color: const Color(0xFF8B8B8B)), + ), + SizedBox( + width: 15.r, + ), + Container( + width: 10.r, + height: 10.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.r)), + color: const Color(0xFFCB191B), + border: Border.all(width: 1.r, color: const Color(0xFFCB191B)), + ), + ), + SizedBox( + width: 2.r, + ), + Text( + '错误', + style: TextStyle(fontSize: 8.sp, color: const Color(0xFF8B8B8B)), + ), + SizedBox( + width: 15.r, + ), + Container( + width: 10.r, + height: 10.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.r)), + // color: Color(0xFF666666), + border: Border.all(width: 1.r, color: const Color(0xFF666666)), + // border: Border.all(width: 1.r,color: Colors.grey), + /* boxShadow: [ + BoxShadow( + color: Colors.grey, + offset: Offset(1.w, 1.h), //阴影y轴偏移量 + blurRadius: 4, //阴影模糊程度 + spreadRadius: 0.1, //阴影扩散程度 + ) + ],*/ + ), + ), + SizedBox( + width: 2.r, + ), + Text( + '已作答未批阅', + style: TextStyle(fontSize: 8.sp, color: const Color(0xFF8B8B8B)), + ), + SizedBox( + width: 15.r, + ), + Container( + width: 10.r, + height: 10.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(5.r)), + border: Border.all(width: 1.r, color: const Color(0xFFDDDDDD)), + // color: Color(0xFFDDDDDD), + ), + ), + SizedBox( + width: 2.r, + ), + Text( + '未做', + style: TextStyle(fontSize: 8.sp, color: const Color(0xFF8B8B8B)), + ), + ], + ), + ), + Expanded( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 10.r), + child: Obx(() { + return EasyRefresh( + firstRefresh: false, + taskIndependence: true, + controller: logic.refreshController, + header: MaterialHeader(), + footer: TaurusFooter(), + onRefresh: () async { + state.page = 1; + logic.getList(); + }, + onLoad: () async { + if (state.page < state.totalPages) { + state.page += 1; + logic.getList(); + } + }, + child: state.studentData.value.items.items.isNotEmpty + ? ListView.builder( + itemCount: + state.studentData.value.items.items.length, + itemBuilder: (context, index) { + StudentItems item = + state.studentData.value.items.items[index]; + return InkWell( + onTap: () { + Get.toNamed(Routes.studentPersonalPage, + arguments: { + 'homeworkId': item.id, + 'studentId': state.studentId, + 'subject':item.subject + }); + }, + child: Container( + margin: EdgeInsets.symmetric( + vertical: 5.r, horizontal: 14.r), + padding: EdgeInsets.symmetric( + vertical: 14.r, horizontal: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.all( + Radius.circular(10.r)), + color: item.allNotDone + ? const Color(0xFFFFEDD3) + : Colors.white), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Container( + width: 32.w, + height: 22.h, + alignment: Alignment.center, + // padding: EdgeInsets.only(left: 2.w), + decoration: BoxDecoration( + color: state.isJob.value + ? Theme.of(context).primaryColor + : const Color(0xFFFFA116), + borderRadius: BorderRadius.all( + Radius.circular(5.r) + ), + ), + margin: EdgeInsets.only(right: 4.w), + child: Text( + state.isJob.value ? '作业' : '考试', + style: TextStyle( + fontSize: 10.sp, + color: Colors.white), + ), + ), + Expanded( + child: Text( + item.name, + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF464646)), + )), + // SizedBox(width: 5.r,), + // Text('2024.1',style: TextStyle(fontSize: 12.sp,color: Color(0xFF5B5B5B)),), + + Container( + width: 40.r, + height: 20.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all( + Radius.circular(4.r)), + border: Border.all( + width: 1.r, + color: Theme.of(context).primaryColor), + ), + child: Center( + child: Text( + EnumUtils.formatSubject( + item.subject), + style: TextStyle( + fontSize: 10.sp, + color: Theme.of(context).primaryColor), + )), + ), + ], + ), + SizedBox( + height: 10.r, + ), + Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + '客:', + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF5B5B5B)), + ), + SizedBox( + width: 5.r, + ), + item.kgtList.isNotEmpty + ? Expanded( + child: Wrap( + direction: Axis.horizontal, + alignment: + WrapAlignment.start, + spacing: 8, + runSpacing: 5, + children: List.generate( + item.kgtList.length, + (i) { + KgtList subjective = + item.kgtList[i]; + return Container( + width: 25.r, + height: 25.r, + decoration: BoxDecoration( + color: subjective.state == 3 + ?const Color(0xFF00B386):subjective.state == 2 + ? const Color(0xFFCB191B):Colors.transparent, + border: Border.all( + width: 1.r, + color: subjective.state == 0 + ? const Color(0xFFDDDDDD) + : subjective.state == 3 + ?const Color(0xFF00B386) + : subjective.state == 2 + ? const Color(0xFFCB191B) + : const Color(0xFF666666)), + borderRadius: BorderRadius.all(Radius.circular(12.5.r))), + child: Center( + child: Text( + subjective.questionNo + .toString(), + style: TextStyle( + fontSize: 10.r, + color: subjective + .state == + 0 + ? const Color( + 0xFFDDDDDD) + : subjective.state == + 3 + ? Colors.white + : subjective.state == + 2 + ?Colors.white + : const Color( + 0xFF666666)), + )), + ); + }), + ), + ) + : Text( + '无', + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF5B5B5B)), + ), + ], + ), + SizedBox( + height: 10.r, + ), + Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + '主:', + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF5B5B5B)), + ), + SizedBox( + width: 5.r, + ), + item.zgtList.isNotEmpty + ? Expanded( + child: Wrap( + direction: Axis.horizontal, + alignment: + WrapAlignment.start, + spacing: 8, + runSpacing: 5, + children: List.generate( + item.zgtList.length, + (i) { + ZgtList subjective = + item.zgtList[i]; + return Container( + width: 25.r, + height: 25.r, + decoration: BoxDecoration( + color: subjective.state == 3 + ? const Color(0xFF00B386):subjective.state == 2 + ? const Color(0xFFCB191B):Colors.transparent, + border: Border.all( + width: 1.r, + color: subjective.state == 0 + ? const Color(0xFFDDDDDD) + : subjective.state == 3 + ? const Color(0xFF00B386) + : subjective.state == 2 + ? const Color(0xFFCB191B) + : const Color(0xFF666666)), + borderRadius: BorderRadius.all(Radius.circular(12.5.r))), + child: Center( + child: Text( + subjective.questionNo + .toString(), + style: TextStyle( + fontSize: 10.r, + color: subjective + .state == + 0 + ? const Color( + 0xFFDDDDDD) + : subjective.state == + 3 + ? Colors.white + : subjective.state == + 2 + ? Colors.white + : const Color( + 0xFF666666)), + )), + ); + }), + ), + ) + : Text( + '无', + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF5B5B5B)), + ), + ], + ), + ProgressBar( + title: '客观题正确率:', + color: const Color(0xFFB2DA93), + percent: item.kgtCorrectRate / 100, + padingEdg: EdgeInsets.zero, + marginEdg: EdgeInsets.only(top: 8.h)), + ProgressBar( + title: '主观题正确率:', + color: const Color(0xFFB2DA93), + percent: item.zgtCorrectRate / 100, + padingEdg: EdgeInsets.zero, + marginEdg: EdgeInsets.only(top: 8.h)), + ProgressBar( + title: '总正确率:', + color: const Color(0xFFB2DA93), + percent: item.correctRate / 100, + padingEdg: EdgeInsets.zero, + marginEdg: EdgeInsets.only(top: 8.h)), + ], + ), + ), + ); + }) + : const MyEmptyWidget(), + ); + }), + ), + ), + ], + ), + ); + }); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} diff --git a/lib/page/home_page/children/student_work_detail/widget/job_condition_filter.dart b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/widget/job_condition_filter.dart similarity index 80% rename from lib/page/home_page/children/student_work_detail/widget/job_condition_filter.dart rename to making_school_asignment_app/lib/page/home_page/children/student_work_detail/widget/job_condition_filter.dart index 3b2a7a4..2fb86dc 100644 --- a/lib/page/home_page/children/student_work_detail/widget/job_condition_filter.dart +++ b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/widget/job_condition_filter.dart @@ -1,19 +1,20 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/home_page/children/student_work_detail/widget/personal_detail_topbar.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/home_page/children/student_work_detail/widget/personal_detail_topbar.dart'; import 'package:syncfusion_flutter_datepicker/datepicker.dart'; class JobConditionFilter extends StatefulWidget { -final TabController controller; -final int jobType; -final PickerDateRange? customTime; -final Function? refreshTime; -final String customTimeStr; -final bool? hasAll; -final Function(String? startTime, String? endTime) onTimeFilter; - const JobConditionFilter({Key? key, + final TabController controller; + final int jobType; + final PickerDateRange? customTime; + final Function? refreshTime; + final String customTimeStr; + final bool? hasAll; + final Function(String? startTime, String? endTime) onTimeFilter; + const JobConditionFilter({ + Key? key, required this.controller, required this.jobType, this.customTime, @@ -28,37 +29,35 @@ final Function(String? startTime, String? endTime) onTimeFilter; } class _JobConditionFilterState extends State { - var customTimeState = const PickerDateRange(null, null); @override void initState() { super.initState(); if (widget.customTime != null) { - customTimeState = PickerDateRange(widget.customTime!.startDate, - widget.customTime!.endDate); + customTimeState = PickerDateRange(widget.customTime!.startDate, widget.customTime!.endDate); } } DateTime getMonthStartDate() { + // DateTime now = DateTime.now(); + // return DateTime(now.year, now.month, 1); // 获取当前月份的第一天 DateTime now = DateTime.now(); - return DateTime(now.year, now.month, 1); // 获取当前月份的第一天 + return now.subtract(const Duration(days: 29)); } DateTime getMonthEndDate() { DateTime now = DateTime.now(); - int nextMonth = now.month + 1; - if (nextMonth > 12) { - nextMonth = 1; - now = now.add(Duration(days: 31 - now.day)); // 跨年了,所以加到当前月的最后一天 - } else { - now = now.add(Duration(days: DateTime(now.year, nextMonth, 0).day - now.day)); // 加到下个月的第一天的前一天,即本月最后一天 - } + // int nextMonth = now.month + 1; + // if (nextMonth > 12) { + // nextMonth = 1; + // now = now.add(Duration(days: 31 - now.day)); // 跨年了,所以加到当前月的最后一天 + // } else { + // now = now.add(Duration(days: DateTime(now.year, nextMonth, 0).day - now.day)); // 加到下个月的第一天的前一天,即本月最后一天 + // } return now; } - - @override Widget build(BuildContext context) { return Container( @@ -73,19 +72,19 @@ class _JobConditionFilterState extends State { customTimeStr: widget.customTimeStr, hasAll: widget.hasAll, onTap: (int val) async { - if(val == 0 && widget.hasAll == true){ + if (val == 3 && widget.hasAll == true) { widget.onTimeFilter(null, null); - }else if((val == 1 && widget.hasAll == true) || (val == 0 && widget.hasAll == false)){ + } else if ((val == 0 && widget.hasAll == true) || (val == 0 && widget.hasAll == false)) { widget.onTimeFilter( Utils.getWeekStartDate().toString().substring(0, 10), Utils.getWeekEndDate().toString().substring(0, 10), ); - }else if((val == 2 && widget.hasAll == true) || (val == 1 && widget.hasAll == false)){ + } else if ((val == 1 && widget.hasAll == true) || (val == 1 && widget.hasAll == false)) { widget.onTimeFilter( getMonthStartDate().toString().substring(0, 10), getMonthEndDate().toString().substring(0, 10), ); - }else{ + } else { var dialogData = await showDialog( context: context, builder: (BuildContext context1) { @@ -120,7 +119,7 @@ class _JobConditionFilterState extends State { ); customTimeState = dialogData!; } - /* switch (val) { + /* switch (val) { case 0: // 全部 widget.onTimeFilter(null, null); break; diff --git a/making_school_asignment_app/lib/page/home_page/children/student_work_detail/widget/line_chart.dart b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/widget/line_chart.dart new file mode 100644 index 0000000..588dbda --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/widget/line_chart.dart @@ -0,0 +1,237 @@ +import 'dart:math'; + +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class LineChartCon extends StatefulWidget { + final bool isShowingMainData; + final int lineNum; + final List? line1; + final List? line2; + final List? line3; + + LineChartCon( + {required this.isShowingMainData, + required this.lineNum, + this.line1, + this.line2, + this.line3}); + + @override + State createState() => _LineChartConState(); +} + +class _LineChartConState extends State { + double maxX = 0.0; + + @override + void initState() { + super.initState(); + } + + getMaxX(){ + if (widget.lineNum > 2) { + if (widget.line3!.length > widget.line2!.length && + widget.line3!.length > widget.line1!.length) { + maxX = double.parse(widget.line3!.length.toString()); + } else if (widget.line2!.length > widget.line3!.length && + widget.line2!.length > widget.line1!.length) { + maxX = double.parse(widget.line2!.length.toString()); + } else { + maxX = double.parse(widget.line1!.length.toString()); + } + } else if (widget.lineNum > 1) { + + } + print('maxx=======$maxX'); + return maxX; + } + + @override + Widget build(BuildContext context) { + + return LineChart( + LineChartData( + lineTouchData: const LineTouchData(enabled: false), + gridData: gridData, + titlesData: titlesData1, + borderData: borderData, + lineBarsData: lineBarsData1, + minX: 1, + maxX: getMaxX()>0? getMaxX():3, + maxY: 6, + minY: 0, + ), + duration: const Duration(milliseconds: 250), + ); + } + + FlTitlesData get titlesData1 => FlTitlesData( + bottomTitles: AxisTitles( + sideTitles: bottomTitles, + ), + rightTitles: const AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + topTitles: const AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + leftTitles: AxisTitles( + sideTitles: leftTitles(), + ), + ); + + List get lineBarsData1 => [ + lineChartBarData1_1, + lineChartBarData1_2, + lineChartBarData1_3, + ]; + + Widget leftTitleWidgets(double value, TitleMeta meta) { + String text; + switch (value.toInt()) { + case 0: + text = '0'; + break; + case 1: + text = '20%'; + break; + case 2: + text = '40%'; + break; + case 3: + text = '60%'; + break; + case 4: + text = '80%'; + break; + case 5: + text = '100%'; + break; + default: + return Container(); + } + + return Text(text, style: TextStyle(fontSize: 12.sp, color: const Color(0xFF070707)), textAlign: TextAlign.left); + + /* return SideTitleWidget( + axisSide: meta.axisSide, + child: Text( + '${value}', + style: TextStyle(fontSize: 12.sp, color: Color(0xFF070707)), + ), + );*/ + } + + SideTitles leftTitles() => SideTitles( + getTitlesWidget: leftTitleWidgets, + showTitles: true, + interval: 1, + reservedSize: 50, + ); + + Widget bottomTitleWidgets(double value, TitleMeta meta) { + return SideTitleWidget( + axisSide: meta.axisSide, + space: 10, + child: Text( + value.toString() == '0.0' ? '' : value.toStringAsFixed(0), + style: TextStyle( + fontWeight: FontWeight.w400, + fontSize: 12.sp, + color: const Color.fromRGBO(39, 39, 39, 0.5), + ), + ), + ); + } + + SideTitles get bottomTitles => SideTitles( + showTitles: true, + reservedSize: 32, + interval: 1, + getTitlesWidget: bottomTitleWidgets, + ); + + FlGridData get gridData => const FlGridData( + show: true, drawVerticalLine: false, horizontalInterval: 1.0); + + FlBorderData get borderData => FlBorderData( + show: true, + border: const Border( + bottom: BorderSide(color: Colors.transparent, width: 1), + left: BorderSide(color: Colors.transparent), + right: BorderSide(color: Colors.transparent), + top: BorderSide(color: Colors.transparent), + ), + ); + + LineChartBarData get lineChartBarData1_1 => LineChartBarData( + isCurved: true, + curveSmoothness: 0, + color: const Color(0xFF4DE6BF), + barWidth: 2, + isStrokeCapRound: true, + dotData: const FlDotData(show: false), + belowBarData: BarAreaData(show: false), + spots: List.generate(widget.line1!.length, (index){ + var element = widget.line1![index]; + return FlSpot(double.parse(element['id'].toString()), double.parse(element['rate'].toString())); + }) + /* const [ + FlSpot(1, 0), + FlSpot(3, 1.5), + FlSpot(5, 1.4), + FlSpot(7, 3.4), + FlSpot(10, 2), + FlSpot(12, 2.2), + FlSpot(13, 1.8), + ],*/ + ); + + LineChartBarData get lineChartBarData1_2 => LineChartBarData( + isCurved: true, + curveSmoothness: 0, + color: Theme.of(context).primaryColor, + barWidth: 2, + isStrokeCapRound: true, + dotData: const FlDotData(show: false), + belowBarData: BarAreaData( + show: false, + color: Colors.yellow, + ), + spots: List.generate(widget.line2!.length, (index){ + var element = widget.line2![index]; + return FlSpot(double.parse(element['id'].toString()), double.parse(element['rate'].toString())); + }) + /* const [ + FlSpot(1, 1), + FlSpot(3, 2.8), + FlSpot(7, 1.2), + FlSpot(10, 2.8), + FlSpot(12, 2.6), + FlSpot(13, 3.9), + ],*/ + ); + + LineChartBarData get lineChartBarData1_3 => LineChartBarData( + isCurved: true, + curveSmoothness: 0, + color: const Color(0xFF1890FF), + barWidth: 2, + isStrokeCapRound: true, + dotData: const FlDotData(show: false), + belowBarData: BarAreaData(show: false), + spots: List.generate(widget.line3!.length, (index){ + var element = widget.line3![index]; + return FlSpot(double.parse(element['id'].toString()), double.parse(element['rate'].toString())); + }) + /* const [ + FlSpot(1, 2.8), + FlSpot(3, 1.9), + FlSpot(6, 3), + FlSpot(10, 1.3), + FlSpot(13, 2.5), + ],*/ + ); +} diff --git a/lib/page/home_page/children/student_work_detail/widget/personal_detail_topbar.dart b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/widget/personal_detail_topbar.dart similarity index 78% rename from lib/page/home_page/children/student_work_detail/widget/personal_detail_topbar.dart rename to making_school_asignment_app/lib/page/home_page/children/student_work_detail/widget/personal_detail_topbar.dart index 12d1d32..2d8459b 100644 --- a/lib/page/home_page/children/student_work_detail/widget/personal_detail_topbar.dart +++ b/making_school_asignment_app/lib/page/home_page/children/student_work_detail/widget/personal_detail_topbar.dart @@ -13,10 +13,10 @@ class PersonalDetailTopBar extends StatefulWidget { } class _PersonalDetailTopBarState extends State { - @override - void initState(){ - super.initState(); - } + @override + void initState(){ + super.initState(); + } @override Widget build(BuildContext context) { @@ -27,24 +27,32 @@ class _PersonalDetailTopBarState extends State { ), child: TabBar( controller: widget.controller, + dividerHeight: 0, + tabAlignment: TabAlignment.start, unselectedLabelStyle: TextStyle(fontSize: 12.sp, color: const Color.fromRGBO(102, 102, 102, 1)), labelStyle: TextStyle( fontSize: 12.sp, fontWeight: FontWeight.bold, - color: const Color.fromRGBO(116, 145, 253, 1), + color: const Color(0xFF4CC793), ), isScrollable: true, - labelColor: const Color(0xFF7491FD), + labelColor: const Color(0xFF4CC793), unselectedLabelColor: const Color(0xFF505E6E), padding: EdgeInsets.symmetric(horizontal: 14.r), // indicatorSize: TabBarIndicatorSize.label, // 设置指示器高度和标签一样高 onTap: widget.onTap, + indicator: UnderlineTabIndicator( + borderSide: BorderSide( + width: 2.r, + color:const Color(0xFF4CC793) + ), + ), tabs: [ - if(widget.hasAll == true) - const Tab(text: '全部'), const Tab(text: '近一周'), const Tab(text: '近一月'), Tab(text: widget.customTimeStr), + if(widget.hasAll == true) + const Tab(text: '全部'), ], ), ); diff --git a/lib/page/home_page/home_binding.dart b/making_school_asignment_app/lib/page/home_page/home_binding.dart similarity index 100% rename from lib/page/home_page/home_binding.dart rename to making_school_asignment_app/lib/page/home_page/home_binding.dart diff --git a/making_school_asignment_app/lib/page/home_page/home_logic.dart b/making_school_asignment_app/lib/page/home_page/home_logic.dart new file mode 100644 index 0000000..46853f6 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/home_logic.dart @@ -0,0 +1,44 @@ +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/work_student.dart'; +import 'package:making_school_asignment_app/common/job/work_student_params.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; + +import 'home_state.dart'; + +class HomeLogic extends GetxController with RequestToolMixin, GetTickerProviderStateMixin { + final HomeState state = HomeState(); + late final EasyRefreshController refreshController; + WorkStudentParams params = WorkStudentParams( + assessType: 0, + ); + + @override + void onInit() { + super.onInit(); + refreshController = EasyRefreshController(); + params.pageSize = state.pageSize; + + getList(); + } + + void getList() async { + params.pageNumber = state.pageNumber; + WorkStudent data = await getClient().getUnAnnotateList(params); + state.totalCount.value = data.totalCount; + state.readOver.value = data.items.length; + /* if(params.pageNumber == 1){ + state.workList.value = data.items; + }else{ + state.workList.addAll(data.items); + } + refreshController.finishRefresh();*/ + } + + @override + void dispose() { + super.dispose(); + refreshController.dispose(); + } +} diff --git a/making_school_asignment_app/lib/page/home_page/home_state.dart b/making_school_asignment_app/lib/page/home_page/home_state.dart new file mode 100644 index 0000000..3e8b0c2 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/home_state.dart @@ -0,0 +1,18 @@ +import 'package:get/get.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/job/work_student.dart'; + +class HomeState { + HomeState() { + ///Initialize variables + } + + late Rx userInfo; + late RxInt readOver = 0.obs; + late RxList workList = RxList(); + late int type = 1; + late int pageSize = 10; + late int pageNumber = 1; + late RxInt totalCount = 1.obs; +} diff --git a/making_school_asignment_app/lib/page/home_page/home_view.dart b/making_school_asignment_app/lib/page/home_page/home_view.dart new file mode 100644 index 0000000..36a02f0 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/home_view.dart @@ -0,0 +1,349 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_easyrefresh/easy_refresh.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:functional_widget_annotation/functional_widget_annotation.dart'; +import 'package:get/get.dart'; +import 'package:badges/badges.dart' as badges; +import 'package:percent_indicator/percent_indicator.dart'; +import 'package:making_school_asignment_app/common/job/work_student.dart'; +import 'package:making_school_asignment_app/common/utils/enum_untils.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +import 'home_logic.dart'; + +part 'home_view.g.dart'; + +class HomePage extends StatefulWidget { + const HomePage({super.key}); + + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State with AutomaticKeepAliveClientMixin { + final logic = Get.find(); + final state = Get.find().state; + + @override + bool get wantKeepAlive => true; + + @override + void initState() { + super.initState(); + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, //状态栏背景颜色 + statusBarIconBrightness: Brightness.light, + systemStatusBarContrastEnforced: false, + )); + } + + @override + Widget build(BuildContext context) { + super.build(context); + var spaceWidth = SizedBox(height: ScreenUtil().screenWidth / 30); + return Scaffold( + backgroundColor: Colors.white, + body: OrientationBuilder( + builder: (BuildContext context, Orientation orientation) { + return EasyRefresh( + firstRefresh: false, + taskIndependence: true, + enableControlFinishLoad: true, + controller: logic.refreshController, + header: MaterialHeader(), + // footer: TaurusFooter(), + onRefresh: () async { + state.pageNumber = 1; + return logic.getList(); + }, + // onLoad: () async { + // if (state.workList.length < state.totalCount.value) { + // state.pageNumber++; + // return logic.getList(); + // } + // }, + child: Stack( + children: [ + Image.asset( + 'assets/images/home_banner.png', + width: Get.width, + fit: BoxFit.fill, + ), + Container( + margin: EdgeInsets.only(top: 300.h), + padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20.r), + decoration: BoxDecoration( + color: Colors.white, borderRadius: BorderRadius.only(topLeft: Radius.circular(30.r), topRight: Radius.circular(30.r))), + child: Column( + children: [ + SizedBox( + height: 15.r, + ), + Text( + '我的作业管理', + style: TextStyle(fontSize: 20.sp, color: const Color(0xFF676666), fontWeight: FontWeight.w600), + ), + SizedBox( + height: 15.r, + ), + Row( + children: [ + Expanded( + child: Obx(() { + return menuItem( + bgImg: 'assets/images/home_bg_01.png', + name: '作业批阅', + value: state.totalCount.value.toString(), + url: Routes.readOverPage, + ); + }), + ), + SizedBox( + width: 20.r, + ), + Expanded( + child: menuItem(bgImg: 'assets/images/home_bg_02.png', name: '知识点掌握', url: Routes.studentHistoryWorkPage, page: 'points'), + ), + ], + ), + SizedBox( + height: 20.r, + ), + Row( + children: [ + Expanded( + child: + menuItem(bgImg: 'assets/images/home_bg_03.png', name: '学生历史作业', url: Routes.studentHistoryWorkPage, page: 'history'), + ), + SizedBox( + width: 20.r, + ), + Expanded( + child: menuItem(bgImg: 'assets/images/home_bg_04.png', name: '答题轨迹', url: Routes.answerTrajectoryPage), + ), + ], + ), + SizedBox( + height: 20.r, + ), + Row( + children: [ + menuItem( + bgImg: 'assets/images/home_bg_05.png', + name: '优先批阅设定', + url: Routes.studentHistoryWorkPage, + page: 'set', + ), + SizedBox( + width: 20.r, + ), + ], + ), + SizedBox(height: 15.h), + ], + ), + ) + ], + ), + ); + }, + ), + ); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} + +Widget menuItem({required String bgImg, required String name, String? value, required String url, String? page}) { + return InkWell( + onTap: () { + Get.toNamed(url, arguments: {'page': page ?? ''}); + }, + child: Container( + width: (Get.width - 60.r) / 2, + height: (Get.width - 60.r) / 2 * 86 / 164, + padding: EdgeInsets.symmetric(vertical: 15.r, horizontal: 15.r), + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage(bgImg), + fit: BoxFit.contain, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + name, + style: TextStyle(fontSize: 14.sp, color: const Color(0xFF4F4F4F), fontWeight: FontWeight.w600), + ), + if (value != null && value != '') + Container( + width: 18.r, + height: 18.r, + alignment: Alignment.center, + decoration: BoxDecoration( + color: const Color(0xFFFF6969), + borderRadius: BorderRadius.all(Radius.circular(9.r)), + ), + child: Text( + value!, + style: TextStyle(fontSize: 10.sp, color: Colors.white, fontWeight: FontWeight.w600), + ), + ) + ], + ), + const Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Image.asset( + 'assets/images/home_right_icon.png', + width: 16.r, + height: 16.r, + ), + ], + ), + ], + ), + ), + ); +} + +class EntranceModel extends Object { + String title; + String image; + String navigationUrl; + String? page; + + EntranceModel({required this.title, required this.image, required this.navigationUrl, this.page}); +} + +@swidget +Widget $termRow(BuildContext context, List items, int? data) { + var leng = items.length; + Widget childWidget; + switch (leng) { + case 1: + childWidget = Row(children: [Expanded(child: $TermItem(items[0], data!))]); + break; + case 2: + childWidget = Row(children: [ + Expanded(flex: 9, child: $TermItem(items[0], data!)), + // const Expanded(flex: 1, child: SizedBox()), + SizedBox(width: ScreenUtil().screenWidth / 30), + Expanded(flex: 9, child: $TermItem(items[1], data!)), + ]); + break; + case 3: + double theHeight = ScreenUtil().screenWidth / 30 + 54.h * 2; + childWidget = Row( + children: [ + Expanded(child: $TermItem(items[0], data!, theHeight: theHeight)), + SizedBox(width: ScreenUtil().screenWidth / 30), + Expanded( + child: SizedBox( + height: theHeight, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + $TermItem(items[1], data), + $TermItem(items[2], data), + ], + ), + ), + ), + ], + ); + break; + default: + childWidget = Container(); + } + + return Container(padding: EdgeInsets.symmetric(horizontal: 14.w), child: childWidget); +} + +@swidget +Widget $termItem(BuildContext context, EntranceModel e, int data, {double? theHeight}) { + bool isJob = e.title == '作业批阅'; + + return Material( + color: Colors.white, + elevation: 3.r, + shadowColor: const Color.fromRGBO(231, 231, 231, 1), + borderRadius: BorderRadius.all(Radius.circular(8.r)), + child: InkWell( + onTap: () { + Get.toNamed(e.navigationUrl, arguments: {'page': e.page ?? ''}); + }, + + // splashColor: splashColor, + borderRadius: BorderRadius.all(Radius.circular(8.r)), + child: badges.Badge( + showBadge: isJob && data > 0, + ignorePointer: false, + badgeContent: quickText(data, color: Colors.white, size: 10.sp), + badgeAnimation: const badges.BadgeAnimation.rotation( + animationDuration: Duration(seconds: 1), + colorChangeAnimationDuration: Duration(seconds: 1), + loopAnimation: false, + curve: Curves.fastOutSlowIn, + colorChangeAnimationCurve: Curves.easeInCubic, + ), + badgeStyle: badges.BadgeStyle( + badgeColor: const Color.fromRGBO(255, 105, 105, 1), + shape: badges.BadgeShape.square, + borderRadius: BorderRadius.only(topLeft: Radius.circular(10.r), topRight: Radius.circular(8.5.r), bottomRight: Radius.circular(8.5.r)), + // borderSide: BorderSide(color: Colors.white, width: 2), + elevation: 1, + padding: EdgeInsets.symmetric(horizontal: Utils.isPad() ? 11.w : 16.w, vertical: 2.h), + ), + position: badges.BadgePosition.topEnd(top: 10.r, end: 10.r), + child: Container( + height: theHeight, + padding: EdgeInsets.symmetric(vertical: 12.h), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8.r)), + // boxShadow: [ + // BoxShadow( + // color: const Color.fromRGBO(231, 231, 231, 1), + // offset: Offset(4.w, 6.h), //阴影y轴偏移量 + // blurRadius: 8, //阴影模糊程度 + // spreadRadius: 0.2, //阴影扩散程度 + // ) + // ], + // border: Border.all(width: 0.5.w, color: Color.fromARGB(255, 219, 226, 250)), + ), + alignment: Alignment.center, + child: isJob + ? Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover), + SizedBox(height: 6.r), + quickText(e.title, size: 12.sp, color: const Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500), + ], + ) + : Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset(e.image, height: 32.r, width: 32.r, fit: BoxFit.cover), + SizedBox(width: 6.r), + quickText(e.title, size: 12.sp, color: const Color.fromRGBO(79, 79, 79, 1), fontWeight: FontWeight.w500), + ], + ), + ), + )), + ); +} diff --git a/lib/page/home_page/widget/progress_bar.dart b/making_school_asignment_app/lib/page/home_page/widget/progress_bar.dart similarity index 83% rename from lib/page/home_page/widget/progress_bar.dart rename to making_school_asignment_app/lib/page/home_page/widget/progress_bar.dart index be9ddae..aa275f1 100644 --- a/lib/page/home_page/widget/progress_bar.dart +++ b/making_school_asignment_app/lib/page/home_page/widget/progress_bar.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:percent_indicator/percent_indicator.dart'; -import 'package:school_asignment_app/common/utils/utils.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; class ProgressBar extends StatefulWidget { late double? fontSize; @@ -12,7 +12,16 @@ class ProgressBar extends StatefulWidget { final double percent; final EdgeInsets padingEdg; final EdgeInsets marginEdg; - ProgressBar({Key? key,this.fontSize,this.lineHeight,required this.title,required this.color,required this.percent,required this.marginEdg,required this.padingEdg}) : super(key: key); + ProgressBar( + {Key? key, + this.fontSize, + this.lineHeight, + required this.title, + required this.color, + required this.percent, + required this.marginEdg, + required this.padingEdg}) + : super(key: key); @override State createState() => _ProgressBarState(); diff --git a/making_school_asignment_app/lib/page/home_page/widget/student_group_list.dart b/making_school_asignment_app/lib/page/home_page/widget/student_group_list.dart new file mode 100644 index 0000000..515e7d0 --- /dev/null +++ b/making_school_asignment_app/lib/page/home_page/widget/student_group_list.dart @@ -0,0 +1,161 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/job/class_item.dart'; +import 'package:making_school_asignment_app/common/utils/enum_untils.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/MyEmptyWidget.dart'; + +class StudentGroupList extends StatelessWidget { + final List studentGroups; + final Function goNextPage; + final Widget? rightBtn; + + const StudentGroupList(this.studentGroups, this.goNextPage, {Key? key, this.rightBtn}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Obx(() { + return studentGroups != null && studentGroups.isNotEmpty + ? Utils.isPad() + ? GridView( + shrinkWrap: true, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + mainAxisSpacing: 10.r, + crossAxisSpacing: 10.r, + childAspectRatio: 556 / 112, + ), + children: List.generate(studentGroups.length, (index) { + ClassItem item = studentGroups[index]; + return InkWell( + onTap: () { + goNextPage(item.classId, '${EnumUtils.formatGrade(item.grade)}${item.className}', item.subject); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10.r)), + color: Colors.white, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(right: 8.r), + child: Text( + '${EnumUtils.formatGrade(item.grade)}${item.className}', + style: TextStyle(fontSize: 10.sp, color:Theme.of(context).primaryColor), + ), + ), + Text( + EnumUtils.formatSubject(item.subject!), + style: TextStyle(fontSize: 10.sp, color: Color(0xFF8B8B8B)), + ), + const Spacer(), + /*Expanded( + child: Text( + classNames, + style: TextStyle( + fontSize: 10.sp, + color: Color(0xFF999999), + overflow: TextOverflow.ellipsis, + ), + textAlign: TextAlign.end, + ), + ),*/ + rightBtn != null + ? rightBtn! + : Container( + margin: EdgeInsets.only(left: 5.r), + height: 20.r, + width: 55.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.r)), + color: Theme.of(context).primaryColor, + ), + child: Center( + child: Text( + '详情', + style: TextStyle(fontSize: 10.sp, color: Colors.white), + ), + ), + ) + ], + ), + ), + ); + }), + ) + : ListView.builder( + shrinkWrap: true, + itemBuilder: (context, index) { + ClassItem item = studentGroups[index]; + return InkWell( + onTap: () { + goNextPage(item.classId, '${EnumUtils.formatGrade(item.grade)}${item.className}', item.subject); + }, + child: Container( + padding: EdgeInsets.symmetric(vertical: 15.r, horizontal: 10.r), + margin: EdgeInsets.only(bottom: 10.r), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(10.r)), + color: Colors.white, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(right: 8.r), + child: Text( + '${EnumUtils.formatGrade(item.grade)}${item.className}', + style: TextStyle(fontSize: 14.sp, color: Theme.of(context).primaryColor), + ), + ), + Text( + EnumUtils.formatSubject(item.subject!), + style: TextStyle(fontSize: 10.sp, color: Color(0xFF8B8B8B)), + ), + const Spacer(), + /* Expanded( + child: Text( + classNames, + style: TextStyle( + fontSize: 12.sp, + color: Color(0xFF999999), + overflow: TextOverflow.ellipsis, + ), + textAlign: TextAlign.end, + ), + ),*/ + rightBtn != null + ? rightBtn! + : Container( + margin: EdgeInsets.only(left: 5.r), + height: 24.r, + width: 55.r, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20.r)), + color: Theme.of(context).primaryColor, + ), + child: Center( + child: Text( + '详情', + style: TextStyle(fontSize: 10.sp, color: Colors.white), + ), + ), + ) + ], + ), + ), + ); + }, + itemCount: studentGroups.length, + ) + : Padding( + padding: EdgeInsets.only(top: MediaQuery.of(context).size.height / 2 - 200.r), + child: const MyEmptyWidget(), + ); + }); + } +} diff --git a/lib/page/home_page/widget/top_user_info.dart b/making_school_asignment_app/lib/page/home_page/widget/top_user_info.dart similarity index 79% rename from lib/page/home_page/widget/top_user_info.dart rename to making_school_asignment_app/lib/page/home_page/widget/top_user_info.dart index 64fd320..16e188c 100644 --- a/lib/page/home_page/widget/top_user_info.dart +++ b/making_school_asignment_app/lib/page/home_page/widget/top_user_info.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/page/home_page/home_logic.dart'; -import 'package:school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/page/home_page/home_logic.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; class TopUserInfo extends StatelessWidget { TopUserInfo({Key? key}) : super(key: key); @@ -16,11 +16,7 @@ class TopUserInfo extends StatelessWidget { }, child: Container( color: Colors.white, - padding: EdgeInsets.only( - top: MediaQuery.of(context).padding.top + 4.h, - left: 14.w, - right: 14.w, - bottom: 19.h), + padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top + 4.h, left: 14.w, right: 14.w, bottom: 19.h), child: Row( children: [ Container( @@ -38,17 +34,14 @@ class TopUserInfo extends StatelessWidget { alignment: Alignment.center, color: const Color.fromRGBO(163, 211, 255, 1), padding: EdgeInsets.all(1.r), - child: Image.asset('assets/images/login_logo.png', - width: 32.w, height: 32.w), + child: Image.asset('assets/images/login_logo_icon.png', width: 32.w, height: 32.w), ), ), Container( margin: EdgeInsets.only(left: 10.h), child: Text( state.userInfo.value!.givenname, - style: TextStyle( - fontSize: 15.sp, - color: const Color.fromRGBO(45, 56, 76, 0.9)), + style: TextStyle(fontSize: 15.sp, color: const Color.fromRGBO(45, 56, 76, 0.9)), ), ), Container( diff --git a/lib/page/login_page/children/agreement_page.dart b/making_school_asignment_app/lib/page/login_page/children/agreement_page.dart similarity index 71% rename from lib/page/login_page/children/agreement_page.dart rename to making_school_asignment_app/lib/page/login_page/children/agreement_page.dart index 1bc7184..a741b6f 100644 --- a/lib/page/login_page/children/agreement_page.dart +++ b/making_school_asignment_app/lib/page/login_page/children/agreement_page.dart @@ -2,12 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:get/get.dart'; -import 'package:school_asignment_app/common/const_text.dart'; -import 'package:school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; // 协议富文本 class AgreementPage extends StatelessWidget { - const AgreementPage({super.key}); @override @@ -17,12 +16,12 @@ class AgreementPage extends StatelessWidget { return Scaffold( appBar: AppBar( backgroundColor: Theme.of(context).primaryColor, - title: quickText(agreement.title,color: Colors.white), + title: quickText(agreement.title, color: Colors.white), ), body: ListView( padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 8.h), children: [ - HtmlWidget(agreement.richText,textStyle:const TextStyle(color: Colors.black)), + HtmlWidget(agreement.richText, textStyle: const TextStyle(color: Colors.black)), ], ), ); diff --git a/making_school_asignment_app/lib/page/login_page/children/register.dart b/making_school_asignment_app/lib/page/login_page/children/register.dart new file mode 100644 index 0000000..d2fe094 --- /dev/null +++ b/making_school_asignment_app/lib/page/login_page/children/register.dart @@ -0,0 +1,291 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; +import 'package:making_school_asignment_app/common/job/user_register_params.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/utils/toast_utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +/// 注册页面 +class Register extends StatefulWidget { + const Register({super.key}); + + @override + State createState() => _RegisterState(); +} + +class _RegisterState extends State with RequestToolMixin { + late final FocusNode _theFocus; + late final FocusNode _pwdFocus; // 密码 + //文本输入框控制器 + late final TextEditingController _userNameController; + late final TextEditingController _passwordController; + + bool readAgreement = false; // 阅读协议 + bool _isShowPwd = true; + bool canLogin = true; + + @override + void initState() { + super.initState(); + _userNameController = TextEditingController(); + _passwordController = TextEditingController(); + _pwdFocus = FocusNode(); + _theFocus = FocusNode(); + } + + @override + void dispose() { + super.dispose(); + _userNameController.dispose(); + _passwordController.dispose(); + _pwdFocus.dispose(); + _theFocus.dispose(); + } + + void toRegister() async { + if (!canLogin) return; + setState(() => canLogin = false); + void toMsg(msg) { + Future.delayed(Duration.zero, () => ToastUtils.showError(msg)); + setState(() => canLogin = true); + } + + FocusScope.of(context).requestFocus(_theFocus); + try { + String userName = _userNameController.text.trim(); + String userPwd = _passwordController.text.trim(); + if (userName == '') return toMsg('请填写用户账号'); + if (userPwd == '') return toMsg('请填写密码'); + if (userPwd.length < 6) return toMsg('密码长度不得少于6位'); + if (!readAgreement) return toMsg('请勾选我已阅读用户协议和隐私协议'); + EasyLoading.show(status: 'loading...'); + var resultData = await getClient().toRegister(UserRegisterParams(account: userName, password: userPwd)); + print(resultData); + // if (resultData.success) return toMsg(resultData.message ?? '注册失败,请重试'); + ToastUtils.showSuccess('注册成功,请登录'); + // 跳转登录页 + Future.delayed(Duration.zero, () => Get.back()); + } catch (e) { + setState(() => canLogin = true); + } finally { + EasyLoading.dismiss(); + } + } + + void _showPassword() { + setState(() { + _isShowPwd = !_isShowPwd; + }); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + FocusScope.of(context).requestFocus(_theFocus); + }, + child: AnnotatedRegion( + value: const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarIconBrightness: Brightness.light, + statusBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.dark, + ), + child: Scaffold( + backgroundColor: Colors.transparent, + resizeToAvoidBottomInset: false, + body: Stack( + children: [ + Container( + width: double.infinity, + height: double.infinity, + alignment: Alignment.center, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/register_bg.png'), + fit: BoxFit.fill, // 完全填充 + ), + ), + child: SingleChildScrollView( + child: Column( + children: [ + Container( + width: 86.w, + height: 86.w, + alignment: Alignment.center, + child: SizedBox( + height: 86.w, + width: 86.w, + child: Image.asset('assets/images/login_logo_icon.png', fit: BoxFit.cover), + ), + ), + Container( + margin: EdgeInsets.symmetric(horizontal: 32.w, vertical: 24.h), + padding: EdgeInsets.only(top: 34.h, bottom: 16.h, left: 22.w, right: 22.w), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 1.w, color: Colors.white), + borderRadius: BorderRadius.all(Radius.circular(10.w)), + boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(46, 91, 255, 0.1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 100, //阴影模糊程度 + spreadRadius: 100, //阴影扩散程度 + ) + ], + ), + child: Column(children: [ + TextField( + controller: _userNameController, + maxLines: 1, + maxLength: 20, + textInputAction: TextInputAction.next, + onEditingComplete: () { + FocusScope.of(context).requestFocus(_pwdFocus); + }, + style: TextStyle( + color: const Color.fromRGBO(80, 87, 103, 1), + fontSize: 15.sp, + ), + decoration: InputDecoration( + hintText: "请输入账号", + hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)), + labelText: "账号", + labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)), + ), + ), + TextField( + focusNode: _pwdFocus, + controller: _passwordController, + keyboardType: TextInputType.number, + maxLines: 1, + obscureText: _isShowPwd, //隐藏密码显示 + textInputAction: TextInputAction.go, + onSubmitted: (_) => toRegister(), + style: TextStyle( + color: const Color.fromRGBO(80, 87, 103, 1), + fontSize: 15.sp, + ), + decoration: InputDecoration( + hintText: "请输入密码", + suffix: GestureDetector( + onTap: _showPassword, + child: Icon( + Icons.remove_red_eye, + color: !_isShowPwd ? Theme.of(context).primaryColor : Colors.grey, + ), + ), + hintStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(153, 153, 153, 1)), + labelText: "密码", + isDense: true, + labelStyle: TextStyle(fontSize: 16.sp, color: const Color.fromRGBO(148, 163, 182, 1)), + ), + ), + SizedBox( + height: 12.h, + ), + InkWell( + onTap: toRegister, + child: Container( + margin: EdgeInsets.symmetric(vertical: 10.h), + decoration: BoxDecoration( + color: canLogin ? Theme.of(context).primaryColor : Colors.grey, + boxShadow: [ + BoxShadow( + color: const Color.fromRGBO(76, 199, 147, 0.5), + offset: Offset(4.w, 6.h), //阴影y轴偏移量 + blurRadius: 10, //阴影模糊程度 + spreadRadius: 0.5, //阴影扩散程度 + ) + ], + borderRadius: BorderRadius.all( + Radius.circular(8.w), + ), + ), + alignment: Alignment.center, + width: double.infinity, + height: 50.h, + child: Text( + '注 册', + style: TextStyle(fontSize: 16.sp, color: Colors.white), + ), + ), + ), + Row( + children: [ + Container( + width: 30.w, + padding: EdgeInsets.only(right: 10.w), + child: Checkbox( + activeColor: Colors.deepOrangeAccent, + checkColor: Colors.white, + value: readAgreement, + onChanged: (value) { + FocusScope.of(context).requestFocus(_pwdFocus); + FocusScope.of(context).requestFocus(_theFocus); + setState(() { + readAgreement = value ?? false; + }); + }, + ), + ), + InkWell( + onTap: () { + // RouterManager.router.navigateTo( + // context, + // '${RouterManager.agreementPath}?type=${AGREEMENT_KEY.USER_AGREEMENT.name}', + // transition: getTransition(), + // ); + }, + child: quickText('我已阅读', size: 11.sp), + ), + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); + }, + child: quickText( + '《用户协议》', + size: 12.sp, + color: Theme.of(context).primaryColor, + ), + ), + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); + }, + child: quickText( + '《隐私协议》', + size: 12.sp, + color:Theme.of(context).primaryColor, + ), + ), + ], + ), + ]), + ) + ], + ), + )), + Positioned( + top: MediaQuery.of(context).padding.top + 20.r, + left: 20.r, + child: InkWell( + onTap: () => Navigator.pop(context), + child: Icon(Icons.arrow_back_ios_new_rounded, color: Colors.white, size: 24.sp), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/making_school_asignment_app/lib/page/login_page/children/sys_protocol.dart b/making_school_asignment_app/lib/page/login_page/children/sys_protocol.dart new file mode 100644 index 0000000..61e7145 --- /dev/null +++ b/making_school_asignment_app/lib/page/login_page/children/sys_protocol.dart @@ -0,0 +1,250 @@ +import 'dart:io'; +import 'package:get/get.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; +import 'package:making_school_asignment_app/common/store/app_storage_key.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/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; + +class Protocol extends Dialog { + final BuildContext context; + const Protocol(this.context, {super.key}); + + @override + Widget build(BuildContext context) { + return Center( + child: Container( + width: isPad() ? 200.w : 260.w, + height: 400.h, + padding: EdgeInsets.symmetric(vertical: 16.h), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12.r), + ), + child: Column( + children: [ + quickText('用户协议与隐私政策', size: 15.sp, color: const Color.fromRGBO(37, 37, 37, 1), fontWeight: FontWeight.bold), + Expanded( + child: ListView( + physics: const BouncingScrollPhysics(), + padding: EdgeInsets.fromLTRB(16.w, 14.h, 16.w, 10.h), + children: [ + Text.rich(TextSpan(children: [ + TextSpan( + text: '感谢您选择点智学APP ! 我们非常重视您的个人信息和隐私保护。为了更好地保障您的个人权益,在您使用我们的产品前,请务必审慎阅读', + style: TextStyle(fontSize: 13.sp, color: const Color.fromRGBO(51, 51, 51, 1)), + ), + TextSpan( + text: '《隐私政策》', + style: TextStyle(fontSize: 13.sp, color: Theme.of(context).primaryColor), + recognizer: TapGestureRecognizer() + ..onTap = () async { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); + // RouterManager.router.navigateTo( + // context, + // '${RouterManager.agreementPath}?type=${AGREEMENT_KEY.PRIVACY_GREEMENT.name}', + // transition: getTransition(), + // ); + }, + ), + TextSpan( + text: '和', + style: TextStyle(fontSize: 13.sp, color: const Color.fromRGBO(51, 51, 51, 1)), + ), + TextSpan( + text: '《用户协议》', + style: TextStyle(fontSize: 13.sp, color: Theme.of(context).primaryColor), + recognizer: TapGestureRecognizer() + ..onTap = () async { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); + // RouterManager.router.navigateTo( + // context, + // '${RouterManager.agreementPath}?type=${AGREEMENT_KEY.USER_AGREEMENT.name}', + // transition: getTransition(), + // ); + }, + ), + TextSpan( + text: '内的所有条款,尤其是:1.我们对您的个人信息的收集/保存/使用/对外提供/保护等规则条款,以及您的用户权利等条款;2.约定我们的限制责任、免责条款;3.其他以颜色或加粗进行标识的重要条款。如您对以上协议有任何疑问,可通过发邮件至yuanxuanjiaoyu@gmail.com与我们联系。您点击"同意并继续”的行为即表示您已阅读完毕并同意以上协议的全部内容。如您同意以上协议内容,请点击"同意并继续”,开始使用我们的产品和服务!', + style: TextStyle(fontSize: 13.sp, color: const Color.fromRGBO(51, 51, 51, 1)), + ), + ])), + ], + ), + ), + SizedBox(height: 10.h), + Row( + children: [ + Expanded( + child: InkWell( + onTap: () { + exit(0); + }, + child: Container( + alignment: Alignment.center, + padding: EdgeInsets.only(top: 15.h), + decoration: BoxDecoration( + border: Border( + top: BorderSide(width: 0.5.r, color: const Color.fromRGBO(238, 238, 238, 1)), + right: BorderSide(width: 0.5.r, color: const Color.fromRGBO(238, 238, 238, 1)), + ), + ), + child: quickText('退出APP', size: 14.sp), + ), + ), + ), + Expanded( + child: InkWell( + onTap: () { + StorageService.to.write(AppStorageKey.privacyAgreement.value, true); + Navigator.of(context).pop(true); + }, + child: Container( + alignment: Alignment.center, + padding: EdgeInsets.only(top: 15.h), + decoration: BoxDecoration( + border: Border( + top: BorderSide(width: 0.5.r, color: const Color.fromRGBO(238, 238, 238, 1)), + ), + ), + child: quickText('同意并继续', color: Theme.of(context).primaryColor, size: 14.sp), + ), + ), + ) + ], + ), + ], + ), + ), + ); + } +} + +/// 系统协议 +Future sysProtocol(BuildContext context) async { + bool? sysProtocol = StorageService.to.hasData(AppStorageKey.privacyAgreement.value); + + if (!sysProtocol) { + return showDialog( + context: context, + barrierDismissible: false, + // useRootNavigator: false, + builder: (ctx) => Protocol(ctx), + ); + } +} + +/// 辅助阅读协议 +Future assistedReadingProtocol(BuildContext context) async { + var flag = await showDialog( + context: context, + barrierDismissible: false, + // useRootNavigator: false, + builder: (ctx) => const ProtocolAssistedGuidance(), + ); + print("点击返回值 :$flag"); + return flag ?? false; +} + +/// 协议辅助引导 +class ProtocolAssistedGuidance extends Dialog { + const ProtocolAssistedGuidance({super.key}); + + @override + Widget build(BuildContext context) { + return Center( + child: Container( + width: isPad() ? 216.w : 260.w, + height: 200.h, + padding: EdgeInsets.symmetric(horizontal: 4.w,vertical: 16.h), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12.r), + ), + child: Column( + children: [ + quickText('协议及政策阅读指引', size: 16.sp, color: const Color.fromRGBO(37, 37, 37, 1), fontWeight: FontWeight.bold), + Expanded( + child: ListView( + physics: const BouncingScrollPhysics(), + padding: EdgeInsets.fromLTRB(10.w, 14.h, 10.w, 10.h), + children: [ + Text.rich(TextSpan(children: [ + TextSpan( + text: '感谢您选择点智学,在使用当前APP服务之前,请仔细阅读', + style: TextStyle(fontSize: 13.sp, color: const Color.fromRGBO(51, 51, 51, 1)), + ), + TextSpan( + text: '《隐私政策》', + style: TextStyle(fontSize: 13.sp, color: Theme.of(context).primaryColor), + recognizer: TapGestureRecognizer() + ..onTap = () async { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); + }, + ), + TextSpan( + text: '和', + style: TextStyle(fontSize: 13.sp, color: const Color.fromRGBO(51, 51, 51, 1)), + ), + TextSpan( + text: '《用户协议》', + style: TextStyle(fontSize: 13.sp, color: Theme.of(context).primaryColor), + recognizer: TapGestureRecognizer() + ..onTap = () async { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); + }, + ), + TextSpan( + text: '如果你已经阅读并同意此协议及政策,请点击“同意并继续”开始使用。', + style: TextStyle(fontSize: 13.sp, color: const Color.fromRGBO(51, 51, 51, 1)), + ), + ])), + ], + ), + ), + SizedBox(height: 10.h), + Row( + children: [ + Expanded( + child: InkWell( + onTap: () => Navigator.of(context).pop(false), + child: Container( + alignment: Alignment.center, + padding: EdgeInsets.only(top: 15.h), + decoration: BoxDecoration( + border: Border( + top: BorderSide(width: 0.5.r, color: const Color.fromRGBO(238, 238, 238, 1)), + right: BorderSide(width: 0.5.r, color: const Color.fromRGBO(238, 238, 238, 1)), + ), + ), + child: quickText('拒绝', size: 14.sp), + ), + ), + ), + Expanded( + child: InkWell( + onTap: () => Navigator.of(context).pop(true), + child: Container( + alignment: Alignment.center, + padding: EdgeInsets.only(top: 15.h), + decoration: BoxDecoration( + border: Border( + top: BorderSide(width: 0.5.r, color: const Color.fromRGBO(238, 238, 238, 1)), + ), + ), + child: quickText('同意并继续', color: Theme.of(context).primaryColor, size: 15.sp), + ), + ), + ) + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/page/login_page/login_binding.dart b/making_school_asignment_app/lib/page/login_page/login_binding.dart similarity index 100% rename from lib/page/login_page/login_binding.dart rename to making_school_asignment_app/lib/page/login_page/login_binding.dart diff --git a/making_school_asignment_app/lib/page/login_page/login_logic.dart b/making_school_asignment_app/lib/page/login_page/login_logic.dart new file mode 100644 index 0000000..37674f3 --- /dev/null +++ b/making_school_asignment_app/lib/page/login_page/login_logic.dart @@ -0,0 +1,155 @@ +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; +import 'package:making_school_asignment_app/common/store/user_store.dart'; +import 'package:making_school_asignment_app/common/utils/app_upgrade/model/UpdateAppEvent.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/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/login_page/children/sys_protocol.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:making_school_asignment_app/common/store/app_storage_key.dart'; + +import 'login_state.dart'; + +class LoginLogic extends GetxController with RequestToolMixin { + final LoginState state = LoginState(); + + @override + void onInit() { + super.onInit(); + + /* state.userNameController = TextEditingController() + ..addListener(userNameListener); + state.passwordController = TextEditingController();*/ + + String account = StorageService.to.read(AppStorageKey.account.value) ?? ''; + String pwd = StorageService.to.read(AppStorageKey.pwd.value) ?? ''; + if (account != '' && pwd != '') { + state.userNameController.text = account; + state.passwordController.text = pwd; + state.keepPwd.value = true; + } + // state.userNameController.text = "AppleTester"; + // state.passwordController.text = "AppleTester123!"; + + // state.userNameController.text = "SZJY200504252"; + // state.passwordController.text = "504252"; + + state.pwdFocus = FocusNode(); + state.theFocus = FocusNode(); + getShowUserAdditionalFeatures(); // + } + + void userNameListener() { + String userName = state.userNameController.text; + int useNameLength = userName.length; + bool hasNameValNew = useNameLength > 0; + if (hasNameValNew != state.hasNameVal) state.hasNameVal = hasNameValNew; + const isProd = bool.fromEnvironment('dart.vm.product'); + if (!isProd && useNameLength == 11) { + state.passwordController.text = userName.substring(useNameLength - 6); + } + } + + void showPassword() { + state.isShowPwd.value = !state.isShowPwd.value; + } + + /// 前往登录 + void toLogin(BuildContext context, UpgradeLogic upgradeLogic) async { + if (!state.canLogin.value) return; + Utils.hideKeyboard(); + state.canLogin.value = false; + + void toMsg(msg, [bool error = true]) { + if (error) { + WidgetsBinding.instance.addPostFrameCallback((_) => ToastUtils.showError(msg)); + } else { + WidgetsBinding.instance.addPostFrameCallback((_) => ToastUtils.showInfo(msg)); + } + state.canLogin.value = true; + } + + String userName = state.userNameController.text.trim(); + String userPwd = state.passwordController.text.trim(); + if (userName == '') return toMsg('请填写用户账号'); + if (userPwd == '') return toMsg('请填写密码再试'); + if (!state.readAgreement.value) { + var consent = await assistedReadingProtocol(context); // 辅助阅读协议阅读引导 + if (!consent) return toMsg('请阅读用户协议、隐私协议'); + state.readAgreement.value = true; + } + + EasyLoading.show(status: 'loading...'); + + try { + /// 检查升级APP + if (userName != 'AppleTester' && const bool.fromEnvironment('dart.vm.product')) { + UpdateAppEvent? updateAppEvent = await upgradeLogic.getUpdateAppEvent(); + var upgrade = updateAppEvent?.upgrade ?? false; + if (upgrade) { + upgradeLogic.getAppUpgrade(Get.context ?? context); + return toMsg('请在升级APP后再次登陆', false); + } + } + await getClient().toLogin(userName, userPwd); + String? nameidentifier = UserStore.to.userInfo.value?.nameidentifier; + if (nameidentifier == null) { + throw Exception('用户信息无效,请重试'); + } + var data = await getClient().getUser(nameidentifier); + if (data == null) { + throw Exception('用户信息获取失败'); + } + UserStore.to.setUserDetailInfo(data); + + if (state.keepPwd.value) { + StorageService.to.write(AppStorageKey.account.value, userName); + StorageService.to.write(AppStorageKey.pwd.value, userPwd); + } + + Get.offAllNamed(Routes.startPage); + } catch (e) { + print('进来异常'); + UserStore.to.erase(); + StorageService.to.erase(); + if (e is Exception) { + try { + if (e is DioException && e.response?.data != null) { + Map? msg = e.response?.data['error']; + if (msg != null && msg["message"] != null) { + return toMsg(msg["message"]); + } + } + toMsg(e.toString().split(":")[1]); + return; + // ignore: empty_catches + } catch (e) {} + } + toMsg('登录失败,请重试'); + } finally { + state.canLogin.value = true; + EasyLoading.dismiss(); + } + } + + @override + void onClose() { + state.userNameController + ..removeListener(userNameListener) + ..dispose(); + state.passwordController.dispose(); + state.pwdFocus.dispose(); + state.theFocus.dispose(); + super.onClose(); + } + + /// 是否展示用户附加功能 + Future getShowUserAdditionalFeatures() async { + // state.showUserAdditionalFeatures.value = ; + } +} diff --git a/lib/page/login_page/login_state.dart b/making_school_asignment_app/lib/page/login_page/login_state.dart similarity index 60% rename from lib/page/login_page/login_state.dart rename to making_school_asignment_app/lib/page/login_page/login_state.dart index 5933131..7c96cd9 100644 --- a/lib/page/login_page/login_state.dart +++ b/making_school_asignment_app/lib/page/login_page/login_state.dart @@ -9,11 +9,12 @@ class LoginState { late final FocusNode pwdFocus; // 密码 late final FocusNode theFocus; //文本输入框控制器 - late final TextEditingController userNameController; - late final TextEditingController passwordController; + late TextEditingController userNameController = TextEditingController(); + late TextEditingController passwordController = TextEditingController(); bool hasNameVal = false; late RxBool isShowPwd = true.obs; late RxBool keepPwd = false.obs; late RxBool canLogin = true.obs; - late RxBool readAgreement = true.obs; + late RxBool readAgreement = false.obs; + late RxBool showUserAdditionalFeatures = false.obs; } diff --git a/making_school_asignment_app/lib/page/login_page/login_view.dart b/making_school_asignment_app/lib/page/login_page/login_view.dart new file mode 100644 index 0000000..964aa0a --- /dev/null +++ b/making_school_asignment_app/lib/page/login_page/login_view.dart @@ -0,0 +1,395 @@ +import 'package:get/get.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:making_school_asignment_app/common/const_text.dart'; +import 'package:making_school_asignment_app/common/utils/anti_shake_throttling.dart'; +import 'package:making_school_asignment_app/common/utils/app_upgrade/upgradeLogic.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/routes/app_pages.dart'; + +import 'children/sys_protocol.dart'; +import 'login_logic.dart'; + +class LoginPage extends StatefulWidget { + const LoginPage({super.key}); + + @override + State createState() => _LoginPageState(); +} + +class _LoginPageState extends State { + final logic = Get.find(); + final upgradeLogic = Get.find(); + final state = Get.find().state; + + @override + void initState() { + SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( + statusBarIconBrightness: Brightness.light, + statusBarColor: Colors.transparent, //状态栏背景颜色 + )); + + WidgetsBinding.instance.addPostFrameCallback((_) async { + await sysProtocol(context); + /// 为了发布各平台方便审核 不能再登陆页面直接弹出审核 + // await Future.delayed(Duration.zero, () => upgradeLogic.getAppUpgrade(context)); + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Utils.hideKeyboard(); + // FocusScope.of(context).requestFocus(state.theFocus); + }, + child: AnnotatedRegion( + value: const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + systemNavigationBarIconBrightness: Brightness.light, + statusBarIconBrightness: Brightness.light, + statusBarBrightness: Brightness.dark, + ), + child: Scaffold( + backgroundColor: Colors.white, + resizeToAvoidBottomInset: false, + body: Stack( + children: [ + Positioned( + top: 0, + left: 0, + child: Image.asset( + 'assets/images/logo_banner.png', + width: Get.width, + fit: BoxFit.fill, + )), + SingleChildScrollView( + child: Column( + children: [ + SizedBox( + height: 130.r, + ), + Container( + width: 77.w, + height: 77.w, + alignment: Alignment.center, + child: SizedBox( + height: 77.w, + width: 77.w, + child: Image.asset('assets/images/login_logo_icon.png', fit: BoxFit.cover), + ), + ), + Container( + margin: EdgeInsets.only(top: 90.r), + padding: EdgeInsets.only(top: 50.h, bottom: 16.h, left: 40.w, right: 40.w), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only(topLeft: Radius.circular(30.r), topRight: Radius.circular(30.r)), + /*boxShadow: const [ + BoxShadow( + color: Color.fromRGBO(46, 91, 255, 0.1), + offset: Offset.zero, //阴影y轴偏移量 + blurRadius: 100, //阴影模糊程度 + spreadRadius: 100, //阴影扩散程度 + ) + ],*/ + ), + child: Column(children: [ + Container( + padding: EdgeInsets.symmetric( + horizontal: 15.w, + ), + decoration: BoxDecoration( + color: Colors.transparent, + border: Border.all(width: 1.w, color: const Color(0xFF434343)), + borderRadius: BorderRadius.all(Radius.circular(17.w)), + ), + child: TextField( + controller: state.userNameController, + /* maxLines: 1, + maxLength: 20,*/ + textInputAction: TextInputAction.next, + onEditingComplete: () { + Get.focusScope?.nextFocus(); + // FocusScope.of(context).requestFocus(_pwdFocus); + }, + style: TextStyle( + color: const Color(0xFF434343), + fontSize: 14.sp, + ), + decoration: InputDecoration( + hintText: "请输入账号", + hintStyle: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF434343), + ), + // labelText: "账号", + labelStyle: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF434343), + ), + border: InputBorder.none, + isDense: true, + prefixIconConstraints: BoxConstraints( + minHeight: 10.w, + minWidth: 10.h, + ), + prefixIcon: Padding( + padding: EdgeInsets.only(right: 5.r), + child: Image.asset( + 'assets/images/login_account.png', + width: 15.r, + height: 15.r, + ), + ), + ), + ), + ), + SizedBox( + height: 20.r, + ), + Obx(() { + return Container( + padding: EdgeInsets.symmetric(horizontal: 15.w), + decoration: BoxDecoration( + color: Colors.transparent, + border: Border.all(width: 1.w, color: const Color(0xFF434343)), + borderRadius: BorderRadius.all(Radius.circular(17.w)), + ), + child: TextField( + focusNode: state.pwdFocus, + controller: state.passwordController, + keyboardType: TextInputType.number, + maxLines: 1, + obscureText: state.isShowPwd.value, + //隐藏密码显示 + // textInputAction: state.isShowPwd.value?TextInputAction.go:TextInputAction.next, + textInputAction: TextInputAction.send, + onSubmitted: (_) => easyThrottle('LOGIN_EASYTHROTTLE', () async{ + Utils.hideKeyboard(); + await Future.delayed(const Duration(milliseconds: 300)); + WidgetsBinding.instance.addPostFrameCallback((_) => logic.toLogin(context,upgradeLogic)); + }), + style: TextStyle( + color: const Color(0xFF434343), + fontSize: 14.sp, + ), + decoration: InputDecoration( + hintText: "请输入密码", + prefixIconConstraints: BoxConstraints( + minHeight: 10.w, + minWidth: 10.h, + ), + prefixIcon: Padding( + padding: EdgeInsets.only(right: 5.r), + child: Image.asset( + 'assets/images/login_pwd.png', + width: 15.r, + height: 15.r, + ), + ), + suffixIconConstraints: BoxConstraints( + minHeight: 10.w, + minWidth: 10.h, + ), + suffixIcon: InkWell( + onTap: () { + state.isShowPwd.value = !state.isShowPwd.value; + }, + child: Padding( + padding: EdgeInsets.only(right: 5.r), + child: Image.asset( + state.isShowPwd.value ? 'assets/images/eye_default.png' : 'assets/images/eye_active.png', + width: 15.r, + height: 15.r, + ), + ), + ), + hintStyle: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF434343), + ), + border: InputBorder.none, + // labelText: "密码", + isDense: true, + labelStyle: TextStyle( + fontSize: 14.sp, + color: Colors.white, + ), + ), + ), + ); + }), + SizedBox(height: 10.h), + Row( + children: [ + Expanded( + child: Row( + children: [ + Container( + width: 25.w, + padding: EdgeInsets.only(right: 0.w), + child: Obx(() { + return Transform.scale( + scale: 1.0, + child: Checkbox( + // activeColor: Colors.transparent, //去掉勾选时背景颜色 + + activeColor: Theme.of(context).primaryColor, + // checkColor: Colors.white, + value: state.keepPwd.value, + onChanged: (value) { + // Get.focusScope?.nextFocus(); + FocusScope.of(context).requestFocus(state.pwdFocus); + FocusScope.of(context).requestFocus(state.theFocus); + state.keepPwd.value = value ?? false; + }, + side: WidgetStateBorderSide.resolveWith( + (Set states) { + if (states.contains(WidgetState.selected)) { + //修改勾选时边框颜色为红色 + return BorderSide(width: 1.5.r, color: Theme.of(context).primaryColor); + } + //修改默认时边框颜色为绿色 + return BorderSide(width: 1.r, color: const Color(0xFF434343)); + }, + )), + ); + }), + ), + InkWell( + onTap: () { + Utils.hideKeyboard(); + Get.focusScope?.nextFocus(); + Get.focusScope?.nextFocus(); + FocusScope.of(context).requestFocus(state.pwdFocus); + FocusScope.of(context).requestFocus(state.theFocus); + state.keepPwd.value = !state.keepPwd.value; + }, + child: Text( + '记住密码', + style: TextStyle( + fontSize: 12.sp, + color: const Color(0xFF434343), + ), + ), + ), + ], + ), + ), + InkWell( + onTap: () => Get.toNamed(Routes.register), + child: quickText('账号注册', color: const Color(0xFF434343)), + ) + ], + ), + InkWell( + onTap: () => easyThrottle('LOGIN_EASYTHROTTLE', () async{ + Utils.hideKeyboard(); + await Future.delayed(Duration.zero); + WidgetsBinding.instance.addPostFrameCallback((_) => logic.toLogin(context,upgradeLogic)); + }), + child: Obx(() { + return Container( + margin: EdgeInsets.symmetric(vertical: 10.h), + decoration: BoxDecoration( + color: state.canLogin.value ? const Color(0xFF8C68FF) : const Color(0xFFdddddd), + /*boxShadow: [ + BoxShadow( + color: + const Color.fromRGBO(76, 199, 147, 0.5), + offset: Offset(6.w, 10.h), //阴影y轴偏移量 + blurRadius: 14, //阴影模糊程度 + spreadRadius: 0.5, //阴影扩散程度 + ) + ],*/ + borderRadius: BorderRadius.all( + Radius.circular(17.w), + ), + ), + alignment: Alignment.center, + width: double.infinity, + height: 50.h, + child: quickText('登 录', size: 18.sp, color: Colors.white)); + }), + ), + Row( + children: [ + Container( + width: 25.w, + padding: EdgeInsets.only(right: 0.w), + child: Obx(() { + return Transform.scale( + scale: 1.0, + child: Checkbox( + activeColor: Theme.of(context).primaryColor, + checkColor: Colors.white, + value: state.readAgreement.value, + onChanged: (value) { + Utils.hideKeyboard(); + /* FocusScope.of(context).requestFocus( + state.pwdFocus); + FocusScope.of(context).requestFocus( + state.theFocus);*/ + state.readAgreement.value = value ?? false; + }, + side: WidgetStateBorderSide.resolveWith( + (Set states) { + if (states.contains(WidgetState.selected)) { + //修改勾选时边框颜色为红色 + return BorderSide(width: 1.5.r, color: Theme.of(context).primaryColor); + } + //修改默认时边框颜色为绿色 + return BorderSide(width: 1.r, color: const Color(0xFF434343)); + }, + ), + ), + ); + }), + ), + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); + }, + child: quickText( + '请仔细阅读', + size: 11.sp, + ), + ), + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.USER_AGREEMENT.name}); + }, + child: Text( + '《用户协议》', + style: TextStyle(fontSize: 12.r, color: Theme.of(context).primaryColor), + ), + ), + InkWell( + onTap: () { + Get.toNamed(Routes.agreementPage, arguments: {"type": AGREEMENT_KEY.PRIVACY_GREEMENT.name}); + }, + child: quickText( + '《隐私协议》', + size: 12.sp, + color: Theme.of(context).primaryColor, + ), + ), + ], + ), + ]), + ) + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/page/work_page/work_binding.dart b/making_school_asignment_app/lib/page/work_page/work_binding.dart similarity index 100% rename from lib/page/work_page/work_binding.dart rename to making_school_asignment_app/lib/page/work_page/work_binding.dart diff --git a/making_school_asignment_app/lib/page/work_page/work_logic.dart b/making_school_asignment_app/lib/page/work_page/work_logic.dart new file mode 100644 index 0000000..719ec61 --- /dev/null +++ b/making_school_asignment_app/lib/page/work_page/work_logic.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/mixins/request_tool_mixin.dart'; + +import 'work_state.dart'; + +class WorkLogic extends GetxController with RequestToolMixin, GetTickerProviderStateMixin { + final WorkState state = WorkState(); + late TabController tabController; + @override + void onInit() { + super.onInit(); + state.tabIndex.value = 0; + tabController = TabController( + length: 2, + vsync: this, + ); + } + + @override + void onClose() { + tabController.dispose(); + super.onClose(); + } + + // @override + // void dispose() { + // super.dispose(); + // tabController.dispose(); + // } +} diff --git a/lib/page/home_page/children/read_over/read_over_state.dart b/making_school_asignment_app/lib/page/work_page/work_state.dart similarity index 70% rename from lib/page/home_page/children/read_over/read_over_state.dart rename to making_school_asignment_app/lib/page/work_page/work_state.dart index 1ca5173..f17b8cc 100644 --- a/lib/page/home_page/children/read_over/read_over_state.dart +++ b/making_school_asignment_app/lib/page/work_page/work_state.dart @@ -1,11 +1,10 @@ import 'package:get/get.dart'; -import 'package:school_asignment_app/common/job/work_student.dart'; +import 'package:making_school_asignment_app/common/job/work_student.dart'; -class ReadOverState { - ReadOverState() { +class WorkState { + WorkState() { ///Initialize variables } - int active = 1; late RxList workList = RxList(); late RxInt tabIndex = 0.obs; diff --git a/making_school_asignment_app/lib/page/work_page/work_view.dart b/making_school_asignment_app/lib/page/work_page/work_view.dart new file mode 100644 index 0000000..1449755 --- /dev/null +++ b/making_school_asignment_app/lib/page/work_page/work_view.dart @@ -0,0 +1,169 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/common/utils/utils.dart'; +import 'package:making_school_asignment_app/page/global_widget/my_text.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/read_over_logic.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/read_over_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/widget/annotate_list.dart'; +import 'package:making_school_asignment_app/page/home_page/children/student_work_detail/widget/job_condition_filter.dart'; +import 'package:making_school_asignment_app/routes/app_pages.dart'; +import 'package:syncfusion_flutter_datepicker/datepicker.dart'; + +import 'work_logic.dart'; + +class WorkPage extends StatefulWidget { + const WorkPage({super.key}); + + @override + State createState() => _WorkPageState(); +} + +class _WorkPageState extends State with AutomaticKeepAliveClientMixin { + final logic = Get.find(); + final state = Get.find().state; + + @override + bool get wantKeepAlive => true; + + @override + void initState() { + // TODO: implement initState + super.initState(); + } + + @override + Widget build(BuildContext context) { + super.build(context); + + return Scaffold( + backgroundColor: const Color.fromRGBO(244, 244, 244, 1), + body: OrientationBuilder( + builder: (BuildContext context, Orientation orientation) { + return Column( + children: [ + Container( + color: Colors.white, + margin: EdgeInsets.only(top: MediaQuery.of(context).padding.top), + padding: EdgeInsets.only(bottom: 9.h, top: 4.h), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + flex: 1, + child: Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.only(left: 10.w), + )), + Expanded( + flex: 4, + child: Container( + padding: EdgeInsets.symmetric(vertical: 2.h), + alignment: Alignment.center, + decoration: BoxDecoration( + color: const Color.fromRGBO(243, 243, 243, 1), + borderRadius: BorderRadius.circular(8.r), + ), + child: TabBar( + padding: EdgeInsets.zero, + indicatorPadding: EdgeInsets.zero, + indicatorWeight: 0, + labelPadding: EdgeInsets.symmetric(horizontal: 2.w), + controller: logic.tabController, + unselectedLabelStyle: TextStyle( + fontSize: 14.sp, + color: const Color.fromRGBO(69, 83, 100, 1), + ), + labelStyle: TextStyle( + fontSize: 14.sp, + color: const Color(0xFF4CC793), + ), + // labelColor: const Color.fromRGBO(45, 56, 76, 1), + indicator: const BoxDecoration(), + onTap: (index) { + state.tabIndex.value = index; + if (index == 1 && state.completedToRefresh) { + // 已阅卷 + // _refreshController2.callRefresh(); + state.completedToRefresh = false; + } + }, + tabs: [ + Tab( + iconMargin: EdgeInsets.zero, + height: 34.h, + child: Obx(() { + return Container( + width: 140.w, + alignment: Alignment.center, + decoration: BoxDecoration( + color: state.tabIndex.value == 0 ? const Color.fromRGBO(255, 255, 255, 1) : null, + borderRadius: BorderRadius.all(Radius.circular(8.r)), + ), + child: quickText( + '待批阅', + size: 14.sp, + color: state.tabIndex.value == 0 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1), + fontWeight: state.tabIndex.value == 0 ? FontWeight.bold : null, + ), + ); + }), + ), + Tab( + iconMargin: EdgeInsets.zero, + height: 34.h, + child: Obx(() { + return Container( + width: 140.w, + alignment: Alignment.center, + decoration: BoxDecoration( + color: state.tabIndex.value == 1 ? const Color.fromRGBO(255, 255, 255, 1) : null, + borderRadius: BorderRadius.all(Radius.circular(8.r)), + ), + child: quickText( + '已批阅', + size: 14.sp, + color: state.tabIndex.value == 1 ? Theme.of(context).primaryColor : const Color.fromRGBO(80, 94, 110, 1), + fontWeight: state.tabIndex.value == 1 ? FontWeight.bold : null, + ), + ); + }), + ), + ], + ), + ), + ), + Expanded( + flex: 1, + child: InkWell( + onTap: () { + Get.toNamed(Routes.studentHistoryWorkPage, arguments: {'page': 'set'}); + }, + child: Icon(const IconData(0xe63e, fontFamily: "AlibabaIcon"), color: const Color.fromRGBO(44, 48, 63, 1), size: 24.sp), + ), + ), + ], + ), + ), + Expanded( + child: Obx(() { + return AnnotateList( + tabIndex: state.tabIndex.value, + assessType: 1, + ); + }), + ), + ], + ); + }, + ), + ); + } + + @override + void dispose() { + Get.delete(); + super.dispose(); + } +} diff --git a/making_school_asignment_app/lib/routes/app_pages.dart b/making_school_asignment_app/lib/routes/app_pages.dart new file mode 100644 index 0000000..bbf1dad --- /dev/null +++ b/making_school_asignment_app/lib/routes/app_pages.dart @@ -0,0 +1,98 @@ +import 'dart:math'; + +import 'package:get/get.dart'; +import 'package:making_school_asignment_app/page/global_widget/other_page.dart'; +import 'package:making_school_asignment_app/page/global_widget/start_page.dart'; +import 'package:making_school_asignment_app/page/home_page/children/annotate_class/annotate_class_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/children/annotate_class/annotate_class_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/answer_trajectory/answer_trajectory_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/children/answer_trajectory/answer_trajectory_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/children/answer_trajectory_detail/answer_trajectory_detail_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/class_student/class_student_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/children/class_student/class_student_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/fav_student/fav_student_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/children/fav_student/fav_student_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/index.dart'; +import 'package:making_school_asignment_app/page/home_page/children/homework_review/configuration_files/zoom_logic.dart'; +import 'package:making_school_asignment_app/page/home_page/children/homework_review/index.dart'; +import 'package:making_school_asignment_app/page/home_page/children/job_report/job_report_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/children/job_report/job_report_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/children/knowledge_points_grasp/knowledge_points_grasp_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/children/knowledge_points_grasp_detail/knowledge_points_grasp_detail_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/my_info.dart'; +import 'package:making_school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/children/quick_data_check/quick_data_check_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/read_over/read_over_binding.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/student_history_work/student_history_work_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/children/student_history_work/student_history_work_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/student_personal/student_personal_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/children/student_personal/student_personal_view.dart'; +import 'package:making_school_asignment_app/page/home_page/children/student_work_detail/student_work_detail_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/children/student_work_detail/student_work_detail_view.dart'; +import 'package:making_school_asignment_app/page/home_page/home_binding.dart'; +import 'package:making_school_asignment_app/page/home_page/home_view.dart'; +import 'package:making_school_asignment_app/page/login_page/children/agreement_page.dart'; +import 'package:making_school_asignment_app/page/login_page/children/register.dart'; +import 'package:making_school_asignment_app/page/login_page/login_binding.dart'; +import 'package:making_school_asignment_app/page/login_page/login_view.dart'; +import 'package:making_school_asignment_app/page/work_page/work_binding.dart'; +import 'package:making_school_asignment_app/page/work_page/work_view.dart'; +part 'app_routes.dart'; + +abstract class AppPages { + static final pages = [ + GetPage(name: Routes.login, page: () => const LoginPage(), binding: LoginBinding(), transition: getTransition()), + GetPage(name: Routes.register, page: () => const Register(), transition: getTransition()), + GetPage(name: Routes.agreementPage, page: () => const AgreementPage(), binding: LoginBinding(), transition: getTransition()), + GetPage(name: Routes.home, page: () => const HomePage(), binding: HomeBinding(), transition: getTransition()), + GetPage( + name: Routes.startPage, + page: () => const StartPage(), + bindings: [ + HomeBinding(), + WorkBinding(), + StartPageIndexBinding(), + ], + transition: getTransition(), + ), + GetPage(name: Routes.myInfo, page: () => const MyInfo(), transition: getTransition()), + GetPage(name: Routes.work, page: () => const WorkPage(), binding: WorkBinding(), transition: getTransition()), + GetPage(name: Routes.otherPage, page: () => const OhterPage(), transition: getTransition()), + GetPage(name: Routes.readOverPage, page: () => const ReadOverPage(), binding: ReadOverBinding(), transition: getTransition()), + GetPage(name: Routes.studentHistoryWorkPage, page: () => const StudentHistoryWorkPage(), binding: StudentHistoryWorkBinding(), transition: getTransition()), + GetPage(name: Routes.classStudentPage, page: () => const ClassStudentPage(), binding: ClassStudentBinding(), transition: getTransition()), + GetPage(name: Routes.annotateClassPage, page: () => const AnnotateClassPage(), binding: AnnotateClassBinding(), transition: getTransition()), + GetPage(name: Routes.quickDataCheckPage, page: () => const QuickDataCheckPage(), binding: QuickDataCheckBinding(), transition: getTransition()), + GetPage(name: Routes.jobReportPage, page: () => const JobReportPage(), binding: JobReportBinding(), transition: getTransition()), + GetPage(name: Routes.studentPersonalPage, page: () => const StudentPersonalPage(), binding: StudentPersonalBinding(), transition: getTransition()), + GetPage(name: Routes.studentWorkDetailPage, page: () => const StudentWorkDetailPage(), binding: StudentWorkDetailBinding(), transition: getTransition()), + GetPage(name: Routes.knowledgePointsGraspPage, page: () => const KnowledgePointsGraspPage(), binding: KnowledgePointsGraspBinding(), transition: getTransition()), + GetPage(name: Routes.knowledgePointsGraspDetailPage, page: () => const KnowledgePointsGraspDetailPage(), binding: KnowledgePointsGraspDetailBinding(), transition: getTransition()), + GetPage(name: Routes.answerTrajectoryPage, page: () => const AnswerTrajectoryPage(), binding: AnswerTrajectoryBinding(), transition: getTransition()), + GetPage(name: Routes.answerTrajectoryDetailPage, page: () => const AnswerTrajectoryDetailPage(), binding: AnswerTrajectoryDetailBinding(), transition: getTransition()), + // 批阅主页(作业、考试) + GetPage(name: Routes.reviewHomework, page: () => const HomeworkReview(), bindings: [HomeworkReviewBinding(), HomeworkReviewZoomBinding()], transition: getTransition()), + // GetPage(name: Routes.reviewExam, page: () => const HomeworkReview(), bindings: [HomeworkReviewBinding(), HomeworkReviewZoomBinding()], transition: getTransition()), + GetPage(name: Routes.favStudentPage, page: () => const FavStudentPage(), binding: FavStudentBinding(), transition: getTransition()), + ]; +} + +/// 获取页面随机跳转 +Transition getTransition() { + try { + List transitions = Transition.values; + return transitions[getRandomNumbers(0, transitions.length - 1)]; + } catch (e) { + return getTransition(); + } +} + +/// 获取指定范围的随机数 +int getRandomNumbers(int minNumber, int maxNumber) { + int next(int min, int max) => min + Random().nextInt(max - min); + return next(minNumber, maxNumber); +} diff --git a/lib/routes/app_routes.dart b/making_school_asignment_app/lib/routes/app_routes.dart similarity index 69% rename from lib/routes/app_routes.dart rename to making_school_asignment_app/lib/routes/app_routes.dart index d83db38..12e5d70 100644 --- a/lib/routes/app_routes.dart +++ b/making_school_asignment_app/lib/routes/app_routes.dart @@ -2,6 +2,7 @@ part of 'app_pages.dart'; abstract class Routes { static const login = '/login'; + static const register = '/register'; static const agreementPage = '/agreementPage'; static const home = '/home'; static const startPage = '/startPage'; @@ -18,4 +19,10 @@ abstract class Routes { static const studentWorkDetailPage = '/studentWorkDetailPage'; static const knowledgePointsGraspPage = '/knowledgePointsGraspPage'; static const knowledgePointsGraspDetailPage = '/knowledgePointsGraspDetailPage'; -} \ No newline at end of file + static const answerTrajectoryPage = '/answerTrajectoryPage'; + static const answerTrajectoryDetailPage = '/answerTrajectoryDetailPage'; + // 批阅主页 + static const reviewHomework = '/review/reviewHomework'; // 作业批阅 + static const reviewExam = '/review/reviewExam'; // 考试批阅 + static const favStudentPage = '/favStudentPage'; // 收藏夹 +} diff --git a/making_school_asignment_app/linux/.gitignore b/making_school_asignment_app/linux/.gitignore new file mode 100644 index 0000000..d3896c9 --- /dev/null +++ b/making_school_asignment_app/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/making_school_asignment_app/linux/CMakeLists.txt b/making_school_asignment_app/linux/CMakeLists.txt new file mode 100644 index 0000000..068efa5 --- /dev/null +++ b/making_school_asignment_app/linux/CMakeLists.txt @@ -0,0 +1,145 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "making_school_asignment_app") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.yuanxuan.making_school_asignment_app") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/making_school_asignment_app/linux/flutter/CMakeLists.txt b/making_school_asignment_app/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000..d5bd016 --- /dev/null +++ b/making_school_asignment_app/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/making_school_asignment_app/linux/flutter/generated_plugin_registrant.cc b/making_school_asignment_app/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..f6f23bf --- /dev/null +++ b/making_school_asignment_app/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); +} diff --git a/making_school_asignment_app/linux/flutter/generated_plugin_registrant.h b/making_school_asignment_app/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/making_school_asignment_app/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/making_school_asignment_app/linux/flutter/generated_plugins.cmake b/making_school_asignment_app/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..f16b4c3 --- /dev/null +++ b/making_school_asignment_app/linux/flutter/generated_plugins.cmake @@ -0,0 +1,24 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + url_launcher_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/making_school_asignment_app/linux/main.cc b/making_school_asignment_app/linux/main.cc new file mode 100644 index 0000000..e7c5c54 --- /dev/null +++ b/making_school_asignment_app/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/making_school_asignment_app/linux/my_application.cc b/making_school_asignment_app/linux/my_application.cc new file mode 100644 index 0000000..dcfcc75 --- /dev/null +++ b/making_school_asignment_app/linux/my_application.cc @@ -0,0 +1,124 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "making_school_asignment_app"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "making_school_asignment_app"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/making_school_asignment_app/linux/my_application.h b/making_school_asignment_app/linux/my_application.h new file mode 100644 index 0000000..72271d5 --- /dev/null +++ b/making_school_asignment_app/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/making_school_asignment_app/macos/.gitignore b/making_school_asignment_app/macos/.gitignore new file mode 100644 index 0000000..746adbb --- /dev/null +++ b/making_school_asignment_app/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/making_school_asignment_app/macos/Flutter/Flutter-Debug.xcconfig b/making_school_asignment_app/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000..4b81f9b --- /dev/null +++ b/making_school_asignment_app/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/making_school_asignment_app/macos/Flutter/Flutter-Release.xcconfig b/making_school_asignment_app/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000..5caa9d1 --- /dev/null +++ b/making_school_asignment_app/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/making_school_asignment_app/macos/Flutter/GeneratedPluginRegistrant.swift b/making_school_asignment_app/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000..ee64873 --- /dev/null +++ b/making_school_asignment_app/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,28 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import app_installer +import app_settings +import auto_updater_macos +import connectivity_plus +import device_info_plus +import package_info_plus +import path_provider_foundation +import sqflite +import url_launcher_macos + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + AppInstallerPlugin.register(with: registry.registrar(forPlugin: "AppInstallerPlugin")) + AppSettingsPlugin.register(with: registry.registrar(forPlugin: "AppSettingsPlugin")) + AutoUpdaterMacosPlugin.register(with: registry.registrar(forPlugin: "AutoUpdaterMacosPlugin")) + ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) + DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) +} diff --git a/making_school_asignment_app/macos/Podfile b/making_school_asignment_app/macos/Podfile new file mode 100644 index 0000000..c795730 --- /dev/null +++ b/making_school_asignment_app/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/making_school_asignment_app/macos/Runner.xcodeproj/project.pbxproj b/making_school_asignment_app/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..ddfbd95 --- /dev/null +++ b/making_school_asignment_app/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,705 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* making_school_asignment_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "making_school_asignment_app.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* making_school_asignment_app.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* making_school_asignment_app.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.yuanxuan.makingSchoolAsignmentApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/making_school_asignment_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/making_school_asignment_app"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.yuanxuan.makingSchoolAsignmentApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/making_school_asignment_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/making_school_asignment_app"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.yuanxuan.makingSchoolAsignmentApp.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/making_school_asignment_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/making_school_asignment_app"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/making_school_asignment_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/making_school_asignment_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/making_school_asignment_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/making_school_asignment_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/making_school_asignment_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..ed2a4ea --- /dev/null +++ b/making_school_asignment_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/making_school_asignment_app/macos/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from ios/Runner.xcworkspace/contents.xcworkspacedata rename to making_school_asignment_app/macos/Runner.xcworkspace/contents.xcworkspacedata diff --git a/making_school_asignment_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/making_school_asignment_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/making_school_asignment_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/making_school_asignment_app/macos/Runner/AppDelegate.swift b/making_school_asignment_app/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000..d53ef64 --- /dev/null +++ b/making_school_asignment_app/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a2ec33f --- /dev/null +++ b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000..3caf642 Binary files /dev/null and b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000..b479756 Binary files /dev/null and b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000..c20ff1f Binary files /dev/null and b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000..8585536 Binary files /dev/null and b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 0000000..d4728f7 Binary files /dev/null and b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000..d087982 Binary files /dev/null and b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000..8449ae1 Binary files /dev/null and b/making_school_asignment_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/making_school_asignment_app/macos/Runner/Base.lproj/MainMenu.xib b/making_school_asignment_app/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..80e867a --- /dev/null +++ b/making_school_asignment_app/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/making_school_asignment_app/macos/Runner/Configs/AppInfo.xcconfig b/making_school_asignment_app/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000..938cf22 --- /dev/null +++ b/making_school_asignment_app/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = making_school_asignment_app + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.yuanxuan.makingSchoolAsignmentApp + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2024 com.yuanxuan. All rights reserved. diff --git a/making_school_asignment_app/macos/Runner/Configs/Debug.xcconfig b/making_school_asignment_app/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000..36b0fd9 --- /dev/null +++ b/making_school_asignment_app/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/making_school_asignment_app/macos/Runner/Configs/Release.xcconfig b/making_school_asignment_app/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000..dff4f49 --- /dev/null +++ b/making_school_asignment_app/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/making_school_asignment_app/macos/Runner/Configs/Warnings.xcconfig b/making_school_asignment_app/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000..42bcbf4 --- /dev/null +++ b/making_school_asignment_app/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/making_school_asignment_app/macos/Runner/DebugProfile.entitlements b/making_school_asignment_app/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000..dddb8a3 --- /dev/null +++ b/making_school_asignment_app/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/making_school_asignment_app/macos/Runner/Info.plist b/making_school_asignment_app/macos/Runner/Info.plist new file mode 100644 index 0000000..4789daa --- /dev/null +++ b/making_school_asignment_app/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/making_school_asignment_app/macos/Runner/MainFlutterWindow.swift b/making_school_asignment_app/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000..3cc05eb --- /dev/null +++ b/making_school_asignment_app/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/making_school_asignment_app/macos/Runner/Release.entitlements b/making_school_asignment_app/macos/Runner/Release.entitlements new file mode 100644 index 0000000..852fa1a --- /dev/null +++ b/making_school_asignment_app/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/making_school_asignment_app/macos/RunnerTests/RunnerTests.swift b/making_school_asignment_app/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..61f3bd1 --- /dev/null +++ b/making_school_asignment_app/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/pubspec.yaml b/making_school_asignment_app/pubspec.yaml similarity index 75% rename from pubspec.yaml rename to making_school_asignment_app/pubspec.yaml index 3548ccc..96fcf85 100644 --- a/pubspec.yaml +++ b/making_school_asignment_app/pubspec.yaml @@ -1,8 +1,8 @@ -name: school_asignment_app -description: A new Flutter project. +name: making_school_asignment_app +description: "A new Flutter project." # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: "none" # Remove this line if you wish to publish to pub.dev +publish_to: 'none' # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 @@ -16,10 +16,10 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.0+1 +version: 1.0.5+6 environment: - sdk: ">=3.0.1 <4.0.0" + sdk: '>=3.4.1 <4.0.0' # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -35,83 +35,110 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 + cupertino_icons: ^1.0.6 # 路由、依赖、状态插件 - get: ^4.6.5 + get: ^4.7.2 # loading插件 flutter_easyloading: ^3.0.5 # 日志插件 - logger: ^1.1.0 + logger: ^2.3.0 # 屏幕尺寸计算插件 - flutter_screenutil: 5.7.0 +# flutter_screenutil: 5.9.1 + flutter_screenutil: 5.0.0+2 # http请求插件 dio: ^5.4.2+1 # 网络缓存图片 cached_network_image: ^3.2.1 # 上拉加载和下拉刷新的组件 flutter_easyrefresh: ^2.2.2 - photo_view: ^0.14.0 + photo_view: ^0.15.0 # 加密验签插件,支持SHA MD5 HMAC crypto: ^3.0.2 # 获取app版本号 - package_info: ^2.0.2 + package_info_plus: ^8.0.0 # 网络监控 - connectivity_plus: ^3.0.6 + connectivity_plus: ^6.0.3 # toast组件用于系统尚未初始化完成时 fluttertoast: ^8.0.9 # functional_widget_annotation: ^0.10.0 - flutter_widget_from_html_core: ^0.10.3 + flutter_widget_from_html_core: ^0.14.12 # APP内存及本地存储插件 get_storage: ^2.0.3 + zoom_widget: ^2.0.1 # start retrofit请求封装 - json_annotation: ^4.8.1 retrofit: ^4.1.0 + json_annotation: ^4.9.0 # end retrofit请求封装 # 进度条 percent_indicator: ^4.2.3 badges: ^3.1.2 # 图表 - fl_chart: ^0.62.0 - data_table_2: ^2.5.10 - flutter_staggered_grid_view: ^0.6.2 + fl_chart: ^0.68.0 + data_table_2: 2.5.10 + flutter_staggered_grid_view: ^0.7.0 dropdown_button2: ^2.3.9 - syncfusion_flutter_datepicker: ^21.2.10 + syncfusion_flutter_datepicker: ^25.2.5 + easy_debounce: ^2.0.3 # 防抖节流 + flutter_hooks: ^0.20.5 + flutter_spinkit: ^5.2.1 + event_bus: ^2.0.0 + path_provider: ^2.1.3 + uuid: ^3.0.7 + flutter_echarts: ^2.4.0 + # 饼图 + flutter_echart: ^2.0.0 + url_launcher: ^6.1.11 + app_installer: ^1.1.0 + auto_updater: ^0.2.1 + permission_handler: ^11.3.1 + flutter_distributor: ^0.4.5 + flutter_native_splash: ^2.4.1 + icons_launcher: ^2.1.7 + app_settings: ^5.1.1 + device_info_plus: ^11.1.0 + auto_size_text: ^3.0.0 + +# dependency_overrides: +# meta: ^1.15.0 dev_dependencies: flutter_test: sdk: flutter - retrofit_generator: ^7.0.8 - build_runner: ^2.4.9 - json_serializable: ^6.3.1 - + retrofit_generator: ^8.1.0 + build_runner: ^2.4.10 + json_serializable: ^6.6.2 + # 分离样式 + functional_widget: ^0.10.2 # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^2.0.0 + flutter_lints: ^3.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter packages. flutter: + # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg assets: - assets/images/ - assets/images/2.0x/ - assets/images/3.0x/ - assets/images/4.0x/ + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware @@ -124,9 +151,10 @@ flutter: # list giving the asset and other descriptors for the font. For # example: fonts: - - family: AlibabaIcon - fonts: - - asset: assets/icons/iconfont.ttf + - family: AlibabaIcon + fonts: + - asset: assets/icons/iconfont.ttf + # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf @@ -140,3 +168,11 @@ flutter: # # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages + +icons_launcher: + platforms: + android: + enable: false + ios: + enable: true + image_path: "assets/images/logo_splash.png" \ No newline at end of file diff --git a/test/widget_test.dart b/making_school_asignment_app/test/widget_test.dart similarity index 94% rename from test/widget_test.dart rename to making_school_asignment_app/test/widget_test.dart index e1a7acc..4483744 100644 --- a/test/widget_test.dart +++ b/making_school_asignment_app/test/widget_test.dart @@ -8,7 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:school_asignment_app/main.dart'; +import 'package:making_school_asignment_app/main.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { diff --git a/making_school_asignment_app/web/favicon.png b/making_school_asignment_app/web/favicon.png new file mode 100644 index 0000000..c20ff1f Binary files /dev/null and b/making_school_asignment_app/web/favicon.png differ diff --git a/making_school_asignment_app/web/icons/Icon-192.png b/making_school_asignment_app/web/icons/Icon-192.png new file mode 100644 index 0000000..a5bd17e Binary files /dev/null and b/making_school_asignment_app/web/icons/Icon-192.png differ diff --git a/making_school_asignment_app/web/icons/Icon-512.png b/making_school_asignment_app/web/icons/Icon-512.png new file mode 100644 index 0000000..d087982 Binary files /dev/null and b/making_school_asignment_app/web/icons/Icon-512.png differ diff --git a/making_school_asignment_app/web/icons/Icon-maskable-192.png b/making_school_asignment_app/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..a5bd17e Binary files /dev/null and b/making_school_asignment_app/web/icons/Icon-maskable-192.png differ diff --git a/making_school_asignment_app/web/icons/Icon-maskable-512.png b/making_school_asignment_app/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d087982 Binary files /dev/null and b/making_school_asignment_app/web/icons/Icon-maskable-512.png differ diff --git a/making_school_asignment_app/web/index.html b/making_school_asignment_app/web/index.html new file mode 100644 index 0000000..29014c6 --- /dev/null +++ b/making_school_asignment_app/web/index.html @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + + + making_school_asignment_app + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/making_school_asignment_app/web/manifest.json b/making_school_asignment_app/web/manifest.json new file mode 100644 index 0000000..162479b --- /dev/null +++ b/making_school_asignment_app/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "making_school_asignment_app", + "short_name": "making_school_asignment_app", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/making_school_asignment_app/windows/.gitignore b/making_school_asignment_app/windows/.gitignore new file mode 100644 index 0000000..d492d0d --- /dev/null +++ b/making_school_asignment_app/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/making_school_asignment_app/windows/CMakeLists.txt b/making_school_asignment_app/windows/CMakeLists.txt new file mode 100644 index 0000000..5732e21 --- /dev/null +++ b/making_school_asignment_app/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(making_school_asignment_app LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "making_school_asignment_app") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/making_school_asignment_app/windows/flutter/CMakeLists.txt b/making_school_asignment_app/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000..903f489 --- /dev/null +++ b/making_school_asignment_app/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/making_school_asignment_app/windows/flutter/generated_plugin_registrant.cc b/making_school_asignment_app/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..a62c1dd --- /dev/null +++ b/making_school_asignment_app/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,23 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + AutoUpdaterWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("AutoUpdaterWindowsPluginCApi")); + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); + PermissionHandlerWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); +} diff --git a/making_school_asignment_app/windows/flutter/generated_plugin_registrant.h b/making_school_asignment_app/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..dc139d8 --- /dev/null +++ b/making_school_asignment_app/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/making_school_asignment_app/windows/flutter/generated_plugins.cmake b/making_school_asignment_app/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000..1a3c9b6 --- /dev/null +++ b/making_school_asignment_app/windows/flutter/generated_plugins.cmake @@ -0,0 +1,27 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + auto_updater_windows + connectivity_plus + permission_handler_windows + url_launcher_windows +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/making_school_asignment_app/windows/packaging/exe/make_config.yaml b/making_school_asignment_app/windows/packaging/exe/make_config.yaml new file mode 100644 index 0000000..049374b --- /dev/null +++ b/making_school_asignment_app/windows/packaging/exe/make_config.yaml @@ -0,0 +1,12 @@ +# The value of AppId uniquely identifies this application. +# Do not use the same AppId value in installers for other applications. +app_id: 9EBCC58D-39D5-4A4A-92B6-966DFFD6CA22 +publisher: LeanFlutter +publisher_url: https://github.com/leanflutter/flutter_distributor +display_name: 点智学 +create_desktop_icon: true +# See: https://jrsoftware.org/ishelp/index.php?topic=setup_defaultdirname +# install_dir_name: "D:\\HELLO-WORLD" +locales: + - en + - zh \ No newline at end of file diff --git a/making_school_asignment_app/windows/runner/CMakeLists.txt b/making_school_asignment_app/windows/runner/CMakeLists.txt new file mode 100644 index 0000000..394917c --- /dev/null +++ b/making_school_asignment_app/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/making_school_asignment_app/windows/runner/Runner.rc b/making_school_asignment_app/windows/runner/Runner.rc new file mode 100644 index 0000000..6af7114 --- /dev/null +++ b/making_school_asignment_app/windows/runner/Runner.rc @@ -0,0 +1,129 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.yuanxuan" "\0" + VALUE "FileDescription", "making_school_asignment_app" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "making_school_asignment_app" "\0" + VALUE "LegalCopyright", "Copyright (C) 2024 com.yuanxuan. All rights reserved." "\0" + VALUE "OriginalFilename", "making_school_asignment_app.exe" "\0" + VALUE "ProductName", "making_school_asignment_app" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// WinSparkle +// + +// And verify signature using DSA public key: +DSAPub DSAPEM "./../../dsa_pub.pem" diff --git a/making_school_asignment_app/windows/runner/flutter_window.cpp b/making_school_asignment_app/windows/runner/flutter_window.cpp new file mode 100644 index 0000000..955ee30 --- /dev/null +++ b/making_school_asignment_app/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/making_school_asignment_app/windows/runner/flutter_window.h b/making_school_asignment_app/windows/runner/flutter_window.h new file mode 100644 index 0000000..6da0652 --- /dev/null +++ b/making_school_asignment_app/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/making_school_asignment_app/windows/runner/main.cpp b/making_school_asignment_app/windows/runner/main.cpp new file mode 100644 index 0000000..0f3bd19 --- /dev/null +++ b/making_school_asignment_app/windows/runner/main.cpp @@ -0,0 +1,44 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + // Win32Window::Size size(1280, 720); + Win32Window::Size size(700, 900); + if (!window.Create(L"", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/making_school_asignment_app/windows/runner/resource.h b/making_school_asignment_app/windows/runner/resource.h new file mode 100644 index 0000000..66a65d1 --- /dev/null +++ b/making_school_asignment_app/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/making_school_asignment_app/windows/runner/resources/app_icon.ico b/making_school_asignment_app/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000..5248030 Binary files /dev/null and b/making_school_asignment_app/windows/runner/resources/app_icon.ico differ diff --git a/making_school_asignment_app/windows/runner/runner.exe.manifest b/making_school_asignment_app/windows/runner/runner.exe.manifest new file mode 100644 index 0000000..a42ea76 --- /dev/null +++ b/making_school_asignment_app/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/making_school_asignment_app/windows/runner/utils.cpp b/making_school_asignment_app/windows/runner/utils.cpp new file mode 100644 index 0000000..3a0b465 --- /dev/null +++ b/making_school_asignment_app/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + unsigned int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/making_school_asignment_app/windows/runner/utils.h b/making_school_asignment_app/windows/runner/utils.h new file mode 100644 index 0000000..3879d54 --- /dev/null +++ b/making_school_asignment_app/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/making_school_asignment_app/windows/runner/win32_window.cpp b/making_school_asignment_app/windows/runner/win32_window.cpp new file mode 100644 index 0000000..60608d0 --- /dev/null +++ b/making_school_asignment_app/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/making_school_asignment_app/windows/runner/win32_window.h b/making_school_asignment_app/windows/runner/win32_window.h new file mode 100644 index 0000000..e901dde --- /dev/null +++ b/making_school_asignment_app/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 9917f15..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,991 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 - url: "https://pub.dev" - source: hosted - version: "64.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" - url: "https://pub.dev" - source: hosted - version: "6.2.0" - args: - dependency: transitive - description: - name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 - url: "https://pub.dev" - source: hosted - version: "2.4.2" - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - badges: - dependency: "direct main" - description: - name: badges - sha256: a7b6bbd60dce418df0db3058b53f9d083c22cdb5132a052145dc267494df0b84 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - build: - dependency: transitive - description: - name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - build_config: - dependency: transitive - description: - name: build_config - sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 - url: "https://pub.dev" - source: hosted - version: "1.1.1" - build_daemon: - dependency: transitive - description: - name: build_daemon - sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" - url: "https://pub.dev" - source: hosted - version: "4.0.1" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - build_runner: - dependency: "direct dev" - description: - name: build_runner - sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" - url: "https://pub.dev" - source: hosted - version: "2.4.9" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" - url: "https://pub.dev" - source: hosted - version: "7.3.0" - built_collection: - dependency: transitive - description: - name: built_collection - sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" - url: "https://pub.dev" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - sha256: fedde275e0a6b798c3296963c5cd224e3e1b55d0e478d5b7e65e6b540f363a0e - url: "https://pub.dev" - source: hosted - version: "8.9.1" - cached_network_image: - dependency: "direct main" - description: - name: cached_network_image - sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f" - url: "https://pub.dev" - source: hosted - version: "3.3.1" - cached_network_image_platform_interface: - dependency: transitive - description: - name: cached_network_image_platform_interface - sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f" - url: "https://pub.dev" - source: hosted - version: "4.0.0" - cached_network_image_web: - dependency: transitive - description: - name: cached_network_image_web - sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - characters: - dependency: transitive - description: - name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" - url: "https://pub.dev" - source: hosted - version: "1.3.0" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff - url: "https://pub.dev" - source: hosted - version: "2.0.3" - clock: - dependency: transitive - description: - name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dev" - source: hosted - version: "1.1.1" - code_builder: - dependency: transitive - description: - name: code_builder - sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 - url: "https://pub.dev" - source: hosted - version: "4.10.0" - collection: - dependency: transitive - description: - name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" - url: "https://pub.dev" - source: hosted - version: "1.17.1" - connectivity_plus: - dependency: "direct main" - description: - name: connectivity_plus - sha256: b74247fad72c171381dbe700ca17da24deac637ab6d43c343b42867acb95c991 - url: "https://pub.dev" - source: hosted - version: "3.0.6" - connectivity_plus_platform_interface: - dependency: transitive - description: - name: connectivity_plus_platform_interface - sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a - url: "https://pub.dev" - source: hosted - version: "1.2.4" - convert: - dependency: transitive - description: - name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" - url: "https://pub.dev" - source: hosted - version: "3.1.1" - crypto: - dependency: "direct main" - description: - name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab - url: "https://pub.dev" - source: hosted - version: "3.0.3" - csslib: - dependency: transitive - description: - name: csslib - sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d - url: "https://pub.dev" - source: hosted - version: "1.0.6" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" - url: "https://pub.dev" - source: hosted - version: "2.3.6" - data_table_2: - dependency: "direct main" - description: - name: data_table_2 - sha256: e403de6d9a58dddf27700114b614ea8ea5aa8442d7fbdfbe8b3d11b0512e7a49 - url: "https://pub.dev" - source: hosted - version: "2.5.12" - dbus: - dependency: transitive - description: - name: dbus - sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" - url: "https://pub.dev" - source: hosted - version: "0.7.10" - dio: - dependency: "direct main" - description: - name: dio - sha256: "0978e9a3e45305a80a7210dbeaf79d6ee8bee33f70c8e542dc654c952070217f" - url: "https://pub.dev" - source: hosted - version: "5.4.2+1" - dropdown_button2: - dependency: "direct main" - description: - name: dropdown_button2 - sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1 - url: "https://pub.dev" - source: hosted - version: "2.3.9" - equatable: - dependency: transitive - description: - name: equatable - sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 - url: "https://pub.dev" - source: hosted - version: "2.0.5" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - ffi: - dependency: transitive - description: - name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - file: - dependency: transitive - description: - name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - fl_chart: - dependency: "direct main" - description: - name: fl_chart - sha256: "48a1b69be9544e2b03d9a8e843affd89e43f3194c9248776222efcb4206bb1ec" - url: "https://pub.dev" - source: hosted - version: "0.62.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_cache_manager: - dependency: transitive - description: - name: flutter_cache_manager - sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" - url: "https://pub.dev" - source: hosted - version: "3.3.1" - flutter_easyloading: - dependency: "direct main" - description: - name: flutter_easyloading - sha256: ba21a3c883544e582f9cc455a4a0907556714e1e9cf0eababfcb600da191d17c - url: "https://pub.dev" - source: hosted - version: "3.0.5" - flutter_easyrefresh: - dependency: "direct main" - description: - name: flutter_easyrefresh - sha256: "5d161ee5dcac34da9065116568147d742dd25fb9bff3b10024d9054b195087ad" - url: "https://pub.dev" - source: hosted - version: "2.2.2" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 - url: "https://pub.dev" - source: hosted - version: "2.0.3" - flutter_localizations: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_screenutil: - dependency: "direct main" - description: - name: flutter_screenutil - sha256: "0a122936b450324cbdfd51be0819cc6fcebb093eb65585e9cd92263f7a1a8a39" - url: "https://pub.dev" - source: hosted - version: "5.7.0" - flutter_spinkit: - dependency: transitive - description: - name: flutter_spinkit - sha256: d2696eed13732831414595b98863260e33e8882fc069ee80ec35d4ac9ddb0472 - url: "https://pub.dev" - source: hosted - version: "5.2.1" - flutter_staggered_grid_view: - dependency: "direct main" - description: - name: flutter_staggered_grid_view - sha256: "1312314293acceb65b92754298754801b0e1f26a1845833b740b30415bbbcf07" - url: "https://pub.dev" - source: hosted - version: "0.6.2" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_widget_from_html_core: - dependency: "direct main" - description: - name: flutter_widget_from_html_core - sha256: "22140caa191cb4bba0fe4d5e4ad875c7e8a9ba47d61517f56d733019cf76396d" - url: "https://pub.dev" - source: hosted - version: "0.10.6" - fluttertoast: - dependency: "direct main" - description: - name: fluttertoast - sha256: dfdde255317af381bfc1c486ed968d5a43a2ded9c931e87cbecd88767d6a71c1 - url: "https://pub.dev" - source: hosted - version: "8.2.4" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" - functional_widget_annotation: - dependency: "direct main" - description: - name: functional_widget_annotation - sha256: f0612079cb7e226b7be32b473bdaf85fe680370886c0c13ea69a102ccc17a0c7 - url: "https://pub.dev" - source: hosted - version: "0.10.0" - get: - dependency: "direct main" - description: - name: get - sha256: "2ba20a47c8f1f233bed775ba2dd0d3ac97b4cf32fc17731b3dfc672b06b0e92a" - url: "https://pub.dev" - source: hosted - version: "4.6.5" - get_storage: - dependency: "direct main" - description: - name: get_storage - sha256: "39db1fffe779d0c22b3a744376e86febe4ade43bf65e06eab5af707dc84185a2" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - glob: - dependency: transitive - description: - name: glob - sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - graphs: - dependency: transitive - description: - name: graphs - sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 - url: "https://pub.dev" - source: hosted - version: "2.3.1" - html: - dependency: transitive - description: - name: html - sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" - url: "https://pub.dev" - source: hosted - version: "0.15.4" - http: - dependency: transitive - description: - name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - intl: - dependency: transitive - description: - name: intl - sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 - url: "https://pub.dev" - source: hosted - version: "0.18.0" - io: - dependency: transitive - description: - name: io - sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" - url: "https://pub.dev" - source: hosted - version: "1.0.4" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" - json_annotation: - dependency: "direct main" - description: - name: json_annotation - sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 - url: "https://pub.dev" - source: hosted - version: "4.8.1" - json_serializable: - dependency: "direct dev" - description: - name: json_serializable - sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969 - url: "https://pub.dev" - source: hosted - version: "6.7.1" - lints: - dependency: transitive - description: - name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - logger: - dependency: "direct main" - description: - name: logger - sha256: "7ad7215c15420a102ec687bb320a7312afd449bac63bfb1c60d9787c27b9767f" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - logging: - dependency: transitive - description: - name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" - url: "https://pub.dev" - source: hosted - version: "0.12.15" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 - url: "https://pub.dev" - source: hosted - version: "0.2.0" - meta: - dependency: transitive - description: - name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - mime: - dependency: transitive - description: - name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e - url: "https://pub.dev" - source: hosted - version: "1.0.4" - nm: - dependency: transitive - description: - name: nm - sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" - url: "https://pub.dev" - source: hosted - version: "0.5.0" - octo_image: - dependency: transitive - description: - name: octo_image - sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - package_config: - dependency: transitive - description: - name: package_config - sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - package_info: - dependency: "direct main" - description: - name: package_info - sha256: "6c07d9d82c69e16afeeeeb6866fe43985a20b3b50df243091bfc4a4ad2b03b75" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - path: - dependency: transitive - description: - name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" - url: "https://pub.dev" - source: hosted - version: "1.8.3" - path_provider: - dependency: transitive - description: - name: path_provider - sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" - url: "https://pub.dev" - source: hosted - version: "2.2.2" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" - url: "https://pub.dev" - source: hosted - version: "2.2.1" - percent_indicator: - dependency: "direct main" - description: - name: percent_indicator - sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c - url: "https://pub.dev" - source: hosted - version: "4.2.3" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 - url: "https://pub.dev" - source: hosted - version: "5.4.0" - photo_view: - dependency: "direct main" - description: - name: photo_view - sha256: "8036802a00bae2a78fc197af8a158e3e2f7b500561ed23b4c458107685e645bb" - url: "https://pub.dev" - source: hosted - version: "0.14.0" - platform: - dependency: transitive - description: - name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" - url: "https://pub.dev" - source: hosted - version: "3.1.4" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 - url: "https://pub.dev" - source: hosted - version: "1.2.3" - retrofit: - dependency: "direct main" - description: - name: retrofit - sha256: "13a2865c0d97da580ea4e3c64d412d81f365fd5b26be2a18fca9582e021da37a" - url: "https://pub.dev" - source: hosted - version: "4.1.0" - retrofit_generator: - dependency: "direct dev" - description: - name: retrofit_generator - sha256: "9499eb46b3657a62192ddbc208ff7e6c6b768b19e83c1ee6f6b119c864b99690" - url: "https://pub.dev" - source: hosted - version: "7.0.8" - rxdart: - dependency: transitive - description: - name: rxdart - sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb" - url: "https://pub.dev" - source: hosted - version: "0.27.7" - shelf: - dependency: transitive - description: - name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 - url: "https://pub.dev" - source: hosted - version: "1.4.1" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" - url: "https://pub.dev" - source: hosted - version: "1.0.4" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" - url: "https://pub.dev" - source: hosted - version: "1.5.0" - source_helper: - dependency: transitive - description: - name: source_helper - sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" - url: "https://pub.dev" - source: hosted - version: "1.3.4" - source_span: - dependency: transitive - description: - name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 - url: "https://pub.dev" - source: hosted - version: "1.9.1" - sprintf: - dependency: transitive - description: - name: sprintf - sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - sqflite: - dependency: transitive - description: - name: sqflite - sha256: a9016f495c927cb90557c909ff26a6d92d9bd54fc42ba92e19d4e79d61e798c6 - url: "https://pub.dev" - source: hosted - version: "2.3.2" - sqflite_common: - dependency: transitive - description: - name: sqflite_common - sha256: "28d8c66baee4968519fb8bd6cdbedad982d6e53359091f0b74544a9f32ec72d5" - url: "https://pub.dev" - source: hosted - version: "2.5.3" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 - url: "https://pub.dev" - source: hosted - version: "1.11.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - stream_transform: - dependency: transitive - description: - name: stream_transform - sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - syncfusion_flutter_core: - dependency: transitive - description: - name: syncfusion_flutter_core - sha256: "8db8f55c77f56968681447d3837c10f27a9e861e238a898fda116c7531def979" - url: "https://pub.dev" - source: hosted - version: "21.2.10" - syncfusion_flutter_datepicker: - dependency: "direct main" - description: - name: syncfusion_flutter_datepicker - sha256: "6b0dacfe2f968de2b9107e2dc24fcaa2499415ae655df8f0d3ad0356eb090213" - url: "https://pub.dev" - source: hosted - version: "21.2.10" - synchronized: - dependency: transitive - description: - name: synchronized - sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" - url: "https://pub.dev" - source: hosted - version: "3.1.0+1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb - url: "https://pub.dev" - source: hosted - version: "0.5.1" - timing: - dependency: transitive - description: - name: timing - sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - tuple: - dependency: transitive - description: - name: tuple - sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 - url: "https://pub.dev" - source: hosted - version: "2.0.2" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c - url: "https://pub.dev" - source: hosted - version: "1.3.2" - uuid: - dependency: transitive - description: - name: uuid - sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f" - url: "https://pub.dev" - source: hosted - version: "4.2.2" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - watcher: - dependency: transitive - description: - name: watcher - sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b - url: "https://pub.dev" - source: hosted - version: "2.4.0" - win32: - dependency: transitive - description: - name: win32 - sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3" - url: "https://pub.dev" - source: hosted - version: "5.0.9" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d - url: "https://pub.dev" - source: hosted - version: "1.0.4" - xml: - dependency: transitive - description: - name: xml - sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" - url: "https://pub.dev" - source: hosted - version: "6.3.0" - yaml: - dependency: transitive - description: - name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" - url: "https://pub.dev" - source: hosted - version: "3.1.2" -sdks: - dart: ">=3.0.1 <4.0.0" - flutter: ">=3.10.0"