Quellcode durchsuchen

Merge branch 'dev-sg'

# Conflicts:
#	packages/cs_resources/lib/local/language/vi_VN.dart
liukai vor 6 Monaten
Ursprung
Commit
cf37385b62
100 geänderte Dateien mit 9690 neuen und 150 gelöschten Zeilen
  1. 9 7
      app/android/app/build.gradle
  2. 2 30
      app/android/build.gradle
  3. 2 2
      app/android/gradle.properties
  4. 22 8
      app/android/settings.gradle
  5. 18 0
      app/ios/Runner.xcodeproj/project.pbxproj
  6. 1 1
      app/ios/Runner/AppDelegate.swift
  7. 12 2
      app/lib/main.dart
  8. 1 1
      app/lib/router/page_router.dart
  9. 6 0
      app/pubspec.yaml
  10. 2 0
      melos.yaml
  11. 15 1
      packages/cpt_auth/lib/modules/login/login_controller.dart
  12. 60 20
      packages/cpt_auth/lib/modules/login/login_page.dart
  13. 25 5
      packages/cpt_auth/lib/modules/main/main_controller.dart
  14. 1 1
      packages/cpt_auth/lib/modules/main/main_item_module.dart
  15. 5 5
      packages/cpt_auth/lib/modules/main/main_page.dart
  16. 5 3
      packages/cpt_auth/lib/modules/main/main_state.dart
  17. 1 1
      packages/cpt_auth/lib/modules/reset_psd/reset_psd_page.dart
  18. 28 0
      packages/cpt_auth/lib/modules/select_country/select_country_controller.dart
  19. 190 0
      packages/cpt_auth/lib/modules/select_country/select_country_page.dart
  20. 1 1
      packages/cpt_auth/lib/modules/setting/setting_page.dart
  21. 1 1
      packages/cpt_auth/lib/modules/sign_up/sign_up_page.dart
  22. 12 6
      packages/cpt_auth/lib/router/page_router.dart
  23. 1 1
      packages/cpt_job/lib/modules/applied_staff_detail/applied_staff_detail_page.dart
  24. 0 4
      packages/cpt_job/lib/modules/applied_staff_detail/staff_detail_widget.dart
  25. 1 1
      packages/cpt_job/lib/modules/applied_staff_detail/staff_labour_history_item.dart
  26. 1 1
      packages/cpt_job/lib/modules/applied_staff_reviews/applied_staff_reviews_page.dart
  27. 1 1
      packages/cpt_job/lib/modules/applied_workflow/applied_workflow_page.dart
  28. 1 0
      packages/cpt_job/lib/modules/job_applied/job_applied_controller.dart
  29. 1 1
      packages/cpt_job/lib/modules/job_applied/job_applied_page.dart
  30. 3 3
      packages/cpt_job/lib/modules/job_applied_edit/job_applied_edit_page.dart
  31. 22 22
      packages/cpt_job/lib/modules/job_list/job_list_filter.dart
  32. 1 1
      packages/cpt_job/lib/modules/job_list/job_list_page.dart
  33. 1 1
      packages/cpt_job/lib/modules/job_list_detail/job_list_detail_page.dart
  34. 5 2
      packages/cpt_job/lib/modules/sign_in_sign_out/sign_in_sign_out_page.dart
  35. 1 0
      packages/cpt_job/lib/router/job_service_impl.dart
  36. 8 8
      packages/cpt_job/lib/router/page_router.dart
  37. 1 1
      packages/cpt_job/pubspec.yaml
  38. 31 0
      packages/cpt_job_sg/.gitignore
  39. 158 0
      packages/cpt_job_sg/lib/modules/applied_staff/applied_staff_add.dart
  40. 173 0
      packages/cpt_job_sg/lib/modules/applied_staff/applied_staff_controller.dart
  41. 156 0
      packages/cpt_job_sg/lib/modules/applied_staff/applied_staff_page.dart
  42. 12 0
      packages/cpt_job_sg/lib/modules/applied_staff/applied_staff_state.dart
  43. 152 0
      packages/cpt_job_sg/lib/modules/applied_staff_detail/applied_staff_detail_controller.dart
  44. 120 0
      packages/cpt_job_sg/lib/modules/applied_staff_detail/applied_staff_detail_page.dart
  45. 14 0
      packages/cpt_job_sg/lib/modules/applied_staff_detail/applied_staff_detail_state.dart
  46. 170 0
      packages/cpt_job_sg/lib/modules/applied_staff_detail/staff_detail_widget.dart
  47. 183 0
      packages/cpt_job_sg/lib/modules/applied_staff_detail/staff_labour_history_item.dart
  48. 109 0
      packages/cpt_job_sg/lib/modules/applied_staff_reviews/applied_staff_reviews_controller.dart
  49. 151 0
      packages/cpt_job_sg/lib/modules/applied_staff_reviews/applied_staff_reviews_item.dart
  50. 162 0
      packages/cpt_job_sg/lib/modules/applied_staff_reviews/applied_staff_reviews_page.dart
  51. 10 0
      packages/cpt_job_sg/lib/modules/applied_staff_reviews/applied_staff_reviews_state.dart
  52. 426 0
      packages/cpt_job_sg/lib/modules/job_applied/applied_staff_item.dart
  53. 313 0
      packages/cpt_job_sg/lib/modules/job_applied/applied_staff_reviews.dart
  54. 350 0
      packages/cpt_job_sg/lib/modules/job_applied/dialog_applied_butch_modify.dart
  55. 530 0
      packages/cpt_job_sg/lib/modules/job_applied/dialog_applied_modify.dart
  56. 57 0
      packages/cpt_job_sg/lib/modules/job_applied/drop_down_status.dart
  57. 496 0
      packages/cpt_job_sg/lib/modules/job_applied/job_applied_controller.dart
  58. 250 0
      packages/cpt_job_sg/lib/modules/job_applied/job_applied_page.dart
  59. 19 0
      packages/cpt_job_sg/lib/modules/job_applied/job_applied_state.dart
  60. 103 0
      packages/cpt_job_sg/lib/modules/revise_add_edit/revise_add_edit_controller.dart
  61. 70 0
      packages/cpt_job_sg/lib/modules/revise_add_edit/revise_add_edit_item.dart
  62. 223 0
      packages/cpt_job_sg/lib/modules/revise_add_edit/revise_add_edit_page.dart
  63. 33 0
      packages/cpt_job_sg/lib/modules/revise_add_edit/revise_add_edit_state.dart
  64. 243 0
      packages/cpt_job_sg/lib/modules/revise_applied/revise_applied_controller.dart
  65. 143 0
      packages/cpt_job_sg/lib/modules/revise_applied/revise_applied_page.dart
  66. 10 0
      packages/cpt_job_sg/lib/modules/revise_applied/revise_applied_state.dart
  67. 299 0
      packages/cpt_job_sg/lib/modules/revise_list/revise_list_controller.dart
  68. 290 0
      packages/cpt_job_sg/lib/modules/revise_list/revise_list_filter.dart
  69. 298 0
      packages/cpt_job_sg/lib/modules/revise_list/revise_list_item.dart
  70. 152 0
      packages/cpt_job_sg/lib/modules/revise_list/revise_list_page.dart
  71. 17 0
      packages/cpt_job_sg/lib/modules/revise_list/revise_list_state.dart
  72. 98 0
      packages/cpt_job_sg/lib/modules/revise_log/revise_log_controller.dart
  73. 155 0
      packages/cpt_job_sg/lib/modules/revise_log/revise_log_item.dart
  74. 102 0
      packages/cpt_job_sg/lib/modules/revise_log/revise_log_page.dart
  75. 10 0
      packages/cpt_job_sg/lib/modules/revise_log/revise_log_state.dart
  76. 30 0
      packages/cpt_job_sg/lib/router/job_sg_service_impl.dart
  77. 58 0
      packages/cpt_job_sg/lib/router/page_router.dart
  78. 40 0
      packages/cpt_job_sg/pubspec.yaml
  79. 16 0
      packages/cpt_job_sg/pubspec_overrides.yaml
  80. 1 1
      packages/cpt_labour/lib/modules/labour_request_add/labour_request_add_page.dart
  81. 2 2
      packages/cpt_labour/lib/modules/labour_request_list/labour_request_list_page.dart
  82. 1 1
      packages/cpt_labour/lib/modules/labour_request_workflow/labour_request_workflow_page.dart
  83. 3 3
      packages/cpt_labour/lib/router/page_router.dart
  84. 1 1
      packages/cpt_labour/pubspec.yaml
  85. 31 0
      packages/cpt_labour_sg/.gitignore
  86. 306 0
      packages/cpt_labour_sg/lib/modules/job_list/job_list_controller.dart
  87. 361 0
      packages/cpt_labour_sg/lib/modules/job_list/job_list_filter.dart
  88. 259 0
      packages/cpt_labour_sg/lib/modules/job_list/job_list_item.dart
  89. 156 0
      packages/cpt_labour_sg/lib/modules/job_list/job_list_page.dart
  90. 15 0
      packages/cpt_labour_sg/lib/modules/job_list/job_list_state.dart
  91. 190 0
      packages/cpt_labour_sg/lib/modules/job_list_edit/job_list_edit_controller.dart
  92. 434 0
      packages/cpt_labour_sg/lib/modules/job_list_edit/job_list_edit_page.dart
  93. 55 0
      packages/cpt_labour_sg/lib/modules/job_list_edit/job_list_edit_state.dart
  94. 131 0
      packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_controller.dart
  95. 367 0
      packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_page.dart
  96. 60 0
      packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_state.dart
  97. 7 0
      packages/cpt_labour_sg/lib/modules/job_template_list/add_edit_template.dart
  98. 193 0
      packages/cpt_labour_sg/lib/modules/job_template_list/job_template_item.dart
  99. 218 0
      packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_controller.dart
  100. 0 0
      packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_page.dart

+ 9 - 7
app/android/app/build.gradle

@@ -1,3 +1,10 @@
+plugins {
+    id "com.android.application"
+    id "kotlin-android"
+    id "kotlin-kapt"
+    id "dev.flutter.flutter-gradle-plugin"
+}
+
 def keystoreProperties = new Properties()
 def keystorePropertiesFile = rootProject.file('key.properties')
 if (keystorePropertiesFile.exists()) {
@@ -20,11 +27,6 @@ if (flutterRoot == null) {
 // 模拟器运行报错时尝试开启此项
 // project.setProperty('target-platform', 'android-arm')
 
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-kapt'
-apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
-
 android {
     compileSdkVersion 34
 
@@ -112,8 +114,8 @@ flutter {
 }
 
 dependencies {
-    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
-    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0"
+    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0"
 
     implementation 'com.github.bumptech.glide:glide:4.11.0'
     kapt 'com.github.bumptech.glide:compiler:4.11.0'

+ 2 - 30
app/android/build.gradle

@@ -1,44 +1,16 @@
-
-buildscript {
-    ext.kotlin_version = '1.8.0'
-    repositories {
-//        maven { url 'https://maven.aliyun.com/repository/public' }//jcenter
-//        maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }//gradle-plugin
-//        maven { url 'https://maven.aliyun.com/repository/central' }//central
-//        maven { url 'https://maven.aliyun.com/repository/google' }//google
-//        maven { url 'https://maven.aliyun.com/repository/jcenter' }
-//        maven { url 'https://maven.aliyun.com/nexus/content/groups/public'}
-        google()
-        mavenCentral()
-        maven { url 'https://jitpack.io' }
-    }
-
-    dependencies {
-        classpath 'com.android.tools.build:gradle:7.1.2'
-        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
-    }
-}
-
 allprojects {
     repositories {
-//        maven { url 'https://maven.aliyun.com/repository/public' }
-//        maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
-//        maven { url 'https://maven.aliyun.com/repository/central' }
-//        maven { url 'https://maven.aliyun.com/repository/google' }
-//        maven { url 'https://maven.aliyun.com/repository/jcenter' }
-//        maven { url 'https://maven.aliyun.com/nexus/content/groups/public'}
         google()
         mavenCentral()
-        maven { url 'https://jitpack.io' }
     }
 }
 
-rootProject.buildDir = '../build'
+rootProject.buildDir = "../build"
 subprojects {
     project.buildDir = "${rootProject.buildDir}/${project.name}"
 }
 subprojects {
-    project.evaluationDependsOn(':app')
+    project.evaluationDependsOn(":app")
 }
 
 tasks.register("clean", Delete) {

+ 2 - 2
app/android/gradle.properties

@@ -1,4 +1,4 @@
-org.gradle.jvmargs=-Xmx1536M
+org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
 android.useAndroidX=true
 android.enableJetifier=true
-maven={ url 'https://maven.aliyun.com/repository/public' }
+maven={ url 'https://maven.aliyun.com/repository/public' }

+ 22 - 8
app/android/settings.gradle

@@ -1,11 +1,25 @@
-include ':app'
+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
+    }()
 
-def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
-def properties = new Properties()
+    includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
 
-assert localPropertiesFile.exists()
-localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
+    repositories {
+        google()
+        mavenCentral()
+        gradlePluginPortal()
+    }
+}
 
-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"
+plugins {
+    id "dev.flutter.flutter-plugin-loader" version "1.0.0"
+    id "com.android.application" version "7.1.2" apply false
+    id "org.jetbrains.kotlin.android" version "1.8.0" apply false
+}
+
+include ":app"

+ 18 - 0
app/ios/Runner.xcodeproj/project.pbxproj

@@ -146,6 +146,7 @@
 				97C146EC1CF9000F007C117D /* Resources */,
 				3B06AD1E1E4923F5004D2608 /* Thin Binary */,
 				F4664E1960AB5AF20D861E87 /* [CP] Embed Pods Frameworks */,
+				F004C36936C89F93981F1B41 /* [CP] Copy Pods Resources */,
 			);
 			buildRules = (
 			);
@@ -262,6 +263,23 @@
 			shellPath = /bin/sh;
 			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
 		};
+		F004C36936C89F93981F1B41 /* [CP] Copy Pods Resources */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
+			);
+			name = "[CP] Copy Pods Resources";
+			outputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
+			showEnvVarsInLog = 0;
+		};
 		F4664E1960AB5AF20D861E87 /* [CP] Embed Pods Frameworks */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;

+ 1 - 1
app/ios/Runner/AppDelegate.swift

@@ -3,7 +3,7 @@ import AppTrackingTransparency
 import Flutter
 import AuthenticationServices
 
-@UIApplicationMain
+@main
 @objc class AppDelegate: FlutterAppDelegate {
     
     var channel:FlutterMethodChannel!

+ 12 - 2
app/lib/main.dart

@@ -2,8 +2,13 @@ import 'package:cpt_auth/router/auth_service_impl.dart';
 import 'package:cpt_auth/router/page_router.dart';
 import 'package:cpt_job/router/job_service_impl.dart';
 import 'package:cpt_job/router/page_router.dart';
+import 'package:cpt_job_sg/router/job_sg_service_impl.dart';
+import 'package:cpt_job_sg/router/page_router.dart';
 import 'package:cpt_labour/router/labour_service_impl.dart';
 import 'package:cpt_labour/router/page_router.dart';
+import 'package:cpt_labour_sg/router/labour_sg_service_impl.dart';
+import 'package:cpt_labour_sg/router/page_router.dart';
+import 'package:cpt_report/router/page_router.dart';
 import 'package:cpt_report/router/report_service_impl.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
@@ -13,7 +18,9 @@ import 'package:initializer/app_initializer.dart';
 import 'package:plugin_basic/basic_export.dart';
 import 'package:router/componentRouter/auth_service.dart';
 import 'package:router/componentRouter/job_service.dart';
+import 'package:router/componentRouter/job_sg_service.dart';
 import 'package:router/componentRouter/labour_service.dart';
+import 'package:router/componentRouter/labour_sg_service.dart';
 import 'package:router/componentRouter/report_service.dart';
 import 'package:cs_resources/local/theme/theme_config.dart';
 import 'package:cs_resources/local/language/translation_service.dart';
@@ -40,6 +47,8 @@ void main() async{
       Get.lazyPut<LabourService>(() => LabourServiceImpl());
       Get.lazyPut<JobService>(() => JobServiceImpl());
       Get.lazyPut<ReportService>(() => ReportServiceImpl());
+      Get.lazyPut<JobSGService>(() => JobSGServiceImpl());
+      Get.lazyPut<LabourSGService>(() => LabourSGServiceImpl());
     });
 
     runApp(MyApp());
