333 lines
15 KiB
Dart
333 lines
15 KiB
Dart
import 'package:animated_tree_view/animated_tree_view.dart';
|
||
import 'package:flutter/cupertino.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter/widgets.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
import 'package:get/get.dart';
|
||
import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dart';
|
||
import 'package:starwork_flutter/base/app_logger.dart';
|
||
import 'package:starwork_flutter/common/constant/app_colors.dart';
|
||
import 'package:starwork_flutter/common/constant/app_images.dart';
|
||
import 'package:starwork_flutter/common/widgets/custome_app_bar_wdiget.dart';
|
||
import 'package:starwork_flutter/extension/function_extension.dart';
|
||
import 'select_person_controller.dart';
|
||
|
||
class SelectPersonView extends GetView<SelectPersonController> {
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
backgroundColor: AppColors.scaffoldBackgroundColor,
|
||
appBar: CustomAppBarWidget(
|
||
title: '选择用户'.tr,
|
||
backgroundColor: AppColors.scaffoldBackgroundColor,
|
||
leading: IconButton(
|
||
icon: const Icon(
|
||
Icons.clear_rounded,
|
||
color: Colors.black,
|
||
),
|
||
onPressed: () => Navigator.of(context).pop(),
|
||
),
|
||
),
|
||
body: SafeArea(
|
||
child: Padding(
|
||
padding: EdgeInsets.symmetric(
|
||
horizontal: 10.w,
|
||
vertical: 10.h,
|
||
),
|
||
child: Column(
|
||
children: [
|
||
_buildSearchBar(),
|
||
SizedBox(
|
||
height: 10.h,
|
||
),
|
||
Container(
|
||
alignment: Alignment.centerLeft,
|
||
child: Text(
|
||
'组织架构',
|
||
textAlign: TextAlign.left,
|
||
style: TextStyle(
|
||
fontSize: 12.sp,
|
||
fontWeight: FontWeight.w500,
|
||
color: Colors.grey,
|
||
),
|
||
),
|
||
),
|
||
SizedBox(
|
||
height: 10.h,
|
||
),
|
||
Expanded(
|
||
child: Obx(
|
||
() {
|
||
return Container(
|
||
decoration: const BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
||
),
|
||
child: RefreshIndicator(
|
||
onRefresh: () async {
|
||
await controller.requestDepartList();
|
||
},
|
||
color: const Color(0xFF4A90E2),
|
||
backgroundColor: Colors.white,
|
||
displacement: 60.0,
|
||
edgeOffset: 0.0,
|
||
triggerMode: RefreshIndicatorTriggerMode.onEdge,
|
||
strokeWidth: 2.5,
|
||
semanticsLabel: '下拉刷新首页内容',
|
||
semanticsValue: '刷新中...',
|
||
child: TreeView.simple(
|
||
tree: controller.treeData.value ?? TreeNode.root(),
|
||
showRootNode: false,
|
||
expansionIndicatorBuilder: noExpansionIndicatorBuilder,
|
||
indentation: const Indentation(style: IndentStyle.roundJoint),
|
||
onItemTap: (item) {
|
||
if (item.data is PersonItem) {
|
||
PersonItem personInfo = item.data;
|
||
// 避免重复添加
|
||
if (!controller.selectPersonNoList.contains(personInfo.personNo) &&
|
||
personInfo.personNo != null) {
|
||
controller.selectPersonNoList.add(personInfo.personNo!);
|
||
} else {
|
||
controller.selectPersonNoList.remove(personInfo.personNo);
|
||
}
|
||
|
||
controller.selectPersonNoList.refresh();
|
||
}
|
||
},
|
||
onTreeReady: (c) {
|
||
controller.treeViewController = c;
|
||
},
|
||
builder: (context, node) {
|
||
String title = "";
|
||
DepartItem departInfo = DepartItem();
|
||
PersonItem personInfo = PersonItem();
|
||
int personNum = 0;
|
||
bool hasChildren = node.childrenAsList.isNotEmpty; // 判断是否有子节点
|
||
bool isPersonItem = node.data is PersonItem; // 判断当前节点是否是人员节点
|
||
bool isOneself = false;
|
||
bool isRootNode = false;
|
||
bool isSuper = false;
|
||
|
||
if (node.data is DepartItem) {
|
||
final depart = node.data as DepartItem;
|
||
title = depart.departName ?? "未命名部门";
|
||
personNum = depart.personNum ?? 0;
|
||
departInfo = depart;
|
||
if (hasChildren) {
|
||
title = title + "($personNum)";
|
||
} else {
|
||
title = title + "(0)";
|
||
}
|
||
if (depart.parentId == -1) {
|
||
isRootNode = true;
|
||
}
|
||
} else if (node.data is PersonItem) {
|
||
// 处理人员节点
|
||
personInfo = node.data as PersonItem;
|
||
title = personInfo.personName ?? "未命名人员";
|
||
|
||
personInfo.roles?.forEach((role) {
|
||
if (role.isSuper == 1) {
|
||
isSuper = true;
|
||
}
|
||
});
|
||
}
|
||
|
||
return Container(
|
||
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 6.h),
|
||
child: Row(
|
||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||
children: [
|
||
Expanded(
|
||
child: Row(
|
||
children: [
|
||
!isPersonItem
|
||
? Container(
|
||
width: 34.w,
|
||
height: 34.w,
|
||
decoration: BoxDecoration(
|
||
color: Colors.grey[300],
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
child: ClipRRect(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
child: Icon(
|
||
Icons.folder,
|
||
size: 22.w,
|
||
color: Colors.blue,
|
||
),
|
||
),
|
||
)
|
||
: Container(
|
||
width: 34.w,
|
||
height: 34.w,
|
||
decoration: BoxDecoration(
|
||
color: Colors.grey[200],
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
),
|
||
child: ClipRRect(
|
||
borderRadius: BorderRadius.circular(8.r),
|
||
child: Image(
|
||
image: const AssetImage(AppImages.defaultAvatar),
|
||
width: 22.w,
|
||
height: 22.w,
|
||
fit: BoxFit.cover,
|
||
gaplessPlayback: true,
|
||
filterQuality: FilterQuality.medium,
|
||
errorBuilder: (context, error, stackTrace) {
|
||
return Icon(
|
||
Icons.person,
|
||
size: 30.sp,
|
||
color: Colors.grey[400],
|
||
);
|
||
},
|
||
),
|
||
),
|
||
),
|
||
SizedBox(
|
||
width: 10.w,
|
||
),
|
||
Expanded(
|
||
child: Text(
|
||
title,
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
fontWeight: FontWeight.w500,
|
||
),
|
||
maxLines: 1,
|
||
overflow: TextOverflow.ellipsis,
|
||
),
|
||
),
|
||
Visibility(
|
||
visible: isPersonItem,
|
||
child: Obx(
|
||
() => Checkbox(
|
||
value: controller.selectPersonNoList.contains(personInfo.personNo),
|
||
activeColor: Colors.blue,
|
||
onChanged: (value) {
|
||
if (value == true) {
|
||
// 避免重复添加
|
||
if (!controller.selectPersonNoList.contains(personInfo.personNo) &&
|
||
personInfo.id != null) {
|
||
controller.selectPersonNoList.add(personInfo.personNo!);
|
||
}
|
||
} else {
|
||
controller.selectPersonNoList.remove(personInfo.personNo);
|
||
}
|
||
controller.selectPersonNoList.refresh();
|
||
},
|
||
),
|
||
),
|
||
)
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
},
|
||
),
|
||
),
|
||
);
|
||
},
|
||
),
|
||
),
|
||
SizedBox(
|
||
height: 10.h,
|
||
),
|
||
Row(
|
||
children: [
|
||
Obx(
|
||
() => Text(
|
||
'已选择:${controller.selectPersonNoList.length}人',
|
||
style: TextStyle(
|
||
fontSize: 14.sp,
|
||
fontWeight: FontWeight.w500,
|
||
color: Colors.blue,
|
||
),
|
||
),
|
||
),
|
||
SizedBox(
|
||
width: 20.w,
|
||
),
|
||
Expanded(
|
||
flex: 1,
|
||
child: ElevatedButton(
|
||
onPressed: () {
|
||
if (controller.selectPersonNoList.isEmpty) {
|
||
controller.showToast('请先选择一个用户'.tr);
|
||
return;
|
||
}
|
||
List<PersonItem> selectPersonList = [];
|
||
// 通过controller.selectPersonNoList 判断controoler.allPersonList对应选中的personInfo
|
||
controller.selectPersonNoList.forEach((personNo) {
|
||
controller.allPersonList.forEach((personInfo) {
|
||
if (personInfo.personNo == personNo) {
|
||
selectPersonList.add(personInfo);
|
||
}
|
||
});
|
||
});
|
||
|
||
Get.back(result: selectPersonList);
|
||
}.debounce(),
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: Colors.blue,
|
||
padding: EdgeInsets.symmetric(vertical: 12.h),
|
||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)),
|
||
),
|
||
child: Text(
|
||
'确定'.tr,
|
||
style: TextStyle(
|
||
fontSize: 16.sp,
|
||
color: Colors.white,
|
||
fontWeight: FontWeight.w500,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
)
|
||
],
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
_buildSearchBar() {
|
||
return TextField(
|
||
controller: controller.searchInputController,
|
||
textInputAction: TextInputAction.search,
|
||
decoration: InputDecoration(
|
||
hintText: '请输入设备名称'.tr,
|
||
hintStyle: TextStyle(
|
||
fontSize: 14.sp,
|
||
color: const Color(0xFF999999),
|
||
),
|
||
prefixIcon: const Icon(
|
||
Icons.search,
|
||
color: Color(0xFF999999),
|
||
),
|
||
filled: true,
|
||
// 启用背景填充
|
||
fillColor: const Color(0xFFf0f0f0),
|
||
// 灰色背景(可调整色值)
|
||
border: InputBorder.none,
|
||
// 设置内边距
|
||
contentPadding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
|
||
focusedBorder: OutlineInputBorder(
|
||
borderSide: const BorderSide(
|
||
color: Colors.blue,
|
||
width: 1.5,
|
||
),
|
||
borderRadius: BorderRadius.circular(8.0.r),
|
||
),
|
||
enabledBorder: OutlineInputBorder(
|
||
borderSide: const BorderSide(color: Colors.transparent),
|
||
borderRadius: BorderRadius.circular(8.0.r),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|