Browse Source

工作标题与模版的完成

liukai 7 months ago
parent
commit
fefbe01159
27 changed files with 1425 additions and 121 deletions
  1. 1 1
      packages/cpt_auth/lib/modules/login/login_page.dart
  2. 2 2
      packages/cpt_job/lib/modules/job_applied_edit/job_applied_edit_page.dart
  3. 124 1
      packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_controller.dart
  4. 337 6
      packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_page.dart
  5. 58 3
      packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_state.dart
  6. 7 0
      packages/cpt_labour_sg/lib/modules/job_template_list/add_edit_template.dart
  7. 193 0
      packages/cpt_labour_sg/lib/modules/job_template_list/job_template_item.dart
  8. 212 1
      packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_controller.dart
  9. 142 4
      packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_page.dart
  10. 11 3
      packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_state.dart
  11. 8 2
      packages/cpt_labour_sg/lib/modules/job_title_list/job_title_add_dialog.dart
  12. 47 81
      packages/cpt_labour_sg/lib/modules/job_title_list/job_title_item.dart
  13. 61 6
      packages/cpt_labour_sg/lib/modules/job_title_list/job_title_list_controller.dart
  14. 4 3
      packages/cpt_labour_sg/lib/modules/job_title_list/job_title_list_page.dart
  15. 2 0
      packages/cs_domain/lib/entity/response/job_template_s_g_entity.dart
  16. 2 0
      packages/cs_domain/lib/entity/response/job_title_s_g_entity.dart
  17. 9 1
      packages/cs_domain/lib/generated/json/job_template_s_g_entity.g.dart
  18. 9 1
      packages/cs_domain/lib/generated/json/job_title_s_g_entity.g.dart
  19. 2 2
      packages/cs_domain/lib/repository/labour_sg_repository.dart
  20. BIN
      packages/cs_resources/assets/base_service/check_box_checked.webp
  21. BIN
      packages/cs_resources/assets/base_service/check_box_uncheck.webp
  22. 2 0
      packages/cs_resources/lib/generated/assets.dart
  23. 24 0
      packages/cs_resources/lib/local/language/en_US.dart
  24. 24 0
      packages/cs_resources/lib/local/language/vi_VN.dart
  25. 24 0
      packages/cs_resources/lib/local/language/zh_CN.dart
  26. 102 0
      packages/cs_widgets/lib/shatter/custom_check_box.dart
  27. 18 4
      packages/cs_widgets/lib/custom_radio_check.dart

+ 1 - 1
packages/cpt_auth/lib/modules/login/login_page.dart

@@ -14,12 +14,12 @@ import 'package:router/path/router_path.dart';
 import 'package:shared/utils/device_utils.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/screen_util.dart';
-import 'package:widgets/custom_radio_check.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_button.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_field.dart';
 import 'package:widgets/my_text_view.dart';
+import 'package:widgets/shatter/custom_radio_check.dart';
 import 'package:widgets/widget_export.dart';
 import 'login_controller.dart';
 import 'login_state.dart';

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

@@ -4,12 +4,12 @@ import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:get/get.dart';
-import 'package:widgets/custom_radio_check.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_button.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/no_shadow_scroll_behavior.dart';
+import 'package:widgets/shatter/custom_radio_check.dart';
 import 'package:widgets/shatter/form_require_text.dart';
 import 'package:widgets/shatter/round_my_text_field.dart';
 import 'package:widgets/widget_export.dart';
@@ -434,7 +434,7 @@ class _JobAppliedEditState extends BaseState<JobAppliedEditPage, JobAppliedEditC
                         isFontRegular: true,
                       ),
 