@@ -115,8 +124,9 @@ class MyApp extends StatelessWidget {
           //是否展示Log
           enableLog: true,
           //默认路由与路由表的加载
-          initialRoute: RouterPath.SPLASH,
-          getPages: PageRouter.routes + BasicPageRouter.routes + AuthPageRouter.routes + JobPageRouter.routes + LabourPageRouter.routes,
+          initialRoute: RouterPath.splash,
+          getPages: PageRouter.routes + BasicPageRouter.routes + AuthPageRouter.routes + JobPageRouter.routes + LabourPageRouter.routes +
+              ReportPageRouter.routes + LabourSGPageRouter.routes + JobPageSGRouter.routes,
           //对原生导航的兼容;SmartDialog路由配置生命周期处理
           navigatorObservers: [GetXRouterObserver(), FlutterSmartDialog.observer, routeObserver],
           //默认页面动画

+ 1 - 1
app/lib/router/page_router.dart

@@ -10,7 +10,7 @@ class PageRouter {
 
     //闪屏页
     GetPage(
-      name: RouterPath.SPLASH,
+      name: RouterPath.splash,
       page: () => SplashPage(),
     ),
 

+ 6 - 0
app/pubspec.yaml

@@ -43,9 +43,15 @@ dependencies:
   cpt_job:
     path: ../packages/cpt_job
 
+  cpt_job_sg:
+    path: ../packages/cpt_job_sg
+
   cpt_labour:
     path: ../packages/cpt_labour
 
+  cpt_labour_sg:
+    path: ../packages/cpt_labour_sg
+
   cpt_report:
     path: ../packages/cpt_report
 

+ 2 - 0
melos.yaml

@@ -11,7 +11,9 @@ packages:
   - "packages/cs_initializer/"
   - "packages/cpt_auth/"
   - "packages/cpt_job/"
+  - "packages/cpt_job_sg/"
   - "packages/cpt_labour/"
+  - "packages/cpt_labour_sg/"
   - "packages/cpt_report/"
 
 

+ 15 - 1
packages/cpt_auth/lib/modules/login/login_controller.dart

@@ -1,14 +1,18 @@
 import 'package:cpt_auth/modules/main/main_page.dart';
 import 'package:cpt_auth/modules/reset_psd/reset_psd_page.dart';
+import 'package:cpt_auth/modules/select_country/select_country_page.dart';
 import 'package:domain/entity/response/hotel_info_entity.dart';
 import 'package:domain/repository/auth_repository.dart';
 import 'package:get/get.dart';
 import 'package:plugin_basic/constants/app_constant.dart';
+import 'package:plugin_basic/service/app_config_service.dart';
 import 'package:plugin_basic/service/user_service.dart';
 import 'package:plugin_platform/engine/sp/sp_util.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_provider.dart';
 import 'package:router/componentRouter/component_router_service.dart';
+import 'package:shared/utils/event_bus.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/util.dart';
 
@@ -77,7 +81,12 @@ class LoginController extends GetxController with DioCancelableMixin {
     UserService.to.setToken(token);
 
     //保存是否是管理员登录
-    SPUtil.putInt(AppConstant.storageIsAdmin, state.loginOptionPosition);
+    if (ConfigService.to.curSelectCountry.value == 1) {
+      //如果是新加坡用户,强制是管理员登录
+      SPUtil.putInt(AppConstant.storageIsAdmin, 1);
+    }else{
+      SPUtil.putInt(AppConstant.storageIsAdmin, state.loginOptionPosition);
+    }
 
     //去首页
     MainPage.startWithPopAll();
@@ -92,4 +101,9 @@ class LoginController extends GetxController with DioCancelableMixin {
   void gotoSignUpPage() {
     SignUpPage.startInstance();
   }
+
+  // 去切换国家的页面
+  void gotoSelectCountryPage() {
+    SelectCountryPage.startInstance();
+  }
 }

+ 60 - 20
packages/cpt_auth/lib/modules/login/login_page.dart

@@ -1,3 +1,5 @@
+// ignore_for_file: slash_for_doc_comments
+
 import 'package:cs_resources/constants/color_constants.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/cupertino.dart';
@@ -8,17 +10,18 @@ import 'package:get/get.dart';
 import 'package:plugin_basic/base/base_stateful_page.dart';
 import 'package:plugin_basic/base/base_state.dart';
 import 'package:plugin_basic/base/mixin_state_lifecycle.dart';
+import 'package:plugin_basic/service/app_config_service.dart';
 import 'package:plugin_basic/utils/ext_get_nav.dart';
 import 'package:router/path/router_path.dart';
 import 'package:shared/utils/device_utils.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/screen_util.dart';
-import 'package:widgets/custom_radio_check.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_button.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_field.dart';
 import 'package:widgets/my_text_view.dart';
+import 'package:widgets/shatter/custom_radio_check.dart';
 import 'package:widgets/widget_export.dart';
 import 'login_controller.dart';
 import 'login_state.dart';
@@ -31,15 +34,15 @@ class LoginPage extends BaseStatefulPage<LoginController> {
 
   //启动当前页面
   static void startInstance() {
-    return Get.start(RouterPath.AUTH_LOGIN, launchModel: LaunchModel.standard);
+    return Get.start(RouterPath.authLogin, launchModel: LaunchModel.standard);
   }
 
   static void startWithPopAll() {
-    Get.offAllNamed(RouterPath.AUTH_LOGIN);
+    Get.offAllNamed(RouterPath.authLogin);
   }
 
   @override
-  State<LoginPage> createState() => _MainPageState();
+  State<LoginPage> createState() => _LoginPageState();
 
   @override
   LoginController createRawController() {
@@ -50,7 +53,7 @@ class LoginPage extends BaseStatefulPage<LoginController> {
 /**
  * 页面
  */
-class _MainPageState extends BaseState<LoginPage, LoginController> with StateLifecycle {
+class _LoginPageState extends BaseState<LoginPage, LoginController> with StateLifecycle {
   late LoginState state;
 
   @override
@@ -93,14 +96,26 @@ class _MainPageState extends BaseState<LoginPage, LoginController> with StateLif
                 //当前选择的国家,这个不跟随滚动
                 Align(
                   alignment: Alignment.topRight,
-                  child: MyTextView(
-                    "Vietnam".tr,
-                    textColor: ColorConstants.white,
-                    isFontMedium: true,
-                    fontSize: 15,
-                    marginTop: ScreenUtil.getStatusBarH(context) + 20,
-                    marginRight: 20,
-                  ),
+                  child: Row(
+                    mainAxisSize: MainAxisSize.min,
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                    children: [
+                      Obx(() {
+                        return MyTextView(
+                          ConfigService.to.curSelectCountry == 0 ? "Vietnam".tr : "Singapore".tr,
+                          textColor: ColorConstants.white,
+                          isFontMedium: true,
+                          marginRight: 5,
+                          fontSize: 15,
+                        );
+                      }),
+                      const MyAssetImage(
+                        Assets.baseServiceTriangleDropDown,
+                        width: 8,
+                        height: 5,
+                      ),
+                    ],
+                  ).onTap(() => controller.gotoSelectCountryPage()).marginOnly(right: 20, top: ScreenUtil.getStatusBarH(context) + 20),
                 ),
 
                 // 底部滚动的布局
@@ -197,12 +212,17 @@ class _MainPageState extends BaseState<LoginPage, LoginController> with StateLif
                                 ),
 
                                 //选择签到功能还是全功能
-                                CustomRadioCheck(
-                                  options: state.loginOption,
-                                  onOptionSelected: (index, text) {
-                                    state.loginOptionPosition = index;
-                                  },
-                                ).marginSymmetric(vertical: 20),
+                                Obx(() {
+                                  return Visibility(
+                                    visible: ConfigService.to.curSelectCountry == 0,
+                                    child: CustomRadioCheck(
+                                      options: state.loginOption,
+                                      onOptionSelected: (index, text) {
+                                        state.loginOptionPosition = index;
+                                      },
+                                    ).marginOnly(top: 20),
+                                  );
+                                }),
 
                                 //登录按钮
                                 MyButton(
@@ -218,7 +238,7 @@ class _MainPageState extends BaseState<LoginPage, LoginController> with StateLif
                                   radius: 22.5,
                                   backgroundColor: hexToColor("#FFBB1B"),
                                   fontWeight: FontWeight.w500,
-                                ),
+                                ).marginOnly(top: 20),
 
                                 //注册入口
                                 Visibility(
@@ -239,6 +259,26 @@ class _MainPageState extends BaseState<LoginPage, LoginController> with StateLif
     );
   }
 
+  @override
+  void onStart() {
+    Log.d("LoginPage Lifecycle - onStart");
+  }
+
+  @override
+  void onStop() {
+    Log.d("LoginPage Lifecycle - onStop");
+  }
+
+  @override
+  void onResume() {
+    Log.d("LoginPage Lifecycle - onResume");
+  }
+
+  @override
+  void onPause() {
+    Log.d("LoginPage Lifecycle - onPause");
+  }
+
   //底部的注册文本
   Widget _buildRichText() {
     return Align(

+ 25 - 5
packages/cpt_auth/lib/modules/main/main_controller.dart

@@ -4,6 +4,7 @@ import 'package:domain/entity/response/hotel_info_entity.dart';
 import 'package:domain/repository/auth_repository.dart';
 import 'package:get/get.dart';
 import 'package:plugin_basic/constants/app_constant.dart';
+import 'package:plugin_basic/service/app_config_service.dart';
 import 'package:plugin_basic/service/user_service.dart';
 import 'package:plugin_platform/engine/sp/sp_util.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
@@ -118,16 +119,30 @@ class MainController extends GetxController {
   void gotoModulePage(HomeModule module) {
     switch (module.key) {
       case 'labReq':
-        ComponentRouterServices.labourService.startLabourRequestPage();
+        if (ConfigService.to.curSelectCountry.value == 1) {
+          //新加坡的用工请求
+          ComponentRouterServices.labourSGService.startLabourRequestPage();
+        } else {
+          //越南的用工请求
+          ComponentRouterServices.labourService.startLabourRequestPage();
+        }
         break;
       case 'jobList':
-        ComponentRouterServices.jobService.startJobListPage();
+        if (ConfigService.to.curSelectCountry.value == 1) {
+          ComponentRouterServices.labourSGService.startJobListPage();
+        } else {
+          //越南的工作列表
+          ComponentRouterServices.jobService.startJobListPage();
+        }
         break;
       case 'sign':
         ComponentRouterServices.jobService.startSignInSignOutPage();
         break;
-      case 'devices':
-        ToastEngine.show("进入 Devices 模块");
+      case 'reviseList':
+        ComponentRouterServices.jobSGService.startReviseListPage();
+        break;
+      case 'device':
+        ComponentRouterServices.reportService.startDeviceListPage();
         break;
       case 'reqReview':
         ToastEngine.show("进入 Labour Request Review 模块");
@@ -136,10 +151,15 @@ class MainController extends GetxController {
         ToastEngine.show("进入 Attendance Review 模块");
         break;
       case 'template':
+        //越南的用工请求
         ToastEngine.show("进入 Default Job Title 模块");
         break;
+      case 'jobTitle':
+        //新加坡的用工请求
+        ComponentRouterServices.labourSGService.startJobTitlePage();
+        break;
       case 'report':
-        ToastEngine.show("进入 Report 模块");
+        ComponentRouterServices.reportService.startReportMainPage();
         break;
     }
   }

+ 1 - 1
packages/cpt_auth/lib/modules/main/main_item_module.dart

@@ -17,7 +17,7 @@ class ModuleItem extends StatelessWidget {
       onTap: onTap,
       child: Container(
         decoration: BoxDecoration(
-          color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+          color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
           borderRadius: BorderRadius.circular(7.5), // 设置圆角
         ),
         child: Column(

+ 5 - 5
packages/cpt_auth/lib/modules/main/main_page.dart

@@ -33,11 +33,11 @@ class MainPage extends BaseStatefulPage<MainController> {
 
   //启动当前页面
   static void startInstance() {
-    return Get.start(RouterPath.MAIN);
+    return Get.start(RouterPath.main);
   }
 
   static void startWithPopAll() {
-    Get.offAllNamed(RouterPath.MAIN);
+    Get.offAllNamed(RouterPath.main);
   }
 
   @override
@@ -139,14 +139,14 @@ class _MainPageState extends BaseState<MainPage, MainController> with StateLifec
                         }).expanded(),
 
                         //设置图标,点击进入设置页面
-                        MyAssetImage(Assets.mainHomeSetting, width: 33, height: 33).onTap(() => controller.gotoSettingPage()),
+                        const MyAssetImage(Assets.mainHomeSetting, width: 33, height: 33).onTap(() => controller.gotoSettingPage()),
                       ],
                     ),
 
                     //欢迎的文本+姓名
                     Obx(() {
                       return MyTextView(
-                        "Welcome".tr + " ${UserService.to.getHotelInfo.name ?? "-"}",
+                        "${"Welcome".tr} ${UserService.to.getHotelInfo.name ?? "-"}",
                         textColor: ColorConstants.textGray9EB0C1,
                         isTextEllipsis: true,
                         isFontMedium: true,
@@ -177,7 +177,7 @@ class _MainPageState extends BaseState<MainPage, MainController> with StateLifec
                               },
                               childCount: state.datas.length,
                             ),
-                            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
+                            gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                               crossAxisCount: 2, // 每行2个项目
                               mainAxisSpacing: 5, // 主轴方向的间距
                               crossAxisSpacing: 5, // 交叉轴方向的间距

+ 5 - 3
packages/cpt_auth/lib/modules/main/main_state.dart

@@ -10,11 +10,13 @@ class MainState {
   final List<HomeModule> modules = [
     HomeModule(key: 'labReq', moduleName: 'Labour Request'.tr, moduleIconPath: Assets.mainHomeLabourRequest, iconWidth: 50, iconHeight: 40.3),
     HomeModule(key: 'jobList', moduleName: 'Job List'.tr, moduleIconPath: Assets.mainHomeJobList, iconWidth: 45, iconHeight: 45),
-    HomeModule(key: 'sign', moduleName: 'Sign in Sign out'.tr, moduleIconPath: Assets.mainHomeSignInOut, iconWidth: 44.5, iconHeight: 44.5),
-    HomeModule(key: 'devices', moduleName: 'Devices'.tr, moduleIconPath: Assets.mainHomeDevices, iconWidth: 45.5, iconHeight: 45.5),
+    HomeModule(key: 'sign', moduleName: 'Sign in Sign out'.tr, moduleIconPath: Assets.mainHomeSignInOut, iconWidth: 44.5, iconHeight: 44.5),  //越南的手动签到
+    HomeModule(key: 'reviseList', moduleName: 'Revise List'.tr, moduleIconPath: Assets.mainHomeSignInOut, iconWidth: 44.5, iconHeight: 44.5),  //新加坡的修改列表
+    HomeModule(key: 'device', moduleName: 'Devices'.tr, moduleIconPath: Assets.mainHomeDevices, iconWidth: 45.5, iconHeight: 45.5),
     HomeModule(key: 'reqReview', moduleName: 'Labour Request Review'.tr, moduleIconPath: Assets.mainHomeLabourRequestReview, iconWidth: 50.5, iconHeight: 43),
     HomeModule(key: 'attReview', moduleName: 'Attendance Review'.tr, moduleIconPath: Assets.mainHomeAttendanceReview, iconWidth: 47.5, iconHeight: 46),
-    HomeModule(key: 'template', moduleName: 'Default Job Title'.tr, moduleIconPath: Assets.mainHomeJobTemplate, iconWidth: 48.5, iconHeight: 46.5),
+    HomeModule(key: 'template', moduleName: 'Default Job Title'.tr, moduleIconPath: Assets.mainHomeJobTemplate, iconWidth: 48.5, iconHeight: 46.5), //越南的模版
+    HomeModule(key: 'jobTitle', moduleName: 'Default Job Title'.tr, moduleIconPath: Assets.mainHomeJobTemplate, iconWidth: 48.5, iconHeight: 46.5), //新加坡的模板
     HomeModule(key: 'report', moduleName: 'Report'.tr, moduleIconPath: Assets.mainHomeReport, iconWidth: 50.5, iconHeight: 45.5),
   ];
 }

+ 1 - 1
packages/cpt_auth/lib/modules/reset_psd/reset_psd_page.dart

@@ -19,7 +19,7 @@ class ResetPasswordPage extends BaseStatefulPage<ResetPasswordController> {
 
   //启动当前页面
   static void startInstance() {
-    return Get.start(RouterPath.AUTH_RESET_PSD);
+    return Get.start(RouterPath.authResetPassword);
   }
 
   @override

+ 28 - 0
packages/cpt_auth/lib/modules/select_country/select_country_controller.dart

@@ -0,0 +1,28 @@
+import 'package:domain/constants/api_constants.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/constants/app_constant.dart';
+import 'package:plugin_basic/service/app_config_service.dart';
+import 'package:plugin_basic/service/http_provider_injection.dart';
+import 'package:plugin_platform/engine/sp/sp_util.dart';
+
+
+class SelectCountryController extends GetxController {
+
+  //设置下一步
+  void setupNext() {
+    int country = ConfigService.to.curSelectCountry.value;
+    SPUtil.putInt(AppConstant.storageSelectedCountry, country);
+
+    String baseUrl;
+    if (country == 1){
+      //新加坡
+      baseUrl = ApiConstants.sgBaseUrl;
+    }else {
+      baseUrl = ApiConstants.baseUrl;
+    }
+
+    HttpProviderInjection.switchBaseUrl(baseUrl);
+
+    Get.back();
+  }
+}

+ 190 - 0
packages/cpt_auth/lib/modules/select_country/select_country_page.dart

@@ -0,0 +1,190 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_stateless_page.dart';
+import 'package:plugin_basic/service/app_config_service.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+
+import 'select_country_controller.dart';
+
+class SelectCountryPage extends BaseStatelessPage<SelectCountryController> {
+  SelectCountryPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.authSelectCountry);
+  }
+
+  @override
+  void initState() {
+  }
+
+  @override
+  SelectCountryController createRawController() {
+    return SelectCountryController();
+  }
+
+  @override
+  Widget buildWidget(BuildContext context) {
+    return Scaffold(
+      body: SafeArea(
+        bottom: true,
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+            ),
+          ),
+          child: Column(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              // 底部滚动的布局
+              SingleChildScrollView(
+                  scrollDirection: Axis.vertical,
+                  physics: const BouncingScrollPhysics(),
+                  child: Column(
+                    mainAxisSize: MainAxisSize.max,
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                    children: [
+                      MyTextView(
+                        "Casual Labour System",
+                        textColor: ColorConstants.white,
+                        isFontBold: true,
+                        fontSize: 35,
+                        marginTop: 20,
+                        fontStyle: FontStyle.italic,
+                        textAlign: TextAlign.center,
+                        marginLeft: 50,
+                        marginRight: 50,
+                      ),
+                      MyTextView(
+                        "Select Country".tr,
+                        textColor: ColorConstants.white,
+                        isFontMedium: true,
+                        fontSize: 21,
+                        marginTop: 18,
+                      ),
+                      MyTextView(
+                        "Browse jobs available in your selected country.".tr,
+                        textColor: ColorConstants.white,
+                        isFontMedium: true,
+                        fontSize: 14,
+                        marginTop: 9,
+                      ),
+
+                      //新加坡的选项
+                      Container(
+                        width: double.infinity,
+                        margin: EdgeInsets.only(top: 48, left: 20, right: 20),
+                        padding: EdgeInsets.symmetric(vertical: 13, horizontal: 17),
+                        decoration: BoxDecoration(
+                          color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+                          borderRadius: BorderRadius.circular(5.0), // 设置圆角
+                        ),
+                        child: Row(
+                          children: [
+                            MyAssetImage(Assets.cptAuthSgIcon, width: 50, height: 33),
+                            MyTextView(
+                              "Singapore".tr,
+                              marginLeft: 17,
+                              textColor: ColorConstants.white,
+                              isFontMedium: true,
+                              fontSize: 18,
+                            ).expanded(),
+                            Obx(() {
+                              return Visibility(
+                                visible: ConfigService.to.curSelectCountry.value == 1,
+                                child: MyAssetImage(Assets.cptAuthCheckedIcon, width: 22, height: 22),
+                              );
+                            }),
+                          ],
+                        ),
+                      ).onTap(() {
+                        ConfigService.to.curSelectCountry.value = 1;
+                      }),
+
+                      //越南的选项
+                      Container(
+                        width: double.infinity,
+                        margin: EdgeInsets.only(top: 13.5, left: 20, right: 20),
+                        padding: EdgeInsets.symmetric(vertical: 13, horizontal: 17),
+                        decoration: BoxDecoration(
+                          color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+                          borderRadius: BorderRadius.circular(5.0), // 设置圆角
+                        ),
+                        child: Row(
+                          children: [
+                            MyAssetImage(Assets.cptAuthVnIcon, width: 50, height: 33),
+                            MyTextView(
+                              "Vietnam".tr,
+                              marginLeft: 17,
+                              textColor: ColorConstants.white,
+                              isFontMedium: true,
+                              fontSize: 18,
+                            ).expanded(),
+                            Obx(() {
+                              return Visibility(
+                                visible: ConfigService.to.curSelectCountry.value == 0,
+                                child: MyAssetImage(Assets.cptAuthCheckedIcon, width: 22, height: 22),
+                              );
+                            }),
+                          ],
+                        ),
+                      ).onTap(() {
+                        ConfigService.to.curSelectCountry.value = 0;
+                      }),
+
+                      //Next按钮
+                      Stack(
+                        children: [
+                          MyButton(
+                            type: ClickType.throttle,
+                            milliseconds: 500,
+                            onPressed: () {
+                              controller.setupNext();
+                            },
+                            text: "Next".tr,
+                            textColor: ColorConstants.white,
+                            fontSize: 18,
+                            minHeight: 50,
+                            radius: 22.5,
+                            backgroundColor: hexToColor("#FFBB1B"),
+                            fontWeight: FontWeight.w500,
+                          ),
+                          Positioned(
+                            right: 28,
+                            top: 0,
+                            bottom: 0,
+                            child: MyAssetImage(Assets.cptAuthNextIcon, width: 20, height: 14.5),
+                          ),
+                        ],
+                      ).marginSymmetric(horizontal: 20, vertical: 36)
+                    ],
+                  )).expanded(),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}

+ 1 - 1
packages/cpt_auth/lib/modules/setting/setting_page.dart

@@ -17,7 +17,7 @@ class SettingPage extends BaseStatelessPage<SettingController> {
 
   //启动当前页面
   static void startInstance() {
-    return Get.start(RouterPath.SETTINGS);
+    return Get.start(RouterPath.settings);
   }
 
   late SettingState state;

+ 1 - 1
packages/cpt_auth/lib/modules/sign_up/sign_up_page.dart

@@ -19,7 +19,7 @@ class SignUpPage extends BaseStatefulPage<SignUpController> {
 
   //启动当前页面
   static void startInstance() {
-    return Get.start(RouterPath.AUTH_SIGNUP);
+    return Get.start(RouterPath.authSignUp);
   }
 
   @override

+ 12 - 6
packages/cpt_auth/lib/router/page_router.dart

@@ -7,38 +7,44 @@ import 'package:router/path/router_path.dart';
 import '../modules/login/login_page.dart';
 import '../modules/main/main_page.dart';
 import '../modules/reset_psd/reset_psd_page.dart';
+import '../modules/select_country/select_country_page.dart';
 
 class AuthPageRouter {
   static final routes = [
     //首页
     GetPage(
-      name: RouterPath.MAIN,
+      name: RouterPath.main,
       page: () => MainPage(),
     ),
 
     //登录
     GetPage(
-      name: RouterPath.AUTH_LOGIN,
+      name: RouterPath.authLogin,
       page: () => LoginPage(),
     ),
 
     //注册
     GetPage(
-      name: RouterPath.AUTH_SIGNUP,
+      name: RouterPath.authSignUp,
       page: () => SignUpPage(),
     ),
 
     //重置密码
     GetPage(
-      name: RouterPath.AUTH_RESET_PSD,
+      name: RouterPath.authResetPassword,
       page: () => ResetPasswordPage(),
     ),
 
-    //重置密码
+    //设置
     GetPage(
-      name: RouterPath.SETTINGS,
+      name: RouterPath.settings,
       page: () => SettingPage(),
     ),
 
+    //切换国家
+    GetPage(
+      name: RouterPath.authSelectCountry,
+      page: () => SelectCountryPage(),
+    ),
   ];
 }

+ 1 - 1
packages/cpt_job/lib/modules/applied_staff_detail/applied_staff_detail_page.dart

@@ -24,7 +24,7 @@ class AppliedStaffDetailPage extends BaseStatefulPage<AppliedStaffDetailControll
 
   //启动当前页面
   static void startInstance(String? memberId) {
-    return Get.start(RouterPath.JOB_APPLIED_STAFF_DETAIL, arguments: {'memberId': memberId});
+    return Get.start(RouterPath.jobAppliedStaffDetail, arguments: {'memberId': memberId});
   }
 
   @override

+ 0 - 4
packages/cpt_job/lib/modules/applied_staff_detail/staff_detail_widget.dart

@@ -1,14 +1,10 @@
 import 'package:cs_resources/constants/color_constants.dart';
-import 'package:cs_resources/generated/assets.dart';
 import 'package:domain/entity/response/staff_detail_entity.dart';
-import 'package:domain/entity/response/staff_labour_history_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:plugin_basic/basic_export.dart';
-import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
-import 'package:widgets/my_button.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 

+ 1 - 1
packages/cpt_job/lib/modules/applied_staff_detail/staff_labour_history_item.dart

@@ -42,7 +42,7 @@ class StaffLabourHistoryItem extends StatelessWidget {
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
               MyTextView(
-                "Job Date:".tr,
+                "Job Date".tr+":",
                 isFontRegular: true,
                 textColor: ColorConstants.textGrayAECAE5,
                 fontSize: 14,

+ 1 - 1
packages/cpt_job/lib/modules/applied_staff_reviews/applied_staff_reviews_page.dart

@@ -29,7 +29,7 @@ class AppliedStaffReviewsPage extends BaseStatefulPage<AppliedStaffReviewsContro
   //启动当前页面
   static void startInstance(String? memberId, String? staffName, double? reviews, String? reviewCount) {
     return Get.start(
-      RouterPath.JOB_APPLIED_STAFF_REVIEWS,
+      RouterPath.jobAppliedStaffReviews,
       arguments: {'memberId': memberId, 'staffName': staffName, 'reviews': reviews, 'reviewCount': reviewCount},
     );
   }

+ 1 - 1
packages/cpt_job/lib/modules/applied_workflow/applied_workflow_page.dart

@@ -23,7 +23,7 @@ class AppliedWorkflowPage extends BaseStatefulPage<AppliedWorkflowController> {
 
   //启动当前页面
   static void startInstance(String? appliedId) {
-    return Get.start(RouterPath.JOB_APPLIED_STAFF_WORKFLOW,arguments: {'appliedId': appliedId});
+    return Get.start(RouterPath.jobAppliedStaffWorkflow,arguments: {'appliedId': appliedId});
   }
 
   @override

+ 1 - 0
packages/cpt_job/lib/modules/job_applied/job_applied_controller.dart

@@ -393,4 +393,5 @@ class JobAppliedController extends GetxController with DioCancelableMixin {
       ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
     }
   }
+
 }

+ 1 - 1
packages/cpt_job/lib/modules/job_applied/job_applied_page.dart

@@ -28,7 +28,7 @@ class JobAppliedPage extends BaseStatefulPage<JobAppliedController> {
 
   //启动当前页面
   static void startInstance(String? jobId) {
-    return Get.start(RouterPath.JOB_APPLIED_STAFF_LIST, arguments: {'jobId': jobId});
+    return Get.start(RouterPath.jobAppliedStaffList, arguments: {'jobId': jobId});
   }
 
   @override

+ 3 - 3
packages/cpt_job/lib/modules/job_applied_edit/job_applied_edit_page.dart

@@ -4,12 +4,12 @@ import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:get/get.dart';
-import 'package:widgets/custom_radio_check.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_button.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/no_shadow_scroll_behavior.dart';
+import 'package:widgets/shatter/custom_radio_check.dart';
 import 'package:widgets/shatter/form_require_text.dart';
 import 'package:widgets/shatter/round_my_text_field.dart';
 import 'package:widgets/widget_export.dart';
@@ -33,7 +33,7 @@ class JobAppliedEditPage extends BaseStatefulPage<JobAppliedEditController> {
 
   //启动当前页面
   static void startInstance(String? appliedId) {
-    return Get.start(RouterPath.JOB_APPLIED_STAFF_EDIT, arguments: {'appliedId': appliedId});
+    return Get.start(RouterPath.jobAppliedStaffEdit, arguments: {'appliedId': appliedId});
   }
 
   @override
@@ -434,7 +434,7 @@ class _JobAppliedEditState extends BaseState<JobAppliedEditPage, JobAppliedEditC
                         isFontRegular: true,
                       ),
 
-                      //选择签到功能还是全功能
+                      //理由的单
                       state.appliedEditView != null
                           ? CustomRadioCheck(
                               options: state.appliedEditView!.reasonList!.map((e) => e.txt).whereType<String>().toList(), //后台返回的数据展示,并且根据后台的数据匹配索引

+ 22 - 22
packages/cpt_job/lib/modules/job_list/job_list_filter.dart

@@ -66,9 +66,9 @@ class _JobListFilterState extends State<JobListFilter> {
           height: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1,
         ),
         Container(
-          padding: EdgeInsets.only(left: 15, right: 15, top: 17.5, bottom: 20),
+          padding: const EdgeInsets.only(left: 15, right: 15, top: 17.5, bottom: 20),
           width: double.infinity,
-          decoration: BoxDecoration(
+          decoration: const BoxDecoration(
             color: Colors.white,
           ),
           child: Column(
@@ -84,12 +84,12 @@ class _JobListFilterState extends State<JobListFilter> {
 
               //选择部门
               Container(
-                padding: EdgeInsets.only(left: 16, right: 10),
-                margin: EdgeInsets.only(top: 10),
+                padding: const EdgeInsets.only(left: 16, right: 10),
+                margin: const EdgeInsets.only(top: 10),
                 height: 45,
-                decoration: BoxDecoration(
+                decoration: const BoxDecoration(
                   color: ColorConstants.grayECECEC,
-                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  borderRadius: BorderRadius.all(Radius.circular(5)),
                 ),
                 child: Row(
                   mainAxisSize: MainAxisSize.max,
@@ -106,7 +106,7 @@ class _JobListFilterState extends State<JobListFilter> {
                       isFontMedium: true,
                       textColor: ColorConstants.black33,
                     ).expanded(),
-                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
                   ],
                 ),
               ).onTap(() {
@@ -124,12 +124,12 @@ class _JobListFilterState extends State<JobListFilter> {
 
               //选择状态
               Container(
-                padding: EdgeInsets.only(left: 16, right: 10),
-                margin: EdgeInsets.only(top: 10),
+                padding: const EdgeInsets.only(left: 16, right: 10),
+                margin: const EdgeInsets.only(top: 10),
                 height: 45,
-                decoration: BoxDecoration(
+                decoration: const BoxDecoration(
                   color: ColorConstants.grayECECEC,
-                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  borderRadius: BorderRadius.all(Radius.circular(5)),
                 ),
                 child: Row(
                   mainAxisSize: MainAxisSize.max,
@@ -146,7 +146,7 @@ class _JobListFilterState extends State<JobListFilter> {
                       isFontMedium: true,
                       textColor: ColorConstants.black33,
                     ).expanded(),
-                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
                   ],
                 ),
               ).onTap(() {
@@ -164,12 +164,12 @@ class _JobListFilterState extends State<JobListFilter> {
 
               //选择时间
               Container(
-                padding: EdgeInsets.only(left: 16, right: 10),
-                margin: EdgeInsets.only(top: 10),
+                padding: const EdgeInsets.only(left: 16, right: 10),
+                margin: const EdgeInsets.only(top: 10),
                 height: 45,
-                decoration: BoxDecoration(
+                decoration: const BoxDecoration(
                   color: ColorConstants.grayECECEC,
-                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  borderRadius: BorderRadius.all(Radius.circular(5)),
                 ),
                 child: Row(
                   mainAxisSize: MainAxisSize.max,
@@ -184,7 +184,7 @@ class _JobListFilterState extends State<JobListFilter> {
                       isFontMedium: true,
                       textColor: ColorConstants.black33,
                     ).expanded(),
-                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
                   ],
                 ),
               ).onTap(() {
@@ -202,12 +202,12 @@ class _JobListFilterState extends State<JobListFilter> {
 
               //选择结束日期
               Container(
-                padding: EdgeInsets.only(left: 16, right: 10),
-                margin: EdgeInsets.only(top: 10),
+                padding: const EdgeInsets.only(left: 16, right: 10),
+                margin: const EdgeInsets.only(top: 10),
                 height: 45,
-                decoration: BoxDecoration(
+                decoration: const BoxDecoration(
                   color: ColorConstants.grayECECEC,
-                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  borderRadius: BorderRadius.all(Radius.circular(5)),
                 ),
                 child: Row(
                   mainAxisSize: MainAxisSize.max,
@@ -222,7 +222,7 @@ class _JobListFilterState extends State<JobListFilter> {
                       isFontMedium: true,
                       textColor: ColorConstants.black33,
                     ).expanded(),
-                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
                   ],
                 ),
               ).onTap(() {

+ 1 - 1
packages/cpt_job/lib/modules/job_list/job_list_page.dart

@@ -26,7 +26,7 @@ class JobListPage extends BaseStatefulPage<JobListController> {
 
   //启动当前页面
   static void startInstance() {
-    return Get.start(RouterPath.JOB_LIST);
+    return Get.start(RouterPath.jobList);
   }
 
   @override

+ 1 - 1
packages/cpt_job/lib/modules/job_list_detail/job_list_detail_page.dart

@@ -26,7 +26,7 @@ class JobListDetailPage extends BaseStatefulPage<JobListDetailController> {
 
   //启动当前页面
   static void startInstance(String? jobId) {
-    return Get.start(RouterPath.JOB_LIST_DETAIL, arguments: {'jobId': jobId});
+    return Get.start(RouterPath.jobListDetail, arguments: {'jobId': jobId});
   }
 
   @override

+ 5 - 2
packages/cpt_job/lib/modules/sign_in_sign_out/sign_in_sign_out_page.dart

@@ -1,7 +1,10 @@
+import 'dart:ui';
+
 import 'package:cs_resources/constants/color_constants.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/src/services/predictive_back_event.dart';
 import 'package:flutter/widgets.dart';
 import 'package:get/get.dart';
 import 'package:plugin_basic/base/base_stateful_page.dart';
@@ -31,7 +34,7 @@ class SignInSignOutPage extends BaseStatefulPage<SignInSignOutController> {
 
   //启动当前页面
   static void startInstance() {
-    return Get.start(RouterPath.JOB_SIGN_IN_SIGN_OUT);
+    return Get.start(RouterPath.jobSignInSignOut);
   }
 
   @override
@@ -254,7 +257,7 @@ class _SignInSignOutPageState extends BaseState<SignInSignOutPage, SignInSignOut
                   crossAxisAlignment: CrossAxisAlignment.center,
                   children: [
                     MyTextView(
-                      "Job Date:".tr,
+                      "Job Date".tr+":",
                       isFontRegular: true,
                       textColor: Color(0XFFAECAE5),
                       fontSize: 14,

+ 1 - 0
packages/cpt_job/lib/router/job_service_impl.dart

@@ -30,4 +30,5 @@ class JobServiceImpl extends GetxService implements JobService {
   void startJobListPage() {
     JobListPage.startInstance();
   }
+
 }

+ 8 - 8
packages/cpt_job/lib/router/page_router.dart

@@ -14,49 +14,49 @@ class JobPageRouter {
   static final routes = [
     //签到签出
     GetPage(
-      name: RouterPath.JOB_SIGN_IN_SIGN_OUT,
+      name: RouterPath.jobSignInSignOut,
       page: () => SignInSignOutPage(),
     ),
 
     //工作列表
     GetPage(
-      name: RouterPath.JOB_LIST,
+      name: RouterPath.jobList,
       page: () => JobListPage(),
     ),
 
     //工作列表详情
     GetPage(
-      name: RouterPath.JOB_LIST_DETAIL,
+      name: RouterPath.jobListDetail,
       page: () => JobListDetailPage(),
     ),
 
     //工作已申请列表
     GetPage(
-      name: RouterPath.JOB_APPLIED_STAFF_LIST,
+      name: RouterPath.jobAppliedStaffList,
       page: () => JobAppliedPage(),
     ),
 
     //工作已申请列表
     GetPage(
-      name: RouterPath.JOB_APPLIED_STAFF_WORKFLOW,
+      name: RouterPath.jobAppliedStaffWorkflow,
       page: () => AppliedWorkflowPage(),
     ),
 
     //编辑申请
     GetPage(
-      name: RouterPath.JOB_APPLIED_STAFF_EDIT,
+      name: RouterPath.jobAppliedStaffEdit,
       page: () => JobAppliedEditPage(),
     ),
 
     //员工详情
     GetPage(
-      name: RouterPath.JOB_APPLIED_STAFF_DETAIL,
+      name: RouterPath.jobAppliedStaffDetail,
       page: () => AppliedStaffDetailPage(),
     ),
 
     //员工评价
     GetPage(
-      name: RouterPath.JOB_APPLIED_STAFF_REVIEWS,
+      name: RouterPath.jobAppliedStaffReviews,
       page: () => AppliedStaffReviewsPage(),
     ),
 

+ 1 - 1
packages/cpt_job/pubspec.yaml

@@ -1,5 +1,5 @@
 name: cpt_job
-description: ProfileComponent Profile-Me组件
+description: 默认越南的工作模块
 
 version: 1.0.0
 

+ 31 - 0
packages/cpt_job_sg/.gitignore

@@ -0,0 +1,31 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+*.lock
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# Visual Studio Code related
+.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub-cache/
+.pub/
+/build/
+proguardMapping.txt

+ 158 - 0
packages/cpt_job_sg/lib/modules/applied_staff/applied_staff_add.dart

@@ -0,0 +1,158 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_applied_staff_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+
+/**
+ * 已申请的员工列表Item
+ */
+class AppliedStaffItem extends StatelessWidget {
+  final int index;
+  final JobAppliedStaffSGRows item;
+  final VoidCallback? onItemAction;
+
+  AppliedStaffItem({
+    required this.index,
+    required this.item,
+    this.onItemAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          //员工姓名
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Name:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //姓名
+              MyTextView(
+                item.name ?? "-",
+                isFontMedium: true,
+                textColor: ColorConstants.white,
+                fontSize: 14,
+                marginLeft: 5,
+                marginRight: 5,
+              ).expanded(),
+
+              //是否选中
+              MyAssetImage(
+                item.isSelected || item.applyState == 1 ? Assets.baseServiceItemSelectedIcon : Assets.baseServiceItemUnselectedIcon,
+                width: 20.5,
+                height: 20.5,
+              ),
+            ],
+          ),
+
+          // 性别
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Gender".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.gender ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 身份证
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Nric".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.nric ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 头像
+          Row(
+            mainAxisSize: MainAxisSize.min,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Avatar".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+                marginRight: 12,
+              ),
+              MyLoadImage(item.profilePicture, width: 100, height: 100),
+            ],
+          ).marginOnly(top: 12),
+
+          // 状态
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Status:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //发布状态
+              MyTextView(
+                item.status == 1 ? "Active" : "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: ColorConstants.textBlue06D9FF, //默认蓝色
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+        ],
+      ).onTap(() {
+        onItemAction?.call();
+      }),
+    );
+  }
+}

+ 173 - 0
packages/cpt_job_sg/lib/modules/applied_staff/applied_staff_controller.dart

@@ -0,0 +1,173 @@
+import 'package:domain/entity/response/job_applied_staff_s_g_entity.dart';
+import 'package:domain/repository/job_sg_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/constants/app_constant.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/event_bus.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'applied_staff_state.dart';
+
+class AppliedStaffController extends GetxController with DioCancelableMixin {
+  final JobSGRepository _jobRepository = Get.find();
+  final AppliedStaffState state = AppliedStaffState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchAppliedStaffList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchAppliedStaffList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchAppliedStaffList();
+  }
+
+  /// 获取服务器数据,通知消息列表
+  Future fetchAppliedStaffList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 获取 Applied 列表
+    var listResult = await _jobRepository.searchJobAppliedStaff(
+      state.jobId,
+      state.keyword,
+      curPage: _curPage,
+      cancelToken: cancelToken,
+    );
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<JobAppliedStaffSGRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchAppliedStaffList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  /// 搜索员工
+  void doSearch(String keyword) {
+    state.keyword = keyword;
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  /// 清空筛选条件
+  void resetFiltering() {
+    state.keyword = "";
+    state.searchController.text = "";
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  /// Item选中与未选中设置
+  void doSelectedOrNot(JobAppliedStaffSGRows data) {
+    //如果此人没有在工作中,可以选中与未选中
+    if (data.applyState == 0){
+      data.isSelected = !data.isSelected;
+      update();
+    }
+
+  }
+
+  /// 提交选中的成员
+  void doSubmit() async {
+    //筛选选中的员工
+    final ids = state.datas.where((element) => element.isSelected).map((e) => e.id).toList();
+
+    if (ids.isEmpty) {
+      ToastEngine.show("Choose Staff".tr);
+      return;
+    }
+
+    var result = await _jobRepository.addStaff2AppliedJob(state.jobId, ids.join(","), cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+      Get.back();
+      bus.emit(AppConstant.eventAppliedListRefresh, "");
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      return;
+    }
+  }
+
+}

+ 156 - 0
packages/cpt_job_sg/lib/modules/applied_staff/applied_staff_page.dart

@@ -0,0 +1,156 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/search_app_bar.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'applied_staff_add.dart';
+import 'applied_staff_controller.dart';
+
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/my_appbar.dart';
+import 'applied_staff_state.dart';
+
+/**
+ * 已申请的页面,添加员工页面
+ */
+class AppliedStaffPage extends BaseStatefulPage<AppliedStaffController> {
+  AppliedStaffPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(String? jobId) {
+    return Get.start(RouterPath.jobListAppliedStaffListSG, arguments: {'jobId': jobId});
+  }
+
+  @override
+  AppliedStaffController createRawController() {
+    return AppliedStaffController();
+  }
+
+  @override
+  State<AppliedStaffPage> createState() => _AppliedStaffState();
+}
+
+class _AppliedStaffState extends BaseState<AppliedStaffPage, AppliedStaffController> {
+  late AppliedStaffState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.jobId = Get.arguments['jobId'];
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return SafeArea(
+        bottom: true,
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+            ),
+          ),
+          child: Column(
+            children: [
+              MyAppBar.titleBar(
+                context,
+                "Add Staff - Choose Staff".tr,
+              ),
+
+              //搜索的条件
+              Row(
+                children: [
+                  SearchAppBar(
+                    value: state.keyword,
+                    onSearch: (keyword) {
+                      controller.doSearch(keyword);
+                    },
+                    hintText: "Name / Nric".tr,
+                    controller: state.searchController,
+                  ).expanded(),
+                  MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      controller.resetFiltering();
+                    },
+                    text: "Reset".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#2BA9F9", opacity: 0.5),
+                    radius: 20,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ),
+                ],
+              ).marginOnly(top: 10, left: 15, right: 15, bottom: 5),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                        return AppliedStaffItem(
+                          index: index,
+                          item: state.datas[index],
+                          onItemAction: () {
+                            controller.doSelectedOrNot(state.datas[index]);
+                          },
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).expanded(),
+
+              MyTextView(
+                "Submit".tr,
+                fontSize: 17,
+                isFontMedium: true,
+                boxHeight: 48,
+                onClick: () {
+                  controller.doSubmit();
+                },
+                alignment: Alignment.center,
+                textAlign: TextAlign.center,
+                textColor: Colors.white,
+                backgroundColor: Color(0XFFFFBB1B),
+              ),
+
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 12 - 0
packages/cpt_job_sg/lib/modules/applied_staff/applied_staff_state.dart

@@ -0,0 +1,12 @@
+import 'package:domain/entity/response/job_applied_staff_s_g_entity.dart';
+import 'package:flutter/material.dart';
+
+class AppliedStaffState {
+  //筛选条件
+  final TextEditingController searchController = TextEditingController();
+  String keyword = "";
+
+  String? jobId;
+
+  List<JobAppliedStaffSGRows> datas = []; //员工列表
+}

+ 152 - 0
packages/cpt_job_sg/lib/modules/applied_staff_detail/applied_staff_detail_controller.dart

@@ -0,0 +1,152 @@
+import 'package:domain/entity/response/staff_detail_s_g_entity.dart';
+import 'package:domain/entity/response/staff_job_history_s_g_entity.dart';
+import 'package:domain/repository/job_sg_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/loading/loading_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../applied_staff_reviews/applied_staff_reviews_page.dart';
+import 'applied_staff_detail_state.dart';
+
+class AppliedStaffDetailController extends GetxController with DioCancelableMixin {
+  final JobSGRepository _jobRepository = Get.find();
+  final AppliedStaffDetailState state = AppliedStaffDetailState();
+
+  var _curPage = 1;
+  var _isSearch = false;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchStaffDetail();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchStaffDetail();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchStaffDetail();
+  }
+
+  /// 获取列表数据
+  Future fetchStaffDetail() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    } else if (_isSearch) {
+      LoadingEngine.show();
+    }
+
+    // 并发执行两个请求
+    var futures = [
+      _jobRepository.fetchStaffJobHistory(
+        state.memberId,
+        curPage: _curPage,
+        cancelToken: cancelToken,
+      ),
+      state.detail == null
+          ? _jobRepository.fetchStaffDetail(state.memberId, cancelToken: cancelToken)
+          : Future(() => HttpResult(isSuccess: true).convert(data: state.detail!)),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<StaffJobHistorySGEntity>;
+    var detailResult = results[1] as HttpResult<StaffDetailSGEntity>;
+
+    //详情数据
+    if (state.detail == null && detailResult.isSuccess) {
+      state.detail = detailResult.data!;
+    }
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    _isSearch = false;
+    LoadingEngine.dismiss();
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<StaffJobHistorySGRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchStaffDetail();
+  }
+
+  @override
+  void onClose() {
+    super.onClose();
+  }
+
+  // 去员工的评论列表页面
+  void gotoReviewHistoryPage() {
+    AppliedStaffReviewsPage.startInstance(
+      state.memberId,
+      state.detail?.workerName,
+      double.parse(state.detail?.reviews?.avgScore ?? "5.0"),
+      state.detail?.reviews?.count.toString() ?? "0",
+    );
+  }
+}

+ 120 - 0
packages/cpt_job_sg/lib/modules/applied_staff_detail/applied_staff_detail_page.dart

@@ -0,0 +1,120 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/widget_export.dart';
+import 'applied_staff_detail_controller.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/my_appbar.dart';
+
+import 'applied_staff_detail_state.dart';
+import 'staff_detail_widget.dart';
+import 'staff_labour_history_item.dart';
+
+/**
+ * 员工的详情(新加坡)
+ */
+class AppliedStaffDetailPage extends BaseStatefulPage<AppliedStaffDetailController> {
+  AppliedStaffDetailPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(String? memberId) {
+    return Get.start(RouterPath.jobListAppliedStaffDetailSG, arguments: {'memberId': memberId});
+  }
+
+  @override
+  AppliedStaffDetailController createRawController() {
+    return AppliedStaffDetailController();
+  }
+
+  @override
+  State<AppliedStaffDetailPage> createState() => _AppliedStaffDetailState();
+}
+
+class _AppliedStaffDetailState extends BaseState<AppliedStaffDetailPage, AppliedStaffDetailController> {
+  late AppliedStaffDetailState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.memberId = Get.arguments['memberId'];
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return SafeArea(
+          bottom: true,
+          top: false,
+          child: Container(
+            width: double.infinity,
+            height: double.infinity,
+            padding: EdgeInsets.only(top:ScreenUtil.getStatusBarH(context)),
+            decoration: const BoxDecoration(
+              gradient: LinearGradient(
+                colors: [
+                  Color(0xFF091D44),
+                  Color(0xFF245A8A),
+                  Color(0xFF7F7CEC),
+                ],
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+              ),
+            ),
+            child: Column(
+              children: [
+                MyAppBar.titleBar(context, "Staff Detail".tr),
+
+                EasyRefresh(
+                  controller: controller.refreshController,
+                  onRefresh: controller.onRefresh,
+                  onLoad: controller.loadMore,
+                  child: LoadStateLayout(
+                    state: controller.loadingState,
+                    errorMessage: controller.errorMessage,
+                    errorRetry: () {
+                      controller.retryRequest();
+                    },
+                    successSliverWidget: [
+                      //顶部用户信息
+                      SliverToBoxAdapter(
+                        child: StaffDetailWidget(detail: state.detail,onRemarkAction: (){
+                          controller.gotoReviewHistoryPage();
+                        }),
+                      ),
+
+                      SliverToBoxAdapter(
+                        child: MyTextView(
+                          "Job History",
+                          marginLeft: 15,
+                          marginTop: 10,
+                          fontSize: 17,
+                          textColor: ColorConstants.white,
+                          isFontMedium: true,
+                        ),
+                      ),
+
+                      //底部工作历史列表
+                      SliverList(delegate: SliverChildBuilderDelegate((context, index) {
+                          return StaffLabourHistoryItem(index: index, item: state.datas[index]);
+                        },
+                        childCount: state.datas.length,
+                      ))
+                    ],
+                  ),
+                ).marginOnly(top: 5,bottom: 5).expanded(),
+              ],
+            ),
+          ),
+        );
+    });
+  }
+
+}

+ 14 - 0
packages/cpt_job_sg/lib/modules/applied_staff_detail/applied_staff_detail_state.dart

@@ -0,0 +1,14 @@
+import 'package:domain/entity/response/staff_detail_s_g_entity.dart';
+import 'package:domain/entity/response/staff_job_history_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+
+class AppliedStaffDetailState {
+
+  TextEditingController? searchController;
+
+  String? memberId;
+
+  StaffDetailSGEntity? detail;
+  List<StaffJobHistorySGRows> datas = [];
+
+}

+ 170 - 0
packages/cpt_job_sg/lib/modules/applied_staff_detail/staff_detail_widget.dart

@@ -0,0 +1,170 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/staff_detail_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+
+/**
+ * 员工的做工记录
+ */
+class StaffDetailWidget extends StatelessWidget {
+  final StaffDetailSGEntity? detail;
+  final void Function() onRemarkAction;
+
+  StaffDetailWidget({
+    required this.detail,
+    required this.onRemarkAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 10),
+      decoration: BoxDecoration(
+        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          //头像
+          Center(
+              child: MyLoadImage(
+            detail?.icon,
+            width: 100,
+            height: 100,
+          )).marginOnly(top: 25, bottom: 15),
+
+          //姓名
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              MyTextView(
+                "Name:".tr,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+                isFontRegular: true,
+              ),
+              MyTextView(
+                detail?.workerName ?? "-",
+                marginLeft: 5,
+                textColor: ColorConstants.white,
+                fontSize: 14,
+                isFontMedium: true,
+              ).expanded(),
+            ],
+          ).marginOnly(left: 22, right: 22),
+
+          //性别
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              MyTextView(
+                "Gender".tr+":",
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+                isFontRegular: true,
+              ),
+              MyTextView(
+                detail?.sex ?? "-",
+                marginLeft: 5,
+                textColor: ColorConstants.white,
+                fontSize: 14,
+                isFontMedium: true,
+              ).expanded(),
+            ],
+          ).marginOnly(left: 22, right: 22, top: 10),
+
+          //电话号码
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              MyTextView(
+                "Mobile".tr + ":",
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+                isFontRegular: true,
+              ),
+              MyTextView(
+                detail?.mobile ?? "-",
+                marginLeft: 5,
+                textColor: ColorConstants.white,
+                fontSize: 14,
+                isFontMedium: true,
+              ).expanded(),
+            ],
+          ).marginOnly(left: 22, right: 22, top: 10),
+
+          //身份证
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              MyTextView(
+                "Nric".tr + ":",
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+                isFontRegular: true,
+              ),
+              MyTextView(
+                detail?.nric ?? "-",
+                marginLeft: 5,
+                textColor: ColorConstants.white,
+                fontSize: 14,
+                isFontMedium: true,
+              ).expanded(),
+            ],
+          ).marginOnly(left: 22, right: 22, top: 10),
+
+          //评分
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              MyTextView(
+                "Reviews".tr + ":",
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+                isFontRegular: true,
+              ),
+              MyTextView(
+                "${detail?.reviews?.avgScore.toString() ?? "-"} (${detail?.reviews?.count ?? "0"} Reviews)",
+                marginLeft: 5,
+                textColor: ColorConstants.textGreen0AC074,
+                fontSize: 14,
+                onClick: onRemarkAction,
+                isFontMedium: true,
+                textDecoration: TextDecoration.underline,
+                decorationColor: ColorConstants.textGreen0AC074,
+                decorationThickness: 2.0,
+                decorationStyle: TextDecorationStyle.solid,
+              ).expanded(),
+            ],
+          ).marginOnly(left: 22, right: 22, top: 10),
+
+          //时薪
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              MyTextView(
+                "Hourly Rate".tr + ":",
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+                isFontRegular: true,
+              ),
+              MyTextView(
+                detail?.hourlyRate ?? "-",
+                marginLeft: 5,
+                textColor: ColorConstants.white,
+                fontSize: 14,
+                isFontMedium: true,
+              ).expanded(),
+            ],
+          ).marginOnly(left: 22, right: 22, top: 10, bottom: 26),
+        ],
+      ),
+    );
+  }
+}

+ 183 - 0
packages/cpt_job_sg/lib/modules/applied_staff_detail/staff_labour_history_item.dart

@@ -0,0 +1,183 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/staff_job_history_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
+
+/**
+ * 员工的做工记录
+ */
+class StaffLabourHistoryItem extends StatelessWidget {
+  final int index;
+  final StaffJobHistorySGRows item;
+
+  StaffLabourHistoryItem({
+    required this.index,
+    required this.item,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          //工作日期
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Job Date".tr+":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期
+              MyTextView(
+                item.jobDate ?? "-",
+                isFontRegular: true,
+                textColor: ColorConstants.white,
+                fontSize: 14,
+                marginLeft: 5,
+                marginRight: 5,
+              ).expanded(),
+
+            ],
+          ),
+
+          // 工作开始时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Start Time:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.startTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          //工作结束时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "End Time:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.endTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          //工作标题(模板)
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Job Title".tr+":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //标题
+              MyTextView(
+                item.jobTitle ?? "-",
+                isFontRegular: true,
+                textColor: ColorConstants.white,
+                fontSize: 14,
+                marginLeft: 5,
+                marginRight: 5,
+              ).expanded(),
+
+            ],
+          ).marginOnly(top: 12),
+
+          //部门
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Outlet:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //部门
+              MyTextView(
+                item.outletName ?? "-",
+                isFontRegular: true,
+                textColor: ColorConstants.white,
+                fontSize: 14,
+                marginLeft: 5,
+                marginRight: 5,
+              ).expanded(),
+
+            ],
+          ).marginOnly(top: 12),
+
+          // 状态
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Status:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //发布状态
+              MyTextView(
+                item.statusShow ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white ,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+        ],
+      ),
+    );
+  }
+}

+ 109 - 0
packages/cpt_job_sg/lib/modules/applied_staff_reviews/applied_staff_reviews_controller.dart

@@ -0,0 +1,109 @@
+import 'package:domain/entity/response/staff_remark_history_entity.dart';
+import 'package:domain/entity/response/staff_review_history_s_g_entity.dart';
+import 'package:domain/repository/job_sg_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'applied_staff_reviews_state.dart';
+
+class AppliedStaffReviewsController extends GetxController with DioCancelableMixin {
+  final JobSGRepository _jobRepository = Get.find();
+  final AppliedStaffReviewsState state = AppliedStaffReviewsState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchStaffReviews();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchStaffReviews();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchStaffReviews();
+  }
+
+  /// 获取列表数据
+  Future fetchStaffReviews() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    var listResult = await _jobRepository.fetchStaffReviewHistory(state.memberId, curPage: _curPage, cancelToken: cancelToken);
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.reviews);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<StaffReviewHistorySGReviews>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchStaffReviews();
+  }
+}

+ 151 - 0
packages/cpt_job_sg/lib/modules/applied_staff_reviews/applied_staff_reviews_item.dart

@@ -0,0 +1,151 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/staff_review_history_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/shatter/rating_widget.dart';
+
+/**
+ * 员工的评价记录
+ */
+class StaffReviewsItem extends StatelessWidget {
+  final int index;
+  final StaffReviewHistorySGReviews item;
+
+  StaffReviewsItem({
+    required this.index,
+    required this.item,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: EdgeInsets.only(bottom: 25, left: 21,right: 21,top: 18.5),
+      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          MyTextView(
+            item.employerName ?? "",
+            isFontRegular: true,
+            textColor: Colors.white,
+            fontSize: 17,
+          ),
+
+          //态度评分
+          Row(
+            children: [
+              MyTextView(
+                "Attitude".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 15,
+              ).expanded(flex: 2),
+              RatingWidget(
+                nomalImage: Assets.baseServiceRatingUnselected,
+                selectImage: Assets.baseServiceRatingSelected,
+                size: 21,
+                padding: 5,
+                selectAble: false,
+                integerOnly: true,
+                value: item.attitudeRate,
+                onRatingUpdate: (value) {},
+              ).expanded(flex: 3)
+            ],
+          ).marginOnly(top: 15),
+
+          //表现评分
+          Row(
+            children: [
+              MyTextView(
+                "Performance".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 15,
+              ).expanded(flex: 2),
+              RatingWidget(
+                nomalImage: Assets.baseServiceRatingUnselected,
+                selectImage: Assets.baseServiceRatingSelected,
+                size: 21,
+                padding: 5,
+                selectAble: false,
+                integerOnly: true,
+                value: item.performanceRate,
+                onRatingUpdate: (value) {},
+              ).expanded(flex: 3)
+            ],
+          ).marginOnly(top: 15),
+
+          //经验评分
+          Row(
+            children: [
+              MyTextView(
+                "Experience".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 15,
+              ).expanded(flex: 2),
+              RatingWidget(
+                nomalImage: Assets.baseServiceRatingUnselected,
+                selectImage: Assets.baseServiceRatingSelected,
+                size: 21,
+                padding: 5,
+                selectAble: false,
+                integerOnly: true,
+                value: item.experienceRate,
+                onRatingUpdate: (value) {},
+              ).expanded(flex: 3)
+            ],
+          ).marginOnly(top: 15),
+
+          //着装评分
+          Row(
+            children: [
+              MyTextView(
+                "Grooming".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 15,
+              ).expanded(flex: 2),
+              RatingWidget(
+                nomalImage: Assets.baseServiceRatingUnselected,
+                selectImage: Assets.baseServiceRatingSelected,
+                size: 21,
+                padding: 5,
+                selectAble: false,
+                integerOnly: true,
+                value: item.groomingRate,
+                onRatingUpdate: (value) {},
+              ).expanded(flex: 3)
+            ],
+          ).marginOnly(top: 15),
+
+          MyTextView(
+            item.feedback ?? "",
+            textColor: Colors.white,
+            fontSize: 15,
+            isFontRegular: true,
+            borderColor: Color(0XFF6D92BA),
+            borderWidth: 0.5,
+            boxHeight: 130,
+            boxWidth: double.infinity,
+            paddingTop: 15,
+            paddingLeft: 12.5,
+            paddingRight: 12.5,
+            paddingBottom: 15,
+            marginTop: 18,
+          ),
+
+        ],
+      ),
+    );
+  }
+}

+ 162 - 0
packages/cpt_job_sg/lib/modules/applied_staff_reviews/applied_staff_reviews_page.dart

@@ -0,0 +1,162 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/shatter/rating_widget.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'applied_staff_reviews_controller.dart';
+
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/my_appbar.dart';
+
+import 'applied_staff_reviews_item.dart';
+import 'applied_staff_reviews_state.dart';
+
+/**
+ * 员工的评论页面
+ */
+class AppliedStaffReviewsPage extends BaseStatefulPage<AppliedStaffReviewsController> {
+  AppliedStaffReviewsPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(String? memberId, String? staffName, double? reviews, String? reviewCount) {
+    return Get.start(
+      RouterPath.jobListAppliedStaffReviewSG,
+      arguments: {'memberId': memberId, 'staffName': staffName, 'reviews': reviews, 'reviewCount': reviewCount},
+    );
+  }
+
+  @override
+  AppliedStaffReviewsController createRawController() {
+    return AppliedStaffReviewsController();
+  }
+
+  @override
+  State<AppliedStaffReviewsPage> createState() => _AppliedStaffReviewsState();
+}
+
+class _AppliedStaffReviewsState extends BaseState<AppliedStaffReviewsPage, AppliedStaffReviewsController> {
+  late AppliedStaffReviewsState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.memberId = Get.arguments['memberId'];
+    state.staffName = Get.arguments['staffName'];
+    state.reviews = Get.arguments['reviews'];
+    state.reviewCount = Get.arguments['reviewCount'];
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return SafeArea(
+        bottom: true,
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+            ),
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              MyAppBar.titleBar(context, "Staff Reviews".tr),
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    //顶部用户信息
+                    SliverToBoxAdapter(
+                      child: _buildRemarkWidget(),
+                    ),
+
+                    //底部工作历史列表
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                        return StaffReviewsItem(index: index, item: state.datas[index]);
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+
+  Widget _buildRemarkWidget() {
+    return Container(
+      padding: EdgeInsets.only(bottom: 22, left: 21, right: 21, top: 18.5),
+      margin: EdgeInsets.only(left: 15, right: 15, top: 14.5, bottom: 5),
+      decoration: BoxDecoration(
+        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          MyTextView(
+            state.staffName ?? "-",
+            fontSize: 17,
+            textColor: ColorConstants.white,
+            isFontMedium: true,
+            marginBottom: 8,
+          ),
+          Row(
+            children: [
+              RatingWidget(
+                nomalImage: Assets.baseServiceRatingUnselected,
+                selectImage: Assets.baseServiceRatingSelected,
+                size: 21,
+                padding: 5,
+                selectAble: false,
+                integerOnly: false,
+                value: state.reviews ?? 0,
+                onRatingUpdate: (value) {},
+              ),
+              MyTextView(
+                "${state.reviews.toString()} (${state.reviewCount} Reviews)",
+                fontSize: 14,
+                marginLeft: 12,
+                textColor: ColorConstants.textYellowF8AE00,
+                isFontMedium: true,
+              ).expanded(),
+            ],
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 10 - 0
packages/cpt_job_sg/lib/modules/applied_staff_reviews/applied_staff_reviews_state.dart

@@ -0,0 +1,10 @@
+import 'package:domain/entity/response/staff_review_history_s_g_entity.dart';
+
+class AppliedStaffReviewsState {
+  String? memberId;
+  String? staffName;
+  double? reviews;
+  String? reviewCount;
+
+  List<StaffReviewHistorySGReviews> datas = [];
+}

+ 426 - 0
packages/cpt_job_sg/lib/modules/job_applied/applied_staff_item.dart

@@ -0,0 +1,426 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_applied_list_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/shatter/border_select_widget.dart';
+
+/**
+ * 已申请的员工列表Item
+ */
+class AppliedStaffItem extends StatelessWidget {
+  final int index;
+  final JobAppliedListSGRows item;
+  final VoidCallback? onModifyAction;
+  final VoidCallback? onEditAction;
+  final VoidCallback? onRemarkAction;
+  final VoidCallback? onItemAction;
+  final VoidCallback? onReviseAction;
+  final VoidCallback? onMemberAction;
+  final void Function(BuildContext targetContext)? onStatusAction;
+
+  AppliedStaffItem({
+    required this.index,
+    required this.item,
+    this.onModifyAction,
+    this.onRemarkAction,
+    this.onEditAction,
+    this.onItemAction,
+    this.onReviseAction,
+    this.onMemberAction,
+    this.onStatusAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: const EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: const EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: const Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          //员工姓名
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Staff Name:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //姓名
+              MyTextView(
+                item.labourerName ?? "-",
+                isFontMedium: true,
+                textColor: ColorConstants.textYellowFFBB1B,
+                fontSize: 14,
+                marginLeft: 5,
+                marginRight: 5,
+                textDecoration: TextDecoration.underline,
+                decorationColor: ColorConstants.textYellowFFBB1B,
+                // 可选,设置下划线的颜色
+                decorationThickness: 2.0,
+                // 可选,设置下划线的粗细
+                decorationStyle: TextDecorationStyle.solid,
+                onClick: onMemberAction,
+              ).expanded(),
+
+              //是否选中
+              Visibility(
+                visible: true,
+                child: MyAssetImage(
+                  item.isSelected ? Assets.baseServiceItemSelectedIcon : Assets.baseServiceItemUnselectedIcon,
+                  width: 20.5,
+                  height: 20.5,
+                ),
+              ),
+            ],
+          ),
+
+          // 身份证
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Nric".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.labourerNric ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 性别
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Gender".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.gender ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 部门
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Outlet".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.outletName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 大厅
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Ballroom".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 工作开始时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Start Time:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.startTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 工作签到时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Work Clock In".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.workIn?.time ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: item.workIn?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          //工作结束时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "End Time:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.endTime ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 工作签出时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "${"Work Clock Out".tr}:",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                item.workOut?.time ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: item.workOut?.changed == 1 ? ColorConstants.textRedFF6262 : Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // + - Hours
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "+/- Hours:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //小时
+              MyTextView(
+                item.adjustHours ?? "",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // Total Hours
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Total Hours:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //小时
+              MyTextView(
+                item.totalHours ?? "",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 12),
+
+          // 状态
+          Row(
+            children: [
+              MyTextView(
+                "Status:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //发布状态
+              BorderSelectWidget(
+                text: item.statusShow ?? "",
+                color: "Completed" == item.statusShow
+                    ? ColorConstants.textGreen00FB92
+                    : "Cancelled" == item.statusShow || "Rejected" == item.statusShow
+                        ? ColorConstants.textRedFF6262
+                        : "Revised" == item.statusShow || "Pending" == item.statusShow || "Approve" == item.statusShow
+                            ? ColorConstants.textYellowFFBB1B
+                            : ColorConstants.textBlue5CEEFF,
+                onTap: (targetContext) {
+                  onStatusAction?.call(targetContext);
+                },
+              ),
+            ],
+          ).marginOnly(top: 12),
+
+          //按钮组
+          Visibility(
+            visible: item.actionList?.isNotEmpty ?? false,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                //编辑按钮
+                Visibility(
+                  visible: item.actionList?.contains("edit") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onEditAction?.call();
+                    },
+                    text: "Edit".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor(
+                      "#FFBB1B",
+                    ),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //状态工作流按钮
+                Visibility(
+                  visible: item.actionList?.contains("modify") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onModifyAction?.call();
+                    },
+                    text: "Modify".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#0AC074"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                Visibility(
+                  visible: item.actionList?.contains("revise") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onReviseAction?.call();
+                    },
+                    text: "Revise".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#0AC074"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //Remark按钮
+                Visibility(
+                  visible: item.actionList?.contains("remarks") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onRemarkAction?.call();
+                    },
+                    text: "Remarks".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#56AAFF"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+              ],
+            ).marginOnly(top: 15),
+          ),
+        ],
+      ).onTap(() {
+        onItemAction?.call();
+      }),
+    );
+  }
+}

+ 313 - 0
packages/cpt_job_sg/lib/modules/job_applied/applied_staff_reviews.dart

@@ -0,0 +1,313 @@
+import 'dart:ui';
+
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_applied_remark_view_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/shatter/rating_widget.dart';
+import 'package:widgets/widget_export.dart';
+
+/**
+ * 员工的评价弹窗
+ */
+class AppliedStaffReviews extends StatefulWidget {
+  JobAppliedRemarkViewSGEntity appliedReviews;
+  void Function(String attitudeRate, String performanceRate, String experienceRate, String groomingRate, String content)? confirmAction;
+
+  AppliedStaffReviews({required this.appliedReviews, this.confirmAction});
+
+  @override
+  State<AppliedStaffReviews> createState() => _AppliedStaffReviewsState();
+}
+
+class _AppliedStaffReviewsState extends State<AppliedStaffReviews> {
+  late JobAppliedRemarkViewSGEntity reviews;
+  late String attitudeRate;
+  late String groomingRate;
+  late String performanceRate;
+  late String experienceRate;
+  late String content;
+  late TextEditingController _controller;
+  late FocusNode _focusNode;
+
+  @override
+  void initState() {
+    super.initState();
+    _controller = TextEditingController();
+    _focusNode = FocusNode();
+
+    reviews = widget.appliedReviews;
+    attitudeRate = reviews.attitudeRate.toString();
+    groomingRate = reviews.groomingRate.toString();
+    performanceRate = reviews.performanceRate.toString();
+    experienceRate = reviews.experienceRate.toString();
+    _controller.text = reviews.feedback ?? "";
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.center,
+      mainAxisAlignment: MainAxisAlignment.center,
+      children: [
+        //Title (如果使用 Container 为最外层容器则默认为 match_parent 的效果,除非我们限制宽度和最大高度最小高度)
+        Container(
+          width: double.infinity,
+          decoration: BoxDecoration(
+            color: Colors.white,
+            borderRadius: const BorderRadius.all(Radius.circular(15)),
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              Center(
+                child: MyTextView(
+                  "Remarks".tr,
+                  fontSize: 19,
+                  isFontMedium: true,
+                  textColor: ColorConstants.black,
+                  marginTop: 23,
+                  marginBottom: 19,
+                  marginLeft: 22,
+                  marginRight: 22,
+                ),
+              ),
+
+              MyTextView(
+                reviews.labourerName ?? "",
+                isFontRegular: true,
+                textColor: Colors.black,
+                marginLeft: 22,
+                marginRight: 22,
+                fontSize: 17,
+              ),
+
+              //态度评分
+              Row(
+                children: [
+                  MyTextView(
+                    "Attitude".tr,
+                    isFontRegular: true,
+                    textColor: ColorConstants.black66,
+                    fontSize: 15,
+                  ).expanded(),
+                  RatingWidget(
+                    nomalImage: Assets.baseServiceRatingUnselected,
+                    selectImage: Assets.baseServiceRatingSelected,
+                    size: 21,
+                    padding: 5,
+                    selectAble: Utils.isEmpty(reviews.feedback),
+                    integerOnly: true,
+                    value: reviews.attitudeRate,
+                    onRatingUpdate: (value) {
+                      attitudeRate = value;
+                    },
+                  )
+                ],
+              ).marginOnly(top: 15, left: 22, right: 22),
+
+              //表现评分
+              Row(
+                children: [
+                  MyTextView(
+                    "Performance".tr,
+                    isFontRegular: true,
+                    textColor: ColorConstants.black66,
+                    fontSize: 15,
+                  ).expanded(),
+                  RatingWidget(
+                    nomalImage: Assets.baseServiceRatingUnselected,
+                    selectImage: Assets.baseServiceRatingSelected,
+                    size: 21,
+                    padding: 5,
+                    selectAble: Utils.isEmpty(reviews.feedback),
+                    integerOnly: true,
+                    value: reviews.performanceRate,
+                    onRatingUpdate: (value) {
+                      performanceRate = value;
+                    },
+                  )
+                ],
+              ).marginOnly(top: 15, left: 22, right: 22),
+
+              //经验评分
+              Row(
+                children: [
+                  MyTextView(
+                    "Experience".tr,
+                    isFontRegular: true,
+                    textColor: ColorConstants.black66,
+                    fontSize: 15,
+                  ).expanded(),
+                  RatingWidget(
+                    nomalImage: Assets.baseServiceRatingUnselected,
+                    selectImage: Assets.baseServiceRatingSelected,
+                    size: 21,
+                    padding: 5,
+                    selectAble: Utils.isEmpty(reviews.feedback),
+                    integerOnly: true,
+                    value: reviews.experienceRate,
+                    onRatingUpdate: (value) {
+                      experienceRate = value;
+                    },
+                  )
+                ],
+              ).marginOnly(top: 15, left: 22, right: 22),
+
+              //着装评分
+              Row(
+                children: [
+                  MyTextView(
+                    "Grooming".tr,
+                    isFontRegular: true,
+                    textColor: ColorConstants.black66,
+                    fontSize: 15,
+                  ).expanded(),
+                  RatingWidget(
+                    nomalImage: Assets.baseServiceRatingUnselected,
+                    selectImage: Assets.baseServiceRatingSelected,
+                    size: 21,
+                    padding: 5,
+                    selectAble: Utils.isEmpty(reviews.feedback),
+                    integerOnly: true,
+                    value: reviews.groomingRate,
+                    onRatingUpdate: (value) {
+                      groomingRate = value;
+                    },
+                  )
+                ],
+              ).marginOnly(top: 15, left: 22, right: 22),
+
+              IgnoreKeyboardDismiss(
+                child: Container(
+                  height: 130,
+                  margin: EdgeInsets.symmetric(vertical: 19, horizontal: 22),
+                  padding: EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+                  decoration: BoxDecoration(
+                    color: Color(0xFFF0F0F0),
+                    border: Border.all(
+                      color: Color(0xFFD8D8D8),
+                      width: 0.5,
+                    ),
+                  ),
+                  child: TextField(
+                    cursorColor: ColorConstants.black66,
+                    cursorWidth: 1.5,
+                    autofocus: false,
+                    enabled: Utils.isEmpty(reviews.feedback),
+                    focusNode: _focusNode,
+                    controller: _controller,
+                    // 装饰
+                    decoration: InputDecoration(
+                      isDense: true,
+                      isCollapsed: true,
+                      border: InputBorder.none,
+                      hintText: "Enter...".tr,
+                      hintStyle: TextStyle(
+                        color: ColorConstants.black66,
+                        fontSize: 15.0,
+                        fontWeight: FontWeight.w400,
+                      ),
+                    ),
+                    style: TextStyle(
+                      color: ColorConstants.black,
+                      fontSize: 15.0,
+                      fontWeight: FontWeight.w400,
+                    ),
+                    // 键盘动作右下角图标
+                    textInputAction: TextInputAction.done,
+                    onSubmitted: (value) {
+                      doCallbackAction();
+                    },
+                  ),
+                ),
+              ),
+
+              // 分割线
+              Container(
+                color: Color(0XFFCECECE),
+                height: 0.5,
+              ),
+
+              //按钮组
+              Row(
+                children: [
+                  Expanded(
+                      flex: 1,
+                      child: InkWell(
+                        onTap: () {
+                          onCancel();
+                        },
+                        child: MyTextView(
+                          "Cancel".tr,
+                          fontSize: 17.5,
+                          isFontMedium: true,
+                          textAlign: TextAlign.center,
+                          textColor: Color(0XFF0085C4),
+                          cornerRadius: 3,
+                          borderWidth: 1,
+                        ),
+                      )),
+                  Container(
+                    color: Color(0xff09141F).withOpacity(0.13),
+                    width: 0.5,
+                  ),
+                  Expanded(
+                      flex: 1,
+                      child: InkWell(
+                        onTap: () {
+                          doCallbackAction();
+                        },
+                        child: MyTextView(
+                          "Submit".tr,
+                          marginLeft: 10,
+                          fontSize: 17.5,
+                          isFontMedium: true,
+                          textAlign: TextAlign.center,
+                          textColor: Color(0XFF0085C4),
+                          cornerRadius: 3,
+                        ),
+                      )),
+                ],
+              ).constrained(height: 46),
+            ],
+          ),
+        ),
+      ],
+    ).constrained(width: 285);
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+
+  //执行回调
+  void doCallbackAction() {
+    _focusNode.unfocus();
+
+    content = _controller.text.toString();
+
+    if (attitudeRate == "0" || experienceRate == "0" || performanceRate == "0" || groomingRate == "0") {
+      ToastEngine.show("Rate First");
+      return;
+    }
+
+    if (Utils.isEmpty(content)) {
+      ToastEngine.show("Please Enter Remark".tr);
+      return;
+    }
+
+    onCancel();
+
+    widget.confirmAction?.call(attitudeRate, performanceRate, experienceRate, groomingRate, content);
+  }
+}

+ 350 - 0
packages/cpt_job_sg/lib/modules/job_applied/dialog_applied_butch_modify.dart

@@ -0,0 +1,350 @@
+import 'dart:typed_data';
+import 'dart:ui';
+
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_field.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/picker/option_pick_util.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/widget_export.dart';
+
+/**
+ * 批量操作修改时间的弹窗
+ */
+class DialogAppliedButchModify extends StatefulWidget {
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  void Function(DateTime? startTime, DateTime? endTime, String? subtractHour, String? statusId)? confirmAction;
+
+  DialogAppliedButchModify({this.selectedStartDate, this.selectedEndDate, this.confirmAction});
+
+  @override
+  State<DialogAppliedButchModify> createState() => _DialogAppliedButchModifyState();
+}
+
+class _DialogAppliedButchModifyState extends State<DialogAppliedButchModify> {
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? chooseStatusId;
+  String? chooseStatusTxt;
+  late TextEditingController hourController;
+  late FocusNode hourFocusNode;
+  List<String> statusIdList = ["1", "6"];
+  List<String> statusTxtList = ["Applied", "No Show"];
+
+  @override
+  void initState() {
+    super.initState();
+    selectedStartDate = widget.selectedStartDate;
+    selectedEndDate = widget.selectedEndDate;
+    hourController = TextEditingController();
+    hourFocusNode = FocusNode();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.center,
+      mainAxisAlignment: MainAxisAlignment.center,
+      children: [
+        //Title (如果使用 Container 为最外层容器则默认为 match_parent 的效果,除非我们限制宽度和最大高度最小高度)
+        Container(
+          padding: EdgeInsets.symmetric(horizontal: 16.5),
+          width: double.infinity,
+          decoration: BoxDecoration(
+            color: Colors.white,
+            borderRadius: const BorderRadius.all(Radius.circular(15)),
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              Center(
+                child: MyTextView(
+                  "Batch Modify".tr,
+                  fontSize: 19,
+                  isFontMedium: true,
+                  textColor: ColorConstants.black,
+                  marginTop: 22,
+                  marginBottom: 20,
+                ),
+              ),
+
+              MyTextView(
+                "Job Start Time".tr,
+                fontSize: 14,
+                textColor: ColorConstants.black33,
+                isFontRegular: true,
+              ),
+
+              //选择时间
+              Container(
+                padding: EdgeInsets.only(left: 16, right: 10),
+                margin: EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      selectedStartDate == null ? "" : DateTimeUtils.formatDate(selectedStartDate),
+                      fontSize: 14,
+                      hint: "Choose Start Date".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerStartDate();
+              }),
+
+              //结束日期
+              MyTextView(
+                "Job End Time".tr,
+                fontSize: 14,
+                marginTop: 11,
+                textColor: ColorConstants.black33,
+                isFontRegular: true,
+              ),
+
+              //选择结束日期
+              Container(
+                padding: EdgeInsets.only(left: 16, right: 10),
+                margin: EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      selectedEndDate == null ? "" : DateTimeUtils.formatDate(selectedEndDate),
+                      fontSize: 14,
+                      hint: "Choose End Date".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerEndDate();
+              }),
+
+              // + / - 小时
+              MyTextView(
+                "Subtract Hours".tr,
+                fontSize: 14,
+                marginTop: 11,
+                textColor: ColorConstants.black33,
+                isFontRegular: true,
+              ),
+
+              // 加减小时的输入框
+              IgnoreKeyboardDismiss(
+                child: MyTextField(
+                  "hour",
+                  "",
+                  hintText: "Enter...".tr,
+                  hintStyle: TextStyle(
+                    color: ColorConstants.gray88,
+                    fontSize: 14,
+                    fontWeight: FontWeight.w400,
+                  ),
+                  controller: hourController,
+                  focusNode: hourFocusNode,
+                  margin: EdgeInsets.only(left: 0, right: 0, top: 8),
+                  showDivider: false,
+                  fillBackgroundColor: ColorConstants.grayECECEC,
+                  fillCornerRadius: 5,
+                  padding: EdgeInsets.only(left: 16, right: 16, top: 0, bottom: 0),
+                  height: 40,
+                  style: TextStyle(
+                    color: ColorConstants.black33,
+                    fontSize: 14,
+                    fontWeight: FontWeight.w400,
+                  ),
+                  inputType: TextInputType.numberWithOptions(signed: false, decimal: true),
+                  textInputAction: TextInputAction.next,
+                  enabled: true,
+                  onSubmit: (key, value) {},
+                  cursorColor: ColorConstants.black33,
+                  showLeftIcon: false,
+                  showRightIcon: false,
+                ),
+              ),
+
+              // 修改状态
+              MyTextView(
+                "Status".tr,
+                fontSize: 14,
+                marginTop: 11,
+                textColor: ColorConstants.black33,
+                isFontRegular: true,
+              ),
+
+              Container(
+                padding: EdgeInsets.only(left: 16, right: 10),
+                margin: EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      chooseStatusTxt ?? "",
+                      fontSize: 14,
+                      hint: "Choose Status".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerStatus();
+              }),
+
+              //分割线
+              Container(
+                margin: EdgeInsets.only(top: 25),
+                color: Color(0XFFCECECE),
+                height: 0.5,
+              ),
+              Row(
+                children: [
+                  Expanded(
+                      flex: 1,
+                      child: InkWell(
+                        onTap: () {
+                          onCancel();
+                        },
+                        child: MyTextView(
+                          "Cancel".tr,
+                          fontSize: 17.5,
+                          isFontMedium: true,
+                          textAlign: TextAlign.center,
+                          textColor: Color(0XFF0085C4),
+                          cornerRadius: 3,
+                          borderWidth: 1,
+                        ),
+                      )),
+                  Container(
+                    color: Color(0xff09141F).withOpacity(0.13),
+                    width: 0.5,
+                  ),
+                  Expanded(
+                      flex: 1,
+                      child: InkWell(
+                        onTap: () async {
+                          String hour = hourController.text;
+                          widget.confirmAction?.call(selectedStartDate, selectedEndDate, hour, chooseStatusId);
+                          onCancel();
+                        },
+                        child: MyTextView(
+                          "Submit".tr,
+                          marginLeft: 10,
+                          fontSize: 17.5,
+                          isFontMedium: true,
+                          textAlign: TextAlign.center,
+                          textColor: Color(0XFF0085C4),
+                          cornerRadius: 3,
+                        ),
+                      )),
+                ],
+              ).constrained(height: 46),
+            ],
+          ),
+        ),
+      ],
+    ).constrained(width: 285);
+  }
+
+  /// 筛选开始日期
+  void pickerStartDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: selectedStartDate,
+      mode: CupertinoDatePickerMode.time,
+      onDateTimeChanged: (date) {
+        setState(() {
+          selectedStartDate = date;
+        });
+      },
+      title: "Start Date".tr,
+    );
+  }
+
+  /// 筛选结束日期
+  void pickerEndDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: selectedEndDate ?? selectedStartDate,
+      mode: CupertinoDatePickerMode.time,
+      onDateTimeChanged: (date) {
+        setState(() {
+          selectedEndDate = date;
+        });
+      },
+      title: "End Date".tr,
+    );
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+
+  /// 筛选状态
+  void pickerStatus() {
+    int selectedIndex;
+    if (chooseStatusId == null) {
+      selectedIndex = 0;
+    } else {
+      selectedIndex = statusIdList.indexWhere((e) => e == chooseStatusId);
+    }
+
+    if (selectedIndex < 0) {
+      selectedIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: statusTxtList,
+      initialSelectIndex: selectedIndex,
+      onPickerChanged: (_, index) {
+        chooseStatusId = statusIdList[index];
+
+        setState(() {
+          chooseStatusTxt = statusTxtList[index];
+        });
+      },
+    );
+  }
+}

