部门人员多级选择器
							parent
							
								
									824d5a403c
								
							
						
					
					
						commit
						4d3fb2b6e6
					
				|  | @ -0,0 +1,135 @@ | ||||||
|  | import 'package:flutter/cupertino.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:qhd_prevention/customWidget/search_bar_widget.dart'; | ||||||
|  | 
 | ||||||
|  | /// 用户数据模型 | ||||||
|  | class Person { | ||||||
|  |   final String userId; | ||||||
|  |   final String name; | ||||||
|  | 
 | ||||||
|  |   Person({required this.userId, required this.name}); | ||||||
|  | 
 | ||||||
|  |   factory Person.fromJson(Map<String, dynamic> json) { | ||||||
|  |     return Person( | ||||||
|  |       userId: json['USER_ID'] as String, | ||||||
|  |       name: json['NAME'] as String, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// 回调签名,返回选中用户的 USER_ID 和 NAME | ||||||
|  | typedef PersonSelectCallback = void Function(String userId, String name); | ||||||
|  | 
 | ||||||
|  | /// 底部弹窗人员选择器(使用预先传入的原始数据列表,不做接口请求) | ||||||
|  | class DepartmentPersonPicker { | ||||||
|  |   /// 显示人员选择弹窗 | ||||||
|  |   /// | ||||||
|  |   /// [personsData]: 已拉取并缓存的原始 Map 列表 | ||||||
|  |   /// [onSelected]: 选中后回调 USER_ID 和 NAME | ||||||
|  |   static Future<void> show( | ||||||
|  |       BuildContext context, { | ||||||
|  |         required List<Map<String, dynamic>> personsData, | ||||||
|  |         required PersonSelectCallback onSelected, | ||||||
|  |       }) async { | ||||||
|  |     // 转换为模型 | ||||||
|  |     final List<Person> _all = | ||||||
|  |     personsData.map((e) => Person.fromJson(e)).toList(); | ||||||
|  |     List<Person> _filtered = List.from(_all); | ||||||
|  |     String _selectedName = ''; | ||||||
|  |     String _selectedId = ''; | ||||||
|  |     final TextEditingController _searchController = TextEditingController(); | ||||||
|  | 
 | ||||||
|  |     await showModalBottomSheet( | ||||||
|  |       context: context, | ||||||
|  |       isScrollControlled: true, | ||||||
|  |       backgroundColor: Colors.white, | ||||||
|  |       shape: const RoundedRectangleBorder( | ||||||
|  |         borderRadius: BorderRadius.vertical(top: Radius.circular(12)), | ||||||
|  |       ), | ||||||
|  |       builder: (ctx) { | ||||||
|  |         return StatefulBuilder( | ||||||
|  |           builder: (BuildContext ctx, StateSetter setState) { | ||||||
|  |             // 搜索逻辑 | ||||||
|  |             void _onSearch(String v) { | ||||||
|  |               final q = v.toLowerCase().trim(); | ||||||
|  |               setState(() { | ||||||
|  |                 _filtered = q.isEmpty | ||||||
|  |                     ? List.from(_all) | ||||||
|  |                     : _all | ||||||
|  |                     .where((p) => p.name.toLowerCase().contains(q)) | ||||||
|  |                     .toList(); | ||||||
|  |               }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return SafeArea( | ||||||
|  |               child: SizedBox( | ||||||
|  |                 height: MediaQuery.of(ctx).size.height * 0.75, | ||||||
|  |                 child: Column( | ||||||
|  |                   children: [ | ||||||
|  |                     // 顶部:取消、搜索、确定 | ||||||
|  |                     Padding( | ||||||
|  |                       padding: const EdgeInsets.symmetric( | ||||||
|  |                           horizontal: 16, vertical: 8), | ||||||
|  |                       child: Row( | ||||||
|  |                         children: [ | ||||||
|  |                           TextButton( | ||||||
|  |                             onPressed: () => Navigator.of(ctx).pop(), | ||||||
|  |                             child: const Text('取消',style: TextStyle(fontSize: 16),), | ||||||
|  |                           ), | ||||||
|  |                           Expanded( | ||||||
|  |                             child: Padding( | ||||||
|  |                               padding: const EdgeInsets.symmetric( | ||||||
|  |                                   horizontal: 8), | ||||||
|  |                               child: SearchBarWidget( | ||||||
|  |                                 controller: _searchController, | ||||||
|  |                                 onTextChanged: _onSearch, | ||||||
|  |                                 isShowSearchButton: false, | ||||||
|  |                                 onSearch: (keyboard) { | ||||||
|  |                                 }, | ||||||
|  |                               ), | ||||||
|  |                             ), | ||||||
|  |                           ), | ||||||
|  |                           TextButton( | ||||||
|  |                             onPressed: _selectedId.isEmpty | ||||||
|  |                                 ? null | ||||||
|  |                                 : () { | ||||||
|  |                               Navigator.of(ctx).pop(); | ||||||
|  |                               onSelected(_selectedId, _selectedName); | ||||||
|  |                             }, | ||||||
|  |                             child: const Text('确定', style: TextStyle(color: Colors.green, fontSize: 16),), | ||||||
|  |                           ), | ||||||
|  |                         ], | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                     const Divider(height: 1), | ||||||
|  |                     // 列表 | ||||||
|  |                     Expanded( | ||||||
|  |                       child: ListView.separated( | ||||||
|  |                         itemCount: _filtered.length, | ||||||
|  |                         separatorBuilder: (_, __) => const Divider(height: 1), | ||||||
|  |                         itemBuilder: (context, index) { | ||||||
|  |                           final person = _filtered[index]; | ||||||
|  |                           final selected = person.userId == _selectedId; | ||||||
|  |                           return ListTile( | ||||||
|  |                             titleAlignment: ListTileTitleAlignment.center, | ||||||
|  |                             title: Text(person.name), | ||||||
|  |                             trailing: | ||||||
|  |                             selected ? const Icon(Icons.check, color: Colors.green) : null, | ||||||
|  |                             onTap: () => setState(() { | ||||||
|  |                               _selectedId = person.userId; | ||||||
|  |                               _selectedName = person.name; | ||||||
|  |                             }), | ||||||
|  |                           ); | ||||||
|  |                         }, | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ); | ||||||
|  |           }, | ||||||
|  |         ); | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -181,7 +181,6 @@ class _DepartmentPickerState extends State<DepartmentPicker> { | ||||||
|                   child: Padding( |                   child: Padding( | ||||||
|                     padding: const EdgeInsets.symmetric(horizontal: 12), |                     padding: const EdgeInsets.symmetric(horizontal: 12), | ||||||
|                     child: SearchBarWidget( |                     child: SearchBarWidget( | ||||||
| 
 |  | ||||||
|                       controller: _searchController, |                       controller: _searchController, | ||||||
|                       isShowSearchButton: false, |                       isShowSearchButton: false, | ||||||
|                       onSearch: (keyboard) { |                       onSearch: (keyboard) { | ||||||
|  |  | ||||||
|  | @ -942,7 +942,7 @@ U6Hzm1ninpWeE+awIDAQAB | ||||||
|   static Future<Map<String, dynamic>> getListTreePersonList(String DEPARTMENT_ID) { |   static Future<Map<String, dynamic>> getListTreePersonList(String DEPARTMENT_ID) { | ||||||
|     return HttpManager().request( |     return HttpManager().request( | ||||||
|       basePath, |       basePath, | ||||||
|       'app/sys/listUser', |       '/app/sys/listUser', | ||||||
|       method: Method.post, |       method: Method.post, | ||||||
|       data: { |       data: { | ||||||
|         "tm":DateTime.now().millisecondsSinceEpoch.toString(), |         "tm":DateTime.now().millisecondsSinceEpoch.toString(), | ||||||
|  |  | ||||||
|  | @ -101,36 +101,54 @@ class ItemListWidget { | ||||||
|   ///    - 可编辑时:标题 + “请选择”提示 + 右箭头 |   ///    - 可编辑时:标题 + “请选择”提示 + 右箭头 | ||||||
|   ///    - 不可编辑时:标题 + 文本内容 |   ///    - 不可编辑时:标题 + 文本内容 | ||||||
|   static Widget selectableLineTitleTextField({ |   static Widget selectableLineTitleTextField({ | ||||||
|     required String label, // 标题文本 |     required String label,         // 标题文本 | ||||||
|     required bool isEditable, // 是否可点击 |     required bool isEditable,      // 是否可点击 | ||||||
|     required String text, // 显示内容或提示 |     required String text,          // 显示内容或提示 | ||||||
|     VoidCallback? onTap, // 点击回调 |     VoidCallback? onTap,           // 点击回调 | ||||||
|     double fontSize = 15, // 字体大小 |     double fontSize = 15,          // 字体大小 | ||||||
|   }) { |   }) { | ||||||
|     return InkWell( |     return InkWell( | ||||||
|       onTap: isEditable ? onTap : null, |       onTap: isEditable ? onTap : null, | ||||||
|       child: Container( |       child: Container( | ||||||
|         padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), |         padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), | ||||||
|         child: Row( |         child: Row( | ||||||
|           mainAxisAlignment: MainAxisAlignment.spaceBetween, |  | ||||||
|           children: [ |           children: [ | ||||||
|  |             // 1. 标题 | ||||||
|             Text( |             Text( | ||||||
|               label, |               label, | ||||||
|               style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold), |               style: TextStyle( | ||||||
|             ), // 显示标题 |                 fontSize: fontSize, | ||||||
|  |                 fontWeight: FontWeight.bold, | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  | 
 | ||||||
|             const SizedBox(width: 8), |             const SizedBox(width: 8), | ||||||
|             Row( | 
 | ||||||
|               children: [ |             Expanded( | ||||||
|                 Text( |               child: Row( | ||||||
|                   text.length > 0 ? text: '请选择', // 默认提示 |                 mainAxisAlignment: MainAxisAlignment.end, | ||||||
|                   style: TextStyle( |                 children: [ | ||||||
|                     fontSize: fontSize, |                   Flexible( | ||||||
|                     color: isEditable ? Colors.black : Colors.grey, // 不可编辑时使用灰色 |                     child: Text( | ||||||
|  |                       text.isNotEmpty ? text : '请选择', | ||||||
|  |                       maxLines: 1, | ||||||
|  |                       overflow: TextOverflow.ellipsis, | ||||||
|  |                       style: TextStyle( | ||||||
|  |                         fontSize: fontSize, | ||||||
|  |                         color: isEditable ? Colors.black : Colors.grey, | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|                   ), |                   ), | ||||||
|                   overflow: TextOverflow.ellipsis, // 超出省略 |                   if (isEditable) | ||||||
|                 ), |                     const Padding( | ||||||
|                 if (isEditable) const Icon(Icons.chevron_right), // 只有可编辑时显示箭头 |                       padding: EdgeInsets.only(left: 4), | ||||||
|               ], |                       child: Icon( | ||||||
|  |                         Icons.chevron_right, | ||||||
|  |                         size: 20, | ||||||
|  |                       ), | ||||||
|  |                     ), | ||||||
|  |                 ], | ||||||
|  |               ), | ||||||
|             ), |             ), | ||||||
|           ], |           ], | ||||||
|         ), |         ), | ||||||
|  | @ -138,6 +156,8 @@ class ItemListWidget { | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|   /// 两行垂直布局: |   /// 两行垂直布局: | ||||||
|   ///    第一行:可点击选择(带箭头)或仅显示标题 |   ///    第一行:可点击选择(带箭头)或仅显示标题 | ||||||
|   ///    第二行:多行输入框或多行文本展示 |   ///    第二行:多行输入框或多行文本展示 | ||||||
|  | @ -164,31 +184,28 @@ class ItemListWidget { | ||||||
|                 Text( |                 Text( | ||||||
|                   label, |                   label, | ||||||
|                   style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold), |                   style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold), | ||||||
|                 ), // 显示标题 |                 ), | ||||||
|                 const SizedBox(width: 8), |  | ||||||
|                 Row( |                 Row( | ||||||
|                   children: [ |                   children: [ | ||||||
|                     Text( |                     Text( | ||||||
|                       isEditable ? '请选择' : '', // 显示内容或提示 |                       isEditable ? (text.isNotEmpty ? text : '请选择') : '', | ||||||
|                       style: TextStyle( |                       style: TextStyle( | ||||||
|                         fontSize: fontSize, |                         fontSize: fontSize, | ||||||
|                         color: isEditable ? Colors.black : Colors.grey, |                         color: isEditable ? Colors.black : Colors.grey, | ||||||
|                       ), |                       ), | ||||||
|  |                       maxLines: 1, | ||||||
|                       overflow: TextOverflow.ellipsis, |                       overflow: TextOverflow.ellipsis, | ||||||
|                     ), |                     ), | ||||||
|                     if (isEditable) const Icon(Icons.chevron_right), |                     if (isEditable) const Icon(Icons.chevron_right), | ||||||
| 
 |  | ||||||
|                   ], |                   ], | ||||||
|                 ) |                 ) | ||||||
|               ], |               ], | ||||||
|             ), |             ), | ||||||
|           ), |           ), | ||||||
|           const SizedBox(height: 8), |           const SizedBox(height: 8), | ||||||
|           // 第二行:多行输入或展示 |  | ||||||
|           Container( |           Container( | ||||||
|             height: row2Height, |             height: row2Height, | ||||||
|             padding: const EdgeInsets.all(8), |             padding: const EdgeInsets.symmetric(vertical: 8), | ||||||
| 
 |  | ||||||
|             child: isEditable |             child: isEditable | ||||||
|                 ? TextField( |                 ? TextField( | ||||||
|               controller: controller, |               controller: controller, | ||||||
|  | @ -196,11 +213,14 @@ class ItemListWidget { | ||||||
|               maxLines: null, |               maxLines: null, | ||||||
|               expands: true, |               expands: true, | ||||||
|               style: TextStyle(fontSize: fontSize), |               style: TextStyle(fontSize: fontSize), | ||||||
|               decoration: const InputDecoration( |               decoration: InputDecoration( | ||||||
|                 hintText: '请输入' |                 hintText: '请输入', | ||||||
|  |                 contentPadding: EdgeInsets.zero, | ||||||
|  |                 border: InputBorder.none, | ||||||
|               ), |               ), | ||||||
|             ) |             ) | ||||||
|                 : SingleChildScrollView( |                 : SingleChildScrollView( | ||||||
|  |               padding: EdgeInsets.zero, | ||||||
|               child: Text( |               child: Text( | ||||||
|                 text, |                 text, | ||||||
|                 style: TextStyle(fontSize: fontSize, color: Colors.grey), |                 style: TextStyle(fontSize: fontSize, color: Colors.grey), | ||||||
|  | @ -211,8 +231,9 @@ class ItemListWidget { | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   /// 两行垂直布局: |   /// 两行垂直布局: | ||||||
|   ///    标题+按钮 |   ///    标题 + 按钮 | ||||||
|   ///    第二行:多行输入框或多行文本展示 |   ///    第二行:多行输入框或多行文本展示 | ||||||
|   static Widget twoRowButtonTitleText({ |   static Widget twoRowButtonTitleText({ | ||||||
|     required String label, // 第一行标题 |     required String label, // 第一行标题 | ||||||
|  | @ -229,27 +250,31 @@ class ItemListWidget { | ||||||
|       child: Column( |       child: Column( | ||||||
|         crossAxisAlignment: CrossAxisAlignment.start, |         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|         children: [ |         children: [ | ||||||
|           // 第一行:可点击区域或纯文本标题 |           // 第一行:标题 + 按钮 | ||||||
|           InkWell( |           InkWell( | ||||||
|             onTap: isEditable ? onTap : null, |             onTap: isEditable ? onTap : null, | ||||||
|             child: Row( |             child: Row( | ||||||
|               mainAxisAlignment: MainAxisAlignment.start, |  | ||||||
|               children: [ |               children: [ | ||||||
|                 Text( |                 Text( | ||||||
|                   label, |                   label, | ||||||
|                   style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold), |                   style: TextStyle(fontSize: fontSize, fontWeight: FontWeight.bold), | ||||||
|                 ), // 显示标题 |                 ), | ||||||
|                 const SizedBox(width: 8), |                 const SizedBox(width: 8), | ||||||
|                 CustomButton(text: "选择其他", height:30, padding: EdgeInsets.symmetric(vertical: 2, horizontal: 5), backgroundColor: Colors.green, onPressed: onTap,) |                 CustomButton( | ||||||
|  |                   text: "选择其他", | ||||||
|  |                   height: 30, | ||||||
|  |                   padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5), | ||||||
|  |                   backgroundColor: Colors.green, | ||||||
|  |                   onPressed: onTap, | ||||||
|  |                 ), | ||||||
|               ], |               ], | ||||||
|             ), |             ), | ||||||
|           ), |           ), | ||||||
|           const SizedBox(height: 8), |           const SizedBox(height: 8), | ||||||
|           // 第二行:多行输入或展示 | 
 | ||||||
|           Container( |           Container( | ||||||
|             height: row2Height, |             height: row2Height, | ||||||
|             padding: const EdgeInsets.all(8), |             padding: const EdgeInsets.symmetric(vertical: 8), | ||||||
| 
 |  | ||||||
|             child: isEditable |             child: isEditable | ||||||
|                 ? TextField( |                 ? TextField( | ||||||
|               controller: controller, |               controller: controller, | ||||||
|  | @ -258,10 +283,13 @@ class ItemListWidget { | ||||||
|               expands: true, |               expands: true, | ||||||
|               style: TextStyle(fontSize: fontSize), |               style: TextStyle(fontSize: fontSize), | ||||||
|               decoration: InputDecoration( |               decoration: InputDecoration( | ||||||
|                   hintText: hintText |                 hintText: hintText, | ||||||
|  |                 contentPadding: EdgeInsets.zero, | ||||||
|  |                 border: InputBorder.none, | ||||||
|               ), |               ), | ||||||
|             ) |             ) | ||||||
|                 : SingleChildScrollView( |                 : SingleChildScrollView( | ||||||
|  |               padding: EdgeInsets.zero, | ||||||
|               child: Text( |               child: Text( | ||||||
|                 text, |                 text, | ||||||
|                 style: TextStyle(fontSize: fontSize, color: Colors.grey), |                 style: TextStyle(fontSize: fontSize, color: Colors.grey), | ||||||
|  | @ -272,4 +300,5 @@ class ItemListWidget { | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,23 +1,34 @@ | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:qhd_prevention/customWidget/ItemWidgetFactory.dart'; | import 'package:qhd_prevention/customWidget/ItemWidgetFactory.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.dart'; | ||||||
|  | import 'package:qhd_prevention/customWidget/toast_util.dart'; | ||||||
| import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart'; | import 'package:qhd_prevention/pages/home/tap/item_list_widget.dart'; | ||||||
|  | import '../../../../../../customWidget/bottom_picker.dart'; | ||||||
| import '../../../../../../http/ApiService.dart'; | import '../../../../../../http/ApiService.dart'; | ||||||
| import '../../../../../my_appbar.dart'; | import '../../../../../my_appbar.dart'; | ||||||
|  | 
 | ||||||
| enum EditUserType { | enum EditUserType { | ||||||
|   analyze, |   analyze('分析单位'), | ||||||
|   confirm, |   confirm('作业负责人单位'), | ||||||
|   guardian, |   guardian('监护人单位'), | ||||||
|   confess, |   confess('安全交底人单位'), | ||||||
|   acceptconfess, |   acceptconfess('接受交底人单位'), | ||||||
|   workstart, |   workstart('作业开始负责人单位'), | ||||||
|   workend, |   workend('作业结束负责人单位'), | ||||||
|   leader, |   leader('安全管理部门'), | ||||||
|   audit, |   audit('审核部门'), | ||||||
|   approve, |   approve('动火审批单位'), | ||||||
|   monitor, |   monitor('动火前在岗部门'), | ||||||
|   accept, |   accept('验收部门'); | ||||||
|  | 
 | ||||||
|  |   /// 对应的单位显示名 | ||||||
|  |   final String displayName; | ||||||
|  | 
 | ||||||
|  |   const EditUserType(this.displayName); | ||||||
| } | } | ||||||
|  | 
 | ||||||
| class HotworkApplyDetail extends StatefulWidget { | class HotworkApplyDetail extends StatefulWidget { | ||||||
|   const HotworkApplyDetail({ |   const HotworkApplyDetail({ | ||||||
|     super.key, |     super.key, | ||||||
|  | @ -34,8 +45,17 @@ class HotworkApplyDetail extends StatefulWidget { | ||||||
| 
 | 
 | ||||||
| class _HotworkApplyDetailState extends State<HotworkApplyDetail> { | class _HotworkApplyDetailState extends State<HotworkApplyDetail> { | ||||||
|   final bool isEditable = true; |   final bool isEditable = true; | ||||||
|   late String treeJson=""; |   /// 编辑还是新增 | ||||||
|  |   late String msg = 'add'; | ||||||
| 
 | 
 | ||||||
|  |   // 保存不同环节的单位和负责人 | ||||||
|  |   final Map<EditUserType, String> _selectedUnitId = {}; | ||||||
|  |   final Map<EditUserType, String> _selectedUnitName = {}; | ||||||
|  |   final Map<EditUserType, String> _selectedPersonId = {}; | ||||||
|  |   final Map<EditUserType, String> _selectedPersonName = {}; | ||||||
|  | 
 | ||||||
|  |   // 存储各单位的人员列表 | ||||||
|  |   final Map<EditUserType, List<Map<String, dynamic>>> _personCache = {}; | ||||||
| 
 | 
 | ||||||
|   Widget _defaultDetail() { |   Widget _defaultDetail() { | ||||||
|     return Column( |     return Column( | ||||||
|  | @ -102,6 +122,7 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> { | ||||||
|       ], |       ], | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   Widget _card(Widget child) { |   Widget _card(Widget child) { | ||||||
|     return Container( |     return Container( | ||||||
|       decoration: BoxDecoration( |       decoration: BoxDecoration( | ||||||
|  | @ -111,37 +132,87 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> { | ||||||
|       child: child, |       child: child, | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|   Widget _chooseItem(String unit, String person,EditUserType type) { | 
 | ||||||
|  |   Widget _chooseItem(String unitLabel, String personLabel, EditUserType type) { | ||||||
|     return Column( |     return Column( | ||||||
|       children: [ |       children: [ | ||||||
|         ItemListWidget.selectableLineTitleTextField(label: unit, isEditable: isEditable, text: '', onTap: () { |         ItemListWidget.selectableLineTitleTextField( | ||||||
|           chooseUnitHandle(type); |           label: unitLabel, | ||||||
|         }), |           isEditable: isEditable, | ||||||
|  |           text: _selectedUnitName[type] ?? '请选择', | ||||||
|  |           onTap: () => chooseUnitHandle(type), | ||||||
|  |         ), | ||||||
|         Divider(), |         Divider(), | ||||||
|         ItemListWidget.selectableLineTitleTextField(label: person, isEditable: isEditable, text: '', onTap: () { |         ItemListWidget.selectableLineTitleTextField( | ||||||
|           choosePersonHandle(type); |           label: personLabel, | ||||||
| 
 |           isEditable: isEditable, | ||||||
|         }), |           text: _selectedPersonName[type] ?? '请选择', | ||||||
|  |           onTap: () => choosePersonHandle(type), | ||||||
|  |         ), | ||||||
|       ], |       ], | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|   /// 弹出单位 | 
 | ||||||
|  |   /// 弹出单位选择 | ||||||
|   void chooseUnitHandle(EditUserType type) { |   void chooseUnitHandle(EditUserType type) { | ||||||
|     showModalBottomSheet( |     showModalBottomSheet( | ||||||
|       context: context, |       context: context, | ||||||
|       isScrollControlled: true, |       isScrollControlled: true, | ||||||
|       barrierColor: Colors.black54, |       barrierColor: Colors.black54, | ||||||
|       backgroundColor: Colors.transparent, |       backgroundColor: Colors.transparent, | ||||||
|       builder: (ctx) => DepartmentPicker(onSelected: (id, name) { |       builder: | ||||||
|         setState(() { |           (_) => DepartmentPicker( | ||||||
|         }); |             onSelected: (id, name) async { | ||||||
|       }), |               setState(() { | ||||||
|  |                 _selectedUnitId[type] = id; | ||||||
|  |                 _selectedUnitName[type] = name; | ||||||
|  |                 // 清空已选人员 | ||||||
|  |                 _selectedPersonId.remove(type); | ||||||
|  |                 _selectedPersonName.remove(type); | ||||||
|  |               }); | ||||||
|  |               // 拉取该单位的人员列表并缓存 | ||||||
|  |               final result = await ApiService.getListTreePersonList(id); | ||||||
|  |               _personCache[type] = List<Map<String, dynamic>>.from( | ||||||
|  |                 result['userList'] as List, | ||||||
|  |               ); | ||||||
|  |             }, | ||||||
|  |           ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|   /// 弹出单位对应的人员列表 | 
 | ||||||
|  |   /// 弹出人员选择,需先选择单位 | ||||||
|   void choosePersonHandle(EditUserType type) { |   void choosePersonHandle(EditUserType type) { | ||||||
|  |     final unitId = _selectedUnitId[type]; | ||||||
|  |     final personList = _personCache[type] ?? []; | ||||||
|  |     if (unitId == null || personList.isEmpty) { | ||||||
|  |       final unitName = type.displayName; | ||||||
|  |       ToastUtil.showNormal(context, '请先选择$unitName'); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     DepartmentPersonPicker.show( | ||||||
|  |       context, | ||||||
|  |       personsData: personList, | ||||||
|  |       onSelected: (userId, name) { | ||||||
|  |         setState(() { | ||||||
|  |           _selectedPersonId[type] = userId; | ||||||
|  |           _selectedPersonName[type] = name; | ||||||
|  |         }); | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |   Future<void> _submit(String STATUS) async { | ||||||
|  |     // '1'提交 ‘0’暂存 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|   } |   } | ||||||
|  |   /// 初始化拉取数据 | ||||||
|  |   Future<void> _getData() async { | ||||||
|  |     // '1'提交 ‘0’暂存 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Scaffold( |     return Scaffold( | ||||||
|  | @ -152,45 +223,49 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> { | ||||||
|           child: Column( |           child: Column( | ||||||
|             children: [ |             children: [ | ||||||
|               _card(_defaultDetail()), |               _card(_defaultDetail()), | ||||||
|               SizedBox(height: 15,), |               SizedBox(height: 15), | ||||||
|               _card(_defaultDetail()), |  | ||||||
|               SizedBox(height: 15,), |  | ||||||
|               _card(_chooseItem('分析单位', '分析单位负责人', EditUserType.analyze)), |               _card(_chooseItem('分析单位', '分析单位负责人', EditUserType.analyze)), | ||||||
|               SizedBox(height: 15,), |               SizedBox(height: 15), | ||||||
|               _card(_chooseItem('监护人单位', '监护人', EditUserType.guardian)), |               _card(_chooseItem('监护人单位', '监护人', EditUserType.guardian)), | ||||||
|               SizedBox(height: 15,), |               SizedBox(height: 15), | ||||||
|               _card(_chooseItem('安全交底人单位', '安全交底人', EditUserType.confess)), |               _card(_chooseItem('安全交底人单位', '安全交底人', EditUserType.confess)), | ||||||
|               SizedBox(height: 15,), |               SizedBox(height: 15), | ||||||
|               _card(_chooseItem('接受交底人单位', '接受交底人', EditUserType.acceptconfess)), |  | ||||||
|               SizedBox(height: 15,), |  | ||||||
|               _card(_chooseItem('作业负责人单位', '作业负责人', EditUserType.confirm)), |  | ||||||
|               SizedBox(height: 15,), |  | ||||||
|               _card(_chooseItem('安全管理部门', '所在单位负责人', EditUserType.leader)), |  | ||||||
|               SizedBox(height: 15,), |  | ||||||
|               _card(_chooseItem('动火审批单位', '动火审批负责人', EditUserType.approve)), |  | ||||||
|               SizedBox(height: 15,), |  | ||||||
|               _card(_chooseItem('动火前在岗部门', '动火前在岗班长', EditUserType.monitor)), |  | ||||||
|               SizedBox(height: 15,), |  | ||||||
|               _card(_chooseItem('作业开始负责人单位', '作业开始负责人', EditUserType.workstart)), |  | ||||||
|               SizedBox(height: 15,), |  | ||||||
| 
 |  | ||||||
|               _card( |               _card( | ||||||
|                   Column( |                 _chooseItem('接受交底人单位', '接受交底人', EditUserType.acceptconfess), | ||||||
|                     mainAxisAlignment: MainAxisAlignment.start, |  | ||||||
|                     children: [ |  | ||||||
|                       _chooseItem('作业开始负责人单位', '作业开始负责人', EditUserType.workend), |  | ||||||
|                       Divider(), |  | ||||||
|                       Row( |  | ||||||
|                         children: [ |  | ||||||
|                           SizedBox(width: 12,), |  | ||||||
|                           Text('友情提示:负责填写作业实际开始时间', style: TextStyle(color: Colors.red),), |  | ||||||
|                         ], |  | ||||||
|                       ), |  | ||||||
|                       SizedBox(height: 5,), |  | ||||||
|                     ], |  | ||||||
|                   ) |  | ||||||
|               ), |               ), | ||||||
|               SizedBox(height: 15,), |               SizedBox(height: 15), | ||||||
|  |               _card(_chooseItem('作业负责人单位', '作业负责人', EditUserType.confirm)), | ||||||
|  |               SizedBox(height: 15), | ||||||
|  |               _card(_chooseItem('安全管理部门', '所在单位负责人', EditUserType.leader)), | ||||||
|  |               SizedBox(height: 15), | ||||||
|  |               _card(_chooseItem('动火审批单位', '动火审批负责人', EditUserType.approve)), | ||||||
|  |               SizedBox(height: 15), | ||||||
|  |               _card(_chooseItem('动火前在岗部门', '动火前在岗班长', EditUserType.monitor)), | ||||||
|  |               SizedBox(height: 15), | ||||||
|  |               _card( | ||||||
|  |                 _chooseItem('作业开始负责人单位', '作业开始负责人', EditUserType.workstart), | ||||||
|  |               ), | ||||||
|  |               SizedBox(height: 15), | ||||||
|  |               _card( | ||||||
|  |                 Column( | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.start, | ||||||
|  |                   children: [ | ||||||
|  |                     _chooseItem('作业开始负责人单位', '作业开始负责人', EditUserType.workend), | ||||||
|  |                     Divider(), | ||||||
|  |                     Row( | ||||||
|  |                       children: [ | ||||||
|  |                         SizedBox(width: 12), | ||||||
|  |                         Text( | ||||||
|  |                           '友情提示:负责填写作业实际开始时间', | ||||||
|  |                           style: TextStyle(color: Colors.red), | ||||||
|  |                         ), | ||||||
|  |                       ], | ||||||
|  |                     ), | ||||||
|  |                     SizedBox(height: 5), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               SizedBox(height: 15), | ||||||
|               _card( |               _card( | ||||||
|                 Column( |                 Column( | ||||||
|                   mainAxisAlignment: MainAxisAlignment.start, |                   mainAxisAlignment: MainAxisAlignment.start, | ||||||
|  | @ -199,28 +274,63 @@ class _HotworkApplyDetailState extends State<HotworkApplyDetail> { | ||||||
|                     Divider(), |                     Divider(), | ||||||
|                     Row( |                     Row( | ||||||
|                       children: [ |                       children: [ | ||||||
|                         SizedBox(width: 12,), |                         SizedBox(width: 12), | ||||||
|                         Text('友情提示:负责填写作业实际结束时间', style: TextStyle(color: Colors.red),), |                         Text( | ||||||
|  |                           '友情提示:负责填写作业实际结束时间', | ||||||
|  |                           style: TextStyle(color: Colors.red), | ||||||
|  |                         ), | ||||||
|                       ], |                       ], | ||||||
|                     ), |                     ), | ||||||
|                     SizedBox(height: 5,), |                     SizedBox(height: 5), | ||||||
|                   ], |                   ], | ||||||
|                 ) |                 ), | ||||||
|               ), |               ), | ||||||
|               SizedBox(height: 15,), |               SizedBox(height: 15), | ||||||
|               _card(_chooseItem('验收部门', '验收部门负责人', EditUserType.accept)), |               _card(_chooseItem('验收部门', '验收部门负责人', EditUserType.accept)), | ||||||
|  |               SizedBox(height: 15), | ||||||
|  |               Row( | ||||||
|  |                 spacing: 10, | ||||||
|  |                 mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                 children: [ | ||||||
|  |                   Expanded( | ||||||
|  |                     child: CustomButton( | ||||||
|  |                       height: 45, | ||||||
|  |                       textStyle: TextStyle(fontSize: 16, color: Colors.white), | ||||||
|  |                       text: '提交', | ||||||
|  |                       backgroundColor: Colors.blue, | ||||||
|  |                       onPressed: () { | ||||||
|  |                         _submit('1'); | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
| 
 | 
 | ||||||
|  |                   Expanded( | ||||||
|  |                     child: CustomButton( | ||||||
|  |                       textStyle: TextStyle(fontSize: 16, color: Colors.white), | ||||||
|  |                       text: '暂存', | ||||||
|  |                       backgroundColor: Colors.green, | ||||||
|  |                       onPressed: () { | ||||||
|  |                         _submit('1'); | ||||||
|  |                       }, | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                 ], | ||||||
|  |               ), | ||||||
|             ], |             ], | ||||||
|           ), |           ), | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   @override |   @override | ||||||
|   void initState() { |   void initState() { | ||||||
|     // TODO: implement initState |     // TODO: implement initState | ||||||
|     super.initState(); |     super.initState(); | ||||||
|  |     if (widget.HOTWORK_ID.length > 0) { | ||||||
|  |       msg = 'edit'; | ||||||
|  |       _getData(); | ||||||
| 
 | 
 | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -116,7 +116,7 @@ class _DhWorkListPageState extends State<DhWorkListPage> { | ||||||
|   /// 申请 |   /// 申请 | ||||||
|   void _handleApply() { |   void _handleApply() { | ||||||
|     // 处理申请按钮点击逻辑 |     // 处理申请按钮点击逻辑 | ||||||
|     Navigator.pushNamed(context, '/hotwork-apply-detail'); |     pushPage(HotworkApplyDetail(HOTWORK_ID: '', flow: widget.flow), context); | ||||||
|   } |   } | ||||||
|   /// 打开流程图 |   /// 打开流程图 | ||||||
|   Future<void> _openFlowDrawer(String hotworkId) async { |   Future<void> _openFlowDrawer(String hotworkId) async { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue