Browse Source

新加坡的工作标题与模板的框架搭建

liukai 7 months ago
parent
commit
f2fb2f49d0
53 changed files with 2725 additions and 13 deletions
  1. 9 1
      app/lib/main.dart
  2. 6 0
      app/pubspec.yaml
  3. 2 0
      melos.yaml
  4. 1 1
      packages/cpt_auth/lib/modules/main/main_controller.dart
  5. 1 0
      packages/cpt_job/lib/modules/job_applied/job_applied_controller.dart
  6. 1 1
      packages/cpt_job/pubspec.yaml
  7. 31 0
      packages/cpt_job_sg/.gitignore
  8. 0 0
      packages/cpt_job_sg/lib/modules/abc
  9. 7 0
      packages/cpt_job_sg/lib/modules/job_list_sg/job_list_sg_controller.dart
  10. 16 0
      packages/cpt_job_sg/lib/modules/job_list_sg/job_list_sg_page.dart
  11. 5 0
      packages/cpt_job_sg/lib/modules/job_list_sg/job_list_sg_state.dart
  12. 28 0
      packages/cpt_job_sg/lib/router/job_sg_service_impl.dart
  13. 17 0
      packages/cpt_job_sg/lib/router/page_router.dart
  14. 40 0
      packages/cpt_job_sg/pubspec.yaml
  15. 16 0
      packages/cpt_job_sg/pubspec_overrides.yaml
  16. 1 1
      packages/cpt_labour/pubspec.yaml
  17. 31 0
      packages/cpt_labour_sg/.gitignore
  18. 7 0
      packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_controller.dart
  19. 19 0
      packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_page.dart
  20. 5 0
      packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_state.dart
  21. 7 0
      packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_controller.dart
  22. 16 0
      packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_page.dart
  23. 5 0
      packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_state.dart
  24. 310 0
      packages/cpt_labour_sg/lib/modules/job_title_list/job_title_add_dialog.dart
  25. 232 0
      packages/cpt_labour_sg/lib/modules/job_title_list/job_title_item.dart
  26. 218 0
      packages/cpt_labour_sg/lib/modules/job_title_list/job_title_list_controller.dart
  27. 167 0
      packages/cpt_labour_sg/lib/modules/job_title_list/job_title_list_page.dart
  28. 15 0
      packages/cpt_labour_sg/lib/modules/job_title_list/job_title_list_state.dart
  29. 26 0
      packages/cpt_labour_sg/lib/router/labour_sg_service_impl.dart
  30. 33 0
      packages/cpt_labour_sg/lib/router/page_router.dart
  31. 40 0
      packages/cpt_labour_sg/pubspec.yaml
  32. 16 0
      packages/cpt_labour_sg/pubspec_overrides.yaml
  33. 39 3
      packages/cs_domain/lib/constants/api_constants.dart
  34. 89 0
      packages/cs_domain/lib/entity/response/job_template_edit_index_entity.dart
  35. 46 0
      packages/cs_domain/lib/entity/response/job_template_s_g_entity.dart
  36. 43 0
      packages/cs_domain/lib/entity/response/job_title_edit_index_entity.dart
  37. 46 0
      packages/cs_domain/lib/entity/response/job_title_s_g_entity.dart
  38. 44 0
      packages/cs_domain/lib/generated/json/base/json_convert_content.dart
  39. 206 0
      packages/cs_domain/lib/generated/json/job_template_edit_index_entity.g.dart
  40. 100 0
      packages/cs_domain/lib/generated/json/job_template_s_g_entity.g.dart
  41. 86 0
      packages/cs_domain/lib/generated/json/job_title_edit_index_entity.g.dart
  42. 93 0
      packages/cs_domain/lib/generated/json/job_title_s_g_entity.g.dart
  43. 33 0
      packages/cs_domain/lib/repository/job_sg_repository.dart
  44. 506 0
      packages/cs_domain/lib/repository/labour_sg_repository.dart
  45. 4 0
      packages/cs_initializer/lib/global_services_injection.dart
  46. 1 0
      packages/cs_resources/lib/constants/color_constants.dart
  47. 6 0
      packages/cs_resources/lib/local/language/en_US.dart
  48. 6 0
      packages/cs_resources/lib/local/language/vi_VN.dart
  49. 6 0
      packages/cs_resources/lib/local/language/zh_CN.dart
  50. 9 0
      packages/cs_router/lib/componentRouter/component_router_service.dart
  51. 11 0
      packages/cs_router/lib/componentRouter/job_sg_service.dart
  52. 11 0
      packages/cs_router/lib/componentRouter/labour_sg_service.dart
  53. 12 6
      packages/cs_router/lib/path/router_path.dart

+ 9 - 1
app/lib/main.dart

