Bladeren bron

template 和 lab-req 增加相关字段

glglove 1 week geleden
bovenliggende
commit
c1e28b8213
30 gewijzigde bestanden met toevoegingen van 1783 en 286 verwijderingen
  1. 133 0
      packages/cpt_uk/lib/modules/job/labour_request_add/labour_request_add_controller.dart
  2. 44 0
      packages/cpt_uk/lib/modules/job/labour_request_add/labour_request_add_state.dart
  3. 141 52
      packages/cpt_uk/lib/modules/job/labour_request_add/widget/lab_request_and_request_review_form.dart
  4. 142 0
      packages/cpt_uk/lib/modules/job/labour_request_add/widget/labour_request_interface.dart
  5. 440 0
      packages/cpt_uk/lib/modules/job/labour_request_add/widget/uploadFileField.dart
  6. 49 11
      packages/cpt_uk/lib/modules/job/template_add/template_add_controller.dart
  7. 45 26
      packages/cpt_uk/lib/modules/job/template_add/template_add_page.dart
  8. 8 0
      packages/cpt_uk/lib/modules/job/template_add/template_add_state.dart
  9. 6 3
      packages/cpt_uk/lib/modules/job/template_list/item_template.dart
  10. 4 4
      packages/cpt_uk/lib/modules/job/template_list/template_list_controller.dart
  11. 2 2
      packages/cpt_uk/lib/modules/job/template_list/template_list_state.dart
  12. 122 0
      packages/cpt_uk/lib/modules/review/labour_review_edit/labour_review_edit_controller.dart
  13. 33 0
      packages/cpt_uk/lib/modules/review/labour_review_edit/labour_review_edit_state.dart
  14. 0 49
      packages/cs_domain/lib/entity/response/u_k_template_entity.dart
  15. 1 0
      packages/cs_domain/lib/entity/response/uk_job_template_detail_by_select_title_entity.dart
  16. 13 4
      packages/cs_domain/lib/entity/response/uk_labour_request_detail_entity.dart
  17. 24 0
      packages/cs_domain/lib/entity/response/uk_template_detail_entity.dart
  18. 20 0
      packages/cs_domain/lib/entity/response/uk_template_detail_index_entity.dart
  19. 53 0
      packages/cs_domain/lib/entity/response/uk_template_table_entity.dart
  20. 25 11
      packages/cs_domain/lib/generated/json/base/json_convert_content.dart
  21. 0 109
      packages/cs_domain/lib/generated/json/u_k_template_entity.g.dart
  22. 7 0
      packages/cs_domain/lib/generated/json/uk_job_template_detail_by_select_title_entity.g.dart
  23. 44 8
      packages/cs_domain/lib/generated/json/uk_labour_request_detail_entity.g.dart
  24. 69 2
      packages/cs_domain/lib/generated/json/uk_template_detail_entity.g.dart
  25. 54 1
      packages/cs_domain/lib/generated/json/uk_template_detail_index_entity.g.dart
  26. 126 0
      packages/cs_domain/lib/generated/json/uk_template_table_entity.g.dart
  27. 22 4
      packages/cs_domain/lib/repository/uk_job_repository.dart
  28. 142 0
      packages/cs_domain/lib/repository/uk_labour_repository.dart
  29. 7 0
      packages/cs_resources/lib/local/language/en_US.dart
  30. 7 0
      packages/cs_resources/lib/local/language/zh_CN.dart

+ 133 - 0
packages/cpt_uk/lib/modules/job/labour_request_add/labour_request_add_controller.dart

@@ -1,6 +1,7 @@
 import 'dart:io';
 
 import 'package:cpt_uk/modules/job/labour_request_add/widget/labour_request_interface.dart';
+import 'package:cpt_uk/modules/job/labour_request_add/widget/uploadFileField.dart';
 import 'package:domain/entity/response/uk_labour_request_detail_entity.dart';
 import 'package:domain/repository/labour_repository.dart';
 import 'package:domain/repository/uk_job_repository.dart';
@@ -73,6 +74,32 @@ class LabourRequestAddController extends GetxController with DioCancelableMixin
       state.jobSelectJobStart = state.labReqOption?.jobStart?? '';
       state.jobSelectJobEnd = state.labReqOption?.jobEnd?? '';
 
+      state.videoText = state.labReqOption?.videoText?? '';
+      state.videoCover = state.labReqOption?.videoCover?? '';
+      state.video = state.labReqOption?.video?? '';
+      state.otherImage = state.labReqOption?.otherImage?? '';
+      state.otherDocument = state.labReqOption?.otherDocument?? '';
+      // 修改 state.uploadFieldList 对应的 fieldPathValueList
+      state.uploadFieldList.forEach((element) {
+        if (element.fieldKey == 'video_cover_key') {
+          element.fieldPathValueList?.clear();
+          element.fieldPathValueList?.add(state.videoCover ?? '');
+          Log.d("video_cover 初始值  ${element.fieldPathValueList}");
+        }
+        if (element.fieldKey == 'video_video_key') {
+          element.fieldPathValueList?.clear();
+          element.fieldPathValueList?.add(state.video ?? '');
+        }
+        if (element.fieldKey == 'video_image_key') {
+          element.fieldPathValueList?.clear();
+          element.fieldPathValueList?.add(state.otherImage ?? '');
+        }
+        if (element.fieldKey == 'video_document_key') {
+          element.fieldPathValueList?.clear();
+          element.fieldPathValueList?.add(state.otherDocument ?? '');
+        }
+      });
+
       if(state.pageType == 0){
         // 新增
         state.noStaff = '';
@@ -96,6 +123,7 @@ class LabourRequestAddController extends GetxController with DioCancelableMixin
       var revenueController = state.formData['revenue']!['controller'];
       var positionController = state.formData['position']!['controller'];
       var totalCostController = state.formData['total_cost']!['controller'];
+
       remarkController.text = state.labReqOption?.description ?? '';
       eventController.text = state.labReqOption?.eventName ?? "";
       eventTypeController.text = state.labReqOption?.eventType ?? "";
@@ -104,6 +132,9 @@ class LabourRequestAddController extends GetxController with DioCancelableMixin
       positionController.text = state.labReqOption?.position ?? "";
       totalCostController.text = state.labReqOption?.estCost ?? "";
 
+      var vidoeTextController = state.formData['video_text']!['controller'];
+      vidoeTextController.text = state.videoText??'';
+
 
       state.selectedDepartmentId = state.labReqOption?.departmentId.toString();
       //时薪还是房间计费
@@ -118,6 +149,85 @@ class LabourRequestAddController extends GetxController with DioCancelableMixin
   @override
   void onReady() {
     super.onReady();
+    state.uploadFieldList = [
+      FileFieldItem(
+        fieldKey: 'video_cover_key',
+        fieldLabel: 'Video Cover'.tr,
+        fieldPathValueList: [''],
+        fieldPlaceholder: "Choose".tr,
+        maxSize: '10MB',
+        allowedFileTypes: ['jpg', 'png', 'jpeg'],  // 'mp4', 'jpg', 'png', 'jpeg', 'pdf', 'docx'
+        multiple: false,
+        preview: false,
+        download: false, // 启用下载功能
+        disabled: false,
+        onFilesSelected: (List<File> files) {
+          print("选中的文件: ${files}");
+          // print("选中的文件: ${files.length}个");
+          if(files.length>0){
+            state.videoCover = files[0].path;
+            update();
+          }
+        }
+      ),
+      FileFieldItem(
+        fieldKey: 'video_video_key',
+        fieldLabel: 'Video'.tr,
+        fieldPathValueList: [''],
+        fieldPlaceholder: "Choose".tr,
+        maxSize: '20MB',
+        allowedFileTypes: ['mp4'],  // 'mp4', 'jpg', 'png', 'jpeg', 'pdf', 'docx'
+        multiple: false,
+        preview: false,
+        download: false, // 启用下载功能
+        disabled: false,
+        onFilesSelected: (List<File> files) {
+          print("选中的文件: ${files}");
+          if(files.length>0){
+            state.video = files[0].path;
+            update();
+          }
+        },
+      ),
+      FileFieldItem(
+        fieldKey: 'video_image_key',
+        fieldLabel: 'Video Image'.tr,
+        fieldPathValueList: [''],
+        fieldPlaceholder: "Choose".tr,
+        maxSize: '10MB',
+        allowedFileTypes: ['jpg', 'png', 'jpeg'],  // 'mp4', 'jpg', 'png', 'jpeg', 'pdf', 'docx'
+        multiple: false,
+        preview: false,
+        download: false, // 启用下载功能
+        disabled: false,
+        onFilesSelected: (List<File> files) {
+          print("选中的文件: ${files}");
+          if(files.length>0){
+            state.otherImage = files[0].path;
+            update();
+          }
+        },
+      ),
+      FileFieldItem(
+        fieldKey: 'video_document_key',
+        fieldLabel: 'Video Document'.tr,
+        fieldPathValueList: [''],
+        fieldPlaceholder: "Choose".tr,
+        maxSize: '10MB',
+        allowedFileTypes: ['pdf','docx', 'doc'],  // 'mp4', 'jpg', 'png', 'jpeg', 'pdf', 'docx','doc'
+        multiple: false,
+        preview: false,
+        download: false, // 启用下载功能
+        disabled: false,
+        onFilesSelected: (List<File> files) {
+          print("选中的文件: ${files}");
+          if(files.length>0){
+            state.otherDocument = files[0].path;
+            update();
+          }
+        },
+      ),
+    ];
     fetchRequestDetail();
   }
 
@@ -147,6 +257,9 @@ class LabourRequestAddController extends GetxController with DioCancelableMixin
     String totalCost = totalCostController.text.toString();
     String remark = remarkController.text.toString();
 
+    var videoTextController = state.formData['video_text']!['controller'];
+    String videoText = videoTextController.text.toString();
+
     // Log.d("89328392  ${state.selectedTypeId}");
     // Log.d("89328392  ${state.selectedTypeId.runtimeType}");
     if (Utils.isEmpty(state.selectedTemplateId)) {
@@ -195,6 +308,11 @@ class LabourRequestAddController extends GetxController with DioCancelableMixin
         "position": position,
         "estCost": totalCost,
         "attUrl": state.attFilePath,
+        "videoText": videoText,
+        "videoCover": state.videoCover,
+        "video": state.video,
+        "otherImage": state.otherImage,
+        "otherDocument": state.otherDocument,
         'cancelToken': cancelToken
       };
       // Log.d("编辑时 state.selectedCertificateList  ${state.selectedCertificateList}");
@@ -224,6 +342,11 @@ class LabourRequestAddController extends GetxController with DioCancelableMixin
         position: params['position'],
         estCost: params['estCost'],
         attUrl: params['attUrl'],
+        videoText: params['videoText'],
+        videoCover: params['videoCover'],
+        video: params['video'],
+        otherImage: params['otherImage'],
+        otherDocument: params['otherDocument'],
         cancelToken: params['cancelToken'],
       );
     } else {
@@ -250,6 +373,11 @@ class LabourRequestAddController extends GetxController with DioCancelableMixin
         "position": position,
         "estCost": totalCost,
         "attUrl": state.attFilePath,
+        "videoText": state.videoText,
+        "videoCover": state.videoCover,
+        "video": state.video,
+        "otherImage": state.otherImage,
+        "otherDocument": state.otherDocument,
         'cancelToken': cancelToken,
       };
       // Log.d("新增时准备提交的 params  ${params}");
@@ -277,6 +405,11 @@ class LabourRequestAddController extends GetxController with DioCancelableMixin
         position: params['position'],
         estCost: params['estCost'],
         attUrl: params['attUrl'],
+        videoText: params['videoText'],
+        videoCover: params['videoCover'],
+        video: params['video'],
+        otherImage: params['otherImage'],
+        otherDocument: params['otherDocument'],
         cancelToken: params['cancelToken'],
       );
     }

+ 44 - 0
packages/cpt_uk/lib/modules/job/labour_request_add/labour_request_add_state.dart

@@ -1,6 +1,7 @@
 import 'dart:io';
 
 import 'package:cpt_uk/modules/job/labour_request_add/widget/labour_request_interface.dart';
+import 'package:cpt_uk/modules/job/labour_request_add/widget/uploadFileField.dart';
 import 'package:domain/entity/response/uk_lab_req_show_template_entity.dart';
 import 'package:domain/entity/response/uk_labour_request_detail_entity.dart';
 import 'package:domain/entity/response/uk_labour_request_preselect_addstatff_list_entity.dart';
@@ -62,6 +63,7 @@ class LabourRequestAddState implements CommonLabourRequestState {
 
   String? chargeOptionId;
 
+  @override
   //表单的校验与数据
   Map<String, Map<String, dynamic>> formData = {
     'no_of_staff': {
@@ -127,16 +129,58 @@ class LabourRequestAddState implements CommonLabourRequestState {
       'hintText': 'Enter...'.tr,
       'obsecure': false,
     },
+    'video_text': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    }
   };
 
+  @override
   int get serviceType => labReqOption?.serviceType ?? 0;
+
+  @override
   List<UkLabourRequestDetailLocationList>? get locationList => labReqOption?.locationList;
+  @override
   List<UkLabourRequestDetailTemplateList>? get templateList => labReqOption?.templateList;
+  @override
   List<UkLabourRequestDetailDepartmentList>? get departmentList => labReqOption?.departmentList;
+  @override
   List<UkLabourRequestDetailChargeList>? get chargeList => labReqOption?.chargeList;
+  @override
   List<UkLabourRequestDetailEmploymentList>? get employmentList => labReqOption?.employmentList;
+  @override
   List<UkLabourRequestDetailCertificateList>? get certificateList => labReqOption?.certificateList;
+  @override
   List<UkLabourRequestDetailVehicleList>? get vehicleList => labReqOption?.vehicleList;
+  @override
   List<UkLabourRequestDetailChallenge25List>? get challenge25List => labReqOption?.challenge25List;
 
+
+  @override
+  String? videoText;
+
+  @override
+  dynamic? videoCover;
+
+  @override
+  dynamic? video;
+
+  @override
+  dynamic? otherImage;
+
+  @override
+  dynamic? otherDocument;
+
+
+  @override
+  String videoTips = '''
+    Video - video type (eg: mp4) and size 20MB
+    Document can be word/pdf,etc and the size 10MB
+    Cover、Image can be jpg,jpeg,png and the size 10MB.
+    ''';
+  @override
+  List<FileFieldItem> uploadFieldList = [];
 }

+ 141 - 52
packages/cpt_uk/lib/modules/job/labour_request_add/widget/lab_request_and_request_review_form.dart