-                      //选择签到功能还是全功能
+                      //理由的单
                       state.appliedEditView != null
                           ? CustomRadioCheck(
                               options: state.appliedEditView!.reasonList!.map((e) => e.txt).whereType<String>().toList(), //后台返回的数据展示,并且根据后台的数据匹配索引

+ 124 - 1
packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_controller.dart

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

+ 337 - 6
packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_page.dart

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

+ 58 - 3
packages/cpt_labour_sg/lib/modules/job_template_add/job_template_add_state.dart

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

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

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

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

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

+ 212 - 1
packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_controller.dart

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

+ 142 - 4
packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_page.dart

@@ -1,16 +1,154 @@
+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_template_item.dart';
 import 'job_template_list_controller.dart';
 
-class JobTemplateListPage extends StatelessWidget {
+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_template_list_state.dart';
+
+class JobTemplateListPage extends BaseStatefulPage<JobTemplateListController> {
   JobTemplateListPage({Key? key}) : super(key: key);
 
-  final controller = Get.put(JobTemplateListController());
-  final state = Get.find<JobTemplateListController>().state;
+  //启动当前页面
+  static void startInstance() {
+    return Get.start(RouterPath.JOB_TEMPLATE_LIST_SG);
+  }
+
+  @override
+  JobTemplateListController createRawController() {
+    return JobTemplateListController();
+  }
+
+  @override
+  State<JobTemplateListPage> createState() => _JobTemplateListState();
+
+}
+
+class _JobTemplateListState extends BaseState<JobTemplateListPage, JobTemplateListController> {
+
+  late JobTemplateListState state;
+
+  @override
+  void initState() {
+    super.initState();
+    state = controller.state;
+  }
 
   @override
   Widget build(BuildContext context) {
-    return Container();
+    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: 'Template Name'.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();
+                      controller.gotoTemplateAddPage();
+                    },
+                    text: "Add New".tr,
+                    textColor: ColorConstants.white,
+                    fontSize: 16,
+                    radius: 20,
+                    backgroundColor: hexToColor("#FFBB1B"),
+                    fontWeight: FontWeight.w500,
+                  ).expanded(),
+                ],
+              ).marginOnly(left: 15,right: 15,top: 15,bottom: 10),
+
+              //底部的列表
+              EasyRefresh(
+                controller: controller.refreshController,
+                onRefresh: controller.onRefresh,
+                onLoad: controller.loadMore,
+                child: LoadStateLayout(
+                  state: controller.loadingState,
+                  errorMessage: controller.errorMessage,
+                  errorRetry: () {
+                    controller.retryRequest();
+                  },
+                  successSliverWidget: [
+                    SliverList(
+                        delegate: SliverChildBuilderDelegate(
+                              (context, index) {
+                            return JobTemplateItem(
+                              index: index,
+                              item: state.datas[index],
+                              onEditAction: () {
+                                controller.gotoEditPage(state.datas[index].id.toString());
+                              },
+                              onDeleteAction: () {
+                                controller.deleteJobTitle(index);
+                              },
+                            );
+                          },
+                          childCount: state.datas.length,
+                        ))
+                  ],
+                ),
+              ).expanded(),
+            ],
+          ),
+        ),
+      );
+    });
   }
 }
+

+ 11 - 3
packages/cpt_labour_sg/lib/modules/job_template_list/job_template_list_state.dart

@@ -1,5 +1,13 @@
+import 'package:domain/entity/response/job_template_s_g_entity.dart';
+import 'package:flutter/material.dart';
+
 class JobTemplateListState {
-  JobTemplateListState() {
-    ///Initialize variables
-  }
+
+  //筛选条件
+  final TextEditingController searchController = TextEditingController();
+  String keyword = "";
+
+  //页面的列表数据
+  List<JobTemplateSGRows> datas = [];
+
 }

+ 8 - 2
packages/cpt_labour_sg/lib/modules/job_title_list/job_title_add_dialog.dart

@@ -27,7 +27,7 @@ import 'package:widgets/widget_export.dart';
 class AddJobTitleDialog extends StatefulWidget {
   JobTitleEditIndexEntity? editIndexEntity;
 
-  void Function(String jobTitle, String templateId, String sort)? confirmAction;
+  void Function(String jobTitleId, String jobTitle, String templateId, String sort)? confirmAction;
 
   AddJobTitleDialog({this.editIndexEntity, this.confirmAction});
 
@@ -51,8 +51,14 @@ class _AddJobTitleDialogState extends State<AddJobTitleDialog> {
     template = widget.editIndexEntity?.template.firstWhere((element) => element?.selected == 'selected', orElse: () => null);
     sort = widget.editIndexEntity?.sort.toString();
     jobTitleController = TextEditingController();
+    if (Utils.isNotEmpty(jobTitle)) {
+      jobTitleController.text = jobTitle!;
+    }
     jobTitleFocusNode = FocusNode();
     sortController = TextEditingController();
+    if (Utils.isNotEmpty(sort)) {
+      sortController.text = sort!;
+    }
     sortFocusNode = FocusNode();
   }
 
@@ -305,6 +311,6 @@ class _AddJobTitleDialogState extends State<AddJobTitleDialog> {
       return;
     }
 
-    widget.confirmAction?.call(jobTitle, template?.value.toString() ?? "", sort);
+    widget.confirmAction?.call(widget.editIndexEntity?.titleId.toString() ?? "", jobTitle, template?.value.toString() ?? "", sort);
   }
 }

