Compare commits

...

3 Commits

Author SHA1 Message Date
hs 5edff0f2e2 Merge remote-tracking branch 'origin/master' 2026-06-15 16:06:27 +08:00
hs 1362a301c0 危险作业需求变更bug 2026-06-15 16:06:22 +08:00
hs 3c4e30bc88 危险作业需求变更 2026-06-15 15:24:33 +08:00
27 changed files with 888 additions and 940 deletions

View File

@ -476,6 +476,11 @@ enum UploadFileType {
'410',
'special_operation_special_apply_involved_signature',
),
// - : '411',
specialOperationInAndOutRecord(
'411',
'special_operation_in_and_out_record',
),

View File

@ -926,7 +926,7 @@ class ItemListWidget {
required VoidCallback? onTapFile, //
double fontSize = 14, //
bool isEdit = true,
String buttonText = '气体分析详情',
String buttonText = '',
double horizontalnum = horizontal_inset,
bool isRequired = false,
final String fileUrl = '',
@ -991,7 +991,7 @@ class ItemListWidget {
],
),
),
if (isEdit)
if (isEdit && buttonText.isNotEmpty)
CustomButton(
text: buttonText,
height: 30,

View File

@ -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<SafeProtectionModule> {
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<SafeProtectionModule> {
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<SafeProtectionModule> {
),
);
}
}
}

View File

@ -155,7 +155,7 @@ class _HotWorkDetailFormWidgetState extends State<HotWorkDetailFormWidget> {
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '申请日期',
label: '申请时间',
text: pd['applyTime'] ?? '',
isEditable: widget.isEditable,
onTap: () async {},

View File

@ -143,9 +143,9 @@ class _HotWorkApplyPageState extends SpecialWorkApplyBaseState<HotWorkApplyPage>
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<HotWorkApplyPage>
},
);
}
}
}

View File

@ -144,7 +144,13 @@ class _BreakgroundDetailFormWidgetState extends State<BreakgroundDetailFormWidge
isEditable: false,
text: pd['applyUser'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '申请时间:',
text: pd['applyTime'] ?? '',
isEditable: widget.isEditable,
onTap: () async {},
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '作业类型:',

View File

@ -158,6 +158,27 @@ class _DlApplyPageState extends SpecialWorkApplyBaseState<DlApplyPage> {
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<DlApplyPage> {
groups[index]['actUserName'] = name;
groups[index]['actUserDepartment'] = data['departmentId'] ?? '';
groups[index]['actUserDepartmentName'] = data['departmentName'] ?? '';
syncSafeMeasureConfirmersWithGasAnalyzer(data);
});
},
);
@ -433,4 +454,4 @@ class _DlApplyPageState extends SpecialWorkApplyBaseState<DlApplyPage> {
}
return true;
}
}
}

View File

@ -144,7 +144,13 @@ class _CutRoadDetailFormWidgetState extends State<CutRoadDetailFormWidget> {
isEditable: false,
text: pd['applyUser'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '申请时间:',
text: pd['applyTime'] ?? '',
isEditable: widget.isEditable,
onTap: () async {},
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '作业类型:',

View File

@ -157,6 +157,27 @@ class _DtApplyPageState extends SpecialWorkApplyBaseState<DtApplyPage> {
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<DtApplyPage> {
groups[index]['actUserName'] = name;
groups[index]['actUserDepartment'] = data['departmentId'] ?? '';
groups[index]['actUserDepartmentName'] = data['departmentName'] ?? '';
syncSafeMeasureConfirmersWithGasAnalyzer(data);
});
},
);
@ -417,4 +438,4 @@ class _DtApplyPageState extends SpecialWorkApplyBaseState<DtApplyPage> {
}
return true;
}
}
}

View File

@ -152,6 +152,27 @@ class _DzApplyPageState extends SpecialWorkApplyBaseState<DzApplyPage> {
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<DzApplyPage> {
groups[index]['actUserName'] = name;
groups[index]['actUserDepartment'] = data['departmentId'] ?? '';
groups[index]['actUserDepartmentName'] = data['departmentName'] ?? '';
syncSafeMeasureConfirmersWithGasAnalyzer(data);
});
},
);
@ -418,4 +439,4 @@ class _DzApplyPageState extends SpecialWorkApplyBaseState<DzApplyPage> {
),
);
}
}
}

