diff --git a/assets/icon/icon_shot_face.jpg b/assets/icon/icon_shot_face.jpg new file mode 100644 index 0000000..0e1bcd5 Binary files /dev/null and b/assets/icon/icon_shot_face.jpg differ diff --git a/assets/icon/icon_shot_face_error_1.jpg b/assets/icon/icon_shot_face_error_1.jpg new file mode 100644 index 0000000..f1af0df Binary files /dev/null and b/assets/icon/icon_shot_face_error_1.jpg differ diff --git a/assets/icon/icon_shot_face_error_2.jpg b/assets/icon/icon_shot_face_error_2.jpg new file mode 100644 index 0000000..41ec13b Binary files /dev/null and b/assets/icon/icon_shot_face_error_2.jpg differ diff --git a/assets/icon/icon_shot_face_error_3.jpg b/assets/icon/icon_shot_face_error_3.jpg new file mode 100644 index 0000000..d2ab215 Binary files /dev/null and b/assets/icon/icon_shot_face_error_3.jpg differ diff --git a/lib/api/api_path.dart b/lib/api/api_path.dart index 5b3f4e4..3d80cfc 100644 --- a/lib/api/api_path.dart +++ b/lib/api/api_path.dart @@ -10,6 +10,7 @@ class ApiPath { static const String bindTeamStarCloudAccount = "/v1/team/bindStarCloudAccount"; static const String updateTeamInfo = "/v1/team/updateTeam"; static const String teamDetail = "/v1/team/detail"; + static const String teamPersonDetail = "/v1/team/personDetail"; static const String getInviteInfo = "/v1/team/getInviteInfo"; static const String getTeamInviteConfig = "/v1/team/teamApplyConfig"; static const String updateTeamInviteConfig = "/v1/team/teamPersonConfigUpdate"; @@ -18,4 +19,6 @@ class ApiPath { static const String roleList = "/v1/team/roleList"; static const String roleCreate = "/v1/team/roleCreate"; static const String createPerson = "/v1/team/personCreate"; + static const String updatePerson = "/v1/team/personUpdate"; + static const String personList = "/v1/team/personList"; } diff --git a/lib/api/model/team/request/edit_person_info_request.dart b/lib/api/model/team/request/edit_person_info_request.dart new file mode 100644 index 0000000..d3a41fd --- /dev/null +++ b/lib/api/model/team/request/edit_person_info_request.dart @@ -0,0 +1,81 @@ +class EditPersonInfoRequest { + String? personNo; + String? departNo; + String? personName; + bool? createUser; + String? phone; + int? sex; + String? position; + String? remark; + List? associateUsers; + int? limitType; + String? limitStartTime; + String? limitEndTime; + String? idCard; + List? roleIds; + bool? isSendSms; + bool? isConfirm; + String? jobNumber; + + EditPersonInfoRequest({ + this.personNo, + this.departNo, + this.personName, + this.createUser, + this.phone, + this.sex, + this.position, + this.remark, + this.associateUsers, + this.limitType, + this.limitStartTime, + this.limitEndTime, + this.idCard, + this.roleIds, + this.isSendSms, + this.isConfirm, + this.jobNumber, + }); + + EditPersonInfoRequest.fromJson(Map json) { + personNo = json['personNo'] as String?; + departNo = json['departNo'] as String?; + personName = json['personName'] as String?; + createUser = json['createUser'] as bool?; + phone = json['phone'] as String?; + sex = json['sex'] as int?; + position = json['position'] as String?; + remark = json['remark'] as String?; + associateUsers = json['associateUsers']?.cast(); + limitType = json['limitType'] as int?; + limitStartTime = json['limitStartTime'] as String?; + limitEndTime = json['limitEndTime'] as String?; + idCard = json['idCard'] as String?; + roleIds = json['roleIds']?.cast(); + isSendSms = json['isSendSms'] as bool?; + isConfirm = json['isConfirm'] as bool?; + jobNumber = json['jobNumber'] as String?; + } + + Map toJson() { + final Map data = {}; + if (personNo != null) data['personNo'] = personNo; + if (departNo != null) data['departNo'] = departNo; + if (personName != null) data['personName'] = personName; + if (createUser != null) data['createUser'] = createUser; + if (phone != null) data['phone'] = phone; + if (sex != null) data['sex'] = sex; + if (position != null) data['position'] = position; + if (remark != null) data['remark'] = remark; + if (associateUsers != null) data['associateUsers'] = associateUsers; + if (limitType != null) data['limitType'] = limitType; + if (limitStartTime != null) data['limitStartTime'] = limitStartTime; + if (limitEndTime != null) data['limitEndTime'] = limitEndTime; + if (idCard != null) data['idCard'] = idCard; + if (roleIds != null) data['roleIds'] = roleIds; + if (isSendSms != null) data['isSendSms'] = isSendSms; + if (isConfirm != null) data['isConfirm'] = isConfirm; + if (jobNumber != null) data['jobNumber'] = jobNumber; + return data; + } +} diff --git a/lib/api/model/team/request/pserson_list_request.dart b/lib/api/model/team/request/pserson_list_request.dart new file mode 100644 index 0000000..5df86f3 --- /dev/null +++ b/lib/api/model/team/request/pserson_list_request.dart @@ -0,0 +1,62 @@ +class PersonListRequest { + int? pageNo; + int? pageSize; + String? departNo; + String? personName; + String? phone; + int? state; + String? jobNumber; + String? cardNo; + bool? hasLeafDepart; + int? userState; + List? passPorts; + + PersonListRequest({ + this.pageNo, + this.pageSize, + this.departNo, + this.personName, + this.phone, + this.state, + this.jobNumber, + this.cardNo, + this.hasLeafDepart, + this.userState, + this.passPorts, + }); + + PersonListRequest.fromJson(Map json) { + pageNo = json['pageNo'] as int?; + pageSize = json['pageSize'] as int?; + departNo = json['departNo'] as String?; + personName = json['personName'] as String?; + phone = json['phone'] as String?; + state = json['state'] as int?; + jobNumber = json['jobNumber'] as String?; + cardNo = json['cardNo'] as String?; + hasLeafDepart = json['hasLeafDepart'] as bool?; + userState = json['userState'] as int?; + passPorts = json['passPorts']?.cast(); + } + + Map toJson() { + final Map data = {}; + if (pageNo != null) data['pageNo'] = pageNo; + if (pageSize != null) data['pageSize'] = pageSize; + if (departNo != null) data['departNo'] = departNo; + if (personName != null) data['personName'] = personName; + if (phone != null) data['phone'] = phone; + if (state != null) data['state'] = state; + if (jobNumber != null) data['jobNumber'] = jobNumber; + if (cardNo != null) data['cardNo'] = cardNo; + if (hasLeafDepart != null) data['hasLeafDepart'] = hasLeafDepart; + if (userState != null) data['userState'] = userState; + if (passPorts != null) data['passPorts'] = passPorts; + return data; + } + + @override + String toString() { + return 'PersonListRequest{pageNo: $pageNo, pageSize: $pageSize, departNo: $departNo, personName: $personName, phone: $phone, state: $state, jobNumber: $jobNumber, cardNo: $cardNo, hasLeafDepart: $hasLeafDepart, userState: $userState, passPorts: $passPorts}'; + } +} diff --git a/lib/api/model/team/response/depart_list_reponse.dart b/lib/api/model/team/response/depart_list_reponse.dart index 23c0dbd..4a5112d 100644 --- a/lib/api/model/team/response/depart_list_reponse.dart +++ b/lib/api/model/team/response/depart_list_reponse.dart @@ -31,8 +31,8 @@ class DepartListResponse { class DepartItem { final int? id; final String? teamNo; - final String? departNo; - final String? departName; + String? departNo; + String? departName; final int? parentId; final PersonItem? leader; final int? level; diff --git a/lib/api/model/team/response/person_details_response.dart b/lib/api/model/team/response/person_details_response.dart new file mode 100644 index 0000000..760e3a5 --- /dev/null +++ b/lib/api/model/team/response/person_details_response.dart @@ -0,0 +1,147 @@ +import 'package:starwork_flutter/api/model/team/response/role_list_response.dart'; + +class PersonDetailsResponse { + int? id; + String? teamNo; + String? departNo; + String? departName; + String? personNo; + String? personName; + int? jobNumber; + String? phone; + int? sex; + String? sexName; + String? pathName; + String? state; + int? userState; + bool? isSuper; + bool? isOperationUser; + String? position; + String? remark; + String? idCard; + List? associateUsers; + List? roleList; + int? limitType; + String? limitStartTime; + String? limitEndTime; + + PersonDetailsResponse({ + this.id, + this.teamNo, + this.departNo, + this.departName, + this.personNo, + this.personName, + this.jobNumber, + this.phone, + this.sex, + this.sexName, + this.pathName, + this.state, + this.userState, + this.isSuper, + this.isOperationUser, + this.position, + this.remark, + this.idCard, + this.associateUsers, + this.roleList, + this.limitType, + this.limitStartTime, + this.limitEndTime, + }); + + PersonDetailsResponse.fromJson(Map json) { + id = json['id'] as int?; + teamNo = json['teamNo'] as String?; + departNo = json['departNo'] as String?; + departName = json['departName'] as String?; + personNo = json['personNo'] as String?; + personName = json['personName'] as String?; + jobNumber = json['jobNumber'] as int?; + phone = json['phone'] as String?; + sex = json['sex'] as int?; + sexName = json['sexName'] as String?; + pathName = json['pathName'] as String?; + state = json['state'] as String?; + userState = json['userState'] as int?; + isSuper = json['isSuper'] as bool?; + isOperationUser = json['isOperationUser'] as bool?; + position = json['position'] as String?; + remark = json['remark'] as String?; + idCard = json['idCard'] as String?; + limitType = json['limitType'] as int?; // 添加这一行 + limitStartTime = json['limitStartTime'] as String?; // 添加这一行 + limitEndTime = json['limitEndTime'] as String?; // 添加这一行 + + if (json['associateUsers'] != null) { + associateUsers = []; + json['associateUsers'].forEach((v) { + associateUsers!.add(AssociateUser.fromJson(v as Map)); + }); + } + + if (json['roleList'] != null) { + roleList = []; + json['roleList'].forEach((v) { + roleList!.add(RoleListResponse.fromJson(v as Map)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['teamNo'] = teamNo; + data['departNo'] = departNo; + data['departName'] = departName; + data['personNo'] = personNo; + data['personName'] = personName; + data['jobNumber'] = jobNumber; + data['phone'] = phone; + data['sex'] = sex; + data['sexName'] = sexName; + data['pathName'] = pathName; + data['state'] = state; + data['userState'] = userState; + data['isSuper'] = isSuper; + data['isOperationUser'] = isOperationUser; + data['position'] = position; + data['remark'] = remark; + data['idCard'] = idCard; + data['limitType'] = limitType; // 添加这一行 + data['limitStartTime'] = limitStartTime; // 添加这一行 + data['limitEndTime'] = limitEndTime; // 添加这一行 + + if (associateUsers != null) { + data['associateUsers'] = associateUsers!.map((v) => v.toJson()).toList(); + } + + if (roleList != null) { + data['roleList'] = roleList!.map((v) => v.toJson()).toList(); + } + return data; + } +} + +class AssociateUser { + String? personNo; + String? personName; + String? avatarUrl; + + AssociateUser({this.personNo, this.personName, this.avatarUrl}); + + AssociateUser.fromJson(Map json) { + personNo = json['personNo'] as String?; + personName = json['personName'] as String?; + avatarUrl = json['avatarUrl'] as String?; + } + + Map toJson() { + final Map data = {}; + data['personNo'] = personNo; + data['personName'] = personName; + data['avatarUrl'] = avatarUrl; + return data; + } +} diff --git a/lib/api/model/team/response/person_list_response.dart b/lib/api/model/team/response/person_list_response.dart new file mode 100644 index 0000000..d82606b --- /dev/null +++ b/lib/api/model/team/response/person_list_response.dart @@ -0,0 +1,140 @@ +class PersonListResponse { + int? pageNo; + int? pageSize; + int? total; + int? pages; + List? list; + + PersonListResponse({ + this.pageNo, + this.pageSize, + this.total, + this.pages, + this.list, + }); + + + PersonListResponse.fromJson(Map json) { + pageNo = json['pageNo'] as int?; + pageSize = json['pageSize'] as int?; + total = json['total'] as int?; + pages = json['pages'] as int?; + + if (json['list'] != null) { + list = []; + json['list'].forEach((v) { + list!.add(PersonItem.fromJson(v as Map)); + }); + } + } + + Map toJson() { + final Map data = {}; + data['pageNo'] = pageNo; + data['pageSize'] = pageSize; + data['total'] = total; + data['pages'] = pages; + + if (list != null) { + data['list'] = list!.map((v) => v.toJson()).toList(); + } + + return data; + } + + @override + String toString() { + return 'PersonListResponse{pageNo: $pageNo, pageSize: $pageSize, total: $total, pages: $pages, list: $list}'; + } +} + +class PersonItem { + int? id; + String? teamNo; + String? departNo; + String? departName; + String? personNo; + String? personName; + int? jobNumber; + String? phone; + int? sex; + String? sexName; + String? pathName; + String? state; + int? userState; + int? faceCount; + int? fingerprintCount; + int? cardCount; + bool? isSuper; + bool? isOperationUser; + + PersonItem({ + this.id, + this.teamNo, + this.departNo, + this.departName, + this.personNo, + this.personName, + this.jobNumber, + this.phone, + this.sex, + this.sexName, + this.pathName, + this.state, + this.userState, + this.faceCount, + this.fingerprintCount, + this.cardCount, + this.isSuper, + this.isOperationUser, + }); + + PersonItem.fromJson(Map json) { + id = json['id'] as int?; + teamNo = json['teamNo'] as String?; + departNo = json['departNo'] as String?; + departName = json['departName'] as String?; + personNo = json['personNo'] as String?; + personName = json['personName'] as String?; + jobNumber = json['jobNumber'] as int?; + phone = json['phone'] as String?; + sex = json['sex'] as int?; + sexName = json['sexName'] as String?; + pathName = json['pathName'] as String?; + state = json['state'] as String?; + userState = json['userState'] as int?; + faceCount = json['faceCount'] as int?; + fingerprintCount = json['fingerprintCount'] as int?; + cardCount = json['cardCount'] as int?; + isSuper = json['isSuper'] as bool?; + isOperationUser = json['isOperationUser'] as bool?; + } + + Map toJson() { + final Map data = {}; + data['id'] = id; + data['teamNo'] = teamNo; + data['departNo'] = departNo; + data['departName'] = departName; + data['personNo'] = personNo; + data['personName'] = personName; + data['jobNumber'] = jobNumber; + data['phone'] = phone; + data['sex'] = sex; + data['sexName'] = sexName; + data['pathName'] = pathName; + data['state'] = state; + data['userState'] = userState; + data['faceCount'] = faceCount; + data['fingerprintCount'] = fingerprintCount; + data['cardCount'] = cardCount; + data['isSuper'] = isSuper; + data['isOperationUser'] = isOperationUser; + return data; + } + + @override + String toString() { + return 'PersonItem{id: $id, teamNo: $teamNo, departNo: $departNo, departName: $departName, personNo: $personNo, personName: $personName, jobNumber: $jobNumber, phone: $phone, sex: $sex, sexName: $sexName, pathName: $pathName, state: $state, userState: $userState, faceCount: $faceCount, fingerprintCount: $fingerprintCount, cardCount: $cardCount, isSuper: $isSuper, isOperationUser: $isOperationUser}'; + } +} diff --git a/lib/api/service/team_api_service.dart b/lib/api/service/team_api_service.dart index 424c673..1d42875 100644 --- a/lib/api/service/team_api_service.dart +++ b/lib/api/service/team_api_service.dart @@ -8,8 +8,10 @@ import 'package:starwork_flutter/api/model/team/request/create_new_depart_reques import 'package:starwork_flutter/api/model/team/request/create_new_person.dart'; import 'package:starwork_flutter/api/model/team/request/create_new_role_request.dart'; import 'package:starwork_flutter/api/model/team/request/create_team_request.dart'; +import 'package:starwork_flutter/api/model/team/request/edit_person_info_request.dart'; import 'package:starwork_flutter/api/model/team/request/get_depart_list_request.dart'; import 'package:starwork_flutter/api/model/team/request/invite_info_request.dart'; +import 'package:starwork_flutter/api/model/team/request/pserson_list_request.dart'; import 'package:starwork_flutter/api/model/team/request/role_list_request.dart'; import 'package:starwork_flutter/api/model/team/request/update_invite_parameter_config_request.dart'; import 'package:starwork_flutter/api/model/team/request/update_team_info_request.dart'; @@ -17,6 +19,8 @@ import 'package:starwork_flutter/api/model/team/response/all_team_list_response. import 'package:starwork_flutter/api/model/team/response/create_team_response.dart'; import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dart'; import 'package:starwork_flutter/api/model/team/response/invite_info_response.dart'; +import 'package:starwork_flutter/api/model/team/response/person_details_response.dart'; +import 'package:starwork_flutter/api/model/team/response/person_list_response.dart'; import 'package:starwork_flutter/api/model/team/response/role_list_response.dart'; import 'package:starwork_flutter/api/model/team/response/scene_info_response.dart'; import 'package:starwork_flutter/api/model/team/response/team_details_response.dart'; @@ -105,6 +109,17 @@ class TeamApiService { ); } + // 查询人员详情 + Future> requestPersonDetails({ + required String personNo, + }) { + return _api.makeRequest( + path: ApiPath.teamPersonDetail, + method: HttpConstant.post, + data: {"personNo": personNo}, + fromJson: (data) => PersonDetailsResponse.fromJson(data), + ); + } /// 获取邀请信息 Future> requestInviteInfo({ @@ -195,4 +210,29 @@ class TeamApiService { fromJson: (data) {}, ); } + + // 编辑人员信息 + Future> requestEditPersonInfo({ + required EditPersonInfoRequest request, + }) { + return _api.makeRequest( + path: ApiPath.updatePerson, + method: HttpConstant.post, + data: request.toJson(), + fromJson: (data) {}, + ); + } + + // 获取人员列表 + Future> requestPersonList({ + required PersonListRequest request, + }) { + return _api.makeRequest( + path: ApiPath.personList, + method: HttpConstant.post, + data: request.toJson(), + fromJson: (data) => PersonListResponse.fromJson(data), + ); + } + } diff --git a/lib/base/base_controller.dart b/lib/base/base_controller.dart index 8e3c94d..a67a0f2 100644 --- a/lib/base/base_controller.dart +++ b/lib/base/base_controller.dart @@ -66,6 +66,8 @@ class BaseController extends GetxController { if (EasyLoading.isShow) { EasyLoading.dismiss(); } + // 收起键盘 + FocusScope.of(Get.overlayContext!).unfocus(); super.onClose(); } diff --git a/lib/common/constant/app_images.dart b/lib/common/constant/app_images.dart index 55488d9..fbc0567 100644 --- a/lib/common/constant/app_images.dart +++ b/lib/common/constant/app_images.dart @@ -55,6 +55,10 @@ class AppImages{ static const String iconTableMenu = 'assets/icon/icon_table_menu.png'; static const String iconVip = 'assets/icon/icon_vip.png'; static const String defaultAvatar = 'assets/images/default_avatar.png'; + static const String iconShotFace = 'assets/icon/icon_shot_face.jpg'; + static const String iconShotFaceError1 = 'assets/icon/icon_shot_face_error_1.jpg'; + static const String iconShotFaceError2 = 'assets/icon/icon_shot_face_error_2.jpg'; + static const String iconShotFaceError3 = 'assets/icon/icon_shot_face_error_3.jpg'; static const String iconLockGroupItem = 'assets/icon/icon_lockGroup_item.png'; static const String iconLockTypeDoorLock = 'assets/icon/lockType_doorLock.png'; static const String iconFace = 'assets/icon/icon_face.jpg'; diff --git a/lib/common/constant/app_view_parameter_keys.dart b/lib/common/constant/app_view_parameter_keys.dart index 8ada631..709932c 100644 --- a/lib/common/constant/app_view_parameter_keys.dart +++ b/lib/common/constant/app_view_parameter_keys.dart @@ -4,8 +4,14 @@ class AppViewParameterKeys { static const String networkInfo = "networkInfo"; static const String teamInfo = "teamInfo"; static const String departItem = "departItem"; + static const String departNo = "departNo"; + static const String personItem = "personItem"; static const String isLongTerm = "isLongTerm"; static const String startDate = "startDate"; static const String endDate = "endDate"; + static const String viewType = "viewType"; + static const String edit = "edit"; + static const String add = "add"; + static const String roleList = "roleList"; } \ No newline at end of file diff --git a/lib/common/widgets/custom_cell_widget.dart b/lib/common/widgets/custom_cell_widget.dart index 1ea1e7f..52e0741 100644 --- a/lib/common/widgets/custom_cell_widget.dart +++ b/lib/common/widgets/custom_cell_widget.dart @@ -8,6 +8,7 @@ class CustomCellWidget extends StatelessWidget { super.key, required this.leftText, this.leftSubText, + this.leftWidget, this.leftIcon, this.rightWidget, this.onTap, @@ -17,6 +18,7 @@ class CustomCellWidget extends StatelessWidget { final String leftText; final String? leftSubText; final Icon? leftIcon; + final Widget? leftWidget; final Widget? rightWidget; final GestureTapCallback? onTap; final bool visible; // 控制是否显示 @@ -48,8 +50,9 @@ class CustomCellWidget extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ - if (leftIcon != null) leftIcon!, - if (leftIcon != null) SizedBox(width: 4.w), + if (leftWidget != null) leftWidget!, + if (leftWidget == null && leftIcon != null) leftIcon!, + if (leftWidget == null && leftIcon != null) SizedBox(width: 4.w), Expanded( child: Text( leftText, diff --git a/lib/common/widgets/custome_app_bar_wdiget.dart b/lib/common/widgets/custome_app_bar_wdiget.dart index 849aaa5..759de6a 100644 --- a/lib/common/widgets/custome_app_bar_wdiget.dart +++ b/lib/common/widgets/custome_app_bar_wdiget.dart @@ -55,6 +55,8 @@ class CustomAppBarWidget extends StatelessWidget implements PreferredSizeWidget centerTitle: false, backgroundColor: backgroundColor, elevation: elevation, + surfaceTintColor: Colors.transparent, // Material3 下控制表面颜色 + shadowColor: Colors.transparent, // 去掉阴影 ); } diff --git a/lib/routes/app_pages.dart b/lib/routes/app_pages.dart index a43dd0f..3b851b6 100644 --- a/lib/routes/app_pages.dart +++ b/lib/routes/app_pages.dart @@ -44,12 +44,24 @@ import 'package:starwork_flutter/views/team/addPerson/selectRole/select_role_bin import 'package:starwork_flutter/views/team/addPerson/selectRole/select_role_view.dart'; import 'package:starwork_flutter/views/team/addRole/add_role_binding.dart'; import 'package:starwork_flutter/views/team/addRole/add_role_view.dart'; +import 'package:starwork_flutter/views/team/editPerson/edit_person_binding.dart'; +import 'package:starwork_flutter/views/team/editPerson/edit_person_view.dart'; +import 'package:starwork_flutter/views/team/editPerson/personInfo/person_info_binding.dart'; +import 'package:starwork_flutter/views/team/editPerson/personInfo/person_info_view.dart'; +import 'package:starwork_flutter/views/team/enterFace/enter_face_binding.dart'; +import 'package:starwork_flutter/views/team/enterFace/enter_face_view.dart'; +import 'package:starwork_flutter/views/team/faceAudit/face_audit_binding.dart'; +import 'package:starwork_flutter/views/team/faceAudit/face_audit_view.dart'; +import 'package:starwork_flutter/views/team/faceInfo/face_info_binding.dart'; +import 'package:starwork_flutter/views/team/faceInfo/face_info_view.dart'; import 'package:starwork_flutter/views/team/inviteTeamMember/invitationSettings/invitation_settings_binding.dart'; import 'package:starwork_flutter/views/team/inviteTeamMember/invitationSettings/invitation_settings_view.dart'; import 'package:starwork_flutter/views/team/inviteTeamMember/invite_team_member_binding.dart'; import 'package:starwork_flutter/views/team/inviteTeamMember/invite_team_member_view.dart'; import 'package:starwork_flutter/views/team/joinTeam/join_team_binding.dart'; import 'package:starwork_flutter/views/team/joinTeam/join_team_view.dart'; +import 'package:starwork_flutter/views/team/newPersonAuditing/new_person_auditing_binding.dart'; +import 'package:starwork_flutter/views/team/newPersonAuditing/new_person_auditing_view.dart'; import 'package:starwork_flutter/views/team/personnelManage/personnel_manage_binding.dart'; import 'package:starwork_flutter/views/team/personnelManage/personnel_manage_view.dart'; import 'package:starwork_flutter/views/team/roleManage/role_manage_binding.dart'; @@ -263,5 +275,34 @@ class AppPages { page: () => SelectPersonView(), binding: SelectPersonBinding(), ), + GetPage( + name: AppRoutes.teamEditPerson, + page: () => EditPersonView(), + binding: EditPersonBinding(), + ), + GetPage( + name: AppRoutes.teamEditPersonInfo, + page: () => PersonInfoView(), + binding: PersonInfoBinding(), + ), + GetPage( + name: AppRoutes.teamFaceInfo, + page: () => FaceInfoView(), + binding: FaceInfoBinding(), + ), + GetPage( + name: AppRoutes.teamFaceAudit, + page: () => FaceAuditView(), + binding: FaceAuditBinding(), + ), + GetPage( + name: AppRoutes.teamEnterFace, + page: () => EnterFaceView(), + binding: EnterFaceBinding(), + ),GetPage( + name: AppRoutes.teamNewPersonAuditing, + page: () => NewPersonAuditingView(), + binding: NewPersonAuditingBinding(), + ), ]; } diff --git a/lib/routes/app_routes.dart b/lib/routes/app_routes.dart index 4b19782..bd44c5c 100644 --- a/lib/routes/app_routes.dart +++ b/lib/routes/app_routes.dart @@ -25,7 +25,13 @@ class AppRoutes{ static const String teamAddRole = '/team/addRole'; static const String teamSelectRole = '/team/selectRole'; static const String teamAddPersonEditValidity = '/team/addPerson/editValidity'; + static const String teamEditPerson = '/team/editPerson'; + static const String teamEditPersonInfo = '/team/editPerson/personInfo'; static const String teamAddOrganization = '/team/addOrganization'; + static const String teamFaceInfo = '/team/faceInfo'; + static const String teamFaceAudit = '/team/faceAudit'; + static const String teamEnterFace = '/team/enterFace'; + static const String teamNewPersonAuditing = '/team/newPersonAuditing'; static const String deviceManage = '/device/deviceManage'; static const String searchDevice = '/device/searchDevice'; static const String confirmPairDevice = '/device/confirmPairDevice'; diff --git a/lib/views/accessControlManage/access_control_manage_view.dart b/lib/views/accessControlManage/access_control_manage_view.dart index 19c27a2..bd31b64 100644 --- a/lib/views/accessControlManage/access_control_manage_view.dart +++ b/lib/views/accessControlManage/access_control_manage_view.dart @@ -30,6 +30,10 @@ class AccessControlManageView extends GetView { // 多于3个时建议 fixed selectedFontSize: 12.sp, unselectedFontSize: 12.sp, + // 选中时的颜色 + fixedColor: Colors.blue, + // 未选中时的颜色 + unselectedItemColor: Colors.grey, ), ), ); diff --git a/lib/views/main/main_controller.dart b/lib/views/main/main_controller.dart index f47384f..1d6ffbd 100644 --- a/lib/views/main/main_controller.dart +++ b/lib/views/main/main_controller.dart @@ -64,8 +64,7 @@ class MainController extends BaseController { late StreamSubscription _refreshDeviceListSubscription; @override - void onReady() { - super.onReady(); + void onInit() { /// 请求团队信息 requestAllTeamInfoList(); @@ -75,6 +74,8 @@ class MainController extends BaseController { /// 请求账户信息 requestUserAccountInfo(); + super.onInit(); + // 监听刷新设备列表事件 _refreshDeviceListSubscription = EventBusUtil().instance.on().listen((event) { _requestTeamDeviceList(); diff --git a/lib/views/main/main_view.dart b/lib/views/main/main_view.dart index b401e7a..3ab267e 100644 --- a/lib/views/main/main_view.dart +++ b/lib/views/main/main_view.dart @@ -31,6 +31,10 @@ class MainView extends GetView { // 多于3个时建议 fixed selectedFontSize: 12.sp, unselectedFontSize: 12.sp, + // 选中时的颜色 + fixedColor: Colors.blue, + // 未选中时的颜色 + unselectedItemColor: Colors.grey, ), ), drawer: Obx( diff --git a/lib/views/team/addPerson/add_person_view.dart b/lib/views/team/addPerson/add_person_view.dart index be4b987..df596a3 100644 --- a/lib/views/team/addPerson/add_person_view.dart +++ b/lib/views/team/addPerson/add_person_view.dart @@ -191,8 +191,13 @@ class AddPersonView extends GetView { ), CustomCellWidget( onTap: () async { - var result = - await Get.toNamed(AppRoutes.teamSelectRole, arguments: controller.selectedRoles); + var result = await Get.toNamed( + AppRoutes.teamSelectRole, + arguments: { + AppViewParameterKeys.viewType: AppViewParameterKeys.add, + AppViewParameterKeys.roleList: controller.selectedRoles + }, + ); if (result != null) { // 处理返回的角色数据 if (result is List) { diff --git a/lib/views/team/addPerson/selectRole/select_role_controller.dart b/lib/views/team/addPerson/selectRole/select_role_controller.dart index 01a58fd..57030a2 100644 --- a/lib/views/team/addPerson/selectRole/select_role_controller.dart +++ b/lib/views/team/addPerson/selectRole/select_role_controller.dart @@ -1,25 +1,48 @@ import 'package:get/get.dart'; +import 'package:starwork_flutter/api/model/team/request/edit_person_info_request.dart'; +import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dart'; import 'package:starwork_flutter/api/model/team/response/role_list_response.dart'; import 'package:starwork_flutter/api/service/team_api_service.dart'; import 'package:starwork_flutter/base/app_logger.dart'; import 'package:starwork_flutter/base/base_controller.dart'; +import 'package:starwork_flutter/common/constant/app_view_parameter_keys.dart'; class SelectRoleController extends BaseController { final teamApi = Get.find(); var roleList = [].obs; - var selectRoleIndexList = [].obs; + var selectRoleIdList = [].obs; + var selectedDepartNo = ''.obs; // 当前选中的组织 + + var viewType = ''.obs; // 存储从参数传递过来的已选角色 List? initialSelectedRoles; + final selectedPersonItem = Rx(null); @override void onInit() { super.onInit(); // 获取传递的参数 var arguments = Get.arguments; - if (arguments != null && arguments is List) { - initialSelectedRoles = arguments; + if (arguments != null && arguments is Map) { + // 从Map中提取角色列表 + var roleListArg = arguments[AppViewParameterKeys.roleList]; + + viewType.value = arguments[AppViewParameterKeys.viewType] ?? ''; + if (roleListArg != null && roleListArg is RxList) { + initialSelectedRoles = roleListArg; + } + if (viewType.value == AppViewParameterKeys.edit) { + var departNo = arguments[AppViewParameterKeys.departNo]; + var personItem = arguments[AppViewParameterKeys.personItem]; + if (departNo != null && departNo is String) { + selectedDepartNo.value = departNo; + } + if (personItem != null && personItem is PersonItem) { + selectedPersonItem.value = personItem; + } + } } requestRoleList(); } @@ -45,14 +68,30 @@ class SelectRoleController extends BaseController { // 在角色列表中查找对应的角色并设置选中状态 for (int i = 0; i < roleList.length; i++) { if (roleList[i].id == selectedRole.id) { - if (!selectRoleIndexList.contains(i)) { - selectRoleIndexList.add(i); + if (!selectRoleIdList.contains(selectedRole.id)) { + selectRoleIdList.add(selectedRole.id!); } break; } } } } - selectRoleIndexList.refresh(); + selectRoleIdList.refresh(); + } + + void requestEditRoles() async { + var response = await teamApi.requestEditPersonInfo( + request: EditPersonInfoRequest( + roleIds: selectRoleIdList, + departNo: selectedDepartNo.value, + personName: selectedPersonItem.value?.personName, + personNo: selectedPersonItem.value?.personNo, + ), + ); + if (response.isSuccess) { + showSuccess(); + } else { + showError(message: response.errorMsg!); + } } } diff --git a/lib/views/team/addPerson/selectRole/select_role_view.dart b/lib/views/team/addPerson/selectRole/select_role_view.dart index 9c1a8b5..6c66fd8 100644 --- a/lib/views/team/addPerson/selectRole/select_role_view.dart +++ b/lib/views/team/addPerson/selectRole/select_role_view.dart @@ -6,6 +6,7 @@ import 'package:get/get.dart'; import 'package:starwork_flutter/api/model/team/response/role_list_response.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_view_parameter_keys.dart'; import 'package:starwork_flutter/common/widgets/custome_app_bar_wdiget.dart'; import 'package:starwork_flutter/extension/function_extension.dart'; import 'package:starwork_flutter/routes/app_routes.dart'; @@ -97,12 +98,12 @@ class SelectRoleView extends GetView { return GestureDetector( onTap: () { // 避免重复添加 - if (!controller.selectRoleIndexList.contains(index)) { - controller.selectRoleIndexList.add(index); + if (!controller.selectRoleIdList.contains(roleList.id)) { + controller.selectRoleIdList.add(roleList.id!); } else { - controller.selectRoleIndexList.remove(index); + controller.selectRoleIdList.remove(roleList.id); } - controller.selectRoleIndexList.refresh(); + controller.selectRoleIdList.refresh(); }, child: Padding( padding: EdgeInsets.symmetric( @@ -113,18 +114,18 @@ class SelectRoleView extends GetView { children: [ Obx( () => Checkbox( - value: controller.selectRoleIndexList.contains(index), + value: controller.selectRoleIdList.contains(roleList.id), activeColor: Colors.blue, onChanged: (value) { if (value == true) { // 避免重复添加 - if (!controller.selectRoleIndexList.contains(index)) { - controller.selectRoleIndexList.add(index); + if (!controller.selectRoleIdList.contains(roleList.id)) { + controller.selectRoleIdList.add(roleList.id!); } } else { - controller.selectRoleIndexList.remove(index); + controller.selectRoleIdList.remove(roleList.id); } - controller.selectRoleIndexList.refresh(); + controller.selectRoleIdList.refresh(); }, ), ), @@ -196,7 +197,7 @@ class SelectRoleView extends GetView { children: [ Obx( () => Text( - '已选中:${controller.selectRoleIndexList.length}个', + '已选中:${controller.selectRoleIdList.length}个', style: TextStyle( fontSize: 14.sp, color: Colors.grey, @@ -205,9 +206,13 @@ class SelectRoleView extends GetView { ), ElevatedButton( onPressed: () { - Get.back( - result: controller.selectRoleIndexList.map((e) => controller.roleList[e]).toList(), - ); + if (controller.viewType.value == AppViewParameterKeys.add) { + Get.back( + result: controller.selectRoleIdList.map((e) => controller.roleList[e]).toList(), + ); + } else if (controller.viewType.value == AppViewParameterKeys.edit) { + controller.requestEditRoles(); + } }.debounce(), style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, diff --git a/lib/views/team/editPerson/edit_person_binding.dart b/lib/views/team/editPerson/edit_person_binding.dart new file mode 100644 index 0000000..b9b3e04 --- /dev/null +++ b/lib/views/team/editPerson/edit_person_binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; + +import 'edit_person_controller.dart'; + +class EditPersonBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => EditPersonController()); + } +} \ No newline at end of file diff --git a/lib/views/team/editPerson/edit_person_controller.dart b/lib/views/team/editPerson/edit_person_controller.dart new file mode 100644 index 0000000..a64e552 --- /dev/null +++ b/lib/views/team/editPerson/edit_person_controller.dart @@ -0,0 +1,201 @@ +import 'package:flutter/widgets.dart'; +import 'package:get/get.dart'; +import 'package:starwork_flutter/api/model/team/request/edit_person_info_request.dart'; +import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dart'; +import 'package:starwork_flutter/api/model/team/response/person_details_response.dart'; +import 'package:starwork_flutter/api/model/team/response/role_list_response.dart'; +import 'package:starwork_flutter/api/service/team_api_service.dart'; +import 'package:starwork_flutter/base/app_logger.dart'; +import 'package:starwork_flutter/base/base_controller.dart'; +import 'package:starwork_flutter/common/constant/app_view_parameter_keys.dart'; + +class EditPersonController extends BaseController { + final selectedPersonItem = Rx(null); + RxString selectedGender = 'male'.obs; + final teamApi = Get.find(); + var selectedDepartItem = DepartItem().obs; // 当前选中的组织 + + var originalPersonData = Rx(null); // 人员原始的详情数据 + + TextEditingController nameInputController = TextEditingController(); + TextEditingController phoneInputController = TextEditingController(); + TextEditingController jobNoInputController = TextEditingController(); // 工号 + TextEditingController positionInputController = TextEditingController(); // 职务 + TextEditingController idCardInputController = TextEditingController(); // 身份证号码 + TextEditingController remarkInputController = TextEditingController(); // 备注 + var isLongTerm = true.obs; // 有效期是否为长期 + var startDate = 0.obs; // 使用时间戳表示开始时间 + var endDate = 0.obs; // 使用时间戳表示结束时间 + var userState = 0.obs; // 账号状态 + var selectedRoles = [].obs; + var isPhoneVisible = false.obs; // 控制手机号是否可见 + + @override + void onInit() async { + super.onInit(); + final args = Get.arguments; + if (args != null && args is PersonItem) { + selectedPersonItem.value = args; + } + + await requestPersonDetail(); + } + + requestPersonDetail() async { + if (selectedPersonItem.value != null && selectedPersonItem.value!.personNo != null) { + var response = await teamApi.requestPersonDetails(personNo: selectedPersonItem.value!.personNo!); + if (response.isSuccess) { + var data = response.data; + // 保存原始数据 + originalPersonData.value = data; + + nameInputController.text = data?.personName ?? ''; + phoneInputController.text = data?.phone ?? ''; + jobNoInputController.text = data?.jobNumber.toString() ?? ''; + positionInputController.text = data?.position ?? ''; + idCardInputController.text = data?.idCard ?? ''; + remarkInputController.text = data?.remark ?? ''; + selectedGender.value = data?.sex == 1 ? 'male' : 'female'; + isLongTerm.value = data?.limitType == 1; + startDate.value = _parseDateStringToTimestamp(data?.limitStartTime); + endDate.value = _parseDateStringToTimestamp(data?.limitEndTime); + userState.value = data?.userState ?? 2; + selectedRoles.value = data?.roleList ?? []; + selectedDepartItem.value.departNo = data?.departNo; + selectedDepartItem.value.departName = data?.departName; + selectedDepartItem.refresh(); + selectedRoles.refresh(); + } + } + } + + // 获取选中角色的显示文本 + String getSelectedRoleDisplayText() { + if (selectedRoles.isEmpty) { + return '请选择'; // 如果没有选中角色,显示"请选择" + } else { + // 将所有选中角色的名称用逗号连接 + return selectedRoles.map((role) => role.roleName ?? '').join('、'); // 使用顿号或逗号分隔 + } + } + + // 手机号脱敏处理方法 + String maskPhoneNumber(String? phone) { + if (phone == null || phone.isEmpty) return ''; + if (phone.length < 11) return phone; + + // 只显示前3位和后3位,中间5位用*代替 + return '${phone.substring(0, 3)}*****${phone.substring(8)}'; + } + + // 获取显示用的手机号(根据可见性决定是否脱敏) + String getDisplayPhone() { + final phone = selectedPersonItem.value?.phone ?? ''; + return isPhoneVisible.value ? phone : maskPhoneNumber(phone); + } + + // 辅助方法:将时间戳转换为日期字符串 + String formatTimestamp(int timestamp) { + if (timestamp <= 0) return '请选择'; + try { + final dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp); + return '${dateTime.year}-${dateTime.month.toString().padLeft(2, '0')}-${dateTime.day.toString().padLeft(2, '0')}'; + } catch (e) { + return '请选择'; + } + } + + // 将字符串日期转为时间戳 + int _parseDateStringToTimestamp(String? dateStr) { + if (dateStr == null || dateStr.isEmpty) return 0; + try { + // 假设日期格式为 "yyyy-MM-dd" 或其他标准格式 + final DateTime dateTime = DateTime.parse(dateStr); + return dateTime.millisecondsSinceEpoch; + } catch (e) { + // 如果解析失败,返回0 + return 0; + } + } + + void requestEditPersonInfo() async { + // 先检查是否有数据变更 + if (!_hasDataChanged()) { + AppLogger.debug('数据无变更,无需修改'); + return; + } + // 构建只包含变更字段的请求对象 + var request = EditPersonInfoRequest(); + request.personNo = selectedPersonItem.value?.personNo; + request.isConfirm = true; + + if (phoneInputController.text.trim() != (originalPersonData.value?.phone ?? '')) { + request.phone = phoneInputController.text.trim(); + } + + request.departNo = selectedDepartItem.value.departNo; + request.personName = nameInputController.text.trim(); + + if (selectedGender.value != (originalPersonData.value?.sex == 1 ? 'male' : 'female')) { + request.sex = selectedGender.value == 'male' ? 1 : 2; + } + + if (positionInputController.text.trim() != (originalPersonData.value?.position ?? '')) { + request.position = positionInputController.text.trim(); + } + + if (remarkInputController.text.trim() != (originalPersonData.value?.remark ?? '')) { + request.remark = remarkInputController.text.trim(); + } + + if (idCardInputController.text.trim() != (originalPersonData.value?.idCard ?? '')) { + request.idCard = idCardInputController.text.trim(); + } + + if (jobNoInputController.text.trim() != (originalPersonData.value?.jobNumber?.toString() ?? '')) { + request.jobNumber = jobNoInputController.text.trim(); + } + + if (isLongTerm.value != (originalPersonData.value?.limitType == 1)) { + request.limitType = isLongTerm.value ? 1 : 2; + } + + // 处理有效期时间字段 + if (!isLongTerm.value) { + var originalStartTime = _parseDateStringToTimestamp(originalPersonData.value?.limitStartTime); + var originalEndTime = _parseDateStringToTimestamp(originalPersonData.value?.limitEndTime); + + if (startDate.value != originalStartTime) { + request.limitStartTime = formatTimestamp(startDate.value); + } + + if (endDate.value != originalEndTime) { + request.limitEndTime = formatTimestamp(endDate.value); + } + } + var response = await teamApi.requestEditPersonInfo(request: request); + if (response.isSuccess) { + showSuccess(); + } else { + showError(message: response.errorMsg!); + } + } + + // 3. 创建比较方法判断是否有修改 + bool _hasDataChanged() { + if (originalPersonData.value == null) return true; + + return nameInputController.text.trim() != (originalPersonData.value?.personName ?? '') || + phoneInputController.text.trim() != (originalPersonData.value?.phone ?? '') || + jobNoInputController.text.trim() != (originalPersonData.value?.jobNumber?.toString() ?? '') || + positionInputController.text.trim() != (originalPersonData.value?.position ?? '') || + idCardInputController.text.trim() != (originalPersonData.value?.idCard ?? '') || + remarkInputController.text.trim() != (originalPersonData.value?.remark ?? '') || + selectedGender.value != (originalPersonData.value?.sex == 1 ? 'male' : 'female') || + selectedDepartItem.value.departNo != originalPersonData.value?.departNo || + isLongTerm.value != (originalPersonData.value?.limitType == 1) || + (!isLongTerm.value && + (startDate.value != _parseDateStringToTimestamp(originalPersonData.value?.limitStartTime) || + endDate.value != _parseDateStringToTimestamp(originalPersonData.value?.limitEndTime))); + } +} diff --git a/lib/views/team/editPerson/edit_person_view.dart b/lib/views/team/editPerson/edit_person_view.dart new file mode 100644 index 0000000..5316ee5 --- /dev/null +++ b/lib/views/team/editPerson/edit_person_view.dart @@ -0,0 +1,652 @@ +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/api/model/team/response/role_list_response.dart'; +import 'package:starwork_flutter/common/constant/app_colors.dart'; +import 'package:starwork_flutter/common/constant/app_view_parameter_keys.dart'; +import 'package:starwork_flutter/common/widgets/custom_cell_list_widget.dart'; +import 'package:starwork_flutter/common/widgets/custom_cell_widget.dart'; +import 'package:starwork_flutter/common/widgets/custome_app_bar_wdiget.dart'; +import 'package:starwork_flutter/extension/function_extension.dart'; +import 'package:starwork_flutter/routes/app_routes.dart'; +import 'edit_person_controller.dart'; + +class EditPersonView extends GetView { + @override + Widget build(BuildContext context) { + // 即使不使用,只是引用一下 controller 就能触发初始化 + final _ = controller; // 添加这一行 + return Scaffold( + appBar: CustomAppBarWidget( + title: '编辑人员'.tr, + backgroundColor: AppColors.scaffoldBackgroundColor, + ), + backgroundColor: AppColors.scaffoldBackgroundColor, + body: SafeArea( + child: SingleChildScrollView( + child: Padding( + padding: EdgeInsets.only( + left: 10.w, + right: 10.w, + bottom: 10.h, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '基本信息'.tr, + style: TextStyle( + fontSize: 12.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + SizedBox( + height: 6.h, + ), + CustomCellListWidget( + children: [ + CustomCellWidget( + onTap: () async { + final result = await Get.toNamed(AppRoutes.teamSelectOrganization); + if (result != null && result is DepartItem) { + controller.selectedDepartItem.value = result; + controller.selectedDepartItem.refresh(); + } + }, + leftText: '组织'.tr, + leftIcon: Icon( + Icons.circle, + size: 4.w, + color: Colors.red, + ), + rightWidget: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Obx( + () => Text( + controller.selectedDepartItem.value.departName ?? '请选择', + style: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + ), + SizedBox( + width: 4.w, + ), + Icon( + Icons.arrow_forward_ios_rounded, + size: 16.sp, + color: Colors.grey[300], + ) + ], + ), + ), + CustomCellWidget( + onTap: () {}, + leftText: '姓名'.tr, + leftIcon: Icon( + Icons.circle, + size: 4.w, + color: Colors.red, + ), + rightWidget: Expanded( + flex: 3, + child: TextField( + controller: controller.nameInputController, + keyboardType: TextInputType.text, + textInputAction: TextInputAction.next, + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 14.sp, + ), + decoration: InputDecoration( + isCollapsed: true, + hintText: '请输入姓名'.tr, + hintStyle: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + // 设置无边框 + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + // 获取焦点时的边框 + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + ), + ), + ), + CustomCellWidget( + onTap: () {}, + leftText: '手机号'.tr, + rightWidget: controller.phoneInputController.text.isNotEmpty + ? Row( + children: [ + Text( + controller.getDisplayPhone(), + style: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + SizedBox( + width: 10.w, + ), + GestureDetector( + onTap: () { + controller.isPhoneVisible.value = !controller.isPhoneVisible.value; + }, + child: Icon( + controller.isPhoneVisible.value ? Icons.visibility : Icons.visibility_off, + size: 16.sp, + color: Colors.grey, + ), + ), + ], + ) + : Expanded( + flex: 3, + child: TextField( + controller: controller.phoneInputController, + keyboardType: TextInputType.number, + textInputAction: TextInputAction.next, + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 14.sp, + ), + decoration: InputDecoration( + isCollapsed: true, + hintText: '请输入手机号'.tr, + hintStyle: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + // 设置无边框 + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + // 获取焦点时的边框 + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + ), + ), + ), + CustomCellWidget( + onTap: () { + Get.toNamed(AppRoutes.teamEditPersonInfo); + }, + leftText: '用户账号'.tr, + rightWidget: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Obx( + () => Text( + controller.userState.value == 1 + ? '已开通' + : controller.userState.value == 2 + ? '未开通' + : '已停用', + style: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + ), + SizedBox( + width: 4.w, + ), + Icon( + Icons.arrow_forward_ios_rounded, + size: 16.sp, + color: Colors.grey[300], + ) + ], + ), + ), + ], + ), + SizedBox( + height: 10.h, + ), + Text( + '凭证信息'.tr, + style: TextStyle( + fontSize: 12.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + SizedBox( + height: 10.h, + ), + SizedBox( + height: 68.w, + child: ListView( + scrollDirection: Axis.horizontal, + children: [ + _buildHorizontalItem(title: '人脸', count: 0), + SizedBox(width: 5.w), // 添加间距 + _buildHorizontalItem(title: '指纹', count: 0), + SizedBox(width: 5.w), // 添加间距 + _buildHorizontalItem(title: '卡片', count: 0), + SizedBox(width: 5.w), // 添加间距 + _buildHorizontalItem(title: '密码', count: 0), + ], + ), + ), + SizedBox( + height: 10.h, + ), + Text( + '扩展信息'.tr, + style: TextStyle( + fontSize: 12.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + SizedBox( + height: 10.h, + ), + CustomCellListWidget( + children: [ + CustomCellWidget( + onTap: () {}, + leftText: '工号'.tr, + rightWidget: Expanded( + flex: 3, + child: TextField( + controller: controller.jobNoInputController, + keyboardType: TextInputType.text, + textInputAction: TextInputAction.next, + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 14.sp, + ), + decoration: InputDecoration( + isCollapsed: true, + hintText: '选填'.tr, + hintStyle: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + // 设置无边框 + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + // 获取焦点时的边框 + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + ), + ), + ), + CustomCellWidget( + onTap: () {}, + leftText: '性别'.tr, + rightWidget: Obx( + () => Row( + children: [ + Radio( + value: 'male', + activeColor: Colors.blue, + groupValue: controller.selectedGender.value, + visualDensity: VisualDensity.compact, + onChanged: (value) { + controller.selectedGender.value = value!; + }, + ), + Text('男'), + Radio( + value: 'female', + activeColor: Colors.blue, + groupValue: controller.selectedGender.value, + visualDensity: VisualDensity.compact, + onChanged: (value) { + controller.selectedGender.value = value!; + }, + ), + Text('女'), + ], + ), + ), + ), + CustomCellWidget( + onTap: () async { + var result = await Get.toNamed(AppRoutes.teamAddPersonEditValidity, arguments: { + AppViewParameterKeys.isLongTerm: controller.isLongTerm.value, + AppViewParameterKeys.startDate: controller.startDate.value, + AppViewParameterKeys.endDate: controller.endDate.value, + }); + if (result != null) { + controller.isLongTerm.value = result[AppViewParameterKeys.isLongTerm]; + if (controller.isLongTerm.isFalse) { + controller.startDate.value = result[AppViewParameterKeys.startDate]; + controller.endDate.value = result[AppViewParameterKeys.endDate]; + } + } + }, + leftText: '有效期'.tr, + rightWidget: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Obx( + () => Text( + controller.isLongTerm.value + ? '长期'.tr + : '${controller.formatTimestamp(controller.startDate.value)} - ' + '${controller.formatTimestamp(controller.endDate.value)}', + style: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + ), + SizedBox( + width: 4.w, + ), + Icon( + Icons.arrow_forward_ios_rounded, + size: 16.sp, + color: Colors.grey[300], + ) + ], + ), + ), + CustomCellWidget( + onTap: () {}, + leftText: '职务'.tr, + rightWidget: Expanded( + flex: 3, + child: TextField( + controller: controller.positionInputController, + keyboardType: TextInputType.text, + textInputAction: TextInputAction.next, + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 14.sp, + ), + decoration: InputDecoration( + isCollapsed: true, + hintText: '选填'.tr, + hintStyle: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + // 设置无边框 + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + // 获取焦点时的边框 + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + ), + ), + ), + CustomCellWidget( + onTap: () {}, + leftText: '备注'.tr, + rightWidget: Expanded( + flex: 3, + child: TextField( + controller: controller.remarkInputController, + keyboardType: TextInputType.text, + textInputAction: TextInputAction.next, + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 14.sp, + ), + decoration: InputDecoration( + isCollapsed: true, + hintText: '选填'.tr, + hintStyle: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + // 设置无边框 + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + // 获取焦点时的边框 + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + ), + ), + ), + CustomCellWidget( + onTap: () {}, + leftText: '身份证号码'.tr, + rightWidget: Expanded( + flex: 3, + child: TextField( + controller: controller.idCardInputController, + keyboardType: TextInputType.text, + textInputAction: TextInputAction.next, + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 14.sp, + ), + decoration: InputDecoration( + isCollapsed: true, + hintText: '选填'.tr, + hintStyle: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + // 设置无边框 + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + // 获取焦点时的边框 + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + ), + ), + ), + CustomCellWidget( + onTap: () async {}, + leftText: '关联用户'.tr, + rightWidget: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + '关联用户', + style: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + SizedBox( + width: 4.w, + ), + Icon( + Icons.arrow_forward_ios_rounded, + size: 16.sp, + color: Colors.grey[300], + ) + ], + ), + ), + CustomCellWidget( + onTap: () async {}, + leftText: '人员ID'.tr, + rightWidget: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Obx( + () => Text( + controller.selectedPersonItem.value?.personNo ?? '', + style: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + ), + ], + ), + ) + ], + ), + ], + ), + SizedBox( + height: 10.h, + ), + Column( + children: [ + SizedBox( + width: double.infinity, + child: Row( + children: [ + Obx( + () => Visibility( + visible: controller.selectedPersonItem.value!.phone!.isEmpty, + child: Expanded( + child: ElevatedButton( + onPressed: () {}.debounce(), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.grey[100], + padding: EdgeInsets.symmetric(vertical: 12.h), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + ), + ), + child: Text( + '开通用户账号'.tr, + style: TextStyle( + fontSize: 16.sp, + color: Colors.blue, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ), + ), + SizedBox( + width: 10.w, + ), + Expanded( + child: ElevatedButton( + onPressed: () {}.debounce(), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.grey[100], + padding: EdgeInsets.symmetric(vertical: 12.h), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + ), + ), + child: Text( + '删除'.tr, + style: TextStyle( + fontSize: 16.sp, + color: Colors.blue, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + SizedBox( + width: 10.w, + ), + Expanded( + child: ElevatedButton( + onPressed: () { + controller.requestEditPersonInfo(); + }.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, + ), + ), + ), + ), + ], + ), + ), + ], + ) + ], + ), + ), + ), + ), + ); + } + + _buildHorizontalItem({ + required String title, + required int count, + }) { + return Container( + width: 88.w, + height: 44.w, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.r), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + count.toString(), + style: TextStyle( + fontSize: 22.sp, + fontWeight: FontWeight.w600, + ), + ), + SizedBox( + height: 2.h, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: TextStyle( + fontSize: 12.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + Icon( + Icons.arrow_forward_ios_rounded, + size: 12.sp, + color: Colors.black54, + ) + ], + ), + ], + ), + ); + } +} diff --git a/lib/views/team/editPerson/personInfo/person_info_binding.dart b/lib/views/team/editPerson/personInfo/person_info_binding.dart new file mode 100644 index 0000000..afed945 --- /dev/null +++ b/lib/views/team/editPerson/personInfo/person_info_binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; + +import 'person_info_controller.dart'; + +class PersonInfoBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => PersonInfoController()); + } +} \ No newline at end of file diff --git a/lib/views/team/editPerson/personInfo/person_info_controller.dart b/lib/views/team/editPerson/personInfo/person_info_controller.dart new file mode 100644 index 0000000..aefee34 --- /dev/null +++ b/lib/views/team/editPerson/personInfo/person_info_controller.dart @@ -0,0 +1,17 @@ +import 'package:get/get.dart'; +import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dart'; +import 'package:starwork_flutter/api/model/team/response/role_list_response.dart'; +import 'package:starwork_flutter/base/app_logger.dart'; +import 'package:starwork_flutter/base/base_controller.dart'; +import 'package:starwork_flutter/views/team/editPerson/edit_person_controller.dart'; + +class PersonInfoController extends BaseController { + final editPersonController = Get.find(); + + @override + void onReady() { + super.onReady(); + var isNotEmpty = editPersonController.phoneInputController.text.isNotEmpty; + AppLogger.highlight('message:${isNotEmpty}'); + } +} diff --git a/lib/views/team/editPerson/personInfo/person_info_view.dart b/lib/views/team/editPerson/personInfo/person_info_view.dart new file mode 100644 index 0000000..663453f --- /dev/null +++ b/lib/views/team/editPerson/personInfo/person_info_view.dart @@ -0,0 +1,193 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:starwork_flutter/api/model/team/response/role_list_response.dart'; +import 'package:starwork_flutter/common/constant/app_colors.dart'; +import 'package:starwork_flutter/common/constant/app_view_parameter_keys.dart'; +import 'package:starwork_flutter/common/widgets/custom_cell_list_widget.dart'; +import 'package:starwork_flutter/common/widgets/custom_cell_widget.dart'; +import 'package:starwork_flutter/common/widgets/custome_app_bar_wdiget.dart'; +import 'package:starwork_flutter/routes/app_routes.dart'; +import 'person_info_controller.dart'; + +class PersonInfoView extends GetView { + @override + Widget build(BuildContext context) { + // 即使不使用,只是引用一下 controller 就能触发初始化 + final _ = controller; // 添加这一行 + return Scaffold( + appBar: CustomAppBarWidget( + title: '用户信息'.tr, + backgroundColor: AppColors.scaffoldBackgroundColor, + ), + backgroundColor: AppColors.scaffoldBackgroundColor, + body: Container( + padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), + child: Column( + children: [ + CustomCellListWidget( + children: [ + CustomCellWidget( + onTap: () {}, + leftText: '手机号'.tr, + rightWidget: controller.editPersonController.phoneInputController.text.isNotEmpty + ? Row( + children: [ + Text( + controller.editPersonController.getDisplayPhone(), + style: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + SizedBox( + width: 10.w, + ), + GestureDetector( + onTap: () { + controller.editPersonController.isPhoneVisible.value = + !controller.editPersonController.isPhoneVisible.value; + }, + child: Icon( + controller.editPersonController.isPhoneVisible.value + ? Icons.visibility + : Icons.visibility_off, + size: 16.sp, + color: Colors.grey, + ), + ), + ], + ) + : Expanded( + flex: 3, + child: TextField( + controller: controller.editPersonController.phoneInputController, + keyboardType: TextInputType.number, + textInputAction: TextInputAction.next, + textAlign: TextAlign.end, + style: TextStyle( + fontSize: 14.sp, + ), + decoration: InputDecoration( + isCollapsed: true, + hintText: '请输入手机号'.tr, + hintStyle: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + // 设置无边框 + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + // 获取焦点时的边框 + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + ), + ), + ), + ), + CustomCellWidget( + onTap: () {}, + leftText: '姓名'.tr, + rightWidget: Row( + children: [ + Text( + controller.editPersonController.nameInputController.text.trim(), + style: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + ], + ), + ), + CustomCellWidget( + onTap: () {}, + leftText: '账号状态'.tr, + rightWidget: Row( + children: [ + Obx( + () => Text( + controller.editPersonController.userState.value == 1 + ? '已开通' + : controller.editPersonController.userState.value == 2 + ? '未开通' + : '已停用', + style: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + ), + ), + ], + ), + ), + CustomCellWidget( + onTap: () async { + var result = await Get.toNamed( + AppRoutes.teamSelectRole, + arguments: { + AppViewParameterKeys.viewType: AppViewParameterKeys.edit, + AppViewParameterKeys.roleList: controller.editPersonController.selectedRoles, + AppViewParameterKeys.departNo: + controller.editPersonController.selectedDepartItem.value.departNo, + AppViewParameterKeys.personItem: controller.editPersonController.selectedPersonItem.value, + }, + ); + if (result != null) { + // 处理返回的角色数据 + if (result is List) { + controller.editPersonController.selectedRoles.value = result; + controller.editPersonController.selectedRoles.refresh(); + // 收起键盘 + FocusScope.of(Get.context!).unfocus(); + } + } + }, + leftText: '分配权限'.tr, + rightWidget: Container( + alignment: Alignment.centerRight, + constraints: BoxConstraints( + maxWidth: 200.w, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Obx( + () => Expanded( + child: Text( + textAlign: TextAlign.end, + controller.editPersonController.getSelectedRoleDisplayText(), + style: TextStyle( + fontSize: 14.sp, + color: Colors.black54, + fontWeight: FontWeight.w400, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + ), + SizedBox( + width: 4.w, + ), + Icon( + Icons.arrow_forward_ios_rounded, + size: 16.sp, + color: Colors.grey[300], + ) + ], + ), + ), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/views/team/enterFace/enter_face_binding.dart b/lib/views/team/enterFace/enter_face_binding.dart new file mode 100644 index 0000000..3d8f169 --- /dev/null +++ b/lib/views/team/enterFace/enter_face_binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; + +import 'enter_face_controller.dart'; + +class EnterFaceBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => EnterFaceController()); + } +} \ No newline at end of file diff --git a/lib/views/team/enterFace/enter_face_controller.dart b/lib/views/team/enterFace/enter_face_controller.dart new file mode 100644 index 0000000..9435a0e --- /dev/null +++ b/lib/views/team/enterFace/enter_face_controller.dart @@ -0,0 +1,16 @@ +import 'package:get/get.dart'; +import 'package:starwork_flutter/api/model/team/response/person_list_response.dart'; +import 'package:starwork_flutter/base/base_controller.dart'; + +class EnterFaceController extends BaseController { + final selectedPersonItem = Rx(null); + + @override + void onInit() { + super.onInit(); + final args = Get.arguments; + if (args != null && args is PersonItem) { + selectedPersonItem.value = args; + } + } +} diff --git a/lib/views/team/enterFace/enter_face_view.dart b/lib/views/team/enterFace/enter_face_view.dart new file mode 100644 index 0000000..7213863 --- /dev/null +++ b/lib/views/team/enterFace/enter_face_view.dart @@ -0,0 +1,375 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.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 'enter_face_controller.dart'; + +class EnterFaceView extends GetView { + @override + Widget build(BuildContext context) { + // 即使不使用,只是引用一下 controller 就能触发初始化 + final _ = controller; // 添加这一行 + + return Scaffold( + appBar: CustomAppBarWidget( + title: '人脸信息'.tr, + backgroundColor: AppColors.scaffoldBackgroundColor, + ), + backgroundColor: AppColors.scaffoldBackgroundColor, + body: Container( + padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), + child: SingleChildScrollView( + child: Column( + children: [ + Container( + padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.r), + ), + child: Row( + children: [ + Container( + width: 34.w, + height: 34.w, + margin: EdgeInsets.only(right: 10.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], + ); + }, + ), + ), + ), + Text(controller.selectedPersonItem.value?.personName ?? ''), + const Spacer(), + Text( + '未录入'.tr, + style: TextStyle( + color: Colors.orange, + fontSize: 16.sp, + ), + ) + ], + ), + ), + SizedBox( + height: 10.h, + ), + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.r), + ), + padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 20.h), + child: Column( + children: [ + Container( + width: 118.w, + height: 118.w, + margin: EdgeInsets.only(right: 10.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.iconShotFace), + width: 118.w, + height: 118.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( + height: 10.h, + ), + Text( + '拍摄须知'.tr, + style: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w500, + ), + ), + SizedBox( + height: 10.h, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '1、露出额头、耳朵,人脸正面、不戴帽子'.tr, + style: TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.w500, + ), + ), + Text( + '2、面部光线均匀、无逆光无美颜处理'.tr, + style: TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.w500, + ), + ), + Text( + '3、背部尽量简洁单一,建议均为白色'.tr, + style: TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.w500, + ), + ), + Text( + '4、确保开启APP的相机与存储权限'.tr, + style: TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + SizedBox( + height: 10.h, + ), + Divider( + height: 0.5.h, + ), + SizedBox( + height: 10.h, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + '错误示例', + style: TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.w500, + color: Colors.grey, + ), + ), + SizedBox( + height: 10.h, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Column( + children: [ + Container( + width: 88.w, + height: 88.w, + margin: EdgeInsets.only(right: 10.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.iconShotFaceError1), + width: 88.w, + height: 88.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( + height: 5.h, + ), + Text( + '人脸过小'.tr, + style: TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.w500, + color: Colors.grey, + ), + ) + ], + ), + Column( + children: [ + Container( + width: 88.w, + height: 88.w, + margin: EdgeInsets.only(right: 10.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.iconShotFaceError2), + width: 88.w, + height: 88.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( + height: 5.h, + ), + Text( + '背景复杂'.tr, + style: TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.w500, + color: Colors.grey, + ), + ) + ], + ), + Column( + children: [ + Container( + width: 88.w, + height: 88.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.iconShotFaceError3), + width: 88.w, + height: 88.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( + height: 5.h, + ), + Text( + '光线太暗'.tr, + style: TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.w500, + color: Colors.grey, + ), + ) + ], + ), + ], + ) + ], + ) + ], + ), + ), + SizedBox( + height: 10.h, + ), + Container( + margin: EdgeInsets.symmetric( + horizontal: 10.w, + ), + child: Row( + children: [ + Expanded( + child: ElevatedButton( + onPressed: () { + + }.debounce(), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.grey[50], + padding: EdgeInsets.symmetric(vertical: 10.h), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)), + ), + child: Text( + '通知人员自助录入'.tr, + style: TextStyle( + fontSize: 16.sp, + color: Colors.blue, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + SizedBox(width: 10.w), + Expanded( + child: ElevatedButton( + onPressed: () { + controller.showFunctionNotOpen(); + }.debounce(), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + padding: EdgeInsets.symmetric(vertical: 10.h), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)), + ), + child: Text( + '录入人脸'.tr, + style: TextStyle( + fontSize: 16.sp, + color: Colors.white, + fontWeight: FontWeight.w500, + ), + ), + ), + ) + ], + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/lib/views/team/faceAudit/face_audit_binding.dart b/lib/views/team/faceAudit/face_audit_binding.dart new file mode 100644 index 0000000..f4e5d7a --- /dev/null +++ b/lib/views/team/faceAudit/face_audit_binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; + +import 'face_audit_controller.dart'; + +class FaceAuditBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => FaceAuditController()); + } +} \ No newline at end of file diff --git a/lib/views/team/faceAudit/face_audit_controller.dart b/lib/views/team/faceAudit/face_audit_controller.dart new file mode 100644 index 0000000..fce20c2 --- /dev/null +++ b/lib/views/team/faceAudit/face_audit_controller.dart @@ -0,0 +1,6 @@ +import 'package:get/get.dart'; +import 'package:starwork_flutter/base/base_controller.dart'; + +class FaceAuditController extends BaseController { + +} \ No newline at end of file diff --git a/lib/views/team/faceAudit/face_audit_view.dart b/lib/views/team/faceAudit/face_audit_view.dart new file mode 100644 index 0000000..779b814 --- /dev/null +++ b/lib/views/team/faceAudit/face_audit_view.dart @@ -0,0 +1,83 @@ +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/common/constant/app_colors.dart'; +import 'package:starwork_flutter/common/widgets/custom_cell_list_widget.dart'; +import 'package:starwork_flutter/common/widgets/custom_cell_widget.dart'; +import 'package:starwork_flutter/common/widgets/custome_app_bar_wdiget.dart'; +import 'package:starwork_flutter/extension/function_extension.dart'; +import 'face_audit_controller.dart'; + +class FaceAuditView extends GetView { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBarWidget( + title: '人脸审核'.tr, + backgroundColor: AppColors.scaffoldBackgroundColor, + ), + backgroundColor: AppColors.scaffoldBackgroundColor, + body: Container( + padding: EdgeInsets.symmetric( + horizontal: 10.w, + vertical: 10.h, + ), + child: Column( + children: [ + CustomCellListWidget( + children: [ + CustomCellWidget( + leftText: '启用审核'.tr, + leftSubText: '若关闭审核,自助录入的人脸信息将自动生效'.tr, + rightWidget: CupertinoSwitch( + value: false, + onChanged: (value) { + controller.showFunctionNotOpen(); + }, + ), + ) + ], + ), + Expanded( + child: Center( + child: Text( + '暂无待审核人脸'.tr, + style: TextStyle( + fontSize: 16.sp, + color: Colors.grey, + ), + ), + ), + ), + SizedBox( + height: 10.h, + ), + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () { + controller.showFunctionNotOpen(); + }.debounce(), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + padding: EdgeInsets.symmetric(vertical: 10.h), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)), + ), + child: Text( + '批量通过'.tr, + style: TextStyle( + fontSize: 16.sp, + color: Colors.white, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/views/team/faceInfo/face_info_binding.dart b/lib/views/team/faceInfo/face_info_binding.dart new file mode 100644 index 0000000..0c0e02e --- /dev/null +++ b/lib/views/team/faceInfo/face_info_binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; + +import 'face_info_controller.dart'; + +class FaceInfoBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => FaceInfoController()); + } +} \ No newline at end of file diff --git a/lib/views/team/faceInfo/face_info_controller.dart b/lib/views/team/faceInfo/face_info_controller.dart new file mode 100644 index 0000000..292c417 --- /dev/null +++ b/lib/views/team/faceInfo/face_info_controller.dart @@ -0,0 +1,31 @@ +import 'package:flutter/widgets.dart'; +import 'package:get/get.dart'; +import 'package:starwork_flutter/api/model/team/request/pserson_list_request.dart'; +import 'package:starwork_flutter/api/model/team/response/person_list_response.dart'; +import 'package:starwork_flutter/api/service/team_api_service.dart'; +import 'package:starwork_flutter/base/app_logger.dart'; +import 'package:starwork_flutter/base/base_controller.dart'; + +class FaceInfoController extends BaseController { + final teamApi = Get.find(); + + // 搜索输入框 + TextEditingController searchInputController = TextEditingController(); + + // 人员集合 + Rx personList = PersonListResponse().obs; + + @override + void onInit() { + requestPersonList(); + super.onInit(); + } + + void requestPersonList() async { + var response = await teamApi.requestPersonList(request: PersonListRequest()); + if (response.isSuccess) { + AppLogger.debug("response.data:${response.data}"); + personList.value = response.data!; + } + } +} diff --git a/lib/views/team/faceInfo/face_info_view.dart b/lib/views/team/faceInfo/face_info_view.dart new file mode 100644 index 0000000..ca6ce37 --- /dev/null +++ b/lib/views/team/faceInfo/face_info_view.dart @@ -0,0 +1,193 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import 'package:starwork_flutter/api/model/team/response/person_list_response.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/custom_cell_list_widget.dart'; +import 'package:starwork_flutter/common/widgets/custom_cell_widget.dart'; +import 'package:starwork_flutter/common/widgets/custome_app_bar_wdiget.dart'; +import 'package:starwork_flutter/extension/function_extension.dart'; +import 'package:starwork_flutter/routes/app_routes.dart'; +import 'face_info_controller.dart'; + +class FaceInfoView extends GetView { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBarWidget( + title: '人脸信息'.tr, + backgroundColor: AppColors.scaffoldBackgroundColor, + ), + backgroundColor: AppColors.scaffoldBackgroundColor, + body: Container( + padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), + child: Column( + children: [ + _buildSearchBar(), + SizedBox( + height: 10.h, + ), + Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.0.r), + ), + child: CustomCellListWidget( + children: [ + CustomCellWidget( + onTap: () { + Get.toNamed(AppRoutes.teamFaceAudit); + }, + leftText: '人脸审核'.tr, + rightWidget: Icon( + Icons.arrow_forward_ios_rounded, + size: 16.sp, + color: Colors.grey, + ), + ) + ], + ), + ), + SizedBox( + height: 10.h, + ), + Obx( + () => Expanded( + child: SingleChildScrollView( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8.0.r), + ), + child: CustomCellListWidget( + children: (controller.personList.value.list ?? []) + .map((e) => _buildPersonItem(e)) + .toList(), + ), + ), + ), + ), + ), + SizedBox( + height: 10.h, + ), + Obx( + () => Visibility( + visible: controller.personList.value.list?.isNotEmpty ?? false, + child: SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: () {}.debounce(), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + padding: EdgeInsets.symmetric(vertical: 10.h), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)), + ), + child: Text( + '一键提醒录入人脸(${controller.personList.value.list?.length}人)'.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: Colors.white, + // 灰色背景(可调整色值) + 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), + ), + ), + ); + } + + _buildPersonItem(PersonItem personItem) { + return CustomCellWidget( + onTap: () { + Get.toNamed(AppRoutes.teamEnterFace, arguments: personItem); + }, + leftText: personItem.personName ?? '', + leftWidget: Container( + width: 34.w, + height: 34.w, + margin: EdgeInsets.only(right: 10.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], + ); + }, + ), + ), + ), + rightWidget: Row( + children: [ + Text( + personItem.faceCount == 0 ? '未录入'.tr : '已录入'.tr, + style: TextStyle( + fontSize: 16.sp, + color: personItem.faceCount == 0 ? Colors.orange : Colors.grey, + fontWeight: FontWeight.w500, + ), + ), + Icon( + Icons.arrow_forward_ios_rounded, + size: 16.sp, + color: Colors.grey, + ), + ], + ), + ); + } +} diff --git a/lib/views/team/newPersonAuditing/new_person_auditing_binding.dart b/lib/views/team/newPersonAuditing/new_person_auditing_binding.dart new file mode 100644 index 0000000..200747e --- /dev/null +++ b/lib/views/team/newPersonAuditing/new_person_auditing_binding.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; + +import 'new_person_auditing_controller.dart'; + +class NewPersonAuditingBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut(() => NewPersonAuditingController()); + } +} \ No newline at end of file diff --git a/lib/views/team/newPersonAuditing/new_person_auditing_controller.dart b/lib/views/team/newPersonAuditing/new_person_auditing_controller.dart new file mode 100644 index 0000000..95d629b --- /dev/null +++ b/lib/views/team/newPersonAuditing/new_person_auditing_controller.dart @@ -0,0 +1,6 @@ +import 'package:get/get.dart'; +import 'package:starwork_flutter/base/base_controller.dart'; + +class NewPersonAuditingController extends BaseController { + // TODO: 在这里添加业务逻辑 +} \ No newline at end of file diff --git a/lib/views/team/newPersonAuditing/new_person_auditing_view.dart b/lib/views/team/newPersonAuditing/new_person_auditing_view.dart new file mode 100644 index 0000000..49eaf73 --- /dev/null +++ b/lib/views/team/newPersonAuditing/new_person_auditing_view.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:starwork_flutter/common/constant/app_colors.dart'; +import 'package:starwork_flutter/common/widgets/custome_app_bar_wdiget.dart'; +import 'new_person_auditing_controller.dart'; + +class NewPersonAuditingView extends GetView { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: CustomAppBarWidget( + title: '新用户审核'.tr, + backgroundColor: AppColors.scaffoldBackgroundColor, + ), + backgroundColor: AppColors.scaffoldBackgroundColor, + body: Container( + child: Center( + child: Text('暂无新的审核信息'), // 页面内容待实现 + ), + ), + ); + } +} diff --git a/lib/views/team/personnelManage/personnel_manage_view.dart b/lib/views/team/personnelManage/personnel_manage_view.dart index 6bc6167..cdce860 100644 --- a/lib/views/team/personnelManage/personnel_manage_view.dart +++ b/lib/views/team/personnelManage/personnel_manage_view.dart @@ -48,24 +48,29 @@ class PersonnelManageView extends GetView { child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - Column( - children: [ - Image.asset( - AppImages.iconFace, - width: 24.w, - fit: BoxFit.cover, - ), - SizedBox( - height: 4.h, - ), - Text( - '人脸信息'.tr, - style: TextStyle( - fontSize: 12.sp, - fontWeight: FontWeight.w500, + GestureDetector( + onTap: () { + Get.toNamed(AppRoutes.teamFaceInfo); + }, + child: Column( + children: [ + Image.asset( + AppImages.iconFace, + width: 24.w, + fit: BoxFit.cover, ), - ), - ], + SizedBox( + height: 4.h, + ), + Text( + '人脸信息'.tr, + style: TextStyle( + fontSize: 12.sp, + fontWeight: FontWeight.w500, + ), + ), + ], + ), ), GestureDetector( onTap: () { @@ -91,24 +96,29 @@ class PersonnelManageView extends GetView { ], ), ), - Column( - children: [ - Image.asset( - AppImages.iconNewPerson, - width: 24.w, - fit: BoxFit.cover, - ), - SizedBox( - height: 4.h, - ), - Text( - '新用户审核'.tr, - style: TextStyle( - fontSize: 10.sp, - fontWeight: FontWeight.w500, + GestureDetector( + onTap: () { + Get.toNamed(AppRoutes.teamNewPersonAuditing); + }, + child: Column( + children: [ + Image.asset( + AppImages.iconNewPerson, + width: 24.w, + fit: BoxFit.cover, ), - ), - ], + SizedBox( + height: 4.h, + ), + Text( + '新用户审核'.tr, + style: TextStyle( + fontSize: 10.sp, + fontWeight: FontWeight.w500, + ), + ), + ], + ), ) ], ), @@ -159,7 +169,11 @@ class PersonnelManageView extends GetView { showRootNode: false, expansionIndicatorBuilder: noExpansionIndicatorBuilder, indentation: const Indentation(style: IndentStyle.roundJoint), - onItemTap: (item) {}, + onItemTap: (item) { + if (item.data is PersonItem) { + Get.toNamed(AppRoutes.teamEditPerson, arguments: item.data); + } + }, onTreeReady: (c) { controller.treeViewController = c; },