import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:qhd_prevention/customWidget/search_bar_widget.dart'; import 'package:qhd_prevention/pages/http/ApiService.dart'; import 'package:qhd_prevention/tools/tools.dart'; // 数据模型 class Category { final String id; final String name; final List children; Category({ required this.id, required this.name, this.children = const [], }); factory Category.fromJson(Map json) { return Category( id: json['id'] as String, name: json['name'] as String, children: (json['children'] as List) .map((e) => Category.fromJson(e as Map)) .toList(), ); } } /// 弹窗回调签名:返回选中项的 id 和 name typedef DeptSelectCallback = void Function(String id, String name); class DepartmentPicker extends StatefulWidget { /// 回调,返回选中部门 id 与 name final DeptSelectCallback onSelected; const DepartmentPicker({Key? key, required this.onSelected}) : super(key: key); @override _DepartmentPickerState createState() => _DepartmentPickerState(); } class _DepartmentPickerState extends State { String selectedId = ''; String selectedName = ''; Set expandedSet = {}; List original = []; List filtered = []; bool loading = true; final TextEditingController _searchController = TextEditingController(); @override void initState() { super.initState(); // 初始均为空 selectedId = ''; selectedName = ''; expandedSet = {}; _searchController.addListener(_onSearchChanged); _loadData(); } @override void dispose() { _searchController.removeListener(_onSearchChanged); _searchController.dispose(); super.dispose(); } Future _loadData() async { try { List raw; if (SessionService.instance.departmentJsonStr?.isNotEmpty ?? false) { raw = json.decode(SessionService.instance.departmentJsonStr!) as List; } else { final result = await ApiService.getHiddenTreatmentListTree(); final String nodes = result['zTreeNodes'] as String; SessionService.instance.departmentJsonStr = nodes; raw = json.decode(nodes) as List; } setState(() { original = raw.map((e) => Category.fromJson(e as Map)).toList(); filtered = original; loading = false; }); } catch (e) { setState(() => loading = false); } } void _onSearchChanged() { final query = _searchController.text.toLowerCase().trim(); setState(() { filtered = query.isEmpty ? original : _filterCategories(original, query); }); } List _filterCategories(List list, String query) { List result = []; for (var cat in list) { final children = _filterCategories(cat.children, query); if (cat.name.toLowerCase().contains(query) || children.isNotEmpty) { result.add(Category(id: cat.id, name: cat.name, children: children)); } } return result; } Widget _buildRow(Category cat, int indent) { final hasChildren = cat.children.isNotEmpty; final isExpanded = expandedSet.contains(cat.id); final isSelected = cat.id == selectedId; return Column( children: [ InkWell( onTap: () { setState(() { if (hasChildren) { isExpanded ? expandedSet.remove(cat.id) : expandedSet.add(cat.id); } selectedId = cat.id; selectedName = cat.name; }); }, child: Container( color: Colors.white, child: Row( children: [ SizedBox(width: 16.0 * indent), SizedBox( width: 24, child: hasChildren ? Icon(isExpanded ? Icons.arrow_drop_down_rounded : Icons.arrow_right_rounded, size: 35, color: Colors.grey[600]) : const SizedBox.shrink(), ), const SizedBox(width: 5), Expanded( child: Padding( padding: const EdgeInsets.symmetric(vertical: 12), child: Text(cat.name), ), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Icon( isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked, color: Colors.green, ), ), ], ), ), ), if (hasChildren && isExpanded) ...cat.children.map((c) => _buildRow(c, indent + 1)), ], ); } @override Widget build(BuildContext context) { return Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height * 0.7, color: Colors.white, child: Column( children: [ Container( color: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Row( children: [ GestureDetector( onTap: () => Navigator.of(context).pop(), child: const Text('取消', style: TextStyle(fontSize: 16)), ), Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: SearchBarWidget( controller: _searchController, isShowSearchButton: false, onSearch: (keyboard) { }, ), ), ), GestureDetector( onTap: () { Navigator.of(context).pop(); widget.onSelected(selectedId, selectedName); }, child: const Text('确定', style: TextStyle(fontSize: 16, color: Colors.green)), ), ], ), ), Divider(), Expanded( child: loading ? const Center(child: CircularProgressIndicator()) : Container( color: Colors.white, child: ListView.builder( itemCount: filtered.length, itemBuilder: (ctx, idx) => _buildRow(filtered[idx], 0), ), ), ), ], ), ); } }