View File

@ -143,7 +143,13 @@ class _HoistingDetailFormWidgetState extends State<HoistingDetailFormWidget> {
isEditable: false,
text: pd['applyUser'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '申请时间:',
text: pd['applyTime'] ?? '',
isEditable: widget.isEditable,
onTap: () async {},
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '作业类型:',

View File

@ -140,7 +140,13 @@ class _HeighWorkDetailFormWidgetState extends State<HeighWorkDetailFormWidget> {
isEditable: false,
text: pd['applyUser'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '申请时间:',
text: pd['applyTime'] ?? '',
isEditable: widget.isEditable,
onTap: () async {},
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '作业类型:',

View File

@ -149,6 +149,27 @@ class _GcApplyPageState extends SpecialWorkApplyBaseState<GcApplyPage> {
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<GcApplyPage> {
groups[index]['actUserName'] = name;
groups[index]['actUserDepartment'] = data['departmentId'] ?? '';
groups[index]['actUserDepartmentName'] = data['departmentName'] ?? '';
syncSafeMeasureConfirmersWithGasAnalyzer(data);
});
},
);
@ -390,4 +411,4 @@ class _GcApplyPageState extends SpecialWorkApplyBaseState<GcApplyPage> {
),
);
}
}
}

View File

@ -146,6 +146,13 @@ class _LsydWorkDetailFormWidgetState extends State<LsydWorkDetailFormWidget> {
text: pd['applyUser'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '申请时间:',
text: pd['applyTime'] ?? '',
isEditable: widget.isEditable,
onTap: () async {},
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '作业类型:',
isEditable: false,

View File

@ -158,6 +158,27 @@ class _LsydApplyPageState extends SpecialWorkApplyBaseState<LsydApplyPage> {
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<LsydApplyPage> {
groups[index]['actUserName'] = name;
groups[index]['actUserDepartment'] = data['departmentId'] ?? '';
groups[index]['actUserDepartmentName'] = data['departmentName'] ?? '';
syncSafeMeasureConfirmersWithGasAnalyzer(data);
});
},
);
@ -435,4 +456,4 @@ class _LsydApplyPageState extends SpecialWorkApplyBaseState<LsydApplyPage> {
),
);
}
}
}

View File

@ -194,7 +194,13 @@ class _MbcdDetailFormWidgetState extends State<MbcdDetailFormWidget> {
isEditable: false,
text: pd['applyUser'] ?? '',
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '申请时间:',
text: pd['applyTime'] ?? '',
isEditable: widget.isEditable,
onTap: () async {},
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '作业类型:',

View File

@ -199,6 +199,27 @@ class _MbcdApplyPageState extends SpecialWorkApplyBaseState<MbcdApplyPage> {
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<MbcdApplyPage> {
),
);
}
}
}

View File

