QinGang_interested/lib/customWidget/related_parties_picker.dart

300 lines
8.5 KiB
Dart

import 'dart:convert';
import 'package:flutter/material.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/tools/tools.dart';
/// 数据模型
class CategoryTypeThree {
final String id;
final String name;
final String pdId;
final Map<String, dynamic> rawJson;
final List<CategoryTypeThree> children;
CategoryTypeThree({
required this.id,
required this.name,
required this.pdId,
required this.rawJson,
this.children = const [],
});
factory CategoryTypeThree.fromJson(Map<String, dynamic> json) {
return CategoryTypeThree(
id: json['id'] != null ? json['id'].toString() : "",
name: json['projectName'] != null ? json['projectName'].toString() : "",
pdId: json['parentId'] != null ? json['parentId'].toString() : "",
rawJson: Map<String, dynamic>.from(json),
children: _parseChildren(json['children']),
);
}
static List<CategoryTypeThree> _parseChildren(dynamic childrenData) {
if (childrenData == null) return [];
if (childrenData is! List) return [];
return childrenData
.whereType<Map<String, dynamic>>()
.map((e) => CategoryTypeThree.fromJson(e))
.toList();
}
}
/// 原来的回调保持不变
typedef DeptSelectCallback = void Function(String id, String name, String pdId);
/// 新增:整条 JSON 回调(可选,不影响旧调用)
typedef DeptSelectJsonCallback = void Function(
String id,
String name,
String pdId,
Map<String, dynamic> selectedJson,
);
class RelatedPartiesPicker extends StatefulWidget {
/// 原来的回调,保留不变
final DeptSelectCallback onSelected;
/// 新增:可选回调,回传整条 JSON
final DeptSelectJsonCallback? onSelectedJson;
final listdata;
const RelatedPartiesPicker({
Key? key,
required this.onSelected,
required this.listdata,
this.onSelectedJson,
}) : super(key: key);
@override
_RelatedPartiesPickerState createState() => _RelatedPartiesPickerState();
}
class _RelatedPartiesPickerState extends State<RelatedPartiesPicker> {
String selectedId = '';
String selectedPDId = '';
String selectedName = '';
Map<String, dynamic> selectedJson = {};
Set<String> expandedSet = {};
List<CategoryTypeThree> original = [];
List<CategoryTypeThree> filtered = [];
bool loading = true;
final TextEditingController _searchController = TextEditingController();
@override
void initState() {
super.initState();
selectedId = '';
selectedName = '';
selectedPDId = '';
selectedJson = {};
expandedSet = {};
_searchController.addListener(_onSearchChanged);
_getRelatedPartiesList();
}
Future<void> _getRelatedPartiesList() async {
try {
final raw = await HiddenDangerApi.getRelatedPartiesList();
if (raw['success']) {
final newList = raw['data'] ?? [];
setState(() {
original = (newList as List<dynamic>)
.whereType<Map<String, dynamic>>()
.map<CategoryTypeThree>((json) => CategoryTypeThree.fromJson(json))
.toList();
filtered = original;
loading = false;
});
} else {
ToastUtil.showNormal(context, "获取列表失败");
setState(() {
original = [];
filtered = original;
loading = false;
});
}
} catch (e) {
print('获取数据失败:$e');
setState(() {
original = [];
filtered = original;
loading = false;
});
}
}
@override
void dispose() {
_searchController.removeListener(_onSearchChanged);
_searchController.dispose();
super.dispose();
}
void _onSearchChanged() {
final query = _searchController.text.toLowerCase().trim();
setState(() {
filtered = query.isEmpty ? original : _filterCategories(original, query);
});
}
List<CategoryTypeThree> _filterCategories(
List<CategoryTypeThree> list,
String query,
) {
List<CategoryTypeThree> result = [];
for (var cat in list) {
final children = _filterCategories(cat.children, query);
if (cat.name.toLowerCase().contains(query) || children.isNotEmpty) {
result.add(
CategoryTypeThree(
id: cat.id,
name: cat.name,
pdId: cat.pdId,
rawJson: cat.rawJson,
children: children,
),
);
}
}
return result;
}
Widget _buildRow(CategoryTypeThree 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);
selectedPDId = cat.pdId;
} else {
selectedPDId = cat.id;
}
selectedId = cat.id;
selectedName = cat.name;
selectedJson = cat.rawJson;
});
},
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.blue,
),
),
],
),
),
),
if (hasChildren && isExpanded)
...cat.children.map((c) => _buildRow(c, indent + 1)),
],
);
}
void _confirm() {
Navigator.of(context).pop();
widget.onSelected(selectedId, selectedName, selectedPDId);
// 新增回调:不影响旧调用
widget.onSelectedJson?.call(
selectedId,
selectedName,
selectedPDId,
selectedJson,
);
}
@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: _confirm,
child: const Text(
'确定',
style: TextStyle(fontSize: 16, color: Colors.blue),
),
),
],
),
),
const 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),
),
),
),
],
),
);
}
}