@@ -2,8 +2,12 @@ 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';
@@ -14,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';
@@ -41,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());
@@ -118,7 +126,7 @@ class MyApp extends StatelessWidget {
           //默认路由与路由表的加载
           initialRoute: RouterPath.SPLASH,
           getPages: PageRouter.routes + BasicPageRouter.routes + AuthPageRouter.routes + JobPageRouter.routes + LabourPageRouter.routes +
-              ReportPageRouter.routes,
+              ReportPageRouter.routes + LabourSGPageRouter.routes + JobPageSGRouter.routes,
           //对原生导航的兼容;SmartDialog路由配置生命周期处理
           navigatorObservers: [GetXRouterObserver(), FlutterSmartDialog.observer, routeObserver],
           //默认页面动画

+ 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/"
 
 

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

@@ -155,7 +155,7 @@ class MainController extends GetxController {
         break;
       case 'jobTitle':
         //新加坡的用工请求
-        ToastEngine.show("进入新加坡的 Default Job Title 模块");
+        ComponentRouterServices.labourSGService.startJobTitlePage();
         break;
       case 'report':
         ToastEngine.show("进入 Report 模块");

+ 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/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

+ 0 - 0
packages/cpt_job_sg/lib/modules/abc


+ 7 - 0
packages/cpt_job_sg/lib/modules/job_list_sg/job_list_sg_controller.dart

@@ -0,0 +1,7 @@
+import 'package:get/get.dart';
+
+import 'job_list_sg_state.dart';
+
+class JobListSgController extends GetxController {
+  final JobListSgState state = JobListSgState();
+}

+ 16 - 0
packages/cpt_job_sg/lib/modules/job_list_sg/job_list_sg_page.dart

@@ -0,0 +1,16 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import 'job_list_sg_controller.dart';
+
+class JobListSgPage extends StatelessWidget {
+  JobListSgPage({Key? key}) : super(key: key);
+
+  final controller = Get.put(JobListSgController());
+  final state = Get.find<JobListSgController>().state;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}

+ 5 - 0
packages/cpt_job_sg/lib/modules/job_list_sg/job_list_sg_state.dart

@@ -0,0 +1,5 @@
+class JobListSgState {
+  JobListSgState() {
+    ///Initialize variables
+  }
+}

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

@@ -0,0 +1,28 @@
+import 'package:plugin_basic/basic_export.dart';
+import 'package:router/componentRouter/job_sg_service.dart';
+import 'package:shared/utils/log_utils.dart';
+
+class JobSGServiceImpl extends GetxService implements JobSGService {
+  @override
+  void onInit() {
+    super.onInit();
+    //初始化资源
+  }
+
+  @override
+  void onClose() {
+    super.onClose();
+    //销毁资源
+  }
+
+  @override
+  void startJobListPage() {
+
+  }
+
+  @override
+  void startReviseListPage() {
+
+  }
+
+}

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

@@ -0,0 +1,17 @@
+
+import 'package:cpt_job_sg/modules/job_list_sg/job_list_sg_page.dart';
+import 'package:get/get.dart';
+import 'package:router/path/router_path.dart';
+
+
+class JobPageSGRouter {
+  static final routes = [
+
+    // 工作列表 (新加坡)
+    GetPage(
+      name: RouterPath.JOB_LIST_SG,
+      page: () => JobListSgPage(),
+    ),
+
+  ];
+}

+ 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/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

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

@@ -0,0 +1,7 @@
+import 'package:get/get.dart';
+
+import 'job_template_add_state.dart';
+
+class JobTemplateAddController extends GetxController {
+  final JobTemplateAddState state = JobTemplateAddState();
+}

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

@@ -0,0 +1,19 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import 'job_template_add_controller.dart';
+
+/**
+ * 模板的添加与编辑页面
+ */
+class JobTemplateAddPage extends StatelessWidget {
+  JobTemplateAddPage({Key? key}) : super(key: key);
+
+  final controller = Get.put(JobTemplateAddController());
+  final state = Get.find<JobTemplateAddController>().state;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}

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

@@ -0,0 +1,5 @@
+class JobTemplateAddState {
+  JobTemplateAddState() {
+    ///Initialize variables
+  }
+}

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

@@ -0,0 +1,7 @@
+import 'package:get/get.dart';
+
+import 'job_template_list_state.dart';
+
+class JobTemplateListController extends GetxController {
+  final JobTemplateListState state = JobTemplateListState();
+}

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

@@ -0,0 +1,16 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import 'job_template_list_controller.dart';
+
+class JobTemplateListPage extends StatelessWidget {
+  JobTemplateListPage({Key? key}) : super(key: key);
+
+  final controller = Get.put(JobTemplateListController());
+  final state = Get.find<JobTemplateListController>().state;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container();
+  }
+}

+ 5 - 0
packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_state.dart

@@ -0,0 +1,5 @@
+class JobTemplateListState {
+  JobTemplateListState() {
+    ///Initialize variables
+  }
+}

+ 310 - 0
packages/cpt_labour_sg/lib/modules/job_title_list/job_title_add_dialog.dart

@@ -0,0 +1,310 @@
+import 'dart:typed_data';
+import 'dart:ui';
+
+import 'package:cs_resources/generated/assets.dart';
+import 'package:domain/entity/response/job_title_edit_index_entity.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:plugin_basic/service/app_config_service.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_load_image.dart';
+import 'package:widgets/my_text_field.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:widgets/picker/option_pick_util.dart';
+import 'package:widgets/shatter/form_require_text.dart';
+import 'package:widgets/widget_export.dart';
+
+/**
+ * 添加工作标题的弹窗
+ */
+class AddJobTitleDialog extends StatefulWidget {
+  JobTitleEditIndexEntity? editIndexEntity;
+
+  void Function(String jobTitle, String templateId, String sort)? confirmAction;
+
+  AddJobTitleDialog({this.editIndexEntity, this.confirmAction});
+
+  @override
+  State<AddJobTitleDialog> createState() => _AddJobTitleDialogState();
+}
+
+class _AddJobTitleDialogState extends State<AddJobTitleDialog> {
+  String? jobTitle;
+  JobTitleEditIndexTemplate? template;
+  String? sort;
+  late TextEditingController jobTitleController;
+  late FocusNode jobTitleFocusNode;
+  late TextEditingController sortController;
+  late FocusNode sortFocusNode;
+
+  @override
+  void initState() {
+    super.initState();
+    jobTitle = widget.editIndexEntity?.jobTitle;
+    template = widget.editIndexEntity?.template.firstWhere((element) => element?.selected == 'selected', orElse: () => null);
+    sort = widget.editIndexEntity?.sort.toString();
+    jobTitleController = TextEditingController();
+    jobTitleFocusNode = FocusNode();
+    sortController = TextEditingController();
+    sortFocusNode = FocusNode();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Padding(
+      padding: EdgeInsets.only(
+        bottom: ConfigService.to.isFullScreenDevice ? MediaQuery.of(context).viewInsets.bottom : 0, //小屏手机不移动
+      ), // 在底部加上键盘高度
+      child: 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(
+                    "Add New".tr,
+                    fontSize: 19,
+                    isFontMedium: true,
+                    textColor: ColorConstants.black,
+                    marginTop: 22,
+                    marginBottom: 20,
+                  ),
+                ),
+
+                // 输入工作标题
+                FormRequireText(
+                  fontSize: 14,
+                  textColor: ColorConstants.black33,
+                  fontWeight: FontWeight.w400,
+                  text: "Job Title".tr,
+                ),
+
+                IgnoreKeyboardDismiss(
+                  child: MyTextField(
+                    "job_title",
+                    jobTitle ?? "",
+                    hintText: "Enter...".tr,
+                    hintStyle: TextStyle(
+                      color: ColorConstants.gray88,
+                      fontSize: 14,
+                      fontWeight: FontWeight.w400,
+                    ),
+                    controller: jobTitleController,
+                    focusNode: jobTitleFocusNode,
+                    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: 45,
+                    style: TextStyle(
+                      color: ColorConstants.black33,
+                      fontSize: 14,
+                      fontWeight: FontWeight.w400,
+                    ),
+                    inputType: TextInputType.text,
+                    textInputAction: TextInputAction.next,
+                    enabled: true,
+                    onSubmit: (key, value) {},
+                    cursorColor: ColorConstants.black33,
+                    showLeftIcon: false,
+                    showRightIcon: false,
+                  ),
+                ),
+
+                //选择模板
+                MyTextView(
+                  "Template".tr,
+                  fontSize: 14,
+                  marginTop: 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(
+                        template?.txt ?? "",
+                        fontSize: 14,
+                        hint: "Choose Outlet".tr,
+                        textHintColor: ColorConstants.black33,
+                        isFontMedium: true,
+                        textColor: ColorConstants.black33,
+                      ).expanded(),
+                      MyAssetImage(Assets.baseServiceTriangleDropDownIcon, width: 11.5, height: 6.28),
+                    ],
+                  ),
+                ).onTap(() {
+                  jobTitleFocusNode.unfocus();
+                  sortFocusNode.unfocus();
+                  FocusScope.of(context).unfocus();
+                  pickerJobTemplate();
+                }),
+
+                //输入自定义排序
+                MyTextView(
+                  "Sort".tr,
+                  fontSize: 14,
+                  marginTop: 14,
+                  textColor: ColorConstants.black33,
+                  isFontRegular: true,
+                ),
+
+                IgnoreKeyboardDismiss(
+                  child: MyTextField(
+                    "sort",
+                    sort ?? "",
+                    hintText: "Enter...".tr,
+                    hintStyle: TextStyle(
+                      color: ColorConstants.gray88,
+                      fontSize: 14,
+                      fontWeight: FontWeight.w400,
+                    ),
+                    controller: sortController,
+                    focusNode: sortFocusNode,
+                    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: 45,
+                    style: TextStyle(
+                      color: ColorConstants.black33,
+                      fontSize: 14,
+                      fontWeight: FontWeight.w400,
+                    ),
+                    inputType: TextInputType.number,
+                    textInputAction: TextInputAction.next,
+                    enabled: true,
+                    inputFormatters: <TextInputFormatter>[FilteringTextInputFormatter.digitsOnly],
+                    onSubmit: (key, value) {},
+                    cursorColor: ColorConstants.black33,
+                    showLeftIcon: false,
+                    showRightIcon: false,
+                  ),
+                ),
+
+                //分割线
+                Container(
+                  margin: EdgeInsets.only(top: 21),
+                  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 {
+                            doCallBack();
+                            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 pickerJobTemplate() {
+    if (widget.editIndexEntity == null) return;
+
+    var selectedTemplateIndex = 0;
+    if (template != null) {
+      int selectedIndex = widget.editIndexEntity?.template.indexWhere((element) => element?.selected == 'selected') ?? -1;
+      if (selectedIndex < 0) {
+        selectedTemplateIndex = 0;
+      }
+    }
+
+    OptionPickerUtil.showCupertinoOptionPicker(
+      items: widget.editIndexEntity!.template.map((e) => e?.txt ?? "").toList(growable: false),
+      initialSelectIndex: selectedTemplateIndex,
+      onPickerChanged: (_, index) {
+        setState(() {
+          template = widget.editIndexEntity!.template[index];
+        });
+      },
+    );
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+
+  void doCallBack() {
+    String jobTitle = jobTitleController.text.toString();
+    String sort = sortController.text.toString();
+
+    if (Utils.isEmpty(jobTitle)) {
+      ToastEngine.show("Enter Job Title".tr);
+      return;
+    }
+
+    widget.confirmAction?.call(jobTitle, template?.value.toString() ?? "", sort);
+  }
+}

+ 232 - 0
packages/cpt_labour_sg/lib/modules/job_title_list/job_title_item.dart

@@ -0,0 +1,232 @@
+import 'package:cs_resources/constants/color_constants.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 LabourRequestItem extends StatelessWidget {
+  final int index;
+  final JobTitleSGRows item;
+  final VoidCallback? onDeleteAction;
+  final VoidCallback? onEditAction;
+
+  LabourRequestItem({
+    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(
+                "Job Title".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.jobTitle ?? "-",
+                marginLeft: 5,
+                isFontMedium: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ),
+
+          // 工作模板
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Template".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.templateName ?? "-",
+                marginLeft: 5,
+                isFontRegular: true,
+                textColor: Colors.white,
+                fontSize: 14,
+              ).expanded(),
+            ],
+          ).marginOnly(top: 14),
+
+          // 排序
+          Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              MyTextView(
+                "Sort".tr + ":",
+                isFontRegular: true,
+                textColor: ColorConstants.textGrayAECAE5,
+                fontSize: 14,
+              ),
+              MyTextView(
+                item.sort.toString(),
+                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),
+
+          //按钮组
+          // Visibility(
+          //   visible: item.actionList?.isNotEmpty ?? false,
+          //   child: Row(
+          //     mainAxisSize: MainAxisSize.max,
+          //     mainAxisAlignment: MainAxisAlignment.end,
+          //     crossAxisAlignment: CrossAxisAlignment.center,
+          //     children: [
+          //       //详情按钮
+          //       Visibility(
+          //         visible: item.actionList?.contains("detail") ?? false,
+          //         child: MyButton(
+          //           onPressed: () {
+          //             FocusScope.of(context).unfocus();
+          //             onDetailAction?.call();
+          //           },
+          //           text: "Detail".tr,
+          //           textColor: ColorConstants.white,
+          //           backgroundColor: hexToColor(
+          //             "#56AAFF",
+          //           ),
+          //           radius: 17.25,
+          //           minWidth: 60,
+          //           minHeight: 35,
+          //         ).marginOnly(left: 12),
+          //       ),
+          //
+          //       //Recall按钮
+          //       Visibility(
+          //         visible: item.actionList?.contains("recall") ?? false,
+          //         child: MyButton(
+          //           onPressed: () {
+          //             FocusScope.of(context).unfocus();
+          //             onRecallAction?.call();
+          //           },
+          //           text: "Recall".tr,
+          //           textColor: ColorConstants.white,
+          //           backgroundColor: hexToColor("#FFBB1B"),
+          //           radius: 17.25,
+          //           minWidth: 60,
+          //           minHeight: 35,
+          //         ).marginOnly(left: 12),
+          //       ),
+          //
+          //       //Edit按钮
+          //       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("status") ?? false,
+          //         child: MyButton(
+          //           onPressed: () {
+          //             FocusScope.of(context).unfocus();
+          //             onStatusAction?.call();
+          //           },
+          //           text: "Status".tr,
+          //           textColor: ColorConstants.white,
+          //           backgroundColor: hexToColor("#0AC074"),
+          //           radius: 17.25,
+          //           minWidth: 60,
+          //           minHeight: 35,
+          //         ).marginOnly(left: 12),
+          //       ),
+          //     ],
+          //   ).marginOnly(top: 18, bottom: 2),
+          // ),
+        ],
+      ),
+    );
+  }
+}