@ -143,7 +143,7 @@ class _SxkjWorkDetailFormWidgetState extends State<SxkjWorkDetailFormWidget> {
),
const Divider(),
ItemListWidget.selectableLineTitleTextRightButton(
label: '申请日期',
label: '申请时间',
text: pd['applyTime'] ?? '',
isEditable: widget.isEditable,
onTap: () async {},
@ -176,12 +176,12 @@ class _SxkjWorkDetailFormWidgetState extends State<SxkjWorkDetailFormWidget> {
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: '有限空间名称及编号:',

View File

@ -75,39 +75,40 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState<SxkjApplyPage> {
@override
Future<void> 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<void> _clearRelatedParties() async {
setState(() {
pd['limitedSpaceNameAndCode'] = '';
pd['chooseLimitedSpace'] = {};
});
}
@override
Future<void> 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<SxkjApplyPage> {
Future<Map<String, dynamic>> 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<SxkjApplyPage> {
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<SxkjApplyPage> {
);
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<SxkjApplyPage> {
groupValue: pd['internalOperationFlag'] == 1,
onChanged: (value) {
setState(() {
isInnerWork = value;
pd['internalOperationFlag'] = value ? 1 : 2;
});
},
@ -266,15 +269,15 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState<SxkjApplyPage> {
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<SxkjApplyPage> {
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<SxkjApplyPage> {
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<SxkjApplyPage> {
//
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<SxkjApplyPage> {
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,43 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState<SxkjApplyPage> {
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<dynamic> personList = allPersonList;
List<dynamic> xgfList = relatedPartiesPersonList;
// if (pd['xgfFlag'] == 1 && relatedPartiesPersonList.isNotEmpty) {
// personList = [...personList, ...relatedPartiesPersonList];
// }
List<dynamic> personList = [];
// List<dynamic> xgfList = relatedPartiesPersonList;
final String workDepartmentId = (pd['workDepartment'] ?? '').toString();
List<dynamic> xgfList =
relatedPartiesPersonList.where((item) {
if (item is! Map) return false;
return (item['departmentId'] ?? '').toString() == workDepartmentId;
}).toList();
if (!FormUtils.hasValue(pd, 'workDepartment')) {
personList = allPersonList;
}
if (personList.isEmpty) {
ToastUtil.showNormal(context, '暂无该部门人员');
return;
}
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 +525,6 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState<SxkjApplyPage> {
pd['workChargeUserDepartment'] = data['departmentId'];
pd['workChargeUserDepartmentName'] = data['departmentName'];
allowChoosePerson['1'] = data;
} else {
pd['workGuardianUserId'] = userId;
pd['workGuardianUserName'] = name;
@ -546,4 +567,4 @@ class _SxkjApplyPageState extends SpecialWorkApplyBaseState<SxkjApplyPage> {
return <String, dynamic>{};
}).toList();
}
}
}

View File

@ -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<String, dynamic> data;
@override
State<SxkjRecordAddPage> createState() => _SxkjRecordAddPageState();
}
class _SxkjRecordAddPageState extends State<SxkjRecordAddPage> {
final List<String> _images = [];
Map<String, dynamic> pd = {};
List<String> signImages = [];
List<String> signTimes = [];
bool _isSubmitting = false;
@override
void initState() {
super.initState();
pd = Map<String, dynamic>.from(widget.data);
}
Future<void> _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<String> _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<String> _uploadSignImages() async {
final paths = <String>[];
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<void> _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<File> 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,
),
],
),
),
),
);
}
}

View File

@ -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<void> onOpenDetail(
BuildContext context,
Map<String, dynamic> item,
bool isEdit,
) async {
BuildContext context,
Map<String, dynamic> 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<void> 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<String, dynamic> item,
Map<String, dynamic> workInfo,
Map<String, dynamic> info,
String statusName,
) {
BuildContext context,
Map<String, dynamic> item,
Map<String, dynamic> workInfo,
Map<String, dynamic> info,
String statusName,
) {
final chooseLimitedSpace = Map<String, dynamic>.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,

View File

@ -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<String, dynamic> info;
@override
State<SxkjTzApplyPage> createState() => _SxkjTzApplyPageState();
}
class _SxkjTzApplyPageState extends State<SxkjTzApplyPage> {
bool _isEditable = true;
// pd
List<Map<String, String>> 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<String, dynamic> pd = {'isEmergencyBook': 2};
//
List typeList = [];
@override
void initState() {
super.initState();
_isEditable = widget.isEdit;
if (!widget.isEdit) {
pd = widget.info;
}
}
//
Future<void> uploadFileHandle() async {
final List<SelectedFile> 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<void> 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<void> 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<void> 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<void> _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),
],
),
],
),
),
),
);
}
}

View File

@ -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<SxkjTzListPage> {
// Data and state variables
List<dynamic> list = [];
int currentPage = 1;
int rows = 10;
int totalPage = 1;
bool isLoading = false;
final TextEditingController _searchController = TextEditingController();
List<Map<String, dynamic>> stepList = [];
int sindex = 0;
String searchKeywords = '';
List<Map<String, dynamic>> flowList = [];
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
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<void> _fetchSteps() async {
try {} catch (e) {
print('Error fetching steps: $e');
}
}
Future<void> _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<String, dynamic> item, bool isEdit) async {
pushPage(
SxkjTzApplyPage(isEdit: false, work_id: item['id'] ?? '', info: item),
context,
);
_fetchData();
}
Widget _buildListItem(Map<String, dynamic> 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<String, dynamic> item) {
final List<Widget> buttons = [];
final List<Widget> 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()),
],
),
),
);
}
}