@@ -1,3 +1,6 @@
+import 'dart:io';
+
+import 'package:cpt_uk/modules/job/labour_request_add/widget/uploadFileField.dart';
 import 'package:cs_resources/constants/color_constants.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:domain/entity/response/uk_labour_request_detail_entity.dart';
@@ -323,7 +326,7 @@ class CommonLabourRequestFormFields extends StatelessWidget {
               },
               selectedPosition: state.challenge25List?.indexWhere((e) => e.checked == "checked") ?? -1,
           ).marginOnly(left: 0, right: 15, top: 10),
-    ),
+        ),
 
         // Vehicle  交通工具
         MyTextView(
@@ -564,59 +567,14 @@ class CommonLabourRequestFormFields extends StatelessWidget {
           },
         ),
 
-        //输入Remark
-        MyTextView(
-          "Remark".tr,
-          fontSize: 15,
-          isFontRegular: true,
-          textColor: Colors.white,
-          marginTop: 15,
-        ),
-
-        IgnoreKeyboardDismiss(
-          child: Container(
-            height: 160,
-            margin: const EdgeInsets.only(top: 10),
-            padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
-            decoration: BoxDecoration(
-              color: const Color(0xFF4DCFF6).withOpacity(isDetailAction == 2 ? 0.5 : 0.2),
-              borderRadius: const BorderRadius.all(Radius.circular(5)),
-            ),
-            child: TextField(
-              cursorColor: ColorConstants.white,
-              cursorWidth: 1.5,
-              autofocus: false,
-              enabled: isAddAction || isEditAction,
-              focusNode: state.formData["remark"]!['focusNode'],
-              controller: state.formData["remark"]!['controller'],
-              // 装饰
-              decoration: InputDecoration(
-                isDense: true,
-                isCollapsed: true,
-                border: InputBorder.none,
-                hintText: state.formData["remark"]!['hintText'],
-                hintStyle: const TextStyle(
-                  color: ColorConstants.textGrayAECAE5,
-                  fontSize: 15.0,
-                  fontWeight: FontWeight.w400,
-                ),
-              ),
-              style: const TextStyle(
-                color: ColorConstants.white,
-                fontSize: 15.0,
-                fontWeight: FontWeight.w400,
-              ),
-              // 键盘动作右下角图标
-              textInputAction: TextInputAction.done,
-              onSubmitted: (value) {
-                FocusScope.of(context).unfocus();
-              },
-            ),
-          ),
-        ),
+          // //输入Remark
+          // _buildRemarkWidget(context, controller, isAddAction, isEditAction, isDetailAction),
 
         // 附件
-        _buildAttachFileWidget(context, controller, isAddAction, isEditAction, isDetailAction),
+        // _buildAttachFileWidget(context, controller, isAddAction, isEditAction, isDetailAction),
+
+        // 视频部分
+        _buildVideoSectionWidget(context, controller, isAddAction, isEditAction, isDetailAction),
 
         const SizedBox(height: 30),
 
@@ -933,6 +891,65 @@ class CommonLabourRequestFormFields extends StatelessWidget {
      );
   }
 
+  // remark
+  Widget _buildRemarkWidget(BuildContext context, CommonLabourRequestController controller,bool isAdd, bool isEdit, bool isDetail){
+    final state = controller.commonState;
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        MyTextView(
+          "Remark".tr,
+          fontSize: 15,
+          isFontRegular: true,
+          textColor: Colors.white,
+          marginTop: 15,
+        ),
+
+        IgnoreKeyboardDismiss(
+          child: Container(
+            height: 160,
+            margin: const EdgeInsets.only(top: 10),
+            padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15),
+            decoration: BoxDecoration(
+              color: const Color(0xFF4DCFF6).withOpacity(isDetail == 2 ? 0.5 : 0.2),
+              borderRadius: const BorderRadius.all(Radius.circular(5)),
+            ),
+            child: TextField(
+              cursorColor: ColorConstants.white,
+              cursorWidth: 1.5,
+              autofocus: false,
+              enabled: isAdd || isEdit,
+              focusNode: state.formData["remark"]!['focusNode'],
+              controller: state.formData["remark"]!['controller'],
+              // 装饰
+              decoration: InputDecoration(
+                isDense: true,
+                isCollapsed: true,
+                border: InputBorder.none,
+                hintText: state.formData["remark"]!['hintText'],
+                hintStyle: const TextStyle(
+                  color: ColorConstants.textGrayAECAE5,
+                  fontSize: 15.0,
+                  fontWeight: FontWeight.w400,
+                ),
+              ),
+              style: const TextStyle(
+                color: ColorConstants.white,
+                fontSize: 15.0,
+                fontWeight: FontWeight.w400,
+              ),
+              // 键盘动作右下角图标
+              textInputAction: TextInputAction.done,
+              onSubmitted: (value) {
+                FocusScope.of(context).unfocus();
+              },
+            ),
+          ),
+        ),
+      ],
+    );
+  }
+
   // 附件
   Widget _buildAttachFileWidget(BuildContext context, CommonLabourRequestController controller,bool isAdd, bool isEdit, bool isDetail){
     final state = controller.commonState;
@@ -993,4 +1010,76 @@ class CommonLabourRequestFormFields extends StatelessWidget {
       ],
     );
   }
+
+  // 视频部分
+  Widget _buildVideoSectionWidget(BuildContext context, CommonLabourRequestController controller,bool isAdd, bool isEdit, bool isDetail){
+    final state = controller.commonState;
+    String videoTips = state.videoTips;
+    List<FileFieldItem> uploadFieldList = state.uploadFieldList;
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        MyTextView(
+          "Video".tr,
+          fontSize: 15,
+          isFontRegular: true,
+          textColor: Colors.white,
+          marginTop: 15,
+        ),
+        MyTextView(
+          "${videoTips}",
+          fontSize: 12,
+          isFontRegular: true,
+          textColor: Colors.white,
+          marginTop: 5,
+        ),
+
+        // video Text
+        Container(
+          child: Column(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              MyTextView(
+                "Video Text".tr,
+                fontSize: 15,
+                isFontRegular: true,
+                textColor: Colors.white,
+              ),
+
+              CustomTextField(
+                formKey: "video_text",
+                marginLeft: 0,
+                marginRight: 0,
+                paddingTop: 0,
+                paddingBottom: 0,
+                marginTop: 10,
+                height: 45,
+                fillBackgroundColor: const Color(0xFF4DCFF6).withOpacity(isDetail? 0.5 : 0.2),
+                enabled: !isDetail,
+                textInputType: TextInputType.number,
+                formData: state.formData,
+                textInputAction: TextInputAction.done,
+                onSubmit: (key, value) {
+                  FocusScope.of(context).unfocus();
+                },
+              ),
+            ],
+          ),
+        ),
+
+        for(int i =0; i< uploadFieldList.length; i++)
+          // video cover
+          _buildUploadFileWidget(context, controller,isAdd, isEdit, isDetail, uploadFieldList[i], i)
+
+      ]
+    );
+  }
+
+  // 上传文件widget
+  Widget _buildUploadFileWidget(BuildContext context, CommonLabourRequestController controller,bool isAdd, bool isEdit, bool isDetail, FileFieldItem fileField, int index){
+    return UploadFileField(
+        fileField: fileField,
+    );
+  }
 }

+ 142 - 0
packages/cpt_uk/lib/modules/job/labour_request_add/widget/labour_request_interface.dart

@@ -1,3 +1,6 @@
+import 'dart:io';
+
+import 'package:cpt_uk/modules/job/labour_request_add/widget/uploadFileField.dart';
 import 'package:domain/entity/response/uk_labour_request_detail_entity.dart';
 import 'package:flutter/material.dart';
 import 'package:plugin_basic/basic_export.dart';
@@ -30,6 +33,138 @@ abstract class CommonLabourRequestState {
   List<UkLabourRequestDetailDepartmentList>? get departmentList;
   List<UkLabourRequestDetailChargeList>? get chargeList;
   List<UkLabourRequestDetailEmploymentList>? get employmentList;
+
+  // 视频相关
+  String videoTips = '''
+    Video - video type (eg: mp4) and size 20MB
+    Document can be word/pdf,etc and the size 10MB
+    Cover、Image can be jpg,jpeg,png and the size 10MB.
+    ''';
+  List<FileFieldItem> uploadFieldList = [
+    FileFieldItem(
+      fieldKey: 'video_cover_key',
+      fieldLabel: 'Cover',
+      fieldPathValueList: [""],
+      fieldPlaceholder: "Choose".tr,
+      maxSize: '10MB',
+      allowedFileTypes: ['jpg', 'png', 'jpeg'],  // 'mp4', 'jpg', 'png', 'jpeg', 'pdf', 'docx'
+      multiple: false,
+      preview: false,
+      download: false, // 启用下载功能
+      disabled: false,
+      onFilesSelected: (List<File> files) {
+        // print("选中的文件: ${files}");
+        // print("选中的文件: ${files.length}个");
+      },
+      onFileRemoved: (file) {
+        print("文件已移除: ${file.path}");
+      },
+      onFilePreview: (file) {
+        // 自定义预览逻辑
+        print("预览文件: ${file.path}");
+      },
+      onFileDownload: (file) {
+        // 自定义下载逻辑
+        print("下载文件: ${file.path}");
+      },
+    ),
+    FileFieldItem(
+      fieldKey: 'video_video_key',
+      fieldLabel: 'Video',
+      fieldPathValueList: [""],
+      fieldPlaceholder: "Choose".tr,
+      maxSize: '20MB',
+      allowedFileTypes: ['mp4'],  // 'mp4', 'jpg', 'png', 'jpeg', 'pdf', 'docx'
+      multiple: false,
+      preview: false,
+      download: false, // 启用下载功能
+      disabled: false,
+      onFilesSelected: (List<File> files) {
+        print("选中的文件: ${files}");
+        print("选中的文件: ${files.length}个");
+      },
+      onFileRemoved: (file) {
+        print("文件已移除: ${file.path}");
+      },
+      onFilePreview: (file) {
+        // 自定义预览逻辑
+        print("预览文件: ${file.path}");
+      },
+      onFileDownload: (file) {
+        // 自定义下载逻辑
+        print("下载文件: ${file.path}");
+        // 可以在这里集成实际的下载实现
+        // 例如使用 dio 下载文件到指定目录
+      },
+    ),
+    FileFieldItem(
+      fieldKey: 'video_image_key',
+      fieldLabel: 'Image',
+      fieldPathValueList: [""],
+      fieldPlaceholder: "Choose".tr,
+      maxSize: '10MB',
+      allowedFileTypes: ['jpg', 'png', 'jpeg'],  // 'mp4', 'jpg', 'png', 'jpeg', 'pdf', 'docx'
+      multiple: false,
+      preview: false,
+      download: false, // 启用下载功能
+      disabled: false,
+      onFilesSelected: (List<File> files) {
+        print("选中的文件: ${files}");
+        print("选中的文件: ${files.length}个");
+      },
+      onFileRemoved: (file) {
+        print("文件已移除: ${file.path}");
+      },
+      onFilePreview: (file) {
+        // 自定义预览逻辑
+        print("预览文件: ${file.path}");
+      },
+      onFileDownload: (file) {
+        // 自定义下载逻辑
+        print("下载文件: ${file.path}");
+        // 可以在这里集成实际的下载实现
+        // 例如使用 dio 下载文件到指定目录
+      },
+    ),
+    FileFieldItem(
+      fieldKey: 'video_document_key',
+      fieldLabel: 'Document',
+      fieldPathValueList: [""],
+      fieldPlaceholder: "Choose".tr,
+      maxSize: '10MB',
+      allowedFileTypes: ['pdf','docx', 'doc'],  // 'mp4', 'jpg', 'png', 'jpeg', 'pdf', 'docx','doc'
+      multiple: false,
+      preview: false,
+      download: false, // 启用下载功能
+      disabled: false,
+      onFilesSelected: (List<File> files) {
+        print("选中的文件: ${files}");
+        print("选中的文件: ${files.length}个");
+      },
+      onFileRemoved: (file) {
+        print("文件已移除: ${file.path}");
+      },
+      onFilePreview: (file) {
+        // 自定义预览逻辑
+        print("预览文件: ${file.path}");
+      },
+      onFileDownload: (file) {
+        // 自定义下载逻辑
+        print("下载文件: ${file.path}");
+        // 可以在这里集成实际的下载实现
+        // 例如使用 dio 下载文件到指定目录
+      },
+    ),
+  ];
+
+  String? videoText;
+  dynamic? videoCover;
+  dynamic? video;
+  dynamic? otherImage;
+  dynamic? otherDocument;
+
+
+
   List<UkLabourRequestDetailCertificateList>? get certificateList => labReqOption?.certificateList;
   List<UkLabourRequestDetailVehicleList>? get vehicleList => labReqOption?.vehicleList;
   List<UkLabourRequestDetailChallenge25List>? get challenge25List => labReqOption?.challenge25List;
@@ -99,6 +234,13 @@ abstract class CommonLabourRequestState {
       'hintText': 'Enter...'.tr,
       'obsecure': false,
     },
+    'video_text': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    }
   };
 }
 

+ 440 - 0
packages/cpt_uk/lib/modules/job/labour_request_add/widget/uploadFileField.dart

