QinGang_interested/lib/customWidget/department_picker_hidden.dart

297 lines
9.1 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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/services/SessionService.dart';
import '../tools/tools.dart'; // 包含 SessionService
// 数据模型
class Category {
final String id;
final String name;
final Map<String, dynamic> extValues;
final String departmentId;
final String parentId;
final String corpinfoId; // 新增:和 departmentId 同层级
final List<Category> childrenList;
Category({
required this.id,
required this.name,
required this.childrenList,
required this.extValues,
required this.departmentId,
required this.parentId,
required this.corpinfoId,
});
factory Category.fromJson(Map<String, dynamic> json) {
// 安全读取并兼容字符串或数字类型的 id
String parseString(dynamic v) {
if (v == null) return '';
if (v is String) return v;
return v.toString();
}
final rawChildren = json['childrenList'];
List<Category> children = [];
if (rawChildren is List) {
try {
children = rawChildren
.where((e) => e != null)
.map((e) => Category.fromJson(Map<String, dynamic>.from(e as Map)))
.toList();
} catch (e) {
// 如果内部解析出错,保持 children 为空并继续
children = [];
}
}
// extValues 有可能为 null 或不是 Map
final extRaw = json['extValues'];
Map<String, dynamic> extMap = {};
if (extRaw is Map) {
extMap = Map<String, dynamic>.from(extRaw);
}
return Category(
id: parseString(json['id']),
name: parseString(json['name']),
childrenList: children,
extValues: extMap,
departmentId: parseString(json['departmentId']),
parentId: parseString(json['parentId']),
corpinfoId: parseString(json['corpinfoId']), // 从 JSON 同层级读取
);
}
}
/// 弹窗回调签名:返回选中项的 id 和 name (保持原样,兼容旧代码)
typedef DeptSelectCallback = void Function(String id, String name);
class DepartmentPickerHidden extends StatefulWidget {
/// 原回调,返回选中部门 id 与 name保持不变
final DeptSelectCallback onSelected;
/// 新增可选扩展回调:当需要 corpinfoId 时使用(不影响原有调用)
final void Function(String id, String name, String? corpinfoId)? onSelectedWithCorp;
/// 是否包含所有公司
final bool includeAllFirm;
final Map? data;
const DepartmentPickerHidden({
Key? key,
required this.onSelected,
this.onSelectedWithCorp,
this.includeAllFirm = false,
this.data,
}) : super(key: key);
@override
_DepartmentPickerHiddenState createState() => _DepartmentPickerHiddenState();
}
class _DepartmentPickerHiddenState extends State<DepartmentPickerHidden> {
String selectedId = '';
String selectedName = '';
String? selectedCorpinfoId; // 记录选中项的 corpinfoId可为 null
Set<String> expandedSet = {};
List<Category> original = [];
List<Category> filtered = [];
bool loading = true;
final TextEditingController _searchController = TextEditingController();
@override
void initState() {
super.initState();
// 初始均为空
selectedId = '';
selectedName = '';
selectedCorpinfoId = null;
expandedSet = {};
_searchController.addListener(_onSearchChanged);
_loadData();
}
@override
void dispose() {
_searchController.removeListener(_onSearchChanged);
_searchController.dispose();
super.dispose();
}
Future<void> _loadData() async {
try {
final result = await BasicInfoApi.getDeptFour(widget.includeAllFirm, data: widget.data);
final raw = result['data'] as List<dynamic>;
print(raw);
setState(() {
original = raw.map((e) => Category.fromJson(e as Map<String, dynamic>)).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<Category> _filterCategories(List<Category> list, String query) {
List<Category> result = [];
for (var cat in list) {
final children = _filterCategories(cat.childrenList, query);
if (cat.name.toLowerCase().contains(query) || children.isNotEmpty) {
result.add(
Category(
id: cat.id,
name: cat.name,
childrenList: children,
extValues: cat.extValues,
departmentId: cat.departmentId,
parentId: cat.parentId,
corpinfoId: cat.corpinfoId, // 保持 corpinfoId 传递
),
);
}
}
return result;
}
Widget _buildRow(Category cat, int indent) {
final hasChildren = cat.childrenList.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;
selectedCorpinfoId = cat.corpinfoId.isEmpty ? null : cat.corpinfoId;
});
},
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.childrenList.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: () {
// 关闭弹窗并回调:优先调用扩展回调(带 corpinfoId否则调用原回调
Navigator.of(context).pop();
if (widget.onSelectedWithCorp != null) {
widget.onSelectedWithCorp!(
selectedId,
selectedName,
selectedCorpinfoId,
);
} else {
widget.onSelected(selectedId, selectedName);
}
},
child: const Text(
'确定',
style: TextStyle(fontSize: 16, color: Colors.blue),
),
),
],
),
),
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),
),
),
),
],
),
);
}
}