flutter_integrated_whb/lib/pages/home/tap/workArea_picker.dart

288 lines
8.6 KiB
Dart
Raw Permalink Normal View History

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/search_bar_widget.dart';
import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/tools/tools.dart';
// ----- Models -----
class Category {
final String ELECTRONIC_FENCE_AREA_ID;
final String POSITIONS;
final String name;
final List<Category> children;
Category({
required this.ELECTRONIC_FENCE_AREA_ID,
required this.name,
this.POSITIONS = '',
this.children = const [],
});
factory Category.fromJson(Map<String, dynamic> json) {
// 保护式读取,避免 null 转 List、String 时抛异常
final id = (json['ELECTRONIC_FENCE_AREA_ID'] ?? '').toString();
final name = (json['name'] ?? '').toString();
final positions = (json['POSITIONS'] ?? '').toString();
// children 可能不存在、为 null、或已经是 List
final rawChildren = json['children'];
List<Category> childrenList = [];
if (rawChildren is List) {
childrenList = rawChildren
.where((e) => e != null)
.map((e) {
// e 可能已经是 Map<String,dynamic> 或 dynamic
if (e is Map<String, dynamic>) {
return Category.fromJson(e);
} else if (e is Map) {
return Category.fromJson(Map<String, dynamic>.from(e));
} else {
// 无法解析的项跳过,或返回空占位
return null;
}
})
.whereType<Category>()
.toList();
}
return Category(
ELECTRONIC_FENCE_AREA_ID: id,
name: name,
POSITIONS: positions,
children: childrenList,
);
}
}
typedef DeptSelectCallback =
void Function(String id, String POSITIONS, String name);
class WorkAreaPicker extends StatefulWidget {
final DeptSelectCallback onSelected;
const WorkAreaPicker({Key? key, required this.onSelected}) : super(key: key);
@override
_WorkAreaPickerState createState() => _WorkAreaPickerState();
}
class _WorkAreaPickerState extends State<WorkAreaPicker> {
String selectedId = '';
String selectedName = '';
String selected_POSITIONS = '';
Set<String> expandedSet = {};
List<Category> original = [];
List<Category> filtered = [];
bool loading = true;
final TextEditingController _searchController = TextEditingController();
@override
void initState() {
super.initState();
// 初始均为空
selectedId = '';
selectedName = '';
selected_POSITIONS = '';
expandedSet = {};
_searchController.addListener(_onSearchChanged);
_loadData();
}
@override
void dispose() {
_searchController.removeListener(_onSearchChanged);
_searchController.dispose();
super.dispose();
}
Future<void> _loadData() async {
try {
final result = await ApiService.getWorkAreaList();
final dynamic nodesField = result['zTreeNodes'];
// nodesField 可能是已经解析过的 List 或者是 StringJSON 字符串)
List<dynamic> raw;
if (nodesField is String) {
raw = json.decode(nodesField) as List<dynamic>;
} else if (nodesField is List) {
raw = nodesField;
} else {
raw = [];
}
// debug 打印(运行中可查看控制台)
// print('raw length = ${raw.length}');
setState(() {
original = raw
.map((e) {
if (e is Map<String, dynamic>) return Category.fromJson(e);
if (e is Map) return Category.fromJson(Map<String, dynamic>.from(e));
return null;
})
.whereType<Category>()
.toList();
filtered = original;
loading = false;
});
} catch (e, st) {
// 打印错误以便调试
// print('loadData error: $e\n$st');
setState(() => loading = false);
}
}
void _onSearchChanged() {
final query = _searchController.text.toLowerCase().trim();
setState(() {
filtered = query.isEmpty ? original : _filterCategories(original, query);
});
}
List<Category> _filterCategories(List<Category> list, String query) {
List<Category> result = [];
for (var cat in list) {
final children = _filterCategories(cat.children, query);
if (cat.name.toLowerCase().contains(query) || children.isNotEmpty) {
result.add(
Category(
ELECTRONIC_FENCE_AREA_ID: cat.ELECTRONIC_FENCE_AREA_ID,
name: cat.name,
children: children,
),
);
}
}
return result;
}
Widget _buildRow(Category cat, int indent) {
final hasChildren = cat.children.isNotEmpty;
final isExpanded = expandedSet.contains(cat.ELECTRONIC_FENCE_AREA_ID);
final isSelected = cat.ELECTRONIC_FENCE_AREA_ID == selectedId;
return Column(
children: [
InkWell(
onTap: () {
setState(() {
if (hasChildren) {
isExpanded
? expandedSet.remove(cat.ELECTRONIC_FENCE_AREA_ID)
: expandedSet.add(cat.ELECTRONIC_FENCE_AREA_ID);
}
selectedId = cat.ELECTRONIC_FENCE_AREA_ID;
selectedName = cat.name;
selected_POSITIONS = cat.POSITIONS;
});
},
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,
selected_POSITIONS,
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),
),
),
),
],
),
);
}
}