From 9376cb6acdd59e26b548f8216dba3e2767190f79 Mon Sep 17 00:00:00 2001 From: xufei <727302827@qq.com> Date: Wed, 15 Apr 2026 17:41:33 +0800 Subject: [PATCH 1/3] =?UTF-8?q?2026.4.15=20=E9=87=8D=E7=82=B9=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/images/upload.png | Bin 0 -> 235 bytes lib/constants/app_enums.dart | 27 +- lib/customWidget/single_images_viewer.dart | 147 +++ lib/http/modules/key_tasks_api.dart | 39 + .../key_taskes_check_confirm_page.dart | 533 ++++++++++ .../key_taskes_danger_page.dart | 914 ++++++++++++++++++ .../key_taskes_detail_widget.dart | 644 ++++++------ .../key_taskes_onlylook_detail_page.dart | 5 +- .../keyTasks/key_tasks_check_list_page.dart | 387 ++++++++ .../home/keyTasks/key_tasks_tab_page.dart | 3 +- lib/services/SessionService.dart | 1 + lib/tools/MultiTextFieldWithTitle.dart | 122 ++- 12 files changed, 2472 insertions(+), 350 deletions(-) create mode 100644 assets/images/upload.png create mode 100644 lib/customWidget/single_images_viewer.dart create mode 100644 lib/pages/home/keyTasks/keyTasksDetail/key_taskes_check_confirm_page.dart create mode 100644 lib/pages/home/keyTasks/keyTasksDetail/key_taskes_danger_page.dart create mode 100644 lib/pages/home/keyTasks/key_tasks_check_list_page.dart diff --git a/assets/images/upload.png b/assets/images/upload.png new file mode 100644 index 0000000000000000000000000000000000000000..fcb982bc22060b488f48c0c6b3409e2b4038f3d0 GIT binary patch literal 235 zcmeAS@N?(olHy`uVBq!ia0vp^av;pY3?xs=ZJr3E6a#!hT!Hj|yx_dz>z_bHTqQw% z!3_2n1R4(H8w4m^+FJJ*D4Or-;us=vIe7tJ0-uq?L+Q0aZWFIXZ9TydS#?oMH#H^m zX{ehASHqjoGeGi8sDq=0{E8CMfXgfr@+Tr%lWa|Y=CBsnRWnVPz}4_MQvA`A@&z9y z3qGwDVNG<%u$*vy3m2n^L*wK}Ow4&~D(*ZCvWwNO@$EjO1+<#M)78&qol`;+0MN2w A761SM literal 0 HcmV?d00001 diff --git a/lib/constants/app_enums.dart b/lib/constants/app_enums.dart index 4fa2317..c8ec46b 100644 --- a/lib/constants/app_enums.dart +++ b/lib/constants/app_enums.dart @@ -383,6 +383,28 @@ enum UploadFileType { /// 在线学习考试签字 - 类型: '166', 路径: 'online_learning_exam_signature' onlineLearningExamSignature('166', 'online_learning_exam_signature'), + + /// 重点工程安全管理协议 - 类型: '168', 路径: 'key_project_safety_management_agreement' + keyProjectSafetyManagementAgreement('168', 'key_project_safety_management_agreement'), + + /// 重点工程发起情况图片 - 类型: '169', 路径: 'key_project_initiation_image' + keyProjectInitiationImage('169', 'key_project_initiation_image'), + + /// 重点工程隐患图片 - 类型: '172', 路径: 'key_projects_hidden_dangers_Pictures' + keyProjectsHiddenDangersPictures('172', 'key_projects_hidden_dangers_pictures'), + + /// 重点工程隐患视频 - 类型: '173', 路径: 'key_projects_hidden_dangers_video' + keyProjectsHiddenDangersVideo('173', 'key_projects_hidden_dangers_video'), + + /// 重点工程签字 - 类型: '175', 路径: 'key_homework_signature_inspector' + keyHomeworkSignatureInspector('175', 'key_homework_signature_inspector'), + + /// 重点工程确认签字 - 类型: '176', 路径: 'key_homework_defendant' + keyHomeworkDefendant('176', 'key_homework_defendant'), + + /// 重点工程确认附件 - 类型: '177', 路径: 'key_homework_confirmer' + keyHomeworkConfirmer('177', 'key_homework_confirmer'), + /// 人脸识别图片上传 - 类型: '300', 路径: 'facial_recognition_images' facialRecognitionImages('300', 'facial_recognition_images'), @@ -477,10 +499,9 @@ enum UploadFileType { /// 封闭区域人员申请人签字 - 类型: '609', 路径: 'enclosed_area_personnel_applicant_signature' enclosedAreaPersonnelApplicantSignature('609', 'enclosed_area_personnel_applicant_signature'), /// 封闭区域车辆申请人签字 - 类型: '610', 路径: 'enclosed_area_vehicle_applicant_signature' - enclosedAreaVehicleApplicantSignature('610', 'enclosed_area_vehicle_applicant_signature'), + enclosedAreaVehicleApplicantSignature('610', 'enclosed_area_vehicle_applicant_signature'); + - /// 重点工程安全管理协议 - 类型: '168', 路径: 'key_project_safety_management_agreement' - keyProjectSafetyManagementAgreement('168', 'key_project_safety_management_agreement'); const UploadFileType(this.type, this.path); diff --git a/lib/customWidget/single_images_viewer.dart b/lib/customWidget/single_images_viewer.dart new file mode 100644 index 0000000..218fc01 --- /dev/null +++ b/lib/customWidget/single_images_viewer.dart @@ -0,0 +1,147 @@ +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:photo_view/photo_view.dart'; +import 'package:photo_view/photo_view_gallery.dart'; +import 'package:qhd_prevention/pages/my_appbar.dart'; + + +class SingleImagesViewer extends StatefulWidget { + final String imageUrl; + /// 可选:多张图片列表。如果需要列表的话,imageUrl可以传空 + final List? imageUrls; + /// 可选:初始显示页(默认 0) + final int initialIndex; + + const SingleImagesViewer({ + Key? key, + required this.imageUrl, + this.imageUrls, + this.initialIndex = 0, + }) : super(key: key); + + @override + State createState() => _SingleImagesViewerState(); +} + +class _SingleImagesViewerState extends State { + late final List _urls; + late final PageController _pageController; + int _currentIndex = 0; + + @override + void initState() { + super.initState(); + // 优先使用 imageUrls + if (widget.imageUrls != null && widget.imageUrls!.isNotEmpty) { + _urls = widget.imageUrls!; + } else { + _urls = [widget.imageUrl]; + } + + _currentIndex = (widget.initialIndex >= 0 && widget.initialIndex < _urls.length) + ? widget.initialIndex + : 0; + _pageController = PageController(initialPage: _currentIndex); + } + + ImageProvider _providerFromUrl(String imageUrl) { + final lower = imageUrl.toLowerCase(); + if (lower.startsWith('http')) { + return NetworkImage(imageUrl); + } else if (imageUrl.startsWith('assets/') || + imageUrl.startsWith('package:') || + imageUrl.startsWith('packages/')) { + return AssetImage(imageUrl); + } else { + if (!kIsWeb) { + try { + final file = File(imageUrl); + if (file.existsSync()) { + return FileImage(file); + } else { + return AssetImage(imageUrl); + } + } catch (e) { + return AssetImage(imageUrl); + } + } else { + return AssetImage(imageUrl); + } + } + } + + @override + void dispose() { + _pageController.dispose(); + super.dispose(); + } + + Color _bgColor() => Colors.black.withOpacity(0.9); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: _bgColor(), + appBar: MyAppbar( + isBack: false, + actions: [ + IconButton( + onPressed: () => Navigator.of(context).pop(), + icon: const Icon( + Icons.close, + color: Colors.white, + size: 40, + ), + ), + ], + backgroundColor: _bgColor(), + title: '', + ), + body: Stack( + children: [ + PhotoViewGallery.builder( + pageController: _pageController, + itemCount: _urls.length, + onPageChanged: (index) => setState(() => _currentIndex = index), + builder: (context, index) { + final url = _urls[index]; + return PhotoViewGalleryPageOptions( + imageProvider: _providerFromUrl(url), + minScale: PhotoViewComputedScale.contained, + maxScale: PhotoViewComputedScale.covered * 2, + onTapUp: (context, details, controllerValue) { + Navigator.of(context).pop(); + }, + ); + }, + backgroundDecoration: BoxDecoration(color: _bgColor()), + // enableRotation: false, // 如果需要可打开旋转 + loadingBuilder: (context, progress) => const Center( + child: CircularProgressIndicator(), + ), + ), + + // 页码指示 + if (_urls.length > 1) + Positioned( + right: 12, + top: 12 + MediaQuery.of(context).padding.top, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.45), + borderRadius: BorderRadius.circular(16), + ), + child: Text( + '${_currentIndex + 1} / ${_urls.length}', + style: const TextStyle(color: Colors.white, fontSize: 14), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/http/modules/key_tasks_api.dart b/lib/http/modules/key_tasks_api.dart index 9921a2d..cbacb68 100644 --- a/lib/http/modules/key_tasks_api.dart +++ b/lib/http/modules/key_tasks_api.dart @@ -56,4 +56,43 @@ class KeyTasksApi { } + /// 安全环保检查分页 + static Future> getKeyTasksSafetyEnvironmentalInspectionList(Map data) { + return HttpManager().request( + '${ApiService.basePath}/keyProject', + '/safetyEnvironmentalInspection/list', + method: Method.post, + data: { + ...data + }, + ); + } + + /// 安全环保检查详情. + static Future> getKeyTasksSafetyEnvironmentalInspectionDetail(String id) { + return HttpManager().request( + '${ApiService.basePath}/keyProject', + '/safetyEnvironmentalInspection/$id', + method: Method.get, + data: { + // ...data + }, + ); + } + + + /// 安全环保检查确认 + static Future> setKeyTasksCheckConfirm(Map data) { + return HttpManager().request( + '${ApiService.basePath}/keyProject', + '/safetyEnvironmentalInspectionDefend/affirm', + method: Method.post, + data: { + ...data + }, + ); + } + + + } \ No newline at end of file diff --git a/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_check_confirm_page.dart b/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_check_confirm_page.dart new file mode 100644 index 0000000..80ff2a1 --- /dev/null +++ b/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_check_confirm_page.dart @@ -0,0 +1,533 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:qhd_prevention/constants/app_enums.dart'; +import 'package:qhd_prevention/customWidget/DocumentPicker.dart'; +import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart'; +import 'package:qhd_prevention/customWidget/custom_button.dart'; +import 'package:qhd_prevention/customWidget/item_list_widget.dart'; +import 'package:qhd_prevention/customWidget/single_image_viewer.dart'; +import 'package:qhd_prevention/customWidget/toast_util.dart'; +import 'package:qhd_prevention/http/modules/file_api.dart'; +import 'package:qhd_prevention/http/modules/key_tasks_api.dart'; +import 'package:qhd_prevention/http/modules/safety_check_api.dart'; +import 'package:qhd_prevention/pages/home/keyTasks/keyTasksDetail/key_taskes_detail_widget.dart'; +import 'package:qhd_prevention/pages/mine/mine_sign_page.dart'; +import 'package:qhd_prevention/pages/my_appbar.dart'; +import 'package:qhd_prevention/services/SessionService.dart'; +import 'package:qhd_prevention/tools/tools.dart'; + +class KeyTaskesCheckConfirmPage extends StatefulWidget { + const KeyTaskesCheckConfirmPage({ + super.key, + required this.id, + required this.inspectionId, + required this.handleType, + }); + + final String id; + final String inspectionId; + final SafeCheckDetailMode handleType; + + @override + State createState() => _KeyTaskesCheckConfirmPageState(); +} + +class _KeyTaskesCheckConfirmPageState extends State { + bool _isEdit = false; // 禁止修改 + /// 被检查单位相关信息 + Map personUnderInspection = { + 'departmentId': '', + 'departmentName': '', + 'userName': '', + 'userId': '', + }; + + // 被检查确认的人员 + late Map inspectedPartyConfirmation = {}; + + List signImages = []; + List signTimes = []; // 签字时间列表 +/// 附件 + late SelectedFile? choosefile = null; + /// 检查人员核实/被检查人申辩 + late bool chooseCheckType = false; + Map checkData = {}; + late var form = null; + + @override + void initState() { + // TODO: implement initState + super.initState(); + _getDetail(); + } + + + + /// 检查人核实编辑 + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: MyAppbar(title: "被检查人确认/申辩", actions: []), + body: SafeArea( + child: ListView( + children: [ + Container( + color: Colors.white, + child: Column( + children: [ + // if (form != null) + KeyTaskesDetailWidget( + inspectionId: widget.inspectionId, + handleType: widget.handleType, + ), + _personUnderInspectionConfirmWidget(), + + const Divider(), + const SizedBox(height: 20), + _statusButtons(), + const SizedBox(height: 20), + ], + ), + ), + + + ], + ), + ), + ); + } + + Widget _personSignItem(Map item, int index) { + return SizedBox( + child: Column( + children: [ + Column( + children: [ + ItemListWidget.multiLineTitleTextField( + label: '检查人意见:', + isEditable: false, + text: item['userRemarks'] ?? '', + ), + const Divider(), + if (FormUtils.hasValue(item, 'signature')) + ItemListWidget.OneRowImageTitle( + label: '检查人签字', + onTapCallBack: (path) { + presentOpaque(SingleImageViewer(imageUrl: path), context); + }, + imgPath: item['signature'], + ), + ], + ), + ], + ), + ); + } + + Widget _personUnderInspectionConfirmWidget() { + return Column( + children: [ + Column( + children: [ + const Divider(), + ListItemFactory.createBuildSimpleSection('被检查单位现场负责人情况'), + // if (form != null && int.parse('${form['hiddenNumber'] ?? '0'}') > 0) ...[ + ListItemFactory.createYesNoSection( + title: '是否申辩:', + groupValue: !chooseCheckType, + yesLabel: '否', + noLabel: '是', + isEdit: true, + isRequired: true, + horizontalPadding: 0, + verticalPadding: 0, + text: '', + onChanged: (val) { + setState(() { + chooseCheckType = !val; + }); + }, + ), + const Divider(), + if (chooseCheckType) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ItemListWidget.multiLineTitleTextField( + label: '申辩说明', + isEditable: true, + hintText: '请输入申辩说明', + onChanged: (val) { + setState(() { + checkData['content'] = val; + }); + }, + ), + const Divider(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ItemListWidget.itemContainer( + ListItemFactory.headerTitle('申辩附件:', isRequired: false), + ), + Padding( + padding: const EdgeInsets.only(right: 15), + child: uploadFileButton(), + ) + ], + ), + + if (choosefile != null) + ...[ + Padding(padding: EdgeInsetsGeometry.only(left: 15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(height: 10), + Icon(Icons.file_copy_outlined, color: Colors.grey,size: 50,), + SizedBox(height: 5), + Text(choosefile!.name), + SizedBox(height: 10), + ], + ),), + ], + const Divider(), + + // const Divider(), + ], + ), + // ], + + ItemListWidget.itemContainer( + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ListItemFactory.headerTitle('签字', isRequired: true), + CustomButton( + text: '手写签字', + height: 36, + backgroundColor: Colors.blue, + onPressed: () { + _sign(); + }, + ), + ], + ), + ), + if (signImages.isNotEmpty) _signListWidget(), + ], + ), + ], + ); + } + + /// 被检查人选择上传附件 + Widget uploadFileButton() { + return GestureDetector( + onTap: () async{ + final List picked = await DocumentPicker.showPickerModal( + context, + maxAssets: 1, + maxSizeInBytes: 20 * 1024 * 1024, + allowedExtensions: ['pdf'], + allowMultipleFiles: false, + // showPhotoSelect: false, + ); + + if (picked.isNotEmpty && picked.first.path != null) { + setState(() { + choosefile = picked.first; + }); + } + + }, + child: Container( + width: choosefile != null ? 120 : 100, + height: 30, + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(4), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset('assets/images/upload.png', width: 15, height: 15), + const SizedBox(width: 5), + Text( + choosefile != null ? '重新选择附件' : '上传附件', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ); + } + + /// 检查人核实编辑 + Widget _signListWidget() { + return Column( + children: + signImages.map((path) { + return Column( + children: [ + const SizedBox(height: 15), + // const Divider(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + GestureDetector( + child: // 用一个 ConstrainedBox 限制最大尺寸,并改为 BoxFit.contain + ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 200, + maxHeight: 150, + ), + child: Image.file( + File(path), + // 改为完整显示 + fit: BoxFit.contain, + ), + ), + onTap: () { + presentOpaque( + SingleImageViewer(imageUrl: path), + context, + ); + }, + ), + Column( + children: [ + Container( + padding: const EdgeInsets.only(right: 5), + child: CustomButton( + text: 'X', + height: 30, + padding: const EdgeInsets.symmetric(horizontal: 10), + backgroundColor: Colors.red, + onPressed: () { + setState(() { + signImages.remove(path); + }); + }, + ), + ), + const SizedBox(height: 80), + ], + ), + ], + ), + ], + ); + }).toList(), + ); + } + + Widget _statusButtons() { + final List buttons = []; + final List buttonRowChildren = []; + + // buttons.add( + // CustomButton( + // text: '取消', + // buttonStyle: ButtonStyleType.secondary, + // backgroundColor: Colors.blue, + // onPressed: () { + // Navigator.pop(context); + // }, + // ), + // ); + buttons.add( + CustomButton( + text: '确定', + backgroundColor: Colors.blue, + onPressed: _checkPersonSubmit, + ), + ); + for (int i = 0; i < buttons.length; i++) { + buttonRowChildren.add( + Expanded(child: SizedBox(height: 40, child: buttons[i])), + ); + if (i != buttons.length - 1) { + buttonRowChildren.add(const SizedBox(width: 10)); + } + } + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: buttonRowChildren, + ); + } + + + Widget _detailWidget() { + return Column( + children: [ + if (inspectedPartyConfirmation.isNotEmpty) + Column( + children: [ + const Divider(), + ListItemFactory.createBuildSimpleSection('检查人员意见'), + SizedBox(height: 5), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: inspectedPartyConfirmation.length, + itemBuilder: (context, index) { + return _personSignItem(inspectedPartyConfirmation[index], index); + }, + ), + ], + ), + ], + ); + } + + Future _getDetail() async { + // try { + // LoadingDialogHelper.show(); + // final result = await SafetyCheckApi.safeCheckDetail(widget.inspectionId); + // LoadingDialogHelper.hide(); + // if (result != null) { + // setState(() { + // final data = result['data']; + // form = data; + // checkData = data['inspectedPartyConfirmation'] ?? {}; + // }); + // } + // } catch (e) { + // LoadingDialogHelper.hide(); + // ToastUtil.showNormal(context, '详情获取失败'); + // } + } + + /// 签字 + Future _sign() async { + await NativeOrientation.setLandscape(); + final path = await Navigator.push( + context, + MaterialPageRoute(builder: (context) => MineSignPage()), + ); + await NativeOrientation.setPortrait(); + if (path != null) { + final now = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()); + setState(() { + signImages = []; + signTimes = []; + signImages.add(path); + signTimes.add(now); + }); + } + } + + // 检查人核实提交 + Future _checkPersonSubmit() async { + if (chooseCheckType) { + if (!FormUtils.hasValue(checkData, 'content')) { + ToastUtil.showNormal(context, '请输入申辩说明'); + return; + } + } + if (signImages.isEmpty) { + ToastUtil.showNormal(context, '请签字'); + return; + } + LoadingDialogHelper.show(); + + printLongString(jsonEncode(SessionService.instance.accountId)); + final checkSign = await _checkSignature(); + final checkFile = await _checkFileUpload(); + + if (checkSign && checkFile) { + + // checkData['status'] = 1; + checkData['signatureTime'] = signTimes.first; + checkData['isDefend'] = chooseCheckType ? 0 : 1; + checkData['inspectionId'] = widget.inspectionId; + try { + final result = await KeyTasksApi.setKeyTasksCheckConfirm(checkData); + if (result['success']) { + LoadingDialogHelper.hide(); + ToastUtil.showNormal(context, '提交成功'); + Navigator.of(context).pop(); + } else { + LoadingDialogHelper.hide(); + ToastUtil.showNormal(context, '提交失败:${result['errMessage']}'); + } + } catch (e) { + LoadingDialogHelper.hide(); + ToastUtil.showNormal(context, '提交异常:$e'); + } + } + } + + /// 校验是否有签字需要上传 + Future _checkSignature() async { + UploadFileType fileType = + UploadFileType.keyHomeworkDefendant; + late bool isSuccess = true; + if (signImages.isNotEmpty) { + try { + await FileApi.uploadFile(signImages.first, fileType, '').then((result) { + if (result['success']) { + // 检查人签字 + checkData['defendantSign'] = result['data']['filePath'] ?? ''; + checkData['signatureTime'] = signTimes.first; + isSuccess = true; + } else { + LoadingDialogHelper.hide(); + ToastUtil.showNormal(context, '签名上传失败'); + isSuccess = false; + } + }); + } catch (e) { + LoadingDialogHelper.hide(); + ToastUtil.showNormal(context, '签名上传失败'); + isSuccess = false; + } + } + + return isSuccess; + } + + /// 校验是否有文件需要上传 + Future _checkFileUpload() async { + UploadFileType fileType = + UploadFileType.keyHomeworkConfirmer; + late bool isSuccess = true; + final choosefile = this.choosefile; + if (choosefile != null) { + try { + await FileApi.uploadFiles([choosefile.path ?? ''], fileType, checkData['inspectionId'] ?? '').then((result) { + if (result['success']) { + // 检查人签字 + checkData['fileUrl'] = result['data']['filePath'] ?? ''; + isSuccess = true; + } else { + LoadingDialogHelper.hide(); + ToastUtil.showNormal(context, '签名上传失败'); + isSuccess = false; + } + }); + } catch (e) { + LoadingDialogHelper.hide(); + ToastUtil.showNormal(context, '签名上传失败'); + isSuccess = false; + } + }else{ + isSuccess = true; + } + + return isSuccess; + } + + + + + + + +} diff --git a/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_danger_page.dart b/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_danger_page.dart new file mode 100644 index 0000000..2ebe0ab --- /dev/null +++ b/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_danger_page.dart @@ -0,0 +1,914 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:intl/intl.dart'; +import 'package:qhd_prevention/constants/app_enums.dart'; +import 'package:qhd_prevention/customWidget/BaiDuMap/map_webview_page.dart'; +import 'package:qhd_prevention/customWidget/DangerPartsPicker.dart'; +import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart'; +import 'package:qhd_prevention/customWidget/MultiDictValuesPicker.dart'; +import 'package:qhd_prevention/customWidget/bottom_picker_two.dart'; +import 'package:qhd_prevention/customWidget/center_multi_picker.dart'; +import 'package:qhd_prevention/customWidget/custom_button.dart'; +import 'package:qhd_prevention/customWidget/department_person_picker.dart'; +import 'package:qhd_prevention/customWidget/department_picker_two.dart'; +import 'package:qhd_prevention/customWidget/item_list_widget.dart'; +import 'package:qhd_prevention/customWidget/photo_picker_row.dart'; +import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.dart'; +import 'package:qhd_prevention/customWidget/toast_util.dart'; +import 'package:qhd_prevention/http/ApiService.dart'; +import 'package:qhd_prevention/http/modules/auth_api.dart'; +import 'package:qhd_prevention/http/modules/hidden_danger_api.dart'; +import 'package:qhd_prevention/http/modules/safety_check_api.dart'; +import 'package:qhd_prevention/pages/my_appbar.dart'; +import 'package:qhd_prevention/services/SessionService.dart'; +import 'package:qhd_prevention/tools/tools.dart'; + +class KeyTaskesDangerPage extends StatefulWidget { + const KeyTaskesDangerPage({ + super.key, + required this.initData, + required this.inspectionId, + required this.isEdit, + this.isAssignment = false, + required this.personList, + this.autoSaveTime = 0, + this.corpId = '', + + }); + final String inspectionId; + final bool isEdit; + final dynamic initData; + /// 被检查人单位Id + final String corpId; + // 是否指派 + final bool isAssignment; + // 隐患发现人(包括自己和检查人员) + final List personList; + final int autoSaveTime; + + @override + State createState() => _KeyTaskesDangerPageState(); +} + +class _KeyTaskesDangerPageState extends State { + /// 隐患确认人 + Map addData = { + "hiddenId": "", + "source": 5, + "foreignKey": "", + "isRelated": '0', //是否相关方 + "corpId": "", + "corpName": "", + "hiddenDesc": "", //隐患描述 + "hiddenPart": "", //隐患部位 + "hiddenLevel": "", //隐患级别 + "hiddenLevelName": "", //隐患级别名称 + "hiddenType": "", //隐患类型 + "hiddenTypeName": "", //隐患类型名称 + "hiddenType2": "", //隐患类型2 + "hiddenType2Name": "", //隐患类型2翻译 + "longitude": "", + "latitude": "", + "positionDesc": "", //隐患位置描述 + "creatorId": "", //发现人(主) + "creatorName": "", //发现人名称(主) + "hiddenFindDept": "", //隐患发现部门(主) + "hiddenFindDeptName": "", //隐患发现部门名称(主) + "hiddenFindTime": "", //隐患发现时间 + "confirmDeptId": "", //确认人部门 + "confirmDeptName": "", //确认人部门名称 + "confirmUserId": "", //确认人 + "confirmUserName": "", //确认人名称 + "rectificationType": "2", //整改类型 1立即整改 2延期整改 + "rectificationDeadline": "", //整改期限(整改截至日期) + "rectificationDescr": "", //描述 + "rectificationDeptId": "", //隐患整改部门 + "rectificationDeptName": "", //隐患整改部门名称 + "rectificationUserId": "", //整改人 + "rectificationUserName": "", //整改人名称 + "checkUserId": "", //验收人 + "checkUserName": "", //验收人名称 + "checkDeptId": "", //验收部门 + "checkDeptName": "", //验收部门名称 + + "hiddenJson": SessionService.instance.hiddenJson, //隐患流程JSON + "isAi": 0, //是否AI识别 ai确认 0否1是 + "legalBasis": "", //法律依据 + "projectId": "", //项目id + "projectName": "", //项目名称 + + "aiBatch": "", //AI批次 + "hiddenImgAddCmds": [], + + "hiddenUserId": "", //整改id(整改图片反的id) + "hiddenPartName": "", //隐患部位名称 + + 'hiddenFindUserdList':[],//隐患发现人多选 + 'hiddenFindUserdName':'',//隐患发现人多选名字 + + }; + + + + // 是否是修改 + late bool _isRevise = false; + late bool _isLoading = true; + late bool _showRectification = true; + late List _HazardPersonlist = []; + + /// 隐患确认人信息 + Map _hazarder = {}; + + // 存储各单位的人员列表 + List> _personCache = []; + + List _dangerImages = []; + List _dangerVideos = []; + List _initFileList = []; + List _removeFileList = []; + + String buMenId = ""; + String buMenName = ""; + String responsibleId = ""; + String responsibleName = ""; + + @override + void initState() { + // TODO: implement initState + super.initState(); + if (widget.initData != null) { + addData = widget.initData; + _dangerImages = addData['imgs'] ?? []; + _dangerVideos = addData['videos'] ?? []; + } else { + addData['hiddenFindTime'] = DateFormat( + 'yyyy-MM-dd HH:mm:ss', + ).format(DateTime.now()); + } + if (widget.isEdit) { + _getUserData(); + } + _isRevise = FormUtils.hasValue(addData, 'id'); + if (_isRevise) { + _getHiddenDetail(); + } else { + setState(() { + _isLoading = false; + }); + } + if (widget.isAssignment) { + _getHazardPersonlist(); + } + } + + Future _getHazardPersonlist() async { + try { + LoadingDialogHelper.show(); + final raw = await HiddenDangerApi.getHazardPersonlist(); + if (raw['success']) { + setState(() { + _HazardPersonlist = raw['data'] as List; + print(_HazardPersonlist); + }); + LoadingDialogHelper.hide(); + } else { + ToastUtil.showNormal(context, "获取列表失败"); + LoadingDialogHelper.hide(); + } + } catch (e) { + // 出错时可以 Toast 或者在页面上显示错误状态 + print('加载首页数据失败:$e'); + LoadingDialogHelper.hide(); + } + } + + Future _getHiddenDetail() async { + // LoadingDialogHelper.show(); + // final result = await HiddenDangerApi.getDangerDetail(widget.initData['id']); + // LoadingDialogHelper.hide(); + // if (result['success']) { + // final data = result['data']; + // setState(() { + // addData = data; + _getHiddenImages(); + // }); + // } + } + + /// 获取隐患照片 + Future _getHiddenImages() async { + final result = await FileApi.getImagePathWithType( + addData['hiddenId'] ?? '', + '', + UploadFileType.keyProjectsHiddenDangersPictures, + ); + if (result['success']) { + final data = result['data']; + for (Map item in data) { + final filePath = item['filePath'] ?? ''; + _initFileList.add(item); + _dangerImages.add(ApiService.baseImgPath + filePath); + } + } + final resultVideo = await FileApi.getImagePathWithType( + addData['hiddenId'] ?? '', + '', + UploadFileType.keyProjectsHiddenDangersVideo, + ); + if (resultVideo['success']) { + final data = resultVideo['data']; + for (Map item in data) { + final filePath = item['filePath'] ?? ''; + _initFileList.add(item); + _dangerVideos.add(ApiService.baseImgPath + filePath); + } + } + setState(() { + _isLoading = false; + }); + } + + /// 选择隐患发起人,只能在安全环保检查发起人和检查人中选择 + Future _getDepartmentPersonList() async { + String choice = await BottomPickerTwo.show( + context, + items: widget.personList, + itemName: "userName", + itemBuilder: + (item) => Text(item["userName"], textAlign: TextAlign.center), + initialIndex: 0, + ); + if (choice != null) { + for (int i = 0; i < widget.personList.length; i++) { + final item = widget.personList[i]; + if (choice == item["userName"]) { + setState(() { + addData['creatorId'] = item['userId']; + addData['creatorName'] = item['userName']; + }); + } + } + } + + } + + Future _getDiscoverPersonList() async { + String choice = await BottomPickerTwo.show( + context, + items: _HazardPersonlist, + itemName: "userName", + itemBuilder: + (item) => Text(item["userName"], textAlign: TextAlign.center), + initialIndex: 0, + ); + if (choice != null) { + for (int i = 0; i < _HazardPersonlist.length; i++) { + if (choice == _HazardPersonlist[i]["userName"]) { + setState(() { + _hazarder = _HazardPersonlist[i]; + }); + } + } + } + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: MyAppbar(title: widget.isAssignment ? "隐患信息维护" : "隐患信息维护"), + backgroundColor: Colors.white, + body: Column( + children: [ + // 详情滚动区域 + _pageDetail(), + ], + ), + ); + } + + Widget _pageDetail() { + return Expanded( + child: SingleChildScrollView( + padding: const EdgeInsets.only(bottom: 20, left: 10, right: 10), + child: + _isLoading + ? NoDataWidget.show() + : Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + RepairedPhotoSection( + isRequired: widget.isEdit, + isEdit: widget.isEdit, + title: "隐患照片", + maxCount: 4, + mediaType: MediaType.image, + isShowAI: false, + followInitialUpdates: true, + initialMediaPaths: _dangerImages, + onChanged: (List files){}, + onMediaAdded: (value) { + _dangerImages.add(value); + }, + onMediaRemoved: (value) { + _dangerImages.remove(value); + _removeFileList.add(value); + }, + onAiIdentify: () { + }, + ), + const Divider(), + RepairedPhotoSection( + title: "隐患视频", + isRequired: false, + isEdit: widget.isEdit, + maxCount: 1, + followInitialUpdates: true, + mediaType: MediaType.video, + initialMediaPaths: _dangerVideos.length > 0 ? [_dangerVideos.last] : [], + onChanged: (List files) { + // _dangerVideos=files[0].path; + }, + onMediaRemoved: (value) { + _dangerVideos.remove(value); + _removeFileList.add(value); + }, + onMediaAdded: (value) { + // 上传视频 files + try { + _dangerVideos.clear(); + _dangerVideos.add(value); + } catch (e) { + print("获取视频失败:${e.toString()}"); + } + }, + onAiIdentify: () {}, + ), + const Divider(), + ItemListWidget.multiLineTitleTextField( + label: '隐患描述', + isEditable: widget.isEdit, + isRequired: widget.isEdit, + + text: addData['hiddenDesc'] ?? '', + hintText: '请输入隐患描述', + onChanged: (value) { + setState(() { + addData['hiddenDesc'] = value; + }); + }, + ), + const Divider(), + + ItemListWidget.selectableLineTitleTextRightButton( + isRequired: widget.isEdit, + label: "隐患级别", + text: + FormUtils.hasValue(addData, 'hiddenLevelName') + ? addData['hiddenLevelName'] + : "请选择", + isEditable: widget.isEdit, + onTap: () { + _getHazardLevel(); + }, + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + isRequired: widget.isEdit, + label: "隐患类型", + text: + FormUtils.hasValue(addData, 'hiddenTypeName') + ? addData['hiddenTypeName'] + : "请选择", + isEditable: widget.isEdit, + onTap: () { + _getHiddenDangerType(); + }, + ), + // const Divider(), + // ListItemFactory.createMultiOptionSection( + // title: '是否相关方:', + // selectedValue: '否', + // options: ['是', '否'], + // isEdit: widget.isEdit, + // isRequired: true, + // horizontalPadding: 3, + // verticalPadding: 10, + // text: '${addData['isRelated'] == '1' ? '是' : '否'}', + // onChanged: (val) { + // setState(() { + // val == '是' ? addData['isRelated'] = '1' : '0'; + // }); + // }, + // ), + + + // const Divider(), + // ItemListWidget.selectableLineTitleTextRightButton( + // isRequired: false, + // label: '隐患部位', + // isEditable: widget.isEdit, + // text: + // FormUtils.hasValue(addData, 'hiddenPartName') + // ? addData['hiddenPartName'] + // : "请选择", + // onTap: () { + // _getHiddenDangerAreas(); + // }, + // ), + const Divider(), + ItemListWidget.multiLineTitleTextField( + label: '隐患位置描述', + isEditable: widget.isEdit, + isRequired: false, + text: addData['positionDesc'] ?? '', + hintText: '请对隐患位置进行详细描述', + onChanged: (value) { + setState(() { + addData['positionDesc'] = value; + }); + }, + ), + // const Divider(), + // ItemListWidget.OneRowButtonTitleText( + // label: '隐患上报位置', + // buttonText: '定位', + // isEdit: widget.isEdit, + // text: '', + // onTap: () async { + // final result = await pushPage( + // MapWebViewPage(), + // context, + // ); + // print(result); + // if (result != null) { + // setState(() { + // addData['longitude'] = + // result['longitude'].toString(); + // addData['latitude'] = result['latitude'].toString(); + // }); + // } + // }, + // ), + // Container( + // padding: EdgeInsets.symmetric(horizontal: 15), + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(5), + // ), + // child: ItemListWidget.selectableLineTitleTextRightButton( + // isRequired: false, + // label: "经度", + // text: addData['longitude'] ?? '', + // isEditable: false, + // ), + // ), + // const Divider(), + // Container( + // padding: EdgeInsets.symmetric(horizontal: 15), + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(5), + // ), + // child: ItemListWidget.selectableLineTitleTextRightButton( + // isRequired: false, + // label: "纬度", + // text: addData['latitude'] ?? '', + // isEditable: false, + // ), + // ), + + const Divider(), + _buildInfoItem( + '整改类型', + '限期整改', + ), + + if(_showRectification)...[ + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + isRequired: widget.isEdit, + label: "整改期限", + text: + FormUtils.hasValue(addData, 'rectificationDeadline') ? addData['rectificationDeadline'] : "请选择", + isEditable: widget.isEdit, + onTap: () async { + DateTime? picked = await BottomDateTimePicker.showDate( + context, + allowPast: false, + allowFuture: true, + mode: BottomPickerMode.dateTimeWithSeconds, + ); + if (picked != null) { + setState(() { + addData['rectificationDeadline'] = DateFormat( + 'yyyy-MM-dd HH:mm:ss', + ).format(picked); + }); + //FocusHelper.clearFocus(context); + } + }, + ), + const Divider(), + + ItemListWidget.selectableLineTitleTextRightButton( + isRequired: widget.isEdit, + label: "整改部门", + text: FormUtils.hasValue(addData, 'rectificationDeptName') ? addData['rectificationDeptName'] : "请选择", + isEditable: widget.isEdit, + onTap: () { + showModalBottomSheet( + context: context, + isScrollControlled: true, + barrierColor: Colors.black54, + backgroundColor: Colors.transparent, + builder: + (ctx) => DepartmentPickerTwo( + onSelected: (id, name,pdId) async { + setState(() { + + addData['rectificationDeptId']= id; + addData['rectificationDeptName']= name; + + addData['rectificationUserId']= ""; + addData['rectificationUserName']= ""; + + + }); + // 拉取该单位的人员列表并缓存 + final result = await HiddenDangerApi.getListTreePersonList(id); + _personCache=List>.from( + result['data'] as List, + ); + }, + ), + ); + }, + ), + + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + isRequired: widget.isEdit, + label: "整改人", + text: FormUtils.hasValue(addData, 'rectificationUserName') ? addData['rectificationUserName'] : "请选择", + isEditable: widget.isEdit, + onTap: () async { + if ( addData['rectificationDeptName'].isEmpty) { + ToastUtil.showNormal(context, '请先选择部门'); + return; + } + DepartmentPersonPicker.show( + context, + personsData: _personCache, + onSelected: (userId, name) { + setState(() { + + addData['rectificationUserId']= userId; + addData['rectificationUserName']= name; + + }); + + }, + ); + }, + ), + + ], + + + + const Divider(), + Column( + children: [ + ItemListWidget.selectableLineTitleTextRightButton( + isRequired: widget.isEdit, + label: "隐患发现人", + text: FormUtils.hasValue(addData, 'hiddenFindUserdName') ? addData['hiddenFindUserdName'] : "请选择", + isEditable: widget.isEdit, + onTap: () async { + final List result = []; + final dynamic coList = widget.personList; + + if (coList is List) { + for (final item in coList) { + if (item is Map) { + final dynamic standardItem = item['userName']; + if (standardItem is String && standardItem.isNotEmpty) { + result.add(standardItem); + } + } + } + } + + // 获取当前已选择的项目 + final dynamic currentSelected = addData['hiddenFindUserdList'] ?? []; + List selectedList = []; + + if (currentSelected is List) { + for (final item in currentSelected) { + if (item is Map) { + final dynamic standardItem = item['userName']; + if (standardItem is String && standardItem.isNotEmpty) { + selectedList.add(standardItem); + } + } + } + } + + + // 计算预选索引 + final List initialIndices = []; + for (final selectedItem in selectedList) { + final int index = result.indexOf(selectedItem); + if (index != -1) { + initialIndices.add(index); + } + } + + // 显示选择器 + final selectedItems = await CenterMultiPicker.show( + context, + items: result, + itemBuilder: (item) => Text( + item, + style: const TextStyle(fontSize: 16), + ), + initialSelectedIndices: initialIndices, // 设置预选索引 + maxSelection: null, // 不限制选择数量 + allowEmpty: true, + title: '隐患发现人', + ); + + // 处理选择结果 + if (selectedItems != null) { + setState(() { + addData['hiddenFindUserdName'] = selectedItems.join(','); + + List result = widget.personList.where((person) { + String userName = person['userName']?.toString() ?? ''; + return selectedItems.contains(userName); + }).toList(); + addData['hiddenFindUserdList'] = result; + + }); + } + // onTap: () { + // _getDepartmentPersonList(); + }, + ), + SizedBox(height: 1), + ], + ), + + + + + + + const Divider(), + + SizedBox(height: 20), + if (widget.isEdit) + CustomButton( + onPressed: () { + _riskListCheckAppAdd(); + }, + text: "保存", + padding: EdgeInsets.symmetric(horizontal: 30), + backgroundColor: Colors.blue, + ), + ], + ), + ), + ); + } + + + Future _riskListCheckAppAdd() async { + if (_dangerImages.isEmpty) { + ToastUtil.showNormal(context, "请上传隐患图片"); + return; + } + + if (!FormUtils.hasValue(addData, 'hiddenDesc')) { + ToastUtil.showNormal(context, "请输入隐患描述"); + return; + } + + if (!FormUtils.hasValue(addData, 'hiddenLevelName')) { + ToastUtil.showNormal(context, "请选择隐患级别"); + return; + } + + if (!FormUtils.hasValue(addData, 'hiddenType')) { + ToastUtil.showNormal(context, "请选择隐患类型"); + return; + } + + if(_showRectification){ + if (!FormUtils.hasValue(addData, 'rectificationDeadline')) { + ToastUtil.showNormal(context, "请选择整改期限"); + return; + } + if (!FormUtils.hasValue(addData, 'rectificationDeptId')) { + ToastUtil.showNormal(context, "请选择整改部门"); + return; + } + if (!FormUtils.hasValue(addData, 'rectificationUserId')) { + ToastUtil.showNormal(context, "请选择整改人"); + return; + } + } + + // if (!FormUtils.hasValue(addData, 'positionDesc')) { + // ToastUtil.showNormal(context, "隐患位置描述不能为空"); + // return; + // } + /// 删除服务器保存的图片 + List ids = []; + for (var item in _initFileList) { + final serverPath = item['filePath']; + for (String path in _removeFileList) { + if (path.contains(serverPath)) { + if (FormUtils.hasValue(item, 'id')) { + ids.add(item['id']); + } + } + } + } + if (ids.isNotEmpty) { + LoadingDialogHelper.show(); + await FileApi.deleteImages(ids); + LoadingDialogHelper.dismiss(); + } + + + addData['imgs'] = _dangerImages; + addData['videos'] = _dangerVideos; + Navigator.pop(context, addData); + // try { + // final raw = await HiddenDangerApi.addRiskListCheckApp(addData); + // if (raw['success']) { + // setState(() { + // LoadingDialogHelper.hide(); + // ToastUtil.showNormal(context, "提交成功"); + // Navigator.pop(context); + // }); + // } else { + // LoadingDialogHelper.hide(); + // ToastUtil.showNormal(context, "提交失败"); + // } + // } catch (e) { + // LoadingDialogHelper.hide(); + // print('Error fetching data: $e'); + // } + } + + Future _identifyImg(String imagePath) async { + try {} catch (e) { + // 出错时可以 Toast 或者在页面上显示错误状态 + print('加载首页数据失败:$e'); + // return ""; + LoadingDialogHelper.hide(); + } + } + + // Future _getHiddenDangerAreas() async { + // showModalBottomSheet( + // context: context, + // isScrollControlled: true, + // barrierColor: Colors.black54, + // backgroundColor: Colors.transparent, + // builder: + // (_) => DangerPartsPicker( + // title: '隐患部位', + // requestData: {'eqCorpinfoId' : widget.corpId}, + // onSelected: (id, name, extraData) { + // setState(() { + // addData['hiddenPartName'] = name; + // addData['hiddenPart'] = id; + // }); + // }, + // ), + // ).then((_) { + // // 可选:FocusHelper.clearFocus(context); + // }); + // } + + Future _getHazardLevel() async { + showModalBottomSheet( + context: context, + isScrollControlled: true, + barrierColor: Colors.black54, + backgroundColor: Colors.transparent, + builder: + (_) => MultiDictValuesPicker( + dictType: 'hiddenLevel', + allowSelectParent: false, + isSafeChekDangerLevel: false, + onSelected: (id, name, extraData) { + setState(() { + print(json.encode(extraData)); + addData['hiddenLevel'] = extraData?['dictValue'] ?? ''; + addData['hiddenLevelName'] = name; + if('轻微隐患'==name||'一般隐患'==name){ + _showRectification=true; + }else{ + _showRectification=false; + } + + }); + }, + ), + ).then((_) { + // 可选:FocusHelper.clearFocus(context); + }); + } + + Future _getHiddenDangerType() async { + showModalBottomSheet( + context: context, + isScrollControlled: true, + barrierColor: Colors.black54, + backgroundColor: Colors.transparent, + builder: + (_) => MultiDictValuesPicker( + title: '检查类型', + dictType: 'hiddenType', + allowSelectParent: false, + onSelected: (id, name, extraData) { + print(json.encode(extraData)); + setState(() { + addData['hiddenType'] = extraData?['dictValue'] ?? ''; + addData['hiddenTypeName'] = name; + + //顶层 + addData['hiddenType2'] = extraData?['dingValue'] ?? ''; + addData['hiddenType2Name'] = extraData?['dingName'] ?? ''; + }); + }, + ), + ).then((_) { + // 可选:FocusHelper.clearFocus(context); + }); + } + + Future _getUserData() async { + try { + final raw = await AuthApi.getUserData(); + if (raw['success']) { + setState(() { + addData['creatorId'] = raw['data']['id']; + addData['creatorName'] = raw['data']['name']; + addData['hiddenFindDept'] = raw['data']['departmentId']; + addData['hiddenFindDeptName'] = raw['data']['departmentName']; + + responsibleId = raw['data']['id']; + responsibleName = raw['data']['name']; + buMenId = raw['data']['departmentId']; + buMenName = raw['data']['departmentName']; + }); + } else { + ToastUtil.showNormal(context, "获取个人信息失败"); + } + } catch (e) { + // 出错时可以 Toast 或者在页面上显示错误状态 + print('加载首页数据失败:$e'); + } + } + + Widget _buildInfoItem(String title, String value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 120, + child: Text( + title, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + Expanded(child: Text(value, textAlign: TextAlign.right)), + ], + ), + ); + } + + Widget _buildSectionContainer({required Widget child}) { + return Container( + margin: const EdgeInsets.only(top: 1), + color: Colors.white, + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10), + child: child, + ); + } + +} diff --git a/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_detail_widget.dart b/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_detail_widget.dart index 945246a..4ed501c 100644 --- a/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_detail_widget.dart +++ b/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_detail_widget.dart @@ -18,7 +18,9 @@ import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.dart'; import 'package:qhd_prevention/customWidget/single_image_viewer.dart'; import 'package:qhd_prevention/customWidget/toast_util.dart'; import 'package:qhd_prevention/http/ApiService.dart'; +import 'package:qhd_prevention/http/modules/key_tasks_api.dart'; import 'package:qhd_prevention/http/modules/safety_check_api.dart'; +import 'package:qhd_prevention/pages/home/keyTasks/keyTasksDetail/key_taskes_danger_page.dart'; import 'package:qhd_prevention/pages/mine/mine_sign_page.dart'; @@ -34,6 +36,7 @@ enum SafeCheckDetailMode { detail, // 详情 } + /// 只读展示版 SafecheckDetailWidget/// 外部负责 push 页面并在页面 pop 时返回可能修改或新增的隐患对象(若无修改返回 null 即可)。 class KeyTaskesDetailWidget extends StatefulWidget { const KeyTaskesDetailWidget({ @@ -69,11 +72,11 @@ class KeyTaskesDetailWidget extends StatefulWidget { final Map? initialInitiator; @override - State createState() => KeyTaskesDetailWidgetState(); + State createState() => keyTaskesDetailWidgetState(); } /// 注意:状态类为公有,外部可以通过 GlobalKey 访问 setDetailData(...) -class KeyTaskesDetailWidgetState extends State { +class keyTaskesDetailWidgetState extends State { // 固定只读 bool _isEdit = false; @@ -122,6 +125,8 @@ class KeyTaskesDetailWidgetState extends State { // 检查来源(4-监管端 5-企业端) }; + bool _showReviewStatus=false; + @override void initState() { super.initState(); @@ -129,10 +134,10 @@ class KeyTaskesDetailWidgetState extends State { _isEdit = false; // 优先:如果外部传了 initialData(完整的 data),直接用它 - if (widget.initialData != null) { - setDetailData(widget.initialData!); - return; - } + // if (widget.initialData != null) { + // setDetailData(widget.initialData!); + // return; + // } // 如果 inspectionId 非空 且 autoFetch 为 true,则组件内部请求接口 if (widget.inspectionId.isNotEmpty && widget.autoFetch) { @@ -151,24 +156,270 @@ class KeyTaskesDetailWidgetState extends State { } } + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 0, vertical: 12), + child: form.isNotEmpty ? _mainWidget() : SizedBox(), + ); + } + + Widget _mainWidget() { + if (!FormUtils.hasValue(form, 'inspectionId')) { + return SizedBox(height: 500, child: NoDataWidget.show(),); + } + + String subjectShow = form['subject'] ?? ''; + if (widget.handleType == SafeCheckDetailMode.add) { + for (var item in subjectList) { + if (item['bianma'] == form['subject']) { + form['subject'] = item['id']; + subjectShow = item['name'] ?? ''; + break; + } + } + } + bool isPlan = form['planType'] == 1; + + return (widget.handleType == SafeCheckDetailMode.add) || + (widget.handleType == SafeCheckDetailMode.edit && + FormUtils.hasValue(form, 'inspectionId') || + widget.handleType == SafeCheckDetailMode.detail) + ? Column( + children: [ + // ItemListWidget.selectableLineTitleTextRightButton( + // isRequired: _isEdit, + // label: '检查题目', + // isEditable: _isEdit, + // text: '${form['subject'] ?? ''}', + // onTap: () {}, + // ), + // const Divider(), + // ItemListWidget.selectableLineTitleTextRightButton( + // isRequired: _isEdit, + // label: '计划属性', + // isEditable: _isEdit, + // text: isPlan ? '计划内' : '计划外', + // onTap: () {}, + // ), + // if (isPlan) ...[ + // const Divider(), + // ItemListWidget.selectableLineTitleTextRightButton( + // isRequired: _isEdit, + // label: '计划名称', + // isEditable: _isEdit, + // text: form['planName'] ?? '', + // onTap: () {}, + // ), + // ], + // const Divider(), + + ItemListWidget.selectableLineTitleTextRightButton( + isRequired: _isEdit, + label: '辖区单位', + isEditable: _isEdit, + text: form['corpName'] ?? '', + onTap: () {}, + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + isRequired: _isEdit, + label: '被检查单位', + isEditable: _isEdit, + text: form['inspectedCorpinfoName'] ?? '', + onTap: () {}, + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + isRequired: _isEdit, + label: '被检查单位现场负责人', + isEditable: _isEdit, + text: form['xgfMasterUserName'] ?? '', + onTap: () {}, + ), + + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + isRequired: _isEdit, + label: '重点作业名称', + isEditable: _isEdit, + text: form['projectName'] ?? '', + onTap: () {} + ), + + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '检查类型:', + onTap: () {}, + isEditable: _isEdit, + text: form['typeName'] ?? '', + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '检查开始时间:', + isEditable: _isEdit, + text: form['timeStart'] ?? '', + onTap: () async {}, + ), + const Divider(), + ItemListWidget.selectableLineTitleTextRightButton( + label: '检查结束时间:', + isEditable: _isEdit, + text: form['timeEnd'] ?? '', + onTap: () async {}, + ), + // if (!_isEdit) + // Column( + // children: [ + // const Divider(), + // ItemListWidget.selectableLineTitleTextRightButton( + // label: '记录填写时间:', + // isEditable: _isEdit, + // text: form['createTime'] ?? '', + // ), + // ], + // ), + + const Divider(), + ItemListWidget.singleLineTitleText( + label: '检查场所:', + isEditable: _isEdit, + text: form['place'] ?? '', + hintText: '请输入检查场所', + onChanged: (val) { + // 只读 + }, + ), + + const Divider(), + ItemListWidget.itemContainer( + Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ListItemFactory.headerTitle('检查人员'), + // _isEdit == false 时不显示添加按钮 + ], + ), + SizedBox(height: 10), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: inspectorList.length, + itemBuilder: (context, index) { + return _personUnitItem(inspectorList[index], index); + }, + ), + ], + ), + ), + + const Divider(), + MultiTextFieldWithTitle( + label: "检查情况:", + isEditable: _isEdit, + items: situationList, + imageCount: 4, + hintText: "请输入检查情况...", + onItemsChanged: (List> value) { + situationList = value; + }, + ), + + + const Divider(), + ItemListWidget.itemContainer( + Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ListItemFactory.headerTitle('发现问题'), + // 添加按钮仅在编辑模式显示(此处不显示) + ], + ), + ], + ), + ), + HiddenListTable( + hiddenList: dangerList, + forbidEdit: _isEdit, + baseImgPath: ApiService.baseImgPath, + personSignImg: '', + personSignTime: '', + showHidden: (item, idx) { + // 打开隐患详情/编辑页的 push 由外部处理 + _openDrawer(item, idx); + }, + removeHidden: (item, idx) { + _delHiddenForm(item, idx); + }, + context: context, + ), + if (widget.handleType == SafeCheckDetailMode.detail) + _detailWidget(), + + SizedBox(height: 15,), + ], + ) + : SizedBox(); + } + + Widget _detailWidget() { + return Column( + children: [ + if (inspectorList.isNotEmpty&&_showReviewStatus) + Column( + children: [ + // const Divider(), + SizedBox(height: 5), + ListItemFactory.createBuildSimpleSection('检查人员审核情况'), + SizedBox(height: 5), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: inspectorList.length, + itemBuilder: (context, index) { + return _personSignItem(inspectorList[index], index); + }, + ), + ], + ), + // if (personUnderInspection.isNotEmpty && FormUtils.hasValue(personUnderInspection, 'signature')) + // Column( + // children: [ + // const Divider(), + // ListItemFactory.createBuildSimpleSection('被检查单位现场负责人确认情况'), + // SizedBox(height: 5), + // _unitSignItem(personUnderInspection) + // + // ], + // ), + ], + ); + } + + /// 公开方法:外部在拿到接口返回的 data 后,直接调用这个方法注入数据 void setDetailData(Map data) { setState(() { form = data; - for (Map subject in subjectList) { - if (subject['bianma'] == form['subject']) { - form['subject'] = subject['name']; - } - } - personUnderInspection = data['inspectedPartyConfirmation'] ?? {}; - inspectorList = data['inspectorVerificationList'] ?? []; - initiator = data['initiator'] ?? {}; - inspectorVerifyList = data['inspectorVerifyList'] ?? []; - toCheckUnitList = data['toCheckUnitList'] ?? []; - situationList = data['content'] ?? []; + // for (Map subject in subjectList) { + // if (subject['bianma'] == form['subject']) { + // form['subject'] = subject['name']; + // } + // } + // personUnderInspection = data['inspectedPartyConfirmation'] ?? {}; + // inspectorList = data['inspectorVerificationList'] ?? []; + // initiator = data['initiator'] ?? {}; + // inspectorVerifyList = data['inspectorVerifyList'] ?? []; + // toCheckUnitList = data['toCheckUnitList'] ?? []; + // situationList = data['content'] ?? []; // 异步填充图片/隐患 _getAllFiles(); - _getDangerList(); + // _getDangerList(); }); } @@ -183,16 +434,24 @@ class KeyTaskesDetailWidgetState extends State { await FileApi.getImagePathWithType( contentId, '', - UploadFileType.safetyEnvironmentalInspectionInspectionSituation, + UploadFileType.keyProjectInitiationImage, ) .then((result) { - final data = result['data']; - final filePath = - (data is List && data.isNotEmpty) - ? data.first['filePath'] ?? '' - : ''; - item['imgPath'] = ApiService.baseImgPath + filePath; + // final data = result['data']; + // final filePath = (data is List && data.isNotEmpty) ? data.first['filePath'] ?? '' : ''; + // item['imgPath'] = ApiService.baseImgPath + filePath; + // situationList[idex] = item; + + List images =[]; + final List data = result['data']; + for(int i=0;i { Future _getDetail() async { try { LoadingDialogHelper.show(); - final result = await SafetyCheckApi.safeCheckDetail(widget.inspectionId); + final result = await KeyTasksApi.getKeyTasksSafetyEnvironmentalInspectionDetail(widget.inspectionId); LoadingDialogHelper.hide(); - if (result != null) { + if (result['success']) { setState(() { final data = result['data']; form = data; - for (Map subject in subjectList) { - if (subject['bianma'] == form['subject']) { - form['subject'] = subject['name']; + + // form['departmentName'] = form['corpName']; + inspectorList=form['inspectionUserList']??[];//检查人列表 + for(int i=0;i { ToastUtil.showNormal(context, '详情获取失败'); } } - /// 获取申辩列表 - Future _getAppealList(String traceId) async { - try { - // final parentPerm = 'dashboard:safety-env-inspection:plea-manage'; - // final targetPerm = ''; - // final menuPath = await RouteService.getMenuPath(parentPerm, targetPerm); - // final result = await SafetyCheckApi.safeCheckAppealList( - // traceId, - // { - // "pageIndex": 1, - // "pageSize": 100, - // "menuPath" : menuPath - // }, - // ); - // if (result != null && result['success']) { - // final dynamic data = result['data']; - // List fetched = []; - // if (data is List) { - // fetched = data; - // } else if (data is Map && data['list'] is List) { - // // 如果后端返回了 { list: [...], total: x } 之类的结构,尝试兼容 - // fetched = data['list']; - // } - // personUnderInspection['content'] = fetched.last['content']; - // - // } - }catch(e){ - } - } - - /// 获取隐患列表 - Future _getDangerList() async { - try { - LoadingDialogHelper.show(); - final data = { - 'foreignKey': form['traceId'], - 'pageSize': 100, - 'pageIndex': 1, - }; - final result = await HiddenDangerApi.getHiddenDangerListByforeignKeyId( - data, - ); - LoadingDialogHelper.hide(); - if (result != null && result['success']) { - setState(() { - dangerList = result['data']; - }); - } else { - ToastUtil.showNormal(context, '获取隐患失败'); - } - } catch (e) { - LoadingDialogHelper.hide(); - ToastUtil.showNormal(context, '获取隐患失败'); - } - } /// 打开隐患 Future _openDrawer(Map hiddenForm, int index) async { // pushPage(HiddenRecordDetailPage(DangerType.ristRecord,7,hiddenForm['id'],hiddenForm['hiddenId'],false), context); + // pushPage(HiddenRecordDetailPage(widget.dangerType,widget.appItem,pageData['id'],pageData['hiddenId'],false), context); + List personList = []; + pushPage( + KeyTaskesDangerPage( + initData: hiddenForm, + inspectionId: widget.inspectionId, + isEdit: _isEdit, + corpId: personUnderInspection['corpId'] ?? '', + personList: personList, + autoSaveTime: 999999999, + ), + context, + ); } Future openCustomDrawer(BuildContext context, Widget child) { @@ -407,6 +640,7 @@ class KeyTaskesDetailWidgetState extends State { children: [ const SizedBox(width: 10), Text('签字时间: ${item['signatureTime'] ?? ''}'), + const SizedBox(width: 10), ], ), ], @@ -484,233 +718,9 @@ class KeyTaskesDetailWidgetState extends State { }); } - Widget _mainWidget() { - if (!FormUtils.hasValue(form, 'inspectionId')) { - return SizedBox(height: 500, child: NoDataWidget.show(),); - } - - String subjectShow = form['subject'] ?? ''; - if (widget.handleType == SafeCheckDetailMode.add) { - for (var item in subjectList) { - if (item['bianma'] == form['subject']) { - form['subject'] = item['id']; - subjectShow = item['name'] ?? ''; - break; - } - } - } - bool isPlan = form['planType'] == 1; - - return (widget.handleType == SafeCheckDetailMode.add) || - (widget.handleType == SafeCheckDetailMode.edit && - FormUtils.hasValue(form, 'inspectionId') || - widget.handleType == SafeCheckDetailMode.detail) - ? Column( - children: [ - // ItemListWidget.selectableLineTitleTextRightButton( - // isRequired: _isEdit, - // label: '检查题目', - // isEditable: _isEdit, - // text: '${form['subject'] ?? ''}', - // onTap: () {}, - // ), - // const Divider(), - // ItemListWidget.selectableLineTitleTextRightButton( - // isRequired: _isEdit, - // label: '计划属性', - // isEditable: _isEdit, - // text: isPlan ? '计划内' : '计划外', - // onTap: () {}, - // ), - // if (isPlan) ...[ - // const Divider(), - // ItemListWidget.selectableLineTitleTextRightButton( - // isRequired: _isEdit, - // label: '计划名称', - // isEditable: _isEdit, - // text: form['planName'] ?? '', - // onTap: () {}, - // ), - // ], - - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - isRequired: _isEdit, - label: '辖区单位', - isEditable: _isEdit, - text: personUnderInspection['departmentName'] ?? '', - onTap: () {}, - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - isRequired: _isEdit, - label: '被检查单位', - isEditable: _isEdit, - text: personUnderInspection['departmentName'] ?? '', - onTap: () {}, - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - isRequired: _isEdit, - label: '被检查单位现场负责人', - isEditable: _isEdit, - text: personUnderInspection['userName'] ?? '', - onTap: () {}, - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '检查类型:', - onTap: () {}, - isEditable: _isEdit, - text: form['typeName'] ?? '', - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '检查开始时间:', - isEditable: _isEdit, - text: form['timeStart'] ?? '', - onTap: () async {}, - ), - const Divider(), - ItemListWidget.selectableLineTitleTextRightButton( - label: '检查结束时间:', - isEditable: _isEdit, - text: form['timeEnd'] ?? '', - onTap: () async {}, - ), - // if (!_isEdit) - // Column( - // children: [ - // const Divider(), - // ItemListWidget.selectableLineTitleTextRightButton( - // label: '记录填写时间:', - // isEditable: _isEdit, - // text: form['createTime'] ?? '', - // ), - // ], - // ), - - const Divider(), - ItemListWidget.singleLineTitleText( - label: '检查场所:', - isEditable: _isEdit, - text: form['place'] ?? '', - hintText: '请输入检查场所', - onChanged: (val) { - // 只读 - }, - ), - - const Divider(), - ItemListWidget.itemContainer( - Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ListItemFactory.headerTitle('检查人员'), - // _isEdit == false 时不显示添加按钮 - ], - ), - SizedBox(height: 10), - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: inspectorList.length, - itemBuilder: (context, index) { - return _personUnitItem(inspectorList[index], index); - }, - ), - ], - ), - ), - - const Divider(), - MultiTextFieldWithTitle( - label: "检查情况:", - isEditable: _isEdit, - items: situationList, - hintText: "请输入检查情况...", - onItemsChanged: (List> value) { - situationList = value; - }, - ), - const Divider(), - ItemListWidget.itemContainer( - Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ListItemFactory.headerTitle('发现问题'), - // 添加按钮仅在编辑模式显示(此处不显示) - ], - ), - ], - ), - ), - HiddenListTable( - hiddenList: dangerList, - forbidEdit: _isEdit, - baseImgPath: ApiService.baseImgPath, - personSignImg: '', - personSignTime: '', - showHidden: (item, idx) { - // 打开隐患详情/编辑页的 push 由外部处理 - _openDrawer(item, idx); - }, - removeHidden: (item, idx) { - _delHiddenForm(item, idx); - }, - context: context, - ), - if (widget.handleType == SafeCheckDetailMode.detail) - _detailWidget(), - ], - ) - : SizedBox(); - } - Widget _detailWidget() { - return Column( - children: [ - if (inspectorList.isNotEmpty) - Column( - children: [ - const Divider(), - ListItemFactory.createBuildSimpleSection('检查人员审核情况'), - SizedBox(height: 5), - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: inspectorList.length, - itemBuilder: (context, index) { - return _personSignItem(inspectorList[index], index); - }, - ), - ], - ), - if (personUnderInspection.isNotEmpty && FormUtils.hasValue(personUnderInspection, 'signature')) - Column( - children: [ - const Divider(), - ListItemFactory.createBuildSimpleSection('被检查单位现场负责人确认情况'), - SizedBox(height: 5), - _unitSignItem(personUnderInspection) - ], - ), - ], - ); - } - @override - Widget build(BuildContext context) { - return Padding( - padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12), - child: form.isNotEmpty ? _mainWidget() : SizedBox(), - ); - } } diff --git a/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_onlylook_detail_page.dart b/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_onlylook_detail_page.dart index 67256c3..f914aa3 100644 --- a/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_onlylook_detail_page.dart +++ b/lib/pages/home/keyTasks/keyTasksDetail/key_taskes_onlylook_detail_page.dart @@ -7,10 +7,11 @@ class KeyTaskesOnlylookDetailPage extends StatefulWidget { const KeyTaskesOnlylookDetailPage({ super.key, required this.inspectionId, + required this.handleType, }); final String inspectionId; - + final SafeCheckDetailMode handleType; @override State createState() => _KeyTaskesOnlylookDetailPageState(); @@ -28,7 +29,7 @@ class _KeyTaskesOnlylookDetailPageState extends State _KeyTasksCheckListPageState(); +} + +class _KeyTasksCheckListPageState extends State { + // 列表数据与分页 + List list = []; + + int currentPage = 1; + int totalPage = 1; + bool isLoading = false; + late var searchData = {}; + + // 步骤列表(用于筛选) + int sindex = 0; // 筛选索引(只有发起模式可见) + String searchKey = ''; + Map flowData = {}; + final GlobalKey _scaffoldKey = GlobalKey(); + final ScrollController _scrollController = ScrollController(); + + + final TextEditingController _searchController = TextEditingController(); + String searchHintText='请输入检查场所'; + + String title=""; + + @override + void initState() { + super.initState(); + + + title='检查发起'; + keyTasksInspectionListData['statusList']=[2]; + + + _fetchData(); + _scrollController.addListener(_onScroll); + } + + + @override + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: MyAppbar( + title: title, + ), + + body: SafeArea( + child: Column( + children: [ + Container( + color: Colors.white, + child: Padding( + padding: EdgeInsets.all(10), + child: SearchBarWidget( + controller: _searchController, + hintText: searchHintText, + showResetButton:true, + onSearch: (keyboard) { + // 输入请求接口 + currentPage=1; + searchKey=keyboard; + _fetchData(); + }, + ), + ), + ), + + const Divider(height: 1), + // List + Expanded(child: _buildListContent()), + ], + ), + ), + ); + } + + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + void _onScroll() { + if (_scrollController.position.pixels >= + _scrollController.position.maxScrollExtent && + !isLoading) { + if (currentPage < totalPage) { + currentPage++; + _fetchData(); + } + } + } + + + + /// 根据当前页面模式返回对应的操作按钮 + List _buildActionButtons(Map item) { + final List buttons = []; + + // 检查人确认:查看、核实 + buttons.addAll([ + CustomButton( + text: '查看', + height: 35, + buttonStyle: ButtonStyleType.secondary, + backgroundColor: Colors.blue, + onPressed: () => _goToDetail(item,SafeCheckDetailMode.detail), + ), + CustomButton( + text: '确认', + height: 35, + backgroundColor: Colors.blue, + onPressed: () => _handleVerify(item), + ), + ]); + + + return buttons; + } + + Widget _buildListItem(Map item) { + final actionButtons = _buildActionButtons(item); + + // 构建一行内均分按钮并在按钮间插入间距 10 + List buttonRowChildren = []; + for (int i = 0; i < actionButtons.length; i++) { + // 将按钮包在 SizedBox 以保证高度一致,同时用 Expanded 占满剩余宽度 + buttonRowChildren.add( + Expanded(child: SizedBox(height: 35, child: actionButtons[i])), + ); + if (i != actionButtons.length - 1) { + buttonRowChildren.add(const SizedBox(width: 10)); + } + } + + return Card( + color: Colors.white, + margin: const EdgeInsets.all(8.0), + child: InkWell( + onTap:() { + + }, + // () => _goToDetail(item), + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "${item['subject'] ?? ''}现场安全检查记录", + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + ], + ), + Text("检查发起人: ${item['corpName'] ?? ''}"), + Text("检查类型: ${item['typeName'] ?? ''}"), + Text("被检查单位: ${item['inspectedCorpinfoName'] ?? ''}"), + Text("被检查单位现场负责人: ${item['xgfMasterUserName'] ?? ''}"), + Text( + "检查时间: 自${item['timeStart'] ?? ''}至${item['timeEnd'] ?? ''}", + ), + Text("发现隐患数: ${item['hiddenNumber'] ?? ''}"), + Text("检查状态: ${_checkStatusWithId(item)}"), + + ], + ), + + const SizedBox(height: 8), + // 按钮行:如果只有一个按钮,不需要间距;多个按钮均分占满行,间距为 10 + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: buttonRowChildren, + ), + ], + ), + ), + ), + ); + } + + Widget _buildListContent() { + if (isLoading && list.isEmpty) { + return const Center(child: CircularProgressIndicator()); + } else if (list.isEmpty) { + return NoDataWidget.show(); + } else { + return ListView.builder( + padding: EdgeInsets.zero, + controller: _scrollController, + itemCount: list.length + (isLoading ? 1 : 0), + itemBuilder: (context, index) { + if (index >= list.length) { + return const Padding( + padding: EdgeInsets.symmetric(vertical: 16.0), + child: Center(child: CircularProgressIndicator()), + ); + } + return _buildListItem(list[index]); + }, + ); + } + } + + + + /// 跳转到详情 + Future _goToDetail( item ,SafeCheckDetailMode type,) async { + // if (type == SafeCheckDetailMode.detail) { + await pushPage( + KeyTaskesOnlylookDetailPage(inspectionId: item['inspectionId'] ?? '', handleType: type), + context, + ); + // 完成后刷新列表 + currentPage = 1; + _fetchData(); + // } else { + // + // await pushPage( + // KeyTasksStartDetail( + // inspectionId: item['inspectionId'] ?? '', + // type: SafeCheckMode.Initiate, + // handleType: type, + // isInPlan: false, + // isAutoSave: true, + // ), + // context, + // ); + // // 完成后刷新列表 + // currentPage = 1; + // _fetchData(); + // } + + } + + + + /// 确认 + Future _handleVerify(Map item) async { + await pushPage( + KeyTaskesCheckConfirmPage( + id: item['id'] ?? '', + inspectionId: item['inspectionId'] ?? '', + handleType: SafeCheckDetailMode.detail, + ), + context, + ); + _fetchData(); + } + + + + + + String _checkStatusWithId(item) { + //状态 (0-暂存,1-待核实,2-待确认,3-待隐患整改,4-待隐患验收,5-检查归档,6-核实打回,7-被检查申辩) + String typeName=''; + int type=item['status']??10; + switch(type){ + case 0: + typeName='暂存'; + break; + case 1: + typeName='待核实'; + break; + case 2: + typeName='待确认'; + break; + case 3: + typeName='待隐患整改'; + break; + case 4: + typeName='待隐患验收'; + break; + case 5: + typeName='检查归档'; + break; + case 6: + typeName='核实打回'; + break; + case 7: + typeName='被检查申辩'; + break; + } + return typeName; + } + + /// 状态 + static List> getStepList() { + List> stepList = [ + {'id': '200', 'name': '待核实'}, + {'id': '300', 'name': '待确认'}, + {'id': '301', 'name': '待指派'}, + {'id': '400', 'name': '待验收'}, + {'id': '500', 'name': '检查归档'}, + {'id': '600', 'name': '检查核实打回'}, + {'id': '700', 'name': '被检查人申辩'}, + ]; + return stepList; + } + + + + Future _fetchData() async { + if (isLoading) return; + setState(() => isLoading = true); + + try { + keyTasksInspectionListData['pageIndex']=currentPage; + keyTasksInspectionListData['place']=searchKey; + + final response = await KeyTasksApi.getKeyTasksSafetyEnvironmentalInspectionList(keyTasksInspectionListData); + + if(response['success']){ + setState(() { + final newData = response['data'] as List? ?? []; + if (currentPage == 1) { + list = newData; + } else { + list.addAll(newData); + } + totalPage = response['totalPages'] ?? 1; + isLoading = false; + }); + } + } catch (e) { + debugPrint('Error fetching data: $e'); + setState(() => isLoading = false); + ToastUtil.showNormal(context, '获取列表失败'); + } + } + + Map keyTasksInspectionListData={ + "place": "", + "createName": "", + "inspectionDepartmentId": "", + "timeStart": "", + "timeEnd": "", + "inspectedCorpinfoName": "", + "projectName": "", + "inspectionUserName": "", + "statusList": [], + "year":"", + "pageSize": 20, + "pageIndex": 1 + }; + + +} + + diff --git a/lib/pages/home/keyTasks/key_tasks_tab_page.dart b/lib/pages/home/keyTasks/key_tasks_tab_page.dart index 07c9659..b75c9a2 100644 --- a/lib/pages/home/keyTasks/key_tasks_tab_page.dart +++ b/lib/pages/home/keyTasks/key_tasks_tab_page.dart @@ -3,6 +3,7 @@ import 'dart:ffi'; import 'package:flutter/material.dart'; import 'package:qhd_prevention/pages/home/doorAndCar/doorCar_tab_page.dart'; +import 'package:qhd_prevention/pages/home/keyTasks/key_tasks_check_list_page.dart'; import 'package:qhd_prevention/pages/home/keyTasks/key_tasks_confirm_list_page.dart'; import 'package:qhd_prevention/pages/my_appbar.dart'; import 'package:qhd_prevention/tools/tools.dart'; @@ -50,7 +51,7 @@ class _DoorcarTabPageState extends State { icon: 'assets/images/door_ico9.png', badge: 0, onTap: () async { - // await pushPage(KeyTasksCheckListPage(1, widget.isLoginJGD), context); + await pushPage(KeyTasksCheckListPage(), context); _getDoorCarCount(); }, ), diff --git a/lib/services/SessionService.dart b/lib/services/SessionService.dart index f1add70..abc8ac1 100644 --- a/lib/services/SessionService.dart +++ b/lib/services/SessionService.dart @@ -262,6 +262,7 @@ class SessionService { // 自加字段 String? loginPhone; String? loginPass; + String? hiddenJson= "{confirm:1,rectify:1,check:1,special:1,extension:1,}"; // 内部:Prefs key static const String _prefsKey = 'session_service_v2'; diff --git a/lib/tools/MultiTextFieldWithTitle.dart b/lib/tools/MultiTextFieldWithTitle.dart index 51edd94..a2d8747 100644 --- a/lib/tools/MultiTextFieldWithTitle.dart +++ b/lib/tools/MultiTextFieldWithTitle.dart @@ -6,6 +6,7 @@ import 'package:qhd_prevention/customWidget/custom_button.dart'; import 'package:qhd_prevention/customWidget/dotted_border_box.dart'; import 'package:qhd_prevention/customWidget/photo_picker_row.dart'; import 'package:qhd_prevention/customWidget/single_image_viewer.dart'; +import 'package:qhd_prevention/customWidget/single_images_viewer.dart'; import 'package:qhd_prevention/http/ApiService.dart'; import 'package:qhd_prevention/tools/tools.dart'; @@ -26,6 +27,7 @@ class MultiTextFieldWithTitle extends StatefulWidget { final double fontSize; final bool isRequired; final bool isDeletFirst; + final int imageCount; final OperationType operationType; final ValueChanged>> onItemsChanged; @@ -41,6 +43,7 @@ class MultiTextFieldWithTitle extends StatefulWidget { this.isRequired = true, this.isAddImage = true, this.isDeletFirst = false, + this.imageCount = 1, this.operationType = OperationType.check, }); @@ -320,11 +323,11 @@ class _MultiTextFieldWithTitleState extends State { final text = _controllers[index].text; final imageList = _getImageListForIndex(index); final itemTitle = - widget.operationType == OperationType.check - ? '检查情况${index + 1}' - : '其他安全措施${index + 1}'; + widget.operationType == OperationType.check + ? '检查情况${index + 1}' + : '其他安全措施${index + 1}'; return Container( - margin: const EdgeInsets.only(bottom: 16), + margin: const EdgeInsets.only(bottom: 10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -363,27 +366,27 @@ class _MultiTextFieldWithTitleState extends State { width: double.maxFinite, child: DottedBorderBox( child: - widget.isEditable - ? TextField( - controller: _controllers[index], - decoration: InputDecoration( - hintText: widget.hintText, - ), - focusNode: _focusNodes[index], - keyboardType: TextInputType.multiline, - maxLines: 3, - style: TextStyle(fontSize: widget.fontSize), - ) - : Padding( - padding: const EdgeInsets.all(12), - child: Text( - text.isEmpty ? '暂无内容' : text, - style: TextStyle( - fontSize: widget.fontSize, - color: text.isEmpty ? Colors.grey : Colors.black, - ), - ), - ), + widget.isEditable + ? TextField( + controller: _controllers[index], + decoration: InputDecoration( + hintText: widget.hintText, + ), + focusNode: _focusNodes[index], + keyboardType: TextInputType.multiline, + maxLines: 3, + style: TextStyle(fontSize: widget.fontSize), + ) + : Padding( + padding: const EdgeInsets.all(12), + child: Text( + text.isEmpty ? '暂无内容' : text, + style: TextStyle( + fontSize: widget.fontSize, + color: text.isEmpty ? Colors.grey : Colors.black, + ), + ), + ), ), ), ), @@ -392,7 +395,7 @@ class _MultiTextFieldWithTitleState extends State { if (widget.isEditable && widget.isAddImage) RepairedPhotoSection( title: '图片', - maxCount: 1, + maxCount: widget.imageCount, isEdit: widget.isEditable, followInitialUpdates: true, // 关键:只传当前条目的图片数组 @@ -432,8 +435,12 @@ class _MultiTextFieldWithTitleState extends State { ), // 非编辑态显示只读图片 - if (!widget.isEditable && imageList.isNotEmpty) + if (!widget.isEditable && imageList.isNotEmpty&&widget.imageCount==1) _buildReadOnlyImage(imageList.first), + + if (!widget.isEditable && imageList.isNotEmpty&&widget.imageCount==4) + _buildReadOnlyFourImage(imageList), + ], ), ); @@ -475,6 +482,67 @@ class _MultiTextFieldWithTitleState extends State { ); } + Widget _buildReadOnlyFourImage( imagePath) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 7), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 8), + Text( + '图片:', + style: TextStyle( + fontSize: widget.fontSize - 1, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 10), + Wrap( + spacing: 8, // 水平间距 + runSpacing: 8, // 垂直间距 + children: List.generate(imagePath.length, (i) { + final url = ApiService.baseImgPath + imagePath[i]; + Widget img; + if (url.startsWith('http')) { + img = Image.network( + url, + height: 90, + width: 90 , + fit: BoxFit.fill, + ); + } else { + img = Image.asset( + url, + height: 90, + width: 90 , + fit: BoxFit.fill, + ); + } + return GestureDetector( + onTap: () { + presentOpaque( + SingleImagesViewer( + imageUrl: '', + imageUrls: imagePath, + initialIndex: i, + ), + context, + ); + }, + child: ClipRRect( + borderRadius: BorderRadius.circular(4), + child: img, + ), + ); + }), + ), + + + ], + ), + ); + } + ImageProvider _getImageProvider(String imagePath) { if (imagePath.startsWith('http')) { return NetworkImage(imagePath); From fb4df426ba5317b0fdb69ed1e34b955483267dd0 Mon Sep 17 00:00:00 2001 From: xufei <727302827@qq.com> Date: Thu, 16 Apr 2026 16:58:53 +0800 Subject: [PATCH 2/3] =?UTF-8?q?2026.4.16=20=E9=87=8D=E7=82=B9=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/images/videostart.png | Bin 0 -> 631 bytes lib/constants/app_enums.dart | 3 + lib/customWidget/item_list_widget.dart | 2 + lib/http/modules/key_tasks_api.dart | 38 + .../key_tasks_hidden_danger_detail.dart | 1512 +++++++++++++++++ .../key_tasks_hidden_danger_list.dart | 596 +++++++ .../keyTasks/key_tasks_check_list_page.dart | 2 +- .../home/keyTasks/key_tasks_tab_page.dart | 5 +- 8 files changed, 2155 insertions(+), 3 deletions(-) create mode 100644 assets/images/videostart.png create mode 100644 lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_detail.dart create mode 100644 lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_list.dart diff --git a/assets/images/videostart.png b/assets/images/videostart.png new file mode 100644 index 0000000000000000000000000000000000000000..0e90cdd28b7bbef7efa3063a437b8abcb2bbb337 GIT binary patch literal 631 zcmeAS@N?(olHy`uVBq!ia0vp^HXzKw3=&b&bO2Hn0X`wFK>GhcfMYA3tO44sUJ~RN z%;0c;>-?qNC%7A$GcLPBjAqW4ot| zV~EG`z1K7Qn+yaR9&UUp_GFUtf#Uw3|Nj>_Z(8S-o{>Gd*8a1KTbrE2_1;GHWIkT+2{EyrF)FKXb*O1hTG~17ol(l^vehN8A7}lWw%s!8v}N=nN7YrDKd4L&bDfb&ps@AB0T-50*~Pxr&7xA8rSHo2!A^Bf&P5CNe=z%8O`S{=DUAL_)_nM%nzz=>-ZclMa;}pY4h4S4?IqUhPh?e@Qu6B3iTA2Ixp zcXwcPnfLNzzs?rBKap}Q{Cd|}j&pbYzS@z`HG65!A=SW literal 0 HcmV?d00001 diff --git a/lib/constants/app_enums.dart b/lib/constants/app_enums.dart index c8ec46b..f7c0a21 100644 --- a/lib/constants/app_enums.dart +++ b/lib/constants/app_enums.dart @@ -396,6 +396,9 @@ enum UploadFileType { /// 重点工程隐患视频 - 类型: '173', 路径: 'key_projects_hidden_dangers_video' keyProjectsHiddenDangersVideo('173', 'key_projects_hidden_dangers_video'), + /// 重点工程 隐患整改图片 - 类型: '174', 路径: 'key_homework_rectification_pictures' + keyHomeworkRectificationPictures('174', 'key_homework_rectification_pictures'), + /// 重点工程签字 - 类型: '175', 路径: 'key_homework_signature_inspector' keyHomeworkSignatureInspector('175', 'key_homework_signature_inspector'), diff --git a/lib/customWidget/item_list_widget.dart b/lib/customWidget/item_list_widget.dart index c856e41..0f73eae 100644 --- a/lib/customWidget/item_list_widget.dart +++ b/lib/customWidget/item_list_widget.dart @@ -924,6 +924,7 @@ class ItemListWidget { double fontSize = 14, // 字体大小 Color btnColor = Colors.blue, bool isRequired = false, + bool isShowPoint = true, }) { return Container( padding: const EdgeInsets.symmetric( @@ -935,6 +936,7 @@ class ItemListWidget { children: [ Row( children: [ + if(isShowPoint) Text("* ", style: TextStyle(color: Colors.red)), Text( label, diff --git a/lib/http/modules/key_tasks_api.dart b/lib/http/modules/key_tasks_api.dart index cbacb68..95f9620 100644 --- a/lib/http/modules/key_tasks_api.dart +++ b/lib/http/modules/key_tasks_api.dart @@ -94,5 +94,43 @@ class KeyTasksApi { } + /// 安全环保检查 隐患分页 + static Future> setKeyTasksHiddenDangerList(Map data) { + return HttpManager().request( + '${ApiService.basePath}/keyProject', + '/hidden/list', + method: Method.post, + data: { + ...data + }, + ); + } + + + /// 安全环保检查 隐患详情 + static Future> getKeyTasksHiddenDangerDetail(String id) { + return HttpManager().request( + '${ApiService.basePath}/keyProject', + '/hidden/$id', + method: Method.get, + data: { + // ...data + }, + ); + } + + /// 安全环保检查 隐患整改提交 + static Future> setHiddenDangerRectification(Map data) { + return HttpManager().request( + '${ApiService.basePath}/keyProject', + '/hiddenRectificationRecord/rectification', + method: Method.post, + data: { + ...data + }, + ); + } + + } \ No newline at end of file diff --git a/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_detail.dart b/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_detail.dart new file mode 100644 index 0000000..74d251c --- /dev/null +++ b/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_detail.dart @@ -0,0 +1,1512 @@ +import 'dart:io'; + +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:intl/intl.dart'; +import 'package:open_file/open_file.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:qhd_prevention/constants/app_enums.dart'; +import 'package:qhd_prevention/customWidget/DocumentPicker.dart'; +import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart'; +import 'package:qhd_prevention/customWidget/MultiDictValuesPicker.dart'; +import 'package:qhd_prevention/customWidget/big_video_viewer.dart'; +import 'package:qhd_prevention/customWidget/bottom_picker_two.dart'; +import 'package:qhd_prevention/customWidget/custom_button.dart'; +import 'package:qhd_prevention/customWidget/department_person_picker.dart'; +import 'package:qhd_prevention/customWidget/department_picker.dart'; +import 'package:qhd_prevention/customWidget/department_picker_three.dart'; +import 'package:qhd_prevention/customWidget/department_picker_two.dart'; +import 'package:qhd_prevention/customWidget/full_screen_video_page.dart'; +import 'package:qhd_prevention/customWidget/item_list_widget.dart'; +import 'package:qhd_prevention/customWidget/photo_picker_row.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/customWidget/toast_util.dart'; +import 'package:qhd_prevention/http/ApiService.dart'; +import 'package:qhd_prevention/http/modules/key_tasks_api.dart'; +import 'package:qhd_prevention/pages/home/keyTasks/keyTasksDetail/key_taskes_detail_widget.dart'; +import 'package:qhd_prevention/pages/home/keyTasks/keyTasksDetail/key_taskes_onlylook_detail_page.dart'; +import 'package:qhd_prevention/pages/my_appbar.dart'; +import 'package:qhd_prevention/services/SessionService.dart'; +import 'package:qhd_prevention/tools/h_colors.dart'; +import 'package:qhd_prevention/tools/tools.dart'; +import 'dart:convert'; +import 'package:video_player/video_player.dart'; +import 'package:qhd_prevention/http/modules/safety_check_api.dart'; + +class KeyTasksHiddenDangerDetail extends StatefulWidget { + const KeyTasksHiddenDangerDetail( + this.item, + this.itemId, + this.hiddenId, + this.foreignKey, + this.canChange, { + Key? key, + this.inspectId, + this.inspectCodeId, + }) : super(key: key); + + final item; // 1 隐患整改 2 隐患记录 + final String itemId; + final String hiddenId; + final String foreignKey; + final bool canChange; + final String? inspectId; + final String? inspectCodeId; + + @override + _KeyTasksHiddenDangerDetailState createState() => _KeyTasksHiddenDangerDetailState(); +} + +class _KeyTasksHiddenDangerDetailState extends State { + late Map pd = {}; + + List files = []; + List videoList = []; + List files2 = []; + + List files4 = []; + List files5 = []; //验收图片 + List files6 = []; //安全环保检查验收图片 + List checkList = []; + List files7 = []; + + //隐患整改照片集合 + List> rectifiedPhotosList = []; + + //隐患验收照片集合 + List> acceptancePhotosList = []; + + bool modalShow = false; + VideoPlayerController? _videoController; + + ///隐患确认 + String buMenId = ""; + String buMenName = ""; + String responsibleId = ""; + String responsibleName = ""; + + // 存储各单位的人员列表缓存: key = deptId + final Map>> _personCache = {}; + + String attachmentUp = '处置方案附件'; + // 整改图片 + List gaiHouImages = []; + + + ///隐患验收 + // 是否合格 + bool _hazardAcceptanceQualified = true; + final TextEditingController _acceptanceDescriptionController = + TextEditingController(); + final TextEditingController _replyFeedbackController = + TextEditingController(); + List _acceptanceImages = []; + + // 查看过程记录 + bool _showAllData = false; + + //附件 + late SelectedFile? choosefile = null; + + String title='隐患记录'; + final TextEditingController _descriptionController = TextEditingController(); + + @override + void initState() { + super.initState(); + + switch (widget.item) { + case 1: //隐患整改 + title = "隐患整改"; + hiddenDangerRectification['id']=widget.itemId; + hiddenDangerRectification['foreignKey']=widget.foreignKey; + hiddenDangerRectification['hiddenId']=widget.hiddenId; + + break; + case 2: //隐患记录 + title='隐患记录'; + break; + } + + + _getUserData(); + getData(); + } + + + @override + void dispose() { + _videoController?.dispose(); + super.dispose(); + } + + Future getData() async { + try { + final data = await KeyTasksApi.getKeyTasksHiddenDangerDetail(widget.itemId); + if (data['success']) { + setState(() { + pd = data['data']; + _getImagePath( + widget.hiddenId, + UploadFileType.keyProjectsHiddenDangersPictures, + ); + _getImagePath( + widget.hiddenId, + UploadFileType.keyProjectsHiddenDangersVideo, + ); + if (pd['rectificationRecord'] != null){ + _getImagePath( + widget.itemId, + UploadFileType.keyHomeworkRectificationPictures, + ); + } + + }); + } else { + ToastUtil.showNormal(context, "获取列表失败"); + } + } catch (e) { + print('Error fetching data: $e'); + } + } + + Future _getUserData() async { + try { + final raw = await AuthApi.getUserData(); + if (raw['success']) { + setState(() { + responsibleId = raw['data']['id']; + responsibleName = raw['data']['name']; + buMenId = raw['data']['departmentId']; + buMenName = raw['data']['departmentName']; + }); + } else { + ToastUtil.showNormal(context, "获取个人信息失败"); + } + } catch (e) { + // 出错时可以 Toast 或者在页面上显示错误状态 + print('加载首页数据失败:$e'); + } + } + + Future _getImagePath(id, type) async { + try { + final data = await FileApi.getImagePath(id, type); + if (data['success']) { + setState(() { + List images = data['data'] ?? []; + if (UploadFileType.keyProjectsHiddenDangersPictures == type) { + files.addAll(images); + } else if (UploadFileType.keyProjectsHiddenDangersVideo == type) { + videoList.addAll(images); + }else if (UploadFileType.keyHomeworkRectificationPictures == type) { + files2.addAll(images); + } + + + }); + } else { + // ToastUtil.showNormal(context, "获取图片失败"); + } + } catch (e) { + print('Error fetching data: $e'); + } + } + + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: MyAppbar(title: title), + body: + pd.isEmpty + ? const Center(child: CircularProgressIndicator()) + : _listWidget(), + ); + } + + Widget _listWidget() { + List list = pd["hiddenAcceptUserCO"] ?? []; + + return LayoutBuilder( + builder: (context, constraints) { + return SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: constraints.maxHeight), + child: Padding( + padding: const EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + Card( + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only( + top: 10, + left: 10, + right: 10, + ), + child: Row( + children: [ + Container( + width: 3, + height: 15, + color: Colors.blue, + ), + const SizedBox(width: 8), + Text( + "检查记录", + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + + _buildInfoItem( + '重点作业名称', + pd["projectName"] ?? '', + ), + Divider(height: 1), + ItemListWidget.OneRowButtonTitle( + isShowPoint: false, + label: '安全环保检查信息:', + buttonText: '【关联检查流程】', + onTap: () { + pushPage( + KeyTaskesOnlylookDetailPage(inspectionId: widget.foreignKey ?? '', handleType: SafeCheckDetailMode.detail), + context, + ); + }, + ), + + ], + ), + ), + + //隐患信息 + SizedBox(height: 10), + Card( + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only( + top: 10, + left: 10, + right: 10, + ), + child: Row( + children: [ + Container( + width: 3, + height: 15, + color: Colors.blue, + ), + const SizedBox(width: 8), + Text( + "隐患信息", + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + + _buildInfoItem('隐患来源', _getSourceDangers(pd)), + + Divider(height: 1), + _buildInfoItem('隐患类型', pd['hiddenTypeName'] ?? ''), + + Divider(height: 1), + _buildInfoItem('隐患级别', pd['hiddenLevelName'] ?? ''), + + Divider(height: 1), + _buildInfoItem('隐患状态', _getState(pd)), + + Divider(height: 1), + _buildInfoItem('隐患描述', pd['hiddenDesc'] ?? ''), + + + if ((pd['positionDesc'] ?? '').isNotEmpty) + Divider(height: 1), + if ((pd['positionDesc'] ?? '').isNotEmpty) + _buildInfoItem('隐患位置描述', pd['positionDesc'] ?? ''), + + Divider(height: 1), + _buildInfoItem( + '整改类型', + _getRectificationType(pd['rectificationType']), + ), + + Divider(height: 1), + _buildInfoItem('整改期限', pd['rectificationDeadline'] ?? ''), + + Divider(height: 1), + _buildInfoItem('整改部门', pd['rectificationDepartmentName'] ?? ''), + + Divider(height: 1), + _buildInfoItem('整改人', pd['rectificationUserName'] ?? ''), + + Divider(height: 1), + _buildInfoItem('隐患发现部门', pd['findDepartmentName'] ?? ''), + + Divider(height: 1), + _buildInfoItem('隐患发现人', pd['findUserName'] ?? ''), + + Divider(height: 1), + _buildInfoItem('隐患发现时间', _changeTime(pd['createTime'] ?? ''),), + + + Divider(height: 1), + // 隐患照片 + // const Text('隐患照片', style: TextStyle(fontWeight: FontWeight.bold)), + // _buildImageGrid(files, onTap: (index) => _showImageGallery(files, index)), + ListItemFactory.createTextImageItem( + text: "隐患照片", + imageUrls: + files + .map((item) => item['filePath'].toString()) + .toList(), + horizontalPadding: 10, + onImageTapped: (index) { + presentOpaque( + SingleImageViewer( + imageUrl: '', + imageUrls: + files + .map( + (item) => + ApiService.baseImgPath + + item['filePath'], + ) + .toList(), + initialIndex: index, + ), + context, + ); + }, + ), + + // 隐患视频 + if (videoList.isNotEmpty) ...[ + SizedBox(height: 10), + Padding( + padding: EdgeInsets.only(left: 10, right: 10), + child: Text( + '隐患视频', + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), + + GestureDetector( + onTap: () { + showDialog( + context: context, + barrierColor: Colors.black54, + builder: + (_) => VideoPlayerPopup( + videoUrl: + ApiService.baseImgPath + + videoList[0]['filePath'], + ), + ); + }, + child: Image.asset( + 'assets/images/videostart.png', // 替换为你的视频占位图 + color: Colors.blue, + width: 120, + height: 120, + ), + ), + ], + ], + ), + ), + + + // 整改信息(发现人预填) + if (pd['rectificationRecord'] != null) ...[ + SizedBox(height: 10), + // const Divider(height: 10,color: Colors.grey,), + Card( + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only( + top: 10, + left: 10, + right: 10, + ), + child: Row( + children: [ + Container( + width: 3, + height: 15, + color: Colors.blue, + ), + const SizedBox(width: 8), + Text( + "整改信息", + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + + _buildInfoItem( + '整改部门', + pd["rectificationRecord"]['rectificationDepartmentIdName'] ?? '', + ), + Divider(height: 1), + _buildInfoItem( + '整改人', + pd["rectificationRecord"]['rectificationUserIdName'] ?? '', + ), + + Divider(height: 1), + _buildInfoItem( + '整改时间', + _changeTime( pd["rectificationRecord"]['rectificationTime'] ?? ''), + // pd["rectificationRecord"]['rectificationTime'] ?? '', + ), + + Divider(height: 1), + _buildInfoItem( + '整改描述', + // _changeTime( pd["hiddenUserPresetsCO"]['rectifyDeadline'] ?? ''), + pd["rectificationRecord"]['rectificationDesc'] ?? '', + ), + + ListItemFactory.createTextImageItem( + text: "整改后图片", + imageUrls: + files2.map((item) => item['filePath'].toString()).toList(), + horizontalPadding: 10, + onImageTapped: (index) { + presentOpaque( + SingleImageViewer( + imageUrl: + ApiService.baseImgPath + files2[index]['filePath'], + ), + context, + ); + }, + ), + + ], + ), + ), + ], + + + // // 整改信息 + // if (pd['hiddenRectifyUserCO'] != null && + // (pd["state"] != 100) && + // (widget.item == 6 || widget.item == 7)) ...[ + // SizedBox(height: 10), + // + // // const Divider(height: 10,color: Colors.grey,), + // if (!_showAllData) + // _ectificationInformationItem( + // pd["hiddenRectifyUserCO"][(pd["hiddenRectifyUserCO"] + // .length - + // 1)], + // 0, + // ), + // + // if (_showAllData) + // ListView.builder( + // shrinkWrap: true, // 自适应内容高度 + // physics: const NeverScrollableScrollPhysics(), + // itemCount: pd["hiddenRectifyUserCO"].length, + // itemBuilder: + // (ctx, idx) => _ectificationInformationItem( + // pd["hiddenRectifyUserCO"][idx], + // idx, + // ), + // ), + // ], + + // // 验收信息 + // if (pd['hiddenAcceptUserCO'] != null && + // (pd["state"] != 100) && + // ((widget.item == 7) || (widget.item == 3))) ...[ + // SizedBox(height: 10), + // + // // const Divider(height: 10,color: Colors.grey,), + // if (!_showAllData) + // _acceptanceInformationItem(list.last, (list.length - 1)), + // + // if (_showAllData) + // ListView.builder( + // shrinkWrap: true, // 自适应内容高度 + // physics: const NeverScrollableScrollPhysics(), + // itemCount: pd["hiddenAcceptUserCO"].length, + // itemBuilder: + // (ctx, idx) => _acceptanceInformationItem( + // pd["hiddenAcceptUserCO"][idx], + // idx, + // ), + // ), + // ], + + + + ///=============以下是操作 + //隐患整改操作 + if (widget.item==1)...[ + SizedBox(height: 10), + Card( + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only( + top: 10, + left: 10, + right: 10, + ), + child: Row( + children: [ + Container( + width: 3, + height: 15, + color: Colors.blue, + ), + const SizedBox(width: 8), + Text( + "整改信息", + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + + + GestureDetector( + onTap: () async { + DateTime? picked = await BottomDateTimePicker.showDate( + mode: BottomPickerMode.dateTimeWithSeconds, + context, + allowPast:false, + ); + if (picked != null) { + setState(() { + hiddenDangerRectification['rectificationTime']= DateFormat('yyyy-MM-dd HH:mm:ss').format(picked); + }); + } + + }, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 15), + child: ListItemFactory.createRowSpaceBetweenItem( + isRequired:true, + leftText: "整改时间", + rightText: hiddenDangerRectification['rectificationTime'].isNotEmpty?hiddenDangerRectification['rectificationTime']:"请选择", + isRight: true, + ), + ), + ), + + const Divider(height: 1), + Container( + padding: EdgeInsets.all(15), + child: Column( + children: [ + ListItemFactory.createBuildMultilineInput( + isRequired:true, + "整改描述", + "请对整改进行详细描述(必填项)", + _descriptionController, + ), + ], + ), + ), + + ItemListWidget.itemContainer( + RepairedPhotoSection( + isRequired:true, + title: "整改照片", + maxCount: 4, + mediaType: MediaType.image, + onChanged: (files) { + // 上传 files 到服务器 + gaiHouImages.clear(); + for(int i=0;i files) { + // // 上传图片 files + // _acceptanceImages.clear(); + // for (int i = 0; i < files.length; i++) { + // _acceptanceImages.add(files[i].path); + // } + // }, + // onAiIdentify: () {}, + // ), + // ), + // ], + // + // Divider(height: 1), + // if (!_hazardAcceptanceQualified) + // ItemListWidget.twoRowSelectableTitleText( + // label: '打回意见', + // isEditable: true, + // text: '请输入', + // isRequired: true, + // showSelect: false, + // controller: _replyFeedbackController, + // ), + // ], + // ), + // ), + // ], + + + + + + + //操作按钮 + + if (widget.item==1)...[ + SizedBox(height: 10,), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + + // 查看详情按钮 + Expanded( + child: CustomButton( + height: 35, + onPressed: () { + _setHiddenDangerRectification(); + + // _setHiddenDangerAcceptance(); + }, + textStyle: const TextStyle(color: Colors.white), + buttonStyle: ButtonStyleType.primary, + text: '提交', + ), + ), + + ], + ), + ], + + // 添加底部安全区域间距 + SizedBox(height: MediaQuery.of(context).padding.bottom + 20), + ], + ), + ), + ), + ); + }, + ); + } + + + Widget _buildInfoItem(String title, String value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 120, + child: Text( + title, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + Expanded(child: Text(value, textAlign: TextAlign.right)), + ], + ), + ); + } + + //隐患整改 + Future _setHiddenDangerRectification() async { + try { + + String miaoShu = _descriptionController.text.trim(); + if (miaoShu.isEmpty) { + ToastUtil.showNormal(context, "请填整改描述"); + return; + } + hiddenDangerRectification['rectificationDesc'] = miaoShu; + + String dataTime = hiddenDangerRectification['rectificationTime']??''; + if (dataTime.isEmpty) { + ToastUtil.showNormal(context, "请选择整改时间"); + return; + } + + if (gaiHouImages.isEmpty) { + ToastUtil.showNormal(context, "请上传整改照片"); + return; + } + + LoadingDialogHelper.show(); + + if (gaiHouImages.isNotEmpty) { + await _addImgFilesZhengGaiID( + gaiHouImages, + UploadFileType.keyHomeworkRectificationPictures, + ); + } + + + LoadingDialogHelper.show(); + final Map raw = await KeyTasksApi.setHiddenDangerRectification(hiddenDangerRectification,); + + if (raw['success']) { + LoadingDialogHelper.hide(); + setState(() { + ToastUtil.showNormal(context, "提交成功"); + Navigator.of(context).pop('1'); + }); + } else { + ToastUtil.showNormal(context, "提交失败"); + LoadingDialogHelper.hide(); + } + } catch (e) { + // 出错时可以 Toast 或者在页面上显示错误状态 + print('加载首页数据失败:$e'); + LoadingDialogHelper.hide(); + } + } + + //隐患验收 + Future _setHiddenDangerAcceptance() async { + try { + if (_hazardAcceptanceQualified) { + hiddenDangerAcceptance['status'] = 1; + String text = _acceptanceDescriptionController.text.trim(); + if (text.isEmpty) { + ToastUtil.showNormal(context, "请填写验收描述"); + return; + } + hiddenDangerAcceptance['descr'] = text; + + if (hiddenDangerAcceptance['rectificationTime'].isEmpty) { + ToastUtil.showNormal(context, "请选择验收日期"); + return; + } + + // if(_acceptanceImages.isEmpty){ + // ToastUtil.showNormal(context, "请选择验收图片"); + // return; + // } + + if (_acceptanceImages.isNotEmpty) { + await _addImgFiles( + _acceptanceImages, + UploadFileType.hiddenDangerVerificationPhoto, + hiddenDangerAcceptance['hiddenId'], + ); + } + } else { + hiddenDangerAcceptance['status'] = 0; + String text = _replyFeedbackController.text.trim(); + if (text.isEmpty) { + ToastUtil.showNormal(context, "请填写打回意见"); + return; + } + hiddenDangerAcceptance['repulseCause'] = text; + } + + LoadingDialogHelper.show(); + final raw = await HiddenDangerApi.setHiddenDangerAcceptance( + hiddenDangerAcceptance, + ); + if (raw['success']) { + LoadingDialogHelper.hide(); + setState(() { + ToastUtil.showNormal(context, "提交成功"); + Navigator.of(context).pop('1'); + }); + } else { + ToastUtil.showNormal(context, "提交失败"); + LoadingDialogHelper.hide(); + } + } catch (e) { + // 出错时可以 Toast 或者在页面上显示错误状态 + print('加载首页数据失败:$e'); + LoadingDialogHelper.hide(); + } + } + + /// 拉取某单位人员并缓存(兼容返回结构) + Future _getPersonListForUnitId(String id) async { + if (id.isEmpty) return; + LoadingDialogHelper.show(); + try { + final result = await BasicInfoApi.getDeptUsers(id); + LoadingDialogHelper.hide(); + // 兼容 result['data'] / result['userList'] 等常见字段 + dynamic raw = result['data']; + List> list = []; + if (raw is List) { + list = + raw.map>((e) { + if (e is Map) return e; + if (e is Map) return Map.from(e); + return {}; + }).toList(); + } else { + list = []; + } + setState(() { + _personCache[id] = list; + }); + } catch (e) { + LoadingDialogHelper.hide(); + ToastUtil.showError(context, '获取人员失败:$e'); + setState(() { + _personCache[id] = []; + }); + } + } + + + + // String _getSourceDangers(final item) { + // int type = item["source"]; + // if (1 == type) { + // return "隐患快报"; + // } else if (2 == type) { + // return "清单排查"; + // } else if (3 == type) { + // return "标准排查"; + // } else if (4 == type) { + // return "安全环保检查(监管端)"; + // } else if (5 == type) { + // return "安全环保检查(企业端)"; + // } else if (6 == type) { + // return "消防点检"; + // }else if (7 == type) { + // return "视频巡屏"; + // } else { + // return "NFC设备巡检"; + // } + // } + // String _getState(final item) { + // int type = item["state"]; + // if (100 == type) { + // return "待确认"; + // } else if (200 == type) { + // return "未整改"; + // } else if (201 == type) { + // return "确认打回"; + // } else if (202 == type) { + // return "待处理特殊隐患"; + // } else if (300 == type) { + // return "已整改"; + // } else if (301 == type) { + // return "已验收"; + // } else if (302 == type) { + // return "验收打回"; + // } else if (303 == type) { + // return "验收打回"; + // } else if (400 == type) { + // return "已处理特殊隐患"; + // } else if (99 == type) { + // return "强制关闭(人员变动)"; + // } else if (98 == type) { + // return "安全环保检查/清单排查暂存"; + // } else if (102 == type) { + // return "安全环保检查,隐患待指派"; + // } else if (97 == type) { + // return "已过期"; + // } else if (101 == type) { + // return "忽略隐患"; + // } else { + // return "已过期"; + // } + // } + + String _getSourceDangers(final item) { + int type = item["source"] ?? 0; + if (1 == type) { + return "隐患来源:安全环保检查(监管端)"; + } else if (2 == type) { + return "隐患来源:安全环保检查(企业端)"; + } else { + return "隐患来源:"; + } + } + + String _getState(final item) { + //1,未整改,2:已整改,3:已验收,4:验收打回 + int type = item["state"]; + if(1==type){ + return "未整改"; + }else if(2==type){ + return "已整改"; + }else if(3==type){ + return "已验收"; + }else if(4==type){ + return "验收打回"; + }else{ + return ""; + } + } + + + String _changeTime(String time) { + try { + // 解析 ISO 8601 格式的时间字符串 + DateTime dateTime = DateTime.parse(time); + // 格式化为年月日 + return DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime); + } catch (e) { + // 如果解析失败,返回原字符串或默认值 + return ''; + } + } + + String _getRectificationType(int? type) { + switch (type) { + case 1: + return '立即整改'; + case 2: + return '限期整改'; + default: + return ''; + } + } + + Future _addImgFiles( + List imagePaths, + UploadFileType type, + String hiddenId, + ) async { + try { + final raw = await FileApi.uploadFiles(imagePaths, type, ''); + if (raw['success']) { + hiddenDangerAcceptance['hiddenUserId'] = raw['data']['foreignKey']; + return raw['data']; + } else { + // _showMessage('反馈提交失败'); + return ""; + } + } catch (e) { + // 出错时可以 Toast 或者在页面上显示错误状态 + print('加载首页数据失败:$e'); + return ""; + } + } + + Future _addImgFilesZhengGai( + List imagePaths, + UploadFileType type, + ) async { + try { + final raw = await FileApi.uploadFiles(imagePaths, type, ''); + if (raw['success']) { + hiddenDangerRectification['hiddenSchemeId'] = raw['data']['foreignKey']; + + return raw['data']; + } else { + // _showMessage('反馈提交失败'); + return ""; + } + } catch (e) { + // 出错时可以 Toast 或者在页面上显示错误状态 + print('加载首页数据失败:$e'); + return ""; + } + } + + Future _addImgFilesZhengGaiID( + List imagePaths, + UploadFileType type, + ) async { + try { + final raw = await FileApi.uploadFiles(imagePaths, type, widget.itemId); + if (raw['success']) { + // raw['data']['foreignKey']; + return raw['data']; + } else { + // _showMessage('反馈提交失败'); + return ""; + } + } catch (e) { + // 出错时可以 Toast 或者在页面上显示错误状态 + print('加载首页数据失败:$e'); + return ""; + } + } + + + + String _getText(int source) { + if (source == 1) { + return "是"; + } else { + return "否"; + } + } + + String _delayInformationText(text) { + if (text != '') { + if (text == 1) { + return "通过"; + } else { + return "未通过"; + } + } else { + return ""; + } + } + + String _delayInformationTextTwo(text) { + if (text != '') { + if (text == 1) { + return "待审核"; + }else if(text == 2){ + return "审批中"; + }else if(text == 3){ + return "已通过"; + }else if(text == 4){ + return "已拒绝"; + } else if(text == 5){ + return "已撤回"; + } else { + return "未通过"; + } + } else { + return ""; + } + } + + //整改信息 + Widget _ectificationInformationItem(itemData, int idx) { + return Card( + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 10, left: 10, right: 10), + child: Row( + children: [ + Container(width: 3, height: 15, color: Colors.blue), + const SizedBox(width: 8), + Text( + "整改信息", + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + + _buildInfoItem( + pd["isRelated"] == 0 ? '整改部门' : '整改单位(相关方项目)', + itemData['deptName'] ?? '', + ), + Divider(height: 1), + _buildInfoItem( + pd["isRelated"] == 0 ? '整改人' : '整改人(相关方项目)', + itemData['userName'] ?? '', + ), + + if (itemData['status'] != 0) ...[ + Divider(height: 1), + _buildInfoItem( + '整改时间', + _changeTime( itemData['rectificationTime'] ?? ''), + // itemData['rectificationTime'] ?? '', + ), + Divider(height: 1), + _buildInfoItem('整改描述', itemData['descr'] ?? ''), + Divider(height: 1), + _buildInfoItem('临时整改措施', itemData['remarks'] ?? ''), + Divider(height: 1), + _buildInfoItem( + '投入资金', + '${itemData['investmentFunds'].toString() ?? ''}元', + ), + + Divider(height: 1), + // const Text('整改后图片', style: TextStyle(fontWeight: FontWeight.bold)), + // _buildImageGrid(files2, onTap: (index) => _showImageGallery(files2, index)), + ListItemFactory.createTextImageItem( + text: "整改后图片", + imageUrls: + files2.map((item) => item['filePath'].toString()).toList(), + horizontalPadding: 10, + onImageTapped: (index) { + presentOpaque( + SingleImageViewer( + imageUrl: + ApiService.baseImgPath + files2[index]['filePath'], + ), + context, + ); + }, + ), + + Divider(height: 1), + _buildInfoItem( + '整改方案', + itemData['isRectificationScheme'] == 1 ? '有' : '无', + ), + Divider(height: 1), + if (itemData['isRectificationScheme'] == 1 && + itemData["hiddenSchemeCO"] != null) + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // _buildInfoItem( + // '排查日期', + // itemData["hiddenSchemeCO"]['screeningDate'] ?? '', + // ), + + // Divider(height: 1), + _buildInfoItem( + '治理标准', + itemData["hiddenSchemeCO"]['governStanDards'] ?? '', + ), + Divider(height: 1), + _buildInfoItem( + '治理方法', + itemData["hiddenSchemeCO"]['governMethod'] ?? '', + ), + Divider(height: 1), + _buildInfoItem( + '经费落实', + itemData["hiddenSchemeCO"]['expenditure'] ?? '', + ), + Divider(height: 1), + _buildInfoItem( + '负责人员', + itemData["hiddenSchemeCO"]['principal'] ?? '', + ), + Divider(height: 1), + _buildInfoItem( + '工时安排', + itemData["hiddenSchemeCO"]['programming'] ?? '', + ), + Divider(height: 1), + _buildInfoItem( + '时限要求', + itemData["hiddenSchemeCO"]['timeLimitFor'] ?? '', + ), + Divider(height: 1), + _buildInfoItem( + '工作要求', + itemData["hiddenSchemeCO"]['jobRequireMent'] ?? '', + ), + Divider(height: 1), + _buildInfoItem( + '其他事项', + itemData["hiddenSchemeCO"]['otherBusiness'] ?? '', + ), + Divider(height: 1), + ListItemFactory.createTextImageItem( + text: "方案图片", + imageUrls: + files4 + .map((item) => item['filePath'].toString()) + .toList(), + horizontalPadding: 10, + onImageTapped: (index) { + presentOpaque( + SingleImageViewer( + imageUrl: + ApiService.baseImgPath + + files4[index]['filePath'], + ), + context, + ); + }, + ), + ], + ), + ], + + if (itemData['status'] == 0) ...[ + Divider(height: 1), + _buildInfoItem('是否正常整改', '否'), + Divider(height: 1), + _buildInfoItem('无法整改原因', itemData['repulseCause'] ?? ''), + ], + ], + ), + ); + } + + //验收信息 + Widget _acceptanceInformationItem(itemData, int idx) { + // if(!_showAllData&&itemData['status']!=null&&itemData['status']==0){ + // return SizedBox(); + // }else{ + return Card( + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 10, left: 10, right: 10), + child: Row( + children: [ + Container(width: 3, height: 15, color: Colors.blue), + const SizedBox(width: 8), + Text( + "验收信息", + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + + _buildInfoItem( + '验收部门', + // pd["isRelated"]==0?'验收部门':'验收单位(相关方项目)', + itemData['deptName'] ?? '', + ), + Divider(height: 1), + _buildInfoItem( + '验收人', + // pd["isRelated"]==0?'验收人':'验收人(相关方项目)', + itemData['userName'] ?? '', + ), + Divider(height: 1), + _buildInfoItem( + '验收时间', + _changeTime(itemData['rectificationTime'] ?? ''), + ), + + if (itemData['status'] != null && itemData['status'] == 0) ...[ + Divider(height: 1), + _buildInfoItem('是否合格', '不合格'), + Divider(height: 1), + _buildInfoItem('验收打回意见', itemData['repulseCause'] ?? ''), + ], + + if (itemData['status'] != 0) ...[ + Divider(height: 1), + _buildInfoItem('是否合格', '合格'), + + if ((itemData['descr'] ?? '').isNotEmpty) ...[ + Divider(height: 1), + _buildInfoItem( + '验收描述', + itemData['descr'] ?? '', + // itemData['repulseCause'] ?? '', + ), + ], + + if (acceptancePhotosList.isNotEmpty && + getFilePathList(acceptancePhotosList, idx).isNotEmpty) ...[ + Divider(height: 1), + ListItemFactory.createTextImageItem( + text: "验收图片", + // imageUrls: files5.map((item) => item['filePath'].toString()).toList(), + imageUrls: getFilePathList(acceptancePhotosList, idx), + horizontalPadding: 10, + onImageTapped: (index) { + presentOpaque( + SingleImageViewer( + imageUrl: + ApiService.baseImgPath + + // files5[index]['filePath'], + acceptancePhotosList[idx][index]['filePath'], + ), + context, + ); + }, + ), + ], + ], + ], + ), + ); + // } + } + + List getFilePathList(List list, int idx) { + // List list= oldList.reversed.toList(); + if (list.isEmpty || idx < 0 || idx >= list.length || list[idx] == null) { + return []; // 返回空列表作为默认值 + } + + final items = list[idx]; + if (items == null || items.isEmpty) { + return []; + } + + // 方法1:使用 cast() + return (items as List) + .map( + (item) => + (item as Map)['filePath']?.toString() ?? '', + ) + .toList(); + } + + + //隐患整改 + Map hiddenDangerRectification = { + "hiddenRectificationRecordId":"", + "foreignKey": "", + "hiddenId": "", + "rectificationTime": "", + "rectificationDesc": "", + }; + + //隐患验收 + Map hiddenDangerAcceptance = { + "id": "", + "hiddenId": "", + "hiddenUserId": "", + "status": "", + "descr": "", + "rectificationTime": "", + "repulseCause": "", + "checkUserId": "", + }; +} diff --git a/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_list.dart b/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_list.dart new file mode 100644 index 0000000..57d64b7 --- /dev/null +++ b/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_list.dart @@ -0,0 +1,596 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:qhd_prevention/CustomWidget/range_filter_bar.dart'; +import 'package:qhd_prevention/customWidget/custom_button.dart'; +import 'package:qhd_prevention/customWidget/search_bar_widget.dart'; +import 'package:qhd_prevention/customWidget/toast_util.dart'; +import 'package:qhd_prevention/http/ApiService.dart'; +import 'package:qhd_prevention/http/modules/key_tasks_api.dart'; +import 'package:qhd_prevention/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_detail.dart'; +import 'package:qhd_prevention/pages/my_appbar.dart'; +import 'package:qhd_prevention/tools/h_colors.dart'; +import 'package:qhd_prevention/tools/tools.dart'; +import 'dart:async'; + + + +class KeyTasksHiddenDangerList extends StatefulWidget { + const KeyTasksHiddenDangerList( this.appItem, {super.key}); + + + final int appItem;// 1 隐患整改 2 隐患记录 + + @override + State createState() => _KeyTasksHiddenDangerListState(); +} + +class _KeyTasksHiddenDangerListState extends State { + int _page = 1; + String searchKey = ""; + int _totalPage = 1; + late List _list = []; + bool _isLoading = false; + bool _hasMore = true; + Timer? _debounceTimer; + String buttonTextOne = '查看'; + String buttonTextTwo = '确认'; + String title = "隐患记录"; + + final TextEditingController _searchController = TextEditingController(); + + bool isJGD = false; + + @override + void initState() { + super.initState(); + // 初始均为空 + + _searchController.addListener(_onSearchChanged); + + switch (widget.appItem) { + case 1: + buttonTextTwo = '整改'; + title = "隐患整改"; + keyTasksHiddenDangerListData['stateList']=[1]; + break; + case 2: + buttonTextTwo = '查看'; + title = "隐患记录"; + keyTasksHiddenDangerListData['stateList']=[1,2,3,4]; + break; + } + + _getListData(false); + } + + @override + void dispose() { + _debounceTimer?.cancel(); + _searchController.removeListener(_onSearchChanged); + _searchController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + // 取屏幕宽度 + final double screenWidth = MediaQuery.of(context).size.width; + + return Scaffold( + appBar: MyAppbar(title:title), + + body: SafeArea( + child: NotificationListener( + onNotification: _onScroll, + child: _vcDetailWidget(), + ), + ), + backgroundColor: Colors.white, + ); + } + + Widget _vcDetailWidget() { + return Column( + children: [ + + if(widget.appItem==1) + Padding( + padding: EdgeInsets.all(10), + child: SearchBarWidget( + controller: _searchController, + isShowSearchButton: true, + showResetButton:true, + hintText: '请输入隐患描述', + onTextChanged: (value) {}, + onSearch: (keyboard) { + _performSearch(_searchController.text); + }, + ), + ), + + if(widget.appItem==2) + RangeFilterBar( + initial: RangeOption.none, + onRangeChanged: (range) { + String searchData=''; + switch (range) { + case RangeOption.oneWeek: + final data = DateTime.now().subtract( + const Duration(days: 7), + ); + final time = DateFormat('yyyy-MM-dd').format(data); + searchData = time; + break; + case RangeOption.oneMonth: + final data = DateTime.now().subtract( + const Duration(days: 30), + ); + final time = DateFormat('yyyy-MM-dd').format(data); + searchData = time; + break; + case RangeOption.threeMonths: + final data = DateTime.now().subtract( + const Duration(days: 90), + ); + final time = DateFormat('yyyy-MM-dd').format(data); + searchData = time; + case RangeOption.none: + break; + case RangeOption.oneDay: + break; + } + _performSearch(searchData); + }, + onFilterPressed: () async { + // 弹出筛选对话框或跳转到筛选页面 + String searchData=''; + // searchData = await pushPage( + // SafecheckListfilterPage( + // searchData: searchData, + // mode: widget.mode, + // ), + // context, + // ); + _performSearch(searchData); + }, + ), + + Container(height: 5, color: h_backGroundColor()), + Expanded( + child: + _list.isEmpty + ? NoDataWidget.show() + : ListView.builder( + itemCount: _list.length, + itemBuilder: (context, index) { + final item = _list[index]; + return _fxitemCell(item); + }, + ), + ), + ], + ); + } + + Widget _fxitemCell(pageData) { + // 使用GestureDetector包裹整个列表项以添加点击事件 + return GestureDetector( + onTap: () {}, + + child: Container( + margin: EdgeInsets.all(6), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.3), + spreadRadius: 2, + blurRadius: 5, + offset: Offset(0, 3), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 标题 + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, // 添加这一行 + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.only(left: 10, top: 15, right: 8), + child: Text( + '隐患描述: ${pageData['hiddenDesc'] ?? ''}', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + maxLines: 1, // 只显示一行 + overflow: TextOverflow.ellipsis, // 超出部分显示省略号 + ), + ), + ), + + // 状态标签 + Container( + padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + color: _getLevelColor(pageData), + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(12), + topRight: Radius.circular(12), // 改为右上角 + ), + ), + child: Text( + pageData['hiddenLevelName'] ?? '', + style: TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + + SizedBox(height: 16), + + Padding( + padding: EdgeInsets.only(left: 10, right: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 来源 + Expanded( + child: Text( + _getSourceDangers(pageData), + style: TextStyle(fontSize: 14, color: Colors.black87), + ), + ), + // 隐患状态 + // Expanded( + // child: Text( + // '隐患状态: ${_getState(pageData)}', + // style: TextStyle(fontSize: 14, color: Colors.black87), + // ), + // ), + ], + ), + ), + + SizedBox(height: 8), + Padding( + padding: EdgeInsets.only(left: 10, right: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 来源 + // Expanded( + // child: Text( + // _getSourceDangers(pageData), + // style: TextStyle(fontSize: 14, color: Colors.black87), + // ), + // ), + // 隐患状态 + Expanded( + child: Text( + '隐患状态: ${_getState(pageData)}', + style: TextStyle(fontSize: 14, color: Colors.black87), + ), + ), + ], + ), + ), + + SizedBox(height: 8), + + Padding( + padding: EdgeInsets.only(left: 10, right: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 隐患发现人 - 使用 Expanded 包裹 + Expanded( + child: Text( + '发现人:${truncateString(pageData['createName'] ?? '')}', + style: TextStyle(fontSize: 14, color: Colors.black87), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + + // 隐患发现时间 - 使用 Expanded 包裹 + Expanded( + child: Text( + '发现时间:${_changeTime(pageData['createTime'] ?? '')}', + + style: TextStyle(fontSize: 14, color: Colors.black87), + // maxLines: 1, + // overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + + + if(widget.appItem==2)...[ + if (pageData['rectificationUserId'] != null && + pageData['rectificationUserId'].isNotEmpty)...[ + SizedBox(height: 8), + Padding( + padding: EdgeInsets.only(left: 10, right: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 整改人 + Expanded( + child: Text( + '整改人:${pageData['rectificationUserName'] ?? ''}', + style: TextStyle(fontSize: 14, color: Colors.black87), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + + Expanded( + child: Text( + '整改时间:${_changeTime(pageData['rectificationTime'] ?? '')}', + + style: TextStyle(fontSize: 14, color: Colors.black87), + // maxLines: 1, + // overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + ], + + if (pageData['acceptUserId'] != null && + pageData['acceptUserId'].isNotEmpty)...[ + SizedBox(height: 8), + Padding( + padding: EdgeInsets.only(left: 10, right: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + // 整改人 + Text( + '验收人: ${pageData['acceptUserName'] ?? ''}', + style: TextStyle(fontSize: 14, color: Colors.black87), + ), + + Text( + '隐患验收时间: ${_changeTime(pageData['acceptUserTime']??'')}', + style: TextStyle( + fontSize: 14, + color: Colors.black87, + ), + ), + ], + ), + ), + ], + ], + + + SizedBox(height: 8), + + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + //查看 + + Expanded( + child: CustomButton( + height: 35, + onPressed: () async { + // print('查看: ${pageData['title']}'); + pushPage( + KeyTasksHiddenDangerDetail( + 2, + pageData['id'], + pageData['hiddenId'], + pageData['foreignKey'], + false, + ), + context, + ); + }, + backgroundColor: h_backGroundColor(), + textStyle: const TextStyle(color: Colors.black), + buttonStyle: ButtonStyleType.secondary, + text: buttonTextOne, + ), + ), + + if(widget.appItem==1) + SizedBox(width: 10), // 使用width而不是height + //整改 + if(widget.appItem==1) + Expanded( + child: CustomButton( + height: 35, + onPressed: () async { + pushPage( + KeyTasksHiddenDangerDetail( + 1, + pageData['id'], + pageData['hiddenId'], + pageData['foreignKey'], + false, + ), + context, + ); + }, + backgroundColor: h_AppBarColor(), + textStyle: const TextStyle(color: Colors.white), + buttonStyle: ButtonStyleType.primary, + text: buttonTextTwo, + ), + ), + + ], + ), + + SizedBox(height: 10), + ], + ), + ), + ); + } + + void _performSearch(String keyword) { + // 执行搜索逻辑 + // if (keyword.isNotEmpty) { + // print('执行搜索: $keyword'); + // 调用API或其他搜索操作 + // 输入请求接口 + _page = 1; + searchKey = keyword; + _getListData(false); + // } + } + + bool _onScroll(ScrollNotification n) { + if (n.metrics.pixels > n.metrics.maxScrollExtent - 100 && + _hasMore && + !_isLoading) { + _page++; + _getListData(true); + } + return false; + } + + void _onSearchChanged() { + final query = _searchController.text.toLowerCase().trim(); + setState(() { + print("=====>" + query); + // filtered = query.isEmpty ? original : _filterCategories(original, query); + }); + } + + + Future _getListData(bool loadMore) async { + try { + if (_isLoading) return; + _isLoading = true; + + keyTasksHiddenDangerListData['pageIndex']=_page; + keyTasksHiddenDangerListData['hiddenDesc']=searchKey; + + LoadingDialogHelper.show(); + final Map result = await KeyTasksApi.setKeyTasksHiddenDangerList(keyTasksHiddenDangerListData); + LoadingDialogHelper.hide(); + + if (result['success']) { + _totalPage = result['pageSize'] ?? 1; + final List newList = result['data'] ?? []; + // setState(() { + // _list.addAll(newList); + // }); + + setState(() { + if (loadMore) { + _list.addAll(newList); + } else { + _list = newList; + } + _hasMore = _page < _totalPage; + // if (_hasMore) _page++; + }); + } else { + ToastUtil.showNormal(context, "加载数据失败"); + // _showMessage('加载数据失败'); + } + } catch (e) { + LoadingDialogHelper.hide(); + // 出错时可以 Toast 或者在页面上显示错误状态 + print('加载数据失败:$e'); + } finally { + // if (!loadMore) LoadingDialogHelper.hide(); + _isLoading = false; + } + } + + String _getSourceDangers(final item) { + int type = item["source"] ?? 0; + if (1 == type) { + return "隐患来源:安全环保检查(监管端)"; + } else if (2 == type) { + return "隐患来源:安全环保检查(企业端)"; + } else { + return "隐患来源:"; + } + } + + // 隐患等级颜色 + Color _getLevelColor(final item) { + String type = item["hiddenLevelName"] ?? ''; + if ("重大隐患" == type) { + return Colors.red; + } else if ("较大隐患" == type) { + return Color(0xFFFF6A4D); + } else if ("一般隐患" == type) { + return Colors.orange; + } else if ("轻微隐患" == type) { + return h_AppBarColor(); + } else { + return Colors.green; + } + } + + String _getState(final item) { + //1,未整改,2:已整改,3:已验收,4:验收打回 + int type = item["state"]; + if(1==type){ + return "未整改"; + }else if(2==type){ + return "已整改"; + }else if(3==type){ + return "已验收"; + }else if(4==type){ + return "验收打回"; + }else{ + return ""; + } + } + + String _changeTime(String time) { + try { + // 解析 ISO 8601 格式的时间字符串 + DateTime dateTime = DateTime.parse(time); + // 格式化为年月日 + return DateFormat('yyyy-MM-dd').format(dateTime); + } catch (e) { + // 如果解析失败,返回原字符串或默认值 + return ' '; + } + } + + String truncateString(String input) { + if (input.length > 10) { + return '${input.substring(0, 10)}...'; + } + return input; + } + + + Map keyTasksHiddenDangerListData={ + "hiddenDesc": "", + "stateList": [], + "pageSize": 20, + "pageIndex": 1 + }; + + +} diff --git a/lib/pages/home/keyTasks/key_tasks_check_list_page.dart b/lib/pages/home/keyTasks/key_tasks_check_list_page.dart index a35cbd2..3f64b88 100644 --- a/lib/pages/home/keyTasks/key_tasks_check_list_page.dart +++ b/lib/pages/home/keyTasks/key_tasks_check_list_page.dart @@ -56,7 +56,7 @@ class _KeyTasksCheckListPageState extends State { super.initState(); - title='检查发起'; + title='被检查确认'; keyTasksInspectionListData['statusList']=[2]; diff --git a/lib/pages/home/keyTasks/key_tasks_tab_page.dart b/lib/pages/home/keyTasks/key_tasks_tab_page.dart index b75c9a2..1685772 100644 --- a/lib/pages/home/keyTasks/key_tasks_tab_page.dart +++ b/lib/pages/home/keyTasks/key_tasks_tab_page.dart @@ -3,6 +3,7 @@ import 'dart:ffi'; import 'package:flutter/material.dart'; import 'package:qhd_prevention/pages/home/doorAndCar/doorCar_tab_page.dart'; +import 'package:qhd_prevention/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_list.dart'; import 'package:qhd_prevention/pages/home/keyTasks/key_tasks_check_list_page.dart'; import 'package:qhd_prevention/pages/home/keyTasks/key_tasks_confirm_list_page.dart'; import 'package:qhd_prevention/pages/my_appbar.dart'; @@ -60,7 +61,7 @@ class _DoorcarTabPageState extends State { icon: 'assets/images/door_ico9.png', badge: 0, onTap: () async { - // await pushPage(KeyTasksHiddenList(1), context); + await pushPage(KeyTasksHiddenDangerList(1), context); _getDoorCarCount(); }, ), @@ -69,7 +70,7 @@ class _DoorcarTabPageState extends State { icon: 'assets/images/door_ico9.png', badge: 0, onTap: () async { - // await pushPage(KeyTasksHiddenList(2), context); + await pushPage(KeyTasksHiddenDangerList(2), context); _getDoorCarCount(); }, ), From 43958103032d0898d55a96a8e43d32ef9ae15a0b Mon Sep 17 00:00:00 2001 From: xufei <727302827@qq.com> Date: Thu, 16 Apr 2026 17:36:16 +0800 Subject: [PATCH 3/3] =?UTF-8?q?2026.4.16=20=E9=87=8D=E7=82=B9=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../key_tasks_hidden_danger_list.dart | 39 +- .../key_tasks_hidden_filter_page.dart | 486 ++++++++++++++++++ 2 files changed, 506 insertions(+), 19 deletions(-) create mode 100644 lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_filter_page.dart diff --git a/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_list.dart b/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_list.dart index 57d64b7..2f02d30 100644 --- a/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_list.dart +++ b/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_list.dart @@ -7,6 +7,7 @@ import 'package:qhd_prevention/customWidget/toast_util.dart'; import 'package:qhd_prevention/http/ApiService.dart'; import 'package:qhd_prevention/http/modules/key_tasks_api.dart'; import 'package:qhd_prevention/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_danger_detail.dart'; +import 'package:qhd_prevention/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_filter_page.dart'; import 'package:qhd_prevention/pages/my_appbar.dart'; import 'package:qhd_prevention/tools/h_colors.dart'; import 'package:qhd_prevention/tools/tools.dart'; @@ -26,7 +27,7 @@ class KeyTasksHiddenDangerList extends StatefulWidget { class _KeyTasksHiddenDangerListState extends State { int _page = 1; - String searchKey = ""; + // String searchKey = ""; int _totalPage = 1; late List _list = []; bool _isLoading = false; @@ -103,7 +104,8 @@ class _KeyTasksHiddenDangerListState extends State { hintText: '请输入隐患描述', onTextChanged: (value) {}, onSearch: (keyboard) { - _performSearch(_searchController.text); + keyTasksHiddenDangerListData['hiddenDesc']=keyboard; + _performSearch(); }, ), ), @@ -112,46 +114,45 @@ class _KeyTasksHiddenDangerListState extends State { RangeFilterBar( initial: RangeOption.none, onRangeChanged: (range) { - String searchData=''; + switch (range) { case RangeOption.oneWeek: final data = DateTime.now().subtract( const Duration(days: 7), ); final time = DateFormat('yyyy-MM-dd').format(data); - searchData = time; + keyTasksHiddenDangerListData['startTime'] = time; break; case RangeOption.oneMonth: final data = DateTime.now().subtract( const Duration(days: 30), ); final time = DateFormat('yyyy-MM-dd').format(data); - searchData = time; + keyTasksHiddenDangerListData['startTime'] = time; break; case RangeOption.threeMonths: final data = DateTime.now().subtract( const Duration(days: 90), ); final time = DateFormat('yyyy-MM-dd').format(data); - searchData = time; + keyTasksHiddenDangerListData['startTime'] = time; case RangeOption.none: break; case RangeOption.oneDay: break; } - _performSearch(searchData); + _performSearch(); }, onFilterPressed: () async { // 弹出筛选对话框或跳转到筛选页面 - String searchData=''; - // searchData = await pushPage( - // SafecheckListfilterPage( - // searchData: searchData, - // mode: widget.mode, - // ), - // context, - // ); - _performSearch(searchData); + // String searchData=''; + keyTasksHiddenDangerListData = await pushPage( + KeyTasksHiddenFilterPage( + searchData: keyTasksHiddenDangerListData, + ), + context, + ); + _performSearch(); }, ), @@ -449,14 +450,14 @@ class _KeyTasksHiddenDangerListState extends State { ); } - void _performSearch(String keyword) { + void _performSearch() { // 执行搜索逻辑 // if (keyword.isNotEmpty) { // print('执行搜索: $keyword'); // 调用API或其他搜索操作 // 输入请求接口 _page = 1; - searchKey = keyword; + // searchKey = keyword; _getListData(false); // } } @@ -486,7 +487,7 @@ class _KeyTasksHiddenDangerListState extends State { _isLoading = true; keyTasksHiddenDangerListData['pageIndex']=_page; - keyTasksHiddenDangerListData['hiddenDesc']=searchKey; + // keyTasksHiddenDangerListData['hiddenDesc']=searchKey; LoadingDialogHelper.show(); final Map result = await KeyTasksApi.setKeyTasksHiddenDangerList(keyTasksHiddenDangerListData); diff --git a/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_filter_page.dart b/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_filter_page.dart new file mode 100644 index 0000000..564706c --- /dev/null +++ b/lib/pages/home/keyTasks/keyTasksDetail/keyTasksHiddenDanger/key_tasks_hidden_filter_page.dart @@ -0,0 +1,486 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:qhd_prevention/customWidget/MultiDictValuesPicker.dart'; +import 'package:qhd_prevention/customWidget/bottom_picker.dart'; +import 'package:qhd_prevention/customWidget/custom_button.dart'; +import 'package:qhd_prevention/customWidget/date_picker_dialog.dart'; +import 'package:qhd_prevention/customWidget/department_person_picker.dart'; +import 'package:qhd_prevention/customWidget/department_picker.dart'; +import 'package:qhd_prevention/customWidget/department_picker_three.dart'; +import 'package:qhd_prevention/customWidget/item_list_widget.dart'; +import 'package:qhd_prevention/customWidget/picker/CupertinoDatePicker.dart'; +import 'package:qhd_prevention/customWidget/toast_util.dart'; +import 'package:qhd_prevention/http/modules/basic_info_api.dart'; +import 'package:qhd_prevention/pages/my_appbar.dart'; +import 'package:qhd_prevention/tools/tools.dart'; + +class KeyTasksHiddenFilterPage extends StatefulWidget { + const KeyTasksHiddenFilterPage({ + super.key, + required this.searchData, + + }); + + final Map searchData; + + @override + State createState() => _KeyTasksHiddenFilterPageState(); +} + +class _KeyTasksHiddenFilterPageState extends State { + + // controllers / state + + /// 检查场所 + TextEditingController _inspectionSiteController = TextEditingController(); + /// 检查发起人 + TextEditingController _initiatorInspectionController = TextEditingController(); + /// 检查人 + TextEditingController _inspectorController = TextEditingController(); + + + // 存储各单位的人员列表 + final Map>> _personCache = {}; + + DateTime? _startDate; + DateTime? _endDate; + Map searchData = {}; + + final DateFormat _dateFmt = DateFormat('yyyy-MM-dd'); + + + @override + void initState() { + // TODO: implement initState + super.initState(); + _fetchData(); + } + + Future _fetchData() async { + setState(() { + searchData=widget.searchData; + _inspectionSiteController.text = searchData['hiddenDesc']; + _initiatorInspectionController.text = searchData['hiddenFindUserName']; + _inspectorController.text = searchData['projectName']; + + }); + } + + + // ========== 页面构建 ========== + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: const MyAppbar(title: '筛选'), + backgroundColor: Colors.white, + body: SafeArea( + child: Column( + children: [ + Expanded( + child: ListView( + children: [ + Container( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + + buildTextFieldRow( + labelText: '隐患描述', + controller: _inspectionSiteController, + hintText: '请输入隐患描述', + onChanged: (value) { + searchData['hiddenDesc'] = value; + }, + ), + + const SizedBox(height: 10), + buildChooseRow( + labelText: '隐患来源', + valueText: searchData['sourceName'], + onTap: () => _getApproverList(), + hintText: '选择隐患来源', + ), + + + const SizedBox(height: 10), + buildTextFieldRow( + labelText: '隐患发现人', + controller: _initiatorInspectionController, + hintText: '请输入隐患发现人', + onChanged: (value) { + searchData['hiddenFindUserName'] = value; + }, + ), + + + + const SizedBox(height: 10), + buildChooseRow( + labelText: '检查开始时间', + valueText: searchData['startTime'], + onTap: () => _pickDate(isStart: true), + hintText: '选择开始时间', + ), + const SizedBox(height: 10), + buildChooseRow( + labelText: '检查结束时间', + valueText: searchData['endTime'], + onTap: () => _pickDate(isStart: false), + hintText: '选择结束时间', + ), + + + const SizedBox(height: 10), + buildTextFieldRow( + labelText: '重点作业名称', + controller: _inspectorController, + hintText: '请输入重点作业名称', + onChanged: (value) { + searchData['projectName'] = value; + }, + ), + + + ], + ), + ), + ], + ), + ), + ItemListWidget.itemContainer( + Row( + children: [ + CustomButton( + text: '重置', + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 30, + ), + buttonStyle: ButtonStyleType.secondary, + onPressed: _resetAll, + ), + const SizedBox(width: 12), + Expanded( + child: CustomButton(text: '确定', onPressed: _confirm), + ), + ], + ), + ), + ], + ), + ), + ); + } + + + + + + @override + void dispose() { + _inspectionSiteController.dispose(); + _initiatorInspectionController.dispose(); + _inspectorController.dispose(); + super.dispose(); + } + + Widget buildTextFieldRow({ + required String labelText, + required TextEditingController controller, + required String hintText, + ValueChanged? onChanged, + }) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + labelText, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + color: Colors.black, + ), + ), + const SizedBox(height: 8), + Container( + height: 45, + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(5), + ), + padding: const EdgeInsets.symmetric(horizontal: 8), + alignment: Alignment.centerLeft, + child: TextFormField( + controller: controller, + decoration: InputDecoration( + hintText: hintText, + hintStyle: const TextStyle(color: Colors.grey), + border: InputBorder.none, + isDense: true, + ), + maxLines: 1, + onChanged: onChanged, + ), + ), + ], + ); + } + + Widget buildChooseRow({ + required String labelText, + required String hintText, + required String valueText, + required VoidCallback onTap, + bool showArrow = true, + }) { + final bool hasValue = valueText.trim().isNotEmpty; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + labelText, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + color: Colors.black, + ), + ), + const SizedBox(height: 8), + Container( + height: 45, + decoration: BoxDecoration( + border: Border.all(color: Colors.grey), + borderRadius: BorderRadius.circular(5), + ), + child: InkWell( + onTap: onTap, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Row( + children: [ + Expanded( + child: Text( + hasValue ? valueText : hintText, + style: TextStyle( + color: hasValue ? Colors.black87 : Colors.black54, + fontSize: 15, + ), + overflow: TextOverflow.ellipsis, + ), + ), + if (showArrow) + const Icon(Icons.arrow_drop_down, color: Colors.black54), + ], + ), + ), + ), + ), + ], + ); + } + + // Future _chooseDepartment({required String typeStr}) async { + // showModalBottomSheet( + // context: context, + // isScrollControlled: true, + // barrierColor: Colors.black54, + // backgroundColor: Colors.transparent, + // builder: + // (_) => DepartmentPicker( + // onSelected: (id, name) async { + // setState(() { + // searchData['inspectionDepartmentId']=id; + // searchData['inspectionDepartmentName']=name; + // // personUnderInspection['departmentId'] = id; + // // personUnderInspection['userName'] = name; + // // if (typeStr == '检查部门') { + // // _inspectionDeptName = name; + // // } else if (typeStr == '被检查单位') { + // // _inspectedDepartmentName = name; + // // } + // }); + // // 拉该单位人员并缓存 + // await _getPersonListForUnitId(typeStr); + // }, + // ), + // ).then((_) { + // // 可选:FocusHelper.clearFocus(context); + // }); + // } + + Future _getPersonListForUnitId(String typeStr) async { + String unitId = searchData['inspectionDepartmentId'] ?? ''; + // 拉取该单位的人员列表并缓存 + final result = await BasicInfoApi.getDeptUsers(unitId); + dynamic raw = result['data']; + List> list = []; + if (raw is List) { + list = + raw.map>((e) { + if (e is Map) return e; + if (e is Map) return Map.from(e); + return {}; + }).toList(); + } else { + list = []; + } + setState(() { + _personCache[typeStr] = list; + }); + //FocusHelper.clearFocus(context); + } + + + Future _getApproverList() async { + try { + + List newList = [ + {'dataId':'1','dataName':'安全环保检查(监管端)',}, + {'dataId':'2','dataName':'安全环保检查(企业端)',}, + {'dataId':'3','dataName':'视频监控',}, + ]; + showModalBottomSheet( + context: context, + isScrollControlled: true, + barrierColor: Colors.black54, + backgroundColor: Colors.transparent, + builder: + (ctx) => DepartmentPickerThree( + listdata: newList, + onSelected: (id, name,pdId) async { + setState(() { + searchData['source']=id; + searchData['sourceName']=name; + }); + + }, + ), + ); + + } catch (e) { + // 出错时可以 Toast 或者在页面上显示错误状态 + print('加载首页数据失败:$e'); + // return ""; + LoadingDialogHelper.hide(); + } + } + + /// 弹出人员选择,需先选择单位 + // void choosePersonHandle(String typeStr) async { + // final personList = _personCache[typeStr]; + // if (!FormUtils.hasValue(_personCache, typeStr)) { + // ToastUtil.showNormal(context, '请先选择单位'); + // return; + // } + // + // DepartmentPersonPicker.show( + // context, + // personsData: personList!, + // onSelectedWithIndex: (userId, name, index) { + // setState(() { + // if (typeStr == '检查人') { + // _inspectionUserName = name; + // } else { + // _inspectedUserName = name; + // } + // }); + // //FocusHelper.clearFocus(context); + // }, + // ).then((_) {}); + // } + + Future _pickDate({required bool isStart}) async { + DateTime? picked = await BottomDateTimePicker.showDate( + context, + minTimeStr: !isStart ? searchData['startTime'] : null, + mode: BottomPickerMode.dateTime, + ); + if (picked != null) { + setState(() { + final dateFormat = DateFormat('yyyy-MM-dd HH:mm'); + if (isStart) { + _startDate = picked; + searchData['startTime'] = dateFormat.format(picked); + } else { + _endDate = picked; + searchData['endTime'] = dateFormat.format(picked); + } + // 保证开始 <= 结束 + if (_endDate != null && _endDate!.isBefore(picked)) { + _endDate = null; + } + }); + } + } + + // // 选择检查状态 + // Future _pickCheckStatus() async { + // List> items = SafeCheckListItem.getStepList(); + // final choice = await BottomPicker.show( + // context, + // items: items.map((item) => item['name'].toString()).toList(), + // itemBuilder: (item) => Text(item, textAlign: TextAlign.center), + // initialIndex: 0, + // ); + // if (choice != null) { + // setState(() { + // Map item = items[items.indexWhere((item) => item['name'] == choice)]; + // _checkStatus = item['id']; + // }); + // } + // } + + + // Future _pickYearDate() async { + // DateTime? picked = await BottomDateTimePicker.showDate( + // context, + // minTimeStr: null, + // mode: BottomPickerMode.year, + // ); + // if (picked != null) { + // setState(() { + // final dateFormat = DateFormat('yyyy'); + // searchData['year'] = dateFormat.format(picked); + // }); + // } + // } + + // ========== 重置 / 确定 ========== + void _resetAll() { + setState(() { + _inspectionSiteController.clear(); + _initiatorInspectionController.clear(); + _inspectorController.clear(); + + searchData['place']=''; + searchData['createName']=''; + searchData['inspectionDepartmentId']=''; + searchData['inspectionDepartmentName']=''; + searchData['timeStart']=''; + searchData['timeEnd']=''; + searchData['inspectedCorpinfoName']=''; + searchData['projectName']=''; + searchData['inspectionUserName']=''; + searchData['year']=''; + }); + final Map pd = { + ...searchData, + }; + Navigator.of(context).pop(pd); + } + + void _confirm() { + final Map pd = { + ...searchData, + }; + // for (Map subject in subjectList) { + // if (subject['bianma'] == pd['inspectionSubject']) { + // pd['inspectionSubject'] = subject['name']; + // } + // } + Navigator.of(context).pop(pd); + } + + +}