+ 47 - 81
packages/cpt_labour_sg/lib/modules/job_title_list/job_title_item.dart

@@ -12,13 +12,13 @@ import 'package:widgets/my_text_view.dart';
 /**
  * 用工请求的主页面列表Item
  */
-class LabourRequestItem extends StatelessWidget {
+class JobTitleListItem extends StatelessWidget {
   final int index;
   final JobTitleSGRows item;
   final VoidCallback? onDeleteAction;
   final VoidCallback? onEditAction;
 
-  LabourRequestItem({
+  JobTitleListItem({
     required this.index,
     required this.item,
     this.onDeleteAction,
@@ -146,85 +146,51 @@ class LabourRequestItem extends StatelessWidget {
           ).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),
-          // ),
+          Visibility(
+            visible: item.actionList.isNotEmpty,
+            child: Row(
+              mainAxisSize: MainAxisSize.max,
+              mainAxisAlignment: MainAxisAlignment.end,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                //编辑按钮
+                Visibility(
+                  visible: item.actionList.contains("edit"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onEditAction?.call();
+                    },
+                    text: "Edit".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textGreen0AC074,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+
+                //删除按钮
+                Visibility(
+                  visible: item.actionList.contains("delete"),
+                  child: MyButton(
+                    onPressed: () {
+                      FocusScope.of(context).unfocus();
+                      onDeleteAction?.call();
+                    },
+                    text: "Delete".tr,
+                    textColor: ColorConstants.white,
+                    backgroundColor: ColorConstants.textRedFF6262,
+                    radius: 17.25,
+                    minWidth: 60,
+                    minHeight: 35,
+                  ).marginOnly(left: 12),
+                ),
+              ],
+            ).marginOnly(top: 18, bottom: 2),
+
+          ),
+
         ],
       ),
     );

+ 61 - 6
packages/cpt_labour_sg/lib/modules/job_title_list/job_title_list_controller.dart

@@ -6,9 +6,11 @@ import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
 import 'package:plugin_platform/engine/notify/notify_engine.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:plugin_platform/http/dio/dio_cancelable_mixin.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
 import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/widget_export.dart';
 
+import '../job_template_list/job_template_list_page.dart';
 import 'job_title_add_dialog.dart';
 import 'job_title_list_state.dart';
 
@@ -141,12 +143,12 @@ class JobTitleListController extends GetxController with DioCancelableMixin {
 
       if (result.isSuccess) {
         state.jobAddIndexEntity = result.data;
-        _showAddNewDialog(state.jobAddIndexEntity);
+        _showAddNewDialog(state.jobAddIndexEntity, false);
       } else {
         ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
       }
     } else {
-      _showAddNewDialog(state.jobAddIndexEntity);
+      _showAddNewDialog(state.jobAddIndexEntity, false);
     }
   }
 
@@ -155,19 +157,23 @@ class JobTitleListController extends GetxController with DioCancelableMixin {
     var result = await _labourRepository.fetchJobTitleEditIndex(titleId, cancelToken: cancelToken);
 
     if (result.isSuccess) {
-      _showAddNewDialog(result.data);
+      _showAddNewDialog(result.data, true);
     } else {
       ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
     }
   }
 
   // 展示新增或者编辑的弹窗
-  void _showAddNewDialog(JobTitleEditIndexEntity? entity) {
+  void _showAddNewDialog(JobTitleEditIndexEntity? entity, bool isEdit) {
     DialogEngine.show(
       widget: AddJobTitleDialog(
         editIndexEntity: entity,
-        confirmAction: (jobTitle, templateId, sort) {
-          _requestAddJobTitle(jobTitle, templateId, sort);
+        confirmAction: (jobTitleId, jobTitle, templateId, sort) {
+          if (isEdit) {
+            _requestEditJobTitle(jobTitleId, jobTitle, templateId, sort);
+          } else {
+            _requestAddJobTitle(jobTitle, templateId, sort);
+          }
         },
       ),
     );
@@ -185,6 +191,54 @@ class JobTitleListController extends GetxController with DioCancelableMixin {
     }
   }
 
+  // 请求接口编辑工作标题
+  void _requestEditJobTitle(String jobTitleId, String jobTitle, String? templateId, String? sort) async {
+    var result = await _labourRepository.editJobTitleSubmit(jobTitleId, jobTitle, sort, templateId, cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+      fetchItemByIdAndRefreshItem(jobTitleId);
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
+  // 去模板列表页面
+  void gotoTemplateListPage() {
+    JobTemplateListPage.startInstance();
+  }
+
+  // 删除JobTitle的逻辑
+  void deleteJobTitle(int index) {
+    DialogEngine.show(
+        widget: AppDefaultDialog(
+      title: "Confirmation".tr,
+      message: "Are you sure you want to delete this job title?".tr,
+      confirmAction: () {
+        _requestDeactivate(index);
+      },
+    ));
+  }
+
+  // 请求接口删除JobTitle
+  void _requestDeactivate(int index) async {
+    final item = state.datas[index];
+    var result = await _labourRepository.deleteJobTitleSubmit(item.id.toString(), cancelToken: cancelToken);
+
+    if (result.isSuccess) {
+      NotifyEngine.showSuccess("Successful".tr);
+
+      if (state.datas.length <= 1) {
+        refreshController.callRefresh();
+      } else {
+        state.datas.removeAt(index);
+        update();
+      }
+    } else {
+      ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
+    }
+  }
+
   /// 根据ID获取Item对象,用于刷新
   void fetchItemByIdAndRefreshItem(String ids) async {
     var result = await _labourRepository.fetchJobTitleListByIds(
@@ -215,4 +269,5 @@ class JobTitleListController extends GetxController with DioCancelableMixin {
       ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
     }
   }
+
 }

+ 4 - 3
packages/cpt_labour_sg/lib/modules/job_title_list/job_title_list_page.dart

@@ -102,6 +102,7 @@ class _JobTitleListState extends BaseState<JobTitleListPage, JobTitleListControl
                     milliseconds: 500,
                     onPressed: () {
                       FocusScope.of(context).unfocus();
+                      controller.gotoTemplateListPage();
                     },
                     text: "Template Setting".tr,
                     textColor: ColorConstants.white,
@@ -142,14 +143,14 @@ class _JobTitleListState extends BaseState<JobTitleListPage, JobTitleListControl
                     SliverList(
                         delegate: SliverChildBuilderDelegate(
                               (context, index) {
-                            return LabourRequestItem(
+                            return JobTitleListItem(
                               index: index,
                               item: state.datas[index],
                               onEditAction: () {
-                                // controller.gotoJobDetailPage(state.datas[index]);
+                               controller.requireEditDialog(state.datas[index].id.toString());
                               },
                               onDeleteAction: () {
-                                // controller.gotoJobAppliedPage(state.datas[index]);
+                                controller.deleteJobTitle(index);
                               },
                             );
                           },

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

@@ -32,6 +32,8 @@ class JobTemplateSGRows {
 	String? createdAt = null;
 	@JSONField(name: "updated_at")
 	String? updatedAt = null;
+	@JSONField(name: "action_list")
+	List<String> actionList = [];
 
 	JobTemplateSGRows();
 

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

@@ -32,6 +32,8 @@ class JobTitleSGRows {
 	String? createdAt = null;
 	@JSONField(name: "updated_at")
 	String? updatedAt = null;
+	@JSONField(name: "action_list")
+	List<String> actionList = [];
 
 	JobTitleSGRows();
 

+ 9 - 1
packages/cs_domain/lib/generated/json/job_template_s_g_entity.g.dart

@@ -63,6 +63,11 @@ JobTemplateSGRows $JobTemplateSGRowsFromJson(Map<String, dynamic> json) {
   if (updatedAt != null) {
     jobTemplateSGRows.updatedAt = updatedAt;
   }
+  final List<String>? actionList = (json['action_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<String>(e) as String).toList();
+  if (actionList != null) {
+    jobTemplateSGRows.actionList = actionList;
+  }
   return jobTemplateSGRows;
 }
 
@@ -75,6 +80,7 @@ Map<String, dynamic> $JobTemplateSGRowsToJson(JobTemplateSGRows entity) {
   data['note'] = entity.note;
   data['created_at'] = entity.createdAt;
   data['updated_at'] = entity.updatedAt;
+  data['action_list'] = entity.actionList;
   return data;
 }
 
@@ -87,6 +93,7 @@ extension JobTemplateSGRowsExtension on JobTemplateSGRows {
     String? note,
     String? createdAt,
     String? updatedAt,
+    List<String>? actionList,
   }) {
     return JobTemplateSGRows()
       ..id = id ?? this.id
@@ -95,6 +102,7 @@ extension JobTemplateSGRowsExtension on JobTemplateSGRows {
       ..contactNo = contactNo ?? this.contactNo
       ..note = note ?? this.note
       ..createdAt = createdAt ?? this.createdAt
-      ..updatedAt = updatedAt ?? this.updatedAt;
+      ..updatedAt = updatedAt ?? this.updatedAt
+      ..actionList = actionList ?? this.actionList;
   }
 }

+ 9 - 1
packages/cs_domain/lib/generated/json/job_title_s_g_entity.g.dart

@@ -59,6 +59,11 @@ JobTitleSGRows $JobTitleSGRowsFromJson(Map<String, dynamic> json) {
   if (updatedAt != null) {
     jobTitleSGRows.updatedAt = updatedAt;
   }
+  final List<String>? actionList = (json['action_list'] as List<dynamic>?)?.map(
+          (e) => jsonConvert.convert<String>(e) as String).toList();
+  if (actionList != null) {
+    jobTitleSGRows.actionList = actionList;
+  }
   return jobTitleSGRows;
 }
 
@@ -70,6 +75,7 @@ Map<String, dynamic> $JobTitleSGRowsToJson(JobTitleSGRows entity) {
   data['sort'] = entity.sort;
   data['created_at'] = entity.createdAt;
   data['updated_at'] = entity.updatedAt;
+  data['action_list'] = entity.actionList;
   return data;
 }
 
@@ -81,6 +87,7 @@ extension JobTitleSGRowsExtension on JobTitleSGRows {
     int? sort,
     String? createdAt,
     String? updatedAt,
+    List<String>? actionList,
   }) {
     return JobTitleSGRows()
       ..id = id ?? this.id
@@ -88,6 +95,7 @@ extension JobTitleSGRowsExtension on JobTitleSGRows {
       ..templateName = templateName ?? this.templateName
       ..sort = sort ?? this.sort
       ..createdAt = createdAt ?? this.createdAt
-      ..updatedAt = updatedAt ?? this.updatedAt;
+      ..updatedAt = updatedAt ?? this.updatedAt
+      ..actionList = actionList ?? this.actionList;
   }
 }

+ 2 - 2
packages/cs_domain/lib/repository/labour_sg_repository.dart

@@ -61,7 +61,7 @@ class LabourSGRepository extends GetxService {
     params["page_size"] = "9999";
 
     if (!Utils.isEmpty(ids)) {
-      params["ids"] = ids!;
+      params["job_title_id"] = ids!;
     }
 
     final result = await httpProvider.requestNetResult(
@@ -275,7 +275,7 @@ class LabourSGRepository extends GetxService {
     params["page_size"] = "9999";
 
     if (!Utils.isEmpty(ids)) {
-      params["ids"] = ids!;
+      params["job_temp_id"] = ids!;
     }
 
     final result = await httpProvider.requestNetResult(

BIN
packages/cs_resources/assets/base_service/check_box_checked.webp


BIN
packages/cs_resources/assets/base_service/check_box_uncheck.webp


+ 2 - 0
packages/cs_resources/lib/generated/assets.dart

@@ -8,6 +8,8 @@ class Assets {
   static const String baseLibDialogDeleteIcon = 'assets/base_lib/dialog_delete_icon.webp';
   static const String baseLibImageDefaultPlaceholder = 'assets/base_lib/image_default_placeholder.png';
   static const String baseLibWhiteBack = 'assets/base_lib/white_back.webp';
+  static const String baseServiceCheckBoxChecked = 'assets/base_service/check_box_checked.webp';
+  static const String baseServiceCheckBoxUncheck = 'assets/base_service/check_box_uncheck.webp';
   static const String baseServiceDialogDeleteIcon = 'assets/base_service/dialog_delete_icon.webp';
   static const String baseServiceItemSelectedIcon = 'assets/base_service/item_selected_icon.webp';
   static const String baseServiceItemUnselectedGrayIcon = 'assets/base_service/item_unselected_gray_icon.webp';

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

@@ -157,6 +157,30 @@ const Map<String, String> en_US = {
   'Add New': 'Add New',
   'Template Setting': 'Template Setting',
   'Enter Job Title': 'Enter Job Title',
+  'Template Name': 'Template Name',
+  'Contact': 'Contact',
+  'Note': 'Note',
+  'Delete': 'Delete',
+  'Are you sure you want to delete this job title?': 'Are you sure you want to delete this job title?',
+  'Are you sure you want to delete this job template?': 'Are you sure you want to delete this job template?',
+  'Age': 'Age',
+  'Gender': 'Gender',
+  'Preferred Language': 'Preferred Language',
+  'Food Hygiene Cert': 'Food Hygiene Cert',
+  'Yes': 'Yes',
+  'No': 'No',
+  'Description': 'Description',
+  'Contact No': 'Contact No',
+  'Create Template': 'Create Template',
+  'Edit Template': 'Edit Template',
+  'Both': 'Both',
+  'Male': 'Male',
+  'Female': 'Female',
+  'English': 'English',
+  'Chinese': 'Chinese',
+  'Malay': 'Malay',
+  'Tamil': 'Tamil',
+  'Hindi': 'Hindi',
 
   //插件的国际化
   'Pull to refresh': 'Pull to refresh',

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

@@ -157,6 +157,30 @@ const Map<String, String> vi_VN = {
   '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',
+  'Template Name': 'Tên mẫu',
+  'Contact': 'Liên hệ',
+  'Note': 'Lưu ý',
+  'Delete': 'Xoá',
+  'Are you sure you want to delete this job title?': 'Bạn có chắc chắn muốn xóa bài đăng này?',
+  'Are you sure you want to delete this job template?': 'Bạn có chắc chắn muốn xóa template này?',
+  'Age': 'Tuổi',
+  'Gender': 'Giới tính',
+  'Preferred Language': 'Ngôn ngữ ưa thích',
+  'Food Hygiene Cert': 'Giấy chứng nhận vệ sinh thực phẩm',
+  'Yes': 'Vâng.',
+  'No': 'Không',
+  'Description': 'Mô tả',
+  'Contact No': 'Số điện thoại',
+  'Create Template': 'Tạo mẫu',
+  'Edit Template': 'Sửa mẫu',
+  'Both': 'Cả hai',
+  'Male': 'Việt',
+  'Female': 'Phụ nữ',
+  'English': 'Tiếng Việt',
+  'Chinese': 'Trung Quốc',
+  'Malay': 'Tiếng Việt',
+  'Tamil': 'Thái Lan',
+  'Hindi': 'Tiếng Hindi',
 
   //插件的国际化
   "Pull to refresh": "Kéo để làm mới",

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

@@ -157,6 +157,30 @@ const Map<String, String> zh_CN = {
   'Add New': '新增',
   'Template Setting': '模板设置',
   'Enter Job Title': '请输入工作标题',
+  'Template Name': '模板名称',
+  'Contact': '联系人',
+  'Note': '注意事项',
+  'Delete': '删除',
+  'Are you sure you want to delete this job title?': '你确定要删除此工作标题吗?',
+  'Are you sure you want to delete this job template?': '你确定要删除此工作模板吗?',
+  'Age': '年龄',
+  'Gender': '性别',
+  'Preferred Language': '首选语言',
+  'Food Hygiene Cert': '食品卫生证书',
+  'Yes': '是',
+  'No': '否',
+  'Description': '详情',
+  'Contact No': '联系电话',
+  'Create Template': '创建模板',
+  'Edit Template': '编辑模板',
+  'Both': '全部',
+  'Male': '男',
+  'Female': '女',
+  'English': '英文',
+  'Chinese': '中文',
+  'Malay': '马来语',
+  'Tamil': '泰米尔语',
+  'Hindi': '印地语',
 
   //插件的国际化
   'Pull to refresh': '下拉刷新',

+ 102 - 0
packages/cs_widgets/lib/shatter/custom_check_box.dart

@@ -0,0 +1,102 @@
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:cs_resources/generated/assets.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get_utils/get_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+
+class CustomCheckBox extends StatefulWidget {
+  final List<String> options;
+  final Function(List<int> selectedIndexes) onOptionsSelected; // 选中项的索引回调
+  final List<String> selectedOptions; // 已选中的选项列表
+
+  CustomCheckBox({
+    required this.options,
+    required this.onOptionsSelected,
+    required this.selectedOptions,
+  });
+
+  @override
+  _CustomCheckBoxState createState() => _CustomCheckBoxState();
+}
+
+class _CustomCheckBoxState extends State<CustomCheckBox> {
+  late List<String> _selectedOptions;
+  late List<int> _selectedIndexes;
+
+  @override
+  void initState() {
+    super.initState();
+    _initializeSelectedOptions();
+  }
+
+  void _initializeSelectedOptions() {
+    _selectedOptions = List.from(widget.selectedOptions);
+    _selectedIndexes =
+        widget.options.asMap().entries.where((entry) => _selectedOptions.contains(entry.value)).map((entry) => entry.key).toList(); // 根据选项匹配初始化索引
+  }
+
+  @override
+  void didUpdateWidget(CustomCheckBox oldWidget) {
+    super.didUpdateWidget(oldWidget);
+    if (oldWidget.selectedOptions != widget.selectedOptions) {
+      _initializeSelectedOptions();
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Wrap(
+      spacing: 15.0,
+      runSpacing: 15.0,
+      children: widget.options.asMap().entries.map((entry) {
+        int index = entry.key;
+        String option = entry.value;
+        return _buildCheckBoxWithIconAndText(
+          path: _selectedIndexes.contains(index) ? Assets.baseServiceCheckBoxChecked : Assets.baseServiceCheckBoxUncheck,
+          text: option,
+          value: _selectedIndexes.contains(index),
+          onChanged: (isChecked) {
+            setState(() {
+              if (isChecked) {
+                if (!_selectedOptions.contains(option)) {
+                  _selectedOptions.add(option);
+                  _selectedIndexes.add(index);
+                }
+              } else {
+                _selectedOptions.remove(option);
+                _selectedIndexes.remove(index);
+              }
+              widget.onOptionsSelected(_selectedIndexes);
+            });
+          },
+        );
+      }).toList(),
+    );
+  }
+
+  Widget _buildCheckBoxWithIconAndText({
+    required String path,
+    required String text,
+    required bool value,
+    required Function(bool) onChanged,
+  }) {
+    return Row(
+      mainAxisSize: MainAxisSize.min,
+      children: <Widget>[
+        MyAssetImage(path, width: 20.5, height: 20.5),
+        SizedBox(width: 10),
+        MyTextView(
+          text.tr,
+          textColor: ColorConstants.white,
+          fontSize: 14,
+          isFontRegular: true,
+        ),
+      ],
+    ).onTap(() {
+      onChanged(!value); // 点击时切换选中状态
+    });
+  }
+}

+ 18 - 4
packages/cs_widgets/lib/custom_radio_check.dart

@@ -7,6 +7,9 @@ import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 
+/**
+ * 条件单选 Radio
+ */
 class CustomRadioCheck extends StatefulWidget {
   final List<String> options;
   int? selectedPosition;
@@ -28,20 +31,31 @@ class _CustomRadioCheckState extends State<CustomRadioCheck> {
   @override
   void initState() {
     super.initState();
-    // 初始化 _selectedOption
+    _initializeSelectedOption();
+  }
+
+  void _initializeSelectedOption() {
     if (widget.selectedPosition != null && widget.selectedPosition! >= 0 && widget.selectedPosition! < widget.options.length) {
       _selectedOption = widget.options[widget.selectedPosition!];
     } else {
-      // 默认选择第一个选项,如果 selectedPosition 不在有效范围内
       _selectedOption = widget.options.isNotEmpty ? widget.options[0] : null;
     }
   }
 
   @override
+  void didUpdateWidget(CustomRadioCheck oldWidget) {
+    super.didUpdateWidget(oldWidget);
+    // 如果 selectedPosition 发生变化,重新初始化选中项
+    if (oldWidget.selectedPosition != widget.selectedPosition) {
+      _initializeSelectedOption();
+    }
+  }
+
+  @override
   Widget build(BuildContext context) {
     return Wrap(
-      spacing: 8.0, // 水平间距
-      runSpacing: 8.0, // 垂直间距
+      spacing: 8.0,
+      runSpacing: 8.0,
       children: widget.options.map((option) {
         return _buildRadioWithIconAndText(
           path: option == _selectedOption ? Assets.cptAuthLoginRadioChecked : Assets.cptAuthLoginRadioUncheck,