1061 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			Dart
		
	
	
			
		
		
	
	
			1061 lines
		
	
	
		
			41 KiB
		
	
	
	
		
			Dart
		
	
	
| import 'dart:convert';
 | ||
| import 'dart:io';
 | ||
| 
 | ||
| import 'package:flutter/material.dart';
 | ||
| import 'package:intl/intl.dart';
 | ||
| import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart';
 | ||
| import 'package:qhd_prevention/customWidget/bottom_picker.dart';
 | ||
| import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
 | ||
| import 'package:qhd_prevention/customWidget/custom_button.dart';
 | ||
| import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.dart';
 | ||
| import 'package:qhd_prevention/customWidget/single_image_viewer.dart';
 | ||
| import 'package:qhd_prevention/customWidget/toast_util.dart';
 | ||
| import 'package:qhd_prevention/http/ApiService.dart';
 | ||
| import 'package:qhd_prevention/pages/KeyProjects/SafeCheck/custom/MultiTextFieldWithTitle.dart';
 | ||
| import 'package:qhd_prevention/pages/KeyProjects/SafeCheck/custom/safeCheck_table.dart';
 | ||
| import 'package:qhd_prevention/pages/KeyProjects/SafeCheck/custom/safe_drawer_page.dart';
 | ||
| import 'package:qhd_prevention/pages/app/Danger_paicha/quick_report_page.dart';
 | ||
| import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart';
 | ||
| import 'package:qhd_prevention/pages/my_appbar.dart';
 | ||
| import 'package:qhd_prevention/tools/tools.dart';
 | ||
| 
 | ||
| class SafecheckDetail extends StatefulWidget {
 | ||
|   const SafecheckDetail({
 | ||
|     super.key,
 | ||
|     required this.OUTSOURCED_ID,
 | ||
|     required this.KEYPROJECTCHECK_ID,
 | ||
|     required this.isEdit,
 | ||
|   });
 | ||
| 
 | ||
|   final String OUTSOURCED_ID;
 | ||
|   final String KEYPROJECTCHECK_ID;
 | ||
|   final bool isEdit;
 | ||
| 
 | ||
|   @override
 | ||
|   State<SafecheckDetail> createState() => _SafecheckDetailState();
 | ||
| }
 | ||
| 
 | ||
