import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:sk_base_mobile/apis/api.dart'; import 'package:sk_base_mobile/app_theme.dart'; import 'package:sk_base_mobile/constants/bg_color.dart'; import 'package:sk_base_mobile/constants/constants.dart'; import 'package:sk_base_mobile/models/user_info.model.dart'; import 'package:sk_base_mobile/screens/hr_manage/components/edit_userinfo.dart'; import 'package:sk_base_mobile/util/date.util.dart'; import 'package:sk_base_mobile/util/debouncer.dart'; import 'package:sk_base_mobile/util/device.util.dart'; import 'package:sk_base_mobile/util/media_util.dart'; import 'package:sk_base_mobile/util/modal.util.dart'; import 'package:sk_base_mobile/util/router.util.dart'; import 'package:sk_base_mobile/util/screen_adaper_util.dart'; import 'package:sk_base_mobile/util/snack_bar.util.dart'; import 'package:sk_base_mobile/widgets/core/sk_avatar.dart'; import 'package:sk_base_mobile/widgets/core/sk_ink.dart'; import 'package:sk_base_mobile/widgets/core/sk_tag.dart'; import 'package:sk_base_mobile/widgets/form_item/sk_text_input.dart'; import 'package:sk_base_mobile/widgets/empty.dart'; import 'package:sk_base_mobile/widgets/fade_in_cache_image.dart'; import 'package:sk_base_mobile/widgets/loading_indicator.dart'; import 'package:sk_base_mobile/widgets/core/sk_appbar.dart'; class HrManagePage extends StatelessWidget { final controller = Get.put(HrManageController()); HrManagePage({super.key}); @override Widget build(BuildContext context) { return GestureDetector( onTap: () { // 取消焦点 FocusScope.of(context).requestFocus(FocusNode()); }, child: Scaffold( appBar: const SkAppbar( backgroundColor: AppTheme.nearlyWhite, iconAndTextColor: AppTheme.black, title: '人事管理', ), body: buildBody(), )); } Widget buildBody() { return Column( children: [ buildSearchBar(), Expanded( child: Container( margin: EdgeInsets.symmetric( horizontal: ScreenAdaper.height(defaultPadding), ), child: Obx( () => controller.loading.value ? const LoadingIndicator(common: true) : SmartRefresher( enablePullDown: true, enablePullUp: true, controller: controller.refreshController, onLoading: controller.onLoading, onRefresh: controller.onRefresh, child: controller.list.isEmpty ? const Center( child: Empty(text: '暂无员工'), ) : ListView.builder( padding: EdgeInsets.symmetric( vertical: ScreenAdaper.height(defaultPadding)), itemBuilder: (context, index) { return buildUserCard(index); }, itemCount: controller.list.length, )), )), ) ], ); } Widget buildSearchBar() { final doSearch = debouncer((String value) { controller.searchKey.value = value; controller.onRefresh(); }, delayTime: 500); return Container( color: AppTheme.nearlyWhite, padding: EdgeInsets.all(ScreenAdaper.width(20)), child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: SizedBox( height: ScreenAdaper.height(70), child: SkTextInput( fillColor: AppTheme.inputFillColor, textController: controller.searchBarTextConroller, onChanged: (value) => doSearch(value), floatingLabelBehavior: FloatingLabelBehavior.never, border: OutlineInputBorder( borderSide: BorderSide.none, borderRadius: BorderRadius.circular(ScreenAdaper.sp(15))), prefix: Icon( Icons.search, color: AppTheme.nearlyBlack, size: ScreenAdaper.height(40), ), // 当searchBarController有值时不显示 suffixIcon: Obx(() => controller.searchKey.value.isEmpty ? const SizedBox() : IconButton( icon: const Icon(Icons.clear), onPressed: () { controller.searchKey.value = ''; controller.searchBarTextConroller.clear(); doSearch(''); }, )), hint: '查询员工 姓名、手机号、邮箱', isDense: true, contentPadding: EdgeInsets.symmetric(vertical: ScreenAdaper.height(10)), ), )), SizedBox( width: ScreenAdaper.width(10), ), buildFilterBtn() ]), ); } Widget buildFilterBtn() { return SkInk( border: Border.all(color: AppTheme.grey.withOpacity(0.8)), borderRadius: BorderRadius.circular(ScreenAdaper.sp(15)), onTap: () {}, child: SizedBox( width: ScreenAdaper.height(65), height: ScreenAdaper.height(65), child: Icon( Icons.filter_list_sharp, size: ScreenAdaper.height(50), ), ), ); } Widget buildUserCard(int index) { return SkInk( onTap: () { RouterUtil.toNamed(RouteConfig.employeeDetail, arguments: controller.list[index]); }, margin: EdgeInsets.only(bottom: ScreenAdaper.height(defaultPadding)), borderRadius: BorderRadius.circular(ScreenAdaper.sp(15)), child: Container( padding: EdgeInsets.symmetric( horizontal: ScreenAdaper.height(defaultPadding), vertical: ScreenAdaper.height(defaultPadding)), child: Column( children: [ Row( children: [ // 头像 SkAvatar(url: controller.list[index].avatar), SizedBox( width: ScreenAdaper.height(defaultPadding), ), // 中间信息 Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('${controller.list[index].nickname}', style: TextStyle( fontSize: ScreenAdaper.height(30), fontWeight: FontWeight.w600)), SizedBox( height: ScreenAdaper.height(5), ), // role Text('${controller.list[index].dept?.name}', style: TextStyle(color: AppTheme.grey)), SizedBox( height: ScreenAdaper.height(5), ), Container( child: Wrap( spacing: ScreenAdaper.height(5), runSpacing: ScreenAdaper.height(5), children: [ ...controller.list[index].roles.map((e) => SkTag( text: '${e.name}', color: AppTheme.primaryColorLight)) ], )), ], )), /// 右侧action /// 电话 buildActionButton( onTap: () { if (controller.list[index].phone == null) { SnackBarUtil().info('该员工没有录入手机号'); return; } DeviceUtil.callPhone(controller.list[index].phone!); }, icon: Icons.phone, ), SizedBox( width: ScreenAdaper.height(defaultPadding), ), /// 邮件 buildActionButton( onTap: () { if (controller.list[index].email == null) { SnackBarUtil().info('该员工没有录入邮箱'); return; } DeviceUtil.sendEmail(controller.list[index].email!); }, icon: Icons.email_outlined, ), SizedBox( width: ScreenAdaper.height(defaultPadding), ), /// 编辑 buildActionButton( onTap: () { ModalUtil.showGeneralDialog( content: EditUserInfo( userId: controller.list[index].id!, )).then((value) { Get.delete(); if (value != null) { controller.list[index] = value; } }); // Get.toNamed(RouteConfig.employeeDetail, // arguments: controller.list[index]); }, icon: Icons.edit, ) ], ), const Divider(), Row( children: [ Text( '工龄: ${SkDateUtil.howLongAgo(controller.list[index].createdAt!)}'), const Spacer(), const SkTag( text: '在职', color: Colors.green, ) ], ) ], ), ), ); } Widget buildActionButton({ required Function() onTap, required IconData icon, }) { return SkInk( onTap: onTap, border: Border.all(color: AppTheme.grey.withOpacity(0.8)), borderRadius: BorderRadius.circular(ScreenAdaper.sp(40)), child: Container( padding: EdgeInsets.all(ScreenAdaper.height(5)), child: Icon( icon, size: ScreenAdaper.height(40), ), ), ); } } class HrManageController extends GetxController { RxList list = RxList([]); RxString searchKey = ''.obs; final searchBarTextConroller = TextEditingController(); RefreshController refreshController = RefreshController(initialRefresh: false); int page = 1; int limit = 15; int total = 0; RxBool loading = false.obs; @override onReady() { super.onReady(); initData(); } initData() async { loading.value = true; try { await getData(isRefresh: true); } finally { loading.value = false; } } Future> getData({bool isRefresh = false}) async { if (isRefresh == true) { page = 1; } else { page++; } final res = await Api.getUsers({ 'page': page, 'pageSize': 15, 'keyword': searchKey.value, }); List newList = res.data!.items.map((e) => UserInfoModel.fromJson(e)).toList(); isRefresh == true ? list.assignAll(newList) : list.addAll(newList); return newList; } Future onRefresh() async { await getData(isRefresh: true).then((_) { refreshController.refreshCompleted(resetFooterState: true); }).catchError((_) { refreshController.refreshFailed(); }); } Future onLoading() async { await getData().then((_) { if (_.isEmpty) { refreshController.loadNoData(); } else { refreshController.loadComplete(); } }).catchError((_) { refreshController.loadFailed(); }); } }