View File

@ -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';

View File

@ -85,6 +85,7 @@ abstract class SpecialWorkApplyBaseState<T extends SpecialWorkApplyBasePage>
///
final SafeProtectionController safeController = SafeProtectionController();
bool _isSyncingGasAndSafe = false;
///
bool loadingInitDone = false;
@ -190,9 +191,16 @@ abstract class SpecialWorkApplyBaseState<T extends SpecialWorkApplyBasePage>
@override
void initState() {
super.initState();
safeController.addListener(_handleSafeControllerChanged);
_loadPage();
}
@override
void dispose() {
safeController.removeListener(_handleSafeControllerChanged);
super.dispose();
}
Future<void> _loadPage() async {
LoadingDialogHelper.show();
try {
@ -224,7 +232,9 @@ abstract class SpecialWorkApplyBaseState<T extends SpecialWorkApplyBasePage>
pd['signStepFlag'] = 2;
pd['gasFlag'] = pd['gasFlag'] ?? 2;
levelList = List<dynamic>.from(pd['taskWorkLevels'] ?? []);
pd['applyTime'] = DateFormat(
'yyyy-MM-dd HH:mm:ss',
).format(DateTime.now());
if (enableSafeProtection) {
await safeController.loadFromRaw(
pd['preparers'] ?? pd['PREPARERS'] ?? [],
@ -385,7 +395,7 @@ abstract class SpecialWorkApplyBaseState<T extends SpecialWorkApplyBasePage>
/// initData
void _initGroupsFromInitData(bool isRefresh) {
_clearAllPerson();
if (!widget.isReEdit) _clearAllPerson();
final List steps =
(initData['settingSignSteps'] is List)
? List.from(initData['settingSignSteps'])
@ -478,7 +488,7 @@ abstract class SpecialWorkApplyBaseState<T extends SpecialWorkApplyBasePage>
}
///
void chooseUnitHandle(int index) {
void chooseUnitHandle(int index, bool ischoosePerson) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
@ -493,9 +503,11 @@ abstract class SpecialWorkApplyBaseState<T extends SpecialWorkApplyBasePage>
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<T extends SpecialWorkApplyBasePage>
});
await _getPersonListForUnitId(id);
},
data: {'corpinfoId': pd['projectExecutionLocationCorpId'] ?? ''},
data: {'eqCorpinfoId': pd['xgfId'] ?? ''},
),
);
@ -606,6 +618,9 @@ abstract class SpecialWorkApplyBaseState<T extends SpecialWorkApplyBasePage>
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<T extends SpecialWorkApplyBasePage>
);
}
void _handleSafeControllerChanged() {
if (_isSyncingGasAndSafe) return;
Map<String, dynamic>? 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<Map?>().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<String, dynamic> 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<T extends SpecialWorkApplyBasePage>
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<T extends SpecialWorkApplyBasePage>
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<T extends SpecialWorkApplyBasePage>
(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<T extends SpecialWorkApplyBasePage>
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<T extends SpecialWorkApplyBasePage>
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<T extends SpecialWorkApplyBasePage>
'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<T extends SpecialWorkApplyBasePage>
}
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'] ?? '';

View File

@ -372,7 +372,24 @@ class _SpecialWorkTaskPageBaseState extends State<SpecialWorkTaskPageBase> {
}
}
}
if (pd['componentName'] == 'personAnderRecordFile') {
// spaceRecordFilelimitSpaceWorkNum
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<SpecialWorkTaskPageBase> {
final info = Map<String, dynamic>.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<SpecialWorkTaskPageBase> {
final info = Map<String, dynamic>.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<SpecialWorkTaskPageBase> {
),
),
),
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<SpecialWorkTaskPageBase> {
return widgets;
}
List<String> _getSpaceRecordFiles(Map<String, dynamic> 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<String> 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) {

View File

@ -199,7 +199,7 @@ class HomePageState extends RouteAwareState<HomePage>
final routeService = RouteService();
final mainTabs = routeService.mainTabs;
if (mainTabs.isEmpty) {
//
// ƒ
return;
}