+ 218 - 0
packages/cpt_labour_sg/lib/modules/job_title_list/job_title_list_controller.dart

@@ -0,0 +1,218 @@
+import 'package:domain/entity/response/job_title_edit_index_entity.dart';
+import 'package:domain/entity/response/job_title_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:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'job_title_add_dialog.dart';
+import 'job_title_list_state.dart';
+
+class JobTitleListController extends GetxController with DioCancelableMixin {
+  final LabourSGRepository _labourRepository = Get.find();
+  final JobTitleListState state = JobTitleListState();
+
+  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.fetchJobTitleList(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<JobTitleSGRows>? 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();
+  }
+
+  // 请求数据并展示添加JobTitle的弹窗
+  void requireAddNewDialog() async {
+    if (state.jobAddIndexEntity == null) {
+      //做了个新增的缓存
+      var result = await _labourRepository.fetchJobTitleAddIndex(cancelToken: cancelToken);
+
+      if (result.isSuccess) {
+        state.jobAddIndexEntity = result.data;
+        _showAddNewDialog(state.jobAddIndexEntity);
+      } else {
+        ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+      }
+    } else {
+      _showAddNewDialog(state.jobAddIndexEntity);
+    }
+  }
+
+  // 请求详情数据,并展示弹窗去编辑
+  void requireEditDialog(String titleId) async {
+    var result = await _labourRepository.fetchJobTitleEditIndex(titleId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      _showAddNewDialog(result.data);
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  // 展示新增或者编辑的弹窗
+  void _showAddNewDialog(JobTitleEditIndexEntity? entity) {
+    DialogEngine.show(
+      widget: AddJobTitleDialog(
+        editIndexEntity: entity,
+        confirmAction: (jobTitle, templateId, sort) {
+          _requestAddJobTitle(jobTitle, templateId, sort);
+        },
+      ),
+    );
+  }
+
+  // 请求接口添加工作标题
+  void _requestAddJobTitle(String jobTitle, String? templateId, String? sort) async {
+    var result = await _labourRepository.addJobTitleSubmit(jobTitle, sort, templateId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+      refreshController.callRefresh();
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  /// 根据ID获取Item对象,用于刷新
+  void fetchItemByIdAndRefreshItem(String ids) async {
+    var result = await _labourRepository.fetchJobTitleListByIds(
+      ids,
+      cancelToken: cancelToken,
+    );
+
+    //处理数据
+    if (result.isSuccess) {
+      var data = result.data;
+      if (data != null && data.rows.isNotEmpty) {
+        List<JobTitleSGRows> newItem = data.rows;
+
+        // 创建一个 Map 来加速查找
+        Map<int, JobTitleSGRows> 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);
+    }
+  }
+}

+ 167 - 0
packages/cpt_labour_sg/lib/modules/job_title_list/job_title_list_page.dart

@@ -0,0 +1,167 @@
+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_button.dart';
+import 'package:widgets/widget_export.dart';
+
+import 'job_title_item.dart';
+import 'job_title_list_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_title_list_state.dart';
+
+/**
+ * 新加坡的工作标题列表
+ */
+class JobTitleListPage extends BaseStatefulPage<JobTitleListController> {
+  JobTitleListPage({Key? key}) : super(key: key);
+
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.JOB_TITLE_LIST_SG);
+  }
+
+  @override
+  JobTitleListController createRawController() {
+    return JobTitleListController();
+  }
+
+  @override
+  State<JobTitleListPage> createState() => _JobTitleListState();
+}
+
+class _JobTitleListState extends BaseState<JobTitleListPage, JobTitleListController> {
+  late JobTitleListState 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: 'Job Title'.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),
+                ],
+              ),
+
+              Row(
+                children: [
+                  MyButton(
+                    type: ClickType.throttle,
+                    milliseconds: 500,
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                    },
+                    text: "Template Setting".tr,
+                    textColor: ColorConstants.white,
+                    fontSize: 16,
+                    radius: 20,
+                    backgroundColor: hexToColor("#855EF5"),
+                    fontWeight: FontWeight.w500,
+                  ).marginOnly(right: 5).expanded(),
+                  MyButton(
+                    type: ClickType.throttle,
+                    milliseconds: 500,
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      controller.requireAddNewDialog();
+                    },
+                    text: "Add New".tr,
+                    textColor: ColorConstants.white,
+                    fontSize: 16,
+                    radius: 20,
+                    backgroundColor: hexToColor("#FFBB1B"),
+                    fontWeight: FontWeight.w500,
+                  ).marginOnly(left: 5).expanded(),
+                ],
+              ).marginAll(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 LabourRequestItem(
+                              index: index,
+                              item: state.datas[index],
+                              onEditAction: () {
+                                // controller.gotoJobDetailPage(state.datas[index]);
+                              },
+                              onDeleteAction: () {
+                                // controller.gotoJobAppliedPage(state.datas[index]);
+                              },
+                            );
+                          },
+                          childCount: state.datas.length,
+                        ))
+                  ],
+                ),
+              ).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
+  }
+}

+ 15 - 0
packages/cpt_labour_sg/lib/modules/job_title_list/job_title_list_state.dart

@@ -0,0 +1,15 @@
+import 'package:domain/entity/response/job_title_edit_index_entity.dart';
+import 'package:domain/entity/response/job_title_s_g_entity.dart';
+import 'package:flutter/material.dart';
+
+class JobTitleListState {
+  //筛选条件
+  final TextEditingController searchController = TextEditingController();
+  String keyword = "";
+
+  //页面的列表数据
+  List<JobTitleSGRows> datas = [];
+
+  JobTitleEditIndexEntity? jobAddIndexEntity;
+
+}

+ 26 - 0
packages/cpt_labour_sg/lib/router/labour_sg_service_impl.dart

@@ -0,0 +1,26 @@
+import 'package:cpt_labour_sg/modules/job_title_list/job_title_list_page.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:router/componentRouter/labour_sg_service.dart';
+import 'package:shared/utils/log_utils.dart';
+
+class LabourSGServiceImpl extends GetxService implements LabourSGService {
+  @override
+  void onInit() {
+    super.onInit();
+    //初始化资源
+  }
+
+  @override
+  void onClose() {
+    super.onClose();
+    //销毁资源
+  }
+
+  @override
+  void startLabourRequestPage() {}
+
+  @override
+  void startJobTitlePage() {
+    JobTitleListPage.startInstance();
+  }
+}

+ 33 - 0
packages/cpt_labour_sg/lib/router/page_router.dart

@@ -0,0 +1,33 @@
+
+import 'package:cpt_labour_sg/modules/job_template_add/job_template_add_page.dart';
+import 'package:cpt_labour_sg/modules/job_template_list/job_template_list_page.dart';
+import 'package:cpt_labour_sg/modules/job_title_list/job_title_list_page.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:router/path/router_path.dart';
+
+
+class LabourSGPageRouter {
+
+  static final routes = [
+
+    // 工作标题列表
+    GetPage(
+      name: RouterPath.JOB_TITLE_LIST_SG,
+      page: () => JobTitleListPage(),
+    ),
+
+    // 工作模板列表
+    GetPage(
+      name: RouterPath.JOB_TEMPLATE_LIST_SG,
+      page: () => JobTemplateListPage(),
+    ),
+
+    // 添加模板
+    GetPage(
+      name: RouterPath.JOB_TEMPLATE_ADD_SG,
+      page: () => JobTemplateAddPage(),
+    ),
+
+  ];
+}

+ 40 - 0
packages/cpt_labour_sg/pubspec.yaml

@@ -0,0 +1,40 @@
+name: cpt_labour_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_labour_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

+ 39 - 3
packages/cs_domain/lib/constants/api_constants.dart