+ 530 - 0
packages/cpt_job_sg/lib/modules/job_applied/dialog_applied_modify.dart

@@ -0,0 +1,530 @@
+import 'dart:typed_data';
+import 'dart:ui';
+
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_applied_edit_index_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_field.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/shatter/custom_radio_check.dart';
+import 'package:widgets/widget_export.dart';
+
+/**
+ * 修改员工的信息的弹窗
+ */
+class DialogAppliedModify extends StatefulWidget {
+  JobAppliedEditIndexSGEntity? editIndexOption;
+
+  void Function(JobAppliedEditIndexSGEntity? entity)? confirmAction;
+
+  DialogAppliedModify({this.editIndexOption, this.confirmAction});
+
+  @override
+  State<DialogAppliedModify> createState() => _DialogAppliedModifyState();
+}
+
+class _DialogAppliedModifyState extends State<DialogAppliedModify> {
+  JobAppliedEditIndexSGEntity? editIndexOption;
+  late TextEditingController hourController;
+  late FocusNode hourFocusNode;
+
+  @override
+  void initState() {
+    super.initState();
+    editIndexOption = widget.editIndexOption;
+    hourController = TextEditingController();
+    if (Utils.isNotEmpty(editIndexOption?.adjustHours) && editIndexOption?.adjustHours != "0.00") {
+      hourController.text = editIndexOption!.adjustHours!;
+    }
+    hourFocusNode = FocusNode();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: EdgeInsets.symmetric(horizontal: 16.5),
+      width: 285,
+      height: 510,
+      decoration: BoxDecoration(
+        color: Colors.white,
+        borderRadius: const BorderRadius.all(Radius.circular(15)),
+      ),
+      child: Column(
+        crossAxisAlignment: CrossAxisAlignment.start,
+        mainAxisSize: MainAxisSize.max,
+        children: [
+          Center(
+            // 标题
+            child: MyTextView(
+              "Modify".tr,
+              fontSize: 19,
+              isFontMedium: true,
+              textColor: ColorConstants.black,
+              marginTop: 22,
+              marginBottom: 20,
+            ),
+          ),
+
+          SingleChildScrollView(
+            scrollDirection: Axis.vertical,
+            physics: const BouncingScrollPhysics(),
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                MyTextView(
+                  "Job Start Time".tr,
+                  fontSize: 14,
+                  textColor: ColorConstants.black33,
+                  isFontRegular: true,
+                ),
+
+                //选择时间
+                Container(
+                  padding: EdgeInsets.only(left: 16, right: 10),
+                  margin: EdgeInsets.only(top: 10),
+                  height: 45,
+                  decoration: BoxDecoration(
+                    color: ColorConstants.grayECECEC,
+                    borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  ),
+                  child: Row(
+                    mainAxisSize: MainAxisSize.max,
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                    mainAxisAlignment: MainAxisAlignment.start,
+                    children: [
+                      MyTextView(
+                        editIndexOption == null ? "" : editIndexOption?.startTime ?? "",
+                        fontSize: 14,
+                        hint: "Choose Start Date".tr,
+                        textHintColor: ColorConstants.textBlackHint,
+                        isFontMedium: true,
+                        textColor: ColorConstants.black33,
+                      ).expanded(),
+                      MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    ],
+                  ),
+                ).onTap(() {
+                  pickerStartDate();
+                }),
+
+                // 门卫签到
+                MyTextView(
+                  "Security Clock In".tr,
+                  fontSize: 14,
+                  marginTop: 11,
+                  textColor: ColorConstants.black33,
+                  isFontRegular: true,
+                ),
+
+                //选择结束日期
+                Container(
+                  padding: EdgeInsets.only(left: 16, right: 10),
+                  margin: EdgeInsets.only(top: 10),
+                  height: 45,
+                  decoration: BoxDecoration(
+                    color: ColorConstants.grayECECEC,
+                    borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  ),
+                  child: Row(
+                    mainAxisSize: MainAxisSize.max,
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                    mainAxisAlignment: MainAxisAlignment.start,
+                    children: [
+                      MyTextView(
+                        editIndexOption == null ? "" : editIndexOption?.securityIn ?? "",
+                        fontSize: 14,
+                        hint: "Choose Date".tr,
+                        textHintColor: ColorConstants.textBlackHint,
+                        isFontMedium: true,
+                        textColor: ColorConstants.black33,
+                      ).expanded(),
+                      MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    ],
+                  ),
+                ).onTap(() {
+                  pickerSecurityIn();
+                }),
+
+                // 工作地签到
+                MyTextView(
+                  "Work Clock In".tr,
+                  fontSize: 14,
+                  marginTop: 11,
+                  textColor: ColorConstants.black33,
+                  isFontRegular: true,
+                ),
+
+                //选择结束日期
+                Container(
+                  padding: EdgeInsets.only(left: 16, right: 10),
+                  margin: EdgeInsets.only(top: 10),
+                  height: 45,
+                  decoration: BoxDecoration(
+                    color: ColorConstants.grayECECEC,
+                    borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  ),
+                  child: Row(
+                    mainAxisSize: MainAxisSize.max,
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                    mainAxisAlignment: MainAxisAlignment.start,
+                    children: [
+                      MyTextView(
+                        editIndexOption == null ? "" : editIndexOption?.workIn ?? "",
+                        fontSize: 14,
+                        hint: "Choose Date".tr,
+                        textHintColor: ColorConstants.textBlackHint,
+                        isFontMedium: true,
+                        textColor: ColorConstants.black33,
+                      ).expanded(),
+                      MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    ],
+                  ),
+                ).onTap(() {
+                  pickerWorkIn();
+                }),
+
+                MyTextView(
+                  "Job End Time".tr,
+                  fontSize: 14,
+                  marginTop: 11,
+                  textColor: ColorConstants.black33,
+                  isFontRegular: true,
+                ),
+
+                //选择结束日期
+                Container(
+                  padding: EdgeInsets.only(left: 16, right: 10),
+                  margin: EdgeInsets.only(top: 10),
+                  height: 45,
+                  decoration: BoxDecoration(
+                    color: ColorConstants.grayECECEC,
+                    borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  ),
+                  child: Row(
+                    mainAxisSize: MainAxisSize.max,
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                    mainAxisAlignment: MainAxisAlignment.start,
+                    children: [
+                      MyTextView(
+                        editIndexOption == null ? "" : editIndexOption?.endTime ?? "",
+                        fontSize: 14,
+                        hint: "Choose End Date".tr,
+                        textHintColor: ColorConstants.textBlackHint,
+                        isFontMedium: true,
+                        textColor: ColorConstants.black33,
+                      ).expanded(),
+                      MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    ],
+                  ),
+                ).onTap(() {
+                  pickerEndDate();
+                }),
+
+                // 工作地签出
+                MyTextView(
+                  "Work Clock Out".tr,
+                  fontSize: 14,
+                  marginTop: 11,
+                  textColor: ColorConstants.black33,
+                  isFontRegular: true,
+                ),
+
+                //选择结束日期
+                Container(
+                  padding: EdgeInsets.only(left: 16, right: 10),
+                  margin: EdgeInsets.only(top: 10),
+                  height: 45,
+                  decoration: BoxDecoration(
+                    color: ColorConstants.grayECECEC,
+                    borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  ),
+                  child: Row(
+                    mainAxisSize: MainAxisSize.max,
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                    mainAxisAlignment: MainAxisAlignment.start,
+                    children: [
+                      MyTextView(
+                        editIndexOption == null ? "" : editIndexOption?.workOut ?? "",
+                        fontSize: 14,
+                        hint: "Choose Date".tr,
+                        textHintColor: ColorConstants.textBlackHint,
+                        isFontMedium: true,
+                        textColor: ColorConstants.black33,
+                      ).expanded(),
+                      MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    ],
+                  ),
+                ).onTap(() {
+                  pickerWorkOut();
+                }),
+
+                // 门卫签出
+                MyTextView(
+                  "Security Clock Out".tr,
+                  fontSize: 14,
+                  marginTop: 11,
+                  textColor: ColorConstants.black33,
+                  isFontRegular: true,
+                ),
+
+                //选择结束日期
+                Container(
+                  padding: EdgeInsets.only(left: 16, right: 10),
+                  margin: EdgeInsets.only(top: 10),
+                  height: 45,
+                  decoration: BoxDecoration(
+                    color: ColorConstants.grayECECEC,
+                    borderRadius: const BorderRadius.all(Radius.circular(5)),
+                  ),
+                  child: Row(
+                    mainAxisSize: MainAxisSize.max,
+                    crossAxisAlignment: CrossAxisAlignment.center,
+                    mainAxisAlignment: MainAxisAlignment.start,
+                    children: [
+                      MyTextView(
+                        editIndexOption == null ? "" : editIndexOption?.securityOut ?? "",
+                        fontSize: 14,
+                        hint: "Choose Date".tr,
+                        textHintColor: ColorConstants.textBlackHint,
+                        isFontMedium: true,
+                        textColor: ColorConstants.black33,
+                      ).expanded(),
+                      MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    ],
+                  ),
+                ).onTap(() {
+                  pickerSecurityOut();
+                }),
+
+                // + / - 小时
+                MyTextView(
+                  "+/- Hours".tr,
+                  fontSize: 14,
+                  marginTop: 11,
+                  textColor: ColorConstants.black33,
+                  isFontRegular: true,
+                ),
+
+                // 加减小时的输入框
+                IgnoreKeyboardDismiss(
+                  child: MyTextField(
+                    "hour",
+                    Utils.isNotEmpty(editIndexOption?.adjustHours) && editIndexOption?.adjustHours != "0.00" ? editIndexOption!.adjustHours! : "",
+                    hintText: "Enter...".tr,
+                    hintStyle: TextStyle(
+                      color: ColorConstants.gray88,
+                      fontSize: 14,
+                      fontWeight: FontWeight.w400,
+                    ),
+                    controller: hourController,
+                    focusNode: hourFocusNode,
+                    margin: EdgeInsets.only(left: 0, right: 0, top: 8),
+                    showDivider: false,
+                    fillBackgroundColor: ColorConstants.grayECECEC,
+                    fillCornerRadius: 5,
+                    padding: EdgeInsets.only(left: 16, right: 16, top: 0, bottom: 0),
+                    height: 40,
+                    style: TextStyle(
+                      color: ColorConstants.black33,
+                      fontSize: 14,
+                      fontWeight: FontWeight.w400,
+                    ),
+                    inputType: TextInputType.numberWithOptions(signed: true,decimal: true),
+                    textInputAction: TextInputAction.next,
+                    enabled: true,
+                    onSubmit: (key, value) {},
+                    cursorColor: ColorConstants.black33,
+                    showLeftIcon: false,
+                    showRightIcon: false,
+                  ),
+                ),
+
+                //状态的选择
+                MyTextView(
+                  "Status".tr,
+                  fontSize: 14,
+                  marginTop: 11,
+                  textColor: ColorConstants.black33,
+                  isFontRegular: true,
+                ),
+
+                //状态单选
+                CustomRadioCheck(
+                  options: editIndexOption?.statusList?.map((e) => e.txt!).toList() ?? [],
+                  onOptionSelected: (index, text) {
+                    editIndexOption?.status = editIndexOption?.statusList?[index].value ?? 0;
+                  },
+                  textColor: ColorConstants.black33,
+                  selectedPosition: editIndexOption?.statusList?.indexWhere((e) => e.checked == "checked") ?? -1,
+                ).marginOnly(left: 15, right: 15, top: 10),
+              ],
+            ),
+          ).expanded(),
+
+          //分割线
+          Container(
+            margin: EdgeInsets.only(top: 25),
+            color: Color(0XFFCECECE),
+            height: 0.5,
+          ),
+          Row(
+            children: [
+              Expanded(
+                  flex: 1,
+                  child: InkWell(
+                    onTap: () {
+                      onCancel();
+                    },
+                    child: MyTextView(
+                      "Cancel".tr,
+                      fontSize: 17.5,
+                      isFontMedium: true,
+                      textAlign: TextAlign.center,
+                      textColor: Color(0XFF0085C4),
+                      cornerRadius: 3,
+                      borderWidth: 1,
+                    ),
+                  )),
+              Container(
+                color: Color(0xff09141F).withOpacity(0.13),
+                width: 0.5,
+              ),
+              Expanded(
+                  flex: 1,
+                  child: InkWell(
+                    onTap: () async {
+                      //输入框需要手动赋值
+                      String hour = hourController.text;
+                      editIndexOption?.adjustHours = hour;
+
+                      widget.confirmAction?.call(editIndexOption);
+                      onCancel();
+                    },
+                    child: MyTextView(
+                      "Submit".tr,
+                      marginLeft: 10,
+                      fontSize: 17.5,
+                      isFontMedium: true,
+                      textAlign: TextAlign.center,
+                      textColor: Color(0XFF0085C4),
+                      cornerRadius: 3,
+                    ),
+                  )),
+            ],
+          ).constrained(height: 46),
+        ],
+      ),
+    );
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+
+  /// 筛选开始日期
+  void pickerStartDate() {
+    if (editIndexOption == null) return;
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: DateTimeUtils.getDateTime(editIndexOption!.startTime ?? ""),
+      mode: CupertinoDatePickerMode.time,
+      onDateTimeChanged: (date) {
+        setState(() {
+          editIndexOption?.startTime = DateTimeUtils.formatDate(date);
+        });
+      },
+      title: "Start Date".tr,
+    );
+  }
+
+  /// 筛选结束日期
+  void pickerEndDate() {
+    if (editIndexOption == null) return;
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: DateTimeUtils.getDateTime(editIndexOption!.endTime ?? ""),
+      mode: CupertinoDatePickerMode.time,
+      onDateTimeChanged: (date) {
+        setState(() {
+          editIndexOption?.endTime = DateTimeUtils.formatDate(date);
+        });
+      },
+      title: "End Date".tr,
+    );
+  }
+
+  /// 选择门卫签到
+  void pickerSecurityIn() {
+    if (editIndexOption == null) return;
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: DateTimeUtils.getDateTime(editIndexOption!.securityIn ?? ""),
+      mode: CupertinoDatePickerMode.dateAndTime,
+      onDateTimeChanged: (date) {
+        setState(() {
+          editIndexOption?.securityIn = DateTimeUtils.formatDate(date);
+        });
+      },
+      title: "Security Clock In".tr,
+    );
+  }
+
+  /// 选择工作地签到
+  void pickerWorkIn() {
+    if (editIndexOption == null) return;
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: DateTimeUtils.getDateTime(editIndexOption!.workIn ?? ""),
+      mode: CupertinoDatePickerMode.dateAndTime,
+      onDateTimeChanged: (date) {
+        setState(() {
+          editIndexOption?.workIn = DateTimeUtils.formatDate(date);
+        });
+      },
+      title: "Work Clock In".tr,
+    );
+  }
+
+  /// 选择工作地签出
+  void pickerWorkOut() {
+    if (editIndexOption == null) return;
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: DateTimeUtils.getDateTime(editIndexOption!.workOut ?? ""),
+      mode: CupertinoDatePickerMode.dateAndTime,
+      onDateTimeChanged: (date) {
+        setState(() {
+          editIndexOption?.workOut = DateTimeUtils.formatDate(date);
+        });
+      },
+      title: "Work Clock Out".tr,
+    );
+  }
+
+  /// 选择门卫签出
+  void pickerSecurityOut() {
+    if (editIndexOption == null) return;
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: DateTimeUtils.getDateTime(editIndexOption!.securityOut ?? ""),
+      mode: CupertinoDatePickerMode.dateAndTime,
+      onDateTimeChanged: (date) {
+        setState(() {
+          editIndexOption?.securityOut = DateTimeUtils.formatDate(date);
+        });
+      },
+      title: "Security Clock Out".tr,
+    );
+  }
+}

