diff --git a/lib/constants/app_enums.dart b/lib/constants/app_enums.dart index 82e8fcb..2229752 100644 --- a/lib/constants/app_enums.dart +++ b/lib/constants/app_enums.dart @@ -476,6 +476,11 @@ enum UploadFileType { '410', 'special_operation_special_apply_involved_signature', ), + // 进出有限空间记录 - 类型: '411', + specialOperationInAndOutRecord( + '411', + 'special_operation_in_and_out_record', + ), diff --git a/lib/pages/home/Tap/special_work/custom/SafeMeasureOption.dart b/lib/pages/home/Tap/special_work/custom/SafeMeasureOption.dart index 21e6bdc..52f569b 100644 --- a/lib/pages/home/Tap/special_work/custom/SafeMeasureOption.dart +++ b/lib/pages/home/Tap/special_work/custom/SafeMeasureOption.dart @@ -169,6 +169,10 @@ class SafeProtectionController extends ChangeNotifier { notifyListeners(); } + void refresh() { + notifyListeners(); + } + void ensureAtLeastOneGroup() { if (_groups.isEmpty) { addGroup(); @@ -359,6 +363,7 @@ class SafeProtectionModule extends StatefulWidget { this.title = '安全防护措施', this.otherTitle = '其他安全措施', this.showOtherSection = false, + this.showAddButton = false, this.onChanged, }); @@ -372,6 +377,7 @@ class SafeProtectionModule extends StatefulWidget { final String title; final String otherTitle; final bool showOtherSection; + final bool showAddButton; final SafeMeasuresChanged? onChanged; @override @@ -451,18 +457,24 @@ class _SafeProtectionModuleState extends State { onSelectedWithData: (updateId, name, data) { setState(() { for (SafeMeasureGroup g in widget.controller.groups) { - // 判重updateId - if (g.updateId == updateId && widget.controller.groups.length > 1) { + if (widget.controller.groups.length > 1 && + g != group && + g.updateId == updateId) { ToastUtil.showNormal(context, '确认人不能重复'); return; } } group.updateId = updateId; group.updateName = name; - group.actUser = data['actUserId'] ?? ''; + group.actUser = updateId; + group.actUserName = name; group.departmentId = data['departmentId'] ?? ''; - group.departmentName = data['departmentName'] ?? data['actUserDepartmentName'] ?? ''; + group.departmentName = + data['departmentName'] ?? data['actUserDepartmentName'] ?? ''; + group.actUserDepartment = group.departmentId; + group.actUserDepartmentName = group.departmentName; }); + widget.controller.refresh(); widget.onChanged?.call(); }, ); @@ -537,16 +549,17 @@ class _SafeProtectionModuleState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ListItemFactory.createBuildSimpleSection(widget.title), - CustomButton( - text: '添加', - padding: const EdgeInsets.symmetric(horizontal: 15), - backgroundColor: Colors.blue, - height: 32, - onPressed: - widget.isEditable - ? () => setState(() => widget.controller.addGroup()) - : null, - ), + if (widget.showAddButton) + CustomButton( + text: '添加', + padding: const EdgeInsets.symmetric(horizontal: 15), + backgroundColor: Colors.blue, + height: 32, + onPressed: + widget.isEditable + ? () => setState(() => widget.controller.addGroup()) + : null, + ), ], ), ...widget.controller.groups.asMap().entries.map((entry) { @@ -669,4 +682,4 @@ class _SafeProtectionModuleState extends State { ), ); } -} \ No newline at end of file +} diff --git a/lib/pages/home/Tap/special_work/dh_work/HotWorkDetailFormWidget.dart b/lib/pages/home/Tap/special_work/dh_work/HotWorkDetailFormWidget.dart index 790f178..b1ae884 100644 --- a/lib/pages/home/Tap/special_work/dh_work/HotWorkDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/dh_work/HotWorkDetailFormWidget.dart @@ -155,7 +155,7 @@ class _HotWorkDetailFormWidgetState extends State { ), const Divider(), ItemListWidget.selectableLineTitleTextRightButton( - label: '申请日期:', + label: '申请时间:', text: pd['applyTime'] ?? '', isEditable: widget.isEditable, onTap: () async {}, diff --git a/lib/pages/home/Tap/special_work/dh_work/hot_apply_page.dart b/lib/pages/home/Tap/special_work/dh_work/hot_apply_page.dart index b90676c..143fb4e 100644 --- a/lib/pages/home/Tap/special_work/dh_work/hot_apply_page.dart +++ b/lib/pages/home/Tap/special_work/dh_work/hot_apply_page.dart @@ -143,9 +143,9 @@ class _HotWorkApplyPageState extends SpecialWorkApplyBaseState text: pd['applyUser'] ?? '', ), const Divider(), - // 申请日期 + // 申请时间 ItemListWidget.selectableLineTitleTextRightButton( - label: '申请日期:', + label: '申请时间:', isEditable: isEditable, onTap: () async { final picked = await BottomDateTimePicker.showDate( @@ -507,4 +507,4 @@ class _HotWorkApplyPageState extends SpecialWorkApplyBaseState }, ); } -} \ No newline at end of file +} diff --git a/lib/pages/home/Tap/special_work/dl_work/breakgroundDetailFormWidget.dart b/lib/pages/home/Tap/special_work/dl_work/breakgroundDetailFormWidget.dart index a6b6397..891961c 100644 --- a/lib/pages/home/Tap/special_work/dl_work/breakgroundDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/dl_work/breakgroundDetailFormWidget.dart @@ -144,7 +144,13 @@ class _BreakgroundDetailFormWidgetState extends State { text: pd['applyUser'] ?? '', ), const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '申请时间:', + isEditable: isEditable, + onTap: () async { + final picked = await BottomDateTimePicker.showDate( + mode: BottomPickerMode.dateTimeWithSeconds, + context, + allowFuture: true, + allowPast: false, + ); + if (picked != null) { + setState(() { + pd['applyTime'] = DateFormat( + 'yyyy-MM-dd HH:mm:ss', + ).format(picked); + }); + } + }, + text: pd['applyTime'] ?? '', + ), + const Divider(), // 作业类型(内部/相关方) if (enableInnerWorkSwitch) ...[ ItemListWidget.selectableLineTitleTextRightButton( @@ -360,7 +381,7 @@ class _DlApplyPageState extends SpecialWorkApplyBaseState { groups[index]['actUserName'] = name; groups[index]['actUserDepartment'] = data['departmentId'] ?? ''; groups[index]['actUserDepartmentName'] = data['departmentName'] ?? ''; - + syncSafeMeasureConfirmersWithGasAnalyzer(data); }); }, ); @@ -433,4 +454,4 @@ class _DlApplyPageState extends SpecialWorkApplyBaseState { } return true; } -} \ No newline at end of file +} diff --git a/lib/pages/home/Tap/special_work/dt_work/cutRoadDetailFormWidget.dart b/lib/pages/home/Tap/special_work/dt_work/cutRoadDetailFormWidget.dart index 1d41437..5614cda 100644 --- a/lib/pages/home/Tap/special_work/dt_work/cutRoadDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/dt_work/cutRoadDetailFormWidget.dart @@ -144,7 +144,13 @@ class _CutRoadDetailFormWidgetState extends State { isEditable: false, text: pd['applyUser'] ?? '', ), - + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '申请时间:', + text: pd['applyTime'] ?? '', + isEditable: widget.isEditable, + onTap: () async {}, + ), const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '作业类型:', diff --git a/lib/pages/home/Tap/special_work/dt_work/dt_apply_page.dart b/lib/pages/home/Tap/special_work/dt_work/dt_apply_page.dart index 942bee0..b88c91b 100644 --- a/lib/pages/home/Tap/special_work/dt_work/dt_apply_page.dart +++ b/lib/pages/home/Tap/special_work/dt_work/dt_apply_page.dart @@ -157,6 +157,27 @@ class _DtApplyPageState extends SpecialWorkApplyBaseState { text: pd['applyUser'] ?? '', ), const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '申请时间:', + isEditable: isEditable, + onTap: () async { + final picked = await BottomDateTimePicker.showDate( + mode: BottomPickerMode.dateTimeWithSeconds, + context, + allowFuture: true, + allowPast: false, + ); + if (picked != null) { + setState(() { + pd['applyTime'] = DateFormat( + 'yyyy-MM-dd HH:mm:ss', + ).format(picked); + }); + } + }, + text: pd['applyTime'] ?? '', + ), + const Divider(), // 作业类型(内部/相关方) if (enableInnerWorkSwitch) ...[ ItemListWidget.selectableLineTitleTextRightButton( @@ -346,7 +367,7 @@ class _DtApplyPageState extends SpecialWorkApplyBaseState { groups[index]['actUserName'] = name; groups[index]['actUserDepartment'] = data['departmentId'] ?? ''; groups[index]['actUserDepartmentName'] = data['departmentName'] ?? ''; - + syncSafeMeasureConfirmersWithGasAnalyzer(data); }); }, ); @@ -417,4 +438,4 @@ class _DtApplyPageState extends SpecialWorkApplyBaseState { } return true; } -} \ No newline at end of file +} diff --git a/lib/pages/home/Tap/special_work/dz_work/dz_apply_page.dart b/lib/pages/home/Tap/special_work/dz_work/dz_apply_page.dart index d843e52..e0eec48 100644 --- a/lib/pages/home/Tap/special_work/dz_work/dz_apply_page.dart +++ b/lib/pages/home/Tap/special_work/dz_work/dz_apply_page.dart @@ -152,6 +152,27 @@ class _DzApplyPageState extends SpecialWorkApplyBaseState { text: pd['applyUser'] ?? '', ), const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '申请时间:', + isEditable: isEditable, + onTap: () async { + final picked = await BottomDateTimePicker.showDate( + mode: BottomPickerMode.dateTimeWithSeconds, + context, + allowFuture: true, + allowPast: false, + ); + if (picked != null) { + setState(() { + pd['applyTime'] = DateFormat( + 'yyyy-MM-dd HH:mm:ss', + ).format(picked); + }); + } + }, + text: pd['applyTime'] ?? '', + ), + const Divider(), // 作业类型(内部/相关方) if (enableInnerWorkSwitch) ...[ ItemListWidget.selectableLineTitleTextRightButton( @@ -357,7 +378,7 @@ class _DzApplyPageState extends SpecialWorkApplyBaseState { groups[index]['actUserName'] = name; groups[index]['actUserDepartment'] = data['departmentId'] ?? ''; groups[index]['actUserDepartmentName'] = data['departmentName'] ?? ''; - + syncSafeMeasureConfirmersWithGasAnalyzer(data); }); }, ); @@ -418,4 +439,4 @@ class _DzApplyPageState extends SpecialWorkApplyBaseState { ), ); } -} \ No newline at end of file +} diff --git a/lib/pages/home/Tap/special_work/dz_work/hoistingDetailFormWidget.dart b/lib/pages/home/Tap/special_work/dz_work/hoistingDetailFormWidget.dart index 41e0701..0885015 100644 --- a/lib/pages/home/Tap/special_work/dz_work/hoistingDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/dz_work/hoistingDetailFormWidget.dart @@ -143,7 +143,13 @@ class _HoistingDetailFormWidgetState extends State { isEditable: false, text: pd['applyUser'] ?? '', ), - + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '申请时间:', + text: pd['applyTime'] ?? '', + isEditable: widget.isEditable, + onTap: () async {}, + ), const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '作业类型:', diff --git a/lib/pages/home/Tap/special_work/gc_work/HeighWorkDetailFormWidget.dart b/lib/pages/home/Tap/special_work/gc_work/HeighWorkDetailFormWidget.dart index d4b8864..fe33d50 100644 --- a/lib/pages/home/Tap/special_work/gc_work/HeighWorkDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/gc_work/HeighWorkDetailFormWidget.dart @@ -140,7 +140,13 @@ class _HeighWorkDetailFormWidgetState extends State { isEditable: false, text: pd['applyUser'] ?? '', ), - + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '申请时间:', + text: pd['applyTime'] ?? '', + isEditable: widget.isEditable, + onTap: () async {}, + ), const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '作业类型:', diff --git a/lib/pages/home/Tap/special_work/gc_work/gc_apply_page.dart b/lib/pages/home/Tap/special_work/gc_work/gc_apply_page.dart index 3712eeb..71aa99c 100644 --- a/lib/pages/home/Tap/special_work/gc_work/gc_apply_page.dart +++ b/lib/pages/home/Tap/special_work/gc_work/gc_apply_page.dart @@ -149,6 +149,27 @@ class _GcApplyPageState extends SpecialWorkApplyBaseState { text: pd['applyUser'] ?? '', ), const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '申请时间:', + isEditable: isEditable, + onTap: () async { + final picked = await BottomDateTimePicker.showDate( + mode: BottomPickerMode.dateTimeWithSeconds, + context, + allowFuture: true, + allowPast: false, + ); + if (picked != null) { + setState(() { + pd['applyTime'] = DateFormat( + 'yyyy-MM-dd HH:mm:ss', + ).format(picked); + }); + } + }, + text: pd['applyTime'] ?? '', + ), + const Divider(), // 作业类型 if (enableInnerWorkSwitch) ...[ ItemListWidget.selectableLineTitleTextRightButton( @@ -330,7 +351,7 @@ class _GcApplyPageState extends SpecialWorkApplyBaseState { groups[index]['actUserName'] = name; groups[index]['actUserDepartment'] = data['departmentId'] ?? ''; groups[index]['actUserDepartmentName'] = data['departmentName'] ?? ''; - + syncSafeMeasureConfirmersWithGasAnalyzer(data); }); }, ); @@ -390,4 +411,4 @@ class _GcApplyPageState extends SpecialWorkApplyBaseState { ), ); } -} \ No newline at end of file +} diff --git a/lib/pages/home/Tap/special_work/lsyd_work/LsydWorkDetailFormWidget.dart b/lib/pages/home/Tap/special_work/lsyd_work/LsydWorkDetailFormWidget.dart index 5841d81..27d5d71 100644 --- a/lib/pages/home/Tap/special_work/lsyd_work/LsydWorkDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/lsyd_work/LsydWorkDetailFormWidget.dart @@ -146,6 +146,13 @@ class _LsydWorkDetailFormWidgetState extends State { text: pd['applyUser'] ?? '', ), const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '申请时间:', + text: pd['applyTime'] ?? '', + isEditable: widget.isEditable, + onTap: () async {}, + ), + const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '作业类型:', isEditable: false, diff --git a/lib/pages/home/Tap/special_work/lsyd_work/lsyd_apply_page.dart b/lib/pages/home/Tap/special_work/lsyd_work/lsyd_apply_page.dart index 95f8b9c..9f21bc6 100644 --- a/lib/pages/home/Tap/special_work/lsyd_work/lsyd_apply_page.dart +++ b/lib/pages/home/Tap/special_work/lsyd_work/lsyd_apply_page.dart @@ -158,6 +158,27 @@ class _LsydApplyPageState extends SpecialWorkApplyBaseState { text: pd['applyUser'] ?? '', ), const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '申请时间:', + isEditable: isEditable, + onTap: () async { + final picked = await BottomDateTimePicker.showDate( + mode: BottomPickerMode.dateTimeWithSeconds, + context, + allowFuture: true, + allowPast: false, + ); + if (picked != null) { + setState(() { + pd['applyTime'] = DateFormat( + 'yyyy-MM-dd HH:mm:ss', + ).format(picked); + }); + } + }, + text: pd['applyTime'] ?? '', + ), + const Divider(), // 作业类型 if (enableInnerWorkSwitch) ...[ ItemListWidget.selectableLineTitleTextRightButton( @@ -382,7 +403,7 @@ class _LsydApplyPageState extends SpecialWorkApplyBaseState { groups[index]['actUserName'] = name; groups[index]['actUserDepartment'] = data['departmentId'] ?? ''; groups[index]['actUserDepartmentName'] = data['departmentName'] ?? ''; - + syncSafeMeasureConfirmersWithGasAnalyzer(data); }); }, ); @@ -435,4 +456,4 @@ class _LsydApplyPageState extends SpecialWorkApplyBaseState { ), ); } -} \ No newline at end of file +} diff --git a/lib/pages/home/Tap/special_work/mbcd_work/mbcdDetailFormWidget.dart b/lib/pages/home/Tap/special_work/mbcd_work/mbcdDetailFormWidget.dart index 6b1cba1..64487d5 100644 --- a/lib/pages/home/Tap/special_work/mbcd_work/mbcdDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/mbcd_work/mbcdDetailFormWidget.dart @@ -194,7 +194,13 @@ class _MbcdDetailFormWidgetState extends State { isEditable: false, text: pd['applyUser'] ?? '', ), - + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '申请时间:', + text: pd['applyTime'] ?? '', + isEditable: widget.isEditable, + onTap: () async {}, + ), const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '作业类型:', diff --git a/lib/pages/home/Tap/special_work/mbcd_work/mbcd_apply_page.dart b/lib/pages/home/Tap/special_work/mbcd_work/mbcd_apply_page.dart index 7140497..3b757ca 100644 --- a/lib/pages/home/Tap/special_work/mbcd_work/mbcd_apply_page.dart +++ b/lib/pages/home/Tap/special_work/mbcd_work/mbcd_apply_page.dart @@ -199,6 +199,27 @@ class _MbcdApplyPageState extends SpecialWorkApplyBaseState { text: pd['applyUser'] ?? '', ), const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '申请时间:', + isEditable: isEditable, + onTap: () async { + final picked = await BottomDateTimePicker.showDate( + mode: BottomPickerMode.dateTimeWithSeconds, + context, + allowFuture: true, + allowPast: false, + ); + if (picked != null) { + setState(() { + pd['applyTime'] = DateFormat('yyyy-MM-dd HH:mm:ss').format( + picked, + ); + }); + } + }, + text: pd['applyTime'] ?? '', + ), + const Divider(), // 作业类型 if (enableInnerWorkSwitch) ...[ ItemListWidget.selectableLineTitleTextRightButton( @@ -584,4 +605,4 @@ class _MbcdApplyPageState extends SpecialWorkApplyBaseState { ), ); } -} \ No newline at end of file +} diff --git a/lib/pages/home/Tap/special_work/sxkj_work/SxkjWorkDetailFormWidget.dart b/lib/pages/home/Tap/special_work/sxkj_work/SxkjWorkDetailFormWidget.dart index 16d463c..b2459a0 100644 --- a/lib/pages/home/Tap/special_work/sxkj_work/SxkjWorkDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/sxkj_work/SxkjWorkDetailFormWidget.dart @@ -143,7 +143,7 @@ class _SxkjWorkDetailFormWidgetState extends State { ), const Divider(), ItemListWidget.selectableLineTitleTextRightButton( - label: '申请日期:', + label: '申请时间:', text: pd['applyTime'] ?? '', isEditable: widget.isEditable, onTap: () async {}, @@ -176,12 +176,12 @@ class _SxkjWorkDetailFormWidgetState extends State { isRequired: true, ), ], - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '管理单位:', - isEditable: widget.isEditable, - text: chooseLimitedSpace['manageDeptName'] ?? '', - ), + // const Divider(), + // ItemListWidget.selectableLineTitleTextRightButton( + // label: '管理单位:', + // isEditable: widget.isEditable, + // text: chooseLimitedSpace['manageDeptName'] ?? '', + // ), const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '有限空间名称及编号:', diff --git a/lib/pages/home/Tap/special_work/sxkj_work/sxkj_apply_page.dart b/lib/pages/home/Tap/special_work/sxkj_work/sxkj_apply_page.dart index 379faaa..b80602f 100644 --- a/lib/pages/home/Tap/special_work/sxkj_work/sxkj_apply_page.dart +++ b/lib/pages/home/Tap/special_work/sxkj_work/sxkj_apply_page.dart @@ -75,39 +75,40 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { @override Future loadExtraData() async { - final data = { "eqWorkType": SpecialWorkTypeEnum.confinedspaceWork.code, "pageSize": 999, "pageIndex": 1, "eqCorpinfoId": pd['projectExecutionLocationCorpId'] ?? '', }; - final limitedSpaceRes = await SpecialWorkApi.specialWorkLimitedSpaceList(data); + final limitedSpaceRes = await SpecialWorkApi.specialWorkLimitedSpaceList( + data, + ); if (limitedSpaceRes['success'] == true) { limitedSpaceList = limitedSpaceRes['data'] ?? []; } // 清空有限空间台账选择的数据 _clearRelatedParties(); } + Future _clearRelatedParties() async { setState(() { pd['limitedSpaceNameAndCode'] = ''; pd['chooseLimitedSpace'] = {}; }); - } @override Future afterInitDataLoaded() async { // 初始化允许选择的人员列表(作业负责人和监护人) allowChoosePerson = { - '1' : { + '1': { "actUser": pd['workGuardianUser'] ?? pd['workGuardianUserId'] ?? '', "actUserDepartment": pd['workGuardianUserDepartment'] ?? '', "actUserDepartmentName": pd['workGuardianUserDepartmentName'] ?? '', "actUserName": pd['workGuardianUserName'] ?? '', }, - '2' : { + '2': { "actUserDepartment": pd['workChargeUserDepartment'] ?? '', "actUserDepartmentName": pd['workChargeUserDepartmentName'] ?? '', "actUser": pd['workChargeUser'] ?? pd['workChargeUserId'] ?? '', @@ -145,9 +146,10 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { Future> buildExtraPayload() async { final preparers = safeController.buildPreparers(); return { - 'others': {'measures': preparers} + 'others': {'measures': preparers}, }; } + @override Widget buildFormContent() { final chooseLimitedSpace = (pd['chooseLimitedSpace'] as Map?) ?? {}; @@ -204,9 +206,9 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { text: pd['applyUser'] ?? '', ), const Divider(), - // 申请日期 + // 申请时间 ItemListWidget.selectableLineTitleTextRightButton( - label: '申请日期:', + label: '申请时间:', isEditable: isEditable, onTap: () async { final picked = await BottomDateTimePicker.showDate( @@ -217,7 +219,9 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { ); if (picked != null) { setState(() { - pd['applyTime'] = DateFormat('yyyy-MM-dd HH:mm:ss').format(picked); + pd['applyTime'] = DateFormat( + 'yyyy-MM-dd HH:mm:ss', + ).format(picked); }); } }, @@ -244,7 +248,6 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { groupValue: pd['internalOperationFlag'] == 1, onChanged: (value) { setState(() { - isInnerWork = value; pd['internalOperationFlag'] = value ? 1 : 2; }); }, @@ -266,15 +269,15 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { onTap: _chooseFromLedger, text: pd['limitedSpaceNameAndCode'] ?? '', ), - const Divider(), - // 管理单位(只读,来自台账) - ItemListWidget.singleLineTitleText( - label: '管理单位:', - isEditable: false, - isTextFont: false, - strongRequired: true, - text: chooseLimitedSpace['manageDeptName'] ?? '', - ), + // const Divider(), + // // 管理单位(只读,来自台账) + // ItemListWidget.singleLineTitleText( + // label: '管理单位:', + // isEditable: false, + // isTextFont: false, + // strongRequired: true, + // text: chooseLimitedSpace['manageDeptName'] ?? '', + // ), const Divider(), // 主要介质(只读) ItemListWidget.singleLineTitleText( @@ -333,7 +336,8 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { isTextFont: false, isRequired: isEditable, text: pd['emergencyEquipment'] ?? '', - onChanged: (value) => setState(() => pd['emergencyEquipment'] = value), + onChanged: + (value) => setState(() => pd['emergencyEquipment'] = value), ), // 重新编辑时展示详情组件 if (widget.isReEdit && FormUtils.hasValue(form, 'id')) ...[ @@ -372,7 +376,8 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { label: '作业监护人', isEditable: isEditable, text: pd['workGuardianUserName'] ?? '请选择', - onTap: () => _chooseAlonePersonHandle(SelectPersonType.workGuardian), + onTap: + () => _chooseAlonePersonHandle(SelectPersonType.workGuardian), ), const Divider(), // 签字流程组(基类提供,但 stepId=3 会被隐藏,因为 shouldHideGroup 已重写) @@ -405,22 +410,24 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { // 区分出两个数组、企业和相关方 if (item['userType'] == 2) { firmList.add(item); - }else{ + } else { xgfList.add(item); } } + //0610修改,作业负责人和作业监护人需与选择的作业单位关联;作业单位肯定是相关方端,所以不考虑企业端 DepartmentAllPersonPicker.show( context, - allowXgfFlag: xgfList.isNotEmpty, - personsData: firmList, - serverData: xgfList, + allowXgfFlag: false, + personsData: [...firmList,...xgfList], + serverData: [], onSelectedWithData: (userId, name, data) { setState(() { groups[index]['actUser'] = userId; groups[index]['actUserName'] = name; groups[index]['actUserDepartment'] = data['departmentId'] ?? ''; - groups[index]['actUserDepartmentName'] = data['departmentName'] ?? ''; - + groups[index]['actUserDepartmentName'] = + data['departmentName'] ?? ''; + syncSafeMeasureConfirmersWithGasAnalyzer(data); }); }, ); @@ -441,13 +448,17 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { style: BottomPickerStyle.list, title: '有限空间名称及编号', height: MediaQuery.of(context).size.height - 120, - items: limitedSpaceList.map((item) => '${item['name']}(${item['code']})').toList(), - itemBuilder: (item) => Text( - item, - softWrap: true, - maxLines: 10, - overflow: TextOverflow.visible, - ), + items: + limitedSpaceList + .map((item) => '${item['name']}(${item['code']})') + .toList(), + itemBuilder: + (item) => Text( + item, + softWrap: true, + maxLines: 10, + overflow: TextOverflow.visible, + ), initialIndex: 0, withIndex: true, ); @@ -469,32 +480,40 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { isScrollControlled: true, barrierColor: Colors.black54, backgroundColor: Colors.transparent, - builder: (_) => DepartmentPicker( - onSelected: (id, name, data) async { - setState(() { - pd['workDepartment'] = id; - pd['workDepartmentName'] = name; - // 清空作业人(如果有联动需要) - }); - await _getPersonListForUnitId(id); - }, - data: {'corpinfoId': pd['projectExecutionLocationCorpId'] ?? ''}, - ), + builder: + (_) => DepartmentPicker( + onSelected: (id, name, data) async { + setState(() { + pd['workDepartment'] = id; + pd['workDepartmentName'] = name; + // 清空作业人(如果有联动需要) + }); + await _getPersonListForUnitId(id); + }, + data: {'eqCorpinfoId': pd['xgfId'] ?? ''}, + ), ); } /// 单独选择作业负责人或监护人 void _chooseAlonePersonHandle(SelectPersonType type) { - List personList = allPersonList; - List xgfList = relatedPartiesPersonList; - // if (pd['xgfFlag'] == 1 && relatedPartiesPersonList.isNotEmpty) { - // personList = [...personList, ...relatedPartiesPersonList]; - // } + List personList = []; + // List xgfList = relatedPartiesPersonList; + final String workDepartmentId = (pd['workDepartment'] ?? '').toString(); + List xgfList = + relatedPartiesPersonList.where((item) { + if (item is! Map) return false; + return (item['departmentId'] ?? '').toString() == workDepartmentId; + }).toList(); + if (!FormUtils.hasValue(pd, 'workDepartment')) { + personList = allPersonList; + } + DepartmentAllPersonPicker.show( context, - allowXgfFlag: pd['xgfFlag'] == 1, - personsData: personList, - serverData: xgfList, + allowXgfFlag: false, + personsData: xgfList, + serverData: [], onSelectedWithData: (userId, name, data) { setState(() { if (type == SelectPersonType.workCharge) { @@ -503,7 +522,6 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { pd['workChargeUserDepartment'] = data['departmentId']; pd['workChargeUserDepartmentName'] = data['departmentName']; allowChoosePerson['1'] = data; - } else { pd['workGuardianUserId'] = userId; pd['workGuardianUserName'] = name; @@ -546,4 +564,4 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState { return {}; }).toList(); } -} \ No newline at end of file +} diff --git a/lib/pages/home/Tap/special_work/sxkj_work/sxkj_record_add_page.dart b/lib/pages/home/Tap/special_work/sxkj_work/sxkj_record_add_page.dart new file mode 100644 index 0000000..c55511f --- /dev/null +++ b/lib/pages/home/Tap/special_work/sxkj_work/sxkj_record_add_page.dart @@ -0,0 +1,277 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:qhd_prevention/constants/app_enums.dart'; +import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart'; +import 'package:qhd_prevention/customWidget/custom_button.dart'; +import 'package:qhd_prevention/customWidget/photo_picker_row.dart'; +import 'package:qhd_prevention/customWidget/single_image_viewer.dart'; +import 'package:qhd_prevention/customWidget/toast_util.dart'; +import 'package:qhd_prevention/http/modules/file_api.dart'; +import 'package:qhd_prevention/http/modules/special_work_api.dart'; +import 'package:qhd_prevention/pages/mine/mine_sign_page.dart'; +import 'package:qhd_prevention/pages/my_appbar.dart'; +import 'package:qhd_prevention/tools/tools.dart'; + +class SxkjRecordAddPage extends StatefulWidget { + const SxkjRecordAddPage({super.key, required this.data}); + + final Map data; + + @override + State createState() => _SxkjRecordAddPageState(); +} + +class _SxkjRecordAddPageState extends State { + final List _images = []; + Map pd = {}; + + List signImages = []; + List signTimes = []; + bool _isSubmitting = false; + + @override + void initState() { + super.initState(); + pd = Map.from(widget.data); + } + + Future _sign() async { + await NativeOrientation.setLandscape(); + final path = await Navigator.push( + context, + MaterialPageRoute(builder: (context) => MineSignPage()), + ); + await NativeOrientation.setPortrait(); + + if (path != null) { + final now = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()); + setState(() { + signImages = [path]; + signTimes = [now]; + }); + } + } + + String _extractUploadedPath(dynamic data) { + if (data is Map) { + final filePath = (data['filePath'] ?? '').toString(); + if (filePath.isNotEmpty) return filePath; + + final fileList = data['fileList']; + if (fileList is List && fileList.isNotEmpty) { + return fileList + .map( + (item) => item is Map ? (item['filePath'] ?? '').toString() : '', + ) + .where((path) => path.isNotEmpty) + .join(','); + } + + final foreignKey = (data['foreignKey'] ?? '').toString(); + if (foreignKey.isNotEmpty) return foreignKey; + } + + if (data is List && data.isNotEmpty) { + return data + .map((item) => item is Map ? (item['filePath'] ?? '').toString() : '') + .where((path) => path.isNotEmpty) + .join(','); + } + + return ''; + } + + Future _uploadRecordImages() async { + final result = await FileApi.uploadFiles( + _images, + UploadFileType.specialOperationInAndOutRecord, + '', + ); + if (result['success'] == true) { + final filePath = _extractUploadedPath(result['data']); + if (filePath.isNotEmpty) return filePath; + } + + throw Exception(result['errMessage'] ?? '记录图片上传失败'); + } + + Future _uploadSignImages() async { + final paths = []; + for (final signImage in signImages) { + final result = await FileApi.uploadFile( + signImage, + UploadFileType.specialOperationProcessSignaturePhoto, + '', + ); + if (result['success'] == true) { + final filePath = _extractUploadedPath(result['data']); + if (filePath.isNotEmpty) { + paths.add(filePath); + continue; + } + } + + throw Exception(result['errMessage'] ?? '签字上传失败'); + } + + return paths.join(','); + } + + Future _submit() async { + if (_isSubmitting) return; + if (_images.isEmpty) { + ToastUtil.showNormal(context, '请上传记录图片'); + return; + } + if (signImages.isEmpty) { + ToastUtil.showNormal(context, '请签字'); + return; + } + + setState(() { + _isSubmitting = true; + }); + LoadingDialogHelper.show(); + try { + final recordFilePath = await _uploadRecordImages(); + final signPath = await _uploadSignImages(); + final other = {'spaceRecordFile': recordFilePath}; + + final params = { + 'id': pd['id'], + 'workId': pd['workId'], + 'stepId': pd['stepId'], + 'status': 1, + 'specialStepCode': pd['specialStepCode'], + 'signPath': signPath, + 'signTime': + signTimes.isNotEmpty + ? signTimes.first + : DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()), + 'others': {'otherParams': jsonEncode(other)}, + }; + final res = await SpecialWorkApi.specialWorkNextStep(params); + if (res['success'] == true) { + ToastUtil.showNormal(context, '提交成功'); + if (mounted) Navigator.pop(context, true); + } else { + ToastUtil.showNormal(context, res['errMessage'] ?? '作业提交失败'); + } + } catch (e) { + ToastUtil.showNormal( + context, + e.toString().replaceFirst('Exception: ', ''), + ); + } finally { + LoadingDialogHelper.hide(); + if (mounted) { + setState(() { + _isSubmitting = false; + }); + } + } + } + + Widget _signListWidget() { + return Column( + children: + signImages.map((path) { + return Column( + children: [ + const SizedBox(height: 15), + const Divider(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + GestureDetector( + onTap: () { + presentOpaque( + SingleImageViewer(imageUrl: path), + context, + ); + }, + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 200, + maxHeight: 150, + ), + child: Image.file(File(path), fit: BoxFit.contain), + ), + ), + CustomButton( + text: 'X', + height: 30, + padding: const EdgeInsets.symmetric(horizontal: 10), + backgroundColor: Colors.red, + onPressed: () { + setState(() { + signImages.remove(path); + }); + }, + ), + ], + ), + ], + ); + }).toList(), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: MyAppbar(title: '记录上传'), + backgroundColor: Colors.white, + body: SafeArea( + child: SingleChildScrollView( + padding: const EdgeInsets.all(12), + child: Column( + children: [ + RepairedPhotoSection( + isRequired: true, + title: '进出有限空间记录', + maxCount: 4, + horizontalPadding: 0, + mediaType: MediaType.image, + isShowAI: false, + onChanged: (List files) { + _images.clear(); + for (final file in files) { + _images.add(file.path); + } + }, + onAiIdentify: () {}, + ), + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ListItemFactory.headerTitle( + '${pd['actorField'] ?? ''}签字', + isRequired: true, + ), + CustomButton( + text: signImages.isNotEmpty ? '重签' : '签字', + height: 36, + padding: const EdgeInsets.symmetric(horizontal: 25), + backgroundColor: Colors.blue, + onPressed: _sign, + ), + ], + ), + if (signImages.isNotEmpty) _signListWidget(), + const SizedBox(height: 30), + CustomButton( + text: _isSubmitting ? '提交中...' : '提交', + onPressed: _submit, + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/pages/home/Tap/special_work/sxkj_work/sxkj_wait_page.dart b/lib/pages/home/Tap/special_work/sxkj_work/sxkj_wait_page.dart index 604aa6b..cf7a3b1 100644 --- a/lib/pages/home/Tap/special_work/sxkj_work/sxkj_wait_page.dart +++ b/lib/pages/home/Tap/special_work/sxkj_work/sxkj_wait_page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:qhd_prevention/http/modules/special_work_api.dart'; import 'package:qhd_prevention/pages/home/Tap/special_header.dart'; +import 'package:qhd_prevention/pages/home/Tap/special_work/sxkj_work/sxkj_record_add_page.dart'; import 'package:qhd_prevention/pages/home/Tap/special_work_wait_scaffold.dart'; import 'package:qhd_prevention/pages/home/Tap/special_work/sxkj_work/special_work_gas_list.dart'; import 'package:qhd_prevention/pages/home/Tap/special_work/sxkj_work/sxkj_apply_page.dart'; @@ -39,22 +40,24 @@ class SxkjWaitPage extends SpecialWorkWaitPageBase { @override Future onOpenDetail( - BuildContext context, - Map item, - bool isEdit, - ) async { + BuildContext context, + Map item, + bool isEdit, + ) async { final hotworkId = item['id'] ?? ''; final hotworkCodeId = item['workId'] ?? ''; - final hotworkInfo = listType == SpecialListType.task ? item['workInfo'] ?? {} : item; + final hotworkInfo = + listType == SpecialListType.task ? item['workInfo'] ?? {} : item; final stepId = '${item['stepId'] ?? ''}'; final status = '${hotworkInfo['status'] ?? ''}'; - final String statusName = isEdit - ? (listType == SpecialListType.task - ? '${item['stepName'] ?? ''}' - : '${hotworkInfo['currentStep'] ?? ''}') - : '查看'; + final String statusName = + isEdit + ? (listType == SpecialListType.task + ? '${item['stepName'] ?? ''}' + : '${hotworkInfo['currentStep'] ?? ''}') + : '查看'; Future openTaskPage({required bool editable}) async { await pushPage( @@ -70,6 +73,10 @@ class SxkjWaitPage extends SpecialWorkWaitPageBase { } if (listType == SpecialListType.task) { + if (stepId == '30') { + await pushPage(SxkjRecordAddPage(data: item), context); + return; + } if (stepId == '2') { if (isEdit) { await pushPage( @@ -85,11 +92,7 @@ class SxkjWaitPage extends SpecialWorkWaitPageBase { if (status == '0' || status == '2') { if (isEdit) { await pushPage( - SxkjApplyPage( - isReEdit: true, - workId: hotworkId, - status: status, - ), + SxkjApplyPage(isReEdit: true, workId: hotworkId, status: status), context, ); } else { @@ -107,13 +110,12 @@ class SxkjWaitPage extends SpecialWorkWaitPageBase { @override Widget buildCardBody( - BuildContext context, - Map item, - Map workInfo, - Map info, - String statusName, - ) { - + BuildContext context, + Map item, + Map workInfo, + Map info, + String statusName, + ) { final chooseLimitedSpace = Map.from( info['chooseLimitedSpace'] ?? {}, ); @@ -161,10 +163,10 @@ class SxkjWaitPage extends SpecialWorkWaitPageBase { ), ], ), - buildWrapPairRow( - '管理单位: ${chooseLimitedSpace['manageDeptName'] ?? ''}', - '作业单位: ${info['workDepartmentName'] ?? ''}', - ), + // buildWrapPairRow( + // '管理单位: ${chooseLimitedSpace['manageDeptName'] ?? ''}', + // '作业单位: ${info['workDepartmentName'] ?? ''}', + // ), Text( '有限空间名称及编号: ${info['limitedSpaceNameAndCode'] ?? ''}', softWrap: true, diff --git a/lib/pages/home/Tap/special_work/sxkj_work/tz/sxkj_tz_apply_page.dart b/lib/pages/home/Tap/special_work/sxkj_work/tz/sxkj_tz_apply_page.dart deleted file mode 100644 index 3db3c43..0000000 --- a/lib/pages/home/Tap/special_work/sxkj_work/tz/sxkj_tz_apply_page.dart +++ /dev/null @@ -1,448 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:qhd_prevention/constants/app_enums.dart'; -import 'package:qhd_prevention/customWidget/BaiDuMap/Map_page.dart'; -import 'package:qhd_prevention/customWidget/DocumentPicker.dart'; -import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart'; -import 'package:qhd_prevention/customWidget/MultiDictValuesPicker.dart'; -import 'package:qhd_prevention/customWidget/center_multi_picker.dart'; -import 'package:qhd_prevention/customWidget/custom_button.dart'; -import 'package:qhd_prevention/customWidget/department_all_person_picker.dart'; -import 'package:qhd_prevention/customWidget/department_person_picker.dart'; -import 'package:qhd_prevention/customWidget/department_picker.dart'; -import 'package:qhd_prevention/customWidget/department_picker_three.dart'; -import 'package:qhd_prevention/customWidget/item_list_widget.dart'; -import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.dart'; -import 'package:qhd_prevention/customWidget/read_file_page.dart'; -import 'package:qhd_prevention/customWidget/related_parties_picker.dart'; -import 'package:qhd_prevention/customWidget/toast_util.dart'; -import 'package:qhd_prevention/tools/h_colors.dart'; -import 'package:qhd_prevention/tools/tools.dart'; -import 'package:qhd_prevention/http/ApiService.dart'; -import 'package:qhd_prevention/pages/my_appbar.dart'; -import 'package:qhd_prevention/customWidget/bottom_picker.dart'; - -class SxkjTzApplyPage extends StatefulWidget { - const SxkjTzApplyPage({ - super.key, - required this.isEdit, - required this.work_id, - required this.info, - }); - - /// 是否是重新编辑 - final bool isEdit; - final String work_id; - final Map info; - - @override - State createState() => _SxkjTzApplyPageState(); -} - -class _SxkjTzApplyPageState extends State { - bool _isEditable = true; - - // pd中各个节点规则填写提示 - List> rules = [ - {'name': 'manageDeptName', 'message': '请选择管理单位'}, - {'name': 'name', 'message': '请填写有限空间名称'}, - {'name': 'code', 'message': '请填写有限空间编号'}, - {'name': 'type', 'message': '请选择有限空间类型'}, - {'name': 'positionAndRange', 'message': '请填写位置及范围'}, - {'name': 'mediumInfo', 'message': '请填写主要介质'}, - {'name': 'hazards', 'message': '请填写主要危险及有害因素'}, - {'name': 'riskLevel', 'message': '请选择风险等级'}, - {'name': 'protectionRequirements', 'message': '请填写防护要求'}, - {'name': 'separateSafetyMeasures', 'message': '请填写隔绝安全措施'}, - {'name': 'maximumNumber', 'message': '请填写最大作业人数'}, - ]; - - /// 详情 - Map pd = {'isEmergencyBook': 2}; - - // 类型 - List typeList = []; - - @override - void initState() { - super.initState(); - _isEditable = widget.isEdit; - if (!widget.isEdit) { - pd = widget.info; - } - } - - // 上传附件 - Future uploadFileHandle() async { - final List picked = await DocumentPicker.showPickerModal( - context, - maxAssets: 1, - maxSizeInBytes: 20 * 1024 * 1024, - allowedExtensions: ['pdf', 'doc', 'docx'], - allowMultipleFiles: false, - showPhotoSelect: false, - ); - - if (picked.isNotEmpty && picked.first.path != null) { - LoadingDialogHelper.show(); - final raw = await FileApi.uploadFile( - picked.first.path!, - UploadFileType.specialOperationRestrictedSpaceLedgerAttachment, - '', - ); - if (raw['success']) { - LoadingDialogHelper.hide(); - setState(() { - pd['emergencyBookFile'] = raw['data']['filePath']; - ToastUtil.showNormal(context, "附件上传成功"); - }); - } else { - ToastUtil.showNormal(context, "附件上传失败"); - LoadingDialogHelper.hide(); - } - } - } - - // 选择管理单位 - Future chooseUnitHandle() async { - showModalBottomSheet( - context: context, - isScrollControlled: true, - barrierColor: Colors.black54, - backgroundColor: Colors.transparent, - builder: - (_) => DepartmentPicker( - onSelected: (id, name, data) async { - setState(() { - pd['manageDeptName'] = name; - pd['manageDeptId'] = id; - }); - }, - ), - ).then((_) { - // 可选:FocusHelper.clearFocus(context); - }); - } - - /// 选择有限空间类型 - Future chooseLevelHandle() async { - showModalBottomSheet( - context: context, - isScrollControlled: true, - barrierColor: Colors.black54, - backgroundColor: Colors.transparent, - builder: - (_) => MultiDictValuesPicker( - title: '有限空间类型', - dictType: 'finiteSpaceType', - onSelected: (id, name, extraData) { - setState(() { - pd['typeName'] = name; - pd['type'] = extraData?['dictValue'] ?? ''; - }); - }, - ), - ).then((_) {}); - } - - // 选择风险等级 - Future chooseRiskLevelHandle() async { - showModalBottomSheet( - context: context, - isScrollControlled: true, - barrierColor: Colors.black54, - backgroundColor: Colors.transparent, - builder: - (_) => MultiDictValuesPicker( - title: '风险等级', - dictType: 'riskGrade', - onSelected: (id, name, extraData) { - setState(() { - pd['riskLevelName'] = name; - pd['riskLevel'] = extraData?['dictValue'] ?? ''; - }); - }, - ), - ); - } - - // 提交 - Future _submit() async { - if (_isEditable) { - // 根据rules规则判断 - for (var item in rules) { - if (pd[item['name']] == null || pd[item['name']] == '') { - ToastUtil.showNormal(context, item['message'] ?? "请填写必填项"); - return; - } - } - // 是否有应急指导书 - if (pd['isEmergencyBook'] == 1) { - if (pd['emergencyBookFile'] == null || pd['emergencyBookFile'] == '') { - ToastUtil.showNormal(context, '请上传应急指导书'); - return; - } - } - LoadingDialogHelper.show(); - final res = await SpecialWorkApi.specialWorkLimitedSpaceSave(pd); - if (res['success'] == true) { - LoadingDialogHelper.hide(); - ToastUtil.showNormal(context, "提交成功"); - Navigator.of(context).pop(); - } else { - LoadingDialogHelper.hide(); - ToastUtil.showNormal(context, res['errMessage'] ?? "作业提交失败"); - } - } - } - - Widget _buildDetail() { - return Container( - padding: const EdgeInsets.all(8), - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(5)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - ItemListWidget.selectableLineTitleTextRightButton( - label: '管理单位:', - isEditable: _isEditable, - onTap: chooseUnitHandle, - text: pd['manageDeptName'] ?? '', - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '有限空间名称:', - isEditable: _isEditable, - hintText: '请输入', - isTextFont: false, - text: pd['name'] ?? '', - onChanged: (value) { - setState(() { - pd['name'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '有限空间编号:', - isEditable: _isEditable, - hintText: '请输入', - isTextFont: false, - text: pd['code'] ?? '', - onChanged: (value) { - setState(() { - pd['code'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '有限空间类型:', - isEditable: _isEditable, - onTap: chooseLevelHandle, - text: pd['typeName'] ?? '', - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '位置及范围:', - isEditable: _isEditable, - hintText: '请输入', - isTextFont: false, - text: pd['positionAndRange'] ?? '', - onChanged: (value) { - setState(() { - pd['positionAndRange'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '主要介质:', - isEditable: _isEditable, - hintText: '请输入', - isTextFont: false, - text: pd['mediumInfo'] ?? '', - onChanged: (value) { - setState(() { - pd['mediumInfo'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '主要危险及有害因素:', - isEditable: _isEditable, - hintText: '请输入', - isTextFont: false, - text: pd['hazards'] ?? '', - onChanged: (value) { - setState(() { - pd['hazards'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '风险等级:', - isEditable: _isEditable, - onTap: chooseRiskLevelHandle, - text: pd['riskLevelName'] ?? '', - ), - - const Divider(), - - ItemListWidget.singleLineTitleText( - label: '防护要求:', - isEditable: _isEditable, - hintText: '请输入', - isTextFont: false, - text: pd['protectionRequirements'] ?? '', - onChanged: (value) { - setState(() { - pd['protectionRequirements'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '隔绝安全措施:', - isEditable: _isEditable, - hintText: '请输入', - isTextFont: false, - text: pd['separateSafetyMeasures'] ?? '', - onChanged: (value) { - setState(() { - pd['separateSafetyMeasures'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '最大作业人数:', - isEditable: _isEditable, - hintText: '请输入', - isTextFont: false, - isNumericInput: true, - text: '${pd['maximumNumber'] ?? ''}', - onChanged: (value) { - setState(() { - pd['maximumNumber'] = value; - }); - }, - ), - const Divider(), - ListItemFactory.createYesNoSection( - horizontalPadding: 2, - verticalPadding: 5, - isEdit: _isEditable, - title: '是否有应急指导书', - isRequired: true, - text: pd['isEmergencyBook'] == 1 ? '是' : '否', - groupValue: pd['isEmergencyBook'] == 1, - onChanged: (value) { - setState(() { - pd['isEmergencyBook'] = value ? 1 : 2; - }); - }, - ), - const Divider(), - if (pd['isEmergencyBook'] == 1) - ItemListWidget.OneRowButtonTitleTextFile( - horizontalnum: 10, - label: '应急指导书', - buttonText: _isEditable ? '上传文件' : '查看文件', - isRequired: _isEditable, - fileUrl: pd['emergencyBookFile'] ?? '', - text: '', - onTap: () async { - if (_isEditable) { - uploadFileHandle(); - } else { - pushPage( - ReadFilePage( - fileUrl: - ApiService.baseImgPath + pd['emergencyBookFile'] ?? - '', - ), - context, - ); - } - }, - onTapFile: () async { - pushPage( - ReadFilePage( - fileUrl: - ApiService.baseImgPath + pd['emergencyBookFile'] ?? - '', - ), - context, - ); - }, - ), - ], - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: h_backGroundColor(), - appBar: MyAppbar(title: _isEditable ? '新增' : '查看'), - body: SafeArea( - child: SingleChildScrollView( - child: Column( - children: [ - _buildDetail(), - const SizedBox(height: 20), - _isEditable - ? Row( - children: [ - SizedBox(width: 50), - Expanded( - child: CustomButton( - height: 45, - textStyle: TextStyle( - fontSize: 16, - color: Colors.white, - ), - text: '提交', - backgroundColor: Colors.green, - onPressed: _submit, - ), - ), - SizedBox(width: 50), - ], - ) - : Row( - children: [ - SizedBox(width: 50), - Expanded( - child: CustomButton( - height: 45, - textStyle: TextStyle( - fontSize: 16, - color: Colors.white, - ), - text: '返回', - onPressed: () { - Navigator.pop(context); - }, - ), - ), - SizedBox(width: 50), - ], - ), - ], - ), - ), - ), - ); - } -} diff --git a/lib/pages/home/Tap/special_work/sxkj_work/tz/sxkj_tz_list_page.dart b/lib/pages/home/Tap/special_work/sxkj_work/tz/sxkj_tz_list_page.dart deleted file mode 100644 index 4f30d95..0000000 --- a/lib/pages/home/Tap/special_work/sxkj_work/tz/sxkj_tz_list_page.dart +++ /dev/null @@ -1,323 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; -import 'package:qhd_prevention/common/route_service.dart'; -import 'package:qhd_prevention/customWidget/item_list_widget.dart'; -import 'package:qhd_prevention/pages/home/Tap/special_header.dart'; - -import 'package:qhd_prevention/pages/home/Tap/special_work/sxkj_work/tz/sxkj_tz_apply_page.dart'; -import 'package:qhd_prevention/pages/my_appbar.dart'; -import 'package:qhd_prevention/services/location_service.dart'; -import 'package:qhd_prevention/tools/tools.dart'; -import 'package:qhd_prevention/customWidget/bottom_picker.dart'; -import 'package:qhd_prevention/customWidget/custom_button.dart'; -import 'package:qhd_prevention/customWidget/search_bar_widget.dart'; -import 'package:qhd_prevention/http/ApiService.dart'; -import 'package:qhd_prevention/pages/home/Tap/special_work/dh_work/hot_task_page.dart'; - -class SxkjTzListPage extends StatefulWidget { - const SxkjTzListPage({Key? key}) : super(key: key); - - @override - _SxkjTzListPageState createState() => _SxkjTzListPageState(); -} - -class _SxkjTzListPageState extends State { - // Data and state variables - List list = []; - int currentPage = 1; - int rows = 10; - int totalPage = 1; - bool isLoading = false; - final TextEditingController _searchController = TextEditingController(); - - List> stepList = []; - int sindex = 0; - String searchKeywords = ''; - - List> flowList = []; - final GlobalKey _scaffoldKey = GlobalKey(); - - final ScrollController _scrollController = ScrollController(); - Map searchData = {}; - - @override - void initState() { - super.initState(); - _fetchData(); - _scrollController.addListener(_onScroll); - } - - @override - void dispose() { - _scrollController.dispose(); - super.dispose(); - } - - void _onScroll() { - if (_scrollController.position.pixels >= - _scrollController.position.maxScrollExtent && - !isLoading) { - if (currentPage < totalPage) { - currentPage++; - _fetchData(); - } - } - } - - Future _fetchSteps() async { - try {} catch (e) { - print('Error fetching steps: $e'); - } - } - - Future _fetchData() async { - if (isLoading) return; - setState(() => isLoading = true); - - try { - var response = {}; - final parentPerm = - 'dashboard:hazardous:work:confined-space-operations:Confined-Space-Work-Ledger'; - final targetPerm = ''; - final menuPath = await RouteService.getMenuPath(parentPerm, targetPerm); - final data = { - "eqWorkType": SpecialWorkTypeEnum.confinedspaceWork.code, - "pageSize": rows, - "pageIndex": currentPage, - "menuPath": menuPath, - ...searchData, - }; - response = await SpecialWorkApi.specialWorkLimitedSpaceList(data); - setState(() { - if (currentPage == 1) { - list = response['data']; - } else { - list.addAll(response['data']); - } - totalPage = response['totalCount'] ?? 1; - isLoading = false; - }); - } catch (e) { - print('Error fetching data: $e'); - setState(() => isLoading = false); - } - } - - void _search() { - searchKeywords = _searchController.text.trim(); - currentPage = 1; - list.clear(); - _fetchData(); - } - - /// 申请 - void _handleApply() async { - await pushPage( - SxkjTzApplyPage(isEdit: true, work_id: '', info: {}), - context, - ); - _fetchData(); - } - - void _goToDetail(Map item, bool isEdit) async { - pushPage( - SxkjTzApplyPage(isEdit: false, work_id: item['id'] ?? '', info: item), - context, - ); - _fetchData(); - } - - Widget _buildListItem(Map item) { - // actUserName - return Card( - color: Colors.white, - margin: const EdgeInsets.all(8.0), - child: InkWell( - onTap: () => _goToDetail(item, false), - child: Padding( - padding: const EdgeInsets.all(12.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - spacing: 8, - children: [ - Row( - children: [ - Expanded( - child: Text( - "有限空间名称: ${item['name'] ?? ''}", - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - ), - softWrap: true, - maxLines: null, - overflow: TextOverflow.visible, - ), - ), - ], - ), - Row( - children: [ - Expanded( - child: Text( - "编号: ${item['code'] ?? ''}", - softWrap: true, - maxLines: null, - overflow: TextOverflow.visible, - ), - ), - ], - ), - - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - "有限空间类型: ${item['typeName'] ?? ''}", - softWrap: true, - maxLines: null, - textAlign: TextAlign.right, - - overflow: TextOverflow.visible, - ), - Text( - "风险等级: ${item['riskLevelName'] ?? ''}", - softWrap: true, - maxLines: null, - overflow: TextOverflow.visible, - ), - ], - ), - Text( - "位置及范围: ${item['positionAndRange'] ?? ''}", - softWrap: true, - maxLines: 30, - overflow: TextOverflow.visible, - ), - Text( - "主要介质: ${item['mediumInfo'] ?? ''}", - softWrap: true, - maxLines: 30, - overflow: TextOverflow.visible, - ), - - _statusButtons(item), - ], - ), - ), - ), - ); - } - - Widget _statusButtons(Map item) { - final List buttons = []; - final List buttonRowChildren = []; - - buttons.add( - CustomButton( - text: '查看', - buttonStyle: ButtonStyleType.primary, - backgroundColor: Colors.blue, - onPressed: () { - _goToDetail(item, false); - }, - ), - ); - - for (int i = 0; i < buttons.length; i++) { - buttonRowChildren.add( - Expanded(child: SizedBox(height: 40, child: buttons[i])), - ); - if (i != buttons.length - 1) { - buttonRowChildren.add(const SizedBox(width: 10)); - } - } - return Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: buttonRowChildren, - ); - } - - Widget _buildListContent() { - if (isLoading && list.isEmpty) { - // 初始加载时显示居中的加载指示器 - return Center(child: CircularProgressIndicator()); - } else if (list.isEmpty) { - // 没有数据 - return NoDataWidget.show(); - } else { - // 有数据或加载更多 - return ListView.builder( - padding: EdgeInsets.zero, - - controller: _scrollController, - itemCount: list.length + (isLoading ? 1 : 0), - itemBuilder: (context, index) { - if (index >= list.length) { - // 加载更多时在列表底部显示加载指示器 - return Padding( - padding: const EdgeInsets.symmetric(vertical: 16.0), - child: Center(child: CircularProgressIndicator()), - ); - } - return _buildListItem(list[index]); - }, - ); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - key: _scaffoldKey, - appBar: MyAppbar( - title: '有限空间管理台账', - actions: [ - IconButton( - onPressed: _handleApply, - icon: const Icon(Icons.add, color: Colors.white, size: 30), - ), - ], - ), - endDrawer: Drawer( - child: SafeArea( - child: - flowList.isEmpty - ? Center(child: Text('暂无流程图数据')) - : ItemListWidget.specialBuildFlowStepItem(flowList: flowList), - ), - ), - - body: SafeArea( - child: Column( - children: [ - Container( - color: Colors.white, - padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 8), - child: SearchBarWidget( - hintText: '请输入有限空间名称', - showResetButton: true, - onSearch: (val) { - searchData = {'likeName' : _searchController.text}; - _fetchData(); - - }, - onReset: () { - _searchController.text = ''; - searchData = {}; - - _fetchData(); - }, - controller: _searchController, - ), - ), - - const Divider(height: 1), - // List - Expanded(child: _buildListContent()), - ], - ), - ), - ); - } -} diff --git a/lib/pages/home/Tap/special_work/sxkj_work/work_tab_space_list.dart b/lib/pages/home/Tap/special_work/sxkj_work/work_tab_space_list.dart index fec3761..433753b 100644 --- a/lib/pages/home/Tap/special_work/sxkj_work/work_tab_space_list.dart +++ b/lib/pages/home/Tap/special_work/sxkj_work/work_tab_space_list.dart @@ -5,10 +5,7 @@ import 'package:qhd_prevention/customWidget/toast_util.dart'; import 'package:qhd_prevention/customWidget/work_tab_icon_grid.dart'; import 'package:qhd_prevention/http/modules/special_work_api.dart'; import 'package:qhd_prevention/pages/home/Tap/special_header.dart'; -import 'package:qhd_prevention/pages/home/Tap/special_work/dh_work/dh_wait_page.dart' hide SpecialListType; -import 'package:qhd_prevention/pages/home/Tap/special_work/sxkj_work/tz/sxkj_tz_list_page.dart'; import 'package:qhd_prevention/pages/home/Tap/special_work/sxkj_work/sxkj_wait_page.dart'; -import 'package:qhd_prevention/pages/home/Tap/work_tab_list_page.dart'; import 'package:qhd_prevention/pages/my_appbar.dart'; import 'package:qhd_prevention/tools/tools.dart'; diff --git a/lib/pages/home/Tap/special_work_apply_base_page.dart b/lib/pages/home/Tap/special_work_apply_base_page.dart index cbdbc5e..f32d424 100644 --- a/lib/pages/home/Tap/special_work_apply_base_page.dart +++ b/lib/pages/home/Tap/special_work_apply_base_page.dart @@ -85,6 +85,7 @@ abstract class SpecialWorkApplyBaseState /// 安全防护措施控制器 final SafeProtectionController safeController = SafeProtectionController(); + bool _isSyncingGasAndSafe = false; /// 初始化完成标志 bool loadingInitDone = false; @@ -190,9 +191,16 @@ abstract class SpecialWorkApplyBaseState @override void initState() { super.initState(); + safeController.addListener(_handleSafeControllerChanged); _loadPage(); } + @override + void dispose() { + safeController.removeListener(_handleSafeControllerChanged); + super.dispose(); + } + Future _loadPage() async { LoadingDialogHelper.show(); try { @@ -224,7 +232,9 @@ abstract class SpecialWorkApplyBaseState pd['signStepFlag'] = 2; pd['gasFlag'] = pd['gasFlag'] ?? 2; levelList = List.from(pd['taskWorkLevels'] ?? []); - + pd['applyTime'] = DateFormat( + 'yyyy-MM-dd HH:mm:ss', + ).format(DateTime.now()); if (enableSafeProtection) { await safeController.loadFromRaw( pd['preparers'] ?? pd['PREPARERS'] ?? [], @@ -478,7 +488,7 @@ abstract class SpecialWorkApplyBaseState } /// 选择部门单位 - void chooseUnitHandle(int index) { + void chooseUnitHandle(int index, bool ischoosePerson) { showModalBottomSheet( context: context, isScrollControlled: true, @@ -493,9 +503,11 @@ abstract class SpecialWorkApplyBaseState groups[index]['actUser'] = ''; groups[index]['actUserName'] = ''; }); - await _getPersonListForUnitId(id); + if (ischoosePerson) { + await _getPersonListForUnitId(id); + } }, - data: {'corpinfoId': pd['projectExecutionLocationCorpId'] ?? ''}, + data: {'eqCorpinfoId': pd['projectExecutionLocationCorpId'] ?? ''}, ), ); } @@ -538,7 +550,7 @@ abstract class SpecialWorkApplyBaseState }); await _getPersonListForUnitId(id); }, - data: {'corpinfoId': pd['projectExecutionLocationCorpId'] ?? ''}, + data: {'eqCorpinfoId': pd['xgfId'] ?? ''}, ), ); @@ -606,6 +618,9 @@ abstract class SpecialWorkApplyBaseState groups[index]['actUserName'] = name; groups[index]['actUserDepartment'] = data['departmentId']; groups[index]['actUserDepartmentName'] = data['departmentName']; + if (stepId == '2') { + syncSafeMeasureConfirmersWithGasAnalyzer(data); + } // 同步更新允许列表,用于安全措施确认人、气体分析人 if (stepId == '20') { allowChoosePerson['1'] = data; @@ -619,6 +634,74 @@ abstract class SpecialWorkApplyBaseState ); } + void _handleSafeControllerChanged() { + if (_isSyncingGasAndSafe) return; + + Map? selectedPerson; + for (final group in safeController.groups) { + if (group.updateId.isNotEmpty) { + selectedPerson = { + 'id': group.updateId, + 'name': group.updateName, + 'departmentId': group.departmentId, + 'departmentName': group.departmentName, + }; + break; + } + } + + if (selectedPerson == null) return; + + final gasItem = groups.cast().firstWhere( + (item) => (item?['stepId'] ?? '').toString() == '2', + orElse: () => null, + ); + if (gasItem == null) return; + + final nextUserId = (selectedPerson['id'] ?? '').toString(); + final currentUserId = (gasItem['actUser'] ?? '').toString(); + if (nextUserId.isEmpty || currentUserId == nextUserId) return; + + _isSyncingGasAndSafe = true; + try { + if (!mounted) return; + setState(() { + gasItem['actUser'] = nextUserId; + gasItem['actUserName'] = (selectedPerson?['name'] ?? '').toString(); + gasItem['actUserDepartment'] = + (selectedPerson?['departmentId'] ?? '').toString(); + gasItem['actUserDepartmentName'] = + (selectedPerson?['departmentName'] ?? '').toString(); + }); + } finally { + _isSyncingGasAndSafe = false; + } + } + + void syncSafeMeasureConfirmersWithGasAnalyzer(Map data) { + if (_isSyncingGasAndSafe) return; + + _isSyncingGasAndSafe = true; + try { + for (final group in safeController.groups) { + group.updateId = (data['id'] ?? data['actUser'] ?? '').toString(); + group.updateName = + (data['name'] ?? data['actUserName'] ?? '').toString(); + group.actUser = group.updateId; + group.actUserName = group.updateName; + group.departmentId = (data['departmentId'] ?? '').toString(); + group.departmentName = + (data['departmentName'] ?? data['actUserDepartmentName'] ?? '') + .toString(); + group.actUserDepartment = group.departmentId; + group.actUserDepartmentName = group.departmentName; + } + safeController.refresh(); + } finally { + _isSyncingGasAndSafe = false; + } + } + // 清空气体检测人和安全措施确认人 void clearRelatedPartiesPerson() { setState(() { @@ -744,6 +827,7 @@ abstract class SpecialWorkApplyBaseState final canSkip = (item['canSkip'] ?? 0) is int ? (item['canSkip'] ?? 0) : 0; final skipCondition = (item['skipCondition'] ?? '').toString(); final allowXgfFlag = item['allowXgfFlag'] ?? 0; + final showSignFlag = item['showSignFlag']; final deptLabel = actorField.isNotEmpty ? '$actorField 部门' : '单位'; final personLabel = actorField.isNotEmpty ? actorField : '人员'; @@ -760,7 +844,9 @@ abstract class SpecialWorkApplyBaseState skipCondition.isNotEmpty && skipCondition.contains('gas_flag') && pd['gasFlag'] == 1; - + if (showSignFlag == 2) { + return SizedBox(); + } return Column( children: [ if (item['selectLevel'] == 1) ...[ @@ -784,11 +870,23 @@ abstract class SpecialWorkApplyBaseState (item['actUserDepartmentName'] as String?)?.isNotEmpty == true ? item['actUserDepartmentName'] : '请选择', - onTap: () => chooseUnitHandle(index), + onTap: () => chooseUnitHandle(index, true), ), const Divider(), ], - if (canSkip == 1) ...[ + if (item['selectLevel'] == 3)...[ // 只选部门 + ItemListWidget.selectableLineTitleTextRightButton( + isRequired: !(canSkip == 1), + label: personLabel, + isEditable: isEditable, + text: + (item['actUserDepartmentName'] as String?)?.isNotEmpty == true + ? item['actUserDepartmentName'] + : '请选择', + onTap: () => chooseUnitHandle(index, false), + ), + const Divider(), + ]else...[if (canSkip == 1) ...[ if (skipCondition.isEmpty) ...[ ListItemFactory.createYesNoSection( horizontalPadding: 2, @@ -832,9 +930,9 @@ abstract class SpecialWorkApplyBaseState label: personLabel, isEditable: isEditable, text: - (item['actUserName'] as String?)?.isNotEmpty == true - ? item['actUserName'] - : '请选择', + (item['actUserName'] as String?)?.isNotEmpty == true + ? item['actUserName'] + : '请选择', onTap: () => choosePersonHandle(index, allowXgfFlag == 1), ), const Divider(), @@ -845,13 +943,14 @@ abstract class SpecialWorkApplyBaseState label: personLabel, isEditable: isEditable, text: - (item['actUserName'] as String?)?.isNotEmpty == true - ? item['actUserName'] - : '请选择', + (item['actUserName'] as String?)?.isNotEmpty == true + ? item['actUserName'] + : '请选择', onTap: () => choosePersonHandle(index, allowXgfFlag == 1), ), const Divider(), - ], + ],], + ], ); } @@ -945,6 +1044,14 @@ abstract class SpecialWorkApplyBaseState 'xgfId' : info['xgfId'] ?? '' }; payload.addAll(extraPayload); + for (final item in signLogs) { + if (item['stepId'] == '30' && info['isInnerWork'] == 1) { + item['actUserDepartment'] = pd['workChargeUserDepartment'] ?? ''; + item['actUserDepartmentName'] = pd['workChargeUserDepartmentName'] ?? ''; + item['actUser'] = pd['workChargeUserId'] ?? ''; + item['actUserName'] = pd['workChargeUserName'] ?? ''; + } + } if (FormUtils.hasValue(payload, 'workId') && widget.status == '2') { payload.remove('checkNo'); @@ -1011,7 +1118,9 @@ abstract class SpecialWorkApplyBaseState } for (final item in groupsToCheck) { - if (item['actUser'] == null || item['actUser'] == '') { + int showSignFlag = item['showSignFlag'] ?? 1; + int selectLevel = item['selectLevel'] ?? 0; + if ((item['actUser'] == null || item['actUser'] == '') && showSignFlag == 1 && selectLevel != 3) { final canSkip = (item['canSkip'] ?? 0) is int ? (item['canSkip'] ?? 0) : 0; final stepId = item['stepId'] ?? ''; diff --git a/lib/pages/home/Tap/special_work_task_page_base.dart b/lib/pages/home/Tap/special_work_task_page_base.dart index 21a956e..5b3c8a2 100644 --- a/lib/pages/home/Tap/special_work_task_page_base.dart +++ b/lib/pages/home/Tap/special_work_task_page_base.dart @@ -372,7 +372,24 @@ class _SpecialWorkTaskPageBaseState extends State { } } } + if (pd['componentName'] == 'personAnderRecordFile') { + // 判断是否上传了应急响应记录 spaceRecordFile、limitSpaceWorkNum + if (!FormUtils.hasValue(other, 'limitSpaceWorkNum')) { + ToastUtil.showNormal( + context, + '请输入有限空间作业人数', + ); + return; + } + if (!FormUtils.hasValue(other, 'spaceRecordFile')) { + ToastUtil.showNormal( + context, + '请上传应急响应记录', + ); + return; + } + } // 5) 签字必填 if (signImages.isEmpty) { if (!FormUtils.hasValue(other, 'isCompleteWork')) { @@ -1030,7 +1047,7 @@ class _SpecialWorkTaskPageBaseState extends State { final info = Map.from(raw); final signPath = (info['signPath'] ?? '').toString().trim(); - return signPath.isNotEmpty; + return signPath.isNotEmpty || _getSpaceRecordFiles(info).isNotEmpty; }).toList(); validEntries.sort((a, b) { @@ -1121,12 +1138,12 @@ class _SpecialWorkTaskPageBaseState extends State { final info = Map.from(raw); final stepName = (info['stepName'] ?? '').toString(); final signPath = (info['signPath'] ?? '').toString().trim(); - final signTime = (info['signTime'] ?? info['signerTime'] ?? '').toString().trim(); + final signTime = + (info['signTime'] ?? info['signerTime'] ?? '').toString().trim(); final remarks = (info['remarks'] ?? '').toString().trim(); + final spaceRecordFiles = _getSpaceRecordFiles(info); - if (signPath.isEmpty) continue; - - final imageUrl = '${ApiService.baseImgPath}$signPath'; + if (signPath.isEmpty && spaceRecordFiles.isEmpty) continue; widgets.add( Container( @@ -1167,27 +1184,35 @@ class _SpecialWorkTaskPageBaseState extends State { ), ), ), - GestureDetector( - onTap: () async { - presentOpaque(SingleImageViewer(imageUrl: imageUrl), context); - }, - child: Align( - alignment: Alignment.centerRight, - child: ConstrainedBox( - constraints: const BoxConstraints( - maxWidth: 220, - maxHeight: 140, - ), - child: Image.network( - imageUrl, - fit: BoxFit.contain, - errorBuilder: (context, error, stackTrace) { - return const Text('签字图片加载失败'); - }, + if (spaceRecordFiles.isNotEmpty) ...[ + _buildSpaceRecordFiles(spaceRecordFiles), + const SizedBox(height: 10), + ], + if (signPath.isNotEmpty) + GestureDetector( + onTap: () async { + presentOpaque( + SingleImageViewer(imageUrl: _fullFileUrl(signPath)), + context, + ); + }, + child: Align( + alignment: Alignment.centerRight, + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 220, + maxHeight: 140, + ), + child: Image.network( + _fullFileUrl(signPath), + fit: BoxFit.contain, + errorBuilder: (context, error, stackTrace) { + return const Text('签字图片加载失败'); + }, + ), ), ), ), - ), const SizedBox(height: 8), Align( alignment: Alignment.centerRight, @@ -1205,6 +1230,113 @@ class _SpecialWorkTaskPageBaseState extends State { return widgets; } + List _getSpaceRecordFiles(Map info) { + dynamic otherParams = info['otherParams']; + + if (otherParams is String) { + try { + otherParams = jsonDecode(otherParams); + } catch (_) { + otherParams = null; + } + } + + final raw = + otherParams is Map + ? (otherParams['spaceRecordFile'] ?? '') + : (info['spaceRecordFile'] ?? ''); + + return raw + .toString() + .split(',') + .map((path) => path.trim()) + .where((path) => path.isNotEmpty) + .toList(); + } + + String _fullFileUrl(String path) { + final value = path.trim(); + if (value.startsWith('http://') || value.startsWith('https://')) { + return value; + } + return '${ApiService.baseImgPath}$value'; + } + + bool _isPreviewImage(String path) { + final lower = path.toLowerCase().split('?').first; + return lower.endsWith('.jpg') || + lower.endsWith('.jpeg') || + lower.endsWith('.png') || + lower.endsWith('.webp') || + lower.endsWith('.gif') || + lower.endsWith('.bmp'); + } + + Widget _buildSpaceRecordFiles(List files) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + Wrap( + spacing: 10, + runSpacing: 10, + children: + files.map((path) { + final fileUrl = _fullFileUrl(path); + if (_isPreviewImage(path)) { + return GestureDetector( + onTap: () { + presentOpaque( + SingleImageViewer(imageUrl: fileUrl), + context, + ); + }, + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 120, + maxHeight: 90, + ), + child: Image.network( + fileUrl, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return const Text(''); + }, + ), + ), + ); + } + + final fileName = path.split('/').last; + return InkWell( + onTap: () { + pushPage(ReadFilePage(fileUrl: fileUrl), context); + }, + child: Container( + constraints: const BoxConstraints(maxWidth: 220), + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 8, + ), + decoration: BoxDecoration( + color: Colors.grey.shade100, + borderRadius: BorderRadius.circular(4), + border: Border.all(color: Colors.grey.shade300), + ), + child: Text( + fileName.isNotEmpty ? fileName : '查看附件', + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 12, color: Colors.blue), + ), + ), + ); + }).toList(), + ), + ], + ); + } + // 其他安全措施回显 Widget _otherMeasureWidgets() { if (_otherMeasuresList.isNotEmpty) { diff --git a/lib/pages/home/home_page.dart b/lib/pages/home/home_page.dart index b4533f9..27c1c67 100644 --- a/lib/pages/home/home_page.dart +++ b/lib/pages/home/home_page.dart @@ -199,7 +199,7 @@ class HomePageState extends RouteAwareState final routeService = RouteService(); final mainTabs = routeService.mainTabs; if (mainTabs.isEmpty) { - // 路由未加载,保持全隐藏 + // 路由未加载,保持全隐藏ƒ return; }