@@ -0,0 +1,440 @@
+// uploadFileField.dart
+import 'dart:io';
+import 'package:cs_resources/constants/color_constants.dart';
+import 'package:flutter/material.dart';
+import 'package:plugin_basic/basic_export.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:shared/utils/util.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_text_view.dart';
+import 'package:file_picker/file_picker.dart';
+
+class FileFieldItem {
+  final String fieldKey; // 字段key
+  final String? fieldLabel; // 文件字段名称
+  late List<String>? fieldPathValueList; // 文件字段值
+  final String? fieldPlaceholder; // 文件字段提示
+  final String? maxSize; // 文件大小限制 如 '500B' '1KB' ‘1MB’
+  final bool multiple; // 是否允许多文件上传
+  final bool canUpload; // 是否可上传
+  final bool disabled; // 是否禁用
+  final bool preview; // 是否可以点击预览
+  final bool download; // 是否可以下载
+  final List<String> allowedFileTypes; // 允许的文件类型
+  final Function(List<File>)? onFilesSelected; // 文件选择回调
+  final Function(File)? onFileRemoved; // 文件删除回调
+  final Function(File)? onFilePreview; // 文件预览回调
+  final Function(File)? onFileDownload; // 文件下载回调
+
+  FileFieldItem({
+    required this.fieldKey,
+    this.fieldLabel,
+    fieldPathValueList,
+    fieldPlaceholder,
+    this.maxSize,
+    multiple,
+    canUpload,
+    disabled,
+    preview,
+    download, // 默认不启用下载
+    allowedFileTypes,
+    this.onFilesSelected,
+    this.onFileRemoved,
+    this.onFilePreview,
+    this.onFileDownload,
+  }): this.fieldPathValueList = fieldPathValueList!=null?fieldPathValueList?.cast<String>()?? []: null,
+      this.fieldPlaceholder = fieldPlaceholder?? 'Choose File',
+      this.canUpload = canUpload?? true,
+      this.multiple = multiple?? false,
+      this.disabled = disabled?? false,
+      this.preview = preview?? false,
+      this.download = download?? false,
+      this.allowedFileTypes = allowedFileTypes ?? ['*'];
+}
+
+class UploadFileField extends StatefulWidget {
+  final FileFieldItem fileField;
+
+  const UploadFileField({
+    Key? key,
+    required this.fileField,
+  }) : super(key: key);
+
+  @override
+  _UploadFileFieldState createState() => _UploadFileFieldState();
+}
+
+class _UploadFileFieldState extends State<UploadFileField> {
+  String? _filedInputText;
+  List<File> _selectedFiles = [];
+  String? _errorMessage;
+
+  @override
+  void initState() {
+    super.initState();
+
+    if(widget.fileField.multiple){
+      // 多选
+      if(widget.fileField.fieldPathValueList!=null && widget.fileField.fieldPathValueList!.isNotEmpty){
+        _filedInputText = widget.fileField.fieldPathValueList!.map((url) {
+          if(url.isEmpty) return '';
+          try {
+            return Uri.parse(url).pathSegments.last;
+          } catch (e) {
+            return '';
+          }
+        }).where((element) => element.isNotEmpty).join(",");
+      }
+    }else {
+      // 单选
+      if (widget.fileField.fieldPathValueList != null &&
+          widget.fileField.fieldPathValueList!.isNotEmpty) {
+        try {
+          String firstUrl = widget.fileField.fieldPathValueList!.first;
+          if (firstUrl.isNotEmpty) {
+            _filedInputText = Uri.parse(firstUrl).pathSegments.last;
+          } else {
+            _filedInputText = "";
+          }
+        } catch (e) {
+          _filedInputText = "";
+        }
+      } else {
+        _filedInputText = "";
+      }
+    }
+  }
+
+  // 将大小字符串转换为字节 B
+  int _parseSizeToBytes(String maxSize) {
+    final RegExp regex = RegExp(r'(\d+)([KMGT]?B)', caseSensitive: false);
+    final match = regex.firstMatch(maxSize.toUpperCase());
+
+    if (match == null) return 0;
+
+    final number = int.parse(match.group(1)!);
+    final unit = match.group(2);
+
+    switch (unit) {
+      case 'KB':
+        return number * 1024;
+      case 'MB':
+        return number * 1024 * 1024;
+      case 'GB':
+        return number * 1024 * 1024 * 1024;
+      case 'TB':
+        return number * 1024 * 1024 * 1024 * 1024;
+      default:
+        return number;
+    }
+  }
+
+  void _pickFiles() async {
+    if (widget.fileField.disabled) return;
+
+    try {
+      FilePickerResult? result = await FilePicker.platform.pickFiles(
+        allowMultiple: widget.fileField.multiple,
+        type: FileType.custom,
+        //   allowedExtensions: widget.fileField.allowedFileTypes,
+        allowedExtensions: ['jpg', 'png', 'jpeg', 'pdf', 'docx','mp4'],
+      );
+
+      Log.d("--选取的文件结果----  ${result}");
+      if (result != null) {
+        if(!widget.fileField.multiple){
+          // 清空上次_selectedFiles
+          _selectedFiles = [];
+        }
+
+        List<PlatformFile> files = result.files;
+        _validateAndSetFiles(files);
+      }
+
+    } catch (e) {
+      setState(() {
+        _errorMessage = '文件选择失败';
+      });
+    }
+  }
+
+  void _validateAndSetFiles(List<PlatformFile> platFormFiles) {
+    Log.d("开始验证和设置文件--${platFormFiles}-");
+    setState(() {
+      _errorMessage = null;
+    });
+
+    Log.d("验证文件大小和类型----${widget.fileField.multiple}---");
+    // 检查是否超过最大文件数量
+    if (!widget.fileField.multiple && (_selectedFiles.length + platFormFiles.length) > 1) {
+      setState(() {
+        _errorMessage = '只允许上传一个文件';
+      });
+      return;
+    }
+
+    Log.d("检查文件大小和类型---类型:${widget.fileField.allowedFileTypes}----大小限制:${widget.fileField.maxSize}-");
+
+    // 检查文件类型
+    if (!widget.fileField.allowedFileTypes.contains('*')) {
+      bool allowTypeRes = _checkAllowFileType(platFormFiles);
+      Log.d("允许文件类型结果--${allowTypeRes}");
+      if (!allowTypeRes) {
+        ToastEngine.show("${_errorMessage}");
+        return;
+      }
+    }
+
+    Log.d("所有文件类型验证通过");
+
+    // 检查文件大小
+    if(widget.fileField.maxSize != null){
+      Log.d("开始检查文件大小");
+      final maxSize = _parseSizeToBytes(widget.fileField.maxSize!);
+      Log.d("文件大小限制字节数:${maxSize} B");
+      bool isAlLowFileSizeRes = _checkAllowFileSize(platFormFiles, maxSize);
+      Log.d("所有文件大小验证结果--${isAlLowFileSizeRes}");
+      if(!isAlLowFileSizeRes){
+        return;
+      }
+    }
+
+    setState(() {
+      List<File> files = platFormFiles.map((file) {
+        return File(file.path!);
+      }).toList();
+      if (widget.fileField.multiple) {
+        _selectedFiles.addAll(files);
+      } else {
+        _selectedFiles = files.take(1).toList();
+      }
+    });
+
+    Log.d("当前选中的文件:$_selectedFiles");
+    if(widget.fileField.multiple && !widget.fileField.disabled){
+      setState(() {
+        _filedInputText = _selectedFiles.map((file) {
+          return Uri.parse(file.path).pathSegments.last;
+        }).join(",");
+      });
+    }else {
+      setState(() {
+        _filedInputText = Uri.parse(_selectedFiles.first.path).pathSegments.last;
+      });
+    }
+    widget.fileField.onFilesSelected?.call(_selectedFiles);
+  }
+
+  // 检查文件大小
+  bool _checkAllowFileSize(List<PlatformFile> platFormFiles, int maxSize){
+    for (var platFormFile in platFormFiles) {
+      // 检查文件大小
+      if (platFormFile.size > maxSize) {
+        setState(() {
+          _errorMessage = '文件大小超过限制 (${widget.fileField.maxSize})';
+        });
+        return false;
+      }
+    }
+    Log.d("文件大小检查通过---");
+    return true;
+  }
+
+  // 检查文件类型
+  bool _checkAllowFileType(List<PlatformFile> platFormFiles){
+    for (var platFormFile in platFormFiles) {
+      String filePath = platFormFile.path!;
+      String fileName = filePath.substring(filePath.lastIndexOf("/") + 1);
+      String fileSuffix = fileName.substring(fileName.lastIndexOf(".") + 1);
+      // 截取文件后缀进行判断
+      if (!widget.fileField.allowedFileTypes.contains(fileSuffix)) {
+        setState(() {
+          _errorMessage = "文件类型错误,请选择${widget.fileField.allowedFileTypes.join(",")}文件";
+        });
+        return false;
+      }
+    }
+    Log.d("文件类型检查通过---");
+    return true;
+  }
+
+  void _removeFile(File file) {
+    setState(() {
+      _selectedFiles.remove(file);
+      _errorMessage = null;
+    });
+    widget.fileField.onFileRemoved?.call(file);
+  }
+
+  void _previewFile(File file) {
+    if (!widget.fileField.preview || widget.fileField.disabled) return;
+
+    // 如果有自定义预览回调,使用回调
+    if (widget.fileField.onFilePreview != null) {
+      widget.fileField.onFilePreview!(file);
+      return;
+    }
+
+    // 默认预览行为 - 显示一个简单的预览对话框
+    _showDefaultPreview(file);
+  }
+
+  void _downloadFile(File file) {
+    if (!widget.fileField.download || widget.fileField.disabled) return;
+
+    // 如果有自定义下载回调,使用回调
+    if (widget.fileField.onFileDownload != null) {
+      widget.fileField.onFileDownload!(file);
+      return;
+    }
+
+    // 默认下载行为
+    _showDefaultDownload(file);
+  }
+
+  void _showDefaultPreview(File file) {
+    showDialog(
+      context: context,
+      builder: (BuildContext context) {
+        return AlertDialog(
+          title: Text(file.path.split('/').last),
+          content: SizedBox(
+            width: double.maxFinite,
+            child: Column(
+              mainAxisSize: MainAxisSize.min,
+              children: [
+                const Icon(Icons.insert_drive_file, size: 60, color: Colors.blue),
+                const SizedBox(height: 16),
+                Text('文件路径: ${file.path}'),
+                Text('文件大小: ${(file.lengthSync() / 1024).toStringAsFixed(2)} KB'),
+              ],
+            ),
+          ),
+          actions: [
+            TextButton(
+              onPressed: () => Navigator.of(context).pop(),
+              child: const Text('关闭'),
+            ),
+          ],
+        );
+      },
+    );
+  }
+
+  void _showDefaultDownload(File file) {
+    // 下载
+    // ScaffoldMessenger.of(context).showSnackBar(
+    //   SnackBar(
+    //     content: Text('开始下载文件: ${file.path.split('/').last}'),
+    //     duration: const Duration(seconds: 2),
+    //   ),
+    // );
+
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        //附件文件
+        MyTextView(
+          widget.fileField.fieldLabel??'-',
+          fontSize: 15,
+          isFontRegular: true,
+          textColor: Colors.white,
+          marginTop: 15,
+        ),
+
+        // 显示和选择附件
+        Container(
+          padding: const EdgeInsets.only(left: 16),
+          margin: const EdgeInsets.only(top: 10),
+          height: 45,
+          decoration: BoxDecoration(
+            color: const Color(0xFF4DCFF6).withOpacity(widget.fileField.disabled ? 0.5 : 0.2),
+            borderRadius: const BorderRadius.all(Radius.circular(5)),
+          ),
+          child: Row(
+            mainAxisSize: MainAxisSize.max,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            mainAxisAlignment: MainAxisAlignment.start,
+            children: [
+              MyTextView(
+                '${_filedInputText}',
+                fontSize: 14,
+                hint: "Choose File".tr,
+                textHintColor: ColorConstants.textGrayAECAE5,
+                isFontMedium: true,
+                textColor: ColorConstants.white,
+              ).expanded(),
+
+              // 上传附件的图标
+              Visibility(
+                visible: widget.fileField.canUpload && !widget.fileField.disabled,
+                child: MyTextView(
+                  'Upload'.tr,
+                  boxHeight: 45,
+                  textAlign: TextAlign.center,
+                  boxWidth: 90,
+                  cornerRadius: 5,
+                  onClick: _pickFiles,
+                  textColor: Colors.white,
+                  fontSize: 15,
+                  fontWeight: FontWeight.w400,
+                  backgroundColor: ColorConstants.textGreen0AC074,
+                ),
+              ),
+            ],
+          ),
+        ),
+      ],
+    );
+
+  }
+
+  Widget _buildFileItem(File file) {
+    return Container(
+      margin: const EdgeInsets.only(bottom: 4),
+      child: Row(
+        children: [
+          const Icon(Icons.insert_drive_file, size: 16, color: Colors.blue),
+          const SizedBox(width: 8),
+          Expanded(
+            child: GestureDetector(
+              onTap: () => _previewFile(file),
+              child: Text(
+                file.path.split('/').last,
+                style: TextStyle(
+                  fontSize: 14,
+                  color: widget.fileField.preview && !widget.fileField.disabled
+                      ? Colors.blue
+                      : Colors.black,
+                  decoration: widget.fileField.preview && !widget.fileField.disabled
+                      ? TextDecoration.underline
+                      : TextDecoration.none,
+                ),
+                overflow: TextOverflow.ellipsis,
+              ),
+            ),
+          ),
+          if (widget.fileField.download && !widget.fileField.disabled)
+            IconButton(
+              icon: const Icon(Icons.download, size: 18, color: Colors.green),
+              onPressed: () => _downloadFile(file),
+              padding: const EdgeInsets.all(0),
+              constraints: const BoxConstraints(),
+            ),
+          if (!widget.fileField.disabled)
+            IconButton(
+              icon: const Icon(Icons.delete, size: 18, color: Colors.red),
+              onPressed: () => _removeFile(file),
+              padding: const EdgeInsets.all(0),
+              constraints: const BoxConstraints(),
+            ),
+        ],
+      ),
+    );
+  }
+}

+ 49 - 11
packages/cpt_uk/lib/modules/job/template_add/template_add_controller.dart

@@ -79,12 +79,13 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
     if (result.isSuccess) {
       UkJobTemplateDetailBySelectTitleEntity? resultData = result.data;
       // var templateNameController = state.formData['template_name']!['controller'];
+      var clientNameController = state.formData['client_name']!['controller'];
       var descController = state.formData['desc']!['controller'];
       var noteController = state.formData['note']!['controller'];
       var contactNameController = state.formData['contact_name']!['controller'];
       var contactNoController = state.formData['contact_no']!['controller'];
 
-
+      clientNameController.text = resultData?.client ?? "";
       descController.text = resultData?.requirements ?? "";
       noteController.text = resultData?.note ?? "";
       contactNameController.text = resultData?.contact ?? "";
@@ -98,7 +99,6 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
           .map((s) => int.tryParse(s) ?? 0)
           .toList();
 
-
       if (jobCertificateList.isNotEmpty) {
         state.indexOptionEntity?.certificateList?.forEach((cerItem) {
           if (jobCertificateList.contains(cerItem.value)) {
@@ -107,6 +107,16 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
         });
       }
 
+      // challenge25 回显
+      state.selectedChallenge25Id = resultData?.challenge25?.toString()??'';
+      if(Utils.isNotEmpty(state.selectedChallenge25Id)){
+        state.indexOptionEntity?.challenge25List?.forEach((challenge25Item) {
+          if (state.selectedChallenge25Id == challenge25Item.value?.toString()) {
+            challenge25Item.checked = "checked";
+          }
+        });
+      }
+
       // 交通工具回显
       List<String> jobVechicleList = (resultData?.jobVehicle ?? '')
           .split(',')
@@ -121,10 +131,6 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
         });
       }
 
-      //回显
-      _handlerCertificateEcho();
-      _handlerVehicleEcho();
-
       //刷新
       update();
     } else {
@@ -145,22 +151,24 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
         _fetchJobTitleOptionsList();
       }
 
+      var clientNameController = state.formData['client_name']!['controller'];
       var descController = state.formData['desc']!['controller'];
       var noteController = state.formData['note']!['controller'];
       var contactNameController = state.formData['contact_name']!['controller'];
       var contactNoController = state.formData['contact_no']!['controller'];
 
 
+      clientNameController.text = state.indexEntity?.row?.clientName ?? "";
       descController.text = state.indexEntity?.row?.description ?? "";
       noteController.text = state.indexEntity?.row?.note ?? "";
       contactNameController.text = state.indexEntity?.row?.contactName ?? "";
       contactNoController.text = state.indexEntity?.row?.contactNo ?? "";
 
-      Log.d("获取详情后的 state.selectedJobTemplateStr---- ${state.selectedJobTemplateStr}");
-
-      Log.d("获取详情后的 state.indexEntity?.row---- ${state.indexEntity?.row}");
-      Log.d("645646  ${state.selectedJobTitleStr}");
-      Log.d("89389   ${state.selectedJobTitleId}");
+      // Log.d("获取详情后的 state.selectedJobTemplateStr---- ${state.selectedJobTemplateStr}");
+      //
+      // Log.d("获取详情后的 state.indexEntity?.row---- ${state.indexEntity?.row}");
+      // Log.d("645646  ${state.selectedJobTitleStr}");
+      // Log.d("89389   ${state.selectedJobTitleId}");
       // 将 state.indexEntity?.certificateList  与 state.indexOptionEntity 进行对比 将 checked 复制给
       state.indexEntity?.certificateList?.forEach((e) {
         var option = state.indexOptionEntity?.certificateList?.firstWhere((option) => option.value == e.value, orElse: () => UkTemplateDetailIndexCertificateList());
@@ -169,6 +177,14 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
         }
       });
 
+      // 将state.indexEntity?.challenge25 与 state.index.OptionEntity 进行对比 修改对应checked
+      state.indexEntity?.challenge25List?.forEach((e) {
+        var option = state.indexOptionEntity?.challenge25List?.firstWhere((option) => option.value == e.value, orElse: () => UkTemplateDetailIndexChallenge25List());
+        if (option != null) {
+          option.checked = e.checked;
+        }
+      });
+
       // 将 state.indexEntity?.vehicleList  与 state.indexOptionEntity 进行对比 将 checked 复制给
       state.indexEntity?.vehicleList?.forEach((e) {
         var option = state.indexOptionEntity?.vehicleList?.firstWhere((option) => option.value == e.value, orElse: () => UkTemplateDetailIndexVehicleList());
@@ -178,6 +194,7 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
       });
 
       // 回显
+      _handlerChallenge25Echo();
       _handlerCertificateEcho();
       _handlerVehicleEcho();
 
@@ -195,16 +212,19 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
     if (result.isSuccess) {
       state.indexOptionEntity = result.data;
       state.selectedJobTemplateStr = state.indexEntity?.templateTitle ?? "";
+      var clientNameController = state.formData['client_name']!['controller'];
       var descController = state.formData['desc']!['controller'];
       var noteController = state.formData['note']!['controller'];
       var contactNameController = state.formData['contact_name']!['controller'];
       var contactNoController = state.formData['contact_no']!['controller'];
+      clientNameController.text =  "";
       descController.text =  "";
       noteController.text =  "";
       contactNameController.text =  "";
       contactNoController.text =  "";
 
       //回显
+      _handlerChallenge25Echo();
       _handlerCertificateEcho();
       _handlerVehicleEcho();
 
@@ -215,6 +235,17 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
     }
   }
 
+  // 回显 challenge25
+  void _handlerChallenge25Echo(){
+    //默认CheckBox
+    state.selectedChallenge25Id = state.indexOptionEntity?.challenge25List
+        ?.where((e) => e.checked == "checked")
+        .map((e) => e.value!.toString())
+        .toList()?.first ?? "";
+    Log.d("当前的challenge25: ${state.indexOptionEntity?.challenge25List}");
+    Log.d("当前选中的challenge25:${state.selectedChallenge25Id}");
+  }
+
   // 回显 certificate
   void _handlerCertificateEcho(){
     //默认CheckBox
@@ -320,7 +351,9 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
 
   /// 提交
   void doSubmit() async {
+    Log.d("提交时  state.selectedCertificateList ${state.selectedCertificateList}");
 
+    var clientNameController = state.formData['client_name']!['controller'];
     var descController = state.formData['desc']!['controller'];
     var noteController = state.formData['note']!['controller'];
     var contactNameController = state.formData['contact_name']!['controller'];
@@ -330,6 +363,7 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
 
     String jobTemplate = state.selectedJobTemplateStr?? "";
     String jobTitle = state.selectedJobTitleStr??"";
+    String clientName = clientNameController.text.toString();
     String desc = descController.text.toString();
     String note = noteController.text.toString();
     String contactName = contactNameController.text.toString();
@@ -353,8 +387,10 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
         templateId: state.templateId?.toString()??'',
         jobTemplateId: state.selectedJobTitleId?.toString()??'',
         jobTitle: jobTitle,
+        clientName: clientName,
         certificate: state.selectedCertificateList,
         vehicle: state.selectedVehicleList,
+        challenge25: state.selectedChallenge25Id,
         desc: desc,
         note: note,
         contactName: contactName,
@@ -366,8 +402,10 @@ class TemplateAddController extends GetxController with DioCancelableMixin {
       taskFuture = _labourRepository.addJobTemplateSubmit(
         jobTemplateId: state.selectedJobTitleId?.toString()??'',
         jobTitle: state.selectedJobTitleStr?? '',
+        clientName: clientName,
         certificate: state.selectedCertificateList,
         vehicle: state.selectedVehicleList,
+        challenge25: state.selectedChallenge25Id,
         desc: desc,
         note: note,
         contactName: contactName,

+ 45 - 26
packages/cpt_uk/lib/modules/job/template_add/template_add_page.dart

@@ -14,6 +14,7 @@ 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_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';
@@ -102,32 +103,24 @@ class _LabourTemplateAddState extends BaseState<UKTemplateAddPage, TemplateAddCo
                       child: Column(
                         crossAxisAlignment: CrossAxisAlignment.start,
                         children: [
-
+                          // 模板
                           _buildTemplateSelectWidget(),
+                          // 工作标题
                           _buildTemplateJobTitleWidget(),
 
-                          // if(isEdit)
-                          //   //模板名称
-                          //   ...[
-                          //     FormRequireText(text: "Template Title".tr).marginOnly(left: 15, top: 19),
-                          //     CustomTextField(
-                          //       formKey: "template_name",
-                          //       formData: state.formData,
-                          //       height: 46,
-                          //       fontSize: 14,
-                          //       enabled: isAdd ? true:false,
-                          //       onSubmit: (key, value) {
-                          //         state.formData[key]!['focusNode'].unfocus();
-                          //         FocusScope.of(context).requestFocus(state.formData['desc']!['focusNode']);
-                          //       },
-                          //       marginTop: 10,
-                          //     )
-                          //   ],
-                          // if(isAdd)
-                          //   ...[
-                          //     _buildTemplateSelectWidget(),
-                          //     _buildTemplateJobTitleWidget(),
-                          //   ],
+                          // 名称
+                          FormRequireText(text: "Name".tr, isRequired: false,).marginOnly(left: 15, top: 19),
+                          CustomTextField(
+                            formKey: "client_name",
+                            formData: state.formData,
+                            height: 46,
+                            fontSize: 14,
+                            onSubmit: (key, value) {
+                              state.formData[key]!['focusNode'].unfocus();
+                              FocusScope.of(context).requestFocus(state.formData['contact_name']!['focusNode']);
+                            },
+                            marginTop: 10,
+                          ),
 
 
                           //证书
@@ -152,15 +145,39 @@ class _LabourTemplateAddState extends BaseState<UKTemplateAddPage, TemplateAddCo
                                 // 转换选中的索引为对应的 value
                                 state.selectedCertificateList = selected
                                     .map((index) {
-                                      return state.indexOptionEntity?.certificateList?[index].value; // 获取对应的 value
+                                      return state.indexOptionEntity?.certificateList?[index].value?.toString(); // 获取对应的 value
                                     })
                                     .whereType<String>()
                                     .toList();
+                                // Log.d("选择的证书  ${state.selectedCertificateList}");
+
                               },
                               selectedOptions: state.indexOptionEntity?.certificateList?.where((e) => e.checked == "checked").map((e) => e.txt!).toList() ?? [],
                             ).marginOnly(left: 15, right: 15, top: 10),
                           ),
 
+
+                          // challenge25
+                          MyTextView(
+                            "Challenge25".tr,
+                            textColor: Colors.white,
+                            fontSize: 14,
+                            isFontRegular: true,
+                            marginLeft: 15,
+                            marginTop: 15,
+                          ),
+
+                          // challenge25 radiobox
+                          Visibility(
+                            child: CustomRadioCheck(
+                              options: state.indexOptionEntity?.challenge25List?.map((e) => e.txt!).toList() ?? [],
+                              onOptionSelected: (index, text) {
+                                state.selectedChallenge25Id = state.indexOptionEntity?.challenge25List![index].value?.toString()??'';
+                              },
+                              selectedPosition: state.indexOptionEntity?.challenge25List?.indexWhere((e) => e.checked == "checked") ?? -1,
+                            ).marginOnly(left: 15, right: 15, top: 10),
+                          ),
+
                           // 交通工具
                           MyTextView(
                             "Vehicle".tr,
@@ -180,10 +197,11 @@ class _LabourTemplateAddState extends BaseState<UKTemplateAddPage, TemplateAddCo
                                 // 转换选中的索引为对应的 value
                                 state.selectedVehicleList = selected
                                     .map((index) {
-                                  return state.indexOptionEntity?.vehicleList?[index].value; // 获取对应的 value
+                                  return state.indexOptionEntity?.vehicleList?[index].value?.toString(); // 获取对应的 value
                                 })
                                     .whereType<String>()
                                     .toList();
+                                // Log.d("选择的车辆  ${state.selectedVehicleList}");
                               },
                               selectedOptions: state.indexOptionEntity?.vehicleList?.where((e) => e.checked == "checked").map((e) => e.txt!).toList() ?? [],
                             ).marginOnly(left: 15, right: 15, top: 10),
@@ -380,7 +398,7 @@ class _LabourTemplateAddState extends BaseState<UKTemplateAddPage, TemplateAddCo
         crossAxisAlignment: CrossAxisAlignment.start,
         children: [
           // template 模板
-          FormRequireText(text: "Template".tr).marginOnly(top: 15),
+          FormRequireText(text: "Industry".tr).marginOnly(top: 15),
           //选择template
           Container(
             padding: const EdgeInsets.only(left: 16, right: 10),
@@ -456,4 +474,5 @@ class _LabourTemplateAddState extends BaseState<UKTemplateAddPage, TemplateAddCo
       ),
     );
   }
+
 }

+ 8 - 0
packages/cpt_uk/lib/modules/job/template_add/template_add_state.dart

@@ -15,6 +15,13 @@ class LabourTemplateAddState {
       'hintText': 'Enter...'.tr,
       'obsecure': false,
     },