@@ -10,7 +10,6 @@ class ApiConstants {
   //新加坡的域名
   static const sgBaseUrl = isServerRelease ? 'https://singapore.casualabour.com' : 'http://singapore-dev.casualabour.com';
 
-
 // =========================== 用户相关 ↓=========================================
 
   // 酒店登录
@@ -118,9 +117,46 @@ class ApiConstants {
   // 用户签到签出
   static const apiSignInOut = "/index.php/api/v1/hotel/sign/clock";
 
-// =========================== 报表与其他 ↓=========================================
+  // =========================== 新加坡用工 ↓=========================================
+
+  // 工作标题列表
+  static const apiJobTitleListSG = "/index.php/api/v1/hotel/title/table";
+
+  // 添加工作标题的选项数据
+  static const apiJobTitleAddIndexSG = "/index.php/api/v1/hotel/title/add-view";
+
+  // 添加工作标题提交
+  static const apiJobTitleAddSubmitSG = "/index.php/api/v1/hotel/title/add-submit";
+
+  // 编辑工作标题的选项数据
+  static const apiJobTitleEditIndexSG = "/index.php/api/v1/hotel/title/edit-view";
+
+  // 编辑工作标题提交
+  static const apiJobTitleEditSubmitSG = "/index.php/api/v1/hotel/title/edit-submit";
+
+  // 删除工作标题
+  static const apiJobTitleDeleteSG = "/index.php/api/v1/hotel/title/delete";
+
+  // 工作模板列表
+  static const apiJobTemplateListSG = "/index.php/api/v1/hotel/temp/table";
+
+  // 添加工作模板选项数据
+  static const apiJobTemplateAddIndexSG = "/index.php/api/v1/hotel/temp/add-view";
+
+  // 添加工作模板选提交
+  static const apiJobTemplateAddSubmitSG = "/index.php/api/v1/hotel/temp/add-submit";
+
+  // 编辑工作模板选项数据
+  static const apiJobTemplateEditIndexSG = "/index.php/api/v1/hotel/temp/edit-view";
+
+  // 编辑工作模板提交
+  static const apiJobTemplateEditSubmitSG = "/index.php/api/v1/hotel/temp/edit-submit";
+
+  // 删除工作模板
+  static const apiJobTemplateDeleteSG = "/index.php/api/v1/hotel/temp/delete";
+
+  // =========================== 报表与其他 ↓=========================================
 
   // 设备列表
   static const apiDeviceList = "/index.php/api/v1/hotel/device/table";
-
 }

+ 89 - 0
packages/cs_domain/lib/entity/response/job_template_edit_index_entity.dart

@@ -0,0 +1,89 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/job_template_edit_index_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/job_template_edit_index_entity.g.dart';
+
+@JsonSerializable()
+class JobTemplateEditIndexEntity {
+	@JSONField(name: "template_id")
+	int templateId = 0;
+	String? name = null;
+	String? contact = null;
+	@JSONField(name: "contact_no")
+	String? contactNo = null;
+	String? description = null;
+	String? note = null;
+	@JSONField(name: "with_food_cert")
+	int withFoodCert = 0;
+	@JSONField(name: "age_list")
+	List<JobTemplateEditIndexAgeList> ageList = [];
+	@JSONField(name: "sex_list")
+	List<JobTemplateEditIndexSexList> sexList = [];
+	@JSONField(name: "language_list")
+	List<JobTemplateEditIndexLanguageList> languageList = [];
+
+	JobTemplateEditIndexEntity();
+
+	factory JobTemplateEditIndexEntity.fromJson(Map<String, dynamic> json) => $JobTemplateEditIndexEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobTemplateEditIndexEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class JobTemplateEditIndexAgeList {
+	String? value = null;
+	String? txt = null;
+	String? checked = null;
+
+	JobTemplateEditIndexAgeList();
+
+	factory JobTemplateEditIndexAgeList.fromJson(Map<String, dynamic> json) => $JobTemplateEditIndexAgeListFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobTemplateEditIndexAgeListToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class JobTemplateEditIndexSexList {
+	String? value = null;
+	String? txt = null;
+	String? checked = null;
+
+	JobTemplateEditIndexSexList();
+
+	factory JobTemplateEditIndexSexList.fromJson(Map<String, dynamic> json) => $JobTemplateEditIndexSexListFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobTemplateEditIndexSexListToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class JobTemplateEditIndexLanguageList {
+	String? value = null;
+	String? txt = null;
+	String? checked = null;
+
+	JobTemplateEditIndexLanguageList();
+
+	factory JobTemplateEditIndexLanguageList.fromJson(Map<String, dynamic> json) => $JobTemplateEditIndexLanguageListFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobTemplateEditIndexLanguageListToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 46 - 0
packages/cs_domain/lib/entity/response/job_template_s_g_entity.dart

@@ -0,0 +1,46 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/job_template_s_g_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/job_template_s_g_entity.g.dart';
+
+@JsonSerializable()
+class JobTemplateSGEntity {
+	int total = 0;
+	List<JobTemplateSGRows> rows = [];
+
+	JobTemplateSGEntity();
+
+	factory JobTemplateSGEntity.fromJson(Map<String, dynamic> json) => $JobTemplateSGEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobTemplateSGEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class JobTemplateSGRows {
+	int id = 0;
+	String? name = null;
+	String? contact = null;
+	@JSONField(name: "contact_no")
+	String? contactNo = null;
+	String? note = null;
+	@JSONField(name: "created_at")
+	String? createdAt = null;
+	@JSONField(name: "updated_at")
+	String? updatedAt = null;
+
+	JobTemplateSGRows();
+
+	factory JobTemplateSGRows.fromJson(Map<String, dynamic> json) => $JobTemplateSGRowsFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobTemplateSGRowsToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 43 - 0
packages/cs_domain/lib/entity/response/job_title_edit_index_entity.dart

@@ -0,0 +1,43 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/job_title_edit_index_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/job_title_edit_index_entity.g.dart';
+
+@JsonSerializable()
+class JobTitleEditIndexEntity {
+	@JSONField(name: "title_id")
+	int titleId = 0;
+	@JSONField(name: "job_title")
+	String? jobTitle = null;
+	int sort = 0;
+	List<JobTitleEditIndexTemplate?> template = [];
+
+	JobTitleEditIndexEntity();
+
+	factory JobTitleEditIndexEntity.fromJson(Map<String, dynamic> json) => $JobTitleEditIndexEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobTitleEditIndexEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class JobTitleEditIndexTemplate {
+	int value = 0;
+	String? txt = null;
+	String? selected = null;
+
+	JobTitleEditIndexTemplate();
+
+	factory JobTitleEditIndexTemplate.fromJson(Map<String, dynamic> json) => $JobTitleEditIndexTemplateFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobTitleEditIndexTemplateToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 46 - 0
packages/cs_domain/lib/entity/response/job_title_s_g_entity.dart

@@ -0,0 +1,46 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/job_title_s_g_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/job_title_s_g_entity.g.dart';
+
+@JsonSerializable()
+class JobTitleSGEntity {
+	int total = 0;
+	List<JobTitleSGRows> rows = [];
+
+	JobTitleSGEntity();
+
+	factory JobTitleSGEntity.fromJson(Map<String, dynamic> json) => $JobTitleSGEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobTitleSGEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class JobTitleSGRows {
+	int id = 0;
+	@JSONField(name: "job_title")
+	String? jobTitle = null;
+	@JSONField(name: "template_name")
+	String? templateName = null;
+	int sort = 0;
+	@JSONField(name: "created_at")
+	String? createdAt = null;
+	@JSONField(name: "updated_at")
+	String? updatedAt = null;
+
+	JobTitleSGRows();
+
+	factory JobTitleSGRows.fromJson(Map<String, dynamic> json) => $JobTitleSGRowsFromJson(json);
+
+	Map<String, dynamic> toJson() => $JobTitleSGRowsToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 44 - 0
packages/cs_domain/lib/generated/json/base/json_convert_content.dart

@@ -19,6 +19,10 @@ import 'package:domain/entity/response/job_list_detail_entity.dart';
 import 'package:domain/entity/response/job_list_entity.dart';
 import 'package:domain/entity/response/job_list_index_entity.dart';
 import 'package:domain/entity/response/job_list_remark_view_entity.dart';
+import 'package:domain/entity/response/job_template_edit_index_entity.dart';
+import 'package:domain/entity/response/job_template_s_g_entity.dart';
+import 'package:domain/entity/response/job_title_edit_index_entity.dart';
+import 'package:domain/entity/response/job_title_s_g_entity.dart';
 import 'package:domain/entity/response/labour_request_edit_index_entity.dart';
 import 'package:domain/entity/response/labour_request_index_entity.dart';
 import 'package:domain/entity/response/labour_request_list_entity.dart';
@@ -250,6 +254,36 @@ class JsonConvert {
     if (<JobListRemarkViewEntity>[] is M) {
       return data.map<JobListRemarkViewEntity>((Map<String, dynamic> e) => JobListRemarkViewEntity.fromJson(e)).toList() as M;
     }
+    if (<JobTemplateEditIndexEntity>[] is M) {
+      return data.map<JobTemplateEditIndexEntity>((Map<String, dynamic> e) => JobTemplateEditIndexEntity.fromJson(e)).toList() as M;
+    }
+    if (<JobTemplateEditIndexAgeList>[] is M) {
+      return data.map<JobTemplateEditIndexAgeList>((Map<String, dynamic> e) => JobTemplateEditIndexAgeList.fromJson(e)).toList() as M;
+    }
+    if (<JobTemplateEditIndexSexList>[] is M) {
+      return data.map<JobTemplateEditIndexSexList>((Map<String, dynamic> e) => JobTemplateEditIndexSexList.fromJson(e)).toList() as M;
+    }
+    if (<JobTemplateEditIndexLanguageList>[] is M) {
+      return data.map<JobTemplateEditIndexLanguageList>((Map<String, dynamic> e) => JobTemplateEditIndexLanguageList.fromJson(e)).toList() as M;
+    }
+    if (<JobTemplateSGEntity>[] is M) {
+      return data.map<JobTemplateSGEntity>((Map<String, dynamic> e) => JobTemplateSGEntity.fromJson(e)).toList() as M;
+    }
+    if (<JobTemplateSGRows>[] is M) {
+      return data.map<JobTemplateSGRows>((Map<String, dynamic> e) => JobTemplateSGRows.fromJson(e)).toList() as M;
+    }
+    if (<JobTitleEditIndexEntity>[] is M) {
+      return data.map<JobTitleEditIndexEntity>((Map<String, dynamic> e) => JobTitleEditIndexEntity.fromJson(e)).toList() as M;
+    }
+    if (<JobTitleEditIndexTemplate>[] is M) {
+      return data.map<JobTitleEditIndexTemplate>((Map<String, dynamic> e) => JobTitleEditIndexTemplate.fromJson(e)).toList() as M;
+    }
+    if (<JobTitleSGEntity>[] is M) {
+      return data.map<JobTitleSGEntity>((Map<String, dynamic> e) => JobTitleSGEntity.fromJson(e)).toList() as M;
+    }
+    if (<JobTitleSGRows>[] is M) {
+      return data.map<JobTitleSGRows>((Map<String, dynamic> e) => JobTitleSGRows.fromJson(e)).toList() as M;
+    }
     if (<LabourRequestEditIndexEntity>[] is M) {
       return data.map<LabourRequestEditIndexEntity>((Map<String, dynamic> e) => LabourRequestEditIndexEntity.fromJson(e)).toList() as M;
     }
@@ -362,6 +396,16 @@ class JsonConvertClassCollection {
     (JobListIndexDepartmentList).toString(): JobListIndexDepartmentList.fromJson,
     (JobListIndexStatusList).toString(): JobListIndexStatusList.fromJson,
     (JobListRemarkViewEntity).toString(): JobListRemarkViewEntity.fromJson,
+    (JobTemplateEditIndexEntity).toString(): JobTemplateEditIndexEntity.fromJson,
+    (JobTemplateEditIndexAgeList).toString(): JobTemplateEditIndexAgeList.fromJson,
+    (JobTemplateEditIndexSexList).toString(): JobTemplateEditIndexSexList.fromJson,
+    (JobTemplateEditIndexLanguageList).toString(): JobTemplateEditIndexLanguageList.fromJson,
+    (JobTemplateSGEntity).toString(): JobTemplateSGEntity.fromJson,
+    (JobTemplateSGRows).toString(): JobTemplateSGRows.fromJson,
+    (JobTitleEditIndexEntity).toString(): JobTitleEditIndexEntity.fromJson,
+    (JobTitleEditIndexTemplate).toString(): JobTitleEditIndexTemplate.fromJson,
+    (JobTitleSGEntity).toString(): JobTitleSGEntity.fromJson,
+    (JobTitleSGRows).toString(): JobTitleSGRows.fromJson,
     (LabourRequestEditIndexEntity).toString(): LabourRequestEditIndexEntity.fromJson,
     (LabourRequestEditIndexTemplateList).toString(): LabourRequestEditIndexTemplateList.fromJson,
     (LabourRequestEditIndexDepartmentList).toString(): LabourRequestEditIndexDepartmentList.fromJson,

+ 206 - 0
packages/cs_domain/lib/generated/json/job_template_edit_index_entity.g.dart

@@ -0,0 +1,206 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/job_template_edit_index_entity.dart';
+
+JobTemplateEditIndexEntity $JobTemplateEditIndexEntityFromJson(Map<String, dynamic> json) {
+  final JobTemplateEditIndexEntity jobTemplateEditIndexEntity = JobTemplateEditIndexEntity();
+  final int? templateId = jsonConvert.convert<int>(json['template_id']);
+  if (templateId != null) {
+    jobTemplateEditIndexEntity.templateId = templateId;
+  }
+  final String? name = jsonConvert.convert<String>(json['name']);
+  if (name != null) {
+    jobTemplateEditIndexEntity.name = name;
+  }
+  final String? contact = jsonConvert.convert<String>(json['contact']);
+  if (contact != null) {
+    jobTemplateEditIndexEntity.contact = contact;
+  }
+  final String? contactNo = jsonConvert.convert<String>(json['contact_no']);
+  if (contactNo != null) {
+    jobTemplateEditIndexEntity.contactNo = contactNo;
+  }
+  final String? description = jsonConvert.convert<String>(json['description']);
+  if (description != null) {
+    jobTemplateEditIndexEntity.description = description;
+  }
+  final String? note = jsonConvert.convert<String>(json['note']);
+  if (note != null) {
+    jobTemplateEditIndexEntity.note = note;
+  }
+  final int? withFoodCert = jsonConvert.convert<int>(json['with_food_cert']);
+  if (withFoodCert != null) {
+    jobTemplateEditIndexEntity.withFoodCert = withFoodCert;
+  }
+  final List<JobTemplateEditIndexAgeList>? ageList = (json['age_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<JobTemplateEditIndexAgeList>(e) as JobTemplateEditIndexAgeList).toList();
+  if (ageList != null) {
+    jobTemplateEditIndexEntity.ageList = ageList;
+  }
+  final List<JobTemplateEditIndexSexList>? sexList = (json['sex_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<JobTemplateEditIndexSexList>(e) as JobTemplateEditIndexSexList).toList();
+  if (sexList != null) {
+    jobTemplateEditIndexEntity.sexList = sexList;
+  }
+  final List<JobTemplateEditIndexLanguageList>? languageList = (json['language_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<JobTemplateEditIndexLanguageList>(e) as JobTemplateEditIndexLanguageList).toList();
+  if (languageList != null) {
+    jobTemplateEditIndexEntity.languageList = languageList;
+  }
+  return jobTemplateEditIndexEntity;
+}
+
+Map<String, dynamic> $JobTemplateEditIndexEntityToJson(JobTemplateEditIndexEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['template_id'] = entity.templateId;
+  data['name'] = entity.name;
+  data['contact'] = entity.contact;
+  data['contact_no'] = entity.contactNo;
+  data['description'] = entity.description;
+  data['note'] = entity.note;
+  data['with_food_cert'] = entity.withFoodCert;
+  data['age_list'] = entity.ageList.map((v) => v.toJson()).toList();
+  data['sex_list'] = entity.sexList.map((v) => v.toJson()).toList();
+  data['language_list'] = entity.languageList.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension JobTemplateEditIndexEntityExtension on JobTemplateEditIndexEntity {
+  JobTemplateEditIndexEntity copyWith({
+    int? templateId,
+    String? name,
+    String? contact,
+    String? contactNo,
+    String? description,
+    String? note,
+    int? withFoodCert,
+    List<JobTemplateEditIndexAgeList>? ageList,
+    List<JobTemplateEditIndexSexList>? sexList,
+    List<JobTemplateEditIndexLanguageList>? languageList,
+  }) {
+    return JobTemplateEditIndexEntity()
+      ..templateId = templateId ?? this.templateId
+      ..name = name ?? this.name
+      ..contact = contact ?? this.contact
+      ..contactNo = contactNo ?? this.contactNo
+      ..description = description ?? this.description
+      ..note = note ?? this.note
+      ..withFoodCert = withFoodCert ?? this.withFoodCert
+      ..ageList = ageList ?? this.ageList
+      ..sexList = sexList ?? this.sexList
+      ..languageList = languageList ?? this.languageList;
+  }
+}
+
+JobTemplateEditIndexAgeList $JobTemplateEditIndexAgeListFromJson(Map<String, dynamic> json) {
+  final JobTemplateEditIndexAgeList jobTemplateEditIndexAgeList = JobTemplateEditIndexAgeList();
+  final String? value = jsonConvert.convert<String>(json['value']);
+  if (value != null) {
+    jobTemplateEditIndexAgeList.value = value;
+  }
+  final String? txt = jsonConvert.convert<String>(json['txt']);
+  if (txt != null) {
+    jobTemplateEditIndexAgeList.txt = txt;
+  }
+  final String? checked = jsonConvert.convert<String>(json['checked']);
+  if (checked != null) {
+    jobTemplateEditIndexAgeList.checked = checked;
+  }
+  return jobTemplateEditIndexAgeList;
+}
+
+Map<String, dynamic> $JobTemplateEditIndexAgeListToJson(JobTemplateEditIndexAgeList entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['value'] = entity.value;
+  data['txt'] = entity.txt;
+  data['checked'] = entity.checked;
+  return data;
+}
+
+extension JobTemplateEditIndexAgeListExtension on JobTemplateEditIndexAgeList {
+  JobTemplateEditIndexAgeList copyWith({
+    String? value,
+    String? txt,
+    String? checked,
+  }) {
+    return JobTemplateEditIndexAgeList()
+      ..value = value ?? this.value
+      ..txt = txt ?? this.txt
+      ..checked = checked ?? this.checked;
+  }
+}
+
+JobTemplateEditIndexSexList $JobTemplateEditIndexSexListFromJson(Map<String, dynamic> json) {
+  final JobTemplateEditIndexSexList jobTemplateEditIndexSexList = JobTemplateEditIndexSexList();
+  final String? value = jsonConvert.convert<String>(json['value']);
+  if (value != null) {
+    jobTemplateEditIndexSexList.value = value;
+  }
+  final String? txt = jsonConvert.convert<String>(json['txt']);
+  if (txt != null) {
+    jobTemplateEditIndexSexList.txt = txt;
+  }
+  final String? checked = jsonConvert.convert<String>(json['checked']);
+  if (checked != null) {
+    jobTemplateEditIndexSexList.checked = checked;
+  }
+  return jobTemplateEditIndexSexList;
+}
+
+Map<String, dynamic> $JobTemplateEditIndexSexListToJson(JobTemplateEditIndexSexList entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['value'] = entity.value;
+  data['txt'] = entity.txt;
+  data['checked'] = entity.checked;
+  return data;
+}
+
+extension JobTemplateEditIndexSexListExtension on JobTemplateEditIndexSexList {
+  JobTemplateEditIndexSexList copyWith({
+    String? value,
+    String? txt,
+    String? checked,
+  }) {
+    return JobTemplateEditIndexSexList()
+      ..value = value ?? this.value
+      ..txt = txt ?? this.txt
+      ..checked = checked ?? this.checked;
+  }
+}
+
+JobTemplateEditIndexLanguageList $JobTemplateEditIndexLanguageListFromJson(Map<String, dynamic> json) {
+  final JobTemplateEditIndexLanguageList jobTemplateEditIndexLanguageList = JobTemplateEditIndexLanguageList();
+  final String? value = jsonConvert.convert<String>(json['value']);
+  if (value != null) {
+    jobTemplateEditIndexLanguageList.value = value;
+  }
+  final String? txt = jsonConvert.convert<String>(json['txt']);
+  if (txt != null) {
+    jobTemplateEditIndexLanguageList.txt = txt;
+  }
+  final String? checked = jsonConvert.convert<String>(json['checked']);
+  if (checked != null) {
+    jobTemplateEditIndexLanguageList.checked = checked;
+  }
+  return jobTemplateEditIndexLanguageList;
+}
+
+Map<String, dynamic> $JobTemplateEditIndexLanguageListToJson(JobTemplateEditIndexLanguageList entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['value'] = entity.value;
+  data['txt'] = entity.txt;
+  data['checked'] = entity.checked;
+  return data;
+}
+
+extension JobTemplateEditIndexLanguageListExtension on JobTemplateEditIndexLanguageList {
+  JobTemplateEditIndexLanguageList copyWith({
+    String? value,
+    String? txt,
+    String? checked,
+  }) {
+    return JobTemplateEditIndexLanguageList()
+      ..value = value ?? this.value
+      ..txt = txt ?? this.txt
+      ..checked = checked ?? this.checked;
+  }
+}

+ 100 - 0
packages/cs_domain/lib/generated/json/job_template_s_g_entity.g.dart

@@ -0,0 +1,100 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/job_template_s_g_entity.dart';
+
+JobTemplateSGEntity $JobTemplateSGEntityFromJson(Map<String, dynamic> json) {
+  final JobTemplateSGEntity jobTemplateSGEntity = JobTemplateSGEntity();
+  final int? total = jsonConvert.convert<int>(json['total']);
+  if (total != null) {
+    jobTemplateSGEntity.total = total;
+  }
+  final List<JobTemplateSGRows>? rows = (json['rows'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<JobTemplateSGRows>(e) as JobTemplateSGRows).toList();
+  if (rows != null) {
+    jobTemplateSGEntity.rows = rows;
+  }
+  return jobTemplateSGEntity;
+}
+
+Map<String, dynamic> $JobTemplateSGEntityToJson(JobTemplateSGEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['total'] = entity.total;
+  data['rows'] = entity.rows.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension JobTemplateSGEntityExtension on JobTemplateSGEntity {
+  JobTemplateSGEntity copyWith({
+    int? total,
+    List<JobTemplateSGRows>? rows,
+  }) {
+    return JobTemplateSGEntity()
+      ..total = total ?? this.total
+      ..rows = rows ?? this.rows;
+  }
+}
+
+JobTemplateSGRows $JobTemplateSGRowsFromJson(Map<String, dynamic> json) {
+  final JobTemplateSGRows jobTemplateSGRows = JobTemplateSGRows();
+  final int? id = jsonConvert.convert<int>(json['id']);
+  if (id != null) {
+    jobTemplateSGRows.id = id;
+  }
+  final String? name = jsonConvert.convert<String>(json['name']);
+  if (name != null) {
+    jobTemplateSGRows.name = name;
+  }
+  final String? contact = jsonConvert.convert<String>(json['contact']);
+  if (contact != null) {
+    jobTemplateSGRows.contact = contact;
+  }
+  final String? contactNo = jsonConvert.convert<String>(json['contact_no']);
+  if (contactNo != null) {
+    jobTemplateSGRows.contactNo = contactNo;
+  }
+  final String? note = jsonConvert.convert<String>(json['note']);
+  if (note != null) {
+    jobTemplateSGRows.note = note;
+  }
+  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
+  if (createdAt != null) {
+    jobTemplateSGRows.createdAt = createdAt;
+  }
+  final String? updatedAt = jsonConvert.convert<String>(json['updated_at']);
+  if (updatedAt != null) {
+    jobTemplateSGRows.updatedAt = updatedAt;
+  }
+  return jobTemplateSGRows;
+}
+
+Map<String, dynamic> $JobTemplateSGRowsToJson(JobTemplateSGRows entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['id'] = entity.id;
+  data['name'] = entity.name;
+  data['contact'] = entity.contact;
+  data['contact_no'] = entity.contactNo;
+  data['note'] = entity.note;
+  data['created_at'] = entity.createdAt;
+  data['updated_at'] = entity.updatedAt;
+  return data;
+}
+
+extension JobTemplateSGRowsExtension on JobTemplateSGRows {
+  JobTemplateSGRows copyWith({
+    int? id,
+    String? name,
+    String? contact,
+    String? contactNo,
+    String? note,
+    String? createdAt,
+    String? updatedAt,
+  }) {
+    return JobTemplateSGRows()
+      ..id = id ?? this.id
+      ..name = name ?? this.name
+      ..contact = contact ?? this.contact
+      ..contactNo = contactNo ?? this.contactNo
+      ..note = note ?? this.note
+      ..createdAt = createdAt ?? this.createdAt
+      ..updatedAt = updatedAt ?? this.updatedAt;
+  }
+}

+ 86 - 0
packages/cs_domain/lib/generated/json/job_title_edit_index_entity.g.dart

@@ -0,0 +1,86 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/job_title_edit_index_entity.dart';
+
+JobTitleEditIndexEntity $JobTitleEditIndexEntityFromJson(Map<String, dynamic> json) {
+  final JobTitleEditIndexEntity jobTitleEditIndexEntity = JobTitleEditIndexEntity();
+  final int? titleId = jsonConvert.convert<int>(json['title_id']);
+  if (titleId != null) {
+    jobTitleEditIndexEntity.titleId = titleId;
+  }
+  final String? jobTitle = jsonConvert.convert<String>(json['job_title']);
+  if (jobTitle != null) {
+    jobTitleEditIndexEntity.jobTitle = jobTitle;
+  }
+  final int? sort = jsonConvert.convert<int>(json['sort']);
+  if (sort != null) {
+    jobTitleEditIndexEntity.sort = sort;
+  }
+  final List<JobTitleEditIndexTemplate?>? template = (json['template'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<JobTitleEditIndexTemplate>(e)).toList();
+  if (template != null) {
+    jobTitleEditIndexEntity.template = template;
+  }
+  return jobTitleEditIndexEntity;
+}
+
+Map<String, dynamic> $JobTitleEditIndexEntityToJson(JobTitleEditIndexEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['title_id'] = entity.titleId;
+  data['job_title'] = entity.jobTitle;
+  data['sort'] = entity.sort;
+  data['template'] = entity.template.map((v) => v?.toJson()).toList();
+  return data;
+}
+
+extension JobTitleEditIndexEntityExtension on JobTitleEditIndexEntity {
+  JobTitleEditIndexEntity copyWith({
+    int? titleId,
+    String? jobTitle,
+    int? sort,
+    List<JobTitleEditIndexTemplate?>? template,
+  }) {
+    return JobTitleEditIndexEntity()
+      ..titleId = titleId ?? this.titleId
+      ..jobTitle = jobTitle ?? this.jobTitle
+      ..sort = sort ?? this.sort
+      ..template = template ?? this.template;
+  }
+}
+
+JobTitleEditIndexTemplate $JobTitleEditIndexTemplateFromJson(Map<String, dynamic> json) {
+  final JobTitleEditIndexTemplate jobTitleEditIndexTemplate = JobTitleEditIndexTemplate();
+  final int? value = jsonConvert.convert<int>(json['value']);
+  if (value != null) {
+    jobTitleEditIndexTemplate.value = value;
+  }
+  final String? txt = jsonConvert.convert<String>(json['txt']);
+  if (txt != null) {
+    jobTitleEditIndexTemplate.txt = txt;
+  }
+  final String? selected = jsonConvert.convert<String>(json['selected']);
+  if (selected != null) {
+    jobTitleEditIndexTemplate.selected = selected;
+  }
+  return jobTitleEditIndexTemplate;
+}
+
+Map<String, dynamic> $JobTitleEditIndexTemplateToJson(JobTitleEditIndexTemplate entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['value'] = entity.value;
+  data['txt'] = entity.txt;
+  data['selected'] = entity.selected;
+  return data;
+}
+
+extension JobTitleEditIndexTemplateExtension on JobTitleEditIndexTemplate {
+  JobTitleEditIndexTemplate copyWith({
+    int? value,
+    String? txt,
+    String? selected,
+  }) {
+    return JobTitleEditIndexTemplate()
+      ..value = value ?? this.value
+      ..txt = txt ?? this.txt
+      ..selected = selected ?? this.selected;
+  }
+}

+ 93 - 0
packages/cs_domain/lib/generated/json/job_title_s_g_entity.g.dart

@@ -0,0 +1,93 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/job_title_s_g_entity.dart';
+
+JobTitleSGEntity $JobTitleSGEntityFromJson(Map<String, dynamic> json) {
+  final JobTitleSGEntity jobTitleSGEntity = JobTitleSGEntity();
+  final int? total = jsonConvert.convert<int>(json['total']);
+  if (total != null) {
+    jobTitleSGEntity.total = total;
+  }
+  final List<JobTitleSGRows>? rows = (json['rows'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<JobTitleSGRows>(e) as JobTitleSGRows).toList();
+  if (rows != null) {
+    jobTitleSGEntity.rows = rows;
+  }
+  return jobTitleSGEntity;
+}
+
+Map<String, dynamic> $JobTitleSGEntityToJson(JobTitleSGEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['total'] = entity.total;
+  data['rows'] = entity.rows.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension JobTitleSGEntityExtension on JobTitleSGEntity {
+  JobTitleSGEntity copyWith({
+    int? total,
+    List<JobTitleSGRows>? rows,
+  }) {
+    return JobTitleSGEntity()
+      ..total = total ?? this.total
+      ..rows = rows ?? this.rows;
+  }
+}
+
+JobTitleSGRows $JobTitleSGRowsFromJson(Map<String, dynamic> json) {
+  final JobTitleSGRows jobTitleSGRows = JobTitleSGRows();
+  final int? id = jsonConvert.convert<int>(json['id']);
+  if (id != null) {
+    jobTitleSGRows.id = id;
+  }
+  final String? jobTitle = jsonConvert.convert<String>(json['job_title']);
+  if (jobTitle != null) {
+    jobTitleSGRows.jobTitle = jobTitle;
+  }
+  final String? templateName = jsonConvert.convert<String>(json['template_name']);
+  if (templateName != null) {
+    jobTitleSGRows.templateName = templateName;
+  }
+  final int? sort = jsonConvert.convert<int>(json['sort']);
+  if (sort != null) {
+    jobTitleSGRows.sort = sort;
+  }
+  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
+  if (createdAt != null) {
+    jobTitleSGRows.createdAt = createdAt;
+  }
+  final String? updatedAt = jsonConvert.convert<String>(json['updated_at']);
+  if (updatedAt != null) {
+    jobTitleSGRows.updatedAt = updatedAt;
+  }
+  return jobTitleSGRows;
+}
+
+Map<String, dynamic> $JobTitleSGRowsToJson(JobTitleSGRows entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['id'] = entity.id;
+  data['job_title'] = entity.jobTitle;
+  data['template_name'] = entity.templateName;
+  data['sort'] = entity.sort;
+  data['created_at'] = entity.createdAt;
+  data['updated_at'] = entity.updatedAt;
+  return data;
+}
+
+extension JobTitleSGRowsExtension on JobTitleSGRows {
+  JobTitleSGRows copyWith({
+    int? id,
+    String? jobTitle,
+    String? templateName,
+    int? sort,
+    String? createdAt,
+    String? updatedAt,
+  }) {
+    return JobTitleSGRows()
+      ..id = id ?? this.id
+      ..jobTitle = jobTitle ?? this.jobTitle
+      ..templateName = templateName ?? this.templateName
+      ..sort = sort ?? this.sort
+      ..createdAt = createdAt ?? this.createdAt
+      ..updatedAt = updatedAt ?? this.updatedAt;
+  }
+}

+ 33 - 0
packages/cs_domain/lib/repository/job_sg_repository.dart

@@ -0,0 +1,33 @@
+import 'dart:typed_data';
+
+import 'package:domain/entity/response/job_list_add_staff_entity.dart';
+import 'package:domain/entity/response/job_list_applied_edit_entity.dart';
+import 'package:domain/entity/response/job_list_applied_info_entity.dart';
+import 'package:domain/entity/response/job_list_applied_staff_list_entity.dart';
+import 'package:domain/entity/response/job_list_applied_staff_search_entity.dart';
+import 'package:domain/entity/response/job_list_detail_entity.dart';
+import 'package:domain/entity/response/job_list_entity.dart';
+import 'package:domain/entity/response/job_list_index_entity.dart';
+import 'package:domain/entity/response/job_list_remark_view_entity.dart';
+import 'package:domain/entity/response/staff_detail_entity.dart';
+import 'package:domain/entity/response/staff_labour_history_entity.dart';
+import 'package:domain/entity/response/staff_remark_history_entity.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/dio_export.dart';
+import 'package:plugin_platform/http/http_provider.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/util.dart';
+
+import '../constants/api_constants.dart';
+import '../entity/response/attendance_entity.dart';
+import '../entity/response/check_success_entity.dart';
+import '../entity/response/job_list_applied_work_flow_entity.dart';
+
+/// 工作相关(新加坡)
+class JobSGRepository extends GetxService {
+  HttpProvider httpProvider;
+
+  JobSGRepository({required this.httpProvider});
+
+
+}

+ 506 - 0
packages/cs_domain/lib/repository/labour_sg_repository.dart

@@ -0,0 +1,506 @@
+import 'dart:typed_data';
+
+import 'package:domain/entity/response/job_template_edit_index_entity.dart';
+import 'package:domain/entity/response/job_template_s_g_entity.dart';
+import 'package:domain/entity/response/job_title_edit_index_entity.dart';
+import 'package:domain/entity/response/job_title_s_g_entity.dart';
+import 'package:get/get.dart';
+import 'package:plugin_platform/dio_export.dart';
+import 'package:plugin_platform/http/http_provider.dart';
+import 'package:plugin_platform/http/http_result.dart';
+import 'package:shared/utils/util.dart';
+
+import '../constants/api_constants.dart';
+
+/// 用工相关(新加坡)
+class LabourSGRepository extends GetxService {
+  HttpProvider httpProvider;
+
+  LabourSGRepository({required this.httpProvider});
+
+  /// 用工模版中的工作标题列表
+  Future<HttpResult<JobTitleSGEntity>> fetchJobTitleList(
+    String? keyword, {
+    required int curPage,
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params["cur_page"] = curPage.toString();
+    params["page_size"] = "10";
+
+    if (!Utils.isEmpty(keyword)) {
+      params["keyword"] = keyword!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTitleListSG,
+      params: params,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = JobTitleSGEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<JobTitleSGEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 根据ID获取主列表的Item数据,用于刷新Item
+  Future<HttpResult<JobTitleSGEntity>> fetchJobTitleListByIds(
+    String? ids, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params["cur_page"] = "1";
+    params["page_size"] = "9999";
+
+    if (!Utils.isEmpty(ids)) {
+      params["ids"] = ids!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTitleListSG,
+      params: params,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = JobTitleSGEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<JobTitleSGEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 添加工作标题的详情或选项数据
+  Future<HttpResult<JobTitleEditIndexEntity>> fetchJobTitleAddIndex({
+    CancelToken? cancelToken,
+  }) async {
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTitleAddIndexSG,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = JobTitleEditIndexEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<JobTitleEditIndexEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 编辑工作标题的详情或选项数据
+  Future<HttpResult<JobTitleEditIndexEntity>> fetchJobTitleEditIndex(
+    String? titleId, {
+    CancelToken? cancelToken,
+  }) async {
+    Map<String, String> params = {};
+    params["title_id"] = titleId ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTitleEditIndexSG,
+      params: params,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = JobTitleEditIndexEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<JobTitleEditIndexEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 添加工作标题的提交
+  Future<HttpResult> addJobTitleSubmit(
+    String? jobTitle,
+    String? sort,
+    String? templateId, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['job_title'] = jobTitle ?? "";
+
+    if (!Utils.isEmpty(templateId)) {
+      params["template_id"] = templateId!;
+    }
+
+    if (!Utils.isEmpty(sort)) {
+      params["sort"] = sort!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTitleAddSubmitSG,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  /// 编辑工作标题的提交
+  Future<HttpResult> editJobTitleSubmit(
+    String? titleId,
+    String? jobTitle,
+    String? sort,
+    String? templateId, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['job_title'] = jobTitle ?? "";
+    params['title_id'] = titleId ?? "";
+
+    if (!Utils.isEmpty(templateId)) {
+      params["template_id"] = templateId!;
+    }
+
+    if (!Utils.isEmpty(sort)) {
+      params["sort"] = sort!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTitleEditSubmitSG,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  /// 删除工作标题的提交
+  Future<HttpResult> deleteJobTitleSubmit(
+    String? titleId, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+
+    params['title_id'] = titleId ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTitleDeleteSG,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  // ===================================  Template  ↓  ===================================
+
+  /// 用工模版中的工作标题列表
+  Future<HttpResult<JobTemplateSGEntity>> fetchJobTemplateList(
+    String? keyword, {
+    required int curPage,
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params["cur_page"] = curPage.toString();
+    params["page_size"] = "10";
+
+    if (!Utils.isEmpty(keyword)) {
+      params["keyword"] = keyword!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTemplateListSG,
+      params: params,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = JobTemplateSGEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<JobTemplateSGEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 根据ID获取主列表的Item数据,用于刷新Item
+  Future<HttpResult<JobTemplateSGEntity>> fetchJobTemplateListByIds(
+      String? ids, {
+        CancelToken? cancelToken,
+      }) async {
+    //参数
+    Map<String, String> params = {};
+    params["cur_page"] = "1";
+    params["page_size"] = "9999";
+
+    if (!Utils.isEmpty(ids)) {
+      params["ids"] = ids!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTemplateListSG,
+      params: params,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = JobTemplateSGEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<JobTemplateSGEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 添加工作模板的详情或选项数据
+  Future<HttpResult<JobTemplateEditIndexEntity>> fetchJobTemplateAddIndex({
+    CancelToken? cancelToken,
+  }) async {
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTemplateAddIndexSG,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = JobTemplateEditIndexEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<JobTemplateEditIndexEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 编辑工作模板的详情或选项数据
+  Future<HttpResult<JobTemplateEditIndexEntity>> fetchJobTemplateEditIndex(
+    String? templateId, {
+    CancelToken? cancelToken,
+  }) async {
+    Map<String, String> params = {};
+    params["template_id"] = templateId ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTemplateEditIndexSG,
+      params: params,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      final json = result.getDataJson();
+      var data = JobTemplateEditIndexEntity.fromJson(json!);
+      //重新赋值data或list
+      return result.convert<JobTemplateEditIndexEntity>(data: data);
+    }
+    return result.convert();
+  }
+
+  /// 添加工作模板的提交
+  Future<HttpResult> addJobTemplateSubmit(
+    String? name,
+    String? contact,
+    String? contact_no,
+    String? description,
+    String? note,
+    String? age,
+    String? sex,
+    String? with_food_cert,
+    String? language, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['name'] = name ?? "";
+
+    if (!Utils.isEmpty(contact)) {
+      params["contact"] = contact!;
+    }
+
+    if (!Utils.isEmpty(contact_no)) {
+      params["contact_no"] = contact_no!;
+    }
+
+    if (!Utils.isEmpty(description)) {
+      params["description"] = description!;
+    }
+
+    if (!Utils.isEmpty(note)) {
+      params["note"] = note!;
+    }
+
+    if (!Utils.isEmpty(age)) {
+      params["age"] = age!;
+    }
+
+    if (!Utils.isEmpty(sex)) {
+      params["sex"] = sex!;
+    }
+
+    if (!Utils.isEmpty(with_food_cert)) {
+      params["with_food_cert"] = with_food_cert!;
+    }
+
+    if (!Utils.isEmpty(language)) {
+      params["language"] = language!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTemplateAddSubmitSG,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  /// 编辑工作模板的提交
+  Future<HttpResult> editJobTemplateSubmit(
+    String? templateId,
+    String? name,
+    String? contact,
+    String? contact_no,
+    String? description,
+    String? note,
+    String? age,
+    String? sex,
+    String? with_food_cert,
+    String? language, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+    params['name'] = name ?? "";
+    params['template_id'] = templateId ?? "";
+
+    if (!Utils.isEmpty(contact)) {
+      params["contact"] = contact!;
+    }
+
+    if (!Utils.isEmpty(contact_no)) {
+      params["contact_no"] = contact_no!;
+    }
+
+    if (!Utils.isEmpty(description)) {
+      params["description"] = description!;
+    }
+
+    if (!Utils.isEmpty(note)) {
+      params["note"] = note!;
+    }
+
+    if (!Utils.isEmpty(age)) {
+      params["age"] = age!;
+    }
+
+    if (!Utils.isEmpty(sex)) {
+      params["sex"] = sex!;
+    }
+
+    if (!Utils.isEmpty(with_food_cert)) {
+      params["with_food_cert"] = with_food_cert!;
+    }
+
+    if (!Utils.isEmpty(language)) {
+      params["language"] = language!;
+    }
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTemplateEditSubmitSG,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+
+  /// 删除工作标题的提交
+  Future<HttpResult> deleteJobTemplateSubmit(
+    String? templateId, {
+    CancelToken? cancelToken,
+  }) async {
+    //参数
+    Map<String, String> params = {};
+
+    params['template_id'] = templateId ?? "";
+
+    final result = await httpProvider.requestNetResult(
+      ApiConstants.apiJobTemplateDeleteSG,
+      method: HttpMethod.POST,
+      params: params,
+      networkDebounce: true,
+      isShowLoadingDialog: true,
+      cancelToken: cancelToken,
+    );
+
+    //根据返回的结果,封装原始数据为Bean/Entity对象
+    if (result.isSuccess) {
+      //重新赋值data或list
+      return result.convert();
+    }
+    return result.convert();
+  }
+}

+ 4 - 0
packages/cs_initializer/lib/global_services_injection.dart

@@ -1,7 +1,9 @@
 import 'package:domain/constants/api_constants.dart';
 import 'package:domain/repository/auth_repository.dart';
 import 'package:domain/repository/job_repository.dart';
+import 'package:domain/repository/job_sg_repository.dart';
 import 'package:domain/repository/labour_repository.dart';
+import 'package:domain/repository/labour_sg_repository.dart';
 import 'package:domain/repository/other_repository.dart';
 import 'package:plugin_basic/basic_export.dart';
 import 'package:plugin_basic/dio_interceptors/interceptor_auth_dio.dart';
@@ -32,7 +34,9 @@ class GlobalServicesInjection {
 
     //其他的数据仓库注入
     Get.lazyPut(() => JobRepository(httpProvider: Get.find()));
+    Get.lazyPut(() => JobSGRepository(httpProvider: Get.find()));
     Get.lazyPut(() => LabourRepository(httpProvider: Get.find()));
+    Get.lazyPut(() => LabourSGRepository(httpProvider: Get.find()));
     Get.lazyPut(() => OtherRepository(httpProvider: Get.find()));
 
     // 用户信息服务(用户信息相关业务类)

+ 1 - 0
packages/cs_resources/lib/constants/color_constants.dart

@@ -12,6 +12,7 @@ class ColorConstants {
 
   static const Color gray = Color(0xFFCCCCCC);
   static const Color grayECECEC = Color(0xFFECECEC);
+  static const Color gray88 = Color(0xFF888888);
   static const Color black = Color(0xFF000000);
   static const Color white = Color(0xFFFFFFFF);
   static const Color dividerA6 = Color(0x4da6a6a6);

+ 6 - 0
packages/cs_resources/lib/local/language/en_US.dart

@@ -151,6 +151,12 @@ const Map<String, String> en_US = {
   'Alive State:': 'Alive State:',
   'Offline': 'Offline',
   'Online': 'Online',
+  'Sort': 'Sort',
+  'Template': 'Template',
+  'Updated At': 'Updated At',
+  'Add New': 'Add New',
+  'Template Setting': 'Template Setting',
+  'Enter Job Title': 'Enter Job Title',
 
   //插件的国际化
   'Pull to refresh': 'Pull to refresh',

+ 6 - 0
packages/cs_resources/lib/local/language/vi_VN.dart

@@ -151,6 +151,12 @@ const Map<String, String> vi_VN = {
   'Alive State:': 'Tình trạng trực tuyến:',
   'Offline': 'Ngoại tuyến',
   'Online': 'Trực tuyến',
+  'Sort': 'Sắp xếp',
+  'Template': 'Mẫu',
+  'Updated At': 'Thời gian cập nhật',
+  'Add New': 'Thêm mới',
+  'Template Setting': 'Thiết lập mẫu',
+  'Enter Job Title': 'Nhập tên công việc',
 
   //插件的国际化
   "Pull to refresh": "Kéo để làm mới",

+ 6 - 0
packages/cs_resources/lib/local/language/zh_CN.dart

@@ -151,6 +151,12 @@ const Map<String, String> zh_CN = {
   'Alive State:': '在线状态:',
   'Offline': '离线',
   'Online': '在线',
+  'Sort': '排序',
+  'Template': '模板',
+  'Updated At': '更新时间',
+  'Add New': '新增',
+  'Template Setting': '模板设置',
+  'Enter Job Title': '请输入工作标题',
 
   //插件的国际化
   'Pull to refresh': '下拉刷新',

+ 9 - 0
packages/cs_router/lib/componentRouter/component_router_service.dart

@@ -1,6 +1,8 @@
 import 'package:get/get.dart';
 import 'package:router/componentRouter/auth_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 'job_service.dart';
 import 'report_service.dart';
@@ -30,4 +32,11 @@ class ComponentRouterServices{
   //获取 Auth 组件服务
   static AuthService get authService => Get.find();
 
+  //获取 Job 组件的服务 (新加坡)
+  static JobSGService get jobSGService => Get.find();
+
+  //获取 Labour 组件的服务 (新加坡)
+  static LabourSGService get labourSGService => Get.find();
+
+
 }

+ 11 - 0
packages/cs_router/lib/componentRouter/job_sg_service.dart

@@ -0,0 +1,11 @@
+
+/**
+ * Job组件对应的路由抽象接口 (新加坡)
+ */
+abstract class JobSGService {
+
+  void startJobListPage();
+
+  void startReviseListPage();
+
+}

+ 11 - 0
packages/cs_router/lib/componentRouter/labour_sg_service.dart

@@ -0,0 +1,11 @@
+
+/**
+ * Labour组件对应的路由抽象接口 (新加坡)
+ */
+abstract class LabourSGService {
+
+  void startLabourRequestPage();
+
+  void startJobTitlePage();
+
+}

+ 12 - 6
packages/cs_router/lib/path/router_path.dart

@@ -19,12 +19,12 @@ class RouterPath {
 
   //工作-列表
   static const JOB_LIST = '/job/list';
-  static const JOB_LIST_DETAIL = '/job/list/detail';  //查看工作的详情
-  static const JOB_APPLIED_STAFF_LIST = '/job/applied';  //指定工作中已申请的成员列表
-  static const JOB_APPLIED_STAFF_EDIT = '/job/applied/edit';  //指定工作中已申请的指定员工的信息修改(签到签出等修改)
-  static const JOB_APPLIED_STAFF_WORKFLOW = '/job/applied/workflow';  //指定工作中已申请的指定员工的信息与状态修改工作流
-  static const JOB_APPLIED_STAFF_DETAIL = '/job/applied/staff/detail';  //工作中员工的详细信息
-  static const JOB_APPLIED_STAFF_REVIEWS = '/job/applied/staff/reviews';  //工作中员工的被评价列表
+  static const JOB_LIST_DETAIL = '/job/list/detail'; //查看工作的详情
+  static const JOB_APPLIED_STAFF_LIST = '/job/applied'; //指定工作中已申请的成员列表
+  static const JOB_APPLIED_STAFF_EDIT = '/job/applied/edit'; //指定工作中已申请的指定员工的信息修改(签到签出等修改)
+  static const JOB_APPLIED_STAFF_WORKFLOW = '/job/applied/workflow'; //指定工作中已申请的指定员工的信息与状态修改工作流
+  static const JOB_APPLIED_STAFF_DETAIL = '/job/applied/staff/detail'; //工作中员工的详细信息
+  static const JOB_APPLIED_STAFF_REVIEWS = '/job/applied/staff/reviews'; //工作中员工的被评价列表
 
   //用工请求
   static const JOB_LABOUR_REQUEST_LIST = '/labour/list'; //用工请求列表
@@ -35,7 +35,13 @@ class RouterPath {
   //其他模块和报表模块
   static const DEVICE_LIST = '/device/list'; //雇主绑定的设备列表
 
+  //新加坡的用工请求
+  static const JOB_TITLE_LIST_SG = '/job/title/list/sg'; //模板的工作标题列表
+  static const JOB_TEMPLATE_LIST_SG = '/job/template/list/sg'; //模板列表
+  static const JOB_TEMPLATE_ADD_SG = '/job/template/add/sg'; //模板添加
 
+  //新加坡的工作列表
+  static const JOB_LIST_SG = '/job/list/sg'; //工作列表(新加坡)
 
   //全局其他
   static const PREVIEW_IMAGE = '/preview/image'; //预览图片