import 'package:flutter/material.dart'; import 'package:lpinyin/lpinyin.dart'; import 'package:qhd_prevention/customWidget/search_bar_widget.dart'; import 'package:qhd_prevention/customWidget/toast_util.dart'; import 'package:qhd_prevention/http/modules/doorAndCar_api.dart'; import 'package:qhd_prevention/pages/my_appbar.dart'; // 人员模型类 class Person { final String employeePersonUserId; final String employeePersonUserName; final String group; final String personCorpId; final String personCorpName; final String personDepartmentId; final String personDepartmentName; final String userFaceUrl; final String userPhone; final String userCard; Person({required this.employeePersonUserId, required this.employeePersonUserName, required this.group, required this.personCorpId, required this.personCorpName, required this.personDepartmentId, required this.personDepartmentName, required this.userFaceUrl, required this.userPhone, required this.userCard, }); // 添加 toJson 方法 Map toJson() { return { 'employeePersonUserId': employeePersonUserId, 'employeePersonUserName': employeePersonUserName, 'group': group, 'personCorpId': personCorpId, 'personCorpName': personCorpName, 'personDepartmentId': personDepartmentId, 'personDepartmentName': personDepartmentName, 'userFaceUrl': userFaceUrl, 'userPhone': userPhone, 'userCard': userCard, }; } } // 选择结果类 class SelectionPersonResult { final List selectedPersons; final Map> groupedSelected; SelectionPersonResult({ required this.selectedPersons, required this.groupedSelected, }); } class PersonSelectionPage extends StatefulWidget { const PersonSelectionPage(this.oldList,this.id, {super.key,this.isMoreSelect=true,}); final List oldList; final String id; final bool isMoreSelect;//是否多选 @override State createState() => _PersonSelectionPageState(); } class _PersonSelectionPageState extends State { // 字母表(将#放在最后) final List alphabet = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '#' ]; // 人员数据 late final Map> groupedPersons; // 存储排序后的分组键列表 late final List sortedGroupKeys; // 存储每个分组的GlobalKey final Map groupKeys = {}; List< dynamic> list =[]; late Future _dataFuture; final Map selectedStates = {}; // 分组选中状态 final Map groupSelectedStates = {}; // 列表控制器 final ScrollController _scrollController = ScrollController(); final TextEditingController _searchController = TextEditingController(); // 存储每个分组在列表中的位置索引 late final Map _groupIndexMap = {}; // 创建oldList的ID集合,用于快速查找 late final Set _oldSelectedIds; @override void initState() { super.initState(); // 创建oldList的ID集合 _oldSelectedIds = widget.oldList.map((person) => person.employeePersonUserId).toSet(); _dataFuture = _initData(); } Future _initData() async { await _getProJectUserList(widget.id); // 根据姓名首字母分组 groupedPersons = {}; for (var item in list) { String id = item['userId']??''; String name = item['userName']??''; // 使用lpinyin获取姓名首字母 String firstLetter = _getFirstLetter(name); // 创建Person对象 Person person = Person( employeePersonUserId: id, employeePersonUserName: name, group: firstLetter, personCorpId: item['deptId']??'', personCorpName: item['deptName']??'', personDepartmentId: item['deptId']??'', personDepartmentName: item['deptName']??'', userFaceUrl: item['deptName']??'', userPhone: item['phone']??'', userCard: item['deptName']??'', ); // 添加到对应分组 if (!groupedPersons.containsKey(firstLetter)) { groupedPersons[firstLetter] = []; } groupedPersons[firstLetter]!.add(person); } // 对每个分组内的人员按姓名排序 groupedPersons.forEach((key, value) { value.sort((a, b) => a.employeePersonUserName.compareTo(b.employeePersonUserName)); }); // 对分组键进行排序(确保#在最后) sortedGroupKeys = groupedPersons.keys.toList()..sort((a, b) { // 如果a是#,a应该在后面 if (a == '#') return 1; // 如果b是#,b应该在后面 if (b == '#') return -1; // 其他情况正常排序 return a.compareTo(b); }); // 构建分组索引映射 for (int i = 0; i < sortedGroupKeys.length; i++) { _groupIndexMap[sortedGroupKeys[i]] = i; } // 初始化选中状态和为每个分组创建GlobalKey for (var group in groupedPersons.keys) { for (var person in groupedPersons[group]!) { // 检查当前人员是否在oldList中,如果在则设置为true selectedStates[person.employeePersonUserId] = _oldSelectedIds.contains(person.employeePersonUserId); } // 初始化分组选中状态 groupSelectedStates[group] = false; groupKeys[group] = GlobalKey(); } // 更新每个分组的全选状态 for (var group in groupedPersons.keys) { _updateGroupSelection(group); } } Future _getProJectUserList(String id) async { try { final Map result = await DoorAndCarApi.getPeopleinProject(id); if (result['success'] ) { setState(() { list = result['data']; }); }else{ ToastUtil.showNormal(context, '加载数据失败'); // _showMessage('加载数据失败'); } } catch (e) { print('Error fetching data: $e'); } } // 使用lpinyin获取姓名的首字母 String _getFirstLetter(String name) { if (name.isEmpty) return '#'; try { // 检查第一个字符是否是英文字母 String firstChar = name.substring(0, 1); RegExp englishLetter = RegExp(r'^[A-Za-z]$'); if (englishLetter.hasMatch(firstChar)) { return firstChar.toUpperCase(); } // 检查第一个字符是否是数字或特殊字符 RegExp nonChinese = RegExp(r'^[0-9!@#\$%^&*()_+\-=\[\]{};:"\\|,.<>\/?~`]'); if (nonChinese.hasMatch(firstChar)) { return '#'; } // 获取拼音 - 使用WITHOUT_TONE格式获取完整拼音 String pinyin = PinyinHelper.getPinyin(name, separator: ' ', format: PinyinFormat.WITHOUT_TONE); if (pinyin.isNotEmpty) { // 获取第一个字的拼音首字母 List pinyinParts = pinyin.split(' '); if (pinyinParts.isNotEmpty) { String firstCharPinyin = pinyinParts[0]; if (firstCharPinyin.isNotEmpty) { String firstLetter = firstCharPinyin.substring(0, 1).toUpperCase(); // 检查是否是英文字母 if (englishLetter.hasMatch(firstLetter)) { return firstLetter; } } } } } catch (e) { // 异常处理,返回# print('拼音转换错误: $e'); } // 如果无法识别,返回# return '#'; } // 滚动到指定分组 void _scrollToGroup(String letter) { if (!groupedPersons.containsKey(letter)) return; // 方法1:使用索引跳转(更精确) int? index = _groupIndexMap[letter]; if (index != null && _scrollController.hasClients) { // 计算大概的滚动位置(每个分组标题高度 + 每个人item高度) double position = 0; for (int i = 0; i < index; i++) { String group = sortedGroupKeys[i]; // 分组标题高度56,每个人item高度56 position += 56; // 分组标题高度 position += (groupedPersons[group]?.length ?? 0) * 56; // 人员列表高度 } _scrollController.animateTo( position, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); return; } // 方法2:使用GlobalKey(备选方案) final key = groupKeys[letter]; if (key?.currentContext != null) { Scrollable.ensureVisible( key!.currentContext!, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, alignment: 0, // 滚动到顶部 ); } } // 更新分组的全选状态 void _updateGroupSelection(String group) { final groupPersons = groupedPersons[group]!; final allSelected = groupPersons.every((person) => selectedStates[person.employeePersonUserId] == true); final anySelected = groupPersons.any((person) => selectedStates[person.employeePersonUserId] == true); setState(() { groupSelectedStates[group] = allSelected; }); } // 切换分组的全选/全不选 void _toggleGroupSelection(String group) { final newState = !(groupSelectedStates[group] ?? false); final groupPersons = groupedPersons[group]!; setState(() { groupSelectedStates[group] = newState; for (var person in groupPersons) { selectedStates[person.employeePersonUserId] = newState; } }); } // 获取选中的人员 SelectionPersonResult _getSelectedResult() { List selectedPersons = []; Map> groupedSelected = {}; for (var group in groupedPersons.keys) { final groupPersons = groupedPersons[group]!; final selectedInGroup = groupPersons .where((person) => selectedStates[person.employeePersonUserId] == true) .toList(); if (selectedInGroup.isNotEmpty) { groupedSelected[group] = selectedInGroup; selectedPersons.addAll(selectedInGroup); } } return SelectionPersonResult( selectedPersons: selectedPersons, groupedSelected: groupedSelected, ); } // 确认添加并返回 void _confirmSelection() { final result = _getSelectedResult(); // ,如果没有选择人员,提示用户 if (result.selectedPersons.isEmpty) { ToastUtil.showNormal(context, '请选择一个人'); return; } Navigator.pop(context, result); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: MyAppbar(title: '选择人员', actions: [ TextButton( onPressed: () { _confirmSelection(); }, child: Text( "确认添加", style: TextStyle(color: Colors.white, fontSize: 16), ), ), ],), body: FutureBuilder( future: _dataFuture, builder: (context, snapshot) { if (snapshot.connectionState != ConnectionState.done) { return const Center(child: CircularProgressIndicator()); } return Column( children: [ Container( color: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 8), child: SearchBarWidget( showResetButton: true, hintText: '请输入关键字', resetButtonText: '重置', onReset: () { FocusScope.of(context).unfocus(); _searchController.text = ''; _search(); }, onSearch: (text) { FocusScope.of(context).unfocus(); _search(); }, controller: _searchController, ), ), // 人员列表 Expanded( child: Row( children: [ // 左侧人员列表 Expanded( child: ListView.builder( controller: _scrollController, itemCount: sortedGroupKeys.length, itemBuilder: (context, index) { String group = sortedGroupKeys[index]; List persons = groupedPersons[group]!; return _buildGroupSection(group, persons); }, ), ), // 右侧字母导航 Container( width: 30, color: Colors.grey.shade50, child: ListView.builder( itemCount: alphabet.length, itemBuilder: (context, index) { final letter = alphabet[index]; final hasGroup = groupedPersons.containsKey(letter); return GestureDetector( onTap: hasGroup ? () => _scrollToGroup(letter) : null, child: Container( height: 30, alignment: Alignment.center, child: Text( letter, style: TextStyle( fontSize: 12, color: hasGroup ? Colors.blue : Colors.grey.shade400, fontWeight: hasGroup ? FontWeight.bold : FontWeight.normal, ), ), ), ); }, ), ), ], ), ), ], ); }, ), ); } // 构建分组区域 Widget _buildGroupSection(String group, List persons) { return Container( key: groupKeys[group], child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 分组标题 Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), color: Colors.grey.shade100, height: 56, // 固定高度便于计算 child: Row( children: [ Text( group, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), const Spacer(), ], ), ), // 人员列表 ...persons.map((person) => _buildPersonItem(person)), ], ), ); } // 构建人员项 Widget _buildPersonItem(Person person) { return Container( decoration: BoxDecoration( border: Border( bottom: BorderSide( color: Colors.grey.shade200, width: 0.5, ), ), ), height: 56, // 固定高度便于计算 child: CheckboxListTile( title: Text( person.employeePersonUserName, style: const TextStyle(fontSize: 14), ), value: selectedStates[person.employeePersonUserId] ?? false, onChanged: (bool? value) { setState(() { if(widget.isMoreSelect){ selectedStates[person.employeePersonUserId] = value ?? false; _updateGroupSelection(person.group); }else{ // 清空所有选中状态 for (var group in groupedPersons.keys) { for (var p in groupedPersons[group]!) { selectedStates[p.employeePersonUserId] = false; } } // 设置当前选中 selectedStates[person.employeePersonUserId] = true; } }); }, activeColor: Colors.blue, controlAffinity: ListTileControlAffinity.leading, contentPadding: const EdgeInsets.symmetric(horizontal: 0), ), ); } void _search() { // searchKeywords = _searchController.text.trim(); // currentPage = 1; // list.clear(); // _fetchData(); } }