+    'client_name': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    },
     'contact_name': {
       'value': '',
       'controller': TextEditingController(),
@@ -70,4 +77,5 @@ class LabourTemplateAddState {
 
   List<String> selectedCertificateList = [];   //选中的 age 的 id
   List<String> selectedVehicleList = [];   //选中的 language 的 id
+  String? selectedChallenge25Id; // 选中的 challenge25 的 id
 }

+ 6 - 3
packages/cpt_uk/lib/modules/job/template_list/item_template.dart

@@ -1,19 +1,21 @@
 import 'package:cs_resources/constants/color_constants.dart';
-import 'package:domain/entity/response/u_k_template_entity.dart';
+import 'package:domain/entity/response/uk_template_table_entity.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/widgets.dart';
 import 'package:plugin_basic/basic_export.dart';
+import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_button.dart';
 import 'package:widgets/my_text_view.dart';
+import 'package:widgets/shatter/custom_radio_check.dart';
 
 /*
  * 用工请求的主页面列表Item
  */
 class TemplateItem extends StatelessWidget {
   final int index;
-  final UKTemplateRows item;
+  final UkTemplateTableRows item;
   final VoidCallback? onDeleteAction;
   final VoidCallback? onEditAction;
 
@@ -49,7 +51,7 @@ class TemplateItem extends StatelessWidget {
                 fontSize: 14,
               ),
               MyTextView(
-                item.jobTitle ?? "-",
+                "${item.jobTitle} ${Utils.isNotEmpty(item.clientName)? '-${item.clientName}':''}",
                 marginLeft: 5,
                 isFontMedium: true,
                 textColor: Colors.white,
@@ -104,6 +106,7 @@ class TemplateItem extends StatelessWidget {
             ],
           ).marginOnly(top: 14),
 
+
           // 联系人
           Row(
             mainAxisSize: MainAxisSize.max,

+ 4 - 4
packages/cpt_uk/lib/modules/job/template_list/template_list_controller.dart

@@ -1,5 +1,5 @@
-import 'package:domain/entity/response/job_template_s_g_entity.dart';
-import 'package:domain/entity/response/u_k_template_entity.dart';
+
+import 'package:domain/entity/response/uk_template_table_entity.dart';
 import 'package:domain/repository/uk_job_repository.dart';
 import 'package:get/get.dart';
 import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
@@ -76,7 +76,7 @@ class TemplateListController extends GetxController with DioCancelableMixin {
   }
 
   // 处理数据与展示的逻辑
-  void handleList(List<UKTemplateRows>? list) {
+  void handleList(List<UkTemplateTableRows>? list) {
     if (list != null && list.isNotEmpty) {
       //有数据,判断是刷新还是加载更多的数据
       if (_curPage == 1) {
@@ -168,7 +168,7 @@ class TemplateListController extends GetxController with DioCancelableMixin {
   // 请求接口删除JobTitle
   void _requestDeactivate(int index) async {
     final item = state.datas[index];
-    var result = await _labourRepository.deleteJobTemplate(templateId: item.id, cancelToken: cancelToken);
+    var result = await _labourRepository.deleteJobTemplate(templateId: item.id.toString(), cancelToken: cancelToken);
 
     if (result.isSuccess) {
       NotifyEngine.showSuccess("Successful".tr);

+ 2 - 2
packages/cpt_uk/lib/modules/job/template_list/template_list_state.dart

@@ -1,5 +1,5 @@
 import 'package:domain/entity/response/job_template_s_g_entity.dart';
-import 'package:domain/entity/response/u_k_template_entity.dart';
+import 'package:domain/entity/response/uk_template_table_entity.dart';
 import 'package:flutter/material.dart';
 
 class TemplateListState {
@@ -9,6 +9,6 @@ class TemplateListState {
   String keyword = "";
 
   //页面的列表数据
-  List<UKTemplateRows> datas = [];
+  List<UkTemplateTableRows> datas = [];
 
 }

+ 122 - 0
packages/cpt_uk/lib/modules/review/labour_review_edit/labour_review_edit_controller.dart

@@ -1,3 +1,5 @@
+import 'dart:io';
+
 import 'package:cpt_uk/modules/job/labour_request_add/widget/labour_request_interface.dart';
 import 'package:cpt_uk/modules/job/labour_request_preselected_list/widget/preselected_add_staff.dart';
 import 'package:cpt_uk/widget/date_range_picker_dialog.dart';
@@ -22,6 +24,7 @@ import 'package:widgets/picker/date_picker_util.dart';
 import 'package:widgets/picker/option_pick_util.dart';
 import 'package:file_picker/file_picker.dart';
 
+import '../../job/labour_request_add/widget/uploadFileField.dart';
 import 'labour_review_edit_state.dart';
 
 class LabourReviewEditController extends GetxController with DioCancelableMixin implements CommonLabourRequestController {
@@ -60,6 +63,31 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
       state.jobSelectJobStart = state.labReqOption?.jobStart?? '';
       state.jobSelectJobEnd = state.labReqOption?.jobEnd?? '';
 
+      state.videoText = state.labReqOption?.videoText?? '';
+      state.videoCover = state.labReqOption?.videoCover?? '';
+      state.video = state.labReqOption?.video?? '';
+      state.otherImage = state.labReqOption?.otherImage?? '';
+      state.otherDocument = state.labReqOption?.otherDocument?? '';
+
+      // 修改 state.uploadFieldList 对应的 fieldPathValueList
+      state.uploadFieldList.forEach((element) {
+        if (element.fieldKey == 'video_cover_key') {
+          element.fieldPathValueList?.clear();
+          element.fieldPathValueList?.add(state.videoCover ?? '');
+        }
+        if (element.fieldKey == 'video_video_key') {
+          element.fieldPathValueList?.clear();
+          element.fieldPathValueList?.add(state.video ?? '');
+        }
+        if (element.fieldKey == 'video_image_key') {
+          element.fieldPathValueList?.clear();
+          element.fieldPathValueList?.add(state.otherImage ?? '');
+        }
+        if (element.fieldKey == 'video_document_key') {
+          element.fieldPathValueList?.clear();
+          element.fieldPathValueList?.add(state.otherDocument ?? '');
+        }
+      });
 
       if(state.pageType == 0){
         // 新增
@@ -96,6 +124,9 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
       //时薪还是房间计费
       state.chargeOptionId = state.labReqOption?.chargeList!.firstWhere((element) => element.checked == "checked").value;
 
+      var vidoeTextController = state.formData['video_text']!['controller'];
+      vidoeTextController.text = state.videoText??'';
+
       update();
     } else {
       ToastEngine.show(result.errorMsg ?? "Network Load Error".tr);
@@ -105,6 +136,85 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
   @override
   void onReady() {
     super.onReady();
+    state.uploadFieldList = [
+      FileFieldItem(
+          fieldKey: 'video_cover_key',
+          fieldLabel: 'Video Cover'.tr,
+          fieldPathValueList: [''],
+          fieldPlaceholder: "Choose".tr,
+          maxSize: '10MB',
+          allowedFileTypes: ['jpg', 'png', 'jpeg'],  // 'mp4', 'jpg', 'png', 'jpeg', 'pdf', 'docx'
+          multiple: false,
+          preview: false,
+          download: false, // 启用下载功能
+          disabled: false,
+          onFilesSelected: (List<File> files) {
+            print("选中的文件: ${files}");
+            // print("选中的文件: ${files.length}个");
+            if(files.length>0){
+              state.videoCover = files[0].path;
+              update();
+            }
+          }
+      ),
+      FileFieldItem(
+        fieldKey: 'video_video_key',
+        fieldLabel: 'Video'.tr,
+        fieldPathValueList: [''],
+        fieldPlaceholder: "Choose".tr,
+        maxSize: '20MB',
+        allowedFileTypes: ['mp4'],  // 'mp4', 'jpg', 'png', 'jpeg', 'pdf', 'docx'
+        multiple: false,
+        preview: false,
+        download: false, // 启用下载功能
+        disabled: false,
+        onFilesSelected: (List<File> files) {
+          print("选中的文件: ${files}");
+          if(files.length>0){
+            state.video = files[0].path;
+            update();
+          }
+        },
+      ),
+      FileFieldItem(
+        fieldKey: 'video_image_key',
+        fieldLabel: 'Video Image'.tr,
+        fieldPathValueList: [''],
+        fieldPlaceholder: "Choose".tr,
+        maxSize: '10MB',
+        allowedFileTypes: ['jpg', 'png', 'jpeg'],  // 'mp4', 'jpg', 'png', 'jpeg', 'pdf', 'docx'
+        multiple: false,
+        preview: false,
+        download: false, // 启用下载功能
+        disabled: false,
+        onFilesSelected: (List<File> files) {
+          print("选中的文件: ${files}");
+          if(files.length>0){
+            state.otherImage = files[0].path;
+            update();
+          }
+        },
+      ),
+      FileFieldItem(
+        fieldKey: 'video_document_key',
+        fieldLabel: 'Video Document'.tr,
+        fieldPathValueList: [''],
+        fieldPlaceholder: "Choose".tr,
+        maxSize: '10MB',
+        allowedFileTypes: ['pdf','docx', 'doc'],  // 'mp4', 'jpg', 'png', 'jpeg', 'pdf', 'docx','doc'
+        multiple: false,
+        preview: false,
+        download: false, // 启用下载功能
+        disabled: false,
+        onFilesSelected: (List<File> files) {
+          print("选中的文件: ${files}");
+          if(files.length>0){
+            state.otherDocument = files[0].path;
+            update();
+          }
+        },
+      ),
+    ];
     fetchRequestDetail();
   }
 
@@ -407,6 +517,8 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
     String totalCost = totalCostController.text.toString();
     String remark = remarkController.text.toString();
 
+    var videoTextController = state.formData['video_text']!['controller'];
+    String videoText = videoTextController.text.toString();
 
     if (Utils.isEmpty(state.selectedTemplateId)) {
       ToastEngine.show("Choose Job Title".tr);
@@ -455,6 +567,11 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
       "position": position,
       "estCost": totalCost,
       "attUrl": state.attFilePath,
+      "videoText": videoText,
+      "videoCover": state.videoCover,
+      "video": state.video,
+      "otherImage": state.otherImage,
+      "otherDocument": state.otherDocument,
       'cancelToken': cancelToken
     };
 
@@ -480,6 +597,11 @@ class LabourReviewEditController extends GetxController with DioCancelableMixin
       position: params['position'],
       estCost: params['estCost'],
       attUrl: params['attUrl'],
+      videoText: params['videoText'],
+      videoCover: params['videoCover'],
+      video: params['video'],
+      otherImage: params['otherImage'],
+      otherDocument: params['otherDocument'],
       cancelToken: params['cancelToken'],
     );
 

+ 33 - 0
packages/cpt_uk/lib/modules/review/labour_review_edit/labour_review_edit_state.dart

@@ -8,6 +8,8 @@ import 'package:flutter/material.dart';
 import 'package:plugin_basic/basic_export.dart';
 import 'package:shared/utils/date_time_utils.dart';
 
+import '../../job/labour_request_add/widget/uploadFileField.dart';
+
 class LabourReviewEditState implements CommonLabourRequestState {
   @override
   String useInSence = 'labour_request_review';  // labour_request 、 labour_request_review
@@ -137,6 +139,37 @@ class LabourReviewEditState implements CommonLabourRequestState {
       'hintText': 'Enter...'.tr,
       'obsecure': false,
     },
+    'video_text': {
+      'value': '',
+      'controller': TextEditingController(),
+      'focusNode': FocusNode(),
+      'hintText': 'Enter...'.tr,
+      'obsecure': false,
+    }
   };
 
+  @override
+  String? videoText;
+
+  @override
+  dynamic? videoCover;
+
+  @override
+  dynamic? video;
+
+  @override
+  dynamic? otherImage;
+
+  @override
+  dynamic? otherDocument;
+
+  @override
+  String videoTips = '''
+    Video - video type (eg: mp4) and size 20MB
+    Document can be word/pdf,etc and the size 10MB
+    Cover、Image can be jpg,jpeg,png and the size 10MB.
+    ''';
+  @override
+  List<FileFieldItem> uploadFieldList = [];
+
 }

+ 0 - 49
packages/cs_domain/lib/entity/response/u_k_template_entity.dart

@@ -1,49 +0,0 @@
-import 'package:domain/generated/json/base/json_field.dart';
-import 'package:domain/generated/json/u_k_template_entity.g.dart';
-import 'dart:convert';
-export 'package:domain/generated/json/u_k_template_entity.g.dart';
-
-@JsonSerializable()
-class UKTemplateEntity {
-	int total = 0;
-	List<UKTemplateRows> rows = [];
-
-	UKTemplateEntity();
-
-	factory UKTemplateEntity.fromJson(Map<String, dynamic> json) => $UKTemplateEntityFromJson(json);
-
-	Map<String, dynamic> toJson() => $UKTemplateEntityToJson(this);
-
-	@override
-	String toString() {
-		return jsonEncode(this);
-	}
-}
-
-@JsonSerializable()
-class UKTemplateRows {
-	String? id;
-	@JSONField(name: "job_title")
-	String? jobTitle;
-	String? vehicle;
-	String? certificate;
-	@JSONField(name: "contact_name")
-	String? contactName;
-	@JSONField(name: "contact_no")
-	String? contactNo;
-	@JSONField(name: "created_by")
-	String? createdBy;
-	@JSONField(name: "created_at")
-	String? createdAt;
-
-	UKTemplateRows();
-
-	factory UKTemplateRows.fromJson(Map<String, dynamic> json) => $UKTemplateRowsFromJson(json);
-
-	Map<String, dynamic> toJson() => $UKTemplateRowsToJson(this);
-
-	@override
-	String toString() {
-		return jsonEncode(this);
-	}
-}

+ 1 - 0
packages/cs_domain/lib/entity/response/uk_job_template_detail_by_select_title_entity.dart

@@ -10,6 +10,7 @@ class UkJobTemplateDetailBySelectTitleEntity {
 	int? titleId;
 	String? title;
 	String? contact;
+	String? client;
 	@JSONField(name: "contact_no")
 	String? contactNo;
 	String? requirements;

+ 13 - 4
packages/cs_domain/lib/entity/response/uk_labour_request_detail_entity.dart

@@ -30,20 +30,29 @@ class UkLabourRequestDetailEntity {
 	@JSONField(name: "employment_type")
 	int? employmentType;
 	@JSONField(name: "event_name")
-	dynamic eventName;
+	String? eventName;
 	@JSONField(name: "event_type")
-	dynamic eventType;
+	String? eventType;
 	int? passengers;
 	@JSONField(name: "est_revenue")
 	dynamic estRevenue;
 	String? position;
-	dynamic description;
+	String? description;
 	@JSONField(name: "att_url")
-	dynamic attUrl;
+	String? attUrl;
 	@JSONField(name: "est_cost")
 	String? estCost;
 	@JSONField(name: "est_ratio")
 	String? estRatio;
+	@JSONField(name: "video_text")
+	String? videoText;
+	@JSONField(name: "video_cover")
+	String? videoCover;
+	String? video;
+	@JSONField(name: "other_image")
+	String? otherImage;
+	@JSONField(name: "other_document")
+	String? otherDocument;
 	@JSONField(name: "certificate_list")
 	List<UkLabourRequestDetailCertificateList>? certificateList;
 	@JSONField(name: "vehicle_list")

+ 24 - 0
packages/cs_domain/lib/entity/response/uk_template_detail_entity.dart

@@ -18,6 +18,8 @@ class UkTemplateDetailEntity {
 	List<UkTemplateDetailCertificateList>? certificateList;
 	@JSONField(name: "vehicle_list")
 	List<UkTemplateDetailVehicleList>? vehicleList;
+	@JSONField(name: "challenge_25_list")
+	List<UkTemplateDetailChallenge25List>? challenge25List;
 
 	UkTemplateDetailEntity();
 
@@ -61,6 +63,10 @@ class UkTemplateDetailRow {
 	int? templateId;
 	@JSONField(name: "job_title_id")
 	int? jobTitleId;
+	@JSONField(name: "client_name")
+	String? clientName;
+	@JSONField(name: "challenge_25")
+	int? challenge25;
 
 	UkTemplateDetailRow();
 
@@ -126,4 +132,22 @@ class UkTemplateDetailVehicleList {
 	String toString() {
 		return jsonEncode(this);
 	}
+}
+
+@JsonSerializable()
+class UkTemplateDetailChallenge25List {
+	int? value;
+	String? txt;
+	String? checked;
+
+	UkTemplateDetailChallenge25List();
+
+	factory UkTemplateDetailChallenge25List.fromJson(Map<String, dynamic> json) => $UkTemplateDetailChallenge25ListFromJson(json);
+
+	Map<String, dynamic> toJson() => $UkTemplateDetailChallenge25ListToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
 }

+ 20 - 0
packages/cs_domain/lib/entity/response/uk_template_detail_index_entity.dart

@@ -11,6 +11,8 @@ class UkTemplateDetailIndexEntity {
 	List<UkTemplateDetailIndexCertificateList>? certificateList;
 	@JSONField(name: "vehicle_list")
 	List<UkTemplateDetailIndexVehicleList>? vehicleList;
+	@JSONField(name: "challenge_25_list")
+	List<UkTemplateDetailIndexChallenge25List>? challenge25List;
 
 	UkTemplateDetailIndexEntity();
 
@@ -58,4 +60,22 @@ class UkTemplateDetailIndexVehicleList {
 	String toString() {
 		return jsonEncode(this);
 	}
+}
+
+@JsonSerializable()
+class UkTemplateDetailIndexChallenge25List {
+	int? value;
+	String? txt;
+	String? checked;
+
+	UkTemplateDetailIndexChallenge25List();
+
+	factory UkTemplateDetailIndexChallenge25List.fromJson(Map<String, dynamic> json) => $UkTemplateDetailIndexChallenge25ListFromJson(json);
+
+	Map<String, dynamic> toJson() => $UkTemplateDetailIndexChallenge25ListToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
 }

+ 53 - 0
packages/cs_domain/lib/entity/response/uk_template_table_entity.dart

@@ -0,0 +1,53 @@
+import 'package:domain/generated/json/base/json_field.dart';
+import 'package:domain/generated/json/uk_template_table_entity.g.dart';
+import 'dart:convert';
+export 'package:domain/generated/json/uk_template_table_entity.g.dart';
+
+@JsonSerializable()
+class UkTemplateTableEntity {
+	int? total;
+	List<UkTemplateTableRows>? rows;
+
+	UkTemplateTableEntity();
+
+	factory UkTemplateTableEntity.fromJson(Map<String, dynamic> json) => $UkTemplateTableEntityFromJson(json);
+
+	Map<String, dynamic> toJson() => $UkTemplateTableEntityToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}
+
+@JsonSerializable()
+class UkTemplateTableRows {
+	int? id;
+	@JSONField(name: "job_title")
+	String? jobTitle;
+	@JSONField(name: "client_name")
+	String? clientName;
+	@JSONField(name: "contact_name")
+	String? contactName;
+	@JSONField(name: "contact_no")
+	String? contactNo;
+	@JSONField(name: "challenge_25")
+	String? challenge25;
+	String? vehicle;
+	String? certificate;
+	@JSONField(name: "created_by")
+	String? createdBy;
+	@JSONField(name: "created_at")
+	String? createdAt;
+
+	UkTemplateTableRows();
+
+	factory UkTemplateTableRows.fromJson(Map<String, dynamic> json) => $UkTemplateTableRowsFromJson(json);
+
+	Map<String, dynamic> toJson() => $UkTemplateTableRowsToJson(this);
+
+	@override
+	String toString() {
+		return jsonEncode(this);
+	}
+}

+ 25 - 11
packages/cs_domain/lib/generated/json/base/json_convert_content.dart

@@ -102,7 +102,6 @@ import 'package:domain/entity/response/u_k_report_labour_entity.dart';
 import 'package:domain/entity/response/u_k_report_working_hours_entity.dart';
 import 'package:domain/entity/response/u_k_security_attendance_entity.dart';
 import 'package:domain/entity/response/u_k_security_attendance_option_entity.dart';
-import 'package:domain/entity/response/u_k_template_entity.dart';
 import 'package:domain/entity/response/uk_attendance_review_entity.dart';
 import 'package:domain/entity/response/uk_attendance_review_remark_entity.dart';
 import 'package:domain/entity/response/uk_job_applied_revise_add_detail_entity.dart';
@@ -127,6 +126,7 @@ import 'package:domain/entity/response/uk_staff_detail_entity.dart';
 import 'package:domain/entity/response/uk_staff_labour_history_entity.dart';
 import 'package:domain/entity/response/uk_template_detail_entity.dart';
 import 'package:domain/entity/response/uk_template_detail_index_entity.dart';
+import 'package:domain/entity/response/uk_template_table_entity.dart';
 import 'package:domain/entity/response/uk_template_title_option_entity.dart';
 import 'package:domain/entity/server_time.dart';
 
@@ -1116,14 +1116,6 @@ class JsonConvert {
           Map<String, dynamic> e) =>
           UKSecurityAttendanceOptionFilter.fromJson(e)).toList() as M;
     }
-    if (<UKTemplateEntity>[] is M) {
-      return data.map<UKTemplateEntity>((Map<String, dynamic> e) =>
-          UKTemplateEntity.fromJson(e)).toList() as M;
-    }
-    if (<UKTemplateRows>[] is M) {
-      return data.map<UKTemplateRows>((Map<String, dynamic> e) =>
-          UKTemplateRows.fromJson(e)).toList() as M;
-    }
     if (<UkAttendanceReviewEntity>[] is M) {
       return data.map<UkAttendanceReviewEntity>((Map<String, dynamic> e) =>
           UkAttendanceReviewEntity.fromJson(e)).toList() as M;
@@ -1459,6 +1451,11 @@ class JsonConvert {
       return data.map<UkTemplateDetailVehicleList>((Map<String, dynamic> e) =>
           UkTemplateDetailVehicleList.fromJson(e)).toList() as M;
     }
+    if (<UkTemplateDetailChallenge25List>[] is M) {
+      return data.map<UkTemplateDetailChallenge25List>((
+          Map<String, dynamic> e) =>
+          UkTemplateDetailChallenge25List.fromJson(e)).toList() as M;
+    }
     if (<UkTemplateDetailIndexEntity>[] is M) {
       return data.map<UkTemplateDetailIndexEntity>((Map<String, dynamic> e) =>
           UkTemplateDetailIndexEntity.fromJson(e)).toList() as M;
@@ -1473,6 +1470,19 @@ class JsonConvert {
           Map<String, dynamic> e) =>
           UkTemplateDetailIndexVehicleList.fromJson(e)).toList() as M;
     }
+    if (<UkTemplateDetailIndexChallenge25List>[] is M) {
+      return data.map<UkTemplateDetailIndexChallenge25List>((
+          Map<String, dynamic> e) =>
+          UkTemplateDetailIndexChallenge25List.fromJson(e)).toList() as M;
+    }
+    if (<UkTemplateTableEntity>[] is M) {
+      return data.map<UkTemplateTableEntity>((Map<String, dynamic> e) =>
+          UkTemplateTableEntity.fromJson(e)).toList() as M;
+    }
+    if (<UkTemplateTableRows>[] is M) {
+      return data.map<UkTemplateTableRows>((Map<String, dynamic> e) =>
+          UkTemplateTableRows.fromJson(e)).toList() as M;
+    }
     if (<UkTemplateTitleOptionEntity>[] is M) {
       return data.map<UkTemplateTitleOptionEntity>((Map<String, dynamic> e) =>
           UkTemplateTitleOptionEntity.fromJson(e)).toList() as M;
@@ -1775,8 +1785,6 @@ class JsonConvertClassCollection {
         .toString(): UKSecurityAttendanceOptionEntity.fromJson,
     (UKSecurityAttendanceOptionFilter)
         .toString(): UKSecurityAttendanceOptionFilter.fromJson,
-    (UKTemplateEntity).toString(): UKTemplateEntity.fromJson,
-    (UKTemplateRows).toString(): UKTemplateRows.fromJson,
     (UkAttendanceReviewEntity).toString(): UkAttendanceReviewEntity.fromJson,
     (UkAttendanceReviewRows).toString(): UkAttendanceReviewRows.fromJson,
     (UkAttendanceReviewRemarkEntity).toString(): UkAttendanceReviewRemarkEntity
@@ -1904,12 +1912,18 @@ class JsonConvertClassCollection {
         .toString(): UkTemplateDetailCertificateList.fromJson,
     (UkTemplateDetailVehicleList).toString(): UkTemplateDetailVehicleList
         .fromJson,
+    (UkTemplateDetailChallenge25List)
+        .toString(): UkTemplateDetailChallenge25List.fromJson,
     (UkTemplateDetailIndexEntity).toString(): UkTemplateDetailIndexEntity
         .fromJson,
     (UkTemplateDetailIndexCertificateList)
         .toString(): UkTemplateDetailIndexCertificateList.fromJson,
     (UkTemplateDetailIndexVehicleList)
         .toString(): UkTemplateDetailIndexVehicleList.fromJson,
+    (UkTemplateDetailIndexChallenge25List)
+        .toString(): UkTemplateDetailIndexChallenge25List.fromJson,
+    (UkTemplateTableEntity).toString(): UkTemplateTableEntity.fromJson,
+    (UkTemplateTableRows).toString(): UkTemplateTableRows.fromJson,
     (UkTemplateTitleOptionEntity).toString(): UkTemplateTitleOptionEntity
         .fromJson,
     (ServerTime).toString(): ServerTime.fromJson,

+ 0 - 109
packages/cs_domain/lib/generated/json/u_k_template_entity.g.dart

@@ -1,109 +0,0 @@
-import 'package:domain/generated/json/base/json_convert_content.dart';
-import 'package:domain/entity/response/u_k_template_entity.dart';
-
-UKTemplateEntity $UKTemplateEntityFromJson(Map<String, dynamic> json) {
-  final UKTemplateEntity uKTemplateEntity = UKTemplateEntity();
-  final int? total = jsonConvert.convert<int>(json['total']);
-  if (total != null) {
-    uKTemplateEntity.total = total;
-  }
-  final List<UKTemplateRows>? rows = (json['rows'] as List<dynamic>?)
-      ?.map(
-          (e) => jsonConvert.convert<UKTemplateRows>(e) as UKTemplateRows)
-      .toList();
-  if (rows != null) {
-    uKTemplateEntity.rows = rows;
-  }
-  return uKTemplateEntity;
-}
-
-Map<String, dynamic> $UKTemplateEntityToJson(UKTemplateEntity entity) {
-  final Map<String, dynamic> data = <String, dynamic>{};
-  data['total'] = entity.total;
-  data['rows'] = entity.rows.map((v) => v.toJson()).toList();
-  return data;
-}
-
-extension UKTemplateEntityExtension on UKTemplateEntity {
-  UKTemplateEntity copyWith({
-    int? total,
-    List<UKTemplateRows>? rows,
-  }) {
-    return UKTemplateEntity()
-      ..total = total ?? this.total
-      ..rows = rows ?? this.rows;
-  }
-}
-
-UKTemplateRows $UKTemplateRowsFromJson(Map<String, dynamic> json) {
-  final UKTemplateRows uKTemplateRows = UKTemplateRows();
-  final String? id = jsonConvert.convert<String>(json['id']);
-  if (id != null) {
-    uKTemplateRows.id = id;
-  }
-  final String? jobTitle = jsonConvert.convert<String>(json['job_title']);
-  if (jobTitle != null) {
-    uKTemplateRows.jobTitle = jobTitle;
-  }
-  final String? vehicle = jsonConvert.convert<String>(json['vehicle']);
-  if (vehicle != null) {
-    uKTemplateRows.vehicle = vehicle;
-  }
-  final String? certificate = jsonConvert.convert<String>(json['certificate']);
-  if (certificate != null) {
-    uKTemplateRows.certificate = certificate;
-  }
-  final String? contactName = jsonConvert.convert<String>(json['contact_name']);
-  if (contactName != null) {
-    uKTemplateRows.contactName = contactName;
-  }
-  final String? contactNo = jsonConvert.convert<String>(json['contact_no']);
-  if (contactNo != null) {
-    uKTemplateRows.contactNo = contactNo;
-  }
-  final String? createdBy = jsonConvert.convert<String>(json['created_by']);
-  if (createdBy != null) {
-    uKTemplateRows.createdBy = createdBy;
-  }
-  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
-  if (createdAt != null) {
-    uKTemplateRows.createdAt = createdAt;
-  }
-  return uKTemplateRows;
-}
-
-Map<String, dynamic> $UKTemplateRowsToJson(UKTemplateRows entity) {
-  final Map<String, dynamic> data = <String, dynamic>{};
-  data['id'] = entity.id;
-  data['job_title'] = entity.jobTitle;
-  data['vehicle'] = entity.vehicle;
-  data['certificate'] = entity.certificate;
-  data['contact_name'] = entity.contactName;
-  data['contact_no'] = entity.contactNo;
-  data['created_by'] = entity.createdBy;
-  data['created_at'] = entity.createdAt;
-  return data;
-}
-
-extension UKTemplateRowsExtension on UKTemplateRows {
-  UKTemplateRows copyWith({
-    String? id,
-    String? jobTitle,
-    String? vehicle,
-    String? certificate,
-    String? contactName,
-    String? contactNo,
-    String? createdBy,
-    String? createdAt,
-  }) {
-    return UKTemplateRows()
-      ..id = id ?? this.id
-      ..jobTitle = jobTitle ?? this.jobTitle
-      ..vehicle = vehicle ?? this.vehicle
-      ..certificate = certificate ?? this.certificate
-      ..contactName = contactName ?? this.contactName
-      ..contactNo = contactNo ?? this.contactNo
-      ..createdBy = createdBy ?? this.createdBy
-      ..createdAt = createdAt ?? this.createdAt;
-  }
-}

+ 7 - 0
packages/cs_domain/lib/generated/json/uk_job_template_detail_by_select_title_entity.g.dart

@@ -20,6 +20,10 @@ UkJobTemplateDetailBySelectTitleEntity $UkJobTemplateDetailBySelectTitleEntityFr
   if (contact != null) {
     ukJobTemplateDetailBySelectTitleEntity.contact = contact;
   }
+  final String? client = jsonConvert.convert<String>(json['client']);
+  if (client != null) {
+    ukJobTemplateDetailBySelectTitleEntity.client = client;
+  }
   final String? contactNo = jsonConvert.convert<String>(json['contact_no']);
   if (contactNo != null) {
     ukJobTemplateDetailBySelectTitleEntity.contactNo = contactNo;
@@ -76,6 +80,7 @@ Map<String, dynamic> $UkJobTemplateDetailBySelectTitleEntityToJson(
   data['title_id'] = entity.titleId;
   data['title'] = entity.title;
   data['contact'] = entity.contact;
+  data['client'] = entity.client;
   data['contact_no'] = entity.contactNo;
   data['requirements'] = entity.requirements;
   data['note'] = entity.note;
@@ -96,6 +101,7 @@ extension UkJobTemplateDetailBySelectTitleEntityExtension on UkJobTemplateDetail
     int? titleId,
     String? title,
     String? contact,
+    String? client,
     String? contactNo,
     String? requirements,
     String? note,
@@ -113,6 +119,7 @@ extension UkJobTemplateDetailBySelectTitleEntityExtension on UkJobTemplateDetail
       ..titleId = titleId ?? this.titleId
       ..title = title ?? this.title
       ..contact = contact ?? this.contact
+      ..client = client ?? this.client
       ..contactNo = contactNo ?? this.contactNo
       ..requirements = requirements ?? this.requirements
       ..note = note ?? this.note

+ 44 - 8
packages/cs_domain/lib/generated/json/uk_labour_request_detail_entity.g.dart

@@ -57,11 +57,11 @@ UkLabourRequestDetailEntity $UkLabourRequestDetailEntityFromJson(
   if (employmentType != null) {
     ukLabourRequestDetailEntity.employmentType = employmentType;
   }
-  final dynamic eventName = json['event_name'];
+  final String? eventName = jsonConvert.convert<String>(json['event_name']);
   if (eventName != null) {
     ukLabourRequestDetailEntity.eventName = eventName;
   }
-  final dynamic eventType = json['event_type'];
+  final String? eventType = jsonConvert.convert<String>(json['event_type']);
   if (eventType != null) {
     ukLabourRequestDetailEntity.eventType = eventType;
   }
@@ -77,11 +77,11 @@ UkLabourRequestDetailEntity $UkLabourRequestDetailEntityFromJson(
   if (position != null) {
     ukLabourRequestDetailEntity.position = position;
   }
-  final dynamic description = json['description'];
+  final String? description = jsonConvert.convert<String>(json['description']);
   if (description != null) {
     ukLabourRequestDetailEntity.description = description;
   }
-  final dynamic attUrl = json['att_url'];
+  final String? attUrl = jsonConvert.convert<String>(json['att_url']);
   if (attUrl != null) {
     ukLabourRequestDetailEntity.attUrl = attUrl;
   }
@@ -93,6 +93,27 @@ UkLabourRequestDetailEntity $UkLabourRequestDetailEntityFromJson(
   if (estRatio != null) {
     ukLabourRequestDetailEntity.estRatio = estRatio;
   }
+  final String? videoText = jsonConvert.convert<String>(json['video_text']);
+  if (videoText != null) {
+    ukLabourRequestDetailEntity.videoText = videoText;
+  }
+  final String? videoCover = jsonConvert.convert<String>(json['video_cover']);
+  if (videoCover != null) {
+    ukLabourRequestDetailEntity.videoCover = videoCover;
+  }
+  final String? video = jsonConvert.convert<String>(json['video']);
+  if (video != null) {
+    ukLabourRequestDetailEntity.video = video;
+  }
+  final String? otherImage = jsonConvert.convert<String>(json['other_image']);
+  if (otherImage != null) {
+    ukLabourRequestDetailEntity.otherImage = otherImage;
+  }
+  final String? otherDocument = jsonConvert.convert<String>(
+      json['other_document']);
+  if (otherDocument != null) {
+    ukLabourRequestDetailEntity.otherDocument = otherDocument;
+  }
   final List<
       UkLabourRequestDetailCertificateList>? certificateList = (json['certificate_list'] as List<
       dynamic>?)?.map(
@@ -193,6 +214,11 @@ Map<String, dynamic> $UkLabourRequestDetailEntityToJson(
   data['att_url'] = entity.attUrl;
   data['est_cost'] = entity.estCost;
   data['est_ratio'] = entity.estRatio;
+  data['video_text'] = entity.videoText;
+  data['video_cover'] = entity.videoCover;
+  data['video'] = entity.video;
+  data['other_image'] = entity.otherImage;
+  data['other_document'] = entity.otherDocument;
   data['certificate_list'] =
       entity.certificateList?.map((v) => v.toJson()).toList();
   data['vehicle_list'] = entity.vehicleList?.map((v) => v.toJson()).toList();
@@ -223,15 +249,20 @@ extension UkLabourRequestDetailEntityExtension on UkLabourRequestDetailEntity {
     String? salaryBy,
     int? amount,
     int? employmentType,
-    dynamic eventName,
-    dynamic eventType,
+    String? eventName,
+    String? eventType,
     int? passengers,
     dynamic estRevenue,
     String? position,
-    dynamic description,
-    dynamic attUrl,
+    String? description,
+    String? attUrl,
     String? estCost,
     String? estRatio,
+    String? videoText,
+    String? videoCover,
+    String? video,
+    String? otherImage,
+    String? otherDocument,
     List<UkLabourRequestDetailCertificateList>? certificateList,
     List<UkLabourRequestDetailVehicleList>? vehicleList,
     List<UkLabourRequestDetailChallenge25List>? challenge25List,
@@ -264,6 +295,11 @@ extension UkLabourRequestDetailEntityExtension on UkLabourRequestDetailEntity {
       ..attUrl = attUrl ?? this.attUrl
       ..estCost = estCost ?? this.estCost
       ..estRatio = estRatio ?? this.estRatio
+      ..videoText = videoText ?? this.videoText
+      ..videoCover = videoCover ?? this.videoCover
+      ..video = video ?? this.video
+      ..otherImage = otherImage ?? this.otherImage
+      ..otherDocument = otherDocument ?? this.otherDocument
       ..certificateList = certificateList ?? this.certificateList
       ..vehicleList = vehicleList ?? this.vehicleList
       ..challenge25List = challenge25List ?? this.challenge25List

+ 69 - 2
packages/cs_domain/lib/generated/json/uk_template_detail_entity.g.dart

@@ -52,6 +52,15 @@ UkTemplateDetailEntity $UkTemplateDetailEntityFromJson(
   if (vehicleList != null) {
     ukTemplateDetailEntity.vehicleList = vehicleList;
   }
+  final List<
+      UkTemplateDetailChallenge25List>? challenge25List = (json['challenge_25_list'] as List<
+      dynamic>?)?.map(
+          (e) =>
+      jsonConvert.convert<UkTemplateDetailChallenge25List>(
+          e) as UkTemplateDetailChallenge25List).toList();
+  if (challenge25List != null) {
+    ukTemplateDetailEntity.challenge25List = challenge25List;
+  }
   return ukTemplateDetailEntity;
 }
 
@@ -66,6 +75,8 @@ Map<String, dynamic> $UkTemplateDetailEntityToJson(
   data['certificate_list'] =
       entity.certificateList?.map((v) => v.toJson()).toList();
   data['vehicle_list'] = entity.vehicleList?.map((v) => v.toJson()).toList();
+  data['challenge_25_list'] =
+      entity.challenge25List?.map((v) => v.toJson()).toList();
   return data;
 }
 
@@ -78,6 +89,7 @@ extension UkTemplateDetailEntityExtension on UkTemplateDetailEntity {
     List<UkTemplateDetailTitleList>? titleList,
     List<UkTemplateDetailCertificateList>? certificateList,
     List<UkTemplateDetailVehicleList>? vehicleList,
+    List<UkTemplateDetailChallenge25List>? challenge25List,
   }) {
     return UkTemplateDetailEntity()
       ..row = row ?? this.row
@@ -86,7 +98,8 @@ extension UkTemplateDetailEntityExtension on UkTemplateDetailEntity {
       ..templateTitle = templateTitle ?? this.templateTitle
       ..titleList = titleList ?? this.titleList
       ..certificateList = certificateList ?? this.certificateList
-      ..vehicleList = vehicleList ?? this.vehicleList;
+      ..vehicleList = vehicleList ?? this.vehicleList
+      ..challenge25List = challenge25List ?? this.challenge25List;
   }
 }
 
@@ -164,6 +177,14 @@ UkTemplateDetailRow $UkTemplateDetailRowFromJson(Map<String, dynamic> json) {
   if (jobTitleId != null) {
     ukTemplateDetailRow.jobTitleId = jobTitleId;
   }
+  final String? clientName = jsonConvert.convert<String>(json['client_name']);
+  if (clientName != null) {
+    ukTemplateDetailRow.clientName = clientName;
+  }
+  final int? challenge25 = jsonConvert.convert<int>(json['challenge_25']);
+  if (challenge25 != null) {
+    ukTemplateDetailRow.challenge25 = challenge25;
+  }
   return ukTemplateDetailRow;
 }
 
@@ -187,6 +208,8 @@ Map<String, dynamic> $UkTemplateDetailRowToJson(UkTemplateDetailRow entity) {
   data['deleted_at'] = entity.deletedAt;
   data['template_id'] = entity.templateId;
   data['job_title_id'] = entity.jobTitleId;
+  data['client_name'] = entity.clientName;
+  data['challenge_25'] = entity.challenge25;
   return data;
 }
 
@@ -210,6 +233,8 @@ extension UkTemplateDetailRowExtension on UkTemplateDetailRow {
     dynamic deletedAt,
     int? templateId,
     int? jobTitleId,
+    String? clientName,
+    int? challenge25,
   }) {
     return UkTemplateDetailRow()
       ..id = id ?? this.id
@@ -229,7 +254,9 @@ extension UkTemplateDetailRowExtension on UkTemplateDetailRow {
       ..updatedAt = updatedAt ?? this.updatedAt
       ..deletedAt = deletedAt ?? this.deletedAt
       ..templateId = templateId ?? this.templateId
-      ..jobTitleId = jobTitleId ?? this.jobTitleId;
+      ..jobTitleId = jobTitleId ?? this.jobTitleId
+      ..clientName = clientName ?? this.clientName
+      ..challenge25 = challenge25 ?? this.challenge25;
   }
 }
 
@@ -344,4 +371,44 @@ extension UkTemplateDetailVehicleListExtension on UkTemplateDetailVehicleList {
       ..txt = txt ?? this.txt
       ..checked = checked ?? this.checked;
   }
+}
+
+UkTemplateDetailChallenge25List $UkTemplateDetailChallenge25ListFromJson(
+    Map<String, dynamic> json) {
+  final UkTemplateDetailChallenge25List ukTemplateDetailChallenge25List = UkTemplateDetailChallenge25List();
+  final int? value = jsonConvert.convert<int>(json['value']);
+  if (value != null) {
+    ukTemplateDetailChallenge25List.value = value;
+  }
+  final String? txt = jsonConvert.convert<String>(json['txt']);
+  if (txt != null) {
+    ukTemplateDetailChallenge25List.txt = txt;
+  }
+  final String? checked = jsonConvert.convert<String>(json['checked']);
+  if (checked != null) {
+    ukTemplateDetailChallenge25List.checked = checked;
+  }
+  return ukTemplateDetailChallenge25List;
+}
+
+Map<String, dynamic> $UkTemplateDetailChallenge25ListToJson(
+    UkTemplateDetailChallenge25List entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['value'] = entity.value;
+  data['txt'] = entity.txt;
+  data['checked'] = entity.checked;
+  return data;
+}
+
+extension UkTemplateDetailChallenge25ListExtension on UkTemplateDetailChallenge25List {
+  UkTemplateDetailChallenge25List copyWith({
+    int? value,
+    String? txt,
+    String? checked,
+  }) {
+    return UkTemplateDetailChallenge25List()
+      ..value = value ?? this.value
+      ..txt = txt ?? this.txt
+      ..checked = checked ?? this.checked;
+  }
 }

+ 54 - 1
packages/cs_domain/lib/generated/json/uk_template_detail_index_entity.g.dart

@@ -29,6 +29,15 @@ UkTemplateDetailIndexEntity $UkTemplateDetailIndexEntityFromJson(
   if (vehicleList != null) {
     ukTemplateDetailIndexEntity.vehicleList = vehicleList;
   }
+  final List<
+      UkTemplateDetailIndexChallenge25List>? challenge25List = (json['challenge_25_list'] as List<
+      dynamic>?)?.map(
+          (e) =>
+      jsonConvert.convert<UkTemplateDetailIndexChallenge25List>(
+          e) as UkTemplateDetailIndexChallenge25List).toList();
+  if (challenge25List != null) {
+    ukTemplateDetailIndexEntity.challenge25List = challenge25List;
+  }
   return ukTemplateDetailIndexEntity;
 }
 
@@ -39,6 +48,8 @@ Map<String, dynamic> $UkTemplateDetailIndexEntityToJson(
   data['certificate_list'] =
       entity.certificateList?.map((v) => v.toJson()).toList();
   data['vehicle_list'] = entity.vehicleList?.map((v) => v.toJson()).toList();
+  data['challenge_25_list'] =
+      entity.challenge25List?.map((v) => v.toJson()).toList();
   return data;
 }
 
@@ -47,11 +58,13 @@ extension UkTemplateDetailIndexEntityExtension on UkTemplateDetailIndexEntity {
     List<String>? templateList,
     List<UkTemplateDetailIndexCertificateList>? certificateList,
     List<UkTemplateDetailIndexVehicleList>? vehicleList,
+    List<UkTemplateDetailIndexChallenge25List>? challenge25List,
   }) {
     return UkTemplateDetailIndexEntity()
       ..templateList = templateList ?? this.templateList
       ..certificateList = certificateList ?? this.certificateList
-      ..vehicleList = vehicleList ?? this.vehicleList;
+      ..vehicleList = vehicleList ?? this.vehicleList
+      ..challenge25List = challenge25List ?? this.challenge25List;
   }
 }
 
@@ -133,4 +146,44 @@ extension UkTemplateDetailIndexVehicleListExtension on UkTemplateDetailIndexVehi
       ..txt = txt ?? this.txt
       ..checked = checked ?? this.checked;
   }
+}
+
+UkTemplateDetailIndexChallenge25List $UkTemplateDetailIndexChallenge25ListFromJson(
+    Map<String, dynamic> json) {
+  final UkTemplateDetailIndexChallenge25List ukTemplateDetailIndexChallenge25List = UkTemplateDetailIndexChallenge25List();
+  final int? value = jsonConvert.convert<int>(json['value']);
+  if (value != null) {
+    ukTemplateDetailIndexChallenge25List.value = value;
+  }
+  final String? txt = jsonConvert.convert<String>(json['txt']);
+  if (txt != null) {
+    ukTemplateDetailIndexChallenge25List.txt = txt;
+  }
+  final String? checked = jsonConvert.convert<String>(json['checked']);
+  if (checked != null) {
+    ukTemplateDetailIndexChallenge25List.checked = checked;
+  }
+  return ukTemplateDetailIndexChallenge25List;
+}
+
+Map<String, dynamic> $UkTemplateDetailIndexChallenge25ListToJson(
+    UkTemplateDetailIndexChallenge25List entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['value'] = entity.value;
+  data['txt'] = entity.txt;
+  data['checked'] = entity.checked;
+  return data;
+}
+
+extension UkTemplateDetailIndexChallenge25ListExtension on UkTemplateDetailIndexChallenge25List {
+  UkTemplateDetailIndexChallenge25List copyWith({
+    int? value,
+    String? txt,
+    String? checked,
+  }) {
+    return UkTemplateDetailIndexChallenge25List()
+      ..value = value ?? this.value
+      ..txt = txt ?? this.txt
+      ..checked = checked ?? this.checked;
+  }
 }

+ 126 - 0
packages/cs_domain/lib/generated/json/uk_template_table_entity.g.dart

@@ -0,0 +1,126 @@
+import 'package:domain/generated/json/base/json_convert_content.dart';
+import 'package:domain/entity/response/uk_template_table_entity.dart';
+
+UkTemplateTableEntity $UkTemplateTableEntityFromJson(
+    Map<String, dynamic> json) {
+  final UkTemplateTableEntity ukTemplateTableEntity = UkTemplateTableEntity();
+  final int? total = jsonConvert.convert<int>(json['total']);
+  if (total != null) {
+    ukTemplateTableEntity.total = total;
+  }
+  final List<UkTemplateTableRows>? rows = (json['rows'] as List<dynamic>?)
+      ?.map(
+          (e) =>
+      jsonConvert.convert<UkTemplateTableRows>(e) as UkTemplateTableRows)
+      .toList();
+  if (rows != null) {
+    ukTemplateTableEntity.rows = rows;
+  }
+  return ukTemplateTableEntity;
+}
+
+Map<String, dynamic> $UkTemplateTableEntityToJson(
+    UkTemplateTableEntity entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['total'] = entity.total;
+  data['rows'] = entity.rows?.map((v) => v.toJson()).toList();
+  return data;
+}
+
+extension UkTemplateTableEntityExtension on UkTemplateTableEntity {
+  UkTemplateTableEntity copyWith({
+    int? total,
+    List<UkTemplateTableRows>? rows,
+  }) {
+    return UkTemplateTableEntity()
+      ..total = total ?? this.total
+      ..rows = rows ?? this.rows;
+  }
+}
+
+UkTemplateTableRows $UkTemplateTableRowsFromJson(Map<String, dynamic> json) {
+  final UkTemplateTableRows ukTemplateTableRows = UkTemplateTableRows();
+  final int? id = jsonConvert.convert<int>(json['id']);
+  if (id != null) {
+    ukTemplateTableRows.id = id;
+  }
+  final String? jobTitle = jsonConvert.convert<String>(json['job_title']);
+  if (jobTitle != null) {
+    ukTemplateTableRows.jobTitle = jobTitle;
+  }
+  final String? clientName = jsonConvert.convert<String>(json['client_name']);
+  if (clientName != null) {
+    ukTemplateTableRows.clientName = clientName;
+  }
+  final String? contactName = jsonConvert.convert<String>(json['contact_name']);
+  if (contactName != null) {
+    ukTemplateTableRows.contactName = contactName;
+  }
+  final String? contactNo = jsonConvert.convert<String>(json['contact_no']);
+  if (contactNo != null) {
+    ukTemplateTableRows.contactNo = contactNo;
+  }
+  final String? challenge25 = jsonConvert.convert<String>(json['challenge_25']);
+  if (challenge25 != null) {
+    ukTemplateTableRows.challenge25 = challenge25;
+  }
+  final String? vehicle = jsonConvert.convert<String>(json['vehicle']);
+  if (vehicle != null) {
+    ukTemplateTableRows.vehicle = vehicle;
+  }
+  final String? certificate = jsonConvert.convert<String>(json['certificate']);
+  if (certificate != null) {
+    ukTemplateTableRows.certificate = certificate;
+  }
+  final String? createdBy = jsonConvert.convert<String>(json['created_by']);
+  if (createdBy != null) {
+    ukTemplateTableRows.createdBy = createdBy;
+  }
+  final String? createdAt = jsonConvert.convert<String>(json['created_at']);
+  if (createdAt != null) {
+    ukTemplateTableRows.createdAt = createdAt;
+  }
+  return ukTemplateTableRows;
+}
+
+Map<String, dynamic> $UkTemplateTableRowsToJson(UkTemplateTableRows entity) {
+  final Map<String, dynamic> data = <String, dynamic>{};
+  data['id'] = entity.id;
+  data['job_title'] = entity.jobTitle;
+  data['client_name'] = entity.clientName;
+  data['contact_name'] = entity.contactName;
+  data['contact_no'] = entity.contactNo;
+  data['challenge_25'] = entity.challenge25;
+  data['vehicle'] = entity.vehicle;
+  data['certificate'] = entity.certificate;
+  data['created_by'] = entity.createdBy;
+  data['created_at'] = entity.createdAt;
+  return data;
+}
+
+extension UkTemplateTableRowsExtension on UkTemplateTableRows {
+  UkTemplateTableRows copyWith({
+    int? id,
+    String? jobTitle,
+    String? clientName,
+    String? contactName,
+    String? contactNo,
+    String? challenge25,
+    String? vehicle,
+    String? certificate,
+    String? createdBy,
+    String? createdAt,
+  }) {
+    return UkTemplateTableRows()
+      ..id = id ?? this.id
+      ..jobTitle = jobTitle ?? this.jobTitle
+      ..clientName = clientName ?? this.clientName
+      ..contactName = contactName ?? this.contactName
+      ..contactNo = contactNo ?? this.contactNo
+      ..challenge25 = challenge25 ?? this.challenge25
+      ..vehicle = vehicle ?? this.vehicle
+      ..certificate = certificate ?? this.certificate
+      ..createdBy = createdBy ?? this.createdBy
+      ..createdAt = createdAt ?? this.createdAt;
+  }
+}

+ 22 - 4
packages/cs_domain/lib/repository/uk_job_repository.dart

@@ -1,4 +1,3 @@
-import 'package:domain/entity/response/u_k_template_entity.dart';
 import 'package:get/get.dart';
 import 'package:plugin_platform/http/http_provider.dart';
 import 'package:plugin_platform/http/http_result.dart';
@@ -20,6 +19,7 @@ import '../entity/response/uk_staff_detail_entity.dart';
 import '../entity/response/uk_staff_labour_history_entity.dart';
 import '../entity/response/uk_template_detail_entity.dart';
 import '../entity/response/uk_template_detail_index_entity.dart';
+import '../entity/response/uk_template_table_entity.dart';
 import '../entity/response/uk_template_title_option_entity.dart';
 
 /// UK工作相关数据仓库
@@ -29,7 +29,7 @@ class UKJobRepository extends GetxService {
   UKJobRepository({required this.httpProvider});
 
   /// 用工模版中的工作标题列表
-  Future<HttpResult<UKTemplateEntity>> fetchJobTemplateList(
+  Future<HttpResult<UkTemplateTableEntity>> fetchJobTemplateList(
     String? keyword, {
     required int curPage,
     CancelToken? cancelToken,
@@ -51,8 +51,8 @@ class UKJobRepository extends GetxService {
 
     if (result.isSuccess) {
       final json = result.getDataJson();
-      var data = UKTemplateEntity.fromJson(json!);
-      return result.convert<UKTemplateEntity>(data: data);
+      var data = UkTemplateTableEntity.fromJson(json!);
+      return result.convert<UkTemplateTableEntity>(data: data);
     }
     return result.convert();
   }
@@ -155,8 +155,10 @@ class UKJobRepository extends GetxService {
   Future<HttpResult> addJobTemplateSubmit({
     required String jobTemplateId ,
     required String jobTitle,
+    String? clientName,
     List<String>? certificate,
     List<String>? vehicle,
+    String? challenge25, // 1.yes,0.no
     String? note,
     String? desc,
     String? contactName,
@@ -169,12 +171,19 @@ class UKJobRepository extends GetxService {
     params['job_template_id'] = jobTemplateId;
     params['job_title'] = jobTitle;
 
+    if (Utils.isNotEmpty(clientName)) {
+      params['client_name'] = clientName ?? "";
+    }
+
     if (certificate != null && certificate.isNotEmpty) {
       params['certificate[]'] = certificate;
     }
     if (vehicle != null && vehicle.isNotEmpty) {
       params['vehicle[]'] = vehicle;
     }
+    if (Utils.isNotEmpty(challenge25)) {
+      params['challenge_25'] = challenge25 ?? "";
+    }
     if (Utils.isNotEmpty(note)) {
       params['note'] = note ?? "";
     }
@@ -208,8 +217,10 @@ class UKJobRepository extends GetxService {
     required String templateId,
     required String jobTemplateId,
     required String jobTitle,
+    String? clientName,
     List<String>? certificate,
     List<String>? vehicle,
+    String? challenge25, // 1 yse  0 no
     String? note,
     String? desc,
     String? contactName,
@@ -222,12 +233,19 @@ class UKJobRepository extends GetxService {
     params['template_id'] = templateId;
     params['job_template_id'] = jobTemplateId;
 
+    if (Utils.isNotEmpty(clientName)) {
+      params['client_name'] = clientName ?? "";
+    }
+
     if (certificate != null && certificate.isNotEmpty) {
       params['certificate[]'] = certificate;
     }
     if (vehicle != null && vehicle.isNotEmpty) {
       params['vehicle[]'] = vehicle;
     }
+    if (Utils.isNotEmpty(challenge25)) {
+      params['challenge_25'] = challenge25 ?? "";
+    }
     if (Utils.isNotEmpty(note)) {
       params['note'] = note ?? "";
     }

+ 142 - 0
packages/cs_domain/lib/repository/uk_labour_repository.dart

@@ -205,6 +205,11 @@ class UkLabourRepository extends GetxService {
       String? position,
       String? estCost,
       dynamic? attUrl,
+      String? videoText,
+      dynamic? videoCover,
+      dynamic? video,
+      dynamic? otherImage,
+      dynamic? otherDocument,
       CancelToken? cancelToken,
     }) async {
 
@@ -259,6 +264,49 @@ class UkLabourRepository extends GetxService {
       }
     }
 
+    // 视频部分的参数
+    params['video_text'] = videoText ?? "";
+
+    //可能是file 也可能是  url
+    // 判断 http 或者 https 开头
+    if(Utils.isNotEmpty(videoCover)){
+      if(videoCover!.startsWith("http") || videoCover!.startsWith("https")){
+        params['video_cover'] = videoCover;
+      }else {
+        filePathParams['video_cover'] = videoCover;
+      }
+    }
+
+    //可能是file 也可能是  url
+    // 判断 http 或者 https 开头
+    if(Utils.isNotEmpty(video)){
+      if(video!.startsWith("http") || video!.startsWith("https")){
+        params['video'] = video;
+      }else {
+        filePathParams['video'] = video;
+      }
+    }
+
+    //可能是file 也可能是  url
+    // 判断 http 或者 https 开头
+    if(Utils.isNotEmpty(otherImage)){
+      if(otherImage!.startsWith("http") || otherImage!.startsWith("https")){
+        params['other_image'] = otherImage;
+      }else {
+        filePathParams['other_image'] = otherImage;
+      }
+    }
+
+    //可能是file 也可能是  url
+    // 判断 http 或者 https 开头
+    if(Utils.isNotEmpty(otherDocument)){
+      if(otherDocument!.startsWith("http") || otherDocument!.startsWith("https")){
+        params['other_document'] = otherDocument;
+      }else {
+        filePathParams['other_document'] = otherDocument;
+      }
+    }
+
 
 
     final result = await httpProvider.requestNetResult(
@@ -302,6 +350,11 @@ class UkLabourRepository extends GetxService {
     String? position,
     String? estCost,
     dynamic? attUrl,
+    String? videoText,
+    dynamic? videoCover,
+    dynamic? video,
+    dynamic? otherImage,
+    dynamic? otherDocument,
     CancelToken? cancelToken,
   }) async {
 
@@ -356,7 +409,48 @@ class UkLabourRepository extends GetxService {
       }
     }
 
+    // 视频部分的参数
+    params['video_text'] = videoText ?? "";
+
+    //可能是file 也可能是  url
+    // 判断 http 或者 https 开头
+    if(Utils.isNotEmpty(videoCover)){
+      if(videoCover!.startsWith("http") || videoCover!.startsWith("https")){
+        params['video_cover'] = videoCover;
+      }else {
+        filePathParams['video_cover'] = videoCover;
+      }
+    }
 
+    //可能是file 也可能是  url
+    // 判断 http 或者 https 开头
+    if(Utils.isNotEmpty(video)){
+      if(video!.startsWith("http") || video!.startsWith("https")){
+        params['video'] = video;
+      }else {
+        filePathParams['video'] = video;
+      }
+    }
+
+    //可能是file 也可能是  url
+    // 判断 http 或者 https 开头
+    if(Utils.isNotEmpty(otherImage)){
+      if(otherImage!.startsWith("http") || otherImage!.startsWith("https")){
+        params['other_image'] = otherImage;
+      }else {
+        filePathParams['other_image'] = otherImage;
+      }
+    }
+
+    //可能是file 也可能是  url
+    // 判断 http 或者 https 开头
+    if(Utils.isNotEmpty(otherDocument)){
+      if(otherDocument!.startsWith("http") || otherDocument!.startsWith("https")){
+        params['other_document'] = otherDocument;
+      }else {
+        filePathParams['other_document'] = otherDocument;
+      }
+    }
 
     final result = await httpProvider.requestNetResult(
       ApiConstants.apiLabourRequestReViewEditUK,
@@ -400,6 +494,11 @@ class UkLabourRepository extends GetxService {
     String? position,
     String? estCost,
     dynamic? attUrl,
+    String? videoText,
+    dynamic? videoCover,
+    dynamic? video,
+    dynamic? otherImage,
+    dynamic? otherDocument,
     CancelToken? cancelToken,
   }) async {
     //参数
@@ -456,6 +555,49 @@ class UkLabourRepository extends GetxService {
       }
     }
 
+    // 视频部分的参数
+    params['video_text'] = videoText ?? "";
+
+    //可能是file 也可能是  url
+    // 判断 http 或者 https 开头
+    if(Utils.isNotEmpty(videoCover)){
+      if(videoCover!.startsWith("http") || videoCover!.startsWith("https")){
+        params['video_cover'] = videoCover;
+      }else {
+        filePathParams['video_cover'] = videoCover;
+      }
+    }
+
+    //可能是file 也可能是  url
+    // 判断 http 或者 https 开头
+    if(Utils.isNotEmpty(video)){
+      if(video!.startsWith("http") || video!.startsWith("https")){
+        params['video'] = video;
+      }else {
+        filePathParams['video'] = video;
+      }
+    }
+
+    //可能是file 也可能是  url
+    // 判断 http 或者 https 开头
+    if(Utils.isNotEmpty(otherImage)){
+      if(otherImage!.startsWith("http") || otherImage!.startsWith("https")){
+        params['other_image'] = otherImage;
+      }else {
+        filePathParams['other_image'] = otherImage;
+      }
+    }
+
+    //可能是file 也可能是  url
+    // 判断 http 或者 https 开头
+    if(Utils.isNotEmpty(otherDocument)){
+      if(otherDocument!.startsWith("http") || otherDocument!.startsWith("https")){
+        params['other_document'] = otherDocument;
+      }else {
+        filePathParams['other_document'] = otherDocument;
+      }
+    }
+
 
     final result = await httpProvider.requestNetResult(
       ApiConstants.apiLabourRequestAddSubmit,

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

@@ -362,6 +362,13 @@ const Map<String, String> en_US = {
   'YY Casual Report By Payout Date (Based the Client Rate)': 'YY Casual Report By Payout Date (Based the Client Rate)',
   'Count': 'Count',
   'Gratuity': 'Gratuity',
+  'Name': 'Name',
+  'Industry': 'Industry',
+  'Video': 'Video',
+  'Video Text': 'Video Text',
+  'Video Cover': 'Video Cover',
+  'Video Image': 'Video Image',
+  'Video Document': 'Video Document',
 
   //插件的国际化
   'Pull to refresh': 'Pull to refresh',

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

@@ -363,6 +363,13 @@ const Map<String, String> zh_CN = {
   'YY Casual Report By Payout Date (Based the Client Rate)': '按支付日期的报告(基于客户费率)',
   'Count': '总数量',
   'Gratuity': '小费',
+  'Name': '名称',
+  'Industry': '行业',
+  'Video': '视频',
+  'Video Text': '视频文字',
+  'Video Cover': '视频封面',
+  'Video Image': '视频图片',
+  'Video Document': '视频文档',
 
   //插件的国际化
   'Pull to refresh': '下拉刷新',