| class _SafecheckDetailState extends State<SafecheckDetail> {
 | ||
|   /// 被检查单位负责人
 | ||
|   late List<dynamic> personList = [];
 | ||
| 
 | ||
|   /// 检查类型
 | ||
|   late List<dynamic> typeList = [];
 | ||
| 
 | ||
|   /// 被检查单位
 | ||
|   late List<dynamic> toCheckUnitList = [];
 | ||
| 
 | ||
|   bool? chooseTitleType = null;
 | ||
| 
 | ||
|   // 存储多行输入的内容
 | ||
|   List<String> multiTexts = [];
 | ||
| 
 | ||
|   List<String> delInspectors = [];
 | ||
|   List<String> delSituations = [];
 | ||
|   List<String> delHiddens = [];
 | ||
|   List<String> delHiddenFiles = [];
 | ||
| 
 | ||
|   // rules 格式: [{ 'name': 'INSPECTION_CATEGORY', 'message': '请填写检查题目' }, ...]
 | ||
|   List<Map<String, String>> rules = [
 | ||
|     {'name': 'INSPECTION_CATEGORY', 'message': '请选择检查题目'},
 | ||
|     {'name': 'UNITS_ID', 'message': '请选择被检查单位'},
 | ||
|     {'name': 'PERSONNELMANAGEMENT_ID', 'message': '请选择被检查单位现场负责人'},
 | ||
|     {'name': 'INSPECTION_PLACE', 'message': '请输入检查场所'},
 | ||
|     {'name': 'INSPECTION_TYPE', 'message': '请选择检查类型'},
 | ||
|     {'name': 'INSPECTION_TIME_START', 'message': '请选择检查开始时间'},
 | ||
|     {'name': 'INSPECTION_TIME_END', 'message': '请选择作业结束时间'},
 | ||
| 
 | ||
|   ];
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|   Map<String, dynamic> form = {
 | ||
|     'INSPECTION_USERS': '',
 | ||
|     'KEYPROJECTCHECK_ID': '', // 检查ID
 | ||
|     'OUTSOURCED_ID': '', // 检查ID
 | ||
|     'INSPECTION_CATEGORY': '', // 检查标题
 | ||
|     'INSPECTION_SOURCE': '5', // 检查来源(4-监管端 5-企业端)
 | ||
|     'INSPECTION_ORIGINATOR_ID': '', // 检查发起人
 | ||
|     'UNITS_ID': '', // 被检查单位
 | ||
|     'UNITS_NAME': '',
 | ||
|     'PERSONNELMANAGEMENT_ID': '', // 被检查单位现场负责人
 | ||
|     'INSPECTED_SITEUSER_INDEX': '',
 | ||
|     'PERSON_NAME': '',
 | ||
|     'INSPECTED_EXPLAIN': '', // 申辩内容
 | ||
|     'INSPECTED_SITEUSER_SIGN_IMG': '', // 被检查单位现场负责人签字
 | ||
|     'INSPECTED_SITEUSER_SIGN_TIME': '', // 被检查单位现场负责人签字时间
 | ||
|     'INSPECTION_TYPE': '', // 检查类型
 | ||
|     'INSPECTION_TYPE_NAME': '',
 | ||
|     'INSPECTION_PLACE': '', // 检查场所
 | ||
|     'INSPECTION_TIME_START': '', // 检查开始时间
 | ||
|     'INSPECTION_TIME_END': '', // 检查结束时间
 | ||
|     'INSPECTION_STATUS': '0', // 状态
 | ||
|     'POSITIONDESC': '', // 隐患位置描述
 | ||
|     'CREATTIME': '',
 | ||
|     'inspectorList': [
 | ||
|       {
 | ||
|         'INSPECTION_INSPECTOR_ID': '', //检查人员主键
 | ||
|         'INSPECTION_DEPARTMENT_ID': '', //检查人员部门ID
 | ||
|         'INSPECTION_DEPARTMENT_NAME': '',
 | ||
|         'INSPECTION_USER_ID': '', //检查人员ID
 | ||
|         'INSPECTION_USER_INDEX': '',
 | ||
|         'INSPECTION_USER_NAME': '',
 | ||
|       },
 | ||
|     ],
 | ||
|     'situationList': [
 | ||
|       {'INSPECTION_SITUATION_ID': '', 'SITUATION': ''},
 | ||
|     ],
 | ||
|     'hiddenList': [
 | ||
|       {
 | ||
|         'ISRELEVANT': '2',
 | ||
|         'HIDDEN_ID': '', // 隐患ID
 | ||
|         'HIDDENDESCR': '', // 隐患描述
 | ||
|         'HIDDENPART': '', // 隐患部位
 | ||
|         'HIDDENPART_NAME': '',
 | ||
|         'HIDDENLEVEL': '', // 隐患级别
 | ||
|         'HIDDENLEVEL_NAME': '',
 | ||
|         'HIDDENTYPE': '', // 隐患类型1
 | ||
|         'HIDDENTYPE_NAME': '',
 | ||
|         'HIDDENTYPE2': '', // 隐患类型2
 | ||
|         'HIDDENTYPE2_NAME': '',
 | ||
|         'LONGITUDE': '', // 隐患位置经度
 | ||
|         'LATITUDE': '', // 隐患位置纬度
 | ||
|         'DISCOVERYTIME': '', // 隐患发现时间
 | ||
|         'HIDDENFINDDEPT': '', // 隐患发现部门(隐患责任人部门)
 | ||
|         'HIDDENFINDDEPT_NAME': '',
 | ||
|         'CREATOR': '', // 发现人(隐患责任人)
 | ||
|         'CREATOR_INDEX': '',
 | ||
|         'CREATOR_NAME': '',
 | ||
|         'SOURCE': '5', // 隐患来源
 | ||
|         'hiddenImgs': <String>[],
 | ||
|         'zgImgs': <String>[],
 | ||
|         'hiddenVideos': <String>[],
 | ||
|         'RECTIFICATIONTYPE': '2',
 | ||
|         'RECTIFICATIONDEADLINE': '',
 | ||
|         'RECTIFYDESCR': '',
 | ||
|         'RECTIFICATIONDEPT_NAME': '',
 | ||
|         'RECTIFICATIONDEPT': '',
 | ||
|         'RECTIFICATIONOR_INDEX': '',
 | ||
|         'HIDDENLEVEL_INDEX': '',
 | ||
|         'RECTIFICATIONOR_NAME': '',
 | ||
|         'RECTIFICATIONOR': '',
 | ||
|         'punishForm': null,
 | ||
|       },
 | ||
|     ],
 | ||
|     'INSPECTION_USER_SIGN_TIME': '',
 | ||
|     'INSPECTION_USER_OPINION': '',
 | ||
|   };
 | ||
| 
 | ||
|   @override
 | ||
|   void initState() {
 | ||
|     super.initState();
 | ||
|     form['OUTSOURCED_ID'] = widget.OUTSOURCED_ID;
 | ||
|     form['KEYPROJECTCHECK_ID'] = widget.KEYPROJECTCHECK_ID;
 | ||
|     form['hiddenList'] = [];
 | ||
|     WidgetsBinding.instance.addPostFrameCallback((_) {
 | ||
|       if (widget.KEYPROJECTCHECK_ID.isNotEmpty) {
 | ||
|         _getData();
 | ||
|       } else {
 | ||
|         // 只有在没有 KEYPROJECTCHECK_ID 时,才做本地的初始值设置
 | ||
|         setState(() {
 | ||
|           form['APPLY_DEPARTMENT_ID'] = SessionService.instance.deptId ?? '';
 | ||
|           form['APPLY_DEPARTMENT_NAME'] =
 | ||
|               SessionService.instance.loginUser?['DEPARTMENT_NAME'] ?? '';
 | ||
|           form['APPLY_USER_ID'] = SessionService.instance.loginUserId ?? '';
 | ||
|           form['APPLY_USER'] = SessionService.instance.username ?? '';
 | ||
|         });
 | ||
|       }
 | ||
|       // 无论如何都去拉取下拉/基础数据
 | ||
|       _getAllRequest();
 | ||
|     });
 | ||
|   }
 | ||
| 
 | ||
|   Future<void> _getData() async {
 | ||
|     try {
 | ||
|       final result = await ApiService.getSafeCheckGoEdit(
 | ||
|         widget.KEYPROJECTCHECK_ID,
 | ||
|       );
 | ||
|       // 在 await 之后检查 mounted,避免页面已经被 pop 导致 setState 报错
 | ||
|       if (!mounted) return;
 | ||
|       setState(() {
 | ||
|         form = result['pd'] ?? {};
 | ||
|         _syncMultiTextsFromForm();
 | ||
|       });
 | ||
|     } catch (e, st) {
 | ||
|       print('加载单条数据失败: $e\n$st');
 | ||
|       if (mounted) {
 | ||
|         ToastUtil.showNormal(context, '加载数据失败:$e');
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   Future<void> _getAllRequest() async {
 | ||
|     try {
 | ||
|       // 在网络请求前确保 widget 已经 build 完毕
 | ||
|       LoadingDialogHelper.show();
 | ||
| 
 | ||
|       final result = await ApiService.addSafeCheckRecord(widget.OUTSOURCED_ID);
 | ||
|       // 若页面已被销毁,就直接返回
 | ||
|       if (!mounted) {
 | ||
|         LoadingDialogHelper.hide();
 | ||
|         return;
 | ||
|       }
 | ||
| 
 | ||
|       setState(() {
 | ||
|         Map pd = result['pd'] ?? {};
 | ||
|         form['UNITS_NAME'] = pd['UNITS_NAME'] ?? '';
 | ||
|         form['UNITS_ID'] = pd['UNITS_ID'] ?? '';
 | ||
|         form['PERSONNELMANAGEMENT_ID'] = pd['PERSONNELMANAGEMENT_ID'] ?? '';
 | ||
|         form['PERSON_NAME'] = pd['NAME'] ?? '';
 | ||
|       });
 | ||
| 
 | ||
|       try {
 | ||
|         final personData = await ApiService.getSafeCheckPersonList(
 | ||
|           form['UNITS_ID'] ?? '',
 | ||
|           '1',
 | ||
|         );
 | ||
|         if (!mounted) return;
 | ||
|         setState(() {
 | ||
|           personList = personData['varList'] ?? [];
 | ||
|         });
 | ||
|       } catch (e) {
 | ||
|         print('加载 personList 失败: $e');
 | ||
|       }
 | ||
| 
 | ||
|       try {
 | ||
|         final typeListData = await ApiService.getSafeCheckTypeList();
 | ||
|         if (!mounted) return;
 | ||
|         setState(() {
 | ||
|           typeList = jsonDecode(typeListData['zTreeNodes'] ?? '[]');
 | ||
|         });
 | ||
|       } catch (e) {
 | ||
|         print('加载 typeList 失败: $e');
 | ||
|       }
 | ||
| 
 | ||
|       try {
 | ||
|         final toUnitListData = await ApiService.getSafeCheckToUnitList(
 | ||
|           widget.OUTSOURCED_ID,
 | ||
|         );
 | ||
|         if (!mounted) return;
 | ||
|         setState(() {
 | ||
|           toCheckUnitList = toUnitListData['varList'] ?? [];
 | ||
|           // 仅在没有选择时自动回填
 | ||
|           if (!FormUtils.hasValue(form, 'UNITS_NAME') &&
 | ||
|               toCheckUnitList.isNotEmpty) {
 | ||
|             form['UNITS_NAME'] = toCheckUnitList.first['UNITS_NAME'];
 | ||
|           }
 | ||
|           if (!FormUtils.hasValue(form, 'UNITS_ID') &&
 | ||
|               toCheckUnitList.isNotEmpty) {
 | ||
|             form['UNITS_ID'] = toCheckUnitList.first['UNITS_ID'];
 | ||
|           }
 | ||
| 
 | ||
|         });
 | ||
|       } catch (e) {
 | ||
|         print('加载 toCheckUnitList 失败: $e');
 | ||
|       }
 | ||
|     } catch (e, st) {
 | ||
|       print('总的加载失败: $e\n$st');
 | ||
|       if (mounted) ToastUtil.showNormal(context, '加载数据失败:$e');
 | ||
|     } finally {
 | ||
|       LoadingDialogHelper.hide();
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   Future<void> _choosePerson() async {
 | ||
|     final choice = await BottomPicker.show<String>(
 | ||
|       context,
 | ||
|       items: personList.map((val) => val['NAME'] as String).toList(),
 | ||
|       itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
 | ||
|       initialIndex: 0,
 | ||
|     );
 | ||
|     if (choice != null) {
 | ||
|       // 用户点击确定并选择了 choice
 | ||
|       setState(() {
 | ||
|         form['PERSON_NAME'] = choice;
 | ||
|         final data = FormUtils.findMapForKeyValue(personList, 'NAME', choice);
 | ||
|         form['PERSONNELMANAGEMENT_ID'] = data['PERSONNELMANAGEMENT_ID'];
 | ||
|         form['INSPECTED_SITEUSER_INDEX'] = personList.indexOf(data);
 | ||
| 
 | ||
|         //FocusHelper.clearFocus(context);
 | ||
|       });
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   Future<void> _chooseType() async {
 | ||
|     final choice = await BottomPicker.show<String>(
 | ||
|       context,
 | ||
|       items: typeList.map((val) => val['name'] as String).toList(),
 | ||
|       itemBuilder: (item) => Text(item, textAlign: TextAlign.center),
 | ||
|       initialIndex: 0,
 | ||
|     );
 | ||
|     if (choice != null) {
 | ||
|       // 用户点击确定并选择了 choice
 | ||
|       setState(() {
 | ||
|         form['INSPECTION_TYPE_NAME'] = choice;
 | ||
|         final data = FormUtils.findMapForKeyValue(typeList, 'name', choice);
 | ||
|         form['INSPECTION_TYPE'] = data['id'];
 | ||
| 
 | ||
|         //FocusHelper.clearFocus(context);
 | ||
|       });
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   Future<void> _openDrawer(Map<String, dynamic> hiddenForm, int index) async {
 | ||
|     try {
 | ||
|       final result = await openCustomDrawer<Map>(
 | ||
|         context,
 | ||
|         SafeDrawerPage(
 | ||
|           initialHidden: hiddenForm,
 | ||
|           editType:
 | ||
|               widget.isEdit
 | ||
|                   ? (index < 0 ? SafeEditType.add : SafeEditType.edit)
 | ||
|                   : SafeEditType.see,
 | ||
|           toCheckUnitList: toCheckUnitList,
 | ||
|         ),
 | ||
|       );
 | ||
| 
 | ||
|       if (result != null && mounted) {
 | ||
|         setState(() {
 | ||
|           if (index < 0) {
 | ||
|             // 新增
 | ||
|             form['hiddenList'].add(result);
 | ||
|           } else {
 | ||
|             // 修改
 | ||
|             form['hiddenList'][index] = result;
 | ||
|           }
 | ||
|         });
 | ||
|       }
 | ||
|     } catch (e) {
 | ||
|       print("打开抽屉失败: $e");
 | ||
|       ToastUtil.showNormal(context, "打开抽屉失败");
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   Future<T?> openCustomDrawer<T>(BuildContext context, Widget child) {
 | ||
|     return Navigator.of(context).push<T>(
 | ||
|       PageRouteBuilder(
 | ||
|         opaque: false,
 | ||
|         barrierDismissible: true,
 | ||
|         barrierColor: Colors.black54,
 | ||
|         pageBuilder: (_, __, ___) {
 | ||
|           return Align(
 | ||
|             alignment: Alignment.centerRight,
 | ||
|             child: FractionallySizedBox(
 | ||
|               widthFactor: 4 / 5,
 | ||
|               child: Material(color: Colors.white, child: child),
 | ||
|             ),
 | ||
|           );
 | ||
|         },
 | ||
|         transitionsBuilder: (_, anim, __, child) {
 | ||
|           return SlideTransition(
 | ||
|             position: Tween(
 | ||
|               begin: const Offset(1, 0),
 | ||
|               end: Offset.zero,
 | ||
|             ).animate(CurvedAnimation(parent: anim, curve: Curves.easeOut)),
 | ||
|             child: child,
 | ||
|           );
 | ||
|         },
 | ||
|       ),
 | ||
|     );
 | ||
|   }
 | ||
| 
 | ||
|   /// 将 form['situationList'](若存在)转换为 List<String>
 | ||
|   List<String> _situationListToStrings() {
 | ||
|     final List<dynamic> cur = List<dynamic>.from(form['situationList'] ?? []);
 | ||
|     if (cur.isEmpty) return ['']; // 保持至少一行,和 uni-app 行为一致
 | ||
|     return cur.map((e) {
 | ||
|       if (e is Map && e['SITUATION'] != null) return e['SITUATION'].toString();
 | ||
|       return '';
 | ||
|     }).toList();
 | ||
|   }
 | ||
| 
 | ||
|   /// 将 List<String> 转换成 uni-app 风格的 situationList(保留已存在的 INSPECTION_SITUATION_ID)
 | ||
|   List<Map<String, dynamic>> _stringsToSituationList(List<String> texts) {
 | ||
|     final List<dynamic> existing = List<dynamic>.from(
 | ||
|       form['situationList'] ?? [],
 | ||
|     );
 | ||
|     final List<Map<String, dynamic>> out = [];
 | ||
| 
 | ||
|     for (int i = 0; i < texts.length; i++) {
 | ||
|       final s = texts[i] ?? '';
 | ||
|       if (i < existing.length && existing[i] is Map) {
 | ||
|         // 保留已有项的其他字段(如 INSPECTION_SITUATION_ID),只覆盖 SITUATION
 | ||
|         final Map<String, dynamic> copy = Map<String, dynamic>.from(
 | ||
|           existing[i],
 | ||
|         );
 | ||
|         copy['SITUATION'] = s;
 | ||
|         // 若没有 INSPECTION_SITUATION_ID 字段,确保它存在(保持原 uni-app 结构)
 | ||
|         copy['INSPECTION_SITUATION_ID'] = copy['INSPECTION_SITUATION_ID'] ?? '';
 | ||
|         out.add(copy);
 | ||
|       } else {
 | ||
|         // 新增项
 | ||
|         out.add({'INSPECTION_SITUATION_ID': '', 'SITUATION': s});
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     // 如果用户删除了行,要把超出的 existing id 记录到 delSituations(可选)
 | ||
|     // 下面为示例:把被删除的旧 ID 收集到 delSituations,便于编辑时提交删除列表
 | ||
|     if (existing.isNotEmpty && existing.length > texts.length) {
 | ||
|       for (int j = texts.length; j < existing.length; j++) {
 | ||
|         final ex = existing[j];
 | ||
|         if (ex is Map) {
 | ||
|           final id = (ex['INSPECTION_SITUATION_ID'] ?? '').toString();
 | ||
|           if (id.isNotEmpty) {
 | ||
|             delSituations.add(id);
 | ||
|           }
 | ||
|         }
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     return out;
 | ||
|   }
 | ||
| 
 | ||
|   /// 在加载数据之后调用:把已存在的 form['situationList'] 同步到 multiTexts(用于 MultiTextFieldWithTitle)
 | ||
|   void _syncMultiTextsFromForm() {
 | ||
|     final List<String> arr = _situationListToStrings();
 | ||
|     setState(() {
 | ||
|       multiTexts = arr;
 | ||
|     });
 | ||
|   }
 | ||
| 
 | ||
|   // ------------ 提交入口 ------------
 | ||
|   Future<void> _submit() async {
 | ||
|     if (!widget.isEdit) {
 | ||
|       Navigator.of(context).pop();
 | ||
|       return;
 | ||
|     }
 | ||
|     bool required = true;
 | ||
|     // 基于 rules 验证
 | ||
|     for (final r in rules) {
 | ||
|       final name = r['name'] ?? '';
 | ||
|       final message = r['message'] ?? '请完善表单';
 | ||
|       final v = form[name];
 | ||
|       if (v == null || v.toString().isEmpty || v.toString() == '请选择') {
 | ||
|         LoadingDialogHelper.hide();
 | ||
|         ToastUtil.showNormal(context, message);
 | ||
|         required = false;
 | ||
|         break;
 | ||
|       }
 | ||
|     }
 | ||
|     if (!required) return;
 | ||
| 
 | ||
|     // situationList 每项 SITUATION 非空
 | ||
|     final situations = (form['situationList'] as List<dynamic>?) ?? [];
 | ||
|     for (var i = 0; i < situations.length; i++) {
 | ||
|       final s = Map<String, dynamic>.from(situations[i]);
 | ||
|       if ((s['SITUATION'] ?? '').toString().trim().isEmpty) {
 | ||
|         LoadingDialogHelper.hide();
 | ||
|         ToastUtil.showNormal(context, '请填写第${i + 1}项检查情况');
 | ||
|         return;
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|     // {'name': 'INSPECTION_USERS', 'message': '请输入检查人员'},
 | ||
|     final name2 = 'INSPECTION_USERS';
 | ||
|     final message2 ='请输入检查人员';
 | ||
|     final v = form[name2];
 | ||
|     if (v == null || v.toString().isEmpty || v.toString() == '请选择') {
 | ||
|       LoadingDialogHelper.hide();
 | ||
|       ToastUtil.showNormal(context, message2);
 | ||
|       return;
 | ||
|     }
 | ||
| 
 | ||
| 
 | ||
|     // 检查 inspectorList 中是否有重复 INSPECTION_USER_ID
 | ||
|     final List<Map<String, String>> inspectors = form['inspectorList'] ?? [];
 | ||
|     final seenIds = <String>{};
 | ||
|     for (final it in inspectors) {
 | ||
|       final id = (it as Map)['INSPECTION_USER_ID']?.toString() ?? '';
 | ||
|       if (id.isNotEmpty) {
 | ||
|         if (seenIds.contains(id)) {
 | ||
|           LoadingDialogHelper.hide();
 | ||
|           ToastUtil.showNormal(context, '检查人重复!请检查数据');
 | ||
|           return;
 | ||
|         }
 | ||
|         seenIds.add(id);
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     //根据 hiddenList 构建需要上传的文件数组
 | ||
|     final origHiddenList = (form['hiddenList'] as List<dynamic>?) ?? [];
 | ||
|     final List<List<Map<String, dynamic>>> hiddenFilesPerHidden = [];
 | ||
| 
 | ||
|     for (var i = 0; i < origHiddenList.length; i++) {
 | ||
|       final hidden = Map<String, dynamic>.from(origHiddenList[i] as Map);
 | ||
|       final List<Map<String, dynamic>> fileList = [];
 | ||
| 
 | ||
|       // hiddenImgs (多张)
 | ||
|       final hiddenImgs = (hidden['hiddenImgs'] as List<dynamic>?) ?? [];
 | ||
|       for (var j = 0; j < hiddenImgs.length; j++) {
 | ||
|         final img = hiddenImgs[j];
 | ||
|         // 如果是字符串路径
 | ||
|         if (img is String) {
 | ||
|           fileList.add({'type': 3, 'FILEPATH': img});
 | ||
|         } else if (img is Map) {
 | ||
|           final hasId = (img['IMGFILES_ID'] ?? '').toString().isNotEmpty;
 | ||
|           if (!hasId) {
 | ||
|             fileList.add({
 | ||
|               'type': 3,
 | ||
|               'FILEPATH': img['FILEPATH'] ?? img['path'] ?? '',
 | ||
|             });
 | ||
|           }
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|       // zgImgs (整改图)
 | ||
|       final zgImgs = (hidden['zgImgs'] as List<dynamic>?) ?? [];
 | ||
|       for (var j = 0; j < zgImgs.length; j++) {
 | ||
|         final img = zgImgs[j];
 | ||
|         if (img is String) {
 | ||
|           fileList.add({'type': 4, 'FILEPATH': img});
 | ||
|         } else if (img is Map) {
 | ||
|           final hasId = (img['IMGFILES_ID'] ?? '').toString().isNotEmpty;
 | ||
|           if (!hasId) {
 | ||
|             fileList.add({
 | ||
|               'type': 4,
 | ||
|               'FILEPATH': img['FILEPATH'] ?? img['path'] ?? '',
 | ||
|             });
 | ||
|           }
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|       // hiddenVideos (只取第一个)
 | ||
|       final hiddenVideos = (hidden['hiddenVideos'] as List<dynamic>?) ?? [];
 | ||
|       if (hiddenVideos.isNotEmpty) {
 | ||
|         final v = hiddenVideos[0];
 | ||
|         if (v is String) {
 | ||
|           fileList.add({'type': 102, 'FILEPATH': v});
 | ||
|         } else if (v is Map) {
 | ||
|           final hasId = (v['IMGFILES_ID'] ?? '').toString().isNotEmpty;
 | ||
|           if (!hasId) {
 | ||
|             fileList.add({
 | ||
|               'type': 102,
 | ||
|               'FILEPATH': v['FILEPATH'] ?? v['path'] ?? '',
 | ||
|             });
 | ||
|           }
 | ||
|         }
 | ||
|       }
 | ||
| 
 | ||
|       hiddenFilesPerHidden.add(fileList);
 | ||
|     }
 | ||
| 
 | ||
|     // 确保当前登录用户在 inspectorList 中(依据 SessionService)
 | ||
|     final loginUser = SessionService.instance.loginUser ?? {};
 | ||
|     final loginUserId = SessionService.instance.loginUserId ?? '';
 | ||
|     final idx = inspectors.indexWhere((item) {
 | ||
|       final m = Map<String, dynamic>.from(item as Map);
 | ||
|       return (m['INSPECTION_USER_ID'] ?? '') ==
 | ||
|           (loginUser['USER_ID'] ?? loginUserId);
 | ||
|     });
 | ||
|     if (idx < 0) {
 | ||
|       inspectors.add({
 | ||
|         'INSPECTION_INSPECTOR_ID': '',
 | ||
|         'INSPECTION_DEPARTMENT_ID': loginUser['DEPARTMENT_ID'] ?? '',
 | ||
|         'INSPECTION_DEPARTMENT_NAME': loginUser['DEPARTMENT_NAME'] ?? '',
 | ||
|         'INSPECTION_USER_ID': loginUser['USER_ID'] ?? loginUserId,
 | ||
|         'INSPECTION_USER_INDEX': '',
 | ||
|         'INSPECTION_USER_NAME': loginUser['NAME'] ?? '',
 | ||
|       });
 | ||
|     }
 | ||
|     // 使用 Expando 标记已访问对象,防止循环引用
 | ||
|     final seen = Expando<bool>();
 | ||
|     final sanitized = _sanitizeForJson(origHiddenList, seen);
 | ||
|     // 如果 sanitized 为 null(极少见),退回到空列表
 | ||
|     final safeForJson = sanitized ?? [];
 | ||
|     String HIDDENJSON = jsonEncode(safeForJson);
 | ||
| 
 | ||
|     // 准备 form 字段(JSON 字符串等)
 | ||
|     form['INSPECTORJSON'] = jsonEncode(inspectors);
 | ||
|     form['SITUATIONJSON'] = jsonEncode(situations);
 | ||
|     form['HIDDENJSON'] = HIDDENJSON;
 | ||
|     form['delInspectors'] = delInspectors.join(',');
 | ||
|     form['delSituations'] = delSituations.join(',');
 | ||
|     form['delHiddens'] = delHiddens.join(',');
 | ||
|     form['delHiddenFiles'] = delHiddenFiles.join(',');
 | ||
|     form['CREATOR'] = loginUser['USER_ID'] ?? loginUserId;
 | ||
|     form['CORPINFO_ID'] = SessionService.instance.corpinfoId ?? '';
 | ||
|     form['ACTION_USER'] = loginUser['NAME'] ?? '';
 | ||
| 
 | ||
|     // 提交主表
 | ||
|     try {
 | ||
|       LoadingDialogHelper.show();
 | ||
|       final res = await ApiService.safeKeyprojectCheckSubmit(form);
 | ||
|       // 如果你的 ApiService 返回结构不同,请按实际调整判断
 | ||
|       if (res != null && res['result'] == 'success') {
 | ||
|         final pd = res['pd'] ?? {};
 | ||
|         final List<dynamic> returnedHiddenList = pd['hiddenList'] ?? [];
 | ||
| 
 | ||
|         // 如果没有附件需要上传,直接完成
 | ||
|         final hasFiles = hiddenFilesPerHidden.any((lst) => lst.isNotEmpty);
 | ||
|         if (!hasFiles) {
 | ||
|           LoadingDialogHelper.hide();
 | ||
|           ToastUtil.showNormal(context, '提交成功');
 | ||
|           Navigator.of(context).pop();
 | ||
|           return;
 | ||
|         }
 | ||
| 
 | ||
|         // 若每个 hidden 有 punishForm,需要先提交罚单
 | ||
|         for (var i = 0; i < returnedHiddenList.length; i++) {
 | ||
|           if (i < (form['hiddenList'] as List).length) {
 | ||
|             final hidden = Map<String, dynamic>.from(
 | ||
|               (form['hiddenList'] as List)[i],
 | ||
|             );
 | ||
|             final punishForm = hidden['punishForm'];
 | ||
|             if (punishForm != null) {
 | ||
|               final hid = (returnedHiddenList[i]['HIDDEN_ID'] ?? '').toString();
 | ||
|               punishForm['HIDDEN_ID'] = hid;
 | ||
|               // await 调用罚单提交(在下面实现)
 | ||
|               await fnSubmit(Map<String, dynamic>.from(punishForm));
 | ||
|             }
 | ||
|           }
 | ||
|         }
 | ||
| 
 | ||
|         // 上传所有附件(按隐患对应的 hiddenId)
 | ||
|         // 把返回的 hiddenList 转为 Map 列表,确保索引一致
 | ||
|         final returnedHiddenMapList =
 | ||
|             returnedHiddenList
 | ||
|                 .map((e) => Map<String, dynamic>.from(e))
 | ||
|                 .toList();
 | ||
|         await uploadHiddenFiles(hiddenFilesPerHidden, returnedHiddenMapList);
 | ||
| 
 | ||
|         LoadingDialogHelper.hide();
 | ||
|         ToastUtil.showNormal(context, '提交成功');
 | ||
|         Navigator.of(context).pop();
 | ||
|       } else {
 | ||
|         LoadingDialogHelper.hide();
 | ||
|         final msg =
 | ||
|             res != null
 | ||
|                 ? (res['msg'] ?? res['msaesge'] ?? res['message'] ?? '提交失败')
 | ||
|                 : '提交失败';
 | ||
|         ToastUtil.showNormal(context, msg);
 | ||
|       }
 | ||
|     } catch (e) {
 | ||
|       LoadingDialogHelper.hide();
 | ||
|       ToastUtil.showNormal(context, '提交异常:$e');
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // Helper: 将任意结构"净化"成可 JSON 序列化的形式(打断循环、替换 File 等)
 | ||
|   dynamic _sanitizeForJson(dynamic value, Expando<bool> seen) {
 | ||
|     // 常量直接返回
 | ||
|     if (value == null || value is num || value is bool || value is String)
 | ||
|       return value;
 | ||
| 
 | ||
|     // 防止循环引用:如果已经访问过,直接返回 null 或一个占位符
 | ||
|     try {
 | ||
|       if (seen[value] == true) {
 | ||
|         // 已访问 -> 打断循环。返回 null 也可以改为返回字符串 "(circular)"
 | ||
|         return null;
 | ||
|       }
 | ||
|     } catch (_) {
 | ||
|       // 某些原始类型可能不能作为 Expando key ——忽略
 | ||
|     }
 | ||
| 
 | ||
|     // 标记为已访问(仅对引用类型有意义)
 | ||
|     try {
 | ||
|       seen[value] = true;
 | ||
|     } catch (_) {}
 | ||
| 
 | ||
|     // 特殊类型处理
 | ||
|     if (value is File) {
 | ||
|       return value.path; // 或者 path 的 basename: p.basename(value.path)
 | ||
|     }
 | ||
|     if (value is DateTime) return value.toIso8601String();
 | ||
|     if (value is Uri) return value.toString();
 | ||
| 
 | ||
|     // Map -> 递归处理键值(键转成字符串)
 | ||
|     if (value is Map) {
 | ||
|       final out = <String, dynamic>{};
 | ||
|       for (final entry in value.entries) {
 | ||
|         final k = entry.key?.toString() ?? '';
 | ||
|         final v = _sanitizeForJson(entry.value, seen);
 | ||
|         if (v != null) out[k] = v;
 | ||
|       }
 | ||
|       return out;
 | ||
|     }
 | ||
| 
 | ||
|     // List/Iterable -> 递归处理元素,过滤 null
 | ||
|     if (value is Iterable) {
 | ||
|       final listOut = <dynamic>[];
 | ||
|       for (final e in value) {
 | ||
|         final s = _sanitizeForJson(e, seen);
 | ||
|         if (s != null) listOut.add(s);
 | ||
|       }
 | ||
|       return listOut;
 | ||
|     }
 | ||
| 
 | ||
|     // 其他不可直接序列化的对象:尝试用 toString() 作为备选(或返回 null)
 | ||
|     try {
 | ||
|       return value.toString();
 | ||
|     } catch (_) {
 | ||
|       return null;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // ========== 上传附件的方法 ==========
 | ||
|   Future<void> uploadHiddenFiles(
 | ||
|     List<List<Map<String, dynamic>>> hiddenFilesPerHidden,
 | ||
|     List<Map<String, dynamic>> returnedHiddenList,
 | ||
|   ) async {
 | ||
|     for (var i = 0; i < hiddenFilesPerHidden.length; i++) {
 | ||
|       final filesForHidden = hiddenFilesPerHidden[i];
 | ||
|       if (filesForHidden.isEmpty) continue;
 | ||
|       final hiddenId =
 | ||
|           i < returnedHiddenList.length
 | ||
|               ? (returnedHiddenList[i]['HIDDEN_ID']?.toString() ?? '')
 | ||
|               : '';
 | ||
|       if (hiddenId.isEmpty) continue;
 | ||
| 
 | ||
|       for (final f in filesForHidden) {
 | ||
|         final filePath = f['FILEPATH']?.toString() ?? '';
 | ||
|         final type = f['type']?.toString() ?? '';
 | ||
|         if (filePath.isEmpty) continue;
 | ||
|         try {
 | ||
|           await ApiService.addImgFiles(filePath, type, hiddenId);
 | ||
|         } catch (e) {
 | ||
|           // 你可以记录失败项或重试,这里先忽略单文件错误
 | ||
|           print('上传文件失败: $e (path=$filePath)');
 | ||
|         }
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   // ========== 罚单提交方法(对应原 fnSubmit) ==========
 | ||
|   Future<bool> fnSubmit(Map<String, dynamic>? ordForm) async {
 | ||
|     if (ordForm == null) return false;
 | ||
| 
 | ||
|     final Map<String, String> punishRules = {
 | ||
|       'REASON': '请填写处罚原因',
 | ||
|       'AMOUT': '请填写处罚金额',
 | ||
|       'DATE': '请选择下发处罚时间',
 | ||
|     };
 | ||
|     // 校验
 | ||
|     for (final entry in punishRules.entries) {
 | ||
|       final key = entry.key;
 | ||
|       final msg = entry.value;
 | ||
|       final val = ordForm[key];
 | ||
|       if (val == null || val.toString().trim().isEmpty) {
 | ||
|         ToastUtil.showNormal(context, msg);
 | ||
|         return false;
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     final requestData = Map<String, dynamic>.from(ordForm);
 | ||
|     requestData['CORPINFO_ID'] = SessionService.instance.corpinfoId ?? '';
 | ||
|     requestData['CREATOR'] = SessionService.instance.loginUserId ?? '';
 | ||
|     requestData['OPERATOR'] = SessionService.instance.loginUserId ?? '';
 | ||
| 
 | ||
|     try {
 | ||
|       LoadingDialogHelper.show();
 | ||
|       final res = await ApiService.safeCheckPunishSubmit(requestData);
 | ||
|       LoadingDialogHelper.hide();
 | ||
|       if (FormUtils.hasValue(res, 'result') && res['result'] == 'success') {
 | ||
|         return true;
 | ||
|       } else {
 | ||
|         final msg =
 | ||
|             res != null
 | ||
|                 ? (res['msg'] ?? res['msaesge'] ?? res['message'] ?? '提交失败')
 | ||
|                 : '提交失败';
 | ||
|         ToastUtil.showNormal(context, msg);
 | ||
|         return false;
 | ||
|       }
 | ||
|     } catch (e) {
 | ||
|       LoadingDialogHelper.hide();
 | ||
|       ToastUtil.showNormal(context, '罚单提交异常:$e');
 | ||
|       return false;
 | ||
|     }
 | ||
|   }
 | ||
|   Map _getCheckUnit() {
 | ||
|     for (Map item in toCheckUnitList) {
 | ||
|       if (item['UNITS_ID'] == form['UNITS_ID']) {
 | ||
|         return item;
 | ||
|       }
 | ||
|     }
 | ||
|     return {};
 | ||
|   }
 | ||
|   @override
 | ||
|   Widget build(BuildContext context) {
 | ||
|     Map checkUnitData = _getCheckUnit();
 | ||
|     return Scaffold(
 | ||
|       appBar: MyAppbar(title: "安全检查发起", actions: []),
 | ||
| 
 | ||
|       body: SafeArea(
 | ||
|         child: Padding(
 | ||
|           padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12),
 | ||
|           child:
 | ||
|               form.isNotEmpty
 | ||
|                   ? ListView(
 | ||
|                     children: [
 | ||
|                       Column(
 | ||
|                         children: [
 | ||
|                           ItemListWidget.itemContainer(
 | ||
|                             horizontal: 0,
 | ||
|                             Column(
 | ||
|                               children: [
 | ||
|                                 ListItemFactory.createYesNoSection(
 | ||
|                                   title: '检查题目:',
 | ||
|                                   groupValue: chooseTitleType,
 | ||
|                                   yesLabel: '安全',
 | ||
|                                   noLabel: '综合',
 | ||
|                                   isEdit: widget.isEdit,
 | ||
|                                   isRequired: true,
 | ||
|                                   horizontalPadding: 5,
 | ||
|                                   verticalPadding: 0,
 | ||
|                                   text: form['INSPECTION_CATEGORY'] ?? '',
 | ||
|                                   onChanged: (val) {
 | ||
|                                     setState(() {
 | ||
|                                       chooseTitleType = val;
 | ||
|                                       form['INSPECTION_CATEGORY'] =
 | ||
|                                           val == true ? '安全' : '综合';
 | ||
|                                     });
 | ||
|                                   },
 | ||
|                                 ),
 | ||
|                                 const Divider(),
 | ||
|                                 ItemListWidget.singleLineTitleText(
 | ||
|                                   label: '被检查单位:',
 | ||
|                                   isEditable: false,
 | ||
|                                   text: form['UNITS_NAME'],
 | ||
|                                   onChanged: (val) {
 | ||
|                                     setState(() {
 | ||
|                                       form['UNITS_NAME'] = val;
 | ||
|                                     });
 | ||
|                                   },
 | ||
|                                 ),
 | ||
|                                 const Divider(),
 | ||
| 
 | ||
|                                 ItemListWidget.selectableLineTitleTextRightButton(
 | ||
|                                   label: '被检查单位现场负责人:',
 | ||
|                                   isEditable: widget.isEdit,
 | ||
|                                   onTap: () {
 | ||
|                                     _choosePerson();
 | ||
|                                   },
 | ||
|                                   text: form['PERSON_NAME'] ?? '',
 | ||
|                                 ),
 | ||
|                                 const Divider(),
 | ||
| 
 | ||
|                                 ItemListWidget.singleLineTitleText(
 | ||
|                                   label: '检查场所:',
 | ||
|                                   isEditable: widget.isEdit,
 | ||
|                                   text: form['INSPECTION_PLACE'],
 | ||
|                                   hintText: '请输入检查场所',
 | ||
|                                   onChanged: (val) {
 | ||
|                                     setState(() {
 | ||
|                                       form['INSPECTION_PLACE'] = val;
 | ||
|                                     });
 | ||
|                                   },
 | ||
|                                 ),
 | ||
|                                 const Divider(),
 | ||
| 
 | ||
|                                 ItemListWidget.selectableLineTitleTextRightButton(
 | ||
|                                   label: '检查类型:',
 | ||
|                                   onTap: () {
 | ||
|                                     _chooseType();
 | ||
|                                   },
 | ||
|                                   isEditable: widget.isEdit,
 | ||
|                                   text: form['INSPECTION_TYPE_NAME'] ?? '',
 | ||
|                                 ),
 | ||
|                                 const Divider(),
 | ||
| 
 | ||
|                                 ItemListWidget.selectableLineTitleTextRightButton(
 | ||
|                                   label: '检查开始时间:',
 | ||
|                                   isEditable: widget.isEdit,
 | ||
|                                   text: form['INSPECTION_TIME_START'] ?? '',
 | ||
|                                   onTap: () async {
 | ||
|                                     DateTime? picked =
 | ||
|                                         await BottomDateTimePicker.showDate(
 | ||
|                                           context,
 | ||
|                                           mode:
 | ||
|                                               BottomPickerMode
 | ||
|                                                   .dateTime,
 | ||
|                                         );
 | ||
|                                     if (picked != null) {
 | ||
|                                       setState(() {
 | ||
|                                         form['INSPECTION_TIME_START'] =
 | ||
|                                             DateFormat(
 | ||
|                                               'yyyy-MM-dd HH:mm',
 | ||
|                                             ).format(picked);
 | ||
|                                         /// 开始时间必须早于结束时间
 | ||
|                                         if (FormUtils.hasValue(form, 'INSPECTION_TIME_END') &&
 | ||
|                                             !isBeforeStr(
 | ||
|                                               form['INSPECTION_TIME_START'],
 | ||
|                                               form['INSPECTION_TIME_END'],
 | ||
|                                             )) {
 | ||
|                                           form['INSPECTION_TIME_END'] = '';
 | ||
|                                         }
 | ||
|                                       });
 | ||
|                                       //FocusHelper.clearFocus(context);
 | ||
|                                     }
 | ||
|                                   },
 | ||
|                                 ),
 | ||
|                                 const Divider(),
 | ||
| 
 | ||
|                                 ItemListWidget.selectableLineTitleTextRightButton(
 | ||
|                                   label: '检查结束时间:',
 | ||
|                                   isEditable: widget.isEdit,
 | ||
|                                   text: form['INSPECTION_TIME_END'] ?? '',
 | ||
|                                   onTap: () async {
 | ||
|                                     DateTime? picked =
 | ||
|                                         await BottomDateTimePicker.showDate(
 | ||
|                                           context,
 | ||
|                                           minTimeStr: form['INSPECTION_TIME_START'] ?? '',
 | ||
|                                           mode:
 | ||
|                                               BottomPickerMode
 | ||
|                                                   .dateTime,
 | ||
|                                         );
 | ||
|                                     if (picked != null) {
 | ||
|                                       setState(() {
 | ||
|                                         form['INSPECTION_TIME_END'] =
 | ||
|                                             DateFormat(
 | ||
|                                               'yyyy-MM-dd HH:mm',
 | ||
|                                             ).format(picked);
 | ||
| 
 | ||
|                                       });
 | ||
|                                       //FocusHelper.clearFocus(context);
 | ||
|                                     }
 | ||
|                                   },
 | ||
|                                 ),
 | ||
|                                 const Divider(),
 | ||
|                                 MultiTextFieldWithTitle(
 | ||
|                                   label: "检查情况",
 | ||
|                                   // 更合适的标题
 | ||
|                                   isEditable: widget.isEdit,
 | ||
|                                   // 使用父组件的编辑状态
 | ||
|                                   hintText: "请输入检查情况...",
 | ||
|                                   texts: multiTexts,
 | ||
|                                   onTextsChanged: (texts) {
 | ||
|                                     setState(() {
 | ||
|                                       multiTexts = texts; // 保存到状态变量
 | ||
|                                       form['situationList'] =
 | ||
|                                           _stringsToSituationList(texts);
 | ||
|                                     });
 | ||
|                                   },
 | ||
|                                 ),
 | ||
| 
 | ||
|                                 const Divider(),
 | ||
|                                 ItemListWidget.multiLineTitleTextField(
 | ||
|                                   label: '检查人员',
 | ||
|                                   text: form['INSPECTION_USERS'] ?? '',
 | ||
|                                   isEditable: widget.isEdit,
 | ||
|                                   onChanged: (val) {
 | ||
|                                     setState(() {
 | ||
|                                       form['INSPECTION_USERS'] = val;
 | ||
|                                     });
 | ||
|                                   },
 | ||
|                                 ),
 | ||
|                                 const Divider(),
 | ||
|                                 ItemListWidget.itemContainer(
 | ||
|                                   Row(
 | ||
|                                     mainAxisAlignment:
 | ||
|                                         MainAxisAlignment.spaceBetween,
 | ||
|                                     children: [
 | ||
|                                       ListItemFactory.headerTitle('发现问题'),
 | ||
|                                       if (widget.isEdit)
 | ||
|                                         CustomButton(
 | ||
|                                           text: "   添加   ",
 | ||
|                                           height: 30,
 | ||
|                                           padding: const EdgeInsets.symmetric(
 | ||
|                                             vertical: 2,
 | ||
|                                             horizontal: 5,
 | ||
|                                           ),
 | ||
|                                           backgroundColor: Colors.blue,
 | ||
|                                           onPressed: () {
 | ||
|                                             _openDrawer(
 | ||
|                                               {'RECTIFICATIONDEPT': checkUnitData['UNITS_ID'] ?? '',
 | ||
|                                               'RECTIFICATIONDEPT_NAME': form['UNITS_NAME'] ?? '',
 | ||
|                                               'RECTIFICATIONOR':form['PERSONNELMANAGEMENT_ID'],
 | ||
|                                               'RECTIFICATIONOR_NAME': form['PERSON_NAME']},
 | ||
|                                               -1,
 | ||
|                                             ); // 添加括号和 await
 | ||
|                                             //FocusHelper.clearFocus(context);
 | ||
|                                           },
 | ||
|                                         ),
 | ||
|                                     ],
 | ||
|                                   ),
 | ||
|                                 ),
 | ||
|                                 HiddenListTable(
 | ||
|                                   hiddenList: form['hiddenList'] ?? [],
 | ||
|                                   forbidEdit: widget.isEdit,
 | ||
|                                   baseImgPath: ApiService.baseImgPath,
 | ||
|                                   personSignImg: form['PERSON_SIGN_IMG'] ?? '',
 | ||
|                                   personSignTime:
 | ||
|                                       form['PERSON_SIGN_TIME'] ?? '',
 | ||
|                                   showHidden: (item, idx) {
 | ||
|                                     _openDrawer(item, idx);
 | ||
|                                   },
 | ||
|                                   removeHidden: (item, idx) {
 | ||
|                                     /* 删除逻辑 */
 | ||
|                                   },
 | ||
|                                   context: context,
 | ||
|                                 ),
 | ||
| 
 | ||
|                                 if (!widget.isEdit)
 | ||
|                                   Column(
 | ||
|                                     children: [
 | ||
|                                       const Divider(),
 | ||
|                                       ItemListWidget.twoRowTitleAndImages(
 | ||
|                                         title: '签字',
 | ||
|                                         onTapCallBack: (p) {
 | ||
|                                           presentOpaque(
 | ||
|                                             SingleImageViewer(imageUrl: p),
 | ||
|                                             context,
 | ||
|                                           );
 | ||
|                                         },
 | ||
|                                         imageUrls: [
 | ||
|                                           '${form['PERSON_SIGN_IMG'] ?? ''}',
 | ||
|                                         ],
 | ||
|                                       ),
 | ||
|                                       const Divider(),
 | ||
|                                       ItemListWidget.singleLineTitleText(
 | ||
|                                         label: '签字时间',
 | ||
|                                         isEditable: false,
 | ||
|                                         text: form['PERSON_SIGN_TIME'] ?? '',
 | ||
|                                       ),
 | ||
|                                     ],
 | ||
|                                   ),
 | ||
|                               ],
 | ||
|                             ),
 | ||
|                           ),
 | ||
|                           SizedBox(height: 20),
 | ||
|                           Row(
 | ||
|                             mainAxisAlignment: MainAxisAlignment.center,
 | ||
|                             children: [
 | ||
|                               if (widget.isEdit)
 | ||
|                                 SizedBox(
 | ||
|                                   width: 150,
 | ||
|                                   child: CustomButton(
 | ||
|                                     text: '返回',
 | ||
|                                     textStyle: TextStyle(
 | ||
|                                       color: Colors.white,
 | ||
|                                       fontSize: 17,
 | ||
|                                     ),
 | ||
|                                     backgroundColor: Colors.black38,
 | ||
|                                     onPressed: () => Navigator.pop(context),
 | ||
|                                   ),
 | ||
|                                 ),
 | ||
|                               SizedBox(
 | ||
|                                 width: 150,
 | ||
|                                 child: CustomButton(
 | ||
|                                   text: widget.isEdit ? '提交' : '返回',
 | ||
|                                   textStyle: TextStyle(
 | ||
|                                     color: Colors.white,
 | ||
|                                     fontSize: 17,
 | ||
|                                   ),
 | ||
|                                   backgroundColor: Colors.blue,
 | ||
|                                   onPressed: _submit,
 | ||
|                                 ),
 | ||
|                               ),
 | ||
|                             ],
 | ||
|                           ),
 | ||
|                         ],
 | ||
|                       ),
 | ||
|                     ],
 | ||
|                   )
 | ||
|                   : SizedBox(),
 | ||
|         ),
 | ||
|       ),
 | ||
|     );
 | ||
|   }
 | ||
| }
 |