diff --git a/lib/customWidget/item_list_widget.dart b/lib/customWidget/item_list_widget.dart index b6f2c5a..c856e41 100644 --- a/lib/customWidget/item_list_widget.dart +++ b/lib/customWidget/item_list_widget.dart @@ -665,32 +665,36 @@ class ItemListWidget { /// 标题 + 按钮 /// 第二行:多行输入框或多行文本展示 static Widget twoRowButtonTitleText({ - required String label, // 第一行标题 - required bool isEditable, // 是否可编辑 - bool isInput = true, // 是否可输入 - required String text, // 显示内容或提示 - TextEditingController? controller, // 第二行编辑控制器 - required VoidCallback? onTap, // 第一行点击回调 + required String label, + required bool isEditable, + bool isInput = true, + required String text, // 初始值或外部显示的文本(当没有controller时使用) + TextEditingController? controller, // 可选:外部传入则优先使用,否则内部自动创建 + required VoidCallback? onTap, String buttonText = '选择其他', required String hintText, - double fontSize = 14, // 字体大小 - double row2Height = 80, // 第二行高度 + double fontSize = 14, + double row2Height = 80, bool isRequired = true, + ValueChanged? onChanged, // 文本变化回调 }) { + // 如果没有传入 controller,则内部创建一个,并设置初始文本 + final effectiveController = controller ?? TextEditingController(text: text); + + // 注意:如果内部创建了 controller,外部无法直接更新其 text。 + // 若需要外部通过改变 text 参数来更新输入框,则必须传入 controller 并手动设置 controller.text。 + // 或者每次重建时根据 text 参数重新创建 controller(会丢失焦点和输入历史)。 + return Container( - padding: const EdgeInsets.symmetric( - vertical: vertical_inset, - horizontal: horizontal_inset, - ), + padding: const EdgeInsets.symmetric(vertical: vertical_inset, horizontal: horizontal_inset), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // 第一行:标题 + 按钮 InkWell( child: Row( children: [ Flexible( - fit: FlexFit.loose, // loose 模式下它可以比最大宽度更小 + fit: FlexFit.loose, child: Row( children: [ if (isRequired && isEditable) @@ -698,10 +702,7 @@ class ItemListWidget { Flexible( child: Text( label, - style: TextStyle( - fontSize: fontSize, - fontWeight: FontWeight.bold, - ), + style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold), maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -714,51 +715,41 @@ class ItemListWidget { CustomButton( text: buttonText, height: 30, - padding: const EdgeInsets.symmetric( - vertical: 2, - horizontal: 10, - ), - textStyle: TextStyle( - color: Colors.white, - fontSize: 11, - fontWeight: FontWeight.bold, - ), + padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 10), + textStyle: TextStyle(color: Colors.white, fontSize: 11, fontWeight: FontWeight.bold), backgroundColor: Colors.blue, onPressed: onTap, ), ], ), ), - const SizedBox(height: 8), - Container( height: row2Height, padding: const EdgeInsets.symmetric(vertical: 8), - child: - (isEditable && isInput) - ? TextField( - autofocus: false, - controller: controller, - keyboardType: TextInputType.multiline, - maxLines: null, - expands: true, - style: TextStyle(fontSize: fontSize), - decoration: InputDecoration( - hintText: hintText, - //contentPadding: EdgeInsets.zero, - border: InputBorder.none, - ), - ) - : SingleChildScrollView( - padding: EdgeInsets.zero, - child: Text( - text, - style: TextStyle( - fontSize: fontSize, - color: detailtextColor, - ), - ), - ), + child: (isEditable && isInput) + ? TextFormField( + controller: effectiveController, + autofocus: false, + onChanged: (value) { + // 触发外部回调,外部可以在回调中 setState 更新自己的变量 + onChanged?.call(value); + }, + keyboardType: TextInputType.multiline, + maxLines: null, + expands: true, + style: TextStyle(fontSize: fontSize), + decoration: InputDecoration( + hintText: hintText, + border: InputBorder.none, + ), + ) + : SingleChildScrollView( + padding: EdgeInsets.zero, + child: Text( + text, + style: TextStyle(fontSize: fontSize, color: detailtextColor), + ), + ), ), ], ), diff --git a/lib/customWidget/related_parties_picker.dart b/lib/customWidget/related_parties_picker.dart index 5b7bb6c..4a93a5a 100644 --- a/lib/customWidget/related_parties_picker.dart +++ b/lib/customWidget/related_parties_picker.dart @@ -102,7 +102,7 @@ class _RelatedPartiesPickerState extends State { Future _getRelatedPartiesList() async { try { - final raw = await HiddenDangerApi.getRelatedPartiesList(); + final raw = await BasicInfoApi.getCropinfoProjectNameList(); if (raw['success']) { final newList = raw['data'] ?? []; setState(() { diff --git a/lib/customWidget/work_tab_icon_grid.dart b/lib/customWidget/work_tab_icon_grid.dart index 2f33877..26fa3df 100644 --- a/lib/customWidget/work_tab_icon_grid.dart +++ b/lib/customWidget/work_tab_icon_grid.dart @@ -25,47 +25,47 @@ class WorkTabIconGrid extends StatelessWidget { borderRadius: BorderRadius.circular(8), ), child: - buttonInfos.length <= 4 - ? Row( - mainAxisAlignment: MainAxisAlignment.start, - children: - buttonInfos.asMap().entries.map((entry) { - final index = entry.key; - final info = entry.value; - return _buildIconButton( - context: context, - iconPath: info['icon'] as String, - label: info['title'] as String, - unreadCount: - int.tryParse(info['unreadCount'].toString()) ?? 0, - onPressed: () => onItemPressed(index), - width: itemW, - ); - }).toList(), - ) - : Wrap( - spacing: 0, - runSpacing: 16, - alignment: WrapAlignment.start, - children: - buttonInfos.asMap().entries.map((entry) { - final index = entry.key; - final info = entry.value; - return _buildIconButton( - context: context, - iconPath: info['icon'] as String, - label: info['title'] as String, - unreadCount: - info['unreadCount'] is String - ? int.tryParse(info['unreadCount']) - : info['unreadCount'] is int - ? info['unreadCount'] - : 0, - onPressed: () => onItemPressed(index), - width: itemW, - ); - }).toList(), - ), + buttonInfos.length <= 4 + ? Row( + mainAxisAlignment: MainAxisAlignment.start, + children: + buttonInfos.asMap().entries.map((entry) { + final index = entry.key; + final info = entry.value; + return _buildIconButton( + context: context, + iconPath: info['icon'] as String, + label: info['title'] as String, + unreadCount: + int.tryParse(info['unreadCount'].toString()) ?? 0, + onPressed: () => onItemPressed(index), + width: itemW, + ); + }).toList(), + ) + : Wrap( + spacing: 0, + runSpacing: 16, + alignment: WrapAlignment.start, + children: + buttonInfos.asMap().entries.map((entry) { + final index = entry.key; + final info = entry.value; + return _buildIconButton( + context: context, + iconPath: info['icon'] as String, + label: info['title'] as String, + unreadCount: + info['unreadCount'] is String + ? int.tryParse(info['unreadCount']) + : info['unreadCount'] is int + ? info['unreadCount'] + : 0, + onPressed: () => onItemPressed(index), + width: itemW, + ); + }).toList(), + ), ); } @@ -93,10 +93,14 @@ class WorkTabIconGrid extends StatelessWidget { children: [ Image.asset(iconPath, width: 30, height: 30), const SizedBox(height: 5), - Text( - label, - style: const TextStyle(fontSize: 13), - textAlign: TextAlign.center, + SizedBox( + width: 70, // 指定宽度,超过则自动换行 + child: Text( + label, + style: const TextStyle(fontSize: 13), + textAlign: TextAlign.center, + softWrap: true, + ), ), ], ), diff --git a/lib/http/ApiService.dart b/lib/http/ApiService.dart index 37759fc..dd898c0 100644 --- a/lib/http/ApiService.dart +++ b/lib/http/ApiService.dart @@ -9,19 +9,19 @@ class ApiService { static final bool isProduct = true; /// 登录及其他管理后台接口 - // static final String basePath = "https://skqhdg.porthebei.com:9007"; - static final String basePath = - isProduct - ? "https://gbs-gateway.qhdsafety.com" - : "http://192.168.20.100:30140"; + static final String basePath = "https://skqhdg.porthebei.com:9007"; + // static final String basePath = + // isProduct + // ? "https://gbs-gateway.qhdsafety.com" + // : "http://192.168.20.100:30140"; /// 图片文件服务 - static final String baseImgPath = - isProduct - ? "https://jpfz.qhdsafety.com/gbsFileTest/" - : "http://192.168.20.240:9787/mnt/"; //内网图片地址 - // static final String baseImgPath = "https://skqhdg.porthebei.com:9004/file/uploadFiles2/"; + // static final String baseImgPath = + // isProduct + // ? "https://jpfz.qhdsafety.com/gbsFileTest/" + // : "http://192.168.20.240:9787/mnt/"; //内网图片地址 + static final String baseImgPath = "https://skqhdg.porthebei.com:9004/file/uploadFiles2/"; static const publicKey = diff --git a/lib/http/modules/basic_info_api.dart b/lib/http/modules/basic_info_api.dart index b027b82..03df6e2 100644 --- a/lib/http/modules/basic_info_api.dart +++ b/lib/http/modules/basic_info_api.dart @@ -121,6 +121,18 @@ class BasicInfoApi { ); } + // 获取分公司项目列表 + static Future> getCropinfoProjectNameList() { + return HttpManager().request( + '${ApiService.basePath}', + '/xgfManager/project/listAllProjectBySelfCorp', + method: Method.post, + data: { + 'pageSize': 999, + 'pageIndex': 1, + }, + ); + } diff --git a/lib/http/modules/hidden_danger_api.dart b/lib/http/modules/hidden_danger_api.dart index a7fd5fc..c3e1b78 100644 --- a/lib/http/modules/hidden_danger_api.dart +++ b/lib/http/modules/hidden_danger_api.dart @@ -4,17 +4,6 @@ import 'package:qhd_prevention/http/ApiService.dart'; import 'package:qhd_prevention/http/HttpManager.dart'; class HiddenDangerApi { - /// 获取执行属地公司 是自己单位的下的项目列表 - static Future> getRelatedPartiesList() { - return HttpManager().request( - '${ApiService.basePath}/xgfManager', - '/project/listAllByCorp', - method: Method.get, - data: { - // ...data, - }, - ); - } /// 获取隐患部位 static Future> getHiddenDangerAreas() { diff --git a/lib/pages/home/Tap/special_header.dart b/lib/pages/home/Tap/special_header.dart index 73997f2..cad4a34 100644 --- a/lib/pages/home/Tap/special_header.dart +++ b/lib/pages/home/Tap/special_header.dart @@ -37,40 +37,12 @@ enum SpecialListType { // 台账 list, } -// "operationTypeName": "请选择作业类型", -// "workLocation": "请输入作业地点", -// "workUserName": "请选择作业人", -// "workHeight": "请输入作业高度", -// "workLevel": "请选择作业级别", -// "workContent": "请输入作业内容", -// "longitude" : "请定位位置", -// "linkSpecialWorks": "请选择关联其他特殊作业及安全作业票编号", -// "riskResults": "请选择风险辨识结果", -// "workStartTime": "请选择作业实施开始时间", -// "workEndTime": "请选择作业实施结束时间", -// "operationTypeName": "请选择作业类型", -// "workLevel": "请选择作业级别", -// "workStartTime": "请选择作业开始时间", -// "workEndTime": "请选择作业结束时间", -// "longitude" : "请定位位置", -// "workContent": "请输入作业内容", -// 'workScopeAndMethod' : "请输入作业内容、范围、方式", -// 'isWorkScopeAndMethodImage' : "请选择作业内容、范围、方式简图", -// "linkSpecialWorks": "请选择关联其他特殊作业及安全作业票编号", -// "riskResults": "请选择风险辨识结果", -// pd['signStepFlag'] = 2; -// pd['gasFlag'] = 2; -// levelList = pd['taskWorkLevels'] ?? []; -// await safeController.loadFromRaw( -// pd['preparers'] ?? pd['PREPARERS'] ?? [], -// ); -// if (levelList.length > 0) { -// final item = levelList.first ?? {}; -// pd['workLevelName'] = item['taskName']; -// pd['workLevel'] = item['workLevel']; class SpecialListInitData { List getInitData(SpecialWorkTypeEnum type) { List list = [ + // 动火 + "work_place",//动火部位 + "work_way", // 受限空间 "applyUnit", "applyUser", @@ -151,8 +123,9 @@ class SpecialListInitData { "applyUserSignImage", ]; - - return list; } -} \ No newline at end of file +} + +bool isKF = true; + diff --git a/lib/pages/home/Tap/special_work/custom/MeasuresListWidget.dart b/lib/pages/home/Tap/special_work/custom/MeasuresListWidget.dart index 0a4f074..480ef9f 100644 --- a/lib/pages/home/Tap/special_work/custom/MeasuresListWidget.dart +++ b/lib/pages/home/Tap/special_work/custom/MeasuresListWidget.dart @@ -8,6 +8,7 @@ import 'package:qhd_prevention/customWidget/dotted_border_box.dart'; import 'package:qhd_prevention/customWidget/item_list_widget.dart'; import 'package:qhd_prevention/customWidget/single_image_viewer.dart'; import 'package:qhd_prevention/http/ApiService.dart'; +import 'package:qhd_prevention/pages/home/Tap/special_header.dart'; import 'package:qhd_prevention/tools/tools.dart'; class MeasuresListWidget extends StatefulWidget { @@ -37,7 +38,7 @@ class _MeasuresListWidgetState extends State { @override Widget build(BuildContext context) { if (measuresList.isEmpty) { - return const Center(child: Text('暂无更多数据')); + return const SizedBox(); } return SingleChildScrollView( @@ -48,7 +49,7 @@ class _MeasuresListWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ ListItemFactory.createBuildSimpleSection('安全防护措施'), - if (widget.isAllowEdit) + if (widget.isAllowEdit && isKF) ItemListWidget.OneRowButtonTitleText( label: '开发按钮-自测使用', buttonText: '一键签字', @@ -82,7 +83,7 @@ class _MeasuresListWidgetState extends State { final columnWidthsReadOnly = { 0: const FlexColumnWidth(7), // 安全措施 1: const FixedColumnWidth(70), // 是否符合 - 2: const FixedColumnWidth(80), // 签字(图片) + 2: const FixedColumnWidth(120), // 签字(图片) }; final isEdit = widget.isAllowEdit; 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 6b0ce66..e31d056 100644 --- a/lib/pages/home/Tap/special_work/dh_work/HotWorkDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/dh_work/HotWorkDetailFormWidget.dart @@ -270,6 +270,29 @@ class _HotWorkDetailFormWidgetState extends State { isEditable: widget.isEditable, text: pd['operationTypeName'] ?? '', ), + + if (pd['xgfFlag'] == 1) ...[ + const Divider(), + ListItemFactory.createYesNoSection( + horizontalPadding: 2, + verticalPadding: 7, + title: '是否项目内作业', + isRequired: true, + isEdit: false, + text: '${pd['internalOperationFlag']}' == '1' ? '是' : '否', + groupValue: null, onChanged: (bool value) { }, + + ), + const Divider(height: 1), + + // 相关方作业 + ItemListWidget.selectableLineTitleTextRightButton( + label: '相关方项目', + isEditable: false, + text: pd['projectName'] ?? '', + isRequired: true, + ), + ], const Divider(), ItemListWidget.singleLineTitleText( label: '动火部位:', diff --git a/lib/pages/home/Tap/special_work/dh_work/dh_wait_page.dart b/lib/pages/home/Tap/special_work/dh_work/dh_wait_page.dart index 4982aa5..dddbaae 100644 --- a/lib/pages/home/Tap/special_work/dh_work/dh_wait_page.dart +++ b/lib/pages/home/Tap/special_work/dh_work/dh_wait_page.dart @@ -409,7 +409,7 @@ class _DhWaitPageState extends State { }, ), ); - if (status == '1' && lockFlag == '2') { + if (status == '1' && lockFlag == '2' && widget.listType == SpecialListType.list) { buttons.add( CustomButton( text: '撤回', 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 d6112f6..1a6c1ae 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 @@ -15,7 +15,8 @@ import 'package:qhd_prevention/customWidget/item_list_widget.dart'; import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.dart'; import 'package:qhd_prevention/customWidget/related_parties_picker.dart'; import 'package:qhd_prevention/customWidget/toast_util.dart'; -// + +// import 'package:qhd_prevention/pages/home/Tap/special_header.dart'; import 'package:qhd_prevention/pages/home/Tap/special_work/custom/CustomSpecialFormDialog.dart'; import 'package:qhd_prevention/pages/home/Tap/special_work/dh_work/HotWorkDetailFormWidget.dart'; @@ -104,10 +105,6 @@ class _HotworkApplyDetailState extends State { _dhworkWays = res['data']; }); } - final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 1); - if (personRes['success'] == true) { - _allPersonList = personRes['data']; - } if (widget.isReEdit) { final initData = await SpecialWorkApi.specialWorkTaskLogDetail( widget.work_id, @@ -131,7 +128,9 @@ class _HotworkApplyDetailState extends State { LoadingDialogHelper.dismiss(); if (initData['success'] == true) { // taskWorkLevels - pd = initData['data']; + pd = initData['data'] ?? {}; + pd['xgfFlag'] = 1; + pd['operationTypeName'] = '相关方作业'; pd['signStepFlag'] = 2; pd['gasFlag'] = 0; levelList = pd['taskWorkLevels']; @@ -197,6 +196,9 @@ class _HotworkApplyDetailState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: { + 'corpinfoId' : pd['projectExecutionLocationCorpId'] ?? '' + }, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); @@ -257,7 +259,7 @@ class _HotworkApplyDetailState extends State { await _getPersonListForUnitId(unitId); personList = _personCache[unitId] ?? []; if (personList.isEmpty) { - ToastUtil.showNormal(context, '暂无可选人员,请选择其他单位'); + ToastUtil.showNormal(context, '暂无可选人员,请选择正确的相关方项目'); return; } } @@ -399,6 +401,19 @@ class _HotworkApplyDetailState extends State { }); } } + if (isKF) test(); + }); + } + Future test() async { + for (Map item in _groups) { + item['actUser'] = '2008745640177348608'; + item['actUserName'] = '李一浩'; + item['actUserDepartment'] = '2008745637258113024'; + item['actUserDepartmentName'] = '测试部'; + final stepId = item['stepId'] ?? ''; + + } + setState(() { }); } @@ -552,6 +567,9 @@ class _HotworkApplyDetailState extends State { 'workType': SpecialWorkTypeEnum.hotWork.code, 'xgfFlag': info['xgfFlag'] ?? '', 'xgfId': info['xgfId'] ?? '', + 'corpinfoId': info['projectExecutionLocationCorpId'] ?? '', + 'projectId': info['projectId'] ?? '', + 'projectName': info['projectName'] ?? '', 'info': info, 'gasFlag': info['gasFlag'] ?? '', 'checkNo': info['checkNo'] ?? '', @@ -559,7 +577,8 @@ class _HotworkApplyDetailState extends State { }; // TODO: 打回删除 checkNo、workId - if (FormUtils.hasValue(data, 'workInfo') && FormUtils.hasValue(data['workInfo'], 'checkNo')) { + if (FormUtils.hasValue(data, 'workInfo') && + FormUtils.hasValue(data['workInfo'], 'checkNo')) { data.remove('checkNo'); data.remove('workId'); } @@ -570,7 +589,10 @@ class _HotworkApplyDetailState extends State { // return; LoadingDialogHelper.show(); if (status == '1') { - final result = await SpecialWorkApi.specialWorkSave(data, SpecialWorkTypeEnum.hotWork); + final result = await SpecialWorkApi.specialWorkSave( + data, + SpecialWorkTypeEnum.hotWork, + ); LoadingDialogHelper.dismiss(); if (result['success'] == true) { ToastUtil.showNormal(context, '保存成功'); @@ -579,7 +601,10 @@ class _HotworkApplyDetailState extends State { ToastUtil.showNormal(context, result['errMessage'] ?? '保存失败'); } } else { - final result = await SpecialWorkApi.specialWorkSaveTemp(data, SpecialWorkTypeEnum.hotWork); + final result = await SpecialWorkApi.specialWorkSaveTemp( + data, + SpecialWorkTypeEnum.hotWork, + ); LoadingDialogHelper.dismiss(); if (result['success'] == true) { ToastUtil.showNormal(context, '已暂存'); @@ -634,7 +659,7 @@ class _HotworkApplyDetailState extends State { LoadingDialogHelper.show(); final data = await CertificateApi.getCertificateUserList({ ...params, - 'corpinfoId': pd['xgfId'], + 'corpinfoId': pd['projectExecutionLocationCorpId'], }); final xgfData = await CertificateApi.getCertificateUserList({ ...params, @@ -694,6 +719,10 @@ class _HotworkApplyDetailState extends State { pd['projectId'] = id; pd['projectName'] = name; pd['xgfId'] = json['corpinfoId']; + pd['projectExecutionLocationCorpId'] = + json['projectExecutionLocationCorpId']; + pd['projectExecutionLocationCorpName'] = + json['projectExecutionLocationCorpName']; }); _getRelatedPartiesUserList(); }, @@ -709,6 +738,10 @@ class _HotworkApplyDetailState extends State { // 获取相关方企业用户列表 Future _getRelatedPartiesUserList() async { + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: pd['projectExecutionLocationCorpId']); + if (personRes['success'] == true) { + _allPersonList = personRes['data']; + } try { final result = await BasicInfoApi.getDeptUsers( '', @@ -872,14 +905,14 @@ class _HotworkApplyDetailState extends State { const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '作业类型:', - isEditable: _isEditable, - onTap: chooseHotworkType, - text: pd['operationTypeName'] ?? '', + isEditable: false, + strongRequired: true, + text: '相关方作业', ), if (pd['xgfFlag'] == 1) ...[ const Divider(), ListItemFactory.createYesNoSection( - horizontalPadding: 5, + horizontalPadding: 3, title: '是否项目内作业', isRequired: true, groupValue: _isInnerWork, @@ -890,7 +923,7 @@ class _HotworkApplyDetailState extends State { }); }, ), - const Divider(), + const Divider(height:1), // 相关方作业 ItemListWidget.selectableLineTitleTextRightButton( diff --git a/lib/pages/home/Tap/special_work/dh_work/hot_delay_page.dart b/lib/pages/home/Tap/special_work/dh_work/hot_delay_page.dart index db2af20..5d055b4 100644 --- a/lib/pages/home/Tap/special_work/dh_work/hot_delay_page.dart +++ b/lib/pages/home/Tap/special_work/dh_work/hot_delay_page.dart @@ -320,7 +320,11 @@ class _HotDelayPageState extends State { setModalState(() {}); // 刷新弹窗内容 }, + data: { + 'corpinfoId' :widget.data['workInfo']['corpinfoId'] ?? '' + }, ), + ); }, ), diff --git a/lib/pages/home/Tap/special_work/dh_work/hot_task_page.dart b/lib/pages/home/Tap/special_work/dh_work/hot_task_page.dart index ade83fb..1e8f4b1 100644 --- a/lib/pages/home/Tap/special_work/dh_work/hot_task_page.dart +++ b/lib/pages/home/Tap/special_work/dh_work/hot_task_page.dart @@ -163,9 +163,10 @@ class _HotTaskPageState extends State { (_initData['settingSignSteps'] is List) ? List.from(_initData['settingSignSteps']) : []; + final corpinfoId = _initData['workInfo']['corpinfoId']; if (steps.isNotEmpty) { LoadingDialogHelper.show(); - final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 1); + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: corpinfoId); LoadingDialogHelper.dismiss(); if (personRes['success'] == true) { @@ -431,6 +432,9 @@ class _HotTaskPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: { + 'corpinfoId' :_initData['workInfo']['corpinfoId'] ?? '' + }, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); diff --git a/lib/pages/home/Tap/special_work/dh_work/work_tab_dh_list.dart b/lib/pages/home/Tap/special_work/dh_work/work_tab_dh_list.dart index cc94be3..5407480 100644 --- a/lib/pages/home/Tap/special_work/dh_work/work_tab_dh_list.dart +++ b/lib/pages/home/Tap/special_work/dh_work/work_tab_dh_list.dart @@ -47,10 +47,33 @@ class _workTabDhListState extends State { _loading = true; }); try { - final res = await SpecialWorkApi.getSpecialWorkStepList(SpecialWorkTypeEnum.hotWork.code); + final res = await SpecialWorkApi.getSpecialWorkStepList( + SpecialWorkTypeEnum.hotWork.code, + ); if (res != null && res['success'] == true) { setState(() { - steps = res['data'] ?? []; + final rawData = res['data'] ?? []; + // 深拷贝并过滤数据,避免直接修改原引用导致的问题,同时移除不符合条件的项 + steps = (rawData as List).map((entry) { + if (entry is Map) { + final List originalSteps = entry['steps'] ?? []; + // 过滤 steps:保留 allowXgfFlag 为 '1' 或存在且有效的项 + final filteredSteps = originalSteps.where((item) { + if (item is Map) { + final flag = item['allowXgfFlag']; + return '${item['allowXgfFlag']}' == '1'; + } + return false; + }).toList(); + + return { + ...entry, + 'steps': filteredSteps, + }; + } + return entry; + }).where((entry) => entry != null).toList(); + _getStepUnreadCount(); }); } else { @@ -75,7 +98,9 @@ class _workTabDhListState extends State { // 获取步骤待办数 Future _getStepUnreadCount() async { - final res = await SpecialWorkApi.specialWorkTaskLogCount(SpecialWorkTypeEnum.hotWork.code); + final res = await SpecialWorkApi.specialWorkTaskLogCount( + SpecialWorkTypeEnum.hotWork.code, + ); LoadingDialogHelper.dismiss(); setState(() { if (res['success'] == true) { @@ -85,16 +110,16 @@ class _workTabDhListState extends State { final count = entry['todoCount']?.toString() ?? '0'; for (var i = 0; i < steps.length; i++) { final group = steps[i] ?? {}; - final stepsData = group['steps'] ?? []; - for (var j = 0; j < stepsData.length; j++) { - final step = stepsData[j] ?? {}; - if (stepId == step['stepId']?.toString()) { - step['unreadCount'] = count; - } + final stepsData = group['steps'] ?? []; + for (var j = 0; j < stepsData.length; j++) { + final step = stepsData[j] ?? {}; + if (stepId == step['stepId']?.toString()) { + step['unreadCount'] = count; } } } } + } }); } @@ -143,7 +168,7 @@ class _workTabDhListState extends State { return buttons; } - void _onGroupItemPressed(int groupIndex, int buttonIndex) async{ + void _onGroupItemPressed(int groupIndex, int buttonIndex) async { if (groupIndex < 0 || groupIndex >= steps.length) return; final group = steps[groupIndex]; final dynamic stepsData = (group is Map) ? group['steps'] : null; @@ -154,7 +179,14 @@ class _workTabDhListState extends State { ? group['groupName'].toString() : ''; final stepId = button['stepId'] ?? ''; - await pushPage(DhWaitPage(stepId: stepId, workTypeTitle: workTypeTitle, listType: SpecialListType.task,), context); + await pushPage( + DhWaitPage( + stepId: stepId, + workTypeTitle: workTypeTitle, + listType: SpecialListType.task, + ), + context, + ); _getData(); } 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 b8175f1..b3d6879 100644 --- a/lib/pages/home/Tap/special_work/dl_work/breakgroundDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/dl_work/breakgroundDetailFormWidget.dart @@ -217,24 +217,9 @@ class _BreakgroundDetailFormWidgetState extends State { }; // 并发请求 - final Future> personFuture = - BasicInfoApi.getDeptUsers('', isMyCorp: 1); - final Future> initDataFuture = widget.isReEdit ? SpecialWorkApi.specialWorkTaskLogDetail(widget.work_id) @@ -120,15 +117,9 @@ class _DlApplyPageState extends State { SpecialWorkTypeEnum.cutRoadWork.code, ); - final results = await Future.wait([personFuture, initDataFuture]); + final results = await Future.wait([initDataFuture]); - final personRes = results[0]; - final initData = results[1]; - - // 人员列表 - if (personRes['success'] == true) { - _allPersonList = personRes['data'] ?? []; - } + final initData = results[0]; printLongString(jsonEncode(initData)); if (initData['success'] == true) { @@ -147,6 +138,8 @@ class _DlApplyPageState extends State { pd = initData['data'] ?? {}; pd['signStepFlag'] = 2; pd['gasFlag'] = 2; + pd['xgfFlag'] = 1; + pd['operationTypeName'] = '相关方作业'; levelList = pd['taskWorkLevels'] ?? []; await safeController.loadFromRaw( pd['preparers'] ?? pd['PREPARERS'] ?? [], @@ -190,21 +183,22 @@ class _DlApplyPageState extends State { if (res['success'] == true) { final List data = res['data'] ?? []; List safeMeasures = - data - .map( - (item) => - SafeMeasureOption.fromJson(Map.from(item)), - ) - .toList(); + data + .map( + (item) => + SafeMeasureOption.fromJson(Map.from(item)), + ) + .toList(); safeController.setAllMeasures(safeMeasures); if (widget.isReEdit) { safeMeasures = data .where((item) => '${item['type']}' == '1') .map( - (item) => - SafeMeasureOption.fromJson(Map.from(item)), - ) + (item) => SafeMeasureOption.fromJson( + Map.from(item), + ), + ) .toList(); await safeController.loadInitialData( safeMeasures.map((item) => item.toJson()).toList(), @@ -233,6 +227,7 @@ class _DlApplyPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: {'corpinfoId' : '${pd['projectExecutionLocationCorpId']}'}, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); @@ -293,7 +288,7 @@ class _DlApplyPageState extends State { await _getPersonListForUnitId(unitId); personList = _personCache[unitId] ?? []; if (personList.isEmpty) { - ToastUtil.showNormal(context, '暂无可选人员,请选择其他单位'); + ToastUtil.showNormal(context, '暂无可选人员,请选择正确的相关方项目'); return; } } @@ -348,6 +343,10 @@ class _DlApplyPageState extends State { pd['projectId'] = id; pd['projectName'] = name; pd['xgfId'] = json['corpinfoId']; + pd['projectExecutionLocationCorpId'] = + json['projectExecutionLocationCorpId']; + pd['projectExecutionLocationCorpName'] = + json['projectExecutionLocationCorpName']; }); _getRelatedPartiesUserList(); }, @@ -363,6 +362,10 @@ class _DlApplyPageState extends State { // 获取相关方企业用户列表 Future _getRelatedPartiesUserList() async { + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: pd['projectExecutionLocationCorpId']); + if (personRes['success'] == true) { + _allPersonList = personRes['data']; + } try { final result = await BasicInfoApi.getDeptUsers( '', @@ -492,6 +495,25 @@ class _DlApplyPageState extends State { }); } } + if (isKF) test(); + }); + } + Future test() async { + for (Map item in _groups) { + item['actUser'] = '2008745640177348608'; + item['actUserName'] = '李一浩'; + item['actUserDepartment'] = '2008745637258113024'; + item['actUserDepartmentName'] = '测试部'; + final stepId = item['stepId'] ?? ''; + if ('$stepId' == '20') { + _allowChoosePersonList[0] = item; + } + if ('$stepId' == '21') { + _allowChoosePersonList[1] = item; + } + + } + setState(() { }); } @@ -634,8 +656,7 @@ class _DlApplyPageState extends State { /// 校验是否有签字需要上传 Future _checkImageUpdata() async { - UploadFileType fileType = - UploadFileType.specialOperationApplyInvolvedPhoto; + UploadFileType fileType = UploadFileType.specialOperationApplyInvolvedPhoto; late bool isSuccess = true; if (_imageList.isNotEmpty) { try { @@ -678,7 +699,6 @@ class _DlApplyPageState extends State { ToastUtil.showNormal(context, err); return; } - } if (_imageList.isNotEmpty) { LoadingDialogHelper.show(); @@ -696,6 +716,9 @@ class _DlApplyPageState extends State { 'workType': SpecialWorkTypeEnum.cutRoadWork.code, 'xgfFlag': info['xgfFlag'] ?? '', 'xgfId': info['xgfId'] ?? '', + 'corpinfoId': info['projectExecutionLocationCorpId'] ?? '', + 'projectId': info['projectId'] ?? '', + 'projectName': info['projectName'] ?? '', 'info': info, 'gasFlag': info['gasFlag'] ?? '', 'checkNo': info['checkNo'] ?? '', @@ -894,12 +917,13 @@ class _DlApplyPageState extends State { onConfirm: (selectedItems) { // 选中的数据列表 setState(() { - pd['linkSpecialWorks'] = - selectedItems.map((item) { - final workName = SpecialWorkTypeEnum.getName(item['workType']); - final checkNo = item['checkNo'] ?? ''; - return {'workTypeName': workName, 'checkNo': checkNo}; - }).toList(); + String w = '${selectedItems.map((item) { + final workName = SpecialWorkTypeEnum.getName(item['workType']); + final checkNo = item['checkNo'] ?? ''; + return '$workName $checkNo'; + }).toList().join(',')},'; + String now = pd['linkSpecialWorks'] ?? ''; + pd['linkSpecialWorks'] = now + w; }); }, ); @@ -914,31 +938,27 @@ class _DlApplyPageState extends State { backgroundColor: Colors.transparent, builder: (_) => MultiDictValuesPicker( - title: '风险辨识结果', - dictType: 'riskGrade', - allowSelectParent: false, - multiSelect: true, - onMultiSelected: ( - List ids, - List names, - List> extraDataList, + title: '风险辨识结果', + dictType: 'riskGrade', + allowSelectParent: false, + multiSelect: true, + onMultiSelected: ( + List ids, + List names, + List> extraDataList, ) { - setState(() { - // addData['hiddenLevel'] = extraData?['dictValue']; - // addData['hiddenLevelName'] = name; - pd['riskResults'] = - extraDataList.map((data) { - final name = data['dictLabel'] ?? ''; - return { - 'riskResultName': name, - 'riskResult': data['dictValue'], - }; - }).toList(); - }); - }, - onSelected: - (String id, String name, Map? extraData) {}, - ), + setState(() { + String w = '${extraDataList.map((data) { + final name = data['dictLabel'] ?? ''; + return name; + }).toList().join(',')},'; + String now = pd['riskResults'] ?? ''; + pd['riskResults'] = now + w; + }); + }, + onSelected: + (String id, String name, Map? extraData) {}, + ), ).then((_) { // 可选:FocusHelper.clearFocus(context); }); @@ -988,14 +1008,14 @@ class _DlApplyPageState extends State { const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '作业类型:', - isEditable: _isEditable, - onTap: chooseHotworkType, - text: pd['operationTypeName'] ?? '', + isEditable: false, + strongRequired: true, + text: '相关方作业', ), if (pd['xgfFlag'] == 1) ...[ const Divider(), ListItemFactory.createYesNoSection( - horizontalPadding: 5, + horizontalPadding: 3, title: '是否项目内作业', isRequired: true, groupValue: _isInnerWork, @@ -1006,7 +1026,7 @@ class _DlApplyPageState extends State { }); }, ), - const Divider(), + const Divider(height:1), // 相关方作业 ItemListWidget.selectableLineTitleTextRightButton( @@ -1072,13 +1092,16 @@ class _DlApplyPageState extends State { title: "断路地段示意图", maxCount: 1, initialMediaPaths: - widget.isReEdit - ? [ - FormUtils.hasValue(pd, 'workScopeAndMethodImage') - ? '${ApiService.baseImgPath}${pd['workScopeAndMethodImage']}' - : '', - ] - : null, + widget.isReEdit + ? [ + FormUtils.hasValue( + pd, + 'workScopeAndMethodImage', + ) + ? '${ApiService.baseImgPath}${pd['workScopeAndMethodImage']}' + : '', + ] + : null, mediaType: MediaType.image, isShowAI: false, isEdit: true, @@ -1147,22 +1170,26 @@ class _DlApplyPageState extends State { label: '关联其他特殊作业及安全作业票编号', isRequired: _isEditable, isEditable: _isEditable, - isInput: false, + isInput: true, onTap: _showChooseOtherWorkTicketDialog, hintText: '请选择关联的其他特殊作业及安全作业票编号', - controller: null, - text: linkShowStr, + text: pd['linkSpecialWorks'] ?? '', + onChanged: (value) { + pd['linkSpecialWorks'] = value; + }, ), const Divider(), ItemListWidget.twoRowButtonTitleText( label: '风险辨识结果', isRequired: _isEditable, isEditable: _isEditable, - isInput: false, + isInput: true, onTap: _showRiskIdentificationResultDialog, hintText: '请选择', - controller: null, - text: riskShowStr, + text: pd['riskResults'] ?? '', + onChanged: (value) { + pd['riskResults'] = value; + }, ), if (widget.isReEdit && FormUtils.hasValue(form, 'id')) ...[ BreakgroundDetailFormWidget(pd: form, isEditable: true), diff --git a/lib/pages/home/Tap/special_work/dl_work/dl_task_page.dart b/lib/pages/home/Tap/special_work/dl_work/dl_task_page.dart index 8e241dc..c0451a4 100644 --- a/lib/pages/home/Tap/special_work/dl_work/dl_task_page.dart +++ b/lib/pages/home/Tap/special_work/dl_work/dl_task_page.dart @@ -160,9 +160,10 @@ class _DlTaskPageState extends State { (_initData['settingSignSteps'] is List) ? List.from(_initData['settingSignSteps']) : []; + final corpinfoId = _initData['workInfo']['corpinfoId']; if (steps.isNotEmpty) { LoadingDialogHelper.show(); - final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 1); + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: corpinfoId); LoadingDialogHelper.dismiss(); if (personRes['success'] == true) { @@ -430,6 +431,9 @@ class _DlTaskPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: { + 'corpinfoId' :_initData['workInfo']['corpinfoId'] ?? '' + }, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); diff --git a/lib/pages/home/Tap/special_work/dl_work/dl_wait_page.dart b/lib/pages/home/Tap/special_work/dl_work/dl_wait_page.dart index 78c1189..71198af 100644 --- a/lib/pages/home/Tap/special_work/dl_work/dl_wait_page.dart +++ b/lib/pages/home/Tap/special_work/dl_work/dl_wait_page.dart @@ -477,7 +477,7 @@ class _DlWaitPageState extends State { }, ), ); - if (status == '1' && lockFlag == '2') { + if (status == '1' && lockFlag == '2' && widget.listType == SpecialListType.list) { buttons.add( CustomButton( text: '撤回', diff --git a/lib/pages/home/Tap/special_work/dl_work/work_tab_dl_list.dart b/lib/pages/home/Tap/special_work/dl_work/work_tab_dl_list.dart index 2690eb0..0d45f5c 100644 --- a/lib/pages/home/Tap/special_work/dl_work/work_tab_dl_list.dart +++ b/lib/pages/home/Tap/special_work/dl_work/work_tab_dl_list.dart @@ -49,7 +49,28 @@ class _WorkTabDlListState extends State { final res = await SpecialWorkApi.getSpecialWorkStepList(SpecialWorkTypeEnum.cutRoadWork.code); if (res != null && res['success'] == true) { setState(() { - steps = res['data'] ?? []; + final rawData = res['data'] ?? []; + // 深拷贝并过滤数据,避免直接修改原引用导致的问题,同时移除不符合条件的项 + steps = (rawData as List).map((entry) { + if (entry is Map) { + final List originalSteps = entry['steps'] ?? []; + // 过滤 steps:保留 allowXgfFlag 为 '1' 或存在且有效的项 + final filteredSteps = originalSteps.where((item) { + if (item is Map) { + final flag = item['allowXgfFlag']; + return '${item['allowXgfFlag']}' == '1'; + } + return false; + }).toList(); + + return { + ...entry, + 'steps': filteredSteps, + }; + } + return entry; + }).where((entry) => entry != null).toList(); + _getStepUnreadCount(); }); } else { 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 d62bd8d..83b3957 100644 --- a/lib/pages/home/Tap/special_work/dt_work/cutRoadDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/dt_work/cutRoadDetailFormWidget.dart @@ -217,24 +217,9 @@ class _CutRoadDetailFormWidgetState extends State { } } - List linkWorks = pd['linkSpecialWorks'] ?? []; - String linkShowStr = linkWorks - .map((item) { - final workName = item['workTypeName']; - final checkNo = item['checkNo'] ?? ''; - return '$workName $checkNo'; - }) - .toList() - .join(','); - List riskResults = pd['riskResults'] ?? []; - String riskShowStr = - riskResults - .map((item) { - final riskResultName = item['riskResultName']; - return riskResultName; - }) - .toList() - .join(); + String linkShowStr = pd['linkSpecialWorks'] ?? ''; + + String riskShowStr = pd['riskResults'] ?? ''; return Container( padding: const EdgeInsets.symmetric(vertical: 0), @@ -277,14 +262,16 @@ class _CutRoadDetailFormWidgetState extends State { if (pd['xgfFlag'] == 1) ...[ const Divider(), ListItemFactory.createYesNoSection( - horizontalPadding: 5, + horizontalPadding: 2, + verticalPadding: 7, title: '是否项目内作业', + isEdit: false, isRequired: true, text: '${pd['internalOperationFlag']}' == '1' ? '是' : '否', groupValue: null, onChanged: (bool value) { }, ), - const Divider(), + const Divider(height: 1), // 相关方作业 ItemListWidget.selectableLineTitleTextRightButton( @@ -350,7 +337,6 @@ class _CutRoadDetailFormWidgetState extends State { isEditable: false, isInput: false, hintText: '请选择关联的其他特殊作业及安全作业票编号', - controller: null, text: linkShowStr, onTap: () { }, ), const Divider(), @@ -361,7 +347,6 @@ class _CutRoadDetailFormWidgetState extends State { isInput: false, onTap: (){}, hintText: '请选择', - controller: null, text: riskShowStr, ), const Divider(), 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 52196a2..930445b 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 @@ -108,9 +108,6 @@ class _DtApplyPageState extends State { }; // 并发请求 - final Future> personFuture = - BasicInfoApi.getDeptUsers('', isMyCorp: 1); - final Future> initDataFuture = widget.isReEdit ? SpecialWorkApi.specialWorkTaskLogDetail(widget.work_id) @@ -118,15 +115,9 @@ class _DtApplyPageState extends State { SpecialWorkTypeEnum.breakgroundWork.code, ); - final results = await Future.wait([personFuture, initDataFuture]); + final results = await Future.wait([initDataFuture]); - final personRes = results[0]; - final initData = results[1]; - - // 人员列表 - if (personRes['success'] == true) { - _allPersonList = personRes['data'] ?? []; - } + final initData = results[0]; printLongString(jsonEncode(initData)); if (initData['success'] == true) { @@ -145,6 +136,8 @@ class _DtApplyPageState extends State { pd = initData['data'] ?? {}; pd['signStepFlag'] = 2; pd['gasFlag'] = 2; + pd['xgfFlag'] = 1; + pd['operationTypeName'] = '相关方作业'; levelList = pd['taskWorkLevels'] ?? []; await safeController.loadFromRaw( pd['preparers'] ?? pd['PREPARERS'] ?? [], @@ -231,6 +224,7 @@ class _DtApplyPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: {'corpinfoId' : '${pd['projectExecutionLocationCorpId']}'}, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); @@ -291,7 +285,7 @@ class _DtApplyPageState extends State { await _getPersonListForUnitId(unitId); personList = _personCache[unitId] ?? []; if (personList.isEmpty) { - ToastUtil.showNormal(context, '暂无可选人员,请选择其他单位'); + ToastUtil.showNormal(context, '暂无可选人员,请选择正确的相关方项目'); return; } } @@ -346,6 +340,8 @@ class _DtApplyPageState extends State { pd['projectId'] = id; pd['projectName'] = name; pd['xgfId'] = json['corpinfoId']; + pd['projectExecutionLocationCorpId'] = json['projectExecutionLocationCorpId']; + pd['projectExecutionLocationCorpName'] = json['projectExecutionLocationCorpName']; }); _getRelatedPartiesUserList(); }, @@ -361,6 +357,10 @@ class _DtApplyPageState extends State { // 获取相关方企业用户列表 Future _getRelatedPartiesUserList() async { + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: pd['projectExecutionLocationCorpId']); + if (personRes['success'] == true) { + _allPersonList = personRes['data']; + } try { final result = await BasicInfoApi.getDeptUsers( '', @@ -490,6 +490,25 @@ class _DtApplyPageState extends State { }); } } + if (isKF) test(); + }); + } + Future test() async { + for (Map item in _groups) { + item['actUser'] = '2008745640177348608'; + item['actUserName'] = '李一浩'; + item['actUserDepartment'] = '2008745637258113024'; + item['actUserDepartmentName'] = '测试部'; + final stepId = item['stepId'] ?? ''; + if ('$stepId' == '20') { + _allowChoosePersonList[0] = item; + } + if ('$stepId' == '21') { + _allowChoosePersonList[1] = item; + } + + } + setState(() { }); } @@ -694,6 +713,9 @@ class _DtApplyPageState extends State { 'workType': SpecialWorkTypeEnum.breakgroundWork.code, 'xgfFlag': info['xgfFlag'] ?? '', 'xgfId': info['xgfId'] ?? '', + 'corpinfoId' : info['projectExecutionLocationCorpId'] ?? '', + 'projectId': info['projectId'] ?? '', + 'projectName': info['projectName'] ?? '', 'info': info, 'gasFlag': info['gasFlag'] ?? '', 'checkNo': info['checkNo'] ?? '', @@ -892,12 +914,13 @@ class _DtApplyPageState extends State { onConfirm: (selectedItems) { // 选中的数据列表 setState(() { - pd['linkSpecialWorks'] = - selectedItems.map((item) { - final workName = SpecialWorkTypeEnum.getName(item['workType']); - final checkNo = item['checkNo'] ?? ''; - return {'workTypeName': workName, 'checkNo': checkNo}; - }).toList(); + String w = '${selectedItems.map((item) { + final workName = SpecialWorkTypeEnum.getName(item['workType']); + final checkNo = item['checkNo'] ?? ''; + return '$workName $checkNo'; + }).toList().join(',')},'; + String now = pd['linkSpecialWorks'] ?? ''; + pd['linkSpecialWorks'] = now + w; }); }, ); @@ -912,31 +935,27 @@ class _DtApplyPageState extends State { backgroundColor: Colors.transparent, builder: (_) => MultiDictValuesPicker( - title: '风险辨识结果', - dictType: 'riskGrade', - allowSelectParent: false, - multiSelect: true, - onMultiSelected: ( - List ids, - List names, - List> extraDataList, + title: '风险辨识结果', + dictType: 'riskGrade', + allowSelectParent: false, + multiSelect: true, + onMultiSelected: ( + List ids, + List names, + List> extraDataList, ) { - setState(() { - // addData['hiddenLevel'] = extraData?['dictValue']; - // addData['hiddenLevelName'] = name; - pd['riskResults'] = - extraDataList.map((data) { - final name = data['dictLabel'] ?? ''; - return { - 'riskResultName': name, - 'riskResult': data['dictValue'], - }; - }).toList(); - }); - }, - onSelected: - (String id, String name, Map? extraData) {}, - ), + setState(() { + String w = '${extraDataList.map((data) { + final name = data['dictLabel'] ?? ''; + return name; + }).toList().join(',')},'; + String now = pd['riskResults'] ?? ''; + pd['riskResults'] = now + w; + }); + }, + onSelected: + (String id, String name, Map? extraData) {}, + ), ).then((_) { // 可选:FocusHelper.clearFocus(context); }); @@ -986,14 +1005,14 @@ class _DtApplyPageState extends State { const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '作业类型:', - isEditable: _isEditable, - onTap: chooseHotworkType, - text: pd['operationTypeName'] ?? '', + isEditable: false, + strongRequired: true, + text: '相关方作业', ), if (pd['xgfFlag'] == 1) ...[ const Divider(), ListItemFactory.createYesNoSection( - horizontalPadding: 5, + horizontalPadding: 3, title: '是否项目内作业', isRequired: true, groupValue: _isInnerWork, @@ -1004,7 +1023,7 @@ class _DtApplyPageState extends State { }); }, ), - const Divider(), + const Divider(height:1), // 相关方作业 ItemListWidget.selectableLineTitleTextRightButton( @@ -1118,22 +1137,26 @@ class _DtApplyPageState extends State { label: '关联其他特殊作业及安全作业票编号', isRequired: _isEditable, isEditable: _isEditable, - isInput: false, + isInput: true, onTap: _showChooseOtherWorkTicketDialog, hintText: '请选择关联的其他特殊作业及安全作业票编号', - controller: null, - text: linkShowStr, + text: pd['linkSpecialWorks'] ?? '', + onChanged: (value) { + pd['linkSpecialWorks'] = value; + }, ), const Divider(), ItemListWidget.twoRowButtonTitleText( label: '风险辨识结果', isRequired: _isEditable, isEditable: _isEditable, - isInput: false, + isInput: true, onTap: _showRiskIdentificationResultDialog, hintText: '请选择', - controller: null, - text: riskShowStr, + text: pd['riskResults'] ?? '', + onChanged: (value) { + pd['riskResults'] = value; + }, ), if (widget.isReEdit && FormUtils.hasValue(form, 'id')) ...[ CutRoadDetailFormWidget(pd: form, isEditable: true), diff --git a/lib/pages/home/Tap/special_work/dt_work/dt_task_page.dart b/lib/pages/home/Tap/special_work/dt_work/dt_task_page.dart index 448b3bc..70bcbae 100644 --- a/lib/pages/home/Tap/special_work/dt_work/dt_task_page.dart +++ b/lib/pages/home/Tap/special_work/dt_work/dt_task_page.dart @@ -159,9 +159,10 @@ class _DtTaskPageState extends State { (_initData['settingSignSteps'] is List) ? List.from(_initData['settingSignSteps']) : []; + final corpinfoId = _initData['workInfo']['corpinfoId']; if (steps.isNotEmpty) { LoadingDialogHelper.show(); - final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 1); + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: corpinfoId); LoadingDialogHelper.dismiss(); if (personRes['success'] == true) { @@ -429,6 +430,9 @@ class _DtTaskPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: { + 'corpinfoId' :_initData['workInfo']['corpinfoId'] ?? '' + }, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); diff --git a/lib/pages/home/Tap/special_work/dt_work/dt_wait_page.dart b/lib/pages/home/Tap/special_work/dt_work/dt_wait_page.dart index 04135db..5087abc 100644 --- a/lib/pages/home/Tap/special_work/dt_work/dt_wait_page.dart +++ b/lib/pages/home/Tap/special_work/dt_work/dt_wait_page.dart @@ -104,6 +104,7 @@ class _DtWaitPageState extends State { }; response = await SpecialWorkApi.specialWorkList(data); } + LoadingDialogHelper.hide(); setState(() { if (currentPage == 1) { @@ -464,7 +465,7 @@ class _DtWaitPageState extends State { }, ), ); - if (status == '1' && lockFlag == '2') { + if (status == '1' && lockFlag == '2' && widget.listType == SpecialListType.list) { buttons.add( CustomButton( text: '撤回', @@ -521,7 +522,6 @@ class _DtWaitPageState extends State { if (ok) { LoadingDialogHelper.show(); final res = await SpecialWorkApi.specialWorkWithdraw(id); - LoadingDialogHelper.hide(); if (res['success']) { ToastUtil.showNormal(context, '操作成功'); _fetchData(); diff --git a/lib/pages/home/Tap/special_work/dt_work/work_tab_dt_list.dart b/lib/pages/home/Tap/special_work/dt_work/work_tab_dt_list.dart index c666abf..448ae50 100644 --- a/lib/pages/home/Tap/special_work/dt_work/work_tab_dt_list.dart +++ b/lib/pages/home/Tap/special_work/dt_work/work_tab_dt_list.dart @@ -49,7 +49,28 @@ class _WorkTabDtListState extends State { final res = await SpecialWorkApi.getSpecialWorkStepList(SpecialWorkTypeEnum.breakgroundWork.code); if (res != null && res['success'] == true) { setState(() { - steps = res['data'] ?? []; + final rawData = res['data'] ?? []; + // 深拷贝并过滤数据,避免直接修改原引用导致的问题,同时移除不符合条件的项 + steps = (rawData as List).map((entry) { + if (entry is Map) { + final List originalSteps = entry['steps'] ?? []; + // 过滤 steps:保留 allowXgfFlag 为 '1' 或存在且有效的项 + final filteredSteps = originalSteps.where((item) { + if (item is Map) { + final flag = item['allowXgfFlag']; + return '${item['allowXgfFlag']}' == '1'; + } + return false; + }).toList(); + + return { + ...entry, + 'steps': filteredSteps, + }; + } + return entry; + }).where((entry) => entry != null).toList(); + _getStepUnreadCount(); }); } else { 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 e29c52a..604362e 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 @@ -112,25 +112,17 @@ class _DzApplyPageState extends State { }; // 并发请求 - final Future> personFuture = - BasicInfoApi.getDeptUsers('', isMyCorp: 1); - final Future> initDataFuture = - widget.isReEdit - ? SpecialWorkApi.specialWorkTaskLogDetail(widget.work_id) - : SpecialWorkApi.specialWorkInit( - SpecialWorkTypeEnum.hoistingWork.code, - ); + widget.isReEdit + ? SpecialWorkApi.specialWorkTaskLogDetail(widget.work_id) + : SpecialWorkApi.specialWorkInit( + SpecialWorkTypeEnum.hoistingWork.code, + ); - final results = await Future.wait([personFuture, initDataFuture]); + final results = await Future.wait([initDataFuture]); - final personRes = results[0]; - final initData = results[1]; + final initData = results[0]; - // 人员列表 - if (personRes['success'] == true) { - _allPersonList = personRes['data'] ?? []; - } printLongString(jsonEncode(initData)); if (initData['success'] == true) { @@ -149,6 +141,10 @@ class _DzApplyPageState extends State { pd = initData['data'] ?? {}; pd['signStepFlag'] = 2; pd['gasFlag'] = 2; + pd['xgfFlag'] = 1; + pd['operationTypeName'] = '相关方作业'; + pd['xgfFlag'] = 1; + pd['operationTypeName'] = '相关方作业'; levelList = pd['taskWorkLevels'] ?? []; await safeController.loadFromRaw( pd['preparers'] ?? pd['PREPARERS'] ?? [], @@ -182,31 +178,32 @@ class _DzApplyPageState extends State { final reqData = {'eqWorkId': form['workId'] ?? ''}; final res = - widget.isReEdit - ? await SpecialWorkApi.specialWorkSignMeasureList(reqData) - : await SpecialWorkApi.specialWorkMeasureList( - SpecialWorkTypeEnum.hoistingWork.code, - ); + widget.isReEdit + ? await SpecialWorkApi.specialWorkSignMeasureList(reqData) + : await SpecialWorkApi.specialWorkMeasureList( + SpecialWorkTypeEnum.hoistingWork.code, + ); // 安全防护措施列表 if (res['success'] == true) { final List data = res['data'] ?? []; List safeMeasures = - data - .map( - (item) => - SafeMeasureOption.fromJson(Map.from(item)), - ) - .toList(); + data + .map( + (item) => + SafeMeasureOption.fromJson(Map.from(item)), + ) + .toList(); safeController.setAllMeasures(safeMeasures); if (widget.isReEdit) { safeMeasures = data .where((item) => '${item['type']}' == '1') .map( - (item) => - SafeMeasureOption.fromJson(Map.from(item)), - ) + (item) => SafeMeasureOption.fromJson( + Map.from(item), + ), + ) .toList(); await safeController.loadInitialData( safeMeasures.map((item) => item.toJson()).toList(), @@ -224,18 +221,19 @@ class _DzApplyPageState extends State { backgroundColor: Colors.transparent, builder: (_) => DepartmentPicker( - onSelected: (id, name, data) async { - setState(() { - _groups[index]['actUserDepartment'] = id; - _groups[index]['actUserDepartmentName'] = name; - // 选单位后清空该组的人员选择 - _groups[index]['actUser'] = ''; - _groups[index]['actUserName'] = ''; - }); - // 拉该单位人员并缓存 - await _getPersonListForUnitId(id); - }, - ), + onSelected: (id, name, data) async { + setState(() { + _groups[index]['actUserDepartment'] = id; + _groups[index]['actUserDepartmentName'] = name; + // 选单位后清空该组的人员选择 + _groups[index]['actUser'] = ''; + _groups[index]['actUserName'] = ''; + }); + // 拉该单位人员并缓存 + await _getPersonListForUnitId(id); + }, + data: {'corpinfoId' : '${pd['projectExecutionLocationCorpId']}'}, + ), ).then((_) { // 可选:FocusHelper.clearFocus(context); }); @@ -295,7 +293,7 @@ class _DzApplyPageState extends State { await _getPersonListForUnitId(unitId); personList = _personCache[unitId] ?? []; if (personList.isEmpty) { - ToastUtil.showNormal(context, '暂无可选人员,请选择其他单位'); + ToastUtil.showNormal(context, '暂无可选人员,请选择正确的相关方项目'); return; } } @@ -344,17 +342,19 @@ class _DzApplyPageState extends State { backgroundColor: Colors.transparent, builder: (ctx) => RelatedPartiesPicker( - listdata: [], - onSelectedJson: (id, name, pdId, json) { - setState(() { - pd['projectId'] = id; - pd['projectName'] = name; - pd['xgfId'] = json['corpinfoId']; - }); - _getRelatedPartiesUserList(); - }, - onSelected: (id, name, pdId) {}, - ), + listdata: [], + onSelectedJson: (id, name, pdId, json) { + setState(() { + pd['projectId'] = id; + pd['projectName'] = name; + pd['xgfId'] = json['corpinfoId']; + pd['projectExecutionLocationCorpId'] = json['projectExecutionLocationCorpId']; + pd['projectExecutionLocationCorpName'] = json['projectExecutionLocationCorpName']; + }); + _getRelatedPartiesUserList(); + }, + onSelected: (id, name, pdId) {}, + ), ); } catch (e) { // 出错时可以 Toast 或者在页面上显示错误状态 @@ -365,6 +365,10 @@ class _DzApplyPageState extends State { // 获取相关方企业用户列表 Future _getRelatedPartiesUserList() async { + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: pd['projectExecutionLocationCorpId']); + if (personRes['success'] == true) { + _allPersonList = personRes['data']; + } try { final result = await BasicInfoApi.getDeptUsers( '', @@ -391,7 +395,7 @@ class _DzApplyPageState extends State { setState(() { // 根据taskName找到对应的item final index = levelList.indexWhere( - (item) => item['taskName'] == choice, + (item) => item['taskName'] == choice, ); final item = levelList[index]; pd['workLevelName'] = item['taskName']; @@ -452,13 +456,13 @@ class _DzApplyPageState extends State { /// 根据 _initData['settingSignSteps'] 构造 _groups 列表 void _initGroupsFromInitData() { final List steps = - (_initData['settingSignSteps'] is List) - ? List.from(_initData['settingSignSteps']) - : []; + (_initData['settingSignSteps'] is List) + ? List.from(_initData['settingSignSteps']) + : []; final List> groups = []; for (var s in steps) { final Map m = - s is Map ? Map.from(s) : {}; + s is Map ? Map.from(s) : {}; groups.add({ ...m, 'actorField': m['actorField']?.toString() ?? '', @@ -494,6 +498,25 @@ class _DzApplyPageState extends State { }); } } + if (isKF) test(); + }); + } + Future test() async { + for (Map item in _groups) { + item['actUser'] = '2008745640177348608'; + item['actUserName'] = '李一浩'; + item['actUserDepartment'] = '2008745637258113024'; + item['actUserDepartmentName'] = '测试部'; + final stepId = item['stepId'] ?? ''; + if ('$stepId' == '20') { + _allowChoosePersonList[0] = item; + } + if ('$stepId' == '21') { + _allowChoosePersonList[1] = item; + } + + } + setState(() { }); } @@ -510,22 +533,22 @@ class _DzApplyPageState extends State { final stepName = item['stepName'] ?? ''; final stepId = item['stepId'] ?? ''; if (stepId == '3') // 安全措施确认不显示 - { + { return SizedBox(height: 0); } /// 如果skipCondition == 'xgf_flag == 1',是根据是否相关方判断是否可跳过 bool is1 = pd['${stepId}_skip'] == 1 || - (skipCondition.isNotEmpty && - skipCondition == 'xgf_flag == 1' && - pd['xgfFlag'] == 1); + (skipCondition.isNotEmpty && + skipCondition == 'xgf_flag == 1' && + pd['xgfFlag'] == 1); /// 如果skipCondition 包含 'gas_flag',是根据是否气体检测判断 bool is2 = skipCondition.isNotEmpty && - skipCondition.contains('gas_flag') && - pd['gasFlag'] == 1; + skipCondition.contains('gas_flag') && + pd['gasFlag'] == 1; return Column( children: [ @@ -547,9 +570,9 @@ class _DzApplyPageState extends State { ToastUtil.showNormal(context, '已清除'); }, text: - (item['actUserDepartmentName'] as String?)?.isNotEmpty == true - ? item['actUserDepartmentName'] - : '请选择', + (item['actUserDepartmentName'] as String?)?.isNotEmpty == true + ? item['actUserDepartmentName'] + : '请选择', onTap: () => chooseUnitHandle(index), ), const Divider(), @@ -571,20 +594,20 @@ class _DzApplyPageState extends State { const Divider(), ], if (stepId == '2' && pd['gasFlag'] > 0) // 气体检测 - ...[ - ListItemFactory.createYesNoSection( - horizontalPadding: 2, - title: '是否气体检测', - isRequired: true, - groupValue: pd['gasFlag'] == 1 || pd['gasFlag'] == '1', - onChanged: (value) { - setState(() { - pd['gasFlag'] = value ? 1 : 2; - }); - }, - ), - const Divider(), - ], + ...[ + ListItemFactory.createYesNoSection( + horizontalPadding: 2, + title: '是否气体检测', + isRequired: true, + groupValue: pd['gasFlag'] == 1 || pd['gasFlag'] == '1', + onChanged: (value) { + setState(() { + pd['gasFlag'] = value ? 1 : 2; + }); + }, + ), + const Divider(), + ], if (is1 || is2) ...[ ItemListWidget.selectableLineTitleTextRightButton( @@ -592,9 +615,9 @@ class _DzApplyPageState extends State { 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), ), @@ -606,9 +629,9 @@ class _DzApplyPageState extends State { 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(), @@ -636,8 +659,7 @@ class _DzApplyPageState extends State { /// 校验是否有签字需要上传 Future _checkImageUpdata() async { - UploadFileType fileType = - UploadFileType.specialOperationApplyInvolvedPhoto; + UploadFileType fileType = UploadFileType.specialOperationApplyInvolvedPhoto; late bool isSuccess = true; if (_imageList.isNotEmpty) { try { @@ -680,7 +702,6 @@ class _DzApplyPageState extends State { ToastUtil.showNormal(context, err); return; } - } if (_imageList.isNotEmpty) { LoadingDialogHelper.show(); @@ -698,6 +719,9 @@ class _DzApplyPageState extends State { 'workType': SpecialWorkTypeEnum.hoistingWork.code, 'xgfFlag': info['xgfFlag'] ?? '', 'xgfId': info['xgfId'] ?? '', + 'corpinfoId' : info['projectExecutionLocationCorpId'] ?? '', + 'projectId': info['projectId'] ?? '', + 'projectName': info['projectName'] ?? '', 'info': info, 'gasFlag': info['gasFlag'] ?? '', 'checkNo': info['checkNo'] ?? '', @@ -742,15 +766,15 @@ class _DzApplyPageState extends State { // 处理签字流程数据 Future> _handleSignLogs( - List> preparers, - ) async { + List> preparers, + ) async { // 处理安全措施确认选择的人替换_groups中安全措施确认节点中的人 List otherMeasuresUsers = []; for (Map item in preparers) { // 取item中updateId不一样的数据组成数组 if (otherMeasuresUsers.indexWhere( (element) => element['updateId'] == item['updateId'], - ) == + ) == -1) { otherMeasuresUsers.add(item); } @@ -760,7 +784,7 @@ class _DzApplyPageState extends State { for (final Map item in _groups) { final bool isStep3 = FormUtils.hasValue(item, 'stepId') && - item['stepId'].toString() == '3'; + item['stepId'].toString() == '3'; if (isStep3) { if (otherMeasuresUsers.isNotEmpty) { for (final Map measure in otherMeasuresUsers) { @@ -799,7 +823,7 @@ class _DzApplyPageState extends State { if (item['actUser'] == null || item['actUser'] == '') { // 特殊处理非必填项 final canSkip = - (item['canSkip'] ?? 0) is int ? (item['canSkip'] ?? 0) : 0; + (item['canSkip'] ?? 0) is int ? (item['canSkip'] ?? 0) : 0; final stepId = item['stepId'] ?? ''; if (canSkip == 1) { @@ -896,12 +920,13 @@ class _DzApplyPageState extends State { onConfirm: (selectedItems) { // 选中的数据列表 setState(() { - pd['linkSpecialWorks'] = - selectedItems.map((item) { - final workName = SpecialWorkTypeEnum.getName(item['workType']); - final checkNo = item['checkNo'] ?? ''; - return {'workTypeName': workName, 'checkNo': checkNo}; - }).toList(); + String w = '${selectedItems.map((item) { + final workName = SpecialWorkTypeEnum.getName(item['workType']); + final checkNo = item['checkNo'] ?? ''; + return '$workName $checkNo'; + }).toList().join(',')},'; + String now = pd['linkSpecialWorks'] ?? ''; + pd['linkSpecialWorks'] = now + w; }); }, ); @@ -926,16 +951,12 @@ class _DzApplyPageState extends State { List> extraDataList, ) { setState(() { - // addData['hiddenLevel'] = extraData?['dictValue']; - // addData['hiddenLevelName'] = name; - pd['riskResults'] = - extraDataList.map((data) { - final name = data['dictLabel'] ?? ''; - return { - 'riskResultName': name, - 'riskResult': data['dictValue'], - }; - }).toList(); + String w = '${extraDataList.map((data) { + final name = data['dictLabel'] ?? ''; + return name; + }).toList().join(',')},'; + String now = pd['riskResults'] ?? ''; + pd['riskResults'] = now + w; }); }, onSelected: @@ -950,21 +971,21 @@ class _DzApplyPageState extends State { List linkWorks = pd['linkSpecialWorks'] ?? []; String linkShowStr = linkWorks .map((item) { - final workName = item['workTypeName']; - final checkNo = item['checkNo'] ?? ''; - return '$workName $checkNo'; - }) + final workName = item['workTypeName']; + final checkNo = item['checkNo'] ?? ''; + return '$workName $checkNo'; + }) .toList() .join(','); List riskResults = pd['riskResults'] ?? []; String riskShowStr = - riskResults - .map((item) { - final riskResultName = item['riskResultName']; - return riskResultName; - }) - .toList() - .join(); + riskResults + .map((item) { + final riskResultName = item['riskResultName']; + return riskResultName; + }) + .toList() + .join(); return Container( padding: const EdgeInsets.symmetric(vertical: 10), decoration: const BoxDecoration( @@ -972,224 +993,229 @@ class _DzApplyPageState extends State { borderRadius: BorderRadius.all(Radius.circular(5)), ), child: - pd.keys.isNotEmpty - ? Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - ItemListWidget.singleLineTitleText( - label: '申请单位:', - isEditable: false, - text: pd['applyUnit'] ?? '', - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '申请人:', - isEditable: false, - text: pd['applyUser'] ?? '', - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '作业类型:', - isEditable: _isEditable, - onTap: chooseHotworkType, - text: pd['operationTypeName'] ?? '', - ), - if (pd['xgfFlag'] == 1) ...[ - const Divider(), - ListItemFactory.createYesNoSection( - horizontalPadding: 5, - title: '是否项目内作业', - isRequired: true, - groupValue: _isInnerWork, - onChanged: (value) { - setState(() { - _isInnerWork = value; - pd['internalOperationFlag'] = value ? 1 : 2; - }); - }, - ), - const Divider(), + pd.keys.isNotEmpty + ? Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ItemListWidget.singleLineTitleText( + label: '申请单位:', + isEditable: false, + text: pd['applyUnit'] ?? '', + ), + const Divider(), + ItemListWidget.singleLineTitleText( + label: '申请人:', + isEditable: false, + text: pd['applyUser'] ?? '', + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '作业类型:', + isEditable: false, + strongRequired: true, + text: '相关方作业', + ), - // 相关方作业 - ItemListWidget.selectableLineTitleTextRightButton( - label: '相关方项目', - isEditable: _isEditable, - text: pd['projectName'] ?? '', - isRequired: true, - onTap: _getRelatedPartiesList, - ), - ], - const Divider(), - ItemListWidget.singleLineTitleText( - label: '吊装地点:', - isEditable: _isEditable, - isTextFont: false, - text: pd['workLocation'] ?? '', - onChanged: (value) { - setState(() { - pd['workLocation'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '吊具名称:', - isEditable: _isEditable, - isTextFont: false, - text: pd['hoistName'] ?? '', - onChanged: (value) { - setState(() { - pd['hoistName'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '吊装作业人:', - isEditable: _isEditable, - isTextFont: false, - text: pd['workUserName'] ?? '', - onChanged: (value) { - setState(() { - pd['workUserName'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '司索人:', - isEditable: _isEditable, - isTextFont: false, - text: pd['pullUserName'] ?? '', - onChanged: (value) { - setState(() { - pd['pullUserName'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '指挥人:', - isEditable: _isEditable, - isTextFont: false, - text: pd['commandUserName'] ?? '', - onChanged: (value) { - setState(() { - pd['commandUserName'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '吊物质量(吨):', - isEditable: _isEditable, - isTextFont: false, - isNumericInput: true, - text: pd['hoistWeight'] ?? '', - onChanged: (value) { - setState(() { - pd['hoistWeight'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '作业级别:', - isEditable: _isEditable, - onTap: chooseLevelHandle, - text: pd['workLevelName'] ?? '', - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '作业开始时间:', - isEditable: _isEditable, - onTap: () async { - DateTime? picked = await BottomDateTimePicker.showDate( - mode: BottomPickerMode.dateTimeWithSeconds, - context, - allowFuture: true, - ); - if (picked != null) { - setState(() { - pd['workStartTime'] = DateFormat( - 'yyyy-MM-dd HH:mm:ss', - ).format(picked); - }); - } - }, - text: pd['workStartTime'] ?? '', - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '作业结束时间:', - isEditable: _isEditable, - onTap: () async { - DateTime? picked = await BottomDateTimePicker.showDate( - mode: BottomPickerMode.dateTimeWithSeconds, - context, - minTimeStr: pd['workEndTime'] ?? '', - allowFuture: true, - ); - if (picked != null) { - setState(() { - pd['workEndTime'] = DateFormat( - 'yyyy-MM-dd HH:mm:ss', - ).format(picked); - }); - } - }, - text: pd['workEndTime'] ?? '', - ), - const Divider(), - _locationWidget(), + if (pd['xgfFlag'] == 1) ...[ + const Divider(), + ListItemFactory.createYesNoSection( + horizontalPadding: 3, + title: '是否项目内作业', + isRequired: true, + groupValue: _isInnerWork, + onChanged: (value) { + setState(() { + _isInnerWork = value; + pd['internalOperationFlag'] = value ? 1 : 2; + }); + }, + ), + const Divider(height:1), - const Divider(), - ItemListWidget.multiLineTitleTextField( - label: '吊物内容:', - isEditable: _isEditable, - text: pd['workContent'] ?? '', - onChanged: (value) { - setState(() { - pd['workContent'] = value; - }); - }, - ), - const Divider(), - ItemListWidget.twoRowButtonTitleText( - label: '关联其他特殊作业及安全作业票编号', - isRequired: _isEditable, - isEditable: _isEditable, - isInput: false, - onTap: _showChooseOtherWorkTicketDialog, - hintText: '请选择关联的其他特殊作业及安全作业票编号', - controller: null, - text: linkShowStr, - ), - const Divider(), - ItemListWidget.twoRowButtonTitleText( - label: '风险辨识结果', - isRequired: _isEditable, - isEditable: _isEditable, - isInput: false, - onTap: _showRiskIdentificationResultDialog, - hintText: '请选择', - controller: null, - text: riskShowStr, - ), - if (widget.isReEdit && FormUtils.hasValue(form, 'id')) ...[ - HoistingDetailFormWidget(pd: form, isEditable: true), - ], - const Divider(), - // 渲染由 settingSignSteps 决定的单位/人员组 - _buildDeptList(), - SafeProtectionModule( - controller: safeController, - personList: _allowChoosePersonList, - isEditable: _isEditable, - ), - ], - ) - : SizedBox(), + // 相关方作业 + ItemListWidget.selectableLineTitleTextRightButton( + label: '相关方项目', + isEditable: _isEditable, + text: pd['projectName'] ?? '', + isRequired: true, + onTap: _getRelatedPartiesList, + ), + ], + const Divider(), + ItemListWidget.singleLineTitleText( + label: '吊装地点:', + isEditable: _isEditable, + isTextFont: false, + text: pd['workLocation'] ?? '', + onChanged: (value) { + setState(() { + pd['workLocation'] = value; + }); + }, + ), + const Divider(), + ItemListWidget.singleLineTitleText( + label: '吊具名称:', + isEditable: _isEditable, + isTextFont: false, + text: pd['hoistName'] ?? '', + onChanged: (value) { + setState(() { + pd['hoistName'] = value; + }); + }, + ), + const Divider(), + ItemListWidget.singleLineTitleText( + label: '吊装作业人:', + isEditable: _isEditable, + isTextFont: false, + text: pd['workUserName'] ?? '', + onChanged: (value) { + setState(() { + pd['workUserName'] = value; + }); + }, + ), + const Divider(), + ItemListWidget.singleLineTitleText( + label: '司索人:', + isEditable: _isEditable, + isTextFont: false, + text: pd['pullUserName'] ?? '', + onChanged: (value) { + setState(() { + pd['pullUserName'] = value; + }); + }, + ), + const Divider(), + ItemListWidget.singleLineTitleText( + label: '指挥人:', + isEditable: _isEditable, + isTextFont: false, + text: pd['commandUserName'] ?? '', + onChanged: (value) { + setState(() { + pd['commandUserName'] = value; + }); + }, + ), + const Divider(), + ItemListWidget.singleLineTitleText( + label: '吊物质量(吨):', + isEditable: _isEditable, + isTextFont: false, + isNumericInput: true, + text: pd['hoistWeight'] ?? '', + onChanged: (value) { + setState(() { + pd['hoistWeight'] = value; + }); + }, + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '作业级别:', + isEditable: _isEditable, + onTap: chooseLevelHandle, + text: pd['workLevelName'] ?? '', + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '作业开始时间:', + isEditable: _isEditable, + onTap: () async { + DateTime? picked = await BottomDateTimePicker.showDate( + mode: BottomPickerMode.dateTimeWithSeconds, + context, + allowFuture: true, + ); + if (picked != null) { + setState(() { + pd['workStartTime'] = DateFormat( + 'yyyy-MM-dd HH:mm:ss', + ).format(picked); + }); + } + }, + text: pd['workStartTime'] ?? '', + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '作业结束时间:', + isEditable: _isEditable, + onTap: () async { + DateTime? picked = await BottomDateTimePicker.showDate( + mode: BottomPickerMode.dateTimeWithSeconds, + context, + minTimeStr: pd['workEndTime'] ?? '', + allowFuture: true, + ); + if (picked != null) { + setState(() { + pd['workEndTime'] = DateFormat( + 'yyyy-MM-dd HH:mm:ss', + ).format(picked); + }); + } + }, + text: pd['workEndTime'] ?? '', + ), + const Divider(), + _locationWidget(), + + const Divider(), + ItemListWidget.multiLineTitleTextField( + label: '吊物内容:', + isEditable: _isEditable, + text: pd['workContent'] ?? '', + onChanged: (value) { + setState(() { + pd['workContent'] = value; + }); + }, + ), + const Divider(), + ItemListWidget.twoRowButtonTitleText( + label: '关联其他特殊作业及安全作业票编号', + isRequired: _isEditable, + isEditable: _isEditable, + isInput: true, + onTap: _showChooseOtherWorkTicketDialog, + hintText: '请选择关联的其他特殊作业及安全作业票编号', + text: pd['linkSpecialWorks'] ?? '', + onChanged: (value) { + pd['linkSpecialWorks'] = value; + }, + ), + const Divider(), + ItemListWidget.twoRowButtonTitleText( + label: '风险辨识结果', + isRequired: _isEditable, + isEditable: _isEditable, + isInput: true, + onTap: _showRiskIdentificationResultDialog, + hintText: '请选择', + text: pd['riskResults'] ?? '', + onChanged: (value) { + pd['riskResults'] = value; + }, + ), + if (widget.isReEdit && FormUtils.hasValue(form, 'id')) ...[ + HoistingDetailFormWidget(pd: form, isEditable: true), + ], + const Divider(), + // 渲染由 settingSignSteps 决定的单位/人员组 + _buildDeptList(), + SafeProtectionModule( + controller: safeController, + personList: _allowChoosePersonList, + isEditable: _isEditable, + ), + ], + ) + : SizedBox(), ); } @@ -1207,65 +1233,65 @@ class _DzApplyPageState extends State { const SizedBox(height: 20), _isEditable ? _loadingInit - ? Row( - spacing: 10, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: CustomButton( - textStyle: TextStyle( - fontSize: 16, - color: Colors.white, - ), - text: '暂存', - buttonStyle: ButtonStyleType.secondary, - onPressed: () { - _submit('0'); - }, - ), - ), - Expanded( - child: CustomButton( - height: 45, - textStyle: TextStyle( - fontSize: 16, - color: Colors.white, - ), - text: '提交', - backgroundColor: Colors.blue, - onPressed: () { - _submit('1'); - }, - ), - ), - ], - ) - : SizedBox() - : Column( - children: [ - SizedBox(height: 20), - Row( - children: [ - SizedBox(width: 50), - Expanded( - child: CustomButton( - height: 45, - textStyle: TextStyle( - fontSize: 16, - color: Colors.white, + ? Row( + spacing: 10, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: CustomButton( + textStyle: TextStyle( + fontSize: 16, + color: Colors.white, + ), + text: '暂存', + buttonStyle: ButtonStyleType.secondary, + onPressed: () { + _submit('0'); + }, + ), ), - text: '返回', - backgroundColor: Colors.green, - onPressed: () { - Navigator.pop(context); - }, - ), + Expanded( + child: CustomButton( + height: 45, + textStyle: TextStyle( + fontSize: 16, + color: Colors.white, + ), + text: '提交', + backgroundColor: Colors.blue, + onPressed: () { + _submit('1'); + }, + ), + ), + ], + ) + : SizedBox() + : Column( + children: [ + SizedBox(height: 20), + Row( + children: [ + SizedBox(width: 50), + Expanded( + child: CustomButton( + height: 45, + textStyle: TextStyle( + fontSize: 16, + color: Colors.white, + ), + text: '返回', + backgroundColor: Colors.green, + onPressed: () { + Navigator.pop(context); + }, + ), + ), + SizedBox(width: 50), + ], ), - SizedBox(width: 50), ], ), - ], - ), ], ), ), diff --git a/lib/pages/home/Tap/special_work/dz_work/dz_task_page.dart b/lib/pages/home/Tap/special_work/dz_work/dz_task_page.dart index 10892bb..e9178f5 100644 --- a/lib/pages/home/Tap/special_work/dz_work/dz_task_page.dart +++ b/lib/pages/home/Tap/special_work/dz_work/dz_task_page.dart @@ -164,9 +164,10 @@ class _DzTaskPageState extends State { (_initData['settingSignSteps'] is List) ? List.from(_initData['settingSignSteps']) : []; + final corpinfoId = _initData['workInfo']['corpinfoId']; if (steps.isNotEmpty) { LoadingDialogHelper.show(); - final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 1); + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: corpinfoId); LoadingDialogHelper.dismiss(); if (personRes['success'] == true) { @@ -434,6 +435,9 @@ class _DzTaskPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: { + 'corpinfoId' :_initData['workInfo']['corpinfoId'] ?? '' + }, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); diff --git a/lib/pages/home/Tap/special_work/dz_work/dz_wait_page.dart b/lib/pages/home/Tap/special_work/dz_work/dz_wait_page.dart index 8ba5804..cee3a34 100644 --- a/lib/pages/home/Tap/special_work/dz_work/dz_wait_page.dart +++ b/lib/pages/home/Tap/special_work/dz_work/dz_wait_page.dart @@ -464,7 +464,7 @@ class _DzWaitPageState extends State { }, ), ); - if (status == '1' && lockFlag == '2') { + if (status == '1' && lockFlag == '2' && widget.listType == SpecialListType.list) { buttons.add( CustomButton( text: '撤回', 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 59addac..29ba212 100644 --- a/lib/pages/home/Tap/special_work/dz_work/hoistingDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/dz_work/hoistingDetailFormWidget.dart @@ -217,24 +217,9 @@ class _HoistingDetailFormWidgetState extends State { } } - List linkWorks = pd['linkSpecialWorks'] ?? []; - String linkShowStr = linkWorks - .map((item) { - final workName = item['workTypeName']; - final checkNo = item['checkNo'] ?? ''; - return '$workName $checkNo'; - }) - .toList() - .join(','); - List riskResults = pd['riskResults'] ?? []; - String riskShowStr = - riskResults - .map((item) { - final riskResultName = item['riskResultName']; - return riskResultName; - }) - .toList() - .join(); + String linkShowStr = pd['linkSpecialWorks'] ?? ''; + + String riskShowStr = pd['riskResults'] ?? ''; return Container( padding: const EdgeInsets.symmetric(vertical: 0), @@ -277,14 +262,16 @@ class _HoistingDetailFormWidgetState extends State { if (pd['xgfFlag'] == 1) ...[ const Divider(), ListItemFactory.createYesNoSection( - horizontalPadding: 5, + horizontalPadding: 2, + verticalPadding: 7, title: '是否项目内作业', + isEdit: false, isRequired: true, text: '${pd['internalOperationFlag']}' == '1' ? '是' : '否', groupValue: null, onChanged: (bool value) { }, ), - const Divider(), + const Divider(height: 1), // 相关方作业 ItemListWidget.selectableLineTitleTextRightButton( @@ -386,7 +373,6 @@ class _HoistingDetailFormWidgetState extends State { isEditable: false, isInput: false, hintText: '请选择关联的其他特殊作业及安全作业票编号', - controller: null, text: linkShowStr, onTap: () { }, ), const Divider(), @@ -397,7 +383,6 @@ class _HoistingDetailFormWidgetState extends State { isInput: false, onTap: (){}, hintText: '请选择', - controller: null, text: riskShowStr, ), ], diff --git a/lib/pages/home/Tap/special_work/dz_work/work_tab_dz_list.dart b/lib/pages/home/Tap/special_work/dz_work/work_tab_dz_list.dart index a6e17ac..625a60d 100644 --- a/lib/pages/home/Tap/special_work/dz_work/work_tab_dz_list.dart +++ b/lib/pages/home/Tap/special_work/dz_work/work_tab_dz_list.dart @@ -49,7 +49,28 @@ class _WorkTabDzListState extends State { final res = await SpecialWorkApi.getSpecialWorkStepList(SpecialWorkTypeEnum.hoistingWork.code); if (res != null && res['success'] == true) { setState(() { - steps = res['data'] ?? []; + final rawData = res['data'] ?? []; + // 深拷贝并过滤数据,避免直接修改原引用导致的问题,同时移除不符合条件的项 + steps = (rawData as List).map((entry) { + if (entry is Map) { + final List originalSteps = entry['steps'] ?? []; + // 过滤 steps:保留 allowXgfFlag 为 '1' 或存在且有效的项 + final filteredSteps = originalSteps.where((item) { + if (item is Map) { + final flag = item['allowXgfFlag']; + return '${item['allowXgfFlag']}' == '1'; + } + return false; + }).toList(); + + return { + ...entry, + 'steps': filteredSteps, + }; + } + return entry; + }).where((entry) => entry != null).toList(); + _getStepUnreadCount(); }); } else { 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 06b4f7a..3a5cf5c 100644 --- a/lib/pages/home/Tap/special_work/gc_work/HeighWorkDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/gc_work/HeighWorkDetailFormWidget.dart @@ -214,24 +214,9 @@ class _HeighWorkDetailFormWidgetState extends State { } } - List linkWorks = pd['linkSpecialWorks'] ?? []; - String linkShowStr = linkWorks - .map((item) { - final workName = item['workTypeName']; - final checkNo = item['checkNo'] ?? ''; - return '$workName $checkNo'; - }) - .toList() - .join(','); - List riskResults = pd['riskResults'] ?? []; - String riskShowStr = - riskResults - .map((item) { - final riskResultName = item['riskResultName']; - return riskResultName; - }) - .toList() - .join(); + String linkShowStr = pd['linkSpecialWorks'] ?? ''; + + String riskShowStr = pd['riskResults'] ?? ''; return Container( padding: const EdgeInsets.symmetric(vertical: 0), @@ -273,14 +258,16 @@ class _HeighWorkDetailFormWidgetState extends State { if (pd['xgfFlag'] == 1) ...[ const Divider(), ListItemFactory.createYesNoSection( - horizontalPadding: 5, + horizontalPadding: 2, + verticalPadding: 7, title: '是否项目内作业', + isEdit: false, isRequired: true, text: '${pd['internalOperationFlag']}' == '1' ? '是' : '否', groupValue: null, onChanged: (bool value) { }, ), - const Divider(), + const Divider(height: 1), // 相关方作业 ItemListWidget.selectableLineTitleTextRightButton( @@ -343,7 +330,6 @@ class _HeighWorkDetailFormWidgetState extends State { isEditable: false, isInput: false, hintText: '', - controller: null, text: linkShowStr, onTap: () { }, ), const Divider(), @@ -353,7 +339,6 @@ class _HeighWorkDetailFormWidgetState extends State { isEditable: false, isInput: false, hintText: '', - controller: null, text: riskShowStr, onTap: () {}, ), ItemListWidget.selectableLineTitleTextRightButton( 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 c8bc3de..969e24b 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 @@ -58,7 +58,7 @@ class _GcApplyPageState extends State { "workHeight": "请输入作业高度", "workLevel": "请选择作业级别", "workContent": "请输入作业内容", - "longitude" : "请定位位置", + "longitude": "请定位位置", "linkSpecialWorks": "请选择关联其他特殊作业及安全作业票编号", "riskResults": "请选择风险辨识结果", "workStartTime": "请选择作业实施开始时间", @@ -96,16 +96,6 @@ class _GcApplyPageState extends State { LoadingDialogHelper.show(); try { - final data = { - "eqWorkType": SpecialWorkTypeEnum.highWork.code, - "pageSize": 999, - "pageIndex": 1, - }; - - // 并发请求 - final Future> personFuture = - BasicInfoApi.getDeptUsers('', isMyCorp: 1); - final Future> initDataFuture = widget.isReEdit ? SpecialWorkApi.specialWorkTaskLogDetail(widget.work_id) @@ -113,15 +103,9 @@ class _GcApplyPageState extends State { SpecialWorkTypeEnum.highWork.code, ); - final results = await Future.wait([personFuture, initDataFuture]); + final results = await Future.wait([initDataFuture]); - final personRes = results[0]; - final initData = results[1]; - - // 人员列表 - if (personRes['success'] == true) { - _allPersonList = personRes['data'] ?? []; - } + final initData = results[0]; printLongString(jsonEncode(initData)); if (initData['success'] == true) { @@ -129,7 +113,6 @@ class _GcApplyPageState extends State { setState(() { form = initData['data'] ?? {}; pd = form['workInfo']['info'] ?? {}; - }); if (FormUtils.hasValue(pd, 'workLevel')) { await getFlowInit(); @@ -138,6 +121,8 @@ class _GcApplyPageState extends State { pd = initData['data'] ?? {}; pd['signStepFlag'] = 2; pd['gasFlag'] = 2; + pd['xgfFlag'] = 1; + pd['operationTypeName'] = '相关方作业'; levelList = pd['taskWorkLevels'] ?? []; await safeController.loadFromRaw( pd['preparers'] ?? pd['PREPARERS'] ?? [], @@ -181,21 +166,22 @@ class _GcApplyPageState extends State { if (res['success'] == true) { final List data = res['data'] ?? []; List safeMeasures = - data - .map( - (item) => - SafeMeasureOption.fromJson(Map.from(item)), - ) - .toList(); + data + .map( + (item) => + SafeMeasureOption.fromJson(Map.from(item)), + ) + .toList(); safeController.setAllMeasures(safeMeasures); if (widget.isReEdit) { safeMeasures = data .where((item) => '${item['type']}' == '1') .map( - (item) => - SafeMeasureOption.fromJson(Map.from(item)), - ) + (item) => SafeMeasureOption.fromJson( + Map.from(item), + ), + ) .toList(); await safeController.loadInitialData( safeMeasures.map((item) => item.toJson()).toList(), @@ -224,6 +210,7 @@ class _GcApplyPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: {'corpinfoId': '${pd['projectExecutionLocationCorpId']}'}, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); @@ -284,7 +271,7 @@ class _GcApplyPageState extends State { await _getPersonListForUnitId(unitId); personList = _personCache[unitId] ?? []; if (personList.isEmpty) { - ToastUtil.showNormal(context, '暂无可选人员,请选择其他单位'); + ToastUtil.showNormal(context, '暂无可选人员,请选择正确的相关方项目'); return; } } @@ -297,7 +284,8 @@ class _GcApplyPageState extends State { // 气体分析 personList = _allowChoosePersonList; } - + // 开发按钮控制 一键选人 + bool isKFoneClick = true; // 显示人员选择器(假设 DepartmentPersonPicker.show 接口存在) DepartmentAllPersonPicker.show( context, @@ -339,6 +327,10 @@ class _GcApplyPageState extends State { pd['projectId'] = id; pd['projectName'] = name; pd['xgfId'] = json['corpinfoId']; + pd['projectExecutionLocationCorpId'] = + json['projectExecutionLocationCorpId']; + pd['projectExecutionLocationCorpName'] = + json['projectExecutionLocationCorpName']; }); _getRelatedPartiesUserList(); }, @@ -354,6 +346,14 @@ class _GcApplyPageState extends State { // 获取相关方企业用户列表 Future _getRelatedPartiesUserList() async { + final personRes = await BasicInfoApi.getDeptUsers( + '', + isMyCorp: 0, + corpinfoId: pd['projectExecutionLocationCorpId'], + ); + if (personRes['success'] == true) { + _allPersonList = personRes['data']; + } try { final result = await BasicInfoApi.getDeptUsers( '', @@ -483,9 +483,27 @@ class _GcApplyPageState extends State { }); } } + if (isKF) test(); }); } + Future test() async { + for (Map item in _groups) { + item['actUser'] = '2008745640177348608'; + item['actUserName'] = '李一浩'; + item['actUserDepartment'] = '2008745637258113024'; + item['actUserDepartmentName'] = '测试部'; + final stepId = item['stepId'] ?? ''; + if ('$stepId' == '20') { + _allowChoosePersonList[0] = item; + } + if ('$stepId' == '21') { + _allowChoosePersonList[1] = item; + } + } + setState(() {}); + } + /// 渲染单个组行(index) Widget _chooseItem(int index) { final Map item = _groups[index]; @@ -649,28 +667,34 @@ class _GcApplyPageState extends State { } } - final data = { 'workLevel': info['workLevel'] ?? '', 'workType': SpecialWorkTypeEnum.highWork.code, 'xgfFlag': info['xgfFlag'] ?? '', 'xgfId': info['xgfId'] ?? '', + 'corpinfoId': info['projectExecutionLocationCorpId'] ?? '', + 'projectId': info['projectId'] ?? '', + 'projectName': info['projectName'] ?? '', 'info': info, 'gasFlag': info['gasFlag'] ?? '', 'checkNo': info['checkNo'] ?? '', 'signLogs': newGroups, - 'others' : others + 'others': others, }; printLongString(jsonEncode(info)); // TODO: 打回删除 checkNo、workId - if (FormUtils.hasValue(data, 'workInfo') && FormUtils.hasValue(data['workInfo'], 'checkNo')) { + if (FormUtils.hasValue(data, 'workInfo') && + FormUtils.hasValue(data['workInfo'], 'checkNo')) { data.remove('checkNo'); data.remove('workId'); } // return; LoadingDialogHelper.show(); if (status == '1') { - final result = await SpecialWorkApi.specialWorkSave(data, SpecialWorkTypeEnum.highWork); + final result = await SpecialWorkApi.specialWorkSave( + data, + SpecialWorkTypeEnum.highWork, + ); LoadingDialogHelper.dismiss(); if (result['success'] == true) { ToastUtil.showNormal(context, '保存成功'); @@ -679,7 +703,10 @@ class _GcApplyPageState extends State { ToastUtil.showNormal(context, result['errMessage'] ?? '保存失败'); } } else { - final result = await SpecialWorkApi.specialWorkSaveTemp(data, SpecialWorkTypeEnum.highWork); + final result = await SpecialWorkApi.specialWorkSaveTemp( + data, + SpecialWorkTypeEnum.highWork, + ); LoadingDialogHelper.dismiss(); if (result['success'] == true) { ToastUtil.showNormal(context, '已暂存'); @@ -846,12 +873,13 @@ class _GcApplyPageState extends State { onConfirm: (selectedItems) { // 选中的数据列表 setState(() { - pd['linkSpecialWorks'] = - selectedItems.map((item) { - final workName = SpecialWorkTypeEnum.getName(item['workType']); - final checkNo = item['checkNo'] ?? ''; - return {'workTypeName': workName, 'checkNo': checkNo}; - }).toList(); + String w = '${selectedItems.map((item) { + final workName = SpecialWorkTypeEnum.getName(item['workType']); + final checkNo = item['checkNo'] ?? ''; + return '$workName $checkNo'; + }).toList().join(',')},'; + String now = pd['linkSpecialWorks'] ?? ''; + pd['linkSpecialWorks'] = now + w; }); }, ); @@ -876,16 +904,12 @@ class _GcApplyPageState extends State { List> extraDataList, ) { setState(() { - // addData['hiddenLevel'] = extraData?['dictValue']; - // addData['hiddenLevelName'] = name; - pd['riskResults'] = - extraDataList.map((data) { - final name = data['dictLabel'] ?? ''; - return { - 'riskResultName': name, - 'riskResult': data['dictValue'], - }; - }).toList(); + String w = '${extraDataList.map((data) { + final name = data['dictLabel'] ?? ''; + return name; + }).toList().join(',')},'; + String now = pd['riskResults'] ?? ''; + pd['riskResults'] = now + w; }); }, onSelected: @@ -897,24 +921,7 @@ class _GcApplyPageState extends State { } Widget _buildDetail() { - List linkWorks = pd['linkSpecialWorks'] ?? []; - String linkShowStr = linkWorks - .map((item) { - final workName = item['workTypeName']; - final checkNo = item['checkNo'] ?? ''; - return '$workName $checkNo'; - }) - .toList() - .join(','); - List riskResults = pd['riskResults'] ?? []; - String riskShowStr = - riskResults - .map((item) { - final riskResultName = item['riskResultName']; - return riskResultName; - }) - .toList() - .join(); + return Container( padding: const EdgeInsets.symmetric(vertical: 10), decoration: const BoxDecoration( @@ -961,14 +968,14 @@ class _GcApplyPageState extends State { // const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '作业类型:', - isEditable: _isEditable, - onTap: chooseHotworkType, - text: pd['operationTypeName'] ?? '', + isEditable: false, + strongRequired: true, + text: '相关方作业', ), if (pd['xgfFlag'] == 1) ...[ const Divider(), ListItemFactory.createYesNoSection( - horizontalPadding: 5, + horizontalPadding: 3, title: '是否项目内作业', isRequired: true, groupValue: _isInnerWork, @@ -979,7 +986,7 @@ class _GcApplyPageState extends State { }); }, ), - const Divider(), + const Divider(height: 1), // 相关方作业 ItemListWidget.selectableLineTitleTextRightButton( @@ -1051,22 +1058,26 @@ class _GcApplyPageState extends State { label: '关联其他特殊作业及安全作业票编号', isRequired: _isEditable, isEditable: _isEditable, - isInput: false, + isInput: true, onTap: _showChooseOtherWorkTicketDialog, hintText: '请选择关联的其他特殊作业及安全作业票编号', - controller: null, - text: linkShowStr, + text: pd['linkSpecialWorks'] ?? '', + onChanged: (value) { + pd['linkSpecialWorks'] = value; + }, ), const Divider(), ItemListWidget.twoRowButtonTitleText( label: '风险辨识结果', isRequired: _isEditable, isEditable: _isEditable, - isInput: false, + isInput: true, onTap: _showRiskIdentificationResultDialog, hintText: '请选择', - controller: null, - text: riskShowStr, + text: pd['riskResults'] ?? '', + onChanged: (value) { + pd['riskResults'] = value; + }, ), if (widget.isReEdit && FormUtils.hasValue(form, 'id')) ...[ HeighWorkDetailFormWidget(pd: form, isEditable: true), diff --git a/lib/pages/home/Tap/special_work/gc_work/gc_task_page.dart b/lib/pages/home/Tap/special_work/gc_work/gc_task_page.dart index 5918693..3690810 100644 --- a/lib/pages/home/Tap/special_work/gc_work/gc_task_page.dart +++ b/lib/pages/home/Tap/special_work/gc_work/gc_task_page.dart @@ -164,9 +164,10 @@ class _GcTaskPageState extends State { (_initData['settingSignSteps'] is List) ? List.from(_initData['settingSignSteps']) : []; + final corpinfoId = _initData['workInfo']['corpinfoId']; if (steps.isNotEmpty) { LoadingDialogHelper.show(); - final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 1); + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: corpinfoId); LoadingDialogHelper.dismiss(); if (personRes['success'] == true) { @@ -434,6 +435,9 @@ class _GcTaskPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: { + 'corpinfoId' :_initData['workInfo']['corpinfoId'] ?? '' + }, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); diff --git a/lib/pages/home/Tap/special_work/gc_work/gc_wait_page.dart b/lib/pages/home/Tap/special_work/gc_work/gc_wait_page.dart index a02d146..8523218 100644 --- a/lib/pages/home/Tap/special_work/gc_work/gc_wait_page.dart +++ b/lib/pages/home/Tap/special_work/gc_work/gc_wait_page.dart @@ -467,7 +467,7 @@ class _GcWaitPageState extends State { }, ), ); - if (status == '1' && lockFlag == '2') { + if (status == '1' && lockFlag == '2' && widget.listType == SpecialListType.list) { buttons.add( CustomButton( text: '撤回', diff --git a/lib/pages/home/Tap/special_work/gc_work/work_tab_gc_list.dart b/lib/pages/home/Tap/special_work/gc_work/work_tab_gc_list.dart index 07f514e..80211cd 100644 --- a/lib/pages/home/Tap/special_work/gc_work/work_tab_gc_list.dart +++ b/lib/pages/home/Tap/special_work/gc_work/work_tab_gc_list.dart @@ -49,7 +49,28 @@ class _WorkTabGcListState extends State { final res = await SpecialWorkApi.getSpecialWorkStepList(SpecialWorkTypeEnum.highWork.code); if (res != null && res['success'] == true) { setState(() { - steps = res['data'] ?? []; + final rawData = res['data'] ?? []; + // 深拷贝并过滤数据,避免直接修改原引用导致的问题,同时移除不符合条件的项 + steps = (rawData as List).map((entry) { + if (entry is Map) { + final List originalSteps = entry['steps'] ?? []; + // 过滤 steps:保留 allowXgfFlag 为 '1' 或存在且有效的项 + final filteredSteps = originalSteps.where((item) { + if (item is Map) { + final flag = item['allowXgfFlag']; + return '${item['allowXgfFlag']}' == '1'; + } + return false; + }).toList(); + + return { + ...entry, + 'steps': filteredSteps, + }; + } + return entry; + }).where((entry) => entry != null).toList(); + _getStepUnreadCount(); }); } else { 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 9ecd7c1..d821c3b 100644 --- a/lib/pages/home/Tap/special_work/lsyd_work/LsydWorkDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/lsyd_work/LsydWorkDetailFormWidget.dart @@ -218,24 +218,9 @@ class _LsydWorkDetailFormWidgetState extends State { } Map chooseLimitedSpace = pd['chooseLimitedSpace'] ?? {}; - List linkWorks = pd['linkSpecialWorks'] ?? []; - String linkShowStr = linkWorks - .map((item) { - final workName = item['workTypeName']; - final checkNo = item['checkNo'] ?? ''; - return '$workName $checkNo'; - }) - .toList() - .join(','); - List riskResults = pd['riskResults'] ?? []; - String riskShowStr = - riskResults - .map((item) { - final riskResultName = item['riskResultName']; - return riskResultName; - }) - .toList() - .join(); + String linkShowStr = pd['linkSpecialWorks'] ?? ''; + + String riskShowStr = pd['riskResults'] ?? ''; return Container( @@ -277,14 +262,16 @@ class _LsydWorkDetailFormWidgetState extends State { if (pd['xgfFlag'] == 1) ...[ const Divider(), ListItemFactory.createYesNoSection( - horizontalPadding: 5, + horizontalPadding: 2, + verticalPadding: 7, title: '是否项目内作业', + isEdit: false, isRequired: true, text: '${pd['internalOperationFlag']}' == '1' ? '是' : '否', groupValue: null, onChanged: (bool value) { }, ), - const Divider(), + const Divider(height: 1), // 相关方作业 ItemListWidget.selectableLineTitleTextRightButton( @@ -359,7 +346,6 @@ class _LsydWorkDetailFormWidgetState extends State { isEditable: false, isInput: false, hintText: '请选择关联的其他特殊作业及安全作业票编号', - controller: null, text: linkShowStr, onTap: () { }, ), const Divider(), @@ -370,7 +356,6 @@ class _LsydWorkDetailFormWidgetState extends State { isInput: false, onTap: (){}, hintText: '请选择', - controller: null, text: riskShowStr, ), const Divider(), 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 4a407f2..ed3642e 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 @@ -61,7 +61,6 @@ class _LsydApplyPageState extends State { Map pd = {}; Map form = {}; - Map _initData = {}; /// 每一组:stepId,actorField、actUserDepartment、actUserDepartmentName、actUser、actUserName @@ -86,14 +85,14 @@ class _LsydApplyPageState extends State { bool _loadingInit = false; -// 初始化必填规则 + // 初始化必填规则 final Map _requiredRules = { "operationTypeName": "请选择作业类型", - "workLocation" : "请输入作业地点", + "workLocation": "请输入作业地点", "workContent": "请输入作业内容", "workUserName": "请输入作业人", - "electricNumber" : "请输入电工证号", - "workLevelName" : "请选择作业级别", + "electricNumber": "请输入电工证号", + "workLevelName": "请选择作业级别", "workStartTime": "请选择作业开始时间", "workEndTime": "请选择作业结束时间", "longitude": "请定位位置", @@ -105,7 +104,6 @@ class _LsydApplyPageState extends State { "electricUser": "请输入用电人", "workCommandPerson": "请输入作业指挥负责人", "electricUserNo": "请输入负责人电工号", - }; @override @@ -126,30 +124,20 @@ class _LsydApplyPageState extends State { }; // 并发请求 - final Future> personFuture = - BasicInfoApi.getDeptUsers('', isMyCorp: 1); final Future> limitedSpaceFuture = SpecialWorkApi.specialWorkLimitedSpaceList(data); final Future> initDataFuture = widget.isReEdit ? SpecialWorkApi.specialWorkTaskLogDetail(widget.work_id) - : SpecialWorkApi.specialWorkInit(SpecialWorkTypeEnum.electricityWork.code); + : SpecialWorkApi.specialWorkInit( + SpecialWorkTypeEnum.electricityWork.code, + ); - final results = await Future.wait([ - personFuture, - initDataFuture, - limitedSpaceFuture, - ]); + final results = await Future.wait([initDataFuture, limitedSpaceFuture]); - final personRes = results[0]; - final initData = results[1]; - final limitedSpaceRes = results[2]; - - // 人员列表 - if (personRes['success'] == true) { - _allPersonList = personRes['data'] ?? []; - } + final initData = results[0]; + final limitedSpaceRes = results[1]; if (limitedSpaceRes['success'] == true) { final List data = limitedSpaceRes['data'] ?? []; @@ -159,7 +147,6 @@ class _LsydApplyPageState extends State { printLongString(jsonEncode(initData)); if (initData['success'] == true) { if (widget.isReEdit) { - setState(() { form = initData['data'] ?? {}; pd = form['workInfo']['info'] ?? {}; @@ -171,6 +158,8 @@ class _LsydApplyPageState extends State { pd = initData['data'] ?? {}; pd['signStepFlag'] = 2; pd['gasFlag'] = 2; + pd['xgfFlag'] = 1; + pd['operationTypeName'] = '相关方作业'; levelList = pd['taskWorkLevels'] ?? []; await safeController.loadFromRaw( pd['preparers'] ?? pd['PREPARERS'] ?? [], @@ -183,7 +172,6 @@ class _LsydApplyPageState extends State { } } getSafeMeasure(); - } else { ToastUtil.showNormal(context, initData['errMessage'] ?? '数据加载失败'); } @@ -199,6 +187,7 @@ class _LsydApplyPageState extends State { LoadingDialogHelper.dismiss(); } } + /// 选择作业级别 Future chooseLevelHandle() async { final choice = await BottomPicker.show( @@ -211,7 +200,7 @@ class _LsydApplyPageState extends State { setState(() { // 根据taskName找到对应的item final index = levelList.indexWhere( - (item) => item['taskName'] == choice, + (item) => item['taskName'] == choice, ); final item = levelList[index]; pd['workLevelName'] = item['taskName']; @@ -221,33 +210,38 @@ class _LsydApplyPageState extends State { await getFlowInit(); } } + /// 获取安全措施 void getSafeMeasure() async { final reqData = {'eqWorkId': form['workId'] ?? ''}; - final res = widget.isReEdit - ? await SpecialWorkApi.specialWorkSignMeasureList(reqData) - : await SpecialWorkApi.specialWorkMeasureList(SpecialWorkTypeEnum.electricityWork.code); + final res = + widget.isReEdit + ? await SpecialWorkApi.specialWorkSignMeasureList(reqData) + : await SpecialWorkApi.specialWorkMeasureList( + SpecialWorkTypeEnum.electricityWork.code, + ); // 安全防护措施列表 if (res['success'] == true) { final List data = res['data'] ?? []; List safeMeasures = - data - .map( - (item) => - SafeMeasureOption.fromJson(Map.from(item)), - ) - .toList(); + data + .map( + (item) => + SafeMeasureOption.fromJson(Map.from(item)), + ) + .toList(); safeController.setAllMeasures(safeMeasures); if (widget.isReEdit) { safeMeasures = data .where((item) => '${item['type']}' == '1') .map( - (item) => - SafeMeasureOption.fromJson(Map.from(item)), - ) + (item) => SafeMeasureOption.fromJson( + Map.from(item), + ), + ) .toList(); await safeController.loadInitialData( safeMeasures.map((item) => item.toJson()).toList(), @@ -276,11 +270,13 @@ class _LsydApplyPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: {'corpinfoId': '${pd['projectExecutionLocationCorpId']}'}, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); }); } + // 选择作业单位 void chooseWorkUnitHandle() { showModalBottomSheet( @@ -290,15 +286,16 @@ class _LsydApplyPageState extends State { backgroundColor: Colors.transparent, builder: (_) => DepartmentPicker( - onSelected: (id, name, data) async { - setState(() { - pd['workDepartment'] = id; - pd['workDepartmentName'] = name; - }); - // 拉该单位人员并缓存 - await _getPersonListForUnitId(id); - }, - ), + onSelected: (id, name, data) async { + setState(() { + pd['workDepartment'] = id; + pd['workDepartmentName'] = name; + }); + // 拉该单位人员并缓存 + await _getPersonListForUnitId(id); + }, + data: {'corpinfoId': '${pd['projectExecutionLocationCorpId']}'}, + ), ).then((_) { // 可选:FocusHelper.clearFocus(context); }); @@ -359,7 +356,7 @@ class _LsydApplyPageState extends State { await _getPersonListForUnitId(unitId); personList = _personCache[unitId] ?? []; if (personList.isEmpty) { - ToastUtil.showNormal(context, '暂无可选人员,请选择其他单位'); + ToastUtil.showNormal(context, '暂无可选人员,请选择正确的相关方项目'); return; } } @@ -398,6 +395,7 @@ class _LsydApplyPageState extends State { //FocusHelper.clearFocus(context); }); } + void _chooseAlonePersonHandle(SelectPersonType type) { if (_allPersonList.isEmpty) { ToastUtil.showNormal(context, '暂无数据'); @@ -444,6 +442,10 @@ class _LsydApplyPageState extends State { pd['projectId'] = id; pd['projectName'] = name; pd['xgfId'] = json['corpinfoId']; + pd['projectExecutionLocationCorpId'] = + json['projectExecutionLocationCorpId']; + pd['projectExecutionLocationCorpName'] = + json['projectExecutionLocationCorpName']; }); _getRelatedPartiesUserList(); }, @@ -459,6 +461,14 @@ class _LsydApplyPageState extends State { // 获取相关方企业用户列表 Future _getRelatedPartiesUserList() async { + final personRes = await BasicInfoApi.getDeptUsers( + '', + isMyCorp: 0, + corpinfoId: pd['projectExecutionLocationCorpId'], + ); + if (personRes['success'] == true) { + _allPersonList = personRes['data']; + } try { final result = await BasicInfoApi.getDeptUsers( '', @@ -498,7 +508,10 @@ class _LsydApplyPageState extends State { /// 初始化流程数据(调用后会填充 _initData,并根据 settingSignSteps 初始化 _groups) Future getFlowInit() async { LoadingDialogHelper.show(); - final data = {'workType': SpecialWorkTypeEnum.electricityWork.code, 'workLevel': pd['workLevel']}; + final data = { + 'workType': SpecialWorkTypeEnum.electricityWork.code, + 'workLevel': pd['workLevel'], + }; try { final res = await SpecialWorkApi.specialWorkFlowInit(data); LoadingDialogHelper.hide(); @@ -544,7 +557,9 @@ class _LsydApplyPageState extends State { final item = groups[i]; final canSkip = item['canSkip'] ?? 0; final skipCondition = item['skipCondition']?.toString() ?? ''; - if (canSkip == 1 && skipCondition.contains('gas_flag') && !widget.isReEdit) { + if (canSkip == 1 && + skipCondition.contains('gas_flag') && + !widget.isReEdit) { setState(() { pd['gasFlag'] = 2; }); @@ -560,6 +575,25 @@ class _LsydApplyPageState extends State { }); } } + if (isKF) test(); + }); + } + Future test() async { + for (Map item in _groups) { + item['actUser'] = '2008745640177348608'; + item['actUserName'] = '李一浩'; + item['actUserDepartment'] = '2008745637258113024'; + item['actUserDepartmentName'] = '测试部'; + final stepId = item['stepId'] ?? ''; + if ('$stepId' == '20') { + _allowChoosePersonList[0] = item; + } + if ('$stepId' == '21') { + _allowChoosePersonList[1] = item; + } + + } + setState(() { }); } @@ -569,7 +603,7 @@ class _LsydApplyPageState extends State { final actorField = (item['actorField'] ?? '').toString(); final canSkip = (item['canSkip'] ?? 0) is int ? (item['canSkip'] ?? 0) : 0; final skipCondition = (item['skipCondition'] ?? '').toString(); - final allowXgfFlag = item['allowXgfFlag']?? 0; + final allowXgfFlag = item['allowXgfFlag'] ?? 0; final deptLabel = actorField.isNotEmpty ? '$actorField 部门' : '单位'; final personLabel = actorField.isNotEmpty ? actorField : '人员'; @@ -731,23 +765,29 @@ class _LsydApplyPageState extends State { 'workType': SpecialWorkTypeEnum.electricityWork.code, 'xgfFlag': info['xgfFlag'] ?? '', 'xgfId': info['xgfId'] ?? '', + 'corpinfoId': info['projectExecutionLocationCorpId'] ?? '', + 'projectId': info['projectId'] ?? '', + 'projectName': info['projectName'] ?? '', 'info': info, 'gasFlag': info['gasFlag'] ?? '', 'checkNo': info['checkNo'] ?? '', 'signLogs': newGroups, - 'others' : others - + 'others': others, }; // TODO: 打回删除 checkNo、workId - if (FormUtils.hasValue(data, 'workInfo') && FormUtils.hasValue(data['workInfo'], 'checkNo')) { + if (FormUtils.hasValue(data, 'workInfo') && + FormUtils.hasValue(data['workInfo'], 'checkNo')) { data.remove('checkNo'); data.remove('workId'); } // return; LoadingDialogHelper.show(); if (status == '1') { - final result = await SpecialWorkApi.specialWorkSave(data, SpecialWorkTypeEnum.electricityWork); + final result = await SpecialWorkApi.specialWorkSave( + data, + SpecialWorkTypeEnum.electricityWork, + ); LoadingDialogHelper.dismiss(); if (result['success'] == true) { ToastUtil.showNormal(context, '保存成功'); @@ -756,7 +796,10 @@ class _LsydApplyPageState extends State { ToastUtil.showNormal(context, result['errMessage'] ?? '保存失败'); } } else { - final result = await SpecialWorkApi.specialWorkSaveTemp(data, SpecialWorkTypeEnum.electricityWork); + final result = await SpecialWorkApi.specialWorkSaveTemp( + data, + SpecialWorkTypeEnum.electricityWork, + ); LoadingDialogHelper.dismiss(); if (result['success'] == true) { ToastUtil.showNormal(context, '已暂存'); @@ -846,6 +889,7 @@ class _LsydApplyPageState extends State { } return true; } + // 关联其他作业票弹窗 void _showChooseOtherWorkTicketDialog() async { PagedMultiSelectPopup.show>( @@ -867,12 +911,13 @@ class _LsydApplyPageState extends State { onConfirm: (selectedItems) { // 选中的数据列表 setState(() { - pd['linkSpecialWorks'] = - selectedItems.map((item) { - final workName = SpecialWorkTypeEnum.getName(item['workType']); - final checkNo = item['checkNo'] ?? ''; - return {'workTypeName': workName, 'checkNo': checkNo}; - }).toList(); + String w = '${selectedItems.map((item) { + final workName = SpecialWorkTypeEnum.getName(item['workType']); + final checkNo = item['checkNo'] ?? ''; + return '$workName $checkNo'; + }).toList().join(',')},'; + String now = pd['linkSpecialWorks'] ?? ''; + pd['linkSpecialWorks'] = now + w; }); }, ); @@ -897,16 +942,12 @@ class _LsydApplyPageState extends State { List> extraDataList, ) { setState(() { - // addData['hiddenLevel'] = extraData?['dictValue']; - // addData['hiddenLevelName'] = name; - pd['riskResults'] = - extraDataList.map((data) { - final name = data['dictLabel'] ?? ''; - return { - 'riskResultName': name, - 'riskResult': data['dictValue'], - }; - }).toList(); + String w = '${extraDataList.map((data) { + final name = data['dictLabel'] ?? ''; + return name; + }).toList().join(',')},'; + String now = pd['riskResults'] ?? ''; + pd['riskResults'] = now + w; }); }, onSelected: @@ -916,6 +957,7 @@ class _LsydApplyPageState extends State { // 可选:FocusHelper.clearFocus(context); }); } + /// 定位组件 Widget _locationWidget() { return Container( @@ -965,25 +1007,7 @@ class _LsydApplyPageState extends State { } Widget _buildDetail() { - Map chooseLimitedSpace = pd['chooseLimitedSpace'] ?? {}; - List linkWorks = pd['linkSpecialWorks'] ?? []; - String linkShowStr = linkWorks - .map((item) { - final workName = item['workTypeName']; - final checkNo = item['checkNo'] ?? ''; - return '$workName $checkNo'; - }) - .toList() - .join(','); - List riskResults = pd['riskResults'] ?? []; - String riskShowStr = - riskResults - .map((item) { - final riskResultName = item['riskResultName']; - return riskResultName; - }) - .toList() - .join(); + return Container( padding: const EdgeInsets.symmetric(vertical: 10), decoration: const BoxDecoration( @@ -1009,14 +1033,14 @@ class _LsydApplyPageState extends State { const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '作业类型:', - isEditable: _isEditable, - onTap: chooseHotworkType, - text: pd['operationTypeName'] ?? '', + isEditable: false, + strongRequired: true, + text: '相关方作业', ), if (pd['xgfFlag'] == 1) ...[ const Divider(), ListItemFactory.createYesNoSection( - horizontalPadding: 5, + horizontalPadding: 3, title: '是否项目内作业', isRequired: true, groupValue: _isInnerWork, @@ -1027,7 +1051,7 @@ class _LsydApplyPageState extends State { }); }, ), - const Divider(), + const Divider(height: 1), // 相关方作业 ItemListWidget.selectableLineTitleTextRightButton( @@ -1139,22 +1163,26 @@ class _LsydApplyPageState extends State { label: '关联其他特殊作业及安全作业票编号', isRequired: _isEditable, isEditable: _isEditable, - isInput: false, + isInput: true, onTap: _showChooseOtherWorkTicketDialog, hintText: '请选择关联的其他特殊作业及安全作业票编号', - controller: null, - text: linkShowStr, + text: pd['linkSpecialWorks'] ?? '', + onChanged: (value) { + pd['linkSpecialWorks'] = value; + }, ), const Divider(), ItemListWidget.twoRowButtonTitleText( label: '风险辨识结果', isRequired: _isEditable, isEditable: _isEditable, - isInput: false, + isInput: true, onTap: _showRiskIdentificationResultDialog, hintText: '请选择', - controller: null, - text: riskShowStr, + text: pd['riskResults'] ?? '', + onChanged: (value) { + pd['riskResults'] = value; + }, ), const Divider(), ItemListWidget.singleLineTitleText( @@ -1287,7 +1315,6 @@ class _LsydApplyPageState extends State { }, ), ), - ], ) : SizedBox() diff --git a/lib/pages/home/Tap/special_work/lsyd_work/lsyd_task_page.dart b/lib/pages/home/Tap/special_work/lsyd_work/lsyd_task_page.dart index 7e47a13..2406677 100644 --- a/lib/pages/home/Tap/special_work/lsyd_work/lsyd_task_page.dart +++ b/lib/pages/home/Tap/special_work/lsyd_work/lsyd_task_page.dart @@ -165,9 +165,10 @@ class _LsydTaskPageState extends State { (_initData['settingSignSteps'] is List) ? List.from(_initData['settingSignSteps']) : []; + final corpinfoId = _initData['workInfo']['corpinfoId']; if (steps.isNotEmpty) { LoadingDialogHelper.show(); - final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 1); + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: corpinfoId); LoadingDialogHelper.dismiss(); if (personRes['success'] == true) { @@ -435,6 +436,9 @@ class _LsydTaskPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: { + 'corpinfoId' :_initData['workInfo']['corpinfoId'] ?? '' + }, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); diff --git a/lib/pages/home/Tap/special_work/lsyd_work/work_tab_lsyd_list.dart b/lib/pages/home/Tap/special_work/lsyd_work/work_tab_lsyd_list.dart index 777928b..7b12346 100644 --- a/lib/pages/home/Tap/special_work/lsyd_work/work_tab_lsyd_list.dart +++ b/lib/pages/home/Tap/special_work/lsyd_work/work_tab_lsyd_list.dart @@ -49,7 +49,28 @@ class _WorkTabLsydListState extends State { final res = await SpecialWorkApi.getSpecialWorkStepList(SpecialWorkTypeEnum.electricityWork.code); if (res != null && res['success'] == true) { setState(() { - steps = res['data'] ?? []; + final rawData = res['data'] ?? []; + // 深拷贝并过滤数据,避免直接修改原引用导致的问题,同时移除不符合条件的项 + steps = (rawData as List).map((entry) { + if (entry is Map) { + final List originalSteps = entry['steps'] ?? []; + // 过滤 steps:保留 allowXgfFlag 为 '1' 或存在且有效的项 + final filteredSteps = originalSteps.where((item) { + if (item is Map) { + final flag = item['allowXgfFlag']; + return '${item['allowXgfFlag']}' == '1'; + } + return false; + }).toList(); + + return { + ...entry, + 'steps': filteredSteps, + }; + } + return entry; + }).where((entry) => entry != null).toList(); + _getStepUnreadCount(); }); } else { 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 295fc12..55df04a 100644 --- a/lib/pages/home/Tap/special_work/mbcd_work/mbcdDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/mbcd_work/mbcdDetailFormWidget.dart @@ -266,24 +266,9 @@ class _MbcdDetailFormWidgetState extends State { } } - List linkWorks = pd['linkSpecialWorks'] ?? []; - String linkShowStr = linkWorks - .map((item) { - final workName = item['workTypeName']; - final checkNo = item['checkNo'] ?? ''; - return '$workName $checkNo'; - }) - .toList() - .join(','); - List riskResults = pd['riskResults'] ?? []; - String riskShowStr = - riskResults - .map((item) { - final riskResultName = item['riskResultName']; - return riskResultName; - }) - .toList() - .join(); + String linkShowStr = pd['linkSpecialWorks'] ?? ''; + + String riskShowStr = pd['riskResults'] ?? ''; return Container( padding: const EdgeInsets.symmetric(vertical: 0), @@ -326,14 +311,16 @@ class _MbcdDetailFormWidgetState extends State { if (pd['xgfFlag'] == 1) ...[ const Divider(), ListItemFactory.createYesNoSection( - horizontalPadding: 5, + horizontalPadding: 2, + verticalPadding: 7, title: '是否项目内作业', + isEdit: false, isRequired: true, text: '${pd['internalOperationFlag']}' == '1' ? '是' : '否', groupValue: null, onChanged: (bool value) { }, ), - const Divider(), + const Divider(height: 1), // 相关方作业 ItemListWidget.selectableLineTitleTextRightButton( @@ -429,7 +416,6 @@ class _MbcdDetailFormWidgetState extends State { isEditable: false, isInput: false, hintText: '请选择关联的其他特殊作业及安全作业票编号', - controller: null, text: linkShowStr, onTap: () { }, ), const Divider(), @@ -440,7 +426,6 @@ class _MbcdDetailFormWidgetState extends State { isInput: false, onTap: (){}, hintText: '请选择', - controller: null, text: riskShowStr, ), 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 7719d9c..e0fb185 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 @@ -117,16 +117,7 @@ class _MbcdApplyPageState extends State { LoadingDialogHelper.show(); try { - final data = { - "eqWorkType": SpecialWorkTypeEnum.blindboardWork.code, - "pageSize": 999, - "pageIndex": 1, - }; - // 并发请求 - final Future> personFuture = - BasicInfoApi.getDeptUsers('', isMyCorp: 1); - final Future> initDataFuture = widget.isReEdit ? SpecialWorkApi.specialWorkTaskLogDetail(widget.work_id) @@ -134,15 +125,9 @@ class _MbcdApplyPageState extends State { SpecialWorkTypeEnum.blindboardWork.code, ); - final results = await Future.wait([personFuture, initDataFuture]); + final results = await Future.wait([initDataFuture]); - final personRes = results[0]; - final initData = results[1]; - - // 人员列表 - if (personRes['success'] == true) { - _allPersonList = personRes['data'] ?? []; - } + final initData = results[0]; printLongString(jsonEncode(initData)); if (initData['success'] == true) { @@ -163,6 +148,8 @@ class _MbcdApplyPageState extends State { pd = initData['data'] ?? {}; pd['signStepFlag'] = 2; pd['gasFlag'] = 2; + pd['xgfFlag'] = 1; + pd['operationTypeName'] = '相关方作业'; levelList = pd['taskWorkLevels'] ?? []; await safeController.loadFromRaw( pd['preparers'] ?? pd['PREPARERS'] ?? [], @@ -250,6 +237,7 @@ class _MbcdApplyPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: {'corpinfoId' : '${pd['projectExecutionLocationCorpId']}'}, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); @@ -310,7 +298,7 @@ class _MbcdApplyPageState extends State { await _getPersonListForUnitId(unitId); personList = _personCache[unitId] ?? []; if (personList.isEmpty) { - ToastUtil.showNormal(context, '暂无可选人员,请选择其他单位'); + ToastUtil.showNormal(context, '暂无可选人员,请选择正确的相关方项目'); return; } } @@ -365,6 +353,8 @@ class _MbcdApplyPageState extends State { pd['projectId'] = id; pd['projectName'] = name; pd['xgfId'] = json['corpinfoId']; + pd['projectExecutionLocationCorpId'] = json['projectExecutionLocationCorpId']; + pd['projectExecutionLocationCorpName'] = json['projectExecutionLocationCorpName']; }); _getRelatedPartiesUserList(); }, @@ -380,6 +370,10 @@ class _MbcdApplyPageState extends State { // 获取相关方企业用户列表 Future _getRelatedPartiesUserList() async { + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: pd['projectExecutionLocationCorpId']); + if (personRes['success'] == true) { + _allPersonList = personRes['data']; + } try { final result = await BasicInfoApi.getDeptUsers( '', @@ -509,6 +503,25 @@ class _MbcdApplyPageState extends State { }); } } + if (isKF) test(); + }); + } + Future test() async { + for (Map item in _groups) { + item['actUser'] = '2008745640177348608'; + item['actUserName'] = '李一浩'; + item['actUserDepartment'] = '2008745637258113024'; + item['actUserDepartmentName'] = '测试部'; + final stepId = item['stepId'] ?? ''; + if ('$stepId' == '20') { + _allowChoosePersonList[0] = item; + } + if ('$stepId' == '21') { + _allowChoosePersonList[1] = item; + } + + } + setState(() { }); } @@ -755,6 +768,9 @@ class _MbcdApplyPageState extends State { 'workType': SpecialWorkTypeEnum.blindboardWork.code, 'xgfFlag': info['xgfFlag'] ?? '', 'xgfId': info['xgfId'] ?? '', + 'corpinfoId' : info['projectExecutionLocationCorpId'] ?? '', + 'projectId': info['projectId'] ?? '', + 'projectName': info['projectName'] ?? '', 'info': info, 'gasFlag': info['gasFlag'] ?? '', 'checkNo': info['checkNo'] ?? '', @@ -1063,12 +1079,13 @@ class _MbcdApplyPageState extends State { onConfirm: (selectedItems) { // 选中的数据列表 setState(() { - pd['linkSpecialWorks'] = - selectedItems.map((item) { - final workName = SpecialWorkTypeEnum.getName(item['workType']); - final checkNo = item['checkNo'] ?? ''; - return {'workTypeName': workName, 'checkNo': checkNo}; - }).toList(); + String w = '${selectedItems.map((item) { + final workName = SpecialWorkTypeEnum.getName(item['workType']); + final checkNo = item['checkNo'] ?? ''; + return '$workName $checkNo'; + }).toList().join(',')},'; + String now = pd['linkSpecialWorks'] ?? ''; + pd['linkSpecialWorks'] = now + w; }); }, ); @@ -1083,31 +1100,27 @@ class _MbcdApplyPageState extends State { backgroundColor: Colors.transparent, builder: (_) => MultiDictValuesPicker( - title: '风险辨识结果', - dictType: 'riskGrade', - allowSelectParent: false, - multiSelect: true, - onMultiSelected: ( - List ids, - List names, - List> extraDataList, + title: '风险辨识结果', + dictType: 'riskGrade', + allowSelectParent: false, + multiSelect: true, + onMultiSelected: ( + List ids, + List names, + List> extraDataList, ) { - setState(() { - // addData['hiddenLevel'] = extraData?['dictValue']; - // addData['hiddenLevelName'] = name; - pd['riskResults'] = - extraDataList.map((data) { - final name = data['dictLabel'] ?? ''; - return { - 'riskResultName': name, - 'riskResult': data['dictValue'], - }; - }).toList(); - }); - }, - onSelected: - (String id, String name, Map? extraData) {}, - ), + setState(() { + String w = '${extraDataList.map((data) { + final name = data['dictLabel'] ?? ''; + return name; + }).toList().join(',')},'; + String now = pd['riskResults'] ?? ''; + pd['riskResults'] = now + w; + }); + }, + onSelected: + (String id, String name, Map? extraData) {}, + ), ).then((_) { // 可选:FocusHelper.clearFocus(context); }); @@ -1165,24 +1178,7 @@ class _MbcdApplyPageState extends State { } Widget _buildDetail() { - List linkWorks = pd['linkSpecialWorks'] ?? []; - String linkShowStr = linkWorks - .map((item) { - final workName = item['workTypeName']; - final checkNo = item['checkNo'] ?? ''; - return '$workName $checkNo'; - }) - .toList() - .join(','); - List riskResults = pd['riskResults'] ?? []; - String riskShowStr = - riskResults - .map((item) { - final riskResultName = item['riskResultName']; - return riskResultName; - }) - .toList() - .join(); + return Container( padding: const EdgeInsets.symmetric(vertical: 10), decoration: const BoxDecoration( @@ -1208,14 +1204,14 @@ class _MbcdApplyPageState extends State { const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '作业类型:', - isEditable: _isEditable, - onTap: chooseHotworkType, - text: pd['operationTypeName'] ?? '', + isEditable: false, + strongRequired: true, + text: '相关方作业', ), if (pd['xgfFlag'] == 1) ...[ const Divider(), ListItemFactory.createYesNoSection( - horizontalPadding: 5, + horizontalPadding: 3, title: '是否项目内作业', isRequired: true, groupValue: _isInnerWork, @@ -1226,7 +1222,7 @@ class _MbcdApplyPageState extends State { }); }, ), - const Divider(), + const Divider(height:1), // 相关方作业 ItemListWidget.selectableLineTitleTextRightButton( @@ -1387,22 +1383,26 @@ class _MbcdApplyPageState extends State { label: '关联其他特殊作业及安全作业票编号', isRequired: _isEditable, isEditable: _isEditable, - isInput: false, + isInput: true, onTap: _showChooseOtherWorkTicketDialog, hintText: '请选择关联的其他特殊作业及安全作业票编号', - controller: null, - text: linkShowStr, + text: pd['linkSpecialWorks'] ?? '', + onChanged: (value) { + pd['linkSpecialWorks'] = value; + }, ), const Divider(), ItemListWidget.twoRowButtonTitleText( label: '风险辨识结果', isRequired: _isEditable, isEditable: _isEditable, - isInput: false, + isInput: true, onTap: _showRiskIdentificationResultDialog, hintText: '请选择', - controller: null, - text: riskShowStr, + text: pd['riskResults'] ?? '', + onChanged: (value) { + pd['riskResults'] = value; + }, ), const Divider(), ItemListWidget.OneRowButtonTitleText( diff --git a/lib/pages/home/Tap/special_work/mbcd_work/mbcd_task_page.dart b/lib/pages/home/Tap/special_work/mbcd_work/mbcd_task_page.dart index 5515f86..ac9013d 100644 --- a/lib/pages/home/Tap/special_work/mbcd_work/mbcd_task_page.dart +++ b/lib/pages/home/Tap/special_work/mbcd_work/mbcd_task_page.dart @@ -159,9 +159,10 @@ class _MbcdTaskPageState extends State { (_initData['settingSignSteps'] is List) ? List.from(_initData['settingSignSteps']) : []; + final corpinfoId = _initData['workInfo']['corpinfoId']; if (steps.isNotEmpty) { LoadingDialogHelper.show(); - final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 1); + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: corpinfoId); LoadingDialogHelper.dismiss(); if (personRes['success'] == true) { @@ -429,6 +430,9 @@ class _MbcdTaskPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: { + 'corpinfoId' :_initData['workInfo']['corpinfoId'] ?? '' + }, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); diff --git a/lib/pages/home/Tap/special_work/mbcd_work/mbcd_wait_page.dart b/lib/pages/home/Tap/special_work/mbcd_work/mbcd_wait_page.dart index 83201e4..217a2da 100644 --- a/lib/pages/home/Tap/special_work/mbcd_work/mbcd_wait_page.dart +++ b/lib/pages/home/Tap/special_work/mbcd_work/mbcd_wait_page.dart @@ -464,7 +464,7 @@ class _MbcdWaitPageState extends State { }, ), ); - if (status == '1' && lockFlag == '2') { + if (status == '1' && lockFlag == '2' && widget.listType == SpecialListType.list) { buttons.add( CustomButton( text: '撤回', diff --git a/lib/pages/home/Tap/special_work/mbcd_work/work_tab_mbcd_list.dart b/lib/pages/home/Tap/special_work/mbcd_work/work_tab_mbcd_list.dart index b1a561b..ae9eb52 100644 --- a/lib/pages/home/Tap/special_work/mbcd_work/work_tab_mbcd_list.dart +++ b/lib/pages/home/Tap/special_work/mbcd_work/work_tab_mbcd_list.dart @@ -49,7 +49,28 @@ class _WorkTabMbcdListState extends State { final res = await SpecialWorkApi.getSpecialWorkStepList(SpecialWorkTypeEnum.blindboardWork.code); if (res != null && res['success'] == true) { setState(() { - steps = res['data'] ?? []; + final rawData = res['data'] ?? []; + // 深拷贝并过滤数据,避免直接修改原引用导致的问题,同时移除不符合条件的项 + steps = (rawData as List).map((entry) { + if (entry is Map) { + final List originalSteps = entry['steps'] ?? []; + // 过滤 steps:保留 allowXgfFlag 为 '1' 或存在且有效的项 + final filteredSteps = originalSteps.where((item) { + if (item is Map) { + final flag = item['allowXgfFlag']; + return '${item['allowXgfFlag']}' == '1'; + } + return false; + }).toList(); + + return { + ...entry, + 'steps': filteredSteps, + }; + } + return entry; + }).where((entry) => entry != null).toList(); + _getStepUnreadCount(); }); } else { 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 755bd8e..05e6ac0 100644 --- a/lib/pages/home/Tap/special_work/sxkj_work/SxkjWorkDetailFormWidget.dart +++ b/lib/pages/home/Tap/special_work/sxkj_work/SxkjWorkDetailFormWidget.dart @@ -3,6 +3,7 @@ import 'package:intl/intl.dart'; import 'package:qhd_prevention/customWidget/ItemWidgetFactory.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/single_image_viewer.dart'; import 'package:qhd_prevention/http/ApiService.dart'; import 'package:qhd_prevention/pages/home/Tap/special_work/custom/MeasuresListWidget.dart'; @@ -105,6 +106,11 @@ class _SxkjWorkDetailFormWidgetState extends State { final signPath = (info['signPath'] ?? '').toString().trim(); final signTime = (info['signTime'] ?? info['signerTime'] ?? '').toString().trim(); final remarks = (info['remarks'] ?? '').toString().trim(); + Map otherParams = info['otherParams'] ?? {}; + String fileUrl = ''; + if (otherParams.keys.isNotEmpty) { + fileUrl = otherParams['spaceRecordFile'] ?? ''; + } if (signPath.isEmpty) continue; @@ -150,6 +156,70 @@ class _SxkjWorkDetailFormWidgetState extends State { ), ), ), + if (remarks.isNotEmpty) + const SizedBox(height: 10), + if (otherParams.keys.isNotEmpty) + Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + alignment: Alignment.centerLeft, + // padding: const EdgeInsets.only(bottom: 10), + child:Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '有限空间作业人数:${otherParams['limitSpaceWorkNum']}', + softWrap: true, + maxLines: null, + style: const TextStyle( + fontSize: 13, + color: Colors.black54, + ), + ), + const SizedBox(height: 10), + Row( + children: [ + Text('附件:'), + const SizedBox(width: 10), + GestureDetector( + onTap: () async { + pushPage( + ReadFilePage( + fileUrl: + ApiService.baseImgPath + fileUrl, + ), + context, + ); + }, + child: Column( + children: [ + Icon(Icons.file_present, color: Colors.blue), + SizedBox(width: 15), + SizedBox( + width: 180, + child: Text( + // 附件名不能太长 + fileUrl.substring(fileUrl.lastIndexOf('/') + 1), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 14, + ), + ), + ), + ], + ), + ) + ], + ) + ], + ), + ), + + ], + ), + GestureDetector( onTap: () async { @@ -262,6 +332,29 @@ class _SxkjWorkDetailFormWidgetState extends State { isEditable: widget.isEditable, text: pd['operationTypeName'] ?? '', ), + + if (pd['xgfFlag'] == 1) ...[ + const Divider(), + ListItemFactory.createYesNoSection( + horizontalPadding: 2, + verticalPadding: 7, + title: '是否项目内作业', + isRequired: true, + isEdit: false, + text: '${pd['internalOperationFlag']}' == '1' ? '是' : '否', + groupValue: null, onChanged: (bool value) { }, + + ), + const Divider(height: 1), + + // 相关方作业 + ItemListWidget.selectableLineTitleTextRightButton( + label: '相关方项目', + isEditable: false, + text: pd['projectName'] ?? '', + isRequired: true, + ), + ], 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 a083c2d..1aa0a23 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 @@ -54,6 +54,9 @@ class _SxkjApplyPageState extends State { // 是否项目内作业 bool _isInnerWork = false; + // 是否重点管控有限空间 + bool _isLimitedSpace = false; + /// 详情 Map pd = {}; Map form = {}; @@ -112,8 +115,6 @@ class _SxkjApplyPageState extends State { }; // 并发请求 - final Future> personFuture = - BasicInfoApi.getDeptUsers('', isMyCorp: 1); final Future> limitedSpaceFuture = SpecialWorkApi.specialWorkLimitedSpaceList(data); @@ -123,19 +124,12 @@ class _SxkjApplyPageState extends State { : SpecialWorkApi.specialWorkInit(SpecialWorkTypeEnum.confinedspaceWork.code); final results = await Future.wait([ - personFuture, initDataFuture, limitedSpaceFuture, ]); - final personRes = results[0]; - final initData = results[1]; - final limitedSpaceRes = results[2]; - - // 人员列表 - if (personRes['success'] == true) { - _allPersonList = personRes['data'] ?? []; - } + final initData = results[0]; + final limitedSpaceRes = results[1]; if (limitedSpaceRes['success'] == true) { final List data = limitedSpaceRes['data'] ?? []; @@ -172,6 +166,8 @@ class _SxkjApplyPageState extends State { pd = initData['data'] ?? {}; pd['signStepFlag'] = 2; pd['gasFlag'] = 2; + pd['xgfFlag'] = 1; + pd['operationTypeName'] = '相关方作业'; levelList = pd['taskWorkLevels'] ?? []; await safeController.loadFromRaw( pd['preparers'] ?? pd['PREPARERS'] ?? [], @@ -255,6 +251,7 @@ class _SxkjApplyPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: {'corpinfoId' : '${pd['projectExecutionLocationCorpId']}'}, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); @@ -277,6 +274,7 @@ class _SxkjApplyPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: {'corpinfoId' : pd['projectExecutionLocationCorpId'] ?? ''}, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); @@ -337,7 +335,7 @@ class _SxkjApplyPageState extends State { await _getPersonListForUnitId(unitId); personList = _personCache[unitId] ?? []; if (personList.isEmpty) { - ToastUtil.showNormal(context, '暂无可选人员,请选择其他单位'); + ToastUtil.showNormal(context, '暂无可选人员,请选择正确的相关方项目'); return; } } @@ -416,6 +414,8 @@ class _SxkjApplyPageState extends State { pd['projectId'] = id; pd['projectName'] = name; pd['xgfId'] = json['corpinfoId']; + pd['projectExecutionLocationCorpId'] = json['projectExecutionLocationCorpId']; + pd['projectExecutionLocationCorpName'] = json['projectExecutionLocationCorpName']; }); _getRelatedPartiesUserList(); }, @@ -431,6 +431,10 @@ class _SxkjApplyPageState extends State { // 获取相关方企业用户列表 Future _getRelatedPartiesUserList() async { + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: pd['projectExecutionLocationCorpId']); + if (personRes['success'] == true) { + _allPersonList = personRes['data']; + } try { final result = await BasicInfoApi.getDeptUsers( '', @@ -557,6 +561,25 @@ class _SxkjApplyPageState extends State { }); } } + if (isKF) test(); + }); + } + Future test() async { + for (Map item in _groups) { + item['actUser'] = '2008745640177348608'; + item['actUserName'] = '李一浩'; + item['actUserDepartment'] = '2008745637258113024'; + item['actUserDepartmentName'] = '测试部'; + final stepId = item['stepId'] ?? ''; + if ('$stepId' == '20') { + _allowChoosePersonList[0] = item; + } + if ('$stepId' == '21') { + _allowChoosePersonList[1] = item; + } + + } + setState(() { }); } @@ -728,6 +751,9 @@ class _SxkjApplyPageState extends State { 'workType': SpecialWorkTypeEnum.confinedspaceWork.code, 'xgfFlag': info['xgfFlag'] ?? '', 'xgfId': info['xgfId'] ?? '', + 'corpinfoId' : info['projectExecutionLocationCorpId'] ?? '', + 'projectId': info['projectId'] ?? '', + 'projectName': info['projectName'] ?? '', 'info': info, 'gasFlag': info['gasFlag'] ?? '', 'checkNo': info['checkNo'] ?? '', @@ -892,14 +918,14 @@ class _SxkjApplyPageState extends State { const Divider(), ItemListWidget.selectableLineTitleTextRightButton( label: '作业类型:', - isEditable: _isEditable, - onTap: chooseHotworkType, - text: pd['operationTypeName'] ?? '', + isEditable: false, + strongRequired: true, + text: '相关方作业', ), if (pd['xgfFlag'] == 1) ...[ const Divider(), ListItemFactory.createYesNoSection( - horizontalPadding: 5, + horizontalPadding: 3, title: '是否项目内作业', isRequired: true, groupValue: _isInnerWork, @@ -910,7 +936,7 @@ class _SxkjApplyPageState extends State { }); }, ), - const Divider(), + const Divider(height:1), // 相关方作业 ItemListWidget.selectableLineTitleTextRightButton( @@ -960,10 +986,10 @@ class _SxkjApplyPageState extends State { horizontalPadding: 5, title: '是否重点管控有限空间', isRequired: true, - groupValue: _isInnerWork, + groupValue: _isLimitedSpace, onChanged: (value) { setState(() { - _isInnerWork = value; + _isLimitedSpace = value; pd['isInnerWork'] = value ? 1 : 2; }); }, diff --git a/lib/pages/home/Tap/special_work/sxkj_work/sxkj_task_page.dart b/lib/pages/home/Tap/special_work/sxkj_work/sxkj_task_page.dart index ebfdf88..7050930 100644 --- a/lib/pages/home/Tap/special_work/sxkj_work/sxkj_task_page.dart +++ b/lib/pages/home/Tap/special_work/sxkj_work/sxkj_task_page.dart @@ -161,9 +161,10 @@ class _SxkjTaskPageState extends State { (_initData['settingSignSteps'] is List) ? List.from(_initData['settingSignSteps']) : []; + final corpinfoId = _initData['workInfo']['corpinfoId']; if (steps.isNotEmpty) { LoadingDialogHelper.show(); - final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 1); + final personRes = await BasicInfoApi.getDeptUsers('', isMyCorp: 0, corpinfoId: corpinfoId); LoadingDialogHelper.dismiss(); if (personRes['success'] == true) { @@ -436,6 +437,9 @@ class _SxkjTaskPageState extends State { // 拉该单位人员并缓存 await _getPersonListForUnitId(id); }, + data: { + 'corpinfoId' :_initData['workInfo']['corpinfoId'] ?? '' + }, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); @@ -626,6 +630,7 @@ class _SxkjTaskPageState extends State { isEditable: true, isTextFont: false, isRequired: true, + isNumericInput: true, text: other['limitSpaceWorkNum'] ?? '', onChanged: (value) { setState(() { @@ -915,6 +920,7 @@ class _SxkjTaskPageState extends State { }, ), ], + const SizedBox(height: 10,), if (widget.isEdit) ...[ _operationWidget(), ] else ...[ 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 44534f0..502f87c 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 @@ -404,7 +404,7 @@ class _SxkjWaitPageState extends State { }, ), ); - if (status == '1' && lockFlag == '2') { + if (status == '1' && lockFlag == '2' && widget.listType == SpecialListType.list) { buttons.add( CustomButton( text: '撤回', 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 index f502318..eb7f17b 100644 --- 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 @@ -114,6 +114,7 @@ class _SxkjTzApplyPageState extends State { pd['manageDeptId'] = id; }); }, + data: {'corpinfoId' : '${pd['projectExecutionLocationCorpId']}'}, ), ).then((_) { // 可选:FocusHelper.clearFocus(context); 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 a18afdf..292632a 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 @@ -59,7 +59,28 @@ class _WorkTabSpaceListState extends State { final res = await SpecialWorkApi.getSpecialWorkStepList('confinedspace_work'); if (res != null && res['success'] == true) { setState(() { - steps = res['data'] ?? []; + final rawData = res['data'] ?? []; + // 深拷贝并过滤数据,避免直接修改原引用导致的问题,同时移除不符合条件的项 + steps = (rawData as List).map((entry) { + if (entry is Map) { + final List originalSteps = entry['steps'] ?? []; + // 过滤 steps:保留 allowXgfFlag 为 '1' 或存在且有效的项 + final filteredSteps = originalSteps.where((item) { + if (item is Map) { + final flag = item['allowXgfFlag']; + return '${item['allowXgfFlag']}' == '1'; + } + return false; + }).toList(); + + return { + ...entry, + 'steps': filteredSteps, + }; + } + return entry; + }).where((entry) => entry != null).toList(); + _getStepUnreadCount(); }); } else { diff --git a/lib/pages/home/Tap/work_tab_list_page.dart b/lib/pages/home/Tap/work_tab_list_page.dart index ac4c413..2af38bc 100644 --- a/lib/pages/home/Tap/work_tab_list_page.dart +++ b/lib/pages/home/Tap/work_tab_list_page.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:qhd_prevention/customWidget/work_tab_icon_grid.dart'; -import 'package:qhd_prevention/http/ApiService.dart'; +import 'package:qhd_prevention/common/route_service.dart'; +import 'package:qhd_prevention/common/route_aware_state.dart'; import 'package:qhd_prevention/customWidget/IconBadgeButton.dart'; +import 'package:qhd_prevention/http/ApiService.dart'; import 'package:qhd_prevention/pages/home/Tap/special_work/dh_work/hot_delay_page.dart'; import 'package:qhd_prevention/pages/home/Tap/special_work/dh_work/work_tab_dh_list.dart'; import 'package:qhd_prevention/pages/home/Tap/special_work/dl_work/work_tab_dl_list.dart'; @@ -13,7 +14,6 @@ import 'package:qhd_prevention/pages/home/Tap/special_work/mbcd_work/work_tab_mb import 'package:qhd_prevention/pages/home/Tap/special_work/sxkj_work/work_tab_space_list.dart'; import 'package:qhd_prevention/pages/my_appbar.dart'; import 'package:qhd_prevention/tools/tools.dart'; -import 'package:qhd_prevention/common/route_aware_state.dart'; class WorkTabListPage extends StatefulWidget { const WorkTabListPage({super.key}); @@ -23,15 +23,63 @@ class WorkTabListPage extends StatefulWidget { } class _WorkTabListPageState extends RouteAwareState { - late List> buttonInfos = [ - {"icon": "assets/images/wxzy_ico7.png", "title": "动火作业", "unreadCount": 0}, - {"icon": "assets/images/wxzy_ico6.png", "title": "受限空间作业", "unreadCount": 0}, - {"icon": "assets/images/wxzy_ico5.png", "title": "高处作业", "unreadCount": 0}, - {"icon": "assets/images/wxzy_ico4.png", "title": "动土作业", "unreadCount": 0}, - {"icon": "assets/images/wxzy_ico3.png", "title": "吊装作业", "unreadCount": 0}, - {"icon": "assets/images/wxzy_ico2.png", "title": "断路作业", "unreadCount": 0}, - {"icon": "assets/images/wxzy_ico1.png", "title": "临时用电作业", "unreadCount": 0}, - {"icon": "assets/images/wxzy_ico8.png", "title": "盲板抽堵作业", "unreadCount": 0}, + final List<_WorkButtonConfig> _allButtons = [ + _WorkButtonConfig( + icon: 'assets/image/wxzy_ico7.png', + title: '动火作业', + workType: 'hot_work', + menuPerms: 'dashboard:hazardous-work:hot-work', + pageBuilder: () => workTabDhList(), + ), + _WorkButtonConfig( + icon: 'assets/image/wxzy_ico6.png', + title: '受限空间作业', + workType: 'confinedspace_work', + menuPerms: 'dashboard:hazardous-work:confined-space-operations', + pageBuilder: () => WorkTabSpaceList(), + ), + _WorkButtonConfig( + icon: 'assets/image/wxzy_ico5.png', + title: '高处作业', + workType: 'high_work', + menuPerms: 'dashboard:hazardous-work:work-at-height', + pageBuilder: () => WorkTabGcList(), + ), + _WorkButtonConfig( + icon: 'assets/image/wxzy_ico4.png', + title: '动土作业', + workType: 'breakground_work', + menuPerms: 'dashboard:hazardous-work:earthwork-operations', + pageBuilder: () => WorkTabDtList(), + ), + _WorkButtonConfig( + icon: 'assets/image/wxzy_ico3.png', + title: '吊装作业', + workType: 'hoisting_work', + menuPerms: 'dashboard:hazardous-work:hoisting-operations', + pageBuilder: () => WorkTabDzList(), + ), + _WorkButtonConfig( + icon: 'assets/image/wxzy_ico2.png', + title: '断路作业', + workType: 'cutroad_work', + menuPerms: 'dashboard:hazardous-work:circuit-breaking-operation', + pageBuilder: () => WorkTabDlList(), + ), + _WorkButtonConfig( + icon: 'assets/image/wxzy_ico1.png', + title: '临时用电作业', + workType: 'electricity_work', + menuPerms: 'dashboard:hazardous-work:temporary-electrical-work', + pageBuilder: () => WorkTabLsydList(), + ), + _WorkButtonConfig( + icon: 'assets/image/wxzy_ico8.png', + title: '盲板抽堵作业', + workType: 'blindboard_work', + menuPerms: 'dashboard:hazardous-work:blind-flange-plugging-operation', + pageBuilder: () => WorkTabMbcdList(), + ), ]; @override @@ -45,137 +93,102 @@ class _WorkTabListPageState extends RouteAwareState { Future _getData() async { final data = await SpecialWorkApi.specialWorkTaskLogTotalCount(); + if (!mounted) return; + if (data['success'] == true) { + final List todoList = data['data'] ?? []; setState(() { - List todoList = data['data']; - for (var todo in todoList) { - if (todo['workType'] == 'hot_work') { - //动火作业 - buttonInfos[0]['unreadCount'] = todo['todoCount']; - } - if (todo['workType'] == 'confinedspace_work') { - //受限空间作业 - buttonInfos[1]['unreadCount'] = todo['todoCount']; - } - if (todo['workType'] == 'high_work') { - // 高处作业 - buttonInfos[2]['unreadCount'] = todo['todoCount']; - } - if (todo['workType'] == 'breakground_work') { - // 断路作业 - buttonInfos[3]['unreadCount'] = todo['todoCount']; - } - if (todo['workType'] == 'hoisting_work') { - // 吊装作业 - buttonInfos[4]['unreadCount'] = todo['todoCount']; - } - if (todo['workType'] == 'cutroad_work') { - // 动土作业 - buttonInfos[5]['unreadCount'] = todo['todoCount']; - } - if (todo['workType'] == 'electricity_work') { - //临时用电作业 - buttonInfos[6]['unreadCount'] = todo['todoCount']; - } - if (todo['workType'] == 'blindboard_work') { - // 盲板抽堵作业 - buttonInfos[7]['unreadCount'] = todo['todoCount']; + for (final todo in todoList) { + final workType = todo['workType']?.toString() ?? ''; + final count = _toInt(todo['todoCount']); + + for (final button in _allButtons) { + if (button.workType == workType) { + button.unreadCount = count; + break; + } } } }); } } - void _handleIconTap(int index) async { - switch (index) { - case 0: - await pushPage(workTabDhList(), context); - break; - case 1: - await pushPage(WorkTabSpaceList(), context); - break; - case 2: - await pushPage(WorkTabGcList(), context); - break; - case 3: - await pushPage(WorkTabDtList(), context); - break; - case 4: - await pushPage(WorkTabDzList(), context); - break; - case 5: - await pushPage(WorkTabDlList(), context); - break; - case 6: - await pushPage(WorkTabLsydList(), context); - break; - case 7: - await pushPage(WorkTabMbcdList(), context); - } + int _toInt(dynamic value) { + if (value == null) return 0; + if (value is int) return value; + if (value is double) return value.toInt(); + return int.tryParse(value.toString()) ?? 0; + } + + Future _handleButtonTap(_WorkButtonConfig config) async { + final page = config.pageBuilder(); + await pushPage(page, context); _getData(); } - // @override - // Widget build(BuildContext context) { - // return Scaffold( - // appBar: MyAppbar(title: '特殊作业'), - // body: SafeArea( - // child: WorkTabIconGrid( - // buttonInfos: buttonInfos, - // onItemPressed: _handleItemPressed, - // ), - // ), - // ); - // } @override Widget build(BuildContext context) { - double bannerHeight = 730 / 1125 * MediaQuery.of(context).size.width; - const double iconSectionHeight = 270.0; - const double iconOverlapBanner = 30.0; // 图标区覆盖 banner 的高度 - return PopScope( - canPop: true, - child: Scaffold( - extendBodyBehindAppBar: true, - appBar: MyAppbar(title: '危险作业', backgroundColor: Colors.transparent), - body: ListView( - physics: const AlwaysScrollableScrollPhysics(), - padding: EdgeInsets.zero, - children: [ - SizedBox( - height: bannerHeight + iconSectionHeight, - child: Stack( - clipBehavior: Clip.none, - children: [ - Positioned( - top: 0, - left: 0, - right: 0, - height: bannerHeight, - child: _buildBannerSection(bannerHeight), - ), - Positioned( - left: 10, - right: 10, - top: bannerHeight - iconOverlapBanner, - height: iconSectionHeight, - child: _buildIconSection(context), - ), - ], - ), + final routeService = RouteService(); + + return AnimatedBuilder( + animation: routeService, + builder: (context, _) { + final visibleButtons = _allButtons.where((item) { + return routeService.hasPerm(item.menuPerms); + }).toList(); + + final double bannerHeight = + 730 / 1125 * MediaQuery.of(context).size.width; + const double iconSectionHeight = 270.0; + const double iconOverlapBanner = 30.0; + + return PopScope( + canPop: true, + child: Scaffold( + extendBodyBehindAppBar: true, + appBar: MyAppbar( + title: '危险作业', + backgroundColor: Colors.transparent, ), - ], - ), - ), + body: ListView( + physics: const AlwaysScrollableScrollPhysics(), + padding: EdgeInsets.zero, + children: [ + SizedBox( + height: bannerHeight + iconSectionHeight, + child: Stack( + clipBehavior: Clip.none, + children: [ + Positioned( + top: 0, + left: 0, + right: 0, + height: bannerHeight, + child: _buildBannerSection(bannerHeight), + ), + Positioned( + left: 10, + right: 10, + top: bannerHeight - iconOverlapBanner, + height: iconSectionHeight, + child: _buildIconSection(context, visibleButtons), + ), + ], + ), + ), + ], + ), + ), + ); + }, ); } - // 构建顶部 Banner Widget _buildBannerSection(double bannerHeight) { return Stack( children: [ - // 背景图片 Image.asset( - "assets/images/wxzy_banner.png", + 'assets/image/wxzy_banner.png', width: MediaQuery.of(context).size.width, height: bannerHeight, fit: BoxFit.fitWidth, @@ -184,68 +197,97 @@ class _WorkTabListPageState extends RouteAwareState { ); } - Widget _buildIconSection(BuildContext context) { + Widget _buildIconSection( + BuildContext context, + List<_WorkButtonConfig> visibleButtons, + ) { return Container( padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 5), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: const [ - BoxShadow(color: Colors.black12, blurRadius: 6, offset: Offset(0, 2)), + BoxShadow( + color: Colors.black12, + blurRadius: 6, + offset: Offset(0, 2), + ), ], ), - child: Column(children: [_buildIconGrid()]), + child: _buildIconGrid(visibleButtons), ); } - Widget _buildIconGrid() { - final List rows = []; - - for (int row = 0; row < 2; row++) { - rows.add( - Padding( - padding: EdgeInsets.only(bottom: row == 0 ? 12 : 0), - child: _buildIconRow(startIndex: row * 4), + Widget _buildIconGrid(List<_WorkButtonConfig> visibleButtons) { + if (visibleButtons.isEmpty) { + return const Center( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 30), + child: Text( + '暂无可用作业入口', + style: TextStyle(color: Colors.grey), + ), + ), + ); + } + + final List rows = []; + const int crossAxisCount = 4; + final int rowCount = (visibleButtons.length / crossAxisCount).ceil(); + + for (int row = 0; row < rowCount; row++) { + final int startIndex = row * crossAxisCount; + final int endIndex = + (startIndex + crossAxisCount) > visibleButtons.length + ? visibleButtons.length + : startIndex + crossAxisCount; + final rowButtons = visibleButtons.sublist(startIndex, endIndex); + + rows.add( + Padding( + padding: EdgeInsets.only(bottom: row == rowCount - 1 ? 0 : 12), + child: Row( + children: rowButtons + .map( + (item) => Expanded( + child: Center( + child: _buildIconButton(item), + ), + ), + ) + .toList(), + ), ), ); - if (row == 0) { - rows.add(SizedBox(height: 12)); - } } return Column(children: rows); } - Widget _buildIconRow({required int startIndex}) { - final List cells = List.generate(4, (i) { - final int idx = startIndex + i; - if (idx < buttonInfos.length) { - return Expanded( - child: Center( - child: _buildIconButton(buttonInfos[idx], idx, context), - ), - ); - } else { - return const Expanded(child: SizedBox.shrink()); - } - }); - - return Row(children: cells); - } - - Widget _buildIconButton( - Map info, - int index, - BuildContext context, - ) { + Widget _buildIconButton(_WorkButtonConfig info) { return IconBadgeButton( - iconPath: info['icon'] ?? '', - title: info['title'] ?? '', - unreadCount: - (info['unreadCount'] ?? 0) is int - ? info['unreadCount'] as int - : int.tryParse('${info['unreadCount']}') ?? 0, - onTap: () => _handleIconTap(index), + iconPath: info.icon, + title: info.title, + unreadCount: info.unreadCount, + onTap: () => _handleButtonTap(info), ); } } + +class _WorkButtonConfig { + final String icon; + final String title; + final String workType; + final String menuPerms; + final Widget Function() pageBuilder; + int unreadCount; + + _WorkButtonConfig({ + required this.icon, + required this.title, + required this.workType, + required this.menuPerms, + required this.pageBuilder, + this.unreadCount = 0, + }); +} \ No newline at end of file diff --git a/lib/pages/home/unit/unit_join_detail_page.dart b/lib/pages/home/unit/unit_join_detail_page.dart index 326665d..39caedd 100644 --- a/lib/pages/home/unit/unit_join_detail_page.dart +++ b/lib/pages/home/unit/unit_join_detail_page.dart @@ -258,29 +258,6 @@ class _UnitJoinDetailPageState extends State { }, ), const Divider(), - - ItemListWidget.singleLineTitleText( - label: '户口所在地:', - isRequired: _isEdit, - hintText: '请输入户口所在地', - text: pd['locationAddress'] ?? '', - isEditable: _isEdit, - onChanged: (value) { - pd['locationAddress'] = value; - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '现住址:', - isRequired: true, - text: pd['currentAddress'] ?? '', - hintText: '请输入现住址', - isEditable: _isEdit, - onChanged: (value) { - pd['currentAddress'] = value; - }, - ), - const Divider(), if (_isEdit || _idCardImgList.isNotEmpty) RepairedPhotoSection( title: '身份证照片', @@ -375,31 +352,6 @@ class _UnitJoinDetailPageState extends State { }, ), const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '婚姻状态:', - isEditable: _isEdit, - text: pd['maritalStatusName'] ?? '请选择', - isRequired: _isEdit, - onTap: () async { - final found = await BottomPicker.show( - context, - items: _hunyinList, - itemBuilder: - (i) => - Text(i['name']!, textAlign: TextAlign.center), - initialIndex: 0, - ); - //FocusHelper.clearFocus(context); - - if (found != null) { - setState(() { - pd['maritalStatusName'] = found['name']; - pd['maritalStatus'] = found['value']; - }); - } - }, - ), - const Divider(), ListItemFactory.createYesNoSection( title: "是否流动人员:", horizontalPadding: 2, diff --git a/lib/pages/user/full_userinfo_page.dart b/lib/pages/user/full_userinfo_page.dart index 9673373..bb49e06 100644 --- a/lib/pages/user/full_userinfo_page.dart +++ b/lib/pages/user/full_userinfo_page.dart @@ -1,3 +1,4 @@ +// 这里保持你的其他 import 不变 import 'dart:convert'; import 'package:file_picker/file_picker.dart'; @@ -22,10 +23,14 @@ import 'package:qhd_prevention/tools/tools.dart'; import 'package:shared_preferences/shared_preferences.dart'; class FullUserinfoPage extends StatefulWidget { - const FullUserinfoPage({super.key, required this.isEidt, required this.isChooseFirm}); + const FullUserinfoPage({ + super.key, + required this.isEidt, + required this.isChooseFirm, + }); final bool isEidt; - final bool isChooseFirm; // 是否选择过企业 + final bool isChooseFirm; @override State createState() => _FullUserinfoPageState(); @@ -39,37 +44,29 @@ class _FullUserinfoPageState extends State { "birthday": "", "gender": "", "nationName": "", - "locationAddress": "", - "currentAddress": "", "culturalLevel": "", "politicalAffiliation": "", - "maritalStatus": "", }; + Map rule = { "name": "请输入姓名", "userIdCard": "请输入身份证号码", "nationName": "请选择民族", - "locationAddress": "请输入户口所在地", - "currentAddress": "请输入现居住地址", - "culturalLevel": "请选择文化程度", "politicalAffiliation": "请选择政治面貌", - "maritalStatus": "请选择婚姻状况", }; - late bool _isEdit; - /// 标记修改 + late bool _isEdit; late bool _isChange = false; String _genderText = ''; String _birthText = ''; String _idValue = ''; String? _userId = SessionService.instance.userId; + List _idCardImgList = []; List _idCartImgIds = []; - /// 是否修改了身份证 bool _isChangeIdCard = false; - List _idCardImgRemoveList = []; List _wenhuachengduList = []; @@ -102,6 +99,7 @@ class _FullUserinfoPageState extends State { _genderText = data['sex'] ?? ''; _birthText = data['birthday'] ?? ''; final eqForeignKey = data['userId']; + await FileApi.getImagePathWithType( eqForeignKey, '', @@ -112,28 +110,27 @@ class _FullUserinfoPageState extends State { _idCardImgList = files.map((item) => item['filePath'].toString()).toList(); _idCartImgIds = files.map((item) => item['id'].toString()).toList(); - // final filePath = fileData.first['filePath'] ?? ''; } }); setState(() { pd = data; - try{ + try { final idCardBase64 = utf8.decode(base64.decode(pd['userIdCard'])); if (idCardBase64.isNotEmpty) { - pd['userIdCard'] =idCardBase64; + pd['userIdCard'] = idCardBase64; + _idValue = idCardBase64; } - }catch(e){ + } catch (e) { print(e); } - }); } } Future _getKeyValues() async { final prefs = await SharedPreferences.getInstance(); - final phone = await prefs.getString("savePhone"); + final phone = prefs.getString("savePhone"); pd['username'] = phone; await BasicInfoApi.getDictValues('wenhuachengdu').then((res) { _wenhuachengduList = res['data']; @@ -141,39 +138,119 @@ class _FullUserinfoPageState extends State { await BasicInfoApi.getDictValues('zhengzhimianmao').then((res) { _zhengzhimianmaoList = res['data']; }); - setState(() { + setState(() {}); + } + void _clearParsedIdCardFields({bool keepInput = true}) { + setState(() { + if (!keepInput) { + pd['userIdCard'] = ''; + } + pd.remove('birthday'); + pd.remove('age'); + pd.remove('gender'); + pd.remove('provinceCode'); + pd.remove('province'); + _genderText = '输入身份证获取'; + _birthText = '输入身份证获取'; }); } + void _applyParsedIdCardInfo(IDCardInfo info, String input) { + setState(() { + pd['userIdCard'] = info.id18 ?? input; + pd['birthday'] = info.birth; + pd['age'] = info.age; + pd['gender'] = info.gender; + pd['provinceCode'] = info.provinceCode; + pd['province'] = info.province; + _genderText = info.gender ?? '未知'; + _birthText = info.birth ?? '未知'; + }); + } + + /// 身份证输入变化 + void _onIdChanged(String value) { + final raw = value.trim().toUpperCase(); + _idValue = raw; + _isChangeIdCard = true; + + setState(() { + pd['userIdCard'] = raw; + }); + + // 只在18位时开始校验 + if (raw.length != 18) { + _clearParsedIdCardFields(keepInput: true); + return; + } + + final info = parseChineseIDCard(raw); + + if (info.isValid) { + setState(() { + pd['userIdCard'] = info.id18 ?? raw; + pd['birthday'] = info.birth; + pd['age'] = info.age; + pd['gender'] = info.gender; + pd['provinceCode'] = info.provinceCode; + pd['province'] = info.province; + _genderText = info.gender ?? '未知'; + _birthText = info.birth ?? '未知'; + }); + } else { + _clearParsedIdCardFields(keepInput: true); + ToastUtil.showNormal(context, info.error ?? '请输入正确身份证号'); + } + } + Future _saveSuccess() async { if (!FormUtils.hasValue(pd, 'faceFiles') && !FormUtils.hasValue(pd, 'userAvatarUrl')) { ToastUtil.showNormal(context, '请上传人脸图片'); return; } + for (String key in rule.keys) { if (!FormUtils.hasValue(pd, key)) { ToastUtil.showNormal(context, rule[key]); return; } } - if (!FormUtils.hasValue(pd, 'userIdCard') || - !FormUtils.hasValue(pd, 'birthday')) { - ToastUtil.showNormal(context, '请输入正确身份证号'); - return ; + + // 保存前再兜底校验一次身份证 + final idRaw = (pd['userIdCard'] ?? '').toString().trim().toUpperCase(); + final idInfo = parseChineseIDCard(idRaw); + + if (!idInfo.isValid) { + ToastUtil.showNormal(context, idInfo.error ?? '请输入正确身份证号'); + return; + } + + // 保存时统一使用标准 18 位 + pd['userIdCard'] = idInfo.id18 ?? idRaw; + pd['birthday'] = idInfo.birth; + pd['age'] = idInfo.age; + pd['gender'] = pd['gender'] ?? idInfo.gender; + pd['provinceCode'] = idInfo.provinceCode; + pd['province'] = idInfo.province; + + if (_genderText.isEmpty) { + _genderText = idInfo.gender ?? ''; + } + if (_birthText.isEmpty) { + _birthText = idInfo.birth ?? ''; } if (idPhotos.length < 2 && !_isChange) { ToastUtil.showNormal(context, '请上传2张身份证照片'); return; } + LoadingDialogHelper.show(); - // 人脸上传 + final signResult = await _checkFaceImage(); - // 证件上传图片 final situationResult = await _checkIDCartImages(); - // 删除服务器图片 final deleteResult = await _checkDeleteImage(); if (signResult && situationResult && deleteResult) { @@ -186,27 +263,29 @@ class _FullUserinfoPageState extends State { if (widget.isChooseFirm || _isChange) { Navigator.pop(context); - }else{ + } else { Navigator.pushReplacement( context, - MaterialPageRoute(builder: (_) => FirmListPage(isBack: false,)), + MaterialPageRoute( + builder: (_) => FirmListPage(isBack: false), + ), ); } - } else { ToastUtil.showNormal(context, res['errMessage'] ?? '保存失败'); } }); - }else{ + } else { ToastUtil.showNormal(context, '保存失败'); LoadingDialogHelper.hide(); } } + Future _checkDeleteImage() async { late bool isSuccess = true; if (_idCardImgRemoveList.isNotEmpty) { final delIds = _idCardImgRemoveList; - try{ + try { await FileApi.deleteImages(delIds).then((result) { if (result['success']) { isSuccess = true; @@ -214,24 +293,23 @@ class _FullUserinfoPageState extends State { isSuccess = false; } }); - }catch(e){ + } catch (e) { LoadingDialogHelper.hide(); } - }else{ + } else { isSuccess = true; } return isSuccess; - } - /// 校验人脸照片上传 Future _checkFaceImage() async { final faceImgPath = pd['faceFiles'] ?? ''; UploadFileType fileType = UploadFileType.userAvatar; late bool isSuccess = true; if (faceImgPath.isNotEmpty) { try { - await FileApi.uploadFile(faceImgPath, fileType, _userId ?? '').then((result) { + await FileApi.uploadFile(faceImgPath, fileType, _userId ?? '') + .then((result) { if (result['success']) { pd['userAvatarUrl'] = result['data']['filePath'] ?? ''; isSuccess = true; @@ -250,10 +328,8 @@ class _FullUserinfoPageState extends State { return isSuccess; } - /// 校验是否需要上传身份证图片 Future _checkIDCartImages() async { late bool isSuccess = true; - // 身份证上传图片 if (idPhotos.isEmpty) { return isSuccess; } @@ -277,69 +353,6 @@ class _FullUserinfoPageState extends State { return isSuccess; } - /// 当身份证输入发生变化时调用(value 为输入框实时值) - void _onIdChanged(String value) { - _idValue = value ?? ''; - _isChangeIdCard = true; - final raw = _idValue.trim().toUpperCase(); - - // 当长度为 15 或 18 时触发解析 - if (raw.length == 15 || raw.length == 18) { - try { - final info = parseChineseIDCard(raw); - if (info.isValid /**&& info.checksumValid*/) { - setState(() { - // 使用 info.id18(标准 18 位)存储身份证号 - pd['userIdCard'] = info.id18 ?? raw; - pd['birthday'] = info.birth; // 格式 YYYY-MM-DD - pd['age'] = info.age; - pd['gender'] = info.gender; // "男"/"女" - pd['provinceCode'] = info.provinceCode; - pd['province'] = info.province; - _genderText = info.gender ?? '未知'; - _birthText = info.birth ?? '未知'; - }); - } else { - // 解析失败或校验位不正确 — 清除解析字段但保留输入 - setState(() { - pd.remove('birthday'); - pd.remove('age'); - pd.remove('gender'); - pd.remove('provinceCode'); - pd.remove('province'); - _genderText = '输入身份证获取'; - _birthText = '输入身份证获取'; - }); - } - } catch (e) { - ToastUtil.showNormal(context, '请输入正确格式身份证号'); - // 出现异常则清除解析字段 - setState(() { - pd.remove('birthday'); - pd.remove('age'); - pd.remove('gender'); - pd.remove('provinceCode'); - pd.remove('province'); - _genderText = '输入身份证获取'; - _birthText = '输入身份证获取'; - }); - } - } else { - // 长度不足时清除解析结果(可按需注释掉保留旧解析) - if (_genderText != '请选择' || _birthText != '请选择') { - setState(() { - pd.remove('birthday'); - pd.remove('age'); - pd.remove('gender'); - pd.remove('provinceCode'); - pd.remove('province'); - _genderText = '输入身份证获取'; - _birthText = '输入身份证获取'; - }); - } - } - } - @override Widget build(BuildContext context) { bool isShow = _isEdit; @@ -359,7 +372,7 @@ class _FullUserinfoPageState extends State { content: '是否放弃修改?', cancelText: '取消', ).then( - (isSure) => { + (isSure) => { if (isSure) {Navigator.pop(context)}, }, ); @@ -376,355 +389,281 @@ class _FullUserinfoPageState extends State { _isEdit = true; }); }, - child: Text( + child: const Text( '修改', style: TextStyle(color: Colors.white, fontSize: 17), ), ), ], ), - body: SafeArea( child: ItemListWidget.itemContainer( horizontal: 5, isShow ? ListView( - children: [ - RepairedPhotoSection( - title: '人脸照片', - inlineSingle: true, - isRequired: _isEdit, - initialMediaPaths: - FormUtils.hasValue(pd, 'userAvatarUrl') - ? [ - '${ApiService.baseImgPath}${pd['userAvatarUrl'] ?? ''}', - ] - : [], - horizontalPadding: _isEdit ? 12 : 0, - inlineImageWidth: 60, - isFaceImage: true, - isEdit: _isEdit, - onChanged: (files) { - if (files.isEmpty) { - return; - } - pd['faceFiles'] = files.first.path; - }, - onAiIdentify: () {}, - // onMediaRemovedForIndex: (index) async { - // final deleFile = pd['userAvatarUrl'] ?? ''; - // if (deleFile.contains(UploadFileType.idCardPhoto.path)) { - // _idCardImgRemoveList.add(deleFile); - // } - // }, + children: [ + RepairedPhotoSection( + title: '人脸照片', + inlineSingle: true, + isRequired: _isEdit, + initialMediaPaths: FormUtils.hasValue(pd, 'userAvatarUrl') + ? [ + '${ApiService.baseImgPath}${pd['userAvatarUrl'] ?? ''}', + ] + : [], + horizontalPadding: _isEdit ? 12 : 0, + inlineImageWidth: 60, + isFaceImage: true, + isEdit: _isEdit, + onChanged: (files) { + if (files.isEmpty) { + return; + } + pd['faceFiles'] = files.first.path; + }, + onAiIdentify: () {}, + ), + if (_isEdit) + ItemListWidget.itemContainer( + const Text( + '温馨提示:该照片为进入项目施工场所口门人脸识别使用', + style: TextStyle(color: Colors.red, fontSize: 10), ), - if (_isEdit) - ItemListWidget.itemContainer( - const Text( - '温馨提示:该照片为进入项目施工场所口门人脸识别使用', - style: TextStyle(color: Colors.red, fontSize: 10), - ), + ), + const Divider(), + ItemListWidget.singleLineTitleText( + label: '姓名:', + isRequired: true, + hintText: '请输入姓名', + text: pd['name'] ?? '', + isEditable: _isEdit, + onChanged: (value) { + pd['name'] = value; + }, + ), + const Divider(), + ItemListWidget.singleLineTitleText( + label: '手机号:', + isRequired: true, + text: pd['username'] ?? '', + isNumericInput: true, + hintText: '请输入手机号', + strongRequired: _isEdit, + isEditable: false, + ), + const Divider(), + ItemListWidget.singleLineTitleText( + label: '身份证:', + isRequired: true, + hintText: '请输入身份证号', + text: pd['userIdCard'] ?? '', + isEditable: _isEdit, + onChanged: (value) { + _onIdChanged(value ?? ''); + }, + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '民族:', + isEditable: _isEdit, + text: pd['nationName'] ?? '请选择', + isRequired: _isEdit, + onTap: () async { + final found = await BottomPicker.show( + context, + items: nationMapList, + itemBuilder: (i) => + Text(i['name']!, textAlign: TextAlign.center), + initialIndex: 0, + ); + + if (found != null) { + setState(() { + pd['nationName'] = found['name']; + pd['nation'] = found['bianma']; + }); + } + }, + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '性别:', + isEditable: false, + text: _genderText, + strongRequired: _isEdit, + isRequired: true, + onTap: () { + showModalBottomSheet( + context: context, + builder: (_) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + title: const Text('男'), + onTap: () { + setState(() { + pd['gender'] = '男'; + _genderText = '男'; + }); + Navigator.pop(context); + }, + ), + ListTile( + title: const Text('女'), + onTap: () { + setState(() { + pd['gender'] = '女'; + _genderText = '女'; + }); + Navigator.pop(context); + }, + ), + ], + ); + }, + ); + }, + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '出生年月:', + isEditable: false, + text: _birthText, + strongRequired: _isEdit, + isRequired: true, + onTap: () {}, + ), + const Divider(), + if (_isEdit || _idCardImgList.isNotEmpty) + RepairedPhotoSection( + title: '身份证照片', + isRequired: _isEdit, + maxCount: 2, + initialMediaPaths: _idCardImgList + .map( + (item) => ApiService.baseImgPath + item, + ) + .toList(), + isEdit: _isEdit, + horizontalPadding: _isEdit ? 12 : 0, + inlineImageWidth: 60, + onChanged: (files) { + idPhotos = files.map((file) => file.path).toList(); + }, + onMediaRemovedForIndex: (index) async { + final deleFile = _idCardImgList[index]; + final deleId = _idCartImgIds[index]; + if (deleFile.contains(UploadFileType.idCardPhoto.path)) { + _idCardImgList.removeAt(index); + _idCartImgIds.removeAt(index); + _idCardImgRemoveList.add(deleId); + } + }, + onAiIdentify: () {}, + ), + if (_isEdit) + ItemListWidget.itemContainer( + const Text( + '温馨提示:用户要上传身份证正反面(身份证照片数量是2张才能进行人员培训)', + style: TextStyle(color: Colors.red, fontSize: 10), + ), + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '文化程度:', + isEditable: _isEdit, + text: pd['culturalLevelName'] ?? '请选择', + isRequired: _isEdit, + onTap: () async { + final found = await BottomPicker.show( + context, + items: _wenhuachengduList, + itemBuilder: (i) => Text( + i['dictLabel']!, + textAlign: TextAlign.center, ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '姓名:', - isRequired: true, - hintText: '请输入姓名', - text: pd['name'] ?? '', - isEditable: _isEdit, - onChanged: (value) { - pd['name'] = value; - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '手机号:', - isRequired: true, - text: pd['username'] ?? '', - isNumericInput: true, - hintText: '请输入手机号', - strongRequired: _isEdit, - isEditable: false, - ), - const Divider(), - // 身份证输入:只使用 onChanged 回调(value 是实时输入框的值) - ItemListWidget.singleLineTitleText( - label: '身份证:', - isRequired: true, - hintText: '请输入身份证号', - text: pd['userIdCard'] ?? '', - isEditable: _isEdit, - onChanged: (value) { - // value 是实时输入框值 - _onIdChanged(value ?? ''); - }, - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '民族:', - isEditable: _isEdit, - text: pd['nationName'] ?? '请选择', - isRequired: _isEdit, - onTap: () async { - final found = await BottomPicker.show( - context, - items: nationMapList, - itemBuilder: - (i) => - Text(i['name']!, textAlign: TextAlign.center), - initialIndex: 0, - ); - //FocusHelper.clearFocus(context); + initialIndex: 0, + ); - if (found != null) { - setState(() { - pd['nationName'] = found['name']; - pd['nation'] = found['bianma']; - }); - } - }, - ), - const Divider(), - // 性别:不可编辑,显示解析结果(也允许手动覆盖) - ItemListWidget.selectableLineTitleTextRightButton( - label: '性别:', - isEditable: false, - text: _genderText, - - strongRequired: _isEdit, - isRequired: true, - onTap: () { - // 允许手动选择覆盖解析结果 - showModalBottomSheet( - context: context, - builder: (_) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - title: const Text('男'), - onTap: () { - setState(() { - pd['gender'] = '男'; - _genderText = '男'; - }); - Navigator.pop(context); - }, - ), - ListTile( - title: const Text('女'), - onTap: () { - setState(() { - pd['gender'] = '女'; - _genderText = '女'; - }); - Navigator.pop(context); - }, - ), - ], - ); - }, - ); - }, - ), - const Divider(), - // 出生年月:显示解析结果,但仍然可以手动修改 - ItemListWidget.selectableLineTitleTextRightButton( - label: '出生年月:', - isEditable: false, - text: _birthText, - strongRequired: _isEdit, - isRequired: true, - onTap: () async { - }, - ), - const Divider(), - - ItemListWidget.singleLineTitleText( - label: '户口所在地:', - isRequired: _isEdit, - hintText: '请输入户口所在地', - text: pd['locationAddress'] ?? '', - isEditable: _isEdit, - onChanged: (value) { - pd['locationAddress'] = value; - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '现住址:', - isRequired: true, - text: pd['currentAddress'] ?? '', - hintText: '请输入现住址', - isEditable: _isEdit, - onChanged: (value) { - pd['currentAddress'] = value; - }, - ), - const Divider(), - if (_isEdit || _idCardImgList.isNotEmpty) - RepairedPhotoSection( - title: '身份证照片', - isRequired: _isEdit, - maxCount: 2, - initialMediaPaths: - _idCardImgList - .map( - (item) => - ApiService.baseImgPath + item, - ) - .toList(), - isEdit: _isEdit, - horizontalPadding: _isEdit ? 12 : 0, - inlineImageWidth: 60, - onChanged: (files) { - idPhotos = files.map((file) => file.path).toList(); - }, - onMediaRemovedForIndex: (index) async { - final deleFile = _idCardImgList[index]; - final deleId = _idCartImgIds[index]; - if (deleFile.contains(UploadFileType.idCardPhoto.path)) { - _idCardImgList.removeAt(index); - _idCartImgIds.removeAt(index); - _idCardImgRemoveList.add(deleId); - } - }, - - onAiIdentify: () { - /* ... */ - }, + if (found != null) { + setState(() { + pd['culturalLevelName'] = found['dictLabel']; + pd['culturalLevel'] = found['dictValue']; + }); + } + }, + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '政治面貌:', + isEditable: _isEdit, + text: pd['politicalAffiliationName'] ?? '请选择', + isRequired: _isEdit, + onTap: () async { + final found = await BottomPicker.show( + context, + items: _zhengzhimianmaoList, + itemBuilder: (i) => Text( + i['dictLabel']!, + textAlign: TextAlign.center, ), - if (_isEdit) - ItemListWidget.itemContainer( - const Text( - '温馨提示:用户要上传身份证正反面(身份证照片数量是2张才能进行人员培训)', - style: TextStyle(color: Colors.red, fontSize: 10), - ), - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '文化程度:', - isEditable: _isEdit, - text: pd['culturalLevelName'] ?? '请选择', - isRequired: _isEdit, - onTap: () async { - final found = await BottomPicker.show( - context, - items: _wenhuachengduList, - itemBuilder: - (i) => Text( - i['dictLabel']!, - textAlign: TextAlign.center, - ), - initialIndex: 0, - ); - //FocusHelper.clearFocus(context); + initialIndex: 0, + ); - if (found != null) { - setState(() { - pd['culturalLevelName'] = found['dictLabel']; - pd['culturalLevel'] = found['dictValue']; - }); - } - }, - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '政治面貌:', - isEditable: _isEdit, - text: pd['politicalAffiliationName'] ?? '请选择', - isRequired: _isEdit, - onTap: () async { - final found = await BottomPicker.show( - context, - items: _zhengzhimianmaoList, - itemBuilder: - (i) => Text( - i['dictLabel']!, - textAlign: TextAlign.center, - ), - initialIndex: 0, - ); - //FocusHelper.clearFocus(context); - - if (found != null) { - setState(() { - pd['politicalAffiliationName'] = found['dictLabel']; - pd['politicalAffiliation'] = found['dictValue']; - }); - } - }, - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '婚姻状态:', - isEditable: _isEdit, - text: pd['maritalStatusName'] ?? '请选择', - isRequired: _isEdit, - onTap: () async { - final found = await BottomPicker.show( - context, - items: _hunyinList, - itemBuilder: - (i) => - Text(i['name']!, textAlign: TextAlign.center), - initialIndex: 0, - ); - //FocusHelper.clearFocus(context); - - if (found != null) { - setState(() { - pd['maritalStatusName'] = found['name']; - pd['maritalStatus'] = found['value']; - }); - } - }, - ), - const Divider(), - ListItemFactory.createYesNoSection( - title: "是否流动人员:", - horizontalPadding: 2, - verticalPadding: 0, - yesLabel: "是", - noLabel: "否", - text: pd['flowFlag'] == 1 ? '是' : '否', - isRequired: true, - isEdit: _isEdit ? (token.isEmpty ? true : false) : false, - groupValue: (pd['flowFlag'] ?? 0) == 1, - onChanged: (val) { - setState(() { - - pd['flowFlag'] = val ? 1 : 0; - }); - }, - ), - const Divider(), - ItemListWidget.singleLineTitleText( - label: '电子邮箱:', - isRequired: false, - isNumericInput: false, - hintText: '请输入电子邮箱', - text: pd['email'] ?? '', - isEditable: _isEdit, - onChanged: (value) { - pd['email'] = value; - }, - ), - const Divider(), - const SizedBox(height: 20), - if (_isEdit) - CustomButton( - text: '保存', - backgroundColor: Colors.blue, - onPressed: () { - _saveSuccess(); - }, - ), - ], - ) + if (found != null) { + setState(() { + pd['politicalAffiliationName'] = + found['dictLabel']; + pd['politicalAffiliation'] = found['dictValue']; + }); + } + }, + ), + const Divider(), + ListItemFactory.createYesNoSection( + title: "是否流动人员:", + horizontalPadding: 2, + verticalPadding: 0, + yesLabel: "是", + noLabel: "否", + text: pd['flowFlag'] == 1 ? '是' : '否', + isRequired: true, + isEdit: _isEdit ? (token.isEmpty ? true : false) : false, + groupValue: (pd['flowFlag'] ?? 0) == 1, + onChanged: (val) { + setState(() { + pd['flowFlag'] = val ? 1 : 0; + }); + }, + ), + const Divider(), + ItemListWidget.singleLineTitleText( + label: '电子邮箱:', + isRequired: false, + isNumericInput: false, + hintText: '请输入电子邮箱', + text: pd['email'] ?? '', + isEditable: _isEdit, + onChanged: (value) { + pd['email'] = value; + }, + ), + const Divider(), + const SizedBox(height: 20), + if (_isEdit) + CustomButton( + text: '保存', + backgroundColor: Colors.blue, + onPressed: () { + _saveSuccess(); + }, + ), + ], + ) : const SizedBox(), ), ), ); } -} +} \ No newline at end of file diff --git a/lib/tools/id_cart_util.dart b/lib/tools/id_cart_util.dart index c526a17..3e585f1 100644 --- a/lib/tools/id_cart_util.dart +++ b/lib/tools/id_cart_util.dart @@ -1,26 +1,27 @@ -// utils/id_card_util.dart import 'dart:core'; class IDCardInfo { final String raw; final bool isValid; final String? error; - final String? id18; // 标准化到18位(若输入15位则自动转换) + final String? id18; + final String? addressCode; final String? provinceCode; final String? province; final DateTime? birthDate; - final String? birth; // YYYY-MM-DD + final String? birth; final int? age; - final String? gender; // '男' / '女' + final String? gender; final bool checksumValid; - final String? constellation; // 星座 - final String? zodiac; // 生肖 + final String? constellation; + final String? zodiac; IDCardInfo({ required this.raw, required this.isValid, this.error, this.id18, + this.addressCode, this.provinceCode, this.province, this.birthDate, @@ -37,6 +38,7 @@ class IDCardInfo { 'isValid': isValid, 'error': error, 'id18': id18, + 'addressCode': addressCode, 'provinceCode': provinceCode, 'province': province, 'birth': birth, @@ -51,14 +53,37 @@ class IDCardInfo { String toString() => toJson().toString(); } -/// 主要调用函数:传入身份证号字符串,返回 IDCardInfo -IDCardInfo parseChineseIDCard(String id) { - final raw = (id ?? '').toString().trim().toUpperCase(); +/// 只校验 18 位身份证号 +IDCardInfo parseChineseIDCard(String? id) { + final raw = _normalizeId(id); + if (raw.isEmpty) { - return IDCardInfo(raw: raw, isValid: false, error: '空字符串', checksumValid: false); + return IDCardInfo( + raw: raw, + isValid: false, + error: '身份证号不能为空', + checksumValid: false, + ); + } + + if (raw.length != 18) { + return IDCardInfo( + raw: raw, + isValid: false, + error: '身份证号长度不正确,应为18位', + checksumValid: false, + ); + } + + if (!RegExp(r'^\d{17}[\dX]$').hasMatch(raw)) { + return IDCardInfo( + raw: raw, + isValid: false, + error: '身份证号格式不正确:前17位必须是数字,最后一位必须是数字或X', + checksumValid: false, + ); } - // 省份码映射(常见) const provinceMap = { '11': '北京市', '12': '天津市', @@ -94,57 +119,79 @@ IDCardInfo parseChineseIDCard(String id) { '71': '台湾省', '81': '香港特别行政区', '82': '澳门特别行政区', - '91': '国外' + '91': '国外', }; - // 校验正则:15 位全数字;18 位前17 数字 + 最后一位数字或 X - final reg15 = RegExp(r'^\d{15}$'); - final reg18 = RegExp(r'^\d{17}[\dX]$'); + final addressCode = raw.substring(0, 6); + final provinceCode = raw.substring(0, 2); + final province = provinceMap[provinceCode]; - String standardized = raw; - bool convertedFrom15 = false; - if (reg15.hasMatch(raw)) { - // 15 位 -> 转 18 位(在第6位后插入 "19"),然后计算校验位 - final prefix17 = raw.substring(0, 6) + '19' + raw.substring(6); - final checkChar = _calcCheckChar(prefix17); - standardized = prefix17 + checkChar; - convertedFrom15 = true; - } else if (reg18.hasMatch(raw)) { - standardized = raw; - } else { + if (province == null) { return IDCardInfo( raw: raw, isValid: false, - error: '身份证格式不正确(不是15位或18位)', + error: '地址码不合法:省份码错误', + id18: raw, + addressCode: addressCode, + provinceCode: provinceCode, checksumValid: false, ); } - // 取出生日期 - final birthStr = standardized.substring(6, 14); // YYYYMMDD - final year = int.tryParse(birthStr.substring(0, 4)); - final month = int.tryParse(birthStr.substring(4, 6)); - final day = int.tryParse(birthStr.substring(6, 8)); + final yearStr = raw.substring(6, 10); + final monthStr = raw.substring(10, 12); + final dayStr = raw.substring(12, 14); - if (year == null || month == null || day == null) { + if (!RegExp(r'^(18|19|20)\d{2}$').hasMatch(yearStr)) { return IDCardInfo( raw: raw, isValid: false, - error: '无法解析出生日期', - id18: standardized, - checksumValid: _verifyCheck(standardized), + error: '年份不合法:必须以18、19或20开头', + id18: raw, + addressCode: addressCode, + provinceCode: provinceCode, + province: province, + checksumValid: false, ); } - // 校验日期是否真实存在(例如闰年等) + if (!RegExp(r'^(0[1-9]|1[0-2])$').hasMatch(monthStr)) { + return IDCardInfo( + raw: raw, + isValid: false, + error: '月份不合法:必须在01到12之间', + id18: raw, + addressCode: addressCode, + provinceCode: provinceCode, + province: province, + checksumValid: false, + ); + } + + if (!RegExp(r'^(0[1-9]|[12]\d|3[01])$').hasMatch(dayStr)) { + return IDCardInfo( + raw: raw, + isValid: false, + error: '日期不合法:必须在01到31之间', + id18: raw, + addressCode: addressCode, + provinceCode: provinceCode, + province: province, + checksumValid: false, + ); + } + + final year = int.parse(yearStr); + final month = int.parse(monthStr); + final day = int.parse(dayStr); + DateTime? birthDate; try { - birthDate = DateTime(year, month, day); - // 额外检查同一天 - if (birthDate.year != year || birthDate.month != month || birthDate.day != day) { - birthDate = null; + final dt = DateTime(year, month, day); + if (dt.year == year && dt.month == month && dt.day == day) { + birthDate = dt; } - } catch (e) { + } catch (_) { birthDate = null; } @@ -152,71 +199,123 @@ IDCardInfo parseChineseIDCard(String id) { return IDCardInfo( raw: raw, isValid: false, - error: '出生日期无效', - id18: standardized, - checksumValid: _verifyCheck(standardized), + error: '出生日期无效:请检查年月日是否真实存在', + id18: raw, + addressCode: addressCode, + provinceCode: provinceCode, + province: province, + checksumValid: false, ); } - // 年龄计算(按生日是否已过来算) - final now = DateTime.now(); - int age = now.year - birthDate.year; - if (now.month < birthDate.month || (now.month == birthDate.month && now.day < birthDate.day)) { - age -= 1; + final seqCode = raw.substring(14, 17); + if (!RegExp(r'^\d{3}$').hasMatch(seqCode)) { + return IDCardInfo( + raw: raw, + isValid: false, + error: '顺序码不合法:第15到17位必须全部为数字', + id18: raw, + addressCode: addressCode, + provinceCode: provinceCode, + province: province, + birthDate: birthDate, + birth: _formatDate(birthDate), + checksumValid: false, + ); } - // 性别:第 17 位(索引 16)为序列码的最后一位,奇数男 偶数女 - final seq = standardized.substring(14, 17); // 3 位序列号 - final seqNum = int.tryParse(seq); - final gender = (seqNum != null && seqNum % 2 == 1) ? '男' : '女'; + final seqNum = int.parse(seqCode); + if (seqNum == 0) { + return IDCardInfo( + raw: raw, + isValid: false, + error: '顺序码不合法:不能为000', + id18: raw, + addressCode: addressCode, + provinceCode: provinceCode, + province: province, + birthDate: birthDate, + birth: _formatDate(birthDate), + checksumValid: false, + ); + } - // 省份 - final provinceCode = standardized.substring(0, 2); - final province = provinceMap[provinceCode] ?? '未知'; + final gender = (seqNum % 2 == 1) ? '男' : '女'; - // 校验位验证 - final checksumValid = _verifyCheck(standardized); - - // 星座与生肖 - final constellation = _calcConstellation(birthDate.month, birthDate.day); - final zodiac = _calcChineseZodiac(birthDate.year); + final checksumValid = _verifyCheck(raw); + if (!checksumValid) { + return IDCardInfo( + raw: raw, + isValid: false, + error: '校验位不正确', + id18: raw, + addressCode: addressCode, + provinceCode: provinceCode, + province: province, + birthDate: birthDate, + birth: _formatDate(birthDate), + age: _calcAge(birthDate), + gender: gender, + checksumValid: false, + constellation: _calcConstellation(birthDate.month, birthDate.day), + zodiac: _calcChineseZodiac(birthDate.year), + ); + } return IDCardInfo( raw: raw, isValid: true, - id18: standardized, + id18: raw, + addressCode: addressCode, provinceCode: provinceCode, province: province, birthDate: birthDate, - birth: '${birthDate.year.toString().padLeft(4, '0')}-${birthDate.month.toString().padLeft(2, '0')}-${birthDate.day.toString().padLeft(2, '0')}', - age: age, + birth: _formatDate(birthDate), + age: _calcAge(birthDate), gender: gender, - checksumValid: checksumValid, - constellation: constellation, - zodiac: zodiac, + checksumValid: true, + constellation: _calcConstellation(birthDate.month, birthDate.day), + zodiac: _calcChineseZodiac(birthDate.year), ); } -// ---- 辅助函数 ---- +String _normalizeId(String? id) { + return (id ?? '') + .trim() + .replaceAll(' ', '') + .replaceAll(' ', '') + .replaceAll('X', 'X') + .toUpperCase(); +} + +String _formatDate(DateTime d) { + return '${d.year.toString().padLeft(4, '0')}-' + '${d.month.toString().padLeft(2, '0')}-' + '${d.day.toString().padLeft(2, '0')}'; +} + +int _calcAge(DateTime birthDate) { + final now = DateTime.now(); + var age = now.year - birthDate.year; + if (now.month < birthDate.month || + (now.month == birthDate.month && now.day < birthDate.day)) { + age -= 1; + } + return age; +} -// 计算 17 位前缀的校验码(返回 '0'-'9' 或 'X') String _calcCheckChar(String id17) { - // 权重 const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; - // 校验码映射 remainder -> char const checkMap = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; int sum = 0; for (var i = 0; i < 17; i++) { - final ch = id17[i]; - final n = int.tryParse(ch) ?? 0; + final n = int.parse(id17[i]); sum += n * weights[i]; } - final mod = sum % 11; - return checkMap[mod]; + return checkMap[sum % 11]; } -// 验证完整 18 位身份证的校验位是否正确 bool _verifyCheck(String id18) { if (id18.length != 18) return false; final id17 = id18.substring(0, 17); @@ -225,15 +324,23 @@ bool _verifyCheck(String id18) { return expected == actual; } -// 计算星座(西方) String _calcConstellation(int month, int day) { const names = [ - '摩羯座', '水瓶座', '双鱼座', '白羊座', '金牛座', '双子座', - '巨蟹座', '狮子座', '处女座', '天秤座', '天蝎座', '射手座' + '摩羯座', + '水瓶座', + '双鱼座', + '白羊座', + '金牛座', + '双子座', + '巨蟹座', + '狮子座', + '处女座', + '天秤座', + '天蝎座', + '射手座' ]; const startDays = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]; - // 月份从1开始 - final idx = (month - 1); + final idx = month - 1; if (day < startDays[idx]) { return names[(idx + 11) % 12]; } else { @@ -241,13 +348,9 @@ String _calcConstellation(int month, int day) { } } -// 计算生肖(中国农历生肖按公历年对照,简化算法) String _calcChineseZodiac(int year) { - const zodiacs = [ - '鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪' - ]; - // 1900 是鼠年(可以用任意基准) + const zodiacs = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪']; final idx = (year - 1900) % 12; final i = idx < 0 ? (idx + 12) % 12 : idx; return zodiacs[i]; -} +} \ No newline at end of file