+ 57 - 0
packages/cpt_job_sg/lib/modules/job_applied/drop_down_status.dart

@@ -0,0 +1,57 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_applied_list_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/shatter/border_select_widget.dart';
+
+/**
+ * 已申请的员工列表Item
+ */
+class DropDownStatus extends StatelessWidget {
+  final List<JobAppliedListSGRowsStatusList> list;
+  final void Function(JobAppliedListSGRowsStatusList bean)? onSelectedAction;
+
+  DropDownStatus({
+    required this.list,
+    this.onSelectedAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: EdgeInsets.symmetric(vertical: 5, horizontal: 12),
+      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: Color(0xFF56AAFF), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: list
+            .map((e) => MyTextView(
+                  e.txt ?? "",
+                  fontSize: 14,
+                  marginTop: 5,
+                  marginBottom: 5,
+                  textColor: Colors.white,
+                  onClick: () {
+                    onSelectedAction?.call(e);
+                    DialogEngine.dismiss();
+                  },
+                  isFontRegular: true,
+                ))
+            .toList(),
+      ),
+    );
+  }
+}

+ 496 - 0
packages/cpt_job_sg/lib/modules/job_applied/job_applied_controller.dart

@@ -0,0 +1,496 @@
+import 'package:cpt_job_sg/modules/applied_staff/applied_staff_page.dart';
+import 'package:cpt_job_sg/modules/revise_applied/revise_applied_page.dart';
+import 'package:domain/entity/response/job_applied_edit_index_s_g_entity.dart';
+import 'package:domain/entity/response/job_applied_list_s_g_entity.dart';
+import 'package:domain/repository/job_sg_repository.dart';
+import 'package:domain/repository/labour_sg_repository.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/src/widgets/framework.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/constants/app_constant.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/event_bus.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/picker/option_pick_util.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../applied_staff_detail/applied_staff_detail_page.dart';
+import 'applied_staff_reviews.dart';
+import 'dialog_applied_butch_modify.dart';
+import 'dialog_applied_modify.dart';
+import 'drop_down_status.dart';
+import 'job_applied_state.dart';
+
+class JobAppliedController extends GetxController with DioCancelableMixin {
+  final JobSGRepository _jobRepository = Get.find();
+  final LabourSGRepository _labourRepository = Get.find();
+  final JobAppliedState state = JobAppliedState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchAppliedStaffList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchAppliedStaffList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchAppliedStaffList();
+  }
+
+  /// 获取服务器数据,通知消息列表
+  Future fetchAppliedStaffList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    if (state.appliedIndexEntity == null) {
+      //不是并发的,顺序执行接口
+      var jobInfoResult = await _jobRepository.fetchJobAppliedIndex(
+        state.jobId,
+        cancelToken: cancelToken,
+      );
+
+      if (jobInfoResult.isSuccess) {
+        state.appliedIndexEntity = jobInfoResult.data;
+        update();
+      } else {
+        errorMessage = jobInfoResult.errorMsg;
+        changeLoadingState(LoadState.State_Error);
+        return;
+      }
+    }
+
+    // 获取 Applied 列表
+    var listResult = await _jobRepository.fetchJobAppliedList(
+      state.jobId,
+      state.selectedStatusId,
+      state.keyword,
+      curPage: _curPage,
+      cancelToken: cancelToken,
+    );
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<JobAppliedListSGRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchAppliedStaffList();
+    registerEventBus();
+  }
+
+  @override
+  void onClose() {
+    unregisterEventBus();
+    state.cb?.call(state.jobId);
+    state.datas.clear();
+    super.onClose();
+  }
+
+  // EventBus 的事件接收
+  Subscription? subscribe;
+
+  void registerEventBus() {
+    subscribe = bus.on(AppConstant.eventAppliedListRefresh, (arg) {
+      var appliedId = arg as String;
+      if (Utils.isNotEmpty(appliedId)) {
+        fetchItemByIdAndRefreshItem(appliedId);
+      } else {
+        refreshController.callRefresh();
+      }
+    });
+  }
+
+  void unregisterEventBus() {
+    bus.off(AppConstant.eventAppliedListRefresh, subscribe);
+  }
+
+  /// 搜索员工
+  void doSearch(String keyword) {
+    state.keyword = keyword;
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  /// 清空筛选条件
+  void resetFiltering() {
+    state.keyword = "";
+    state.searchController.text = "";
+    state.selectedStatusTxt = "";
+    state.selectedStatusId = null;
+    update();
+
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  /// 展示添加员工的弹窗
+  void gotoAddStaffPage() {
+    AppliedStaffPage.startInstance(state.jobId);
+  }
+
+  /// 展示编辑员工信息的弹窗
+  void showAppliedEditDialog(JobAppliedListSGRows data) async {
+    var result = await _jobRepository.fetchEditJobAppliedIndex(data.appliedId.toString());
+
+    if (result.isSuccess) {
+      //接口数据获取成功,展示弹窗
+      DialogEngine.show(
+        widget: DialogAppliedModify(
+          editIndexOption: result.data!,
+          confirmAction: (entity) {
+            if (entity != null) {
+              _requestSubmitEditApplied(entity);
+            }
+          },
+        ),
+      );
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      return;
+    }
+  }
+
+  // 提交编辑的接口
+  void _requestSubmitEditApplied(JobAppliedEditIndexSGEntity entity) async {
+    Log.d("选中的数据为:${entity.toString()}");
+
+    var result = await _jobRepository.submitEditJobApplied(
+      entity.appliedId,
+      DateTimeUtils.formatDateStr(entity.startTime ?? "", format: "HH:mm:ss"),
+      DateTimeUtils.formatDateStr(entity.endTime ?? "", format: "HH:mm:ss"),
+      entity.securityIn,
+      entity.securityOut,
+      entity.workIn,
+      entity.workOut,
+      entity.adjustHours,
+      entity.status == 0 ? "" : entity.status.toString(),
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //调用接口刷新指定的Staff的信息
+      fetchItemByIdAndRefreshItem(entity.appliedId);
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      return;
+    }
+  }
+
+  /// 展示评论的弹窗
+  void showRemarkDialog(JobAppliedListSGRows data) async {
+    //请求接口获取到已评论的数据
+    var result = await _jobRepository.fetchJobAppliedRemarkView(data.appliedId.toString());
+
+    if (result.isSuccess) {
+      //接口数据获取成功,展示弹窗
+      DialogEngine.show(
+        widget: AppliedStaffReviews(
+          appliedReviews: result.data!,
+          confirmAction: (attitudeRate, performanceRate, experienceRate, groomingRate, content) async {
+            //请求接口,提交评论
+            var submitResult = await _jobRepository.submitAppliedRemark(
+              data.appliedId.toString(),
+              attitudeRate,
+              groomingRate,
+              performanceRate,
+              experienceRate,
+              content,
+            );
+
+            if (submitResult.isSuccess) {
+              NotifyEngine.showSuccess("Successful".tr);
+            } else {
+              ToastEngine.show(submitResult.errorMsg ?? "Network Load Error".tr);
+            }
+          },
+        ),
+      );
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      return;
+    }
+  }
+
+  /// 去 Revise Applied 的页面
+  void gotoReviseAppliedPage(JobAppliedListSGRows item) {
+    ReviseAppliedPage.startInstance(item.appliedId, state.appliedIndexEntity?.jobTitle, state.appliedIndexEntity?.jobDate);
+  }
+
+  /// 去查看员工详情页面
+  void gotoStaffDetailPage(JobAppliedListSGRows data) {
+    AppliedStaffDetailPage.startInstance(data.memberId);
+  }
+
+  /// Item选中与未选中设置
+  void doSelectedOrNot(JobAppliedListSGRows data) {
+    data.isSelected = !data.isSelected;
+    update();
+  }
+
+  /// 批量修改的弹窗
+  void showBatchModifyDialog() async {
+    if (state.appliedIndexEntity == null) return;
+    //找出已经选中的员工
+    var selectedList = state.datas.where((element) => element.isSelected).toList(growable: false);
+    if (selectedList.isNotEmpty) {
+      var ids = selectedList.map((e) => e.appliedId.toString()).toList(growable: false);
+      var separatedIds = ids.join(',');
+
+      DialogEngine.show(
+          widget: DialogAppliedButchModify(
+              selectedStartDate: null,
+              selectedEndDate: null,
+              confirmAction: (start, end, hour, status) {
+                _requestBatchModify(start, end, hour, status, separatedIds);
+              }));
+    } else {
+      ToastEngine.show("Please select the applied record".tr);
+    }
+  }
+
+  /// 执行批量修改的请求
+  void _requestBatchModify(DateTime? start, DateTime? end, String? hour, String? status, String separatedIds) async {
+    //执行请求
+    var result = await _jobRepository.batchEditJobApplied(
+      separatedIds,
+      start == null ? "" : DateTimeUtils.formatDate(start, format: "HH:mm:ss"),
+      end == null ? "" : DateTimeUtils.formatDate(end, format: "HH:mm:ss"),
+      hour,
+      status,
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //调用接口刷新指定的Staff的信息
+      fetchItemByIdAndRefreshItem(separatedIds);
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      return;
+    }
+  }
+
+  /// 根据ID获取Item对象,用于刷新
+  void fetchItemByIdAndRefreshItem(String? appliedIds) async {
+    var result = await _jobRepository.fetchItemByAppliedIds(
+      state.jobId,
+      appliedIds,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      var data = result.data;
+      if (data != null && data.rows.isNotEmpty) {
+        List<JobAppliedListSGRows> newItem = data.rows;
+
+        // 创建一个 Map 来加速查找
+        Map<String, JobAppliedListSGRows> newItemMap = {for (var item in newItem) item.appliedId ?? "": item};
+
+        // 遍历 state.datas 进行替换
+        for (int i = 0; i < state.datas.length; i++) {
+          if (newItemMap.containsKey(state.datas[i].appliedId)) {
+            state.datas[i] = newItemMap[state.datas[i].appliedId]!;
+          }
+        }
+
+        //刷新
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  /// 请求接口发送电子考勤,确定考勤
+  void confirmJob() {
+    //如果当前没有员工则无需发送考勤
+    if (state.datas.isEmpty) {
+      ToastEngine.show('There are no staff for this job, E-Attendance cannot be sent');
+      return;
+    }
+
+    DialogEngine.show(
+      widget: AppDefaultDialog(
+          title: "Notice".tr,
+          message: "Are you sure you want to send the e-attendance to agency?".tr,
+          confirmAction: () {
+            _requestSendEAttendance();
+          }),
+    );
+  }
+
+  //发送接口
+  void _requestSendEAttendance() async {
+    var result = await _labourRepository.confirmJobList(
+      state.jobId,
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //调用接口刷新指定的Staff的信息
+      refreshController.callRefresh();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      return;
+    }
+  }
+
+  // 顶部的筛选状态
+  void pickStatus() {
+    if (state.appliedIndexEntity == null) {
+      return;
+    }
+
+    int selectedTemplateIndex;
+    if (state.selectedStatusId == null) {
+      selectedTemplateIndex = 0;
+    } else {
+      selectedTemplateIndex = state.appliedIndexEntity!.statusList.indexWhere((department) => department.value.toString() == state.selectedStatusId);
+    }
+
+    if (selectedTemplateIndex < 0) {
+      selectedTemplateIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: state.appliedIndexEntity!.statusList.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedTemplateIndex,
+      onPickerChanged: (_, index) {
+        state.selectedStatusId = state.appliedIndexEntity!.statusList[index].value!.toString();
+        state.selectedStatusTxt = state.appliedIndexEntity!.statusList[index].txt!.toString();
+        update();
+
+        refreshController.callRefresh();
+      },
+    );
+  }
+
+  // 下拉选选择修改状态
+  void dropDownStatus(int index, BuildContext context) {
+    final statusOptions = state.datas[index].statusList;
+    if (statusOptions.isEmpty) return;
+
+    DialogEngine.showAttach(
+      targetContext: context,
+      position: DialogPosition.bottom,
+      widget: DropDownStatus(
+        list: statusOptions,
+        onSelectedAction: (item) {
+          _changeMemberStatus(state.datas[index].appliedId, item.value, index);
+        },
+      ),
+    );
+  }
+
+  // 请求接口修改用户的状态
+  void _changeMemberStatus(String? appliedId, String? statusId, int index) async {
+    //执行请求
+    var result = await _jobRepository.submitEditAppliedStatus(
+      appliedId,
+      statusId,
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      if ("4" == statusId) {
+        //如果是拒绝了,移除这个Item
+        if (state.datas.length > 1) {
+          state.datas.removeAt(index);
+          update();
+        } else {
+          refreshController.callRefresh();
+        }
+      } else {
+        //其他状态刷新当前Item,调用接口刷新指定的Staff的信息
+        fetchItemByIdAndRefreshItem(appliedId);
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      return;
+    }
+  }
+}

+ 250 - 0
packages/cpt_job_sg/lib/modules/job_applied/job_applied_page.dart

@@ -0,0 +1,250 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/search_app_bar.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'applied_staff_item.dart';
+import 'job_applied_controller.dart';
+
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/my_appbar.dart';
+import 'job_applied_state.dart';
+
+/*
+ * 已申请的页面 (新加坡)
+ */
+class JobAppliedPage extends BaseStatefulPage<JobAppliedController> {
+  JobAppliedPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(String? jobId, void Function(dynamic value)? cb) {
+    return Get.start(RouterPath.jobListAppliedSG, arguments: {'jobId': jobId, 'cb': cb});
+  }
+
+  @override
+  JobAppliedController createRawController() {
+    return JobAppliedController();
+  }
+
+  @override
+  State<JobAppliedPage> createState() => _JobAppliedState();
+}
+
+class _JobAppliedState extends BaseState<JobAppliedPage, JobAppliedController> {
+  late JobAppliedState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.jobId = Get.arguments['jobId'];
+    state.cb = Get.arguments['cb'] as void Function(dynamic)?;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return SafeArea(
+        bottom: true,
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+            ),
+          ),
+          child: Column(
+            children: [
+              MyAppBar.titleBar(
+                context,
+                state.appliedIndexEntity?.jobTitle ?? "Title".tr,
+                subTitle: "(${state.appliedIndexEntity?.jobDate ?? "-"})",
+                subTitleColor: ColorConstants.textGrayAECAE5,
+              ),
+
+              //搜索的条件
+              Row(
+                children: [
+                  Container(
+                    padding: const EdgeInsets.only(left: 11, right: 11),
+                    margin: const EdgeInsets.only(right: 10),
+                    height: 40,
+                    decoration: BoxDecoration(
+                      color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                      borderRadius: const BorderRadius.all(Radius.circular(20)),
+                    ),
+                    child: Row(
+                      mainAxisSize: MainAxisSize.max,
+                      crossAxisAlignment: CrossAxisAlignment.center,
+                      mainAxisAlignment: MainAxisAlignment.start,
+                      children: [
+                        MyTextView(
+                          state.selectedStatusTxt ?? "",
+                          fontSize: 14,
+                          hint: "Status".tr,
+                          textHintColor: ColorConstants.textGrayAECAE5,
+                          isFontMedium: true,
+                          textColor: ColorConstants.white,
+                        ).expanded(),
+
+                        //下拉选图标
+                        const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                      ],
+                    ),
+                  ).onTap(() {
+                    FocusScope.of(context).unfocus();
+                    controller.pickStatus();
+                  }).expanded(),
+                  SearchAppBar(
+                    value: state.keyword,
+                    searchBarHeight: 40,
+                    margin: const EdgeInsets.only(right: 10),
+                    onSearch: (keyword) {
+                      controller.doSearch(keyword);
+                    },
+                    hintText: "Search".tr,
+                    controller: state.searchController,
+                  ).expanded(),
+                  MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      controller.resetFiltering();
+                    },
+                    text: "Reset".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#2BA9F9", opacity: 0.5),
+                    radius: 20,
+                    minWidth: 60,
+                    minHeight: 40,
+                  ),
+                ],
+              ).marginOnly(top: 10, left: 15, right: 15, bottom: 5),
+
+              Row(
+                children: [
+                  MyButton(
+                    type: ClickType.throttle,
+                    milliseconds: 500,
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      controller.confirmJob();
+                    },
+                    padding: const EdgeInsets.symmetric(horizontal: 5.0),
+                    text: "Send E-Attendance".tr,
+                    textColor: ColorConstants.white,
+                    fontSize: 16,
+                    radius: 20,
+                    backgroundColor: hexToColor("#855EF5"),
+                    fontWeight: FontWeight.w500,
+                  ).expanded(),
+
+                  // 添加按钮
+                  Visibility(
+                    visible: state.appliedIndexEntity?.canAppend == true,
+                    child: MyButton(
+                      type: ClickType.throttle,
+                      milliseconds: 500,
+                      onPressed: () {
+                        FocusScope.of(context).unfocus();
+                        controller.gotoAddStaffPage();
+                      },
+                      text: "Add Staff".tr,
+                      padding: const EdgeInsets.symmetric(horizontal: 5.0),
+                      textColor: ColorConstants.white,
+                      fontSize: 16,
+                      radius: 20,
+                      backgroundColor: hexToColor("#FFBB1B"),
+                      fontWeight: FontWeight.w500,
+                    ).marginOnly(left: 10).expanded(),
+                  ),
+                ],
+              ).marginOnly(left: 15, right: 15, top: 5, bottom: 10),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                        return AppliedStaffItem(
+                          index: index,
+                          item: state.datas[index],
+                          onEditAction: () {
+                            controller.showAppliedEditDialog(state.datas[index]);
+                          },
+                          onRemarkAction: () {
+                            controller.showRemarkDialog(state.datas[index]);
+                          },
+                          onReviseAction: () {
+                            controller.gotoReviseAppliedPage(state.datas[index]);
+                          },
+                          onModifyAction: () {
+                            controller.showAppliedEditDialog(state.datas[index]);
+                          },
+                          onItemAction: () {
+                            controller.doSelectedOrNot(state.datas[index]);
+                          },
+                          onMemberAction: () {
+                            controller.gotoStaffDetailPage(state.datas[index]);
+                          },
+                          onStatusAction: (targetContext) {
+                            controller.dropDownStatus(index, targetContext);
+                          },
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).expanded(),
+
+              MyTextView(
+                "Batch Modify".tr,
+                fontSize: 17,
+                isFontMedium: true,
+                boxHeight: 48,
+                onClick: () {
+                  controller.showBatchModifyDialog();
+                },
+                alignment: Alignment.center,
+                textAlign: TextAlign.center,
+                textColor: Colors.white,
+                backgroundColor: Color(0XFFFFBB1B),
+              ),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 19 - 0
packages/cpt_job_sg/lib/modules/job_applied/job_applied_state.dart

@@ -0,0 +1,19 @@
+import 'package:domain/entity/response/job_applied_index_s_g_entity.dart';
+import 'package:domain/entity/response/job_applied_list_s_g_entity.dart';
+import 'package:flutter/material.dart';
+
+class JobAppliedState {
+  //筛选条件
+  final TextEditingController searchController = TextEditingController();
+  String keyword = "";
+
+  String? selectedStatusId;
+  String? selectedStatusTxt;
+
+  String? jobId;
+  void Function(dynamic value)? cb;
+
+  JobAppliedIndexSGEntity? appliedIndexEntity; //指定工作的简短信息
+
+  List<JobAppliedListSGRows> datas = []; //Applied的员工列表
+}

+ 103 - 0
packages/cpt_job_sg/lib/modules/revise_add_edit/revise_add_edit_controller.dart

@@ -0,0 +1,103 @@
+import 'package:domain/entity/response/add_edit_revise_view_s_g_entity.dart';
+import 'package:domain/repository/job_sg_repository.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/util.dart';
+
+import 'revise_add_edit_state.dart';
+
+class ReviseAddEditController extends GetxController with DioCancelableMixin {
+  final JobSGRepository _jobRepository = Get.find();
+  final ReviseAddEditState state = ReviseAddEditState();
+
+  /// 获取首页的数据
+  void fetchRequestDetail() async {
+    //获取到数据
+    Future<HttpResult<AddEditReviseViewSGEntity>> taskFuture;
+    if (state.pageType != 0 && Utils.isNotEmpty(state.id) && state.id != "0") {
+      taskFuture = _jobRepository.fetchReviseEditIndex(state.id, cancelToken: cancelToken);
+    } else {
+      taskFuture = _jobRepository.fetchReviseAddIndex(state.id);
+    }
+
+    var result = await taskFuture;
+
+    //处理数据
+    if (result.isSuccess) {
+      state.addEditEntity = result.data;
+
+      TextEditingController reviseHourController = state.formData['revise_hour']!['controller'];
+      TextEditingController reasonController = state.formData['reason']!['controller'];
+
+      reviseHourController.text = state.addEditEntity?.reviseHours ?? "";
+      reasonController.text = state.addEditEntity?.reviseMsg ?? "";
+
+      update();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchRequestDetail();
+  }
+
+  /// 提交
+  void doSubmit() async {
+    TextEditingController reviseHourController = state.formData['revise_hour']!['controller'];
+    TextEditingController reasonController = state.formData['reason']!['controller'];
+    String reviseHour = reviseHourController.text.toString();
+    String reason = reasonController.text.toString();
+
+    if (Utils.isEmpty(reviseHour)) {
+      ToastEngine.show("Enter Revise Hour".tr);
+      return;
+    } else if (Utils.isEmpty(reason)) {
+      ToastEngine.show("Enter Reason".tr);
+      return;
+    }
+
+    Future<HttpResult> taskFuture;
+    if (state.pageType != 0 && Utils.isNotEmpty(state.id) && state.id != "0") {
+      taskFuture = _jobRepository.submitReviseEdit(
+        state.id,
+        reviseHour,
+        reason,
+        cancelToken: cancelToken,
+      );
+    } else {
+      taskFuture = _jobRepository.submitReviseAdd(
+        state.id,
+        reviseHour,
+        reason,
+        cancelToken: cancelToken,
+      );
+    }
+
+    var result = await taskFuture;
+
+    //处理数据
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //根据类型刷新
+      if (state.pageType != 0 && Utils.isNotEmpty(state.id) && state.id != "0") {
+        //编辑就发送指定的 reviseId 刷新
+        state.cb?.call(state.id ?? "");
+      } else {
+        //新增的就发送空
+        state.cb?.call("");
+      }
+
+      Get.back();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+}

+ 70 - 0
packages/cpt_job_sg/lib/modules/revise_add_edit/revise_add_edit_item.dart

@@ -0,0 +1,70 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_applied_list_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/shatter/border_select_widget.dart';
+
+/**
+ * 每一个选项
+ */
+class ReviseAddEditItem extends StatelessWidget {
+  final String title;
+  final String content;
+
+  ReviseAddEditItem({
+    required this.title,
+    required this.content,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      mainAxisSize: MainAxisSize.min,
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+
+        //工作标题,选择模板
+        MyTextView(
+          title,
+          textColor:ColorConstants.white,
+          isFontRegular: true,
+          marginTop: 14,
+          fontSize: 15,
+        ),
+
+        //工作标题
+        Container(
+          padding: EdgeInsets.only(left: 16, right: 10),
+          margin: EdgeInsets.only(top: 10),
+          height: 45,
+          decoration: BoxDecoration(
+            color: Color(0xFF4DCFF6).withOpacity(0.5),
+            borderRadius: const BorderRadius.all(Radius.circular(5)),
+          ),
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            mainAxisAlignment: MainAxisAlignment.start,
+            children: [
+              MyTextView(
+                content,
+                fontSize: 15,
+                isFontRegular: true,
+                textColor: ColorConstants.white,
+              ).expanded(),
+
+            ],
+          ),
+        ),
+
+      ],
+    );
+  }
+}

+ 223 - 0
packages/cpt_job_sg/lib/modules/revise_add_edit/revise_add_edit_page.dart

@@ -0,0 +1,223 @@
+import 'package:cpt_job_sg/modules/revise_add_edit/revise_add_edit_item.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/widgets.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+
+import 'package:widgets/no_shadow_scroll_behavior.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/shatter/round_my_text_field.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'revise_add_edit_controller.dart';
+import 'revise_add_edit_state.dart';
+
+/**
+ * Revise数据的添加,编辑,详情的页面
+ */
+class ReviseAddEditPage extends BaseStatefulPage<ReviseAddEditController> {
+  ReviseAddEditPage({Key? key}) : super(key: key);
+
+  //启动当前页面,pageType 0 是新增  1是编辑  2是详情
+  static void startInstance(int pageType, String? id, void Function(dynamic value)? cb) {
+    return Get.start(RouterPath.reviseEditSG, arguments: {'pageType': pageType, 'id': id,'cb': cb});
+  }
+
+  @override
+  ReviseAddEditController createRawController() {
+    return ReviseAddEditController();
+  }
+
+  @override
+  State<ReviseAddEditPage> createState() => _LabourRequestAddState();
+}
+
+class _LabourRequestAddState extends BaseState<ReviseAddEditPage, ReviseAddEditController> {
+  late ReviseAddEditState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.pageType = Get.arguments['pageType'];
+    state.id = Get.arguments['id'];
+    state.cb = Get.arguments['cb'] as void Function(dynamic)?;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(
+            context,
+            state.pageType == 0
+                ? "Add Revise".tr
+                : state.pageType == 1
+                    ? "Edit Revise".tr
+                    : "Detail".tr),
+        body: SafeArea(
+          bottom: true,
+          top: false,
+          child: Container(
+            width: double.infinity,
+            height: double.infinity,
+            padding: EdgeInsets.only(top: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1),
+            decoration: const BoxDecoration(
+              gradient: LinearGradient(
+                colors: [
+                  Color(0xFF091D44),
+                  Color(0xFF245A8A),
+                  Color(0xFF7F7CEC),
+                ],
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+              ),
+            ),
+            child: Scrollbar(
+              child: ScrollConfiguration(
+                behavior: NoShadowScrollBehavior(),
+                child: SingleChildScrollView(
+                  scrollDirection: Axis.vertical,
+                  physics: const BouncingScrollPhysics(),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      ReviseAddEditItem(title: "Staff Name".tr, content: state.addEditEntity?.labourerName ?? ""),
+
+                      ReviseAddEditItem(title: "Job Date".tr, content: state.addEditEntity?.jobDate ?? ""),
+
+                      ReviseAddEditItem(title: "Job Start Time".tr, content: state.addEditEntity?.startTime ?? ""),
+
+                      ReviseAddEditItem(title: "Job End Time".tr, content: state.addEditEntity?.endTime ?? ""),
+
+                      ReviseAddEditItem(title: "Security Clock In".tr, content: state.addEditEntity?.securityIn ?? ""),
+
+                      ReviseAddEditItem(title: "Security Clock Out".tr, content: state.addEditEntity?.securityOut ?? ""),
+
+                      ReviseAddEditItem(title: "Work Clock In".tr, content: state.addEditEntity?.workIn ?? ""),
+
+                      ReviseAddEditItem(title: "Work Clock Out".tr, content: state.addEditEntity?.workOut ?? ""),
+
+                      ReviseAddEditItem(title: "+/- Hours".tr, content: state.addEditEntity?.adjustHours ?? ""),
+
+                      ReviseAddEditItem(title: "Total Hours".tr, content: state.addEditEntity?.totalHours ?? ""),
+
+                      //修改的小时
+                      FormRequireText(
+                        fontSize: 15,
+                        text: "Revise Hours".tr,
+                      ).marginOnly(top: 15),
+
+                      //输入框
+                      CustomTextField(
+                        formKey: "revise_hour",
+                        marginLeft: 0,
+                        marginRight: 0,
+                        paddingTop: 0,
+                        paddingBottom: 0,
+                        height: 45,
+                        fillBackgroundColor: Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+                        enabled: state.pageType != 2,
+                        textInputType: TextInputType.number,
+                        formData: state.formData,
+                        textInputAction: TextInputAction.next,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['reason']!['focusNode']);
+                        },
+                        marginTop: 10,
+                      ),
+
+                      //修改的原因
+                      FormRequireText(
+                        fontSize: 15,
+                        text: "Reason".tr,
+                      ).marginOnly(top: 15),
+
+                      //输入框
+                      IgnoreKeyboardDismiss(
+                        child: Container(
+                          height: 160,
+                          padding: EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+                          decoration: BoxDecoration(
+                            color: Color(0xFF4DCFF6).withOpacity(state.pageType == 2 ? 0.5 : 0.2),
+                            borderRadius: const BorderRadius.all(Radius.circular(5)),
+                          ),
+                          child: TextField(
+                            enabled: state.pageType != 2,
+                            cursorColor: ColorConstants.white,
+                            cursorWidth: 1.5,
+                            autofocus: false,
+                            controller: state.formData["reason"]!['controller'],
+                            focusNode: state.formData["reason"]!['focusNode'],
+                            obscureText: state.formData["reason"]!['obsecure'],
+                            // 装饰
+                            decoration: InputDecoration(
+                              isDense: true,
+                              isCollapsed: true,
+                              border: InputBorder.none,
+                              hintText: state.formData["reason"]!['hintText'],
+                              hintStyle: TextStyle(
+                                color: ColorConstants.textGrayAECAE5,
+                                fontSize: 15.0,
+                                fontWeight: FontWeight.w400,
+                              ),
+                            ),
+                            style: TextStyle(
+                              color: ColorConstants.white,
+                              fontSize: 15.0,
+                              fontWeight: FontWeight.w400,
+                            ),
+                            // 键盘动作右下角图标
+                            textInputAction: TextInputAction.done,
+                            onSubmitted: (value) {
+                              FocusScope.of(context).unfocus();
+                              controller.doSubmit();
+                            },
+                          ),
+                        ),
+                      ).marginOnly(top: 10),
+
+                      //提交按钮
+                      Visibility(
+                        visible: state.pageType != 2,
+                        child: MyButton(
+                          type: ClickType.throttle,
+                          milliseconds: 500,
+                          onPressed: () {
+                            FocusScope.of(context).unfocus();
+                            controller.doSubmit();
+                          },
+                          text: "Submit".tr,
+                          textColor: ColorConstants.white,
+                          fontSize: 16,
+                          radius: 22.5,
+                          backgroundColor: hexToColor("#FFBB1B"),
+                          fontWeight: FontWeight.w500,
+                        ).marginOnly(top: 20),
+                      ),
+
+                      SizedBox(height: 20),
+                    ],
+                  ).paddingOnly(left: 15, right: 15),
+                ),
+              ),
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 33 - 0
packages/cpt_job_sg/lib/modules/revise_add_edit/revise_add_edit_state.dart

@@ -0,0 +1,33 @@
+import 'package:domain/entity/response/add_edit_revise_view_s_g_entity.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+
+class ReviseAddEditState {
+
+  int pageType = 0;  //页面的状态 0 是新增  1是编辑  2是详情
+  String? id;  //编辑和详情需要用到ID,新增是 appliedId  编辑和详情是 reviseId
+  void Function(dynamic value)? cb;
+
+  //页面对应的详情数据
+  AddEditReviseViewSGEntity? addEditEntity;
+
+
+  //表单的校验与数据
+  Map<String, Map<String, dynamic>> formData = {
+    'revise_hour': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'reason': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+  };
+
+}

+ 243 - 0
packages/cpt_job_sg/lib/modules/revise_applied/revise_applied_controller.dart

@@ -0,0 +1,243 @@
+import 'package:cpt_job_sg/modules/revise_add_edit/revise_add_edit_page.dart';
+import 'package:domain/entity/response/revise_list_s_g_entity.dart';
+import 'package:domain/repository/job_sg_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../revise_log/revise_log_page.dart';
+import 'revise_applied_state.dart';
+
+class ReviseAppliedController extends GetxController with DioCancelableMixin {
+  final JobSGRepository _jobRepository = Get.find();
+  final ReviseAppliedState state = ReviseAppliedState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchNotifyList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchNotifyList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchNotifyList();
+  }
+
+  /// 获取服务器数据,通知消息列表
+  Future fetchNotifyList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 并发执行两个请求
+
+    var listResult = await _jobRepository.fetchReviseList(
+      state.appliedId,
+      null,
+      null,
+      null,
+      null,
+      curPage: _curPage,
+      cancelToken: cancelToken,
+    );
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<ReviseListSGRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchNotifyList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  /// 去日志页面
+  void gotoReviseLogsPage(int index) {
+    ReviseLogPage.startInstance(state.datas[index].reviseId);
+  }
+
+  /// 去详情页面
+  void gotoReviseEditPage(int index) {
+    ReviseAddEditPage.startInstance(1, state.datas[index].reviseId, (result) {
+      if (result is String) {
+        //编辑之后刷新当前Item
+        fetchItemByIdAndRefreshItem(result);
+      }
+    });
+  }
+
+  /// 去编辑页面
+  void gotoReviseDetailPage(int index) {
+    ReviseAddEditPage.startInstance(2, state.datas[index].reviseId, null);
+  }
+
+  //执行取消操作
+  void doRecallAction(int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+      title: "Confirmation".tr,
+      message: "Are you sure you want to recall this revise?".tr,
+      confirmAction: () {
+        _requestRecall(index);
+      },
+    ));
+  }
+
+  //执行删除操作
+  void doDeleteAction(int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+      title: "Confirmation".tr,
+      message: "Are you sure you want to delete this revise?".tr,
+      confirmAction: () {
+        _requestDeactivate(index);
+      },
+    ));
+  }
+
+  // 请求接口删除Job
+  void _requestDeactivate(int index) async {
+    var result = await _jobRepository.deleteRevise(state.datas[index].reviseId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      if (state.datas.length <= 1) {
+        refreshController.callRefresh();
+      } else {
+        state.datas.removeAt(index);
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  void _requestRecall(int index) async {
+    var result = await _jobRepository.recallRevise(state.datas[index].reviseId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      fetchItemByIdAndRefreshItem(state.datas[index].reviseId ?? "");
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  /// 根据ID获取Item对象,用于刷新
+  void fetchItemByIdAndRefreshItem(String ids) async {
+    var result = await _jobRepository.fetchReviseListByIds(
+      ids,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      var data = result.data;
+      if (data != null && data.rows.isNotEmpty) {
+        List<ReviseListSGRows> newItem = data.rows;
+
+        // 创建一个 Map 来加速查找
+        Map<String, ReviseListSGRows> newItemMap = {for (var item in newItem) item.reviseId ?? "": item};
+
+        // 遍历 state.datas 进行替换
+        for (int i = 0; i < state.datas.length; i++) {
+          if (newItemMap.containsKey(state.datas[i].reviseId)) {
+            state.datas[i] = newItemMap[state.datas[i].reviseId]!;
+          }
+        }
+
+        //刷新
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  //去添加Revise
+  void gotoReviewAddPage() {
+    ReviseAddEditPage.startInstance(0, state.appliedId, (value) {
+      //添加成功,刷新页面
+      refreshController.callRefresh();
+    });
+  }
+}

+ 143 - 0
packages/cpt_job_sg/lib/modules/revise_applied/revise_applied_page.dart

@@ -0,0 +1,143 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../revise_list/revise_list_item.dart';
+import 'revise_applied_controller.dart';
+import 'revise_applied_state.dart';
+
+/**
+ * Revise的全部列表
+ */
+class ReviseAppliedPage extends BaseStatefulPage<ReviseAppliedController> {
+  ReviseAppliedPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(String? appliedId, String? jobTitle, String? jobDate) {
+    return Get.start(RouterPath.reviseAppliedSG, arguments: {'appliedId': appliedId, 'jobTitle': jobTitle, 'jobDate': jobDate});
+  }
+
+  @override
+  ReviseAppliedController createRawController() {
+    return ReviseAppliedController();
+  }
+
+  @override
+  State<ReviseAppliedPage> createState() => _JobListState();
+}
+
+class _JobListState extends BaseState<ReviseAppliedPage, ReviseAppliedController> {
+  late ReviseAppliedState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.appliedId = Get.arguments['appliedId'];
+    state.jobTitle = Get.arguments['jobTitle'];
+    state.jobDate = Get.arguments['jobDate'];
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return SafeArea(
+        bottom: true,
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+            ),
+          ),
+          child: Column(
+            children: [
+              MyAppBar.titleBar(
+                context,
+                state.jobTitle ?? "Title".tr,
+                subTitle: "(${state.jobDate ?? "-"})",
+                subTitleColor: ColorConstants.textGrayAECAE5,
+              ),
+
+              // 添加按钮
+              MyButton(
+                type: ClickType.throttle,
+                milliseconds: 500,
+                onPressed: () {
+                  FocusScope.of(context).unfocus();
+                  controller.gotoReviewAddPage();
+                },
+                text: "Add Revise".tr,
+                textColor: ColorConstants.white,
+                fontSize: 16,
+                radius: 20,
+                backgroundColor: hexToColor("#FFBB1B"),
+                fontWeight: FontWeight.w500,
+              ).marginOnly(left: 15, right: 15, top: 15, bottom: 5),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                        return ReviseListItem(
+                          index: index,
+                          item: state.datas[index],
+                          onDetailAction: () {
+                            controller.gotoReviseDetailPage(index);
+                          },
+                          onLogsAction: () {
+                            controller.gotoReviseLogsPage(index);
+                          },
+                          onDeleteAction: () {
+                            controller.doDeleteAction(index);
+                          },
+                          onRecallAction: () {
+                            controller.doRecallAction(index);
+                          },
+                          onEditAction: () {
+                            controller.gotoReviseEditPage(index);
+                          },
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).marginOnly(top: 5, bottom: 5).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 10 - 0
packages/cpt_job_sg/lib/modules/revise_applied/revise_applied_state.dart

@@ -0,0 +1,10 @@
+import 'package:domain/entity/response/revise_list_s_g_entity.dart';
+
+class ReviseAppliedState {
+  String? appliedId;
+  String? jobTitle;
+  String? jobDate;
+
+  //页面的列表数据
+  List<ReviseListSGRows> datas = [];
+}

+ 299 - 0
packages/cpt_job_sg/lib/modules/revise_list/revise_list_controller.dart

@@ -0,0 +1,299 @@
+import 'package:cpt_job_sg/modules/revise_add_edit/revise_add_edit_page.dart';
+import 'package:domain/entity/response/revise_index_s_g_entity.dart';
+import 'package:domain/entity/response/revise_list_s_g_entity.dart';
+import 'package:domain/repository/job_sg_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../revise_log/revise_log_page.dart';
+import 'revise_list_filter.dart';
+import 'revise_list_state.dart';
+
+class ReviseListController extends GetxController with DioCancelableMixin {
+  final JobSGRepository _jobRepository = Get.find();
+  final ReviseListState state = ReviseListState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchNotifyList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchNotifyList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchNotifyList();
+  }
+
+  /// 获取服务器数据,通知消息列表
+  Future fetchNotifyList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 并发执行两个请求
+    var futures = [
+      _jobRepository.fetchReviseList(
+        null,
+        state.selectedStatusId,
+        state.keyword,
+        DateTimeUtils.formatDate(state.selectedStartDate, format: "yyyy-MM-dd"),
+        DateTimeUtils.formatDate(state.selectedEndDate, format: "yyyy-MM-dd"),
+        curPage: _curPage,
+        cancelToken: cancelToken,
+      ),
+      state.indexOptions == null
+          ? _jobRepository.fetchReviseIndex(
+              cancelToken: cancelToken,
+            )
+          : Future(() => HttpResult(isSuccess: true).convert(data: state.indexOptions!)),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<ReviseListSGEntity>;
+    var optionResult = results[1] as HttpResult<ReviseIndexSGEntity>;
+
+    //选项数据
+    if (state.indexOptions == null && optionResult.isSuccess) {
+      state.indexOptions = optionResult.data!;
+    }
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<ReviseListSGRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  // 执行搜索
+  void doSearch(String keyword) {
+    state.keyword = keyword;
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  // 清空搜索条件
+  void resetFiltering() {
+    state.keyword = "";
+    state.searchController.text = "";
+
+    state.selectedStartDate = null;
+    state.selectedEndDate = null;
+    state.selectedStatusId = null;
+
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  //展示筛选的弹窗
+  void showFilterDialog() {
+    if (state.indexOptions != null) {
+      DialogEngine.show(
+        widget: ReviseListFilter(
+          optionResult: state.indexOptions!,
+          selectedStartDate: state.selectedStartDate,
+          selectedEndDate: state.selectedEndDate,
+          selectedStatusId: state.selectedStatusId,
+          onFilterAction: (startDate, endDate, statusId) {
+            state.selectedStartDate = startDate;
+            state.selectedEndDate = endDate;
+            state.selectedStatusId = statusId;
+
+            //赋值之后刷新
+            refreshController.callRefresh();
+          },
+        ),
+        position: DialogPosition.top,
+        animType: DialogAnimation.fade,
+      );
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchNotifyList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  /// 去日志页面
+  void gotoReviseLogsPage(int index) {
+    ReviseLogPage.startInstance(state.datas[index].reviseId);
+  }
+
+  /// 去详情页面
+  void gotoReviseEditPage(int index) {
+    ReviseAddEditPage.startInstance(1, state.datas[index].reviseId,(result){
+      if (result is String){
+        //编辑之后刷新当前Item
+        fetchItemByIdAndRefreshItem(result);
+      }
+    });
+  }
+
+  /// 去编辑页面
+  void gotoReviseDetailPage(int index) {
+    ReviseAddEditPage.startInstance(2, state.datas[index].reviseId,null);
+  }
+
+  //执行取消操作
+  void doRecallAction(int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+      title: "Confirmation".tr,
+      message: "Are you sure you want to recall this revise?".tr,
+      confirmAction: () {
+        _requestRecall(index);
+      },
+    ));
+  }
+
+  //执行删除操作
+  void doDeleteAction(int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+      title: "Confirmation".tr,
+      message: "Are you sure you want to delete this revise?".tr,
+      confirmAction: () {
+        _requestDeactivate(index);
+      },
+    ));
+  }
+
+  // 请求接口删除Job
+  void _requestDeactivate(int index) async {
+    var result = await _jobRepository.deleteRevise(state.datas[index].reviseId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      if (state.datas.length <= 1) {
+        refreshController.callRefresh();
+      } else {
+        state.datas.removeAt(index);
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  void _requestRecall(int index) async {
+    var result = await _jobRepository.recallRevise(state.datas[index].reviseId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      fetchItemByIdAndRefreshItem(state.datas[index].reviseId ?? "");
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  /// 根据ID获取Item对象,用于刷新
+  void fetchItemByIdAndRefreshItem(String ids) async {
+    var result = await _jobRepository.fetchReviseListByIds(
+      ids,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      var data = result.data;
+      if (data != null && data.rows.isNotEmpty) {
+        List<ReviseListSGRows> newItem = data.rows;
+
+        // 创建一个 Map 来加速查找
+        Map<String, ReviseListSGRows> newItemMap = {for (var item in newItem) item.reviseId ?? "": item};
+
+        // 遍历 state.datas 进行替换
+        for (int i = 0; i < state.datas.length; i++) {
+          if (newItemMap.containsKey(state.datas[i].reviseId)) {
+            state.datas[i] = newItemMap[state.datas[i].reviseId]!;
+          }
+        }
+
+        //刷新
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+}

+ 290 - 0
packages/cpt_job_sg/lib/modules/revise_list/revise_list_filter.dart

@@ -0,0 +1,290 @@
+import 'dart:ui';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/revise_index_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/picker/option_pick_util.dart';
+import 'package:widgets/widget_export.dart';
+
+/**
+ * 用工请求列表的筛选
+ */
+class ReviseListFilter extends StatefulWidget {
+  void Function(DateTime? selectedStartDate, DateTime? selectedEndDate, String? selectedStatusId)? onFilterAction;
+  ReviseIndexSGEntity optionResult;
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedStatusId;
+
+  ReviseListFilter({
+    required this.optionResult,
+    required this.selectedStartDate,
+    required this.selectedEndDate,
+    required this.selectedStatusId,
+    this.onFilterAction,
+  });
+
+  @override
+  State<ReviseListFilter> createState() => _ReviseListFilterState();
+}
+
+class _ReviseListFilterState extends State<ReviseListFilter> {
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedStatusId;
+
+  @override
+  void initState() {
+    super.initState();
+    this.selectedStartDate = widget.selectedStartDate;
+    this.selectedEndDate = widget.selectedEndDate;
+    this.selectedStatusId = widget.selectedStatusId;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      mainAxisAlignment: MainAxisAlignment.start,
+      children: [
+        SizedBox(
+          height: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1,
+        ),
+        Container(
+          padding: EdgeInsets.only(left: 15, right: 15, top: 17.5, bottom: 20),
+          width: double.infinity,
+          decoration: BoxDecoration(
+            color: Colors.white,
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              //状态
+              MyTextView(
+                "Status".tr,
+                fontSize: 14,
+                isFontMedium: true,
+                textColor: ColorConstants.black33,
+              ),
+
+              //选择状态
+              Container(
+                padding: EdgeInsets.only(left: 16, right: 10),
+                margin: EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      selectedStatusId == null || selectedStatusId == "0"
+                          ? ""
+                          : widget.optionResult.statusList.firstWhere((element) => element.value == selectedStatusId).txt!,
+                      fontSize: 14,
+                      hint: "Choose Status".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerStatus();
+              }),
+
+              //开始时间
+              MyTextView(
+                "Start Date".tr,
+                fontSize: 14,
+                isFontMedium: true,
+                marginTop: 11,
+                textColor: ColorConstants.black33,
+              ),
+
+              //选择时间
+              Container(
+                padding: EdgeInsets.only(left: 16, right: 10),
+                margin: EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      selectedStartDate == null ? "" : DateTimeUtils.formatDate(selectedStartDate, format: "yyyy-MM-dd"),
+                      fontSize: 14,
+                      hint: "Choose Start Date".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerStartDate();
+              }),
+
+              //结束日期
+              MyTextView(
+                "End Date".tr,
+                fontSize: 14,
+                marginTop: 11,
+                isFontMedium: true,
+                textColor: ColorConstants.black33,
+              ),
+
+              //选择结束日期
+              Container(
+                padding: EdgeInsets.only(left: 16, right: 10),
+                margin: EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      selectedEndDate == null ? "" : DateTimeUtils.formatDate(selectedEndDate, format: "yyyy-MM-dd"),
+                      fontSize: 14,
+                      hint: "Choose End Date".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerEndDate();
+              }),
+
+              //按钮组
+              Row(
+                children: [
+                  MyButton(
+                    onPressed: () {
+                      //只是Reset当前的弹窗筛选选项
+                      widget.selectedStartDate = null;
+                      widget.selectedEndDate = null;
+                      widget.selectedStatusId = null;
+
+                      setState(() {
+                        selectedStartDate = null;
+                        selectedEndDate = null;
+                        selectedStatusId = null;
+                      });
+                    },
+                    text: "Reset".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#FFBB1B"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 36,
+                  ).expanded(),
+                  SizedBox(width: 15),
+                  MyButton(
+                    onPressed: () {
+                      onCancel();
+                      widget.onFilterAction?.call(selectedStartDate, selectedEndDate, selectedStatusId);
+                    },
+                    text: "Filter".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#0AC074"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 36,
+                  ).expanded(),
+                ],
+              ).marginOnly(top: 20),
+            ],
+          ),
+        ),
+        Center(child: MyAssetImage(Assets.baseServiceDialogDeleteIcon, width: 26.5, height: 26.5).marginOnly(top: 35)).onTap(() {
+          onCancel();
+        }),
+      ],
+    );
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+
+  /// 筛选开始日期
+  void pickerStartDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: selectedStartDate,
+      onDateTimeChanged: (date) {
+        setState(() {
+          selectedStartDate = date;
+        });
+      },
+      title: "Start Date".tr,
+    );
+  }
+
+  /// 筛选结束日期
+  void pickerEndDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: selectedEndDate ?? selectedStartDate,
+      onDateTimeChanged: (date) {
+        setState(() {
+          selectedEndDate = date;
+        });
+      },
+      title: "End Date".tr,
+    );
+  }
+
+  /// 筛选状态
+  void pickerStatus() {
+    int selectedStatusIndex;
+    if (selectedStatusId == null) {
+      selectedStatusIndex = 0;
+    } else {
+      selectedStatusIndex = widget.optionResult.statusList!.indexWhere((department) => department.value == selectedStatusId);
+    }
+
+    if (selectedStatusIndex < 0) {
+      selectedStatusIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: widget.optionResult.statusList.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedStatusIndex,
+      onPickerChanged: (_, index) {
+        setState(() {
+          selectedStatusId = widget.optionResult.statusList[index].value;
+        });
+      },
+    );
+  }
+}

+ 298 - 0
packages/cpt_job_sg/lib/modules/revise_list/revise_list_item.dart

@@ -0,0 +1,298 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/revise_list_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+
+/**
+ * Revise的Item布局
+ */
+class ReviseListItem extends StatelessWidget {
+  final int index;
+  final ReviseListSGRows item;
+  final VoidCallback? onDetailAction;
+  final VoidCallback? onLogsAction;
+  final VoidCallback? onDeleteAction;
+  final VoidCallback? onRecallAction;
+  final VoidCallback? onEditAction;
+
+  ReviseListItem({
+    required this.index,
+    required this.item,
+    this.onDetailAction,
+    this.onLogsAction,
+    this.onDeleteAction,
+    this.onRecallAction,
+    this.onEditAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          // 姓名
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Name:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.name ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 身份证
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Nric".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期时间
+              MyTextView(
+                item.nric ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 工作时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Job Time".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.jobTime ?? "",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: ColorConstants.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 加减小时
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "+/- Hours".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.adjustHours ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 总小时
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Total Hours:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.totalHours ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 修改小时
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Revise Hours".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.reviseHours ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 状态
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Status:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //状态
+              MyTextView(
+                item.statusShow == null ? "" : item.statusShow!.tr,
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          //按钮组
+          Visibility(
+            visible: item.actionList?.isNotEmpty ?? false,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                //编辑按钮
+                Visibility(
+                  visible: item.actionList?.contains("edit") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onEditAction?.call();
+                    },
+                    text: "Edit".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor(
+                      "#FFBB1B",
+                    ),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //状态工作流按钮
+                Visibility(
+                  visible: item.actionList?.contains("recall") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onRecallAction?.call();
+                    },
+                    text: "Recall".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textYellowF8AE00,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //状态工作流按钮
+                Visibility(
+                  visible: item.actionList?.contains("delete") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDeleteAction?.call();
+                    },
+                    text: "Delete".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textRedFF6262,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //详情按钮
+                Visibility(
+                  visible: item.actionList?.contains("detail") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDetailAction?.call();
+                    },
+                    text: "Detail".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textBlue56AAFF,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //日志
+                Visibility(
+                  visible: item.actionList?.contains("logs") ?? false,
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onLogsAction?.call();
+                    },
+                    text: "Logs".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textGreen0AC074,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+              ],
+            ).marginOnly(top: 18, bottom: 2),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 152 - 0
packages/cpt_job_sg/lib/modules/revise_list/revise_list_page.dart

@@ -0,0 +1,152 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'revise_list_item.dart';
+import 'revise_list_controller.dart';
+import 'revise_list_state.dart';
+
+/**
+ * Revise的全部列表
+ */
+class ReviseListPage extends BaseStatefulPage<ReviseListController> {
+  ReviseListPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.reviseListSG);
+  }
+
+  @override
+  ReviseListController createRawController() {
+    return ReviseListController();
+  }
+
+  @override
+  State<ReviseListPage> createState() => _JobListState();
+}
+
+class _JobListState extends BaseState<ReviseListPage, ReviseListController> {
+  late ReviseListState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return SafeArea(
+        bottom: true,
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+            ),
+          ),
+          child: Column(
+            children: [
+              MyAppBar.searchTitleBar(
+                context,
+                value: state.keyword,
+                hintText: 'Search'.tr,
+                controller: state.searchController,
+                onSearch: (keyword) {
+                  controller.doSearch(keyword);
+                },
+                actions: [
+                  //重置按钮
+                  MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      controller.resetFiltering();
+                    },
+                    text: "Reset".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#2BA9F9", opacity: 0.5),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(right: 15),
+
+                  //筛选图标
+                  MyAssetImage(
+                    Assets.baseServiceTitleBarFilterIcon,
+                    width: 24,
+                    height: 16.5,
+                  ).onTap(() {
+                    FocusScope.of(context).unfocus();
+                    controller.showFilterDialog();
+                  }).marginOnly(right: 15),
+                ],
+              ),
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(delegate: SliverChildBuilderDelegate((context, index) {
+                        return ReviseListItem(
+                          index: index,
+                          item: state.datas[index],
+                          onDetailAction: () {
+                            controller.gotoReviseDetailPage(index);
+                          },
+                          onLogsAction: () {
+                            controller.gotoReviseLogsPage(index);
+                          },
+                          onDeleteAction: () {
+                            controller.doDeleteAction(index);
+                          },
+                          onRecallAction: () {
+                            controller.doRecallAction(index);
+                          },
+                          onEditAction: () {
+                            controller.gotoReviseEditPage(index);
+                          },
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).marginOnly(top: 5, bottom: 5).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+
+}

+ 17 - 0
packages/cpt_job_sg/lib/modules/revise_list/revise_list_state.dart

@@ -0,0 +1,17 @@
+import 'package:domain/entity/response/revise_index_s_g_entity.dart';
+import 'package:domain/entity/response/revise_list_s_g_entity.dart';
+
+import 'package:flutter/material.dart';
+
+class ReviseListState {
+  //筛选条件
+  final TextEditingController searchController = TextEditingController();
+  String keyword = "";
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedStatusId;
+
+  //页面的列表数据
+  List<ReviseListSGRows> datas = [];
+  ReviseIndexSGEntity? indexOptions;
+}

+ 98 - 0
packages/cpt_job_sg/lib/modules/revise_log/revise_log_controller.dart

@@ -0,0 +1,98 @@
+import 'package:domain/entity/response/revise_log_s_g_entity.dart';
+import 'package:domain/repository/job_sg_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'revise_log_state.dart';
+
+/**
+ * 修改的记录
+ */
+class  ReviseLogController extends GetxController with DioCancelableMixin{
+  final JobSGRepository _jobRepository = Get.find();
+  final ReviseLogState state = ReviseLogState();
+
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: false,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    fetchWorkFlowList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _needShowPlaceholder = true;
+    fetchWorkFlowList();
+  }
+
+  /// 获取服务器数据,成员考勤列表
+  Future fetchWorkFlowList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    //获取到数据
+    var result = await _jobRepository.fetchReviseLogs(
+      state.reviseId,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      handleList(result.data?.records);
+      refreshController.finishRefresh(IndicatorResult.success);
+    } else {
+      errorMessage = result.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+      refreshController.finishRefresh(IndicatorResult.fail);
+    }
+
+    //最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<ReviseLogSGRecords>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      state.datas.clear();
+      state.datas.addAll(list);
+      //更新状态
+      changeLoadingState(LoadState.State_Success);
+    } else {
+      //展示无数据的布局
+      state.datas.clear();
+      changeLoadingState(LoadState.State_Empty);
+    }
+  }
+
+  @override
+  void onReady() async {
+    super.onReady();
+    fetchWorkFlowList();
+  }
+
+  @override
+  void onClose() {
+    super.onClose();
+    state.datas.clear();
+  }
+}

+ 155 - 0
packages/cpt_job_sg/lib/modules/revise_log/revise_log_item.dart

@@ -0,0 +1,155 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/revise_log_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
+
+/**
+ * 修改记录Item
+ */
+class ReviseLogItem extends StatelessWidget {
+  final int index;
+  final ReviseLogSGRecords item;
+
+  ReviseLogItem({
+    required this.index,
+    required this.item,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          //时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Date Time".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.createdAt ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ),
+
+          // 操作者
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Operator:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.operationName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 操作类型
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Action".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //状态
+              MyTextView(
+                item.actText ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: item.actText == "Audit" ? ColorConstants.textYellowF8AE00 : ColorConstants.textGreen0AC074,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 操作内容
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              MyTextView(
+                "Content".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //时间
+              MyTextView(
+                _obtainContent(),
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+        ],
+      ),
+    );
+  }
+
+  String _obtainContent() {
+    String displayText = "";
+
+    // 检查 reviseHours
+    if (item.content?.reviseHours != null) {
+      displayText += "Revise Hours => ${item.content!.reviseHours!.value!}\n";
+    }
+
+    // 检查 reviseMsg
+    if (item.content?.reviseMsg != null) {
+      displayText += "Reason => ${item.content!.reviseMsg!.value!}\n";
+    }
+
+    // 检查 status
+    if (item.content?.status != null) {
+      displayText += "Status => ${item.content!.status!.value!}\n";
+    }
+
+    // 如果没有任何信息,则显示 "-"
+    if (displayText.isEmpty) {
+      displayText = "-";
+    } else {
+      // 去掉末尾的换行符
+      displayText = displayText.trim();
+    }
+
+    return displayText;
+  }
+}

+ 102 - 0
packages/cpt_job_sg/lib/modules/revise_log/revise_log_page.dart

@@ -0,0 +1,102 @@
+
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'revise_log_controller.dart';
+import 'revise_log_state.dart';
+import 'revise_log_item.dart';
+
+/**
+ * 修改的记录
+ */
+class ReviseLogPage extends BaseStatefulPage<ReviseLogController> {
+  ReviseLogPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(String? reviseId) {
+    return Get.start(RouterPath.reviseLogSG,arguments: {'reviseId': reviseId});
+  }
+
+  @override
+  ReviseLogController createRawController() {
+    return ReviseLogController();
+  }
+
+  @override
+  State<ReviseLogPage> createState() => _AppliedWorkflowState();
+
+}
+
+class _AppliedWorkflowState extends BaseState<ReviseLogPage, ReviseLogController> {
+
+  late ReviseLogState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+    state.reviseId = Get.arguments['reviseId'];
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return  SafeArea(
+          bottom: true,
+          top: false,
+          child: Container(
+            width: double.infinity,
+            height: double.infinity,
+            padding: EdgeInsets.only(top:ScreenUtil.getStatusBarH(context)),
+            decoration: const BoxDecoration(
+              gradient: LinearGradient(
+                colors: [
+                  Color(0xFF091D44),
+                  Color(0xFF245A8A),
+                  Color(0xFF7F7CEC),
+                ],
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+              ),
+            ),
+            child: Column(
+              children: [
+                MyAppBar.titleBar(context, "Logs".tr),
+
+                EasyRefresh(
+                  controller: controller.refreshController,
+                  onRefresh: controller.onRefresh,
+                  child: LoadStateLayout(
+                    state: controller.loadingState,
+                    errorMessage: controller.errorMessage,
+                    errorRetry: () {
+                      controller.retryRequest();
+                    },
+                    successSliverWidget: [
+                      SliverList(
+                          delegate: SliverChildBuilderDelegate((context, index) {
+                              return ReviseLogItem(index: index,item: state.datas[index]);
+                            },
+                            childCount: state.datas.length,
+                          ))
+                    ],
+                  ),
+                ).marginOnly(top: 5,bottom: 5).expanded(),
+              ],
+            ).marginOnly(top: 10),
+          ),
+        );
+    });
+  }
+}
+
+

+ 10 - 0
packages/cpt_job_sg/lib/modules/revise_log/revise_log_state.dart

@@ -0,0 +1,10 @@
+import 'package:domain/entity/response/revise_log_s_g_entity.dart';
+
+class ReviseLogState {
+
+  String? reviseId;
+
+  //页面的列表数据
+  List<ReviseLogSGRecords> datas = [];
+
+}

+ 30 - 0
packages/cpt_job_sg/lib/router/job_sg_service_impl.dart

@@ -0,0 +1,30 @@
+import 'package:cpt_job_sg/modules/revise_list/revise_list_page.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:router/componentRouter/job_sg_service.dart';
+
+import '../modules/job_applied/job_applied_page.dart';
+
+class JobSGServiceImpl extends GetxService implements JobSGService {
+  @override
+  void onInit() {
+    super.onInit();
+    //初始化资源
+  }
+
+  @override
+  void onClose() {
+    super.onClose();
+    //销毁资源
+  }
+
+  @override
+  void startJobAppliedPage(String? jobId,void Function(dynamic value)? cb) {
+    JobAppliedPage.startInstance(jobId,cb);
+  }
+
+  @override
+  void startReviseListPage() {
+    ReviseListPage.startInstance();
+  }
+
+}

+ 58 - 0
packages/cpt_job_sg/lib/router/page_router.dart

@@ -0,0 +1,58 @@
+import 'package:cpt_job_sg/modules/revise_list/revise_list_page.dart';
+import 'package:cpt_job_sg/modules/revise_log/revise_log_page.dart';
+import 'package:get/get.dart';
+import 'package:router/path/router_path.dart';
+
+import '../modules/applied_staff/applied_staff_page.dart';
+import '../modules/applied_staff_detail/applied_staff_detail_page.dart';
+import '../modules/applied_staff_reviews/applied_staff_reviews_page.dart';
+import '../modules/job_applied/job_applied_page.dart';
+import '../modules/revise_add_edit/revise_add_edit_page.dart';
+import '../modules/revise_applied/revise_applied_page.dart';
+
+class JobPageSGRouter {
+  static final routes = [
+    // 工作列表 (新加坡)
+    // 新加坡工作列表已申请列表
+    GetPage(
+      name: RouterPath.jobListAppliedSG,
+      page: () => JobAppliedPage(),
+    ),
+
+    GetPage(
+      name: RouterPath.jobListAppliedStaffListSG,
+      page: () => AppliedStaffPage(),
+    ),
+
+    GetPage(
+      name: RouterPath.jobListAppliedStaffDetailSG,
+      page: () => AppliedStaffDetailPage(),
+    ),
+
+    GetPage(
+      name: RouterPath.jobListAppliedStaffReviewSG,
+      page: () => AppliedStaffReviewsPage(),
+    ),
+
+    GetPage(
+      name: RouterPath.reviseListSG,
+      page: () => ReviseListPage(),
+    ),
+
+    GetPage(
+      name: RouterPath.reviseLogSG,
+      page: () => ReviseLogPage(),
+    ),
+
+    GetPage(
+      name: RouterPath.reviseEditSG,
+      page: () => ReviseAddEditPage(),
+    ),
+
+    GetPage(
+      name: RouterPath.reviseAppliedSG,
+      page: () => ReviseAppliedPage(),
+    ),
+
+  ];
+}

+ 40 - 0
packages/cpt_job_sg/pubspec.yaml

@@ -0,0 +1,40 @@
+name: cpt_job_sg
+description: 指定新加坡的工作模块
+
+version: 1.0.0
+
+environment:
+  sdk: '>=3.0.2 <4.0.0'
+
+dependencies:
+
+  flutter_localizations:
+    sdk: flutter
+
+  flutter:
+    sdk: flutter
+
+  #基础组件的依赖
+  domain:
+    path: ../cs_domain
+
+  plugin_basic:
+    path: ../cs_plugin_basic
+
+  plugin_platform:
+    path: ../cs_plugin_platform
+
+  shared:
+    path: ../cs_shared
+
+  cs_resources:
+    path: ../cs_resources
+
+  router:
+    path: ../cs_router
+
+  widgets:
+    path: ../cs_widgets
+
+flutter:
+  uses-material-design: true

+ 16 - 0
packages/cpt_job_sg/pubspec_overrides.yaml

@@ -0,0 +1,16 @@
+# melos_managed_dependency_overrides: cs_resources,domain,plugin_basic,plugin_platform,router,shared,widgets
+dependency_overrides:
+  cs_resources:
+    path: ../cs_resources
+  domain:
+    path: ../cs_domain
+  plugin_basic:
+    path: ../cs_plugin_basic
+  plugin_platform:
+    path: ../cs_plugin_platform
+  router:
+    path: ../cs_router
+  shared:
+    path: ../cs_shared
+  widgets:
+    path: ../cs_widgets

+ 1 - 1
packages/cpt_labour/lib/modules/labour_request_add/labour_request_add_page.dart

@@ -30,7 +30,7 @@ class LabourRequestAddPage extends BaseStatefulPage<LabourRequestAddController>
 
   //启动当前页面,pageType 0 是新增  1是编辑  2是详情
   static void startInstance(int pageType, String? appliedId) {
-    return Get.start(RouterPath.JOB_LABOUR_REQUEST_ADD, arguments: {'pageType': pageType, 'appliedId': appliedId});
+    return Get.start(RouterPath.jobLabourRequestAdd, arguments: {'pageType': pageType, 'appliedId': appliedId});
   }
 
   @override

+ 2 - 2
packages/cpt_labour/lib/modules/labour_request_list/labour_request_list_page.dart

@@ -26,7 +26,7 @@ class LabourRequestListPage extends BaseStatefulPage<LabourRequestListController
 
   //启动当前页面
   static void startInstance() {
-    return Get.start(RouterPath.JOB_LABOUR_REQUEST_LIST);
+    return Get.start(RouterPath.jobLabourRequestList);
   }
 
   @override
@@ -94,7 +94,7 @@ class _LabourRequestListState extends BaseState<LabourRequestListPage, LabourReq
                   ).marginOnly(right: 15),
 
                   //筛选图标
-                  MyAssetImage(
+                  const MyAssetImage(
                     Assets.baseServiceTitleBarFilterIcon,
                     width: 24,
                     height: 16.5,

+ 1 - 1
packages/cpt_labour/lib/modules/labour_request_workflow/labour_request_workflow_page.dart

@@ -23,7 +23,7 @@ class LabourRequestWorkflowPage extends BaseStatefulPage<LabourRequestWorkflowCo
 
   //启动当前页面
   static void startInstance(String? requestId) {
-    return Get.start(RouterPath.JOB_LABOUR_REQUEST_WORKFLOW,arguments: {'requestId': requestId});
+    return Get.start(RouterPath.jobLabourRequestWorkflow,arguments: {'requestId': requestId});
   }
 
   @override

+ 3 - 3
packages/cpt_labour/lib/router/page_router.dart

@@ -13,19 +13,19 @@ class LabourPageRouter {
 
     //用工请求列表
     GetPage(
-      name: RouterPath.JOB_LABOUR_REQUEST_LIST,
+      name: RouterPath.jobLabourRequestList,
       page: () => LabourRequestListPage(),
     ),
 
     //用工请求添加
     GetPage(
-      name: RouterPath.JOB_LABOUR_REQUEST_ADD,
+      name: RouterPath.jobLabourRequestAdd,
       page: () => LabourRequestAddPage(),
     ),
 
     //用工请求状态修改工作流
     GetPage(
-      name: RouterPath.JOB_LABOUR_REQUEST_WORKFLOW,
+      name: RouterPath.jobLabourRequestWorkflow,
       page: () => LabourRequestWorkflowPage(),
     ),
 

+ 1 - 1
packages/cpt_labour/pubspec.yaml

@@ -1,5 +1,5 @@
 name: cpt_labour
-description: ProfileComponent Profile-Me组件
+description: 默认的越南用工模块
 
 version: 1.0.0
 

+ 31 - 0
packages/cpt_labour_sg/.gitignore

@@ -0,0 +1,31 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+*.lock
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# Visual Studio Code related
+.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub-cache/
+.pub/
+/build/
+proguardMapping.txt

+ 306 - 0
packages/cpt_labour_sg/lib/modules/job_list/job_list_controller.dart

@@ -0,0 +1,306 @@
+import 'package:cpt_labour_sg/modules/labour_request_add/labour_request_add_page.dart';
+import 'package:domain/entity/response/job_list_index_s_g_entity.dart';
+import 'package:domain/entity/response/job_list_s_g_entity.dart';
+import 'package:domain/repository/labour_sg_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:router/componentRouter/component_router_service.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../job_list_edit/job_list_edit_page.dart';
+import 'job_list_filter.dart';
+import 'job_list_state.dart';
+
+class JobListController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _jobRepository = Get.find();
+  final JobListState state = JobListState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchNotifyList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchNotifyList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchNotifyList();
+  }
+
+  /// 获取服务器数据,通知消息列表
+  Future fetchNotifyList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    // 并发执行两个请求
+    var futures = [
+      _jobRepository.fetchJobListTable(
+        DateTimeUtils.formatDate(state.selectedStartDate, format: "yyyy-MM-dd"),
+        DateTimeUtils.formatDate(state.selectedEndDate, format: "yyyy-MM-dd"),
+        state.selectedStatusId,
+        state.selectedOutletId,
+        curPage: _curPage,
+        cancelToken: cancelToken,
+      ),
+      state.indexOptions == null
+          ? _jobRepository.fetchJobListIndex(
+              cancelToken: cancelToken,
+            )
+          : Future(() => HttpResult(isSuccess: true).convert(data: state.indexOptions!)),
+    ];
+
+    //拿到结果
+    var results = await Future.wait(futures);
+    var listResult = results[0] as HttpResult<JobListSGEntity>;
+    var optionResult = results[1] as HttpResult<JobListIndexSGEntity>;
+
+    //选项数据
+    if (state.indexOptions == null && optionResult.isSuccess) {
+      state.indexOptions = optionResult.data!;
+    }
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<JobListSGRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  // 清空搜索条件
+  void resetFiltering() {
+    state.selectedStartDate = null;
+    state.selectedEndDate = null;
+    state.selectedStatusId = null;
+    state.selectedOutletId = null;
+
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  //展示筛选的弹窗
+  void showFilterDialog() {
+    if (state.indexOptions != null) {
+      DialogEngine.show(
+        widget: JobListFilter(
+          optionResult: state.indexOptions!,
+          selectedStartDate: state.selectedStartDate,
+          selectedEndDate: state.selectedEndDate,
+          selectedStatusId: state.selectedStatusId,
+          selectedOutletId: state.selectedOutletId,
+          onFilterAction: (startDate, endDate, statusId, outletId) {
+            state.selectedStartDate = startDate;
+            state.selectedEndDate = endDate;
+            state.selectedStatusId = statusId;
+            state.selectedOutletId = outletId;
+
+            //赋值之后刷新
+            refreshController.callRefresh();
+          },
+        ),
+        position: DialogPosition.top,
+        animType: DialogAnimation.fade,
+      );
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchNotifyList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  /// 去详情页面
+  void gotoJobDetailPage(int index) {
+    JobListEditPage.startInstance(false, state.datas[index].jobId, null);
+  }
+
+  // 执行编辑操作
+  void doEditAction(int index) {
+    JobListEditPage.startInstance(true, state.datas[index].jobId, (result) {
+      fetchItemByIdAndRefreshItem(state.datas[index].jobId ?? "");
+    });
+  }
+
+  /// 去已申请的成员列表
+  void gotoJobAppliedPage(int index) {
+    ComponentRouterServices.jobSGService.startJobAppliedPage(state.datas[index].jobId, (result) {
+      if (result is String?) {
+        //添加成功之后刷新
+        fetchItemByIdAndRefreshItem(result ?? "");
+      }
+    });
+  }
+
+  //执行取消操作
+  void doCancelAction(int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+      title: "Confirmation".tr,
+      message: "Are you sure you want to cancel this job?".tr,
+      confirmAction: () {
+        _requestCancel(index);
+      },
+    ));
+  }
+
+  //执行删除操作
+  void doDeleteAction(int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+      title: "Confirmation".tr,
+      message: "Are you sure you want to delete this job?".tr,
+      confirmAction: () {
+        _requestDeactivate(index);
+      },
+    ));
+  }
+
+  // 请求接口删除Job
+  void _requestDeactivate(int index) async {
+    final item = state.datas[index];
+    var result = await _jobRepository.deleteJobList(item.jobId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      if (state.datas.length <= 1) {
+        refreshController.callRefresh();
+      } else {
+        state.datas.removeAt(index);
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  void _requestCancel(int index) async {
+    final item = state.datas[index];
+    var result = await _jobRepository.cancelJobList(item.jobId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      fetchItemByIdAndRefreshItem(item.jobId ?? "");
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  //添加新的工作
+  void gotoLabourRequestAddPage() {
+    LabourRequestAddPage.startInstance((result) {
+      if (result is bool) {
+        //添加成功之后刷新
+        refreshController.callRefresh();
+      }
+    });
+  }
+
+  /// 根据ID获取Item对象,用于刷新
+  void fetchItemByIdAndRefreshItem(String ids) async {
+    var result = await _jobRepository.fetchJobListByIds(
+      ids,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      var data = result.data;
+      if (data != null && data.rows.isNotEmpty) {
+        List<JobListSGRows> newItem = data.rows;
+
+        // 创建一个 Map 来加速查找
+        Map<String, JobListSGRows> newItemMap = {for (var item in newItem) item.jobId ?? "": item};
+
+        // 遍历 state.datas 进行替换
+        for (int i = 0; i < state.datas.length; i++) {
+          if (newItemMap.containsKey(state.datas[i].jobId)) {
+            state.datas[i] = newItemMap[state.datas[i].jobId]!;
+          }
+        }
+
+        //刷新
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+}

+ 361 - 0
packages/cpt_labour_sg/lib/modules/job_list/job_list_filter.dart

@@ -0,0 +1,361 @@
+import 'dart:ui';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_list_index_entity.dart';
+import 'package:domain/entity/response/job_list_index_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/picker/option_pick_util.dart';
+import 'package:widgets/widget_export.dart';
+
+/**
+ * 用工请求列表的筛选
+ */
+class JobListFilter extends StatefulWidget {
+  void Function(DateTime? selectedStartDate, DateTime? selectedEndDate, String? selectedStatusId, String? selectedOutletId)? onFilterAction;
+  JobListIndexSGEntity optionResult;
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedStatusId;
+  String? selectedOutletId;
+
+  JobListFilter({
+    required this.optionResult,
+    required this.selectedStartDate,
+    required this.selectedEndDate,
+    required this.selectedStatusId,
+    required this.selectedOutletId,
+    this.onFilterAction,
+  });
+
+  @override
+  State<JobListFilter> createState() => _JobListFilterState();
+}
+
+class _JobListFilterState extends State<JobListFilter> {
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedStatusId;
+  String? selectedDepartmentId;
+
+  @override
+  void initState() {
+    super.initState();
+    this.selectedStartDate = widget.selectedStartDate;
+    this.selectedEndDate = widget.selectedEndDate;
+    this.selectedStatusId = widget.selectedStatusId;
+    this.selectedDepartmentId = widget.selectedOutletId;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      mainAxisAlignment: MainAxisAlignment.start,
+      children: [
+        SizedBox(
+          height: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1,
+        ),
+        Container(
+          padding: EdgeInsets.only(left: 15, right: 15, top: 17.5, bottom: 20),
+          width: double.infinity,
+          decoration: BoxDecoration(
+            color: Colors.white,
+          ),
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              //部门
+              MyTextView(
+                "Outlet".tr,
+                fontSize: 14,
+                isFontMedium: true,
+                textColor: ColorConstants.black33,
+              ),
+
+              //选择部门
+              Container(
+                padding: EdgeInsets.only(left: 16, right: 10),
+                margin: EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      selectedDepartmentId == null || selectedDepartmentId == "0"
+                          ? ""
+                          : widget.optionResult.outletList!.firstWhere((element) => element.value.toString() == selectedDepartmentId).txt!,
+                      hint: "Choose Outlet".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      fontSize: 14,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerOutlet();
+              }),
+
+              //状态
+              MyTextView(
+                "Status".tr,
+                fontSize: 14,
+                isFontMedium: true,
+                marginTop: 11,
+                textColor: ColorConstants.black33,
+              ),
+
+              //选择状态
+              Container(
+                padding: EdgeInsets.only(left: 16, right: 10),
+                margin: EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      selectedStatusId == null || selectedStatusId == "0"
+                          ? ""
+                          : widget.optionResult.statusList!.firstWhere((element) => element.value.toString() == selectedStatusId).txt!,
+                      fontSize: 14,
+                      hint: "Choose Status".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerStatus();
+              }),
+
+              //开始时间
+              MyTextView(
+                "Start Date".tr,
+                fontSize: 14,
+                isFontMedium: true,
+                marginTop: 11,
+                textColor: ColorConstants.black33,
+              ),
+
+              //选择时间
+              Container(
+                padding: EdgeInsets.only(left: 16, right: 10),
+                margin: EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      selectedStartDate == null ? "" : DateTimeUtils.formatDate(selectedStartDate, format: "yyyy-MM-dd"),
+                      fontSize: 14,
+                      hint: "Choose Start Date".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerStartDate();
+              }),
+
+              //结束日期
+              MyTextView(
+                "End Date".tr,
+                fontSize: 14,
+                marginTop: 11,
+                isFontMedium: true,
+                textColor: ColorConstants.black33,
+              ),
+
+              //选择结束日期
+              Container(
+                padding: EdgeInsets.only(left: 16, right: 10),
+                margin: EdgeInsets.only(top: 10),
+                height: 45,
+                decoration: BoxDecoration(
+                  color: ColorConstants.grayECECEC,
+                  borderRadius: const BorderRadius.all(Radius.circular(5)),
+                ),
+                child: Row(
+                  mainAxisSize: MainAxisSize.max,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  mainAxisAlignment: MainAxisAlignment.start,
+                  children: [
+                    MyTextView(
+                      selectedEndDate == null ? "" : DateTimeUtils.formatDate(selectedEndDate, format: "yyyy-MM-dd"),
+                      fontSize: 14,
+                      hint: "Choose End Date".tr,
+                      textHintColor: ColorConstants.textBlackHint,
+                      isFontMedium: true,
+                      textColor: ColorConstants.black33,
+                    ).expanded(),
+                    MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                  ],
+                ),
+              ).onTap(() {
+                pickerEndDate();
+              }),
+
+              //按钮组
+              Row(
+                children: [
+                  MyButton(
+                    onPressed: () {
+                      //只是Reset当前的弹窗筛选选项
+                      widget.selectedStartDate = null;
+                      widget.selectedEndDate = null;
+                      widget.selectedStatusId = null;
+                      widget.selectedOutletId = null;
+
+                      setState(() {
+                        selectedStartDate = null;
+                        selectedEndDate = null;
+                        selectedStatusId = null;
+                        selectedDepartmentId = null;
+                      });
+                    },
+                    text: "Reset".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#FFBB1B"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 36,
+                  ).expanded(),
+                  SizedBox(width: 15),
+                  MyButton(
+                    onPressed: () {
+                      onCancel();
+                      widget.onFilterAction?.call(selectedStartDate, selectedEndDate, selectedStatusId, selectedDepartmentId);
+                    },
+                    text: "Filter".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: hexToColor("#0AC074"),
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 36,
+                  ).expanded(),
+                ],
+              ).marginOnly(top: 20),
+            ],
+          ),
+        ),
+        Center(child: MyAssetImage(Assets.baseServiceDialogDeleteIcon, width: 26.5, height: 26.5).marginOnly(top: 35)).onTap(() {
+          onCancel();
+        }),
+      ],
+    );
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+
+  /// 筛选开始日期
+  void pickerStartDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: selectedStartDate,
+      onDateTimeChanged: (date) {
+        setState(() {
+          selectedStartDate = date;
+        });
+      },
+      title: "Start Date".tr,
+    );
+  }
+
+  /// 筛选结束日期
+  void pickerEndDate() {
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: selectedEndDate ?? selectedStartDate,
+      onDateTimeChanged: (date) {
+        setState(() {
+          selectedEndDate = date;
+        });
+      },
+      title: "End Date".tr,
+    );
+  }
+
+  /// 筛选部门
+  void pickerOutlet() {
+    int selectedDepartmentIndex;
+    if (selectedDepartmentId == null) {
+      selectedDepartmentIndex = 0;
+    } else {
+      selectedDepartmentIndex = widget.optionResult.outletList!.indexWhere((department) => department.value.toString() == selectedDepartmentId);
+    }
+
+    if (selectedDepartmentIndex < 0) {
+      selectedDepartmentIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: widget.optionResult.outletList!.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedDepartmentIndex,
+      onPickerChanged: (_, index) {
+        setState(() {
+          selectedDepartmentId = widget.optionResult.outletList![index].value!.toString();
+        });
+      },
+    );
+  }
+
+  /// 筛选状态
+  void pickerStatus() {
+    int selectedStatusIndex;
+    if (selectedStatusId == null) {
+      selectedStatusIndex = 0;
+    } else {
+      selectedStatusIndex = widget.optionResult.statusList!.indexWhere((department) => department.value.toString() == selectedStatusId);
+    }
+
+    if (selectedStatusIndex < 0) {
+      selectedStatusIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: widget.optionResult.statusList!.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedStatusIndex,
+      onPickerChanged: (_, index) {
+        setState(() {
+          selectedStatusId = widget.optionResult.statusList![index].value!.toString();
+        });
+      },
+    );
+  }
+}

+ 259 - 0
packages/cpt_labour_sg/lib/modules/job_list/job_list_item.dart

@@ -0,0 +1,259 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/job_list_s_g_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+
+/**
+ * 用工请求的主页面列表Item
+ */
+class JobListItem extends StatelessWidget {
+  final int index;
+  final JobListSGRows item;
+  final VoidCallback? onDetailAction;
+  final VoidCallback? onEditAction;
+  final VoidCallback? onCancelAction;
+  final VoidCallback? onDeleteAction;
+  final VoidCallback? onAppliedAction;
+
+  JobListItem({
+    required this.index,
+    required this.item,
+    this.onDetailAction,
+    this.onEditAction,
+    this.onCancelAction,
+    this.onDeleteAction,
+    this.onAppliedAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          //工作标题
+          MyTextView(
+            item.jobTitle ?? "-",
+            isFontMedium: true,
+            textColor: ColorConstants.textYellowFFBB1B,
+            fontSize: 14,
+            textDecoration: TextDecoration.underline,
+            decorationColor: ColorConstants.textYellowFFBB1B,
+            // 可选,设置下划线的颜色
+            decorationThickness: 2.0,
+            // 可选,设置下划线的粗细
+            decorationStyle: TextDecorationStyle.solid, // 可选,设置下划线的样式
+          ),
+
+          // 工作日期
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Job Date".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期时间
+              MyTextView(
+                item.jobDate ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 部门
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Outlet:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //部门
+              MyTextView(
+                item.outletName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 工作开始时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Job Time".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //日期时间
+              MyTextView(
+                "${item.startTime} - ${item.endTime}",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 人数
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "No. of Staff:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //人数
+              MyTextView(
+                item.hiringNum ?? "",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: ColorConstants.textYellowFFBB1B,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          // 状态
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Status:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //状态
+              MyTextView(
+                item.statusShow == null ? "" : item.statusShow!.tr,
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: "Completed" == item.statusShow
+                    ? ColorConstants.textGreen05DC82
+                    : "Cancelled" == item.statusShow
+                        ? ColorConstants.textRedFF6262
+                        : "Revised" == item.statusShow || "Pending" == item.statusShow
+                            ? ColorConstants.textYellowFFBB1B
+                            : ColorConstants.textBlue06D9FF,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 15),
+
+          //按钮组
+          Visibility(
+            visible: item.actionList?.isNotEmpty ?? false,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                //详情按钮
+                Visibility(
+                  visible: item.actionList.contains("detail"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDetailAction?.call();
+                    },
+                    text: "Detail".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textYellowFFBB1B,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+                Visibility(
+                  visible: item.actionList.contains("edit"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onEditAction?.call();
+                    },
+                    text: "Edit".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textGreen0AC074,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+                Visibility(
+                  visible: item.actionList.contains("cancel"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onCancelAction?.call();
+                    },
+                    text: "Cancel".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textYellowFFBB1B,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+                Visibility(
+                  visible: item.actionList.contains("delete"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDeleteAction?.call();
+                    },
+                    text: "Delete".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textRedFF6262,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+              ],
+            ).marginOnly(top: 18, bottom: 2),
+          ),
+        ],
+      ),
+    ).onTap(() {
+      onAppliedAction?.call();
+    });
+  }
+}

+ 156 - 0
packages/cpt_labour_sg/lib/modules/job_list/job_list_page.dart

@@ -0,0 +1,156 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/base/base_state.dart';
+import 'package:plugin_basic/base/base_stateful_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'job_list_item.dart';
+import 'job_list_controller.dart';
+import 'job_list_state.dart';
+
+/*
+ * 新加坡的JobList其实就是Labour的查询
+ */
+class JobListPage extends BaseStatefulPage<JobListController> {
+  JobListPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance({String? date}) {
+    return Get.start(RouterPath.jobListSG, arguments: {'date': date ?? ""});
+  }
+
+  @override
+  JobListController createRawController() {
+    return JobListController();
+  }
+
+  @override
+  State<JobListPage> createState() => _JobListState();
+}
+
+class _JobListState extends BaseState<JobListPage, JobListController> {
+  late JobListState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+
+    //如果有传递的Date,那就直接显示
+    String date = Get.arguments['date'];
+    if (Utils.isNotEmpty(date)) {
+      DateTime? selectDate = DateTimeUtils.getDateTime(date);
+      state.selectedStartDate = selectDate;
+      state.selectedEndDate = selectDate;
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return SafeArea(
+        bottom: true,
+        top: false,
+        child: Container(
+          width: double.infinity,
+          height: double.infinity,
+          padding: EdgeInsets.only(top: ScreenUtil.getStatusBarH(context)),
+          decoration: const BoxDecoration(
+            gradient: LinearGradient(
+              colors: [
+                Color(0xFF091D44),
+                Color(0xFF245A8A),
+                Color(0xFF7F7CEC),
+              ],
+              begin: Alignment.topCenter,
+              end: Alignment.bottomCenter,
+            ),
+          ),
+          child: Column(
+            children: [
+              MyAppBar.titleBar(context, "Job List".tr, actions: [
+                //筛选图标
+                const MyAssetImage(
+                  Assets.baseServiceTitleBarFilterIcon,
+                  width: 24,
+                  height: 16.5,
+                ).onTap(() {
+                  FocusScope.of(context).unfocus();
+                  controller.showFilterDialog();
+                }).marginOnly(right: 15),
+              ]),
+              //添加用工请求按钮
+              MyButton(
+                type: ClickType.throttle,
+                milliseconds: 500,
+                onPressed: () {
+                  FocusScope.of(context).unfocus();
+                  controller.gotoLabourRequestAddPage();
+                },
+                text: "Create New Job".tr,
+                textColor: ColorConstants.white,
+                fontSize: 16,
+                radius: 20,
+                backgroundColor: hexToColor("#FFBB1B"),
+                fontWeight: FontWeight.w500,
+              ).marginOnly(left: 15, right: 15, top: 15, bottom: 5),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                      (context, index) {
+                        return JobListItem(
+                          index: index,
+                          item: state.datas[index],
+                          onDetailAction: () {
+                            controller.gotoJobDetailPage(index);
+                          },
+                          onEditAction: () {
+                            controller.doEditAction(index);
+                          },
+                          onCancelAction: () {
+                            controller.doCancelAction(index);
+                          },
+                          onDeleteAction: () {
+                            controller.doDeleteAction(index);
+                          },
+                          onAppliedAction: () {
+                            controller.gotoJobAppliedPage(index);
+                          },
+                        );
+                      },
+                      childCount: state.datas.length,
+                    ))
+                  ],
+                ),
+              ).marginOnly(top: 5, bottom: 5).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 15 - 0
packages/cpt_labour_sg/lib/modules/job_list/job_list_state.dart

@@ -0,0 +1,15 @@
+
+import 'package:domain/entity/response/job_list_index_s_g_entity.dart';
+import 'package:domain/entity/response/job_list_s_g_entity.dart';
+
+class JobListState {
+
+  DateTime? selectedStartDate;
+  DateTime? selectedEndDate;
+  String? selectedStatusId;
+  String? selectedOutletId;
+
+  //页面的列表数据
+  List<JobListSGRows> datas = [];
+  JobListIndexSGEntity? indexOptions;
+}

+ 190 - 0
packages/cpt_labour_sg/lib/modules/job_list_edit/job_list_edit_controller.dart

@@ -0,0 +1,190 @@
+import 'package:domain/entity/response/job_list_edit_index_s_g_entity.dart';
+import 'package:domain/repository/labour_sg_repository.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/picker/date_picker_util.dart';
+import 'package:widgets/picker/option_pick_util.dart';
+
+import 'job_list_edit_state.dart';
+
+class JobListEditController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final JobListEditState state = JobListEditState();
+
+  // 获取添加选项数据
+  void fetchLabourRequestEditIndex() async {
+    var result = await _labourRepository.fetchJobListEditIndex(
+      state.jobId,
+      cancelToken: cancelToken,
+    );
+
+    if (result.isSuccess) {
+      state.editEntity = result.data;
+
+      TextEditingController maleNoController = state.formData['need_male']!['controller'];
+      TextEditingController femaleNoController = state.formData['need_female']!['controller'];
+      TextEditingController needNoController = state.formData['need_no']!['controller'];
+      TextEditingController remarkController = state.formData['remark']!['controller'];
+
+      //赋值展示
+      state.selectedOutlet = state.editEntity?.outletList.firstWhere((e) => e.selected == "selected", orElse: () => JobListEditIndexOption()).txt;
+      state.selectedOutletId = state.editEntity?.outletList.firstWhere((e) => e.selected == "selected", orElse: () => JobListEditIndexOption()).value;
+      state.genderOptionType = state.editEntity?.sexLimit ?? 0;
+      state.selectRequestTypeIndex = state.editEntity!.requestType.indexWhere((e) => e.checked == "checked");
+
+      //时间赋值
+      state.selectedStartTime = state.editEntity?.startTime == null ? null : DateTimeUtils.getDateTime(state.editEntity?.startTime ?? "");
+      state.selectedEndTime = state.editEntity?.endTime == null ? null : DateTimeUtils.getDateTime(state.editEntity?.endTime ?? "");
+
+      state.isOtherFormDisEnable = Utils.isEmpty(state.editEntity?.disabled);
+
+      maleNoController.text = state.editEntity?.maleLimit == 0 ? "" : state.editEntity?.maleLimit.toString() ?? "";
+      femaleNoController.text = state.editEntity?.femaleLimit == 0 ? "" : state.editEntity?.femaleLimit.toString() ?? "";
+      needNoController.text = state.editEntity?.needNum == 0 ? "" : state.editEntity?.needNum.toString() ?? "";
+      remarkController.text = state.editEntity?.remark ?? "";
+
+      update();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchLabourRequestEditIndex();
+  }
+
+  //选择开始时间
+  void pickStartTime() {
+    if (state.editEntity == null) {
+      return;
+    }
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedStartTime,
+      mode: CupertinoDatePickerMode.dateAndTime,
+      onDateTimeChanged: (date) {
+        state.selectedStartTime = date;
+        update();
+      },
+      title: "Start Time".tr,
+    );
+  }
+
+  // 选择结束时间
+  void pickEndTime() {
+    if (state.editEntity == null) {
+      return;
+    }
+
+    DatePickerUtil.showCupertinoDatePicker(
+      selectedDateTime: state.selectedEndTime ?? state.selectedStartTime,
+      mode: CupertinoDatePickerMode.dateAndTime,
+      onDateTimeChanged: (date) {
+        state.selectedEndTime = date;
+        update();
+      },
+      title: "End Time".tr,
+    );
+  }
+
+  //选择部门
+  void pickOutlet() {
+    if (state.editEntity == null) {
+      return;
+    }
+
+    int selectedIndex;
+    if (state.selectedOutletId == null) {
+      selectedIndex = 0;
+    } else {
+      selectedIndex = state.editEntity!.outletList.indexWhere((department) => department.value.toString() == state.selectedOutletId);
+    }
+
+    if (selectedIndex < 0) {
+      selectedIndex = 0;
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: state.editEntity!.outletList.map((e) => e.txt!).toList(growable: false),
+      initialSelectIndex: selectedIndex,
+      onPickerChanged: (_, index) {
+        state.selectedOutletId = state.editEntity!.outletList[index].value!.toString();
+        state.selectedOutlet = state.editEntity!.outletList[index].txt!.toString();
+        update();
+      },
+    );
+  }
+
+  // 提交表单
+  void doSubmit() async {
+    var maleNoController = state.formData['need_male']!['controller'];
+    var femaleNoController = state.formData['need_female']!['controller'];
+    var needNoController = state.formData['need_no']!['controller'];
+    var remarkController = state.formData['remark']!['controller'];
+
+    String maleNo = maleNoController.text.toString();
+    String femaleNo = femaleNoController.text.toString();
+    String needNo = needNoController.text.toString();
+    String remark = remarkController.text.toString();
+
+    if (state.selectedStartTime == null) {
+      ToastEngine.show("Select Job Start Time".tr);
+      return;
+    }
+
+    if (state.selectedEndTime == null) {
+      ToastEngine.show("Select Job End Time".tr);
+      return;
+    }
+
+    if (Utils.isEmpty(state.selectedOutletId)) {
+      ToastEngine.show("Choose Outlet".tr);
+      return;
+    }
+
+    if (state.genderOptionType == 0) {
+      if (Utils.isEmpty(needNo)) {
+        ToastEngine.show("Enter No. of Staff".tr);
+        return;
+      }
+    } else {
+      if (Utils.isEmpty(maleNo) || Utils.isEmpty(femaleNo)) {
+        ToastEngine.show("Enter No. of Staff of The Corresponding Gender".tr);
+        return;
+      }
+    }
+
+    var result = await _labourRepository.editJobListSubmit(
+      state.jobId,
+      DateTimeUtils.formatDate(state.selectedStartTime),
+      DateTimeUtils.formatDate(state.selectedEndTime),
+      state.selectedOutletId,
+      state.genderOptionType,
+      maleNo,
+      femaleNo,
+      needNo,
+      state.editEntity?.requestType[state.selectRequestTypeIndex].value,
+      remark,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //根据类型刷新
+      state.cb?.call(state.jobId);
+
+      Get.back();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+}

+ 434 - 0
packages/cpt_labour_sg/lib/modules/job_list_edit/job_list_edit_page.dart

@@ -0,0 +1,434 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/widgets.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/date_time_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/no_shadow_scroll_behavior.dart';
+import 'package:widgets/shatter/custom_radio_check.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/shatter/round_my_text_field.dart';
+import 'package:widgets/widget_export.dart';
+import 'job_list_edit_controller.dart';
+import 'package:plugin_basic/base/base_stateless_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+
+import 'job_list_edit_state.dart';
+
+/*
+ * 新加坡的工作详情,其实就是LabourRequest的详情和编辑
+ */
+class JobListEditPage extends BaseStatelessPage<JobListEditController> {
+  JobListEditPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(bool isEditType, String? jobId, void Function(dynamic value)? cb) {
+    return Get.start(RouterPath.jobListEditSG, arguments: {'isEditType': isEditType, 'jobId': jobId, 'cb': cb});
+  }
+
+  late JobListEditState state;
+
+  @override
+  void initState() {
+    state = controller.state;
+    state.isEditType = Get.arguments['isEditType'];
+    state.jobId = Get.arguments['jobId'];
+    state.cb = Get.arguments['cb'] as void Function(dynamic)?;
+  }
+
+  @override
+  JobListEditController createRawController() {
+    return JobListEditController();
+  }
+
+  @override
+  Widget buildWidget(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(context, state.isEditType ? "Edit".tr : "Detail".tr),
+        body: SafeArea(
+          bottom: true,
+          top: false,
+          child: Container(
+            width: double.infinity,
+            height: double.infinity,
+            padding: EdgeInsets.only(top: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1),
+            decoration: const BoxDecoration(
+              gradient: LinearGradient(
+                colors: [
+                  Color(0xFF091D44),
+                  Color(0xFF245A8A),
+                  Color(0xFF7F7CEC),
+                ],
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+              ),
+            ),
+            child: Scrollbar(
+              child: ScrollConfiguration(
+                behavior: NoShadowScrollBehavior(),
+                child: SingleChildScrollView(
+                  scrollDirection: Axis.vertical,
+                  physics: const BouncingScrollPhysics(),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      //工作标题,选择模板
+                      FormRequireText(
+                        text: "Job Title".tr,
+                      ).marginOnly(top: 15),
+
+                      //工作标题
+                      Container(
+                        padding: const EdgeInsets.only(left: 16, right: 10),
+                        margin: const EdgeInsets.only(top: 10),
+                        height: 45,
+                        decoration: BoxDecoration(
+                          color: const Color(0xFF4DCFF6).withOpacity(0.5),
+                          borderRadius: const BorderRadius.all(Radius.circular(5)),
+                        ),
+                        child: Row(
+                          mainAxisSize: MainAxisSize.max,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          mainAxisAlignment: MainAxisAlignment.start,
+                          children: [
+                            MyTextView(
+                              state.editEntity?.jobTitle ?? "",
+                              fontSize: 14,
+                              textHintColor: ColorConstants.textGrayAECAE5,
+                              isFontMedium: true,
+                              textColor: ColorConstants.white,
+                            ).expanded(),
+                          ],
+                        ),
+                      ),
+
+                      //选择工作时间
+                      FormRequireText(
+                        text: "Job Time".tr,
+                      ).marginOnly(top: 15),
+
+                      Row(
+                        mainAxisSize: MainAxisSize.max,
+                        crossAxisAlignment: CrossAxisAlignment.center,
+                        mainAxisAlignment: MainAxisAlignment.start,
+                        children: [
+                          //选择开始时间
+                          Expanded(
+                            child: Container(
+                              padding: const EdgeInsets.only(left: 16, right: 10),
+                              height: 45,
+                              decoration: BoxDecoration(
+                                color: const Color(0xFF4DCFF6).withOpacity(state.isEditType && state.isOtherFormDisEnable ? 0.2 : 0.5),
+                                borderRadius: const BorderRadius.all(Radius.circular(5)),
+                              ),
+                              child: Row(
+                                mainAxisSize: MainAxisSize.max,
+                                crossAxisAlignment: CrossAxisAlignment.center,
+                                mainAxisAlignment: MainAxisAlignment.start,
+                                children: [
+                                  MyTextView(
+                                    state.selectedStartTime == null ? "" : DateTimeUtils.formatDate(state.selectedStartTime, format: "yyyy-MM-dd HH:mm"),
+                                    fontSize: 14,
+                                    hint: "Job Start Time".tr,
+                                    textHintColor: ColorConstants.textGrayAECAE5,
+                                    isFontMedium: true,
+                                    textColor: ColorConstants.white,
+                                  ).expanded(),
+                                  //下拉选图标
+                                  Visibility(
+                                    visible: state.isEditType && state.isOtherFormDisEnable,
+                                    child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                                  ),
+                                ],
+                              ),
+                            ).onTap(() {
+                              if (state.isEditType && state.isOtherFormDisEnable) {
+                                FocusScope.of(context).unfocus();
+                                controller.pickStartTime();
+                              }
+                            }),
+                          ),
+
+                          // //选择结束时间
+                          Expanded(
+                            child: Container(
+                              padding: const EdgeInsets.only(left: 16, right: 10),
+                              margin: const EdgeInsets.only(left: 10),
+                              height: 45,
+                              decoration: BoxDecoration(
+                                color: const Color(0xFF4DCFF6).withOpacity(state.isEditType && state.isOtherFormDisEnable ? 0.2 : 0.5),
+                                borderRadius: const BorderRadius.all(Radius.circular(5)),
+                              ),
+                              child: Row(
+                                mainAxisSize: MainAxisSize.max,
+                                crossAxisAlignment: CrossAxisAlignment.center,
+                                mainAxisAlignment: MainAxisAlignment.start,
+                                children: [
+                                  MyTextView(
+                                    state.selectedEndTime == null ? "" : DateTimeUtils.formatDate(state.selectedEndTime, format: "yyyy-MM-dd HH:mm"),
+                                    fontSize: 14,
+                                    hint: "Job End Time".tr,
+                                    textHintColor: ColorConstants.textGrayAECAE5,
+                                    isFontMedium: true,
+                                    textColor: ColorConstants.white,
+                                  ).expanded(),
+                                  //下拉选图标
+                                  Visibility(
+                                    visible: state.isEditType && state.isOtherFormDisEnable,
+                                    child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                                  ),
+                                ],
+                              ),
+                            ).onTap(() {
+                              if (state.isEditType && state.isOtherFormDisEnable) {
+                                FocusScope.of(context).unfocus();
+                                controller.pickEndTime();
+                              }
+                            }),
+                          ),
+                        ],
+                      ).marginOnly(top: 10),
+
+                      //工作选择部门
+                      FormRequireText(
+                        text: "Outlet".tr,
+                      ).marginOnly(top: 15),
+
+                      //选择部门
+                      Container(
+                        padding: const EdgeInsets.only(left: 16, right: 10),
+                        margin: const EdgeInsets.only(top: 10),
+                        height: 45,
+                        decoration: BoxDecoration(
+                          color: const Color(0xFF4DCFF6).withOpacity(state.isEditType ? 0.2 : 0.5),
+                          borderRadius: const BorderRadius.all(Radius.circular(5)),
+                        ),
+                        child: Row(
+                          mainAxisSize: MainAxisSize.max,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          mainAxisAlignment: MainAxisAlignment.start,
+                          children: [
+                            MyTextView(
+                              state.selectedOutlet ?? "",
+                              fontSize: 14,
+                              hint: "Choose Outlet".tr,
+                              textHintColor: ColorConstants.textGrayAECAE5,
+                              isFontMedium: true,
+                              textColor: ColorConstants.white,
+                            ).expanded(),
+                            Visibility(
+                              visible: state.isEditType,
+                              child: const MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                            ),
+                          ],
+                        ),
+                      ).onTap(() {
+                        FocusScope.of(context).unfocus();
+                        controller.pickOutlet();
+                      }),
+
+                      //需要的人数
+                      FormRequireText(
+                        text: "No. of Staff".tr,
+                      ).marginOnly(top: 15),
+
+                      //选择人数类型单选
+                      CustomRadioCheck(
+                        options: state.editEntity?.limitList.map((e) => e.txt!).toList() ?? [],
+                        onOptionSelected: (index, text) {
+                          state.genderOptionType = index;
+                          controller.update();
+                        },
+                        enable: state.isEditType && state.isOtherFormDisEnable,
+                        selectedPosition: state.editEntity == null ? -1 : state.genderOptionType,
+                      ).marginOnly(top: 10),
+
+                      //输入框(只允许输入数字)
+                      Visibility(
+                        visible: state.genderOptionType == 0,
+                        child: CustomTextField(
+                          formKey: "need_no",
+                          marginLeft: 0,
+                          marginRight: 0,
+                          paddingTop: 0,
+                          paddingBottom: 0,
+                          height: 45,
+                          enabled: state.isEditType && state.isOtherFormDisEnable,
+                          fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(state.isEditType && state.isOtherFormDisEnable ? 0.2 : 0.5),
+                          inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
+                          textInputType: TextInputType.number,
+                          formData: state.formData,
+                          textInputAction: TextInputAction.done,
+                          onSubmit: (key, value) {
+                            FocusScope.of(context).unfocus();
+                          },
+                          marginTop: 10,
+                        ),
+                      ),
+
+                      Visibility(
+                        visible: state.genderOptionType != 0,
+                        child: Row(
+                          children: [
+                            MyTextView(
+                              "Male".tr,
+                              fontSize: 15,
+                              isFontRegular: true,
+                              marginRight: 10,
+                              textColor: ColorConstants.textGrayAECAE5,
+                            ),
+                            CustomTextField(
+                              formKey: "need_male",
+                              marginLeft: 0,
+                              marginRight: 0,
+                              paddingTop: 0,
+                              paddingBottom: 0,
+                              height: 45,
+                              enabled: state.isEditType && state.isOtherFormDisEnable,
+                              fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(state.isEditType && state.isOtherFormDisEnable ? 0.2 : 0.5),
+                              inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
+                              textInputType: TextInputType.number,
+                              formData: state.formData,
+                              textInputAction: TextInputAction.done,
+                              onSubmit: (key, value) {
+                                FocusScope.of(context).unfocus();
+                              },
+                            ).expanded(),
+                            MyTextView(
+                              "Female".tr,
+                              fontSize: 15,
+                              isFontRegular: true,
+                              marginLeft: 12,
+                              marginRight: 10,
+                              textColor: ColorConstants.textGrayAECAE5,
+                            ),
+                            CustomTextField(
+                              formKey: "need_female",
+                              marginLeft: 0,
+                              marginRight: 0,
+                              paddingTop: 0,
+                              paddingBottom: 0,
+                              height: 45,
+                              enabled: state.isEditType && state.isOtherFormDisEnable,
+                              fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(state.isEditType && state.isOtherFormDisEnable ? 0.2 : 0.5),
+                              inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
+                              textInputType: TextInputType.number,
+                              formData: state.formData,
+                              textInputAction: TextInputAction.done,
+                              onSubmit: (key, value) {
+                                FocusScope.of(context).unfocus();
+                              },
+                            ).expanded(),
+                          ],
+                        ).marginOnly(top: 10),
+                      ),
+
+                      //Request Type
+                      MyTextView(
+                        "Request Type".tr,
+                        fontSize: 15,
+                        isFontRegular: true,
+                        textColor: Colors.white,
+                        marginTop: 15,
+                      ),
+
+                      //Request Type单选
+                      CustomRadioCheck(
+                        options: state.editEntity?.requestType.map((e) => e.txt!).toList() ?? [],
+                        onOptionSelected: (index, text) {
+                          state.selectRequestTypeIndex = index;
+                        },
+                        enable: state.isEditType && state.isOtherFormDisEnable,
+                        selectedPosition: state.editEntity == null ? -1 : state.selectRequestTypeIndex,
+                      ).marginOnly(top: 10),
+
+                      //输入Remark
+                      MyTextView(
+                        "Remark".tr,
+                        fontSize: 15,
+                        isFontRegular: true,
+                        textColor: Colors.white,
+                        marginTop: 15,
+                      ),
+
+                      IgnoreKeyboardDismiss(
+                        child: Container(
+                          height: 160,
+                          margin: const EdgeInsets.only(top: 10),
+                          padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+                          decoration: BoxDecoration(
+                            color: const Color(0xFF4DCFF6).withOpacity(state.isEditType && state.isOtherFormDisEnable ? 0.2 : 0.5),
+                            borderRadius: const BorderRadius.all(Radius.circular(5)),
+                          ),
+                          child: TextField(
+                            cursorColor: ColorConstants.white,
+                            cursorWidth: 1.5,
+                            autofocus: false,
+                            enabled: state.isEditType && state.isOtherFormDisEnable,
+                            focusNode: state.formData["remark"]!['focusNode'],
+                            controller: state.formData["remark"]!['controller'],
+                            // 装饰
+                            decoration: InputDecoration(
+                              isDense: true,
+                              isCollapsed: true,
+                              border: InputBorder.none,
+                              hintText: state.formData["remark"]!['hintText'],
+                              hintStyle: const TextStyle(
+                                color: ColorConstants.textGrayAECAE5,
+                                fontSize: 15.0,
+                                fontWeight: FontWeight.w400,
+                              ),
+                            ),
+                            style: const TextStyle(
+                              color: ColorConstants.white,
+                              fontSize: 15.0,
+                              fontWeight: FontWeight.w400,
+                            ),
+                            // 键盘动作右下角图标
+                            textInputAction: TextInputAction.done,
+                            onSubmitted: (value) {
+                              FocusScope.of(context).unfocus();
+                            },
+                          ),
+                        ),
+                      ),
+
+                      //提交按钮
+                      Visibility(
+                          visible: state.isEditType,
+                          child: MyButton(
+                            type: ClickType.throttle,
+                            milliseconds: 500,
+                            onPressed: () {
+                              FocusScope.of(context).unfocus();
+                              controller.doSubmit();
+                            },
+                            text: "Submit".tr,
+                            textColor: ColorConstants.white,
+                            fontSize: 16,
+                            radius: 22.5,
+                            backgroundColor: hexToColor("#FFBB1B"),
+                            fontWeight: FontWeight.w500,
+                          )).marginSymmetric(horizontal: 0, vertical: 30),
+                    ],
+                  ).paddingOnly(left: 15, right: 15),
+                ),
+              ),
+            ),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 55 - 0
packages/cpt_labour_sg/lib/modules/job_list_edit/job_list_edit_state.dart

@@ -0,0 +1,55 @@
+import 'package:domain/entity/response/job_list_edit_index_s_g_entity.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+
+class JobListEditState {
+  //表单的校验与数据
+  Map<String, Map<String, dynamic>> formData = {
+    'need_male': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Needs Num'.tr,
+      'obsecure': false,
+    },
+    'need_female': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Needs Num'.tr,
+      'obsecure': false,
+    },
+    'need_no': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Needs Num'.tr,
+      'obsecure': false,
+    },
+    'remark': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+  };
+
+  bool isEditType = false;
+  String? jobId;
+  void Function(dynamic value)? cb;
+
+  int genderOptionType = 0;  //使用哪一种类型限制
+
+  JobListEditIndexSGEntity? editEntity;
+
+  bool isOtherFormDisEnable = true; //除了 OutLet 其他字段是否能修改
+
+  DateTime? selectedStartTime;
+  DateTime? selectedEndTime;
+
+  String? selectedOutlet;
+  String? selectedOutletId;
+
+  int selectRequestTypeIndex = 0;
+}

+ 131 - 0
packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_controller.dart

@@ -0,0 +1,131 @@
+import 'package:cpt_labour_sg/modules/job_template_list/add_edit_template.dart';
+import 'package:domain/entity/response/job_template_edit_index_entity.dart';
+import 'package:domain/repository/labour_sg_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
+
+import 'job_template_add_state.dart';
+
+class JobTemplateAddController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final JobTemplateAddState state = JobTemplateAddState();
+
+  // 获取添加或者编辑的详情
+  void _fetchAddEditIndexDetail() async {
+    //获取到数据
+    Future<HttpResult<JobTemplateEditIndexEntity>> taskFuture;
+    if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+      //编辑
+      taskFuture = _labourRepository.fetchJobTemplateEditIndex(state.templateId, cancelToken: cancelToken);
+    } else {
+      //新增
+      taskFuture = _labourRepository.fetchJobTemplateAddIndex(cancelToken: cancelToken);
+    }
+
+    var result = await taskFuture;
+
+    //处理数据
+    if (result.isSuccess) {
+      state.indexEntity = result.data;
+
+      var templateNameController = state.formData['template_name']!['controller'];
+      var descController = state.formData['desc']!['controller'];
+      var contactController = state.formData['contact']!['controller'];
+      var contactNoController = state.formData['contact_no']!['controller'];
+      var noteController = state.formData['note']!['controller'];
+      templateNameController.text = state.indexEntity?.name ?? "";
+      descController.text = state.indexEntity?.description ?? "";
+      contactController.text = state.indexEntity?.contact ?? "";
+      contactNoController.text = state.indexEntity?.contactNo ?? "";
+      noteController.text = state.indexEntity?.note ?? "";
+
+      //默认赋值
+      state.selectedAgeList = state.indexEntity?.ageList.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
+      Log.d("当前选中的年龄1:${ state.selectedAgeList}");
+      state.selectedLanguageList = state.indexEntity?.languageList.where((e) => e.checked == "checked").map((e) => e.value!).toList() ?? [];
+      Log.d("当前选中的语言1:${ state.selectedLanguageList}");
+      state.foodCert = state.indexEntity?.withFoodCert.toString();
+      state.gender = state.indexEntity?.sexList.firstWhere((e) => e.checked == "checked").value;
+
+      update();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  /// 提交
+  void doSubmit() async {
+    var templateNameController = state.formData['template_name']!['controller'];
+    var descController = state.formData['desc']!['controller'];
+    var contactController = state.formData['contact']!['controller'];
+    var contactNoController = state.formData['contact_no']!['controller'];
+    var noteController = state.formData['note']!['controller'];
+
+    String templateName = templateNameController.text.toString();
+    String desc = descController.text.toString();
+    String contact = contactController.text.toString();
+    String contactNo = contactNoController.text.toString();
+    String note = noteController.text.toString();
+
+    //只校验模版的名称
+    if (Utils.isEmpty(templateName)) {
+      ToastEngine.show("Enter Job Template Name".tr);
+      return;
+    }
+
+    Future<HttpResult> taskFuture;
+    if (Utils.isNotEmpty(state.templateId) && state.templateId != "0") {
+      taskFuture = _labourRepository.editJobTemplateSubmit(
+        state.templateId,
+        templateName,
+        contact,
+        contactNo,
+        desc,
+        note,
+        state.selectedAgeList.join(","),
+        state.gender,
+        state.foodCert,
+        state.selectedLanguageList.join(","),
+        cancelToken: cancelToken,
+      );
+    } else {
+      taskFuture = _labourRepository.addJobTemplateSubmit(
+        templateName,
+        contact,
+        contactNo,
+        desc,
+        note,
+        state.selectedAgeList.join(","),
+        state.gender,
+        state.foodCert,
+        state.selectedLanguageList.join(","),
+        cancelToken: cancelToken,
+      );
+    }
+
+    var result = await taskFuture;
+
+    //处理数据
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      //根据类型刷新
+      state.cb?.call(state.templateId);
+
+      Get.back();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    _fetchAddEditIndexDetail();
+  }
+}

+ 367 - 0
packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_page.dart

@@ -0,0 +1,367 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/screen_util.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_appbar.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/no_shadow_scroll_behavior.dart';
+import 'package:widgets/shatter/custom_check_box.dart';
+import 'package:widgets/shatter/custom_radio_check.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/shatter/round_my_text_field.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'job_template_add_controller.dart';
+
+import 'package:plugin_basic/base/base_stateless_page.dart';
+import 'package:plugin_basic/utils/ext_get_nav.dart';
+import 'package:router/path/router_path.dart';
+
+import 'job_template_add_state.dart';
+
+/**
+ * 模板的添加与编辑
+ */
+class JobTemplateAddPage extends BaseStatelessPage<JobTemplateAddController> {
+  JobTemplateAddPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance(
+    String templateId,
+    void Function(dynamic value)? cb,
+  ) {
+    return Get.start(RouterPath.jobTemplateAddSG, arguments: {'templateId': templateId, 'cb': cb});
+  }
+
+  late JobTemplateAddState state;
+
+  @override
+  void initState() {
+    state = controller.state;
+    state.templateId = Get.arguments['templateId'];
+    state.cb = Get.arguments['cb'] as void Function(dynamic)?;
+  }
+
+  @override
+  JobTemplateAddController createRawController() {
+    return JobTemplateAddController();
+  }
+
+  @override
+  Widget buildWidget(BuildContext context) {
+    return autoCtlGetBuilder(builder: (controller) {
+      return Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: MyAppBar.appBar(context, Utils.isEmpty(state.templateId) ? "Create Template".tr : "Edit Template".tr),
+        body: SafeArea(
+          bottom: true,
+          top: false,
+          child: Container(
+            width: double.infinity,
+            height: double.infinity,
+            padding: EdgeInsets.only(top: kToolbarHeight + ScreenUtil.getStatusBarH(context) + 1),
+            decoration: const BoxDecoration(
+              gradient: LinearGradient(
+                colors: [
+                  Color(0xFF091D44),
+                  Color(0xFF245A8A),
+                  Color(0xFF7F7CEC),
+                ],
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+              ),
+            ),
+            child: Scrollbar(
+              child: ScrollConfiguration(
+                behavior: NoShadowScrollBehavior(),
+                child: SingleChildScrollView(
+                  scrollDirection: Axis.vertical,
+                  physics: const BouncingScrollPhysics(),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      //模板名称
+                      FormRequireText(text: "Template Name".tr).marginOnly(left: 15, top: 19),
+
+                      CustomTextField(
+                        formKey: "template_name",
+                        formData: state.formData,
+                        height: 46,
+                        fontSize: 14,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['desc']!['focusNode']);
+                        },
+                        marginTop: 10,
+                      ),
+
+                      //年龄
+                      MyTextView(
+                        "Age".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 15,
+                      ),
+
+                      // 年龄的多选
+                      CustomCheckBox(
+                        options: state.indexEntity?.ageList.map((e) => e.txt!).toList() ?? [],
+                        onOptionsSelected: (selected) {
+                          // 转换选中的索引为对应的 value
+                          state.selectedAgeList = selected
+                              .map((index) {
+                                return state.indexEntity?.ageList[index].value; // 获取对应的 value
+                              })
+                              .whereType<String>()
+                              .toList();
+                        },
+                        selectedOptions: state.indexEntity?.ageList.where((e) => e.checked == "checked").map((e) => e.txt!).toList() ?? [],
+                      ).marginOnly(left: 15, right: 15, top: 10),
+
+                      //性别
+                      MyTextView(
+                        "Gender".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 15,
+                      ),
+
+                      //性别单选
+                      CustomRadioCheck(
+                        options: state.indexEntity?.sexList.map((e) => e.txt!).toList() ?? [],
+                        onOptionSelected: (index, text) {
+                          state.gender = state.indexEntity!.sexList[index].value;
+                        },
+                        selectedPosition: state.indexEntity?.sexList.indexWhere((e) => e.checked == "checked") ?? -1,
+                      ).marginOnly(left: 15, right: 15, top: 10),
+
+                      //语言
+                      MyTextView(
+                        "Preferred Language".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 15,
+                      ),
+
+                      // 语言的多选
+                      CustomCheckBox(
+                        options: state.indexEntity?.languageList.map((e) => e.txt!).toList() ?? [],
+                        onOptionsSelected: (selected) {
+                          // 转换选中的索引为对应的 value
+                          state.selectedLanguageList = selected
+                              .map((index) {
+                                return state.indexEntity?.languageList[index].value; // 获取对应的 value
+                              })
+                              .whereType<String>()
+                              .toList();
+                        },
+                        selectedOptions: state.indexEntity?.languageList.where((e) => e.checked == "checked").map((e) => e.txt!).toList() ?? [],
+                      ).marginOnly(left: 15, right: 15, top: 10),
+
+                      //食品安全证书
+                      MyTextView(
+                        "Food Hygiene Cert".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 15,
+                      ),
+
+                      //食品安全证书单选
+                      CustomRadioCheck(
+                        options: state.indexEntity?.withFoodCert != null ? state.foodHygieneCertOption : [],
+                        onOptionSelected: (index, text) {
+                          state.foodCert = index == 0 ? "1" : "0";
+                        },
+                        selectedPosition: state.indexEntity?.withFoodCert != null
+                            ? state.indexEntity?.withFoodCert == 0 ? 1 : 0 : -1,
+                      ).marginOnly(left: 15, right: 15, top: 10),
+
+                      //模板详情
+                      MyTextView(
+                        "Description".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 15,
+                      ),
+
+                      IgnoreKeyboardDismiss(
+                        child: Container(
+                          height: 130,
+                          margin: const EdgeInsets.only(left: 15, right: 15, top: 10),
+                          padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+                          decoration: BoxDecoration(
+                            color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                            borderRadius: const BorderRadius.all(Radius.circular(5)),
+                          ),
+                          child: TextField(
+                            cursorColor: ColorConstants.white,
+                            cursorWidth: 1.5,
+                            autofocus: false,
+                            enabled: true,
+                            focusNode: state.formData["desc"]!['focusNode'],
+                            controller: state.formData["desc"]!['controller'],
+                            // 装饰
+                            decoration: InputDecoration(
+                              isDense: true,
+                              isCollapsed: true,
+                              border: InputBorder.none,
+                              hintText: state.formData["desc"]!['hintText'],
+                              hintStyle: const TextStyle(
+                                color: ColorConstants.textGrayAECAE5,
+                                fontSize: 15.0,
+                                fontWeight: FontWeight.w400,
+                              ),
+                            ),
+                            style: const TextStyle(
+                              color: ColorConstants.white,
+                              fontSize: 15.0,
+                              fontWeight: FontWeight.w400,
+                            ),
+                            // 键盘动作右下角图标
+                            textInputAction: TextInputAction.next,
+                            onSubmitted: (value) {
+                              state.formData[key]!['focusNode'].unfocus();
+                              FocusScope.of(context).requestFocus(state.formData['contact']!['focusNode']);
+                            },
+                          ),
+                        ),
+                      ),
+
+                      //联系人
+                      MyTextView(
+                        "Contact".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 15,
+                      ),
+
+                      CustomTextField(
+                        formKey: "contact",
+                        formData: state.formData,
+                        height: 46,
+                        fontSize: 14,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['contact_no']!['focusNode']);
+                        },
+                        marginTop: 10,
+                      ),
+
+                      //联系人电话
+                      MyTextView(
+                        "Contact No".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 18,
+                      ),
+
+                      CustomTextField(
+                        formKey: "contact_no",
+                        formData: state.formData,
+                        fontSize: 14,
+                        height: 46,
+                        textInputType: TextInputType.phone,
+                        onSubmit: (key, value) {
+                          state.formData[key]!['focusNode'].unfocus();
+                          FocusScope.of(context).requestFocus(state.formData['note']!['focusNode']);
+                        },
+                        marginTop: 10,
+                      ),
+
+                      //备注
+                      MyTextView(
+                        "Note".tr,
+                        textColor: Colors.white,
+                        fontSize: 14,
+                        isFontRegular: true,
+                        marginLeft: 15,
+                        marginTop: 18,
+                      ),
+
+                      IgnoreKeyboardDismiss(
+                        child: Container(
+                          height: 130,
+                          margin: const EdgeInsets.only(left: 15, right: 15, top: 10),
+                          padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+                          decoration: BoxDecoration(
+                            color: const Color(0xFF4DCFF6).withOpacity(0.2),
+                            borderRadius: const BorderRadius.all(Radius.circular(5)),
+                          ),
+                          child: TextField(
+                            cursorColor: ColorConstants.white,
+                            cursorWidth: 1.5,
+                            autofocus: false,
+                            enabled: true,
+                            focusNode: state.formData["note"]!['focusNode'],
+                            controller: state.formData["note"]!['controller'],
+                            // 装饰
+                            decoration: InputDecoration(
+                              isDense: true,
+                              isCollapsed: true,
+                              border: InputBorder.none,
+                              hintText: state.formData["note"]!['hintText'],
+                              hintStyle: const TextStyle(
+                                color: ColorConstants.textGrayAECAE5,
+                                fontSize: 14.0,
+                                fontWeight: FontWeight.w400,
+                              ),
+                            ),
+                            style: const TextStyle(
+                              color: ColorConstants.white,
+                              fontSize: 14.0,
+                              fontWeight: FontWeight.w400,
+                            ),
+                            // 键盘动作右下角图标
+                            textInputAction: TextInputAction.next,
+                            onSubmitted: (value) {
+                              state.formData[key]!['focusNode'].unfocus();
+                              FocusScope.of(context).requestFocus(state.formData['contact']!['focusNode']);
+                            },
+                          ),
+                        ),
+                      ),
+
+                      //提交按钮
+                      MyButton(
+                        type: ClickType.throttle,
+                        milliseconds: 500,
+                        onPressed: () {
+                          FocusScope.of(context).unfocus();
+                          controller.doSubmit();
+                        },
+                        text: "Submit".tr,
+                        textColor: ColorConstants.white,
+                        fontSize: 16,
+                        radius: 20,
+                        backgroundColor: ColorConstants.textYellowFFBB1B,
+                        fontWeight: FontWeight.w500,
+                      ).marginSymmetric(vertical: 25, horizontal: 15),
+                    ],
+                  ),
+                ),
+              ),
+            ).expanded(),
+          ),
+        ),
+      );
+    });
+  }
+}

+ 60 - 0
packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_state.dart

@@ -0,0 +1,60 @@
+import 'package:domain/entity/response/job_template_edit_index_entity.dart';
+import 'package:domain/entity/response/job_template_s_g_entity.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+
+class JobTemplateAddState {
+  //表单的校验与数据
+  Map<String, Map<String, dynamic>> formData = {
+    'template_name': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'desc': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'contact': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'contact_no': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+    'note': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
+  };
+
+
+  final foodHygieneCertOption = ["Yes".tr, "No".tr];
+
+  String templateId = "";
+  void Function(dynamic value)? cb;
+
+  JobTemplateEditIndexEntity? indexEntity;  //新增或者编辑的详情
+
+
+  List<String> selectedAgeList = [];   //选中的 age 的 id
+  List<String> selectedLanguageList = [];   //选中的 language 的 id
+  String? gender;
+  String? foodCert;
+
+}

+ 7 - 0
packages/cpt_labour_sg/lib/modules/job_template_list/add_edit_template.dart

@@ -0,0 +1,7 @@
+//编辑和新增页面返回的对象
+class AddEditTemplate{
+   bool isEdit = false;
+   String? templateId;
+
+   AddEditTemplate(this.isEdit, this.templateId);
+}

+ 193 - 0
packages/cpt_labour_sg/lib/modules/job_template_list/job_template_item.dart

@@ -0,0 +1,193 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:domain/entity/response/job_template_s_g_entity.dart';
+import 'package:domain/entity/response/job_title_s_g_entity.dart';
+import 'package:domain/entity/response/labour_request_list_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_button.dart';
+import 'package:widgets/my_text_view.dart';
+
+/**
+ * 用工请求的主页面列表Item
+ */
+class JobTemplateItem extends StatelessWidget {
+  final int index;
+  final JobTemplateSGRows item;
+  final VoidCallback? onDeleteAction;
+  final VoidCallback? onEditAction;
+
+  JobTemplateItem({
+    required this.index,
+    required this.item,
+    this.onDeleteAction,
+    this.onEditAction,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      padding: EdgeInsets.symmetric(vertical: 23, horizontal: 21),
+      margin: EdgeInsets.only(left: 15, right: 15, top: 5, bottom: 5),
+      decoration: BoxDecoration(
+        color: Color(0xFF4DCFF6).withOpacity(0.2), // 设置背景颜色和不透明度
+        borderRadius: BorderRadius.circular(5), // 设置圆角
+      ),
+      child: Column(
+        mainAxisSize: MainAxisSize.max,
+        crossAxisAlignment: CrossAxisAlignment.start,
+        children: [
+          // 标题
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Template Name".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.name ?? "-",
+                marginLeft: 5,
+                isFontMedium: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ),
+
+          // 联系人
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Contact".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.contact ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 14),
+
+          // 创建时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Created At:".tr,
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+
+              //状态
+              MyTextView(
+                item.createdAt ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 14),
+
+          // 更新时间
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Updated At".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.updatedAt ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 14),
+
+          MyTextView(
+            "Note".tr + ":",
+            isFontRegular: true,
+            marginTop: 14,
+            textColor: ColorConstants.textGrayAECAE5,
+            fontSize: 14,
+          ),
+
+          MyTextView(
+            item.note ?? "",
+            marginTop: 13,
+            isFontRegular: true,
+            textColor: Colors.white,
+            fontSize: 14,
+          ),
+
+          //按钮组
+          Visibility(
+            visible: item.actionList.isNotEmpty,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                //编辑按钮
+                Visibility(
+                  visible: item.actionList.contains("edit"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onEditAction?.call();
+                    },
+                    text: "Edit".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textGreen0AC074,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //删除按钮
+                Visibility(
+                  visible: item.actionList.contains("delete"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDeleteAction?.call();
+                    },
+                    text: "Delete".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textRedFF6262,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+              ],
+            ).marginOnly(top: 18, bottom: 2),
+
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 218 - 0
packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_controller.dart

@@ -0,0 +1,218 @@
+import 'package:domain/entity/response/job_template_s_g_entity.dart';
+import 'package:domain/repository/labour_sg_repository.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
+import 'package:plugin_platform/engine/notify/notify_engine.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../job_template_add/job_template_add_page.dart';
+import 'add_edit_template.dart';
+import 'job_template_list_state.dart';
+
+class JobTemplateListController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final JobTemplateListState state = JobTemplateListState();
+
+  var _curPage = 1;
+  var _needShowPlaceholder = true;
+
+  //页面PlaceHolder的展示
+  LoadState loadingState = LoadState.State_Success;
+  String? errorMessage;
+
+  //刷新页面状态
+  void changeLoadingState(LoadState state) {
+    loadingState = state;
+    update();
+  }
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,
+    controlFinishLoad: true,
+  );
+
+  // Refresh 刷新事件
+  Future onRefresh() async {
+    _curPage = 1;
+    fetchNotifyList();
+  }
+
+  // Refresh 加载事件
+  Future loadMore() async {
+    _curPage++;
+    fetchNotifyList();
+  }
+
+  // 重试请求
+  Future retryRequest() async {
+    _curPage = 1;
+    _needShowPlaceholder = true;
+    fetchNotifyList();
+  }
+
+  /// 获取服务器数据,通知消息列表
+  Future fetchNotifyList() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading);
+    }
+
+    var listResult = await _labourRepository.fetchJobTemplateList(state.keyword, curPage: _curPage, cancelToken: cancelToken);
+
+    // 处理数据
+    if (listResult.isSuccess) {
+      handleList(listResult.data?.rows);
+    } else {
+      errorMessage = listResult.errorMsg;
+      changeLoadingState(LoadState.State_Error);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
+  }
+
+  // 处理数据与展示的逻辑
+  void handleList(List<JobTemplateSGRows>? list) {
+    if (list != null && list.isNotEmpty) {
+      //有数据,判断是刷新还是加载更多的数据
+      if (_curPage == 1) {
+        //刷新的方式
+        state.datas.clear();
+        state.datas.addAll(list);
+        refreshController.finishRefresh();
+
+        //更新展示的状态
+        changeLoadingState(LoadState.State_Success);
+      } else {
+        //加载更多
+        state.datas.addAll(list);
+        refreshController.finishLoad();
+        update();
+      }
+    } else {
+      if (_curPage == 1) {
+        //展示无数据的布局
+        state.datas.clear();
+        changeLoadingState(LoadState.State_Empty);
+        refreshController.finishRefresh();
+      } else {
+        //展示加载完成,没有更多数据了
+        refreshController.finishLoad(IndicatorResult.noMore);
+      }
+    }
+  }
+
+  // 执行搜索
+  void doSearch(String keyword) {
+    state.keyword = keyword;
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  // 清空搜索条件
+  void resetFiltering() {
+    state.keyword = "";
+    state.searchController.text = "";
+
+    //赋值之后刷新
+    refreshController.callRefresh();
+  }
+
+  @override
+  void onReady() {
+    super.onReady();
+    fetchNotifyList();
+  }
+
+  @override
+  void onClose() {
+    state.datas.clear();
+    super.onClose();
+  }
+
+  //去添加模板的页面
+  void gotoTemplateAddPage() {
+    JobTemplateAddPage.startInstance("", (result) {
+      if (result is String) {
+        refreshController.callRefresh();
+      }
+    });
+  }
+
+  //去编辑的页面
+  void gotoEditPage(String templateId) {
+    JobTemplateAddPage.startInstance(templateId, (result) {
+      if (result is String) {
+        fetchItemByIdAndRefreshItem(templateId);
+      }
+    });
+  }
+
+  //删除工作模板
+  void deleteJobTitle(int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+      title: "Confirmation".tr,
+      message: "Are you sure you want to delete this job template?".tr,
+      confirmAction: () {
+        _requestDeactivate(index);
+      },
+    ));
+  }
+
+  // 请求接口删除JobTitle
+  void _requestDeactivate(int index) async {
+    final item = state.datas[index];
+    var result = await _labourRepository.deleteJobTemplateSubmit(item.id.toString(), cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      if (state.datas.length <= 1) {
+        refreshController.callRefresh();
+      } else {
+        state.datas.removeAt(index);
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  /// 根据ID获取Item对象,用于刷新
+  void fetchItemByIdAndRefreshItem(String ids) async {
+    var result = await _labourRepository.fetchJobTemplateListByIds(
+      ids,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      var data = result.data;
+      if (data != null && data.rows.isNotEmpty) {
+        List<JobTemplateSGRows> newItem = data.rows;
+
+        // 创建一个 Map 来加速查找
+        Map<int, JobTemplateSGRows> newItemMap = {for (var item in newItem) item.id: item};
+
+        // 遍历 state.datas 进行替换
+        for (int i = 0; i < state.datas.length; i++) {
+          if (newItemMap.containsKey(state.datas[i].id)) {
+            state.datas[i] = newItemMap[state.datas[i].id]!;
+          }
+        }
+
+        //刷新
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+}

+ 0 - 0
packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_page.dart


Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.