feat: 增加(添加人员功能页面完善与接口对接、添加子组织页面完善与接口对接、选择用户页面开发)
This commit is contained in:
parent
9b4d112825
commit
9e10952bef
@ -16,4 +16,5 @@ class ApiPath {
|
|||||||
static const String departCreate = "/v1/team/departCreate";
|
static const String departCreate = "/v1/team/departCreate";
|
||||||
static const String roleList = "/v1/team/roleList";
|
static const String roleList = "/v1/team/roleList";
|
||||||
static const String roleCreate = "/v1/team/roleCreate";
|
static const String roleCreate = "/v1/team/roleCreate";
|
||||||
|
static const String createPerson = "/v1/team/personCreate";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,9 +56,9 @@ class BaseApiService {
|
|||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
final uri = Uri.parse('${dio.options.baseUrl}$path');
|
final uri = Uri.parse('${dio.options.baseUrl}$path');
|
||||||
final queryString = queryParameters != null ? '?${uri.queryParameters.toString()}' : '';
|
final queryString = queryParameters != null ? '?${uri.queryParameters.toString()}' : '';
|
||||||
debugPrint('🟦 API Request: $method ${uri.toString()}$queryString');
|
AppLogger.debug('🟦 API Request: $method ${uri.toString()}$queryString');
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
debugPrint('🟦 Request Body: $data');
|
AppLogger.debug('🟦 Request Body: $data');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,8 +86,8 @@ class BaseApiService {
|
|||||||
|
|
||||||
// ✅ 打印响应
|
// ✅ 打印响应
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
debugPrint('🟩 API Response [${response.statusCode}] ${response.requestOptions.path}');
|
AppLogger.debug('🟩 API Response [${response.statusCode}] ${response.requestOptions.path}');
|
||||||
debugPrint('🟩 Response Data: ${response.data}');
|
AppLogger.debug('🟩 Response Data: ${response.data}');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.statusCode! >= 200 && response.statusCode! < 300) {
|
if (response.statusCode! >= 200 && response.statusCode! < 300) {
|
||||||
@ -116,10 +116,10 @@ class BaseApiService {
|
|||||||
} on dioAlias.DioException catch (e) {
|
} on dioAlias.DioException catch (e) {
|
||||||
// ❌ 打印错误
|
// ❌ 打印错误
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
debugPrint('🟥 API Error: ${e.type} - ${e.message}');
|
AppLogger.error('🟥 API Error: ${e.type} - ${e.message}', error: e);
|
||||||
if (e.response != null) {
|
if (e.response != null) {
|
||||||
debugPrint('🟥 Error Response: ${e.response?.data}');
|
AppLogger.error('🟥 Error Response: ${e.response?.data}');
|
||||||
debugPrint('🟥 Status Code: ${e.response?.statusCode}');
|
AppLogger.error('🟥 Status Code: ${e.response?.statusCode}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ class BaseApiService {
|
|||||||
return ApiResponse.error(message, errorCode: statusCode);
|
return ApiResponse.error(message, errorCode: statusCode);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
debugPrint('🟥 Unexpected Error: $e');
|
AppLogger.error('🟥 Unexpected Error: $e', error: e);
|
||||||
}
|
}
|
||||||
return ApiResponse.error('Unexpected error: $e');
|
return ApiResponse.error('Unexpected error: $e');
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
81
lib/api/model/team/request/create_new_person.dart
Normal file
81
lib/api/model/team/request/create_new_person.dart
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
class CreateNewPerson {
|
||||||
|
String? departNo;
|
||||||
|
String? personName;
|
||||||
|
bool? createUser;
|
||||||
|
String? phone;
|
||||||
|
int? sex;
|
||||||
|
String? position;
|
||||||
|
String? remark;
|
||||||
|
List<String>? associateUsers;
|
||||||
|
int? limitType;
|
||||||
|
String? limitStartTime;
|
||||||
|
String? limitEndTime;
|
||||||
|
String? idCard;
|
||||||
|
bool? isConfirm;
|
||||||
|
List<int>? roleIds;
|
||||||
|
String? jobNumber;
|
||||||
|
|
||||||
|
CreateNewPerson({
|
||||||
|
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.isConfirm,
|
||||||
|
this.roleIds,
|
||||||
|
this.jobNumber,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory CreateNewPerson.fromJson(Map<String, dynamic> json) {
|
||||||
|
return CreateNewPerson(
|
||||||
|
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'] != null
|
||||||
|
? List<String>.from(json['associateUsers'])
|
||||||
|
: null,
|
||||||
|
limitType: json['limitType'] as int?,
|
||||||
|
limitStartTime: json['limitStartTime'] as String?,
|
||||||
|
limitEndTime: json['limitEndTime'] as String?,
|
||||||
|
idCard: json['idCard'] as String?,
|
||||||
|
isConfirm: json['isConfirm'] as bool?,
|
||||||
|
roleIds: json['roleIds'] != null
|
||||||
|
? List<int>.from(json['roleIds'])
|
||||||
|
: null,
|
||||||
|
jobNumber: json['jobNumber'] as String?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
|
||||||
|
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 (isConfirm != null) data['isConfirm'] = isConfirm;
|
||||||
|
if (roleIds != null) data['roleIds'] = roleIds;
|
||||||
|
if (jobNumber != null) data['jobNumber'] = jobNumber;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ import 'package:starwork_flutter/api/base_api_service.dart';
|
|||||||
import 'package:starwork_flutter/api/model/team/request/bind_team_star_cloud_account_request.dart';
|
import 'package:starwork_flutter/api/model/team/request/bind_team_star_cloud_account_request.dart';
|
||||||
import 'package:starwork_flutter/api/model/team/request/change_current_team_request.dart';
|
import 'package:starwork_flutter/api/model/team/request/change_current_team_request.dart';
|
||||||
import 'package:starwork_flutter/api/model/team/request/create_new_depart_request.dart';
|
import 'package:starwork_flutter/api/model/team/request/create_new_depart_request.dart';
|
||||||
|
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_new_role_request.dart';
|
||||||
import 'package:starwork_flutter/api/model/team/request/create_team_request.dart';
|
import 'package:starwork_flutter/api/model/team/request/create_team_request.dart';
|
||||||
import 'package:starwork_flutter/api/model/team/request/get_depart_list_request.dart';
|
import 'package:starwork_flutter/api/model/team/request/get_depart_list_request.dart';
|
||||||
@ -139,7 +140,7 @@ class TeamApiService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取组织列表
|
// 创建新的组织
|
||||||
Future<ApiResponse<void>> requestCreateDepart({
|
Future<ApiResponse<void>> requestCreateDepart({
|
||||||
required CreateNewDepartRequest request,
|
required CreateNewDepartRequest request,
|
||||||
}) {
|
}) {
|
||||||
@ -171,4 +172,16 @@ class TeamApiService {
|
|||||||
fromJson: (data) {},
|
fromJson: (data) {},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加新的人员
|
||||||
|
Future<ApiResponse<void>> requestAddPerson({
|
||||||
|
required CreateNewPerson request,
|
||||||
|
}) {
|
||||||
|
return _api.makeRequest(
|
||||||
|
path: ApiPath.createPerson,
|
||||||
|
method: HttpConstant.post,
|
||||||
|
data: request.toJson(),
|
||||||
|
fromJson: (data) {},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,4 +68,5 @@ class BaseController extends GetxController {
|
|||||||
}
|
}
|
||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,5 +4,8 @@ class AppViewParameterKeys {
|
|||||||
static const String networkInfo = "networkInfo";
|
static const String networkInfo = "networkInfo";
|
||||||
static const String teamInfo = "teamInfo";
|
static const String teamInfo = "teamInfo";
|
||||||
static const String departItem = "departItem";
|
static const String departItem = "departItem";
|
||||||
|
static const String isLongTerm = "isLongTerm";
|
||||||
|
static const String startDate = "startDate";
|
||||||
|
static const String endDate = "endDate";
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ class F {
|
|||||||
// Release环境的API地址
|
// Release环境的API地址
|
||||||
switch (appFlavor) {
|
switch (appFlavor) {
|
||||||
case Flavor.sky:
|
case Flavor.sky:
|
||||||
return 'https://192.168.1.137:8112/api'; // 生产环境API
|
return 'https://192.168.1.136:8112/api'; // 生产环境API
|
||||||
case Flavor.xhj:
|
case Flavor.xhj:
|
||||||
return 'https://api.xhjcn.ltd/api'; // 生产环境API
|
return 'https://api.xhjcn.ltd/api'; // 生产环境API
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ class F {
|
|||||||
// Debug/Profile环境的API地址(开发环境)
|
// Debug/Profile环境的API地址(开发环境)
|
||||||
switch (appFlavor) {
|
switch (appFlavor) {
|
||||||
case Flavor.sky:
|
case Flavor.sky:
|
||||||
return 'http://192.168.1.137:8112/api';
|
return 'http://192.168.1.136:8112/api';
|
||||||
case Flavor.xhj:
|
case Flavor.xhj:
|
||||||
return 'https://loacl.work.star-lock.cn/api';
|
return 'https://loacl.work.star-lock.cn/api';
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ class F {
|
|||||||
// Debug/Profile环境的StarCloud地址(开发环境)
|
// Debug/Profile环境的StarCloud地址(开发环境)
|
||||||
switch (appFlavor) {
|
switch (appFlavor) {
|
||||||
case Flavor.sky:
|
case Flavor.sky:
|
||||||
return 'http://192.168.1.137:8111/sdk';
|
return 'http://192.168.1.136:8111/sdk';
|
||||||
case Flavor.xhj:
|
case Flavor.xhj:
|
||||||
return 'http://local.cloud.star-lock.cn';
|
return 'http://local.cloud.star-lock.cn';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,8 +34,12 @@ import 'package:starwork_flutter/views/login/login_binding.dart';
|
|||||||
import 'package:starwork_flutter/views/login/login_view.dart';
|
import 'package:starwork_flutter/views/login/login_view.dart';
|
||||||
import 'package:starwork_flutter/views/main/main_binding.dart';
|
import 'package:starwork_flutter/views/main/main_binding.dart';
|
||||||
import 'package:starwork_flutter/views/main/main_view.dart';
|
import 'package:starwork_flutter/views/main/main_view.dart';
|
||||||
|
import 'package:starwork_flutter/views/team/addOrganization/add_organization_binding.dart';
|
||||||
|
import 'package:starwork_flutter/views/team/addOrganization/add_organization_view.dart';
|
||||||
import 'package:starwork_flutter/views/team/addPerson/add_person_binding.dart';
|
import 'package:starwork_flutter/views/team/addPerson/add_person_binding.dart';
|
||||||
import 'package:starwork_flutter/views/team/addPerson/add_person_view.dart';
|
import 'package:starwork_flutter/views/team/addPerson/add_person_view.dart';
|
||||||
|
import 'package:starwork_flutter/views/team/addPerson/editValidity/edit_validity_binding.dart';
|
||||||
|
import 'package:starwork_flutter/views/team/addPerson/editValidity/edit_validity_view.dart';
|
||||||
import 'package:starwork_flutter/views/team/addPerson/selectRole/select_role_binding.dart';
|
import 'package:starwork_flutter/views/team/addPerson/selectRole/select_role_binding.dart';
|
||||||
import 'package:starwork_flutter/views/team/addPerson/selectRole/select_role_view.dart';
|
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_binding.dart';
|
||||||
@ -52,6 +56,8 @@ import 'package:starwork_flutter/views/team/roleManage/role_manage_binding.dart'
|
|||||||
import 'package:starwork_flutter/views/team/roleManage/role_manage_view.dart';
|
import 'package:starwork_flutter/views/team/roleManage/role_manage_view.dart';
|
||||||
import 'package:starwork_flutter/views/team/selectOrganization/select_organization_binding.dart';
|
import 'package:starwork_flutter/views/team/selectOrganization/select_organization_binding.dart';
|
||||||
import 'package:starwork_flutter/views/team/selectOrganization/select_organization_view.dart';
|
import 'package:starwork_flutter/views/team/selectOrganization/select_organization_view.dart';
|
||||||
|
import 'package:starwork_flutter/views/team/selectPerson/select_person_binding.dart';
|
||||||
|
import 'package:starwork_flutter/views/team/selectPerson/select_person_view.dart';
|
||||||
import 'package:starwork_flutter/views/team/teamManage/teamInfo/team_info_binding.dart';
|
import 'package:starwork_flutter/views/team/teamManage/teamInfo/team_info_binding.dart';
|
||||||
import 'package:starwork_flutter/views/team/teamManage/teamInfo/team_info_view.dart';
|
import 'package:starwork_flutter/views/team/teamManage/teamInfo/team_info_view.dart';
|
||||||
import 'package:starwork_flutter/views/team/teamManage/team_manage_binding.dart';
|
import 'package:starwork_flutter/views/team/teamManage/team_manage_binding.dart';
|
||||||
@ -242,5 +248,20 @@ class AppPages {
|
|||||||
page: () => SelectRoleView(),
|
page: () => SelectRoleView(),
|
||||||
binding: SelectRoleBinding(),
|
binding: SelectRoleBinding(),
|
||||||
),
|
),
|
||||||
|
GetPage(
|
||||||
|
name: AppRoutes.teamAddPersonEditValidity,
|
||||||
|
page: () => EditValidityView(),
|
||||||
|
binding: EditValidityBinding(),
|
||||||
|
),
|
||||||
|
GetPage(
|
||||||
|
name: AppRoutes.teamAddOrganization,
|
||||||
|
page: () => AddOrganizationView(),
|
||||||
|
binding: AddOrganizationBinding(),
|
||||||
|
),
|
||||||
|
GetPage(
|
||||||
|
name: AppRoutes.teamSelectPerson,
|
||||||
|
page: () => SelectPersonView(),
|
||||||
|
binding: SelectPersonBinding(),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,9 +20,12 @@ class AppRoutes{
|
|||||||
static const String teamAddPerson = '/team/addPerson';
|
static const String teamAddPerson = '/team/addPerson';
|
||||||
static const String teamRoleManage = '/team/roleManage';
|
static const String teamRoleManage = '/team/roleManage';
|
||||||
static const String teamSelectOrganization = '/team/selectOrganization';
|
static const String teamSelectOrganization = '/team/selectOrganization';
|
||||||
|
static const String teamSelectPerson = '/team/selectPerson';
|
||||||
static const String teamPersonnelManage = '/team/personnelManage';
|
static const String teamPersonnelManage = '/team/personnelManage';
|
||||||
static const String teamAddRole = '/team/addRole';
|
static const String teamAddRole = '/team/addRole';
|
||||||
static const String teamSelectRole = '/team/selectRole';
|
static const String teamSelectRole = '/team/selectRole';
|
||||||
|
static const String teamAddPersonEditValidity = '/team/addPerson/editValidity';
|
||||||
|
static const String teamAddOrganization = '/team/addOrganization';
|
||||||
static const String deviceManage = '/device/deviceManage';
|
static const String deviceManage = '/device/deviceManage';
|
||||||
static const String searchDevice = '/device/searchDevice';
|
static const String searchDevice = '/device/searchDevice';
|
||||||
static const String confirmPairDevice = '/device/confirmPairDevice';
|
static const String confirmPairDevice = '/device/confirmPairDevice';
|
||||||
|
|||||||
10
lib/views/team/addOrganization/add_organization_binding.dart
Normal file
10
lib/views/team/addOrganization/add_organization_binding.dart
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import 'add_organization_controller.dart';
|
||||||
|
|
||||||
|
class AddOrganizationBinding extends Bindings {
|
||||||
|
@override
|
||||||
|
void dependencies() {
|
||||||
|
Get.lazyPut(() => AddOrganizationController());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:starwork_flutter/api/model/team/request/create_new_depart_request.dart';
|
||||||
|
import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dart';
|
||||||
|
import 'package:starwork_flutter/api/service/team_api_service.dart';
|
||||||
|
import 'package:starwork_flutter/base/base_controller.dart';
|
||||||
|
import 'package:starwork_flutter/common/constant/app_view_parameter_keys.dart';
|
||||||
|
|
||||||
|
class AddOrganizationController extends BaseController {
|
||||||
|
TextEditingController organizationNameInputController = TextEditingController();
|
||||||
|
var selectedDepartItem = DepartItem().obs; // 当前选中的组织
|
||||||
|
var selectedPerson = <PersonItem>[].obs; // 当前选中的用户
|
||||||
|
final teamApi = Get.find<TeamApiService>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onReady() {
|
||||||
|
super.onReady();
|
||||||
|
// 读取参数
|
||||||
|
final args = Get.arguments;
|
||||||
|
if (args != null && args.containsKey(AppViewParameterKeys.departItem)) {
|
||||||
|
final json = args[AppViewParameterKeys.departItem];
|
||||||
|
selectedDepartItem.value = DepartItem.fromJson(json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取选中角色的显示文本
|
||||||
|
String getSelectedPersonDisplayText() {
|
||||||
|
if (selectedPerson.isEmpty) {
|
||||||
|
return '请选择组织负责人(选填)'; // 如果没有选中角色,显示"请选择"
|
||||||
|
} else {
|
||||||
|
// 将所有选中角色的名称用逗号连接
|
||||||
|
return selectedPerson.map((person) => person.personName ?? '').join('、'); // 使用顿号或逗号分隔
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestCreateDepart() async {
|
||||||
|
var response = await teamApi.requestCreateDepart(
|
||||||
|
request: CreateNewDepartRequest(
|
||||||
|
departName: organizationNameInputController.text.trim(),
|
||||||
|
parentDepartNo: selectedDepartItem.value.departNo!,
|
||||||
|
leader: selectedPerson
|
||||||
|
.map((e) => e.personNo)
|
||||||
|
.whereType<String>() // 只保留非 null 的 String
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (response.isSuccess) {
|
||||||
|
showSuccess();
|
||||||
|
} else {
|
||||||
|
showError(message: response.errorMsg!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
200
lib/views/team/addOrganization/add_organization_view.dart
Normal file
200
lib/views/team/addOrganization/add_organization_view.dart
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
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/depart_list_reponse.dart';
|
||||||
|
import 'package:starwork_flutter/base/app_logger.dart';
|
||||||
|
import 'package:starwork_flutter/common/constant/app_colors.dart';
|
||||||
|
import 'package:starwork_flutter/common/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 'add_organization_controller.dart';
|
||||||
|
|
||||||
|
class AddOrganizationView extends GetView<AddOrganizationController> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// 即使不使用,只是引用一下 controller 就能触发初始化
|
||||||
|
final _ = controller; // 添加这一行
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
FocusScope.of(context).requestFocus(FocusNode());
|
||||||
|
},
|
||||||
|
child: Scaffold(
|
||||||
|
appBar: CustomAppBarWidget(
|
||||||
|
title: '添加子组织'.tr,
|
||||||
|
backgroundColor: AppColors.scaffoldBackgroundColor,
|
||||||
|
),
|
||||||
|
backgroundColor: AppColors.scaffoldBackgroundColor,
|
||||||
|
body: SafeArea(
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
CustomCellListWidget(
|
||||||
|
children: [
|
||||||
|
CustomCellWidget(
|
||||||
|
onTap: () {},
|
||||||
|
leftText: '组织名称'.tr,
|
||||||
|
leftIcon: Icon(
|
||||||
|
Icons.circle,
|
||||||
|
size: 4.w,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
rightWidget: Expanded(
|
||||||
|
flex: 3,
|
||||||
|
child: TextField(
|
||||||
|
controller: controller.organizationNameInputController,
|
||||||
|
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 {
|
||||||
|
final result = await Get.toNamed(AppRoutes.teamSelectOrganization);
|
||||||
|
if (result != null) {
|
||||||
|
if (result is DepartItem) {
|
||||||
|
controller.selectedDepartItem.value = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
leftText: '上级组织'.tr,
|
||||||
|
leftIcon: Icon(
|
||||||
|
Icons.circle,
|
||||||
|
size: 4.w,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
rightWidget: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Obx(
|
||||||
|
() => Text(
|
||||||
|
controller.selectedDepartItem.value.departName ?? '请选择上级组织'.tr,
|
||||||
|
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 {
|
||||||
|
final result =
|
||||||
|
await Get.toNamed(AppRoutes.teamSelectPerson, arguments: controller.selectedPerson);
|
||||||
|
if (result != null && result is List<PersonItem>) {
|
||||||
|
controller.selectedPerson.value = result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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.getSelectedPersonDisplayText(),
|
||||||
|
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],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (controller.organizationNameInputController.text.isEmpty) {
|
||||||
|
controller.showToast('请先输入组织名称'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (controller.selectedDepartItem.value.departNo == null) {
|
||||||
|
controller.showToast('请先选择上级组织'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await controller.requestCreateDepart();
|
||||||
|
}.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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 10.h,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,24 +2,30 @@ import 'package:flutter/widgets.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:get/get_rx/get_rx.dart';
|
import 'package:get/get_rx/get_rx.dart';
|
||||||
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
||||||
|
import 'package:starwork_flutter/api/model/team/request/create_new_person.dart';
|
||||||
import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.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/model/team/response/role_list_response.dart';
|
||||||
|
import 'package:starwork_flutter/api/service/team_api_service.dart';
|
||||||
import 'package:starwork_flutter/base/base_controller.dart';
|
import 'package:starwork_flutter/base/base_controller.dart';
|
||||||
import 'package:starwork_flutter/common/constant/app_view_parameter_keys.dart';
|
import 'package:starwork_flutter/common/constant/app_view_parameter_keys.dart';
|
||||||
|
|
||||||
class AddPersonController extends BaseController {
|
class AddPersonController extends BaseController {
|
||||||
RxString selectedGender = 'male'.obs;
|
RxString selectedGender = 'male'.obs;
|
||||||
|
final teamApi = Get.find<TeamApiService>();
|
||||||
var selectedDepartItem = DepartItem().obs; // 当前选中的组织
|
var selectedDepartItem = DepartItem().obs; // 当前选中的组织
|
||||||
|
|
||||||
TextEditingController nameInputController = TextEditingController();
|
TextEditingController nameInputController = TextEditingController();
|
||||||
|
TextEditingController phoneInputController = TextEditingController();
|
||||||
TextEditingController jobNoInputController = TextEditingController(); // 工号
|
TextEditingController jobNoInputController = TextEditingController(); // 工号
|
||||||
TextEditingController postInputController = TextEditingController(); // 职务
|
TextEditingController postInputController = TextEditingController(); // 职务
|
||||||
TextEditingController idCardInputController = TextEditingController(); // 身份证号码
|
TextEditingController idCardInputController = TextEditingController(); // 身份证号码
|
||||||
|
TextEditingController remarkInputController = TextEditingController(); // 备注
|
||||||
var isOpeningAccount = false.obs; // 是否开通账户
|
var isOpeningAccount = false.obs; // 是否开通账户
|
||||||
|
var isLongTerm = true.obs; // 有效期是否为长期
|
||||||
|
var startDate = 0.obs; // 使用时间戳表示开始时间
|
||||||
|
var endDate = 0.obs; // 使用时间戳表示结束时间
|
||||||
var selectedRoles = <RoleListResponse>[].obs;
|
var selectedRoles = <RoleListResponse>[].obs;
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onReady() {
|
void onReady() {
|
||||||
super.onReady();
|
super.onReady();
|
||||||
@ -30,15 +36,77 @@ class AddPersonController extends BaseController {
|
|||||||
selectedDepartItem.value = DepartItem.fromJson(json);
|
selectedDepartItem.value = DepartItem.fromJson(json);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取选中角色的显示文本
|
// 获取选中角色的显示文本
|
||||||
String getSelectedRoleDisplayText() {
|
String getSelectedRoleDisplayText() {
|
||||||
if (selectedRoles.isEmpty) {
|
if (selectedRoles.isEmpty) {
|
||||||
return '请选择'; // 如果没有选中角色,显示"请选择"
|
return '请选择'; // 如果没有选中角色,显示"请选择"
|
||||||
} else {
|
} else {
|
||||||
// 将所有选中角色的名称用逗号连接
|
// 将所有选中角色的名称用逗号连接
|
||||||
return selectedRoles
|
return selectedRoles.map((role) => role.roleName ?? '').join('、'); // 使用顿号或逗号分隔
|
||||||
.map((role) => role.roleName ?? '')
|
|
||||||
.join('、'); // 使用顿号或逗号分隔
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 保存员工信息
|
||||||
|
/// [isSustain] 是否为持续保存
|
||||||
|
void savePerson({
|
||||||
|
bool isSustain = false,
|
||||||
|
}) async {
|
||||||
|
List<int?> list = selectedRoles.map((role) => role.id).toList();
|
||||||
|
var response = await teamApi.requestAddPerson(
|
||||||
|
request: CreateNewPerson(
|
||||||
|
departNo: selectedDepartItem.value.departNo,
|
||||||
|
personName: nameInputController.text.trim(),
|
||||||
|
phone: phoneInputController.text.trim(),
|
||||||
|
sex: selectedGender.value == 'male' ? 1 : 2,
|
||||||
|
position: postInputController.text.trim(),
|
||||||
|
idCard: idCardInputController.text.trim(),
|
||||||
|
remark: remarkInputController.text.trim(),
|
||||||
|
jobNumber: jobNoInputController.text.trim(),
|
||||||
|
limitType: isLongTerm.value ? 1 : 2,
|
||||||
|
limitStartTime: isLongTerm.value ? null : formatTimestamp(startDate.value),
|
||||||
|
limitEndTime: isLongTerm.value ? null : formatTimestamp(endDate.value),
|
||||||
|
isConfirm: true,
|
||||||
|
roleIds: list.whereType<int>().toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (response.isSuccess) {
|
||||||
|
showSuccess();
|
||||||
|
if (!isSustain) {
|
||||||
|
Get.back(result: true);
|
||||||
|
} else {
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showError(message: response.errorMsg!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助方法:将时间戳转换为日期字符串
|
||||||
|
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 '请选择';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置表单
|
||||||
|
void resetForm() {
|
||||||
|
nameInputController.text = '';
|
||||||
|
phoneInputController.text = '';
|
||||||
|
jobNoInputController.text = '';
|
||||||
|
postInputController.text = '';
|
||||||
|
idCardInputController.text = '';
|
||||||
|
remarkInputController.text = '';
|
||||||
|
selectedGender.value = 'male';
|
||||||
|
isOpeningAccount.value = false;
|
||||||
|
isLongTerm.value = true;
|
||||||
|
startDate.value = 0;
|
||||||
|
endDate.value = 0;
|
||||||
|
selectedRoles.clear();
|
||||||
|
selectedDepartItem.value = DepartItem();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dar
|
|||||||
import 'package:starwork_flutter/api/model/team/response/role_list_response.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/app_logger.dart';
|
||||||
import 'package:starwork_flutter/common/constant/app_colors.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_list_widget.dart';
|
||||||
import 'package:starwork_flutter/common/widgets/custom_cell_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/common/widgets/custome_app_bar_wdiget.dart';
|
||||||
@ -16,6 +17,8 @@ import 'add_person_controller.dart';
|
|||||||
class AddPersonView extends GetView<AddPersonController> {
|
class AddPersonView extends GetView<AddPersonController> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
// 即使不使用,只是引用一下 controller 就能触发初始化
|
||||||
|
final _ = controller; // 添加这一行
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
FocusScope.of(context).requestFocus(FocusNode());
|
FocusScope.of(context).requestFocus(FocusNode());
|
||||||
@ -51,136 +54,33 @@ class AddPersonView extends GetView<AddPersonController> {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 6.h,
|
height: 6.h,
|
||||||
),
|
),
|
||||||
CustomCellListWidget(
|
Obx(
|
||||||
children: [
|
() => CustomCellListWidget(
|
||||||
CustomCellWidget(
|
children: [
|
||||||
onTap: () async {
|
CustomCellWidget(
|
||||||
final result = await Get.toNamed(AppRoutes.teamSelectOrganization);
|
onTap: () async {
|
||||||
if (result != null) {
|
final result = await Get.toNamed(AppRoutes.teamSelectOrganization);
|
||||||
AppLogger.highlight('result:${result}');
|
|
||||||
if (result is DepartItem) {
|
if (result != null && result is DepartItem) {
|
||||||
controller.selectedDepartItem.value = result;
|
controller.selectedDepartItem.value = result;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
leftText: '组织'.tr,
|
||||||
leftText: '组织'.tr,
|
leftIcon: Icon(
|
||||||
leftIcon: Icon(
|
Icons.circle,
|
||||||
Icons.circle,
|
size: 4.w,
|
||||||
size: 4.w,
|
color: Colors.red,
|
||||||
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,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
rightWidget: Row(
|
||||||
),
|
|
||||||
CustomCellWidget(
|
|
||||||
onTap: () {},
|
|
||||||
leftText: '开通账号'.tr,
|
|
||||||
leftSubText: '可登录并使用应用或管理功能',
|
|
||||||
leftIcon: Icon(
|
|
||||||
Icons.circle,
|
|
||||||
size: 4.w,
|
|
||||||
color: Colors.red,
|
|
||||||
),
|
|
||||||
rightWidget: CupertinoSwitch(
|
|
||||||
value: true,
|
|
||||||
onChanged: (bool value) {},
|
|
||||||
activeColor: Colors.blue, // 可选:打开时的颜色(iOS 默认为系统蓝色,可自定义)
|
|
||||||
trackColor: Colors.grey, // 可选:关闭时的背景轨道颜色
|
|
||||||
),
|
|
||||||
),
|
|
||||||
CustomCellWidget(
|
|
||||||
onTap: () async {
|
|
||||||
var result =
|
|
||||||
await Get.toNamed(AppRoutes.teamSelectRole, arguments: controller.selectedRoles);
|
|
||||||
if (result != null) {
|
|
||||||
// 处理返回的角色数据
|
|
||||||
if (result is List<RoleListResponse>) {
|
|
||||||
controller.selectedRoles.value = result;
|
|
||||||
controller.selectedRoles.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
leftText: '分配权限'.tr,
|
|
||||||
leftIcon: Icon(
|
|
||||||
Icons.circle,
|
|
||||||
size: 4.w,
|
|
||||||
color: Colors.red,
|
|
||||||
),
|
|
||||||
rightWidget: Container(
|
|
||||||
constraints: BoxConstraints(
|
|
||||||
maxWidth: 200.w,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Obx(
|
Obx(
|
||||||
() => Expanded(
|
() => Text(
|
||||||
child: Text(
|
controller.selectedDepartItem.value.departName ?? '请选择',
|
||||||
controller.getSelectedRoleDisplayText(),
|
style: TextStyle(
|
||||||
style: TextStyle(
|
fontSize: 14.sp,
|
||||||
fontSize: 14.sp,
|
color: Colors.black54,
|
||||||
color: Colors.black54,
|
fontWeight: FontWeight.w400,
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -195,8 +95,157 @@ class AddPersonView extends GetView<AddPersonController> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
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,
|
||||||
|
leftIcon: controller.isOpeningAccount.value
|
||||||
|
? Icon(
|
||||||
|
Icons.circle,
|
||||||
|
size: 4.w,
|
||||||
|
color: Colors.red,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
rightWidget: 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: controller.isOpeningAccount.value ? '若开通账号则必填'.tr : '请输入手机号'.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,
|
||||||
|
leftSubText: '可登录并使用应用或管理功能',
|
||||||
|
leftIcon: Icon(
|
||||||
|
Icons.circle,
|
||||||
|
size: 4.w,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
rightWidget: Obx(
|
||||||
|
() => CupertinoSwitch(
|
||||||
|
value: controller.isOpeningAccount.value,
|
||||||
|
onChanged: (bool value) {
|
||||||
|
controller.isOpeningAccount.value = value;
|
||||||
|
},
|
||||||
|
activeColor: Colors.blue, // 可选:打开时的颜色(iOS 默认为系统蓝色,可自定义)
|
||||||
|
trackColor: Colors.grey, // 可选:关闭时的背景轨道颜色
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
CustomCellWidget(
|
||||||
|
onTap: () async {
|
||||||
|
var result =
|
||||||
|
await Get.toNamed(AppRoutes.teamSelectRole, arguments: controller.selectedRoles);
|
||||||
|
if (result != null) {
|
||||||
|
// 处理返回的角色数据
|
||||||
|
if (result is List<RoleListResponse>) {
|
||||||
|
controller.selectedRoles.value = result;
|
||||||
|
controller.selectedRoles.refresh();
|
||||||
|
// 收起键盘
|
||||||
|
FocusScope.of(Get.context!).unfocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
leftText: '分配权限'.tr,
|
||||||
|
leftIcon: Icon(
|
||||||
|
Icons.circle,
|
||||||
|
size: 4.w,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
rightWidget: Container(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
maxWidth: 200.w,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Obx(
|
||||||
|
() => Expanded(
|
||||||
|
child: Text(
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
controller.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],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 10.h,
|
height: 10.h,
|
||||||
@ -275,17 +324,35 @@ class AddPersonView extends GetView<AddPersonController> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
CustomCellWidget(
|
CustomCellWidget(
|
||||||
onTap: () {},
|
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,
|
leftText: '有效期'.tr,
|
||||||
rightWidget: Row(
|
rightWidget: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Obx(
|
||||||
'请选择',
|
() => Text(
|
||||||
style: TextStyle(
|
controller.isLongTerm.value
|
||||||
fontSize: 14.sp,
|
? '长期'.tr
|
||||||
color: Colors.black54,
|
: '${controller.formatTimestamp(controller.startDate.value)} - '
|
||||||
fontWeight: FontWeight.w400,
|
'${controller.formatTimestamp(controller.endDate.value)}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.sp,
|
||||||
|
color: Colors.black54,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@ -335,6 +402,7 @@ class AddPersonView extends GetView<AddPersonController> {
|
|||||||
rightWidget: Expanded(
|
rightWidget: Expanded(
|
||||||
flex: 3,
|
flex: 3,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
|
controller: controller.remarkInputController,
|
||||||
keyboardType: TextInputType.text,
|
keyboardType: TextInputType.text,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
textAlign: TextAlign.end,
|
textAlign: TextAlign.end,
|
||||||
@ -365,6 +433,7 @@ class AddPersonView extends GetView<AddPersonController> {
|
|||||||
rightWidget: Expanded(
|
rightWidget: Expanded(
|
||||||
flex: 3,
|
flex: 3,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
|
controller: controller.idCardInputController,
|
||||||
keyboardType: TextInputType.text,
|
keyboardType: TextInputType.text,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
textAlign: TextAlign.end,
|
textAlign: TextAlign.end,
|
||||||
@ -451,7 +520,26 @@ class AddPersonView extends GetView<AddPersonController> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {}.debounce(),
|
onPressed: () {
|
||||||
|
if (controller.selectedDepartItem.value.departNo == null) {
|
||||||
|
controller.showToast('请先选择组织'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (controller.nameInputController.text.isEmpty) {
|
||||||
|
controller.showToast('请输入姓名'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (controller.phoneInputController.text.isEmpty &&
|
||||||
|
controller.isOpeningAccount.isTrue) {
|
||||||
|
controller.showToast('请输入手机号'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (controller.selectedRoles.isEmpty) {
|
||||||
|
controller.showToast('请先选择角色'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
controller.savePerson();
|
||||||
|
}.debounce(),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.grey[100],
|
backgroundColor: Colors.grey[100],
|
||||||
padding: EdgeInsets.symmetric(vertical: 12.h),
|
padding: EdgeInsets.symmetric(vertical: 12.h),
|
||||||
@ -474,7 +562,26 @@ class AddPersonView extends GetView<AddPersonController> {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {}.debounce(),
|
onPressed: () {
|
||||||
|
if (controller.selectedDepartItem.value.departNo == null) {
|
||||||
|
controller.showToast('请先选择组织'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (controller.nameInputController.text.isEmpty) {
|
||||||
|
controller.showToast('请输入姓名'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (controller.phoneInputController.text.isEmpty &&
|
||||||
|
controller.isOpeningAccount.isTrue) {
|
||||||
|
controller.showToast('请输入手机号'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (controller.selectedRoles.isEmpty) {
|
||||||
|
controller.showToast('请先选择角色'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
controller.savePerson(isSustain: true);
|
||||||
|
}.debounce(),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.blue,
|
backgroundColor: Colors.blue,
|
||||||
padding: EdgeInsets.symmetric(vertical: 12.h),
|
padding: EdgeInsets.symmetric(vertical: 12.h),
|
||||||
|
|||||||
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import 'edit_validity_controller.dart';
|
||||||
|
|
||||||
|
class EditValidityBinding extends Bindings {
|
||||||
|
@override
|
||||||
|
void dependencies() {
|
||||||
|
Get.lazyPut(() => EditValidityController());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:starwork_flutter/base/base_controller.dart';
|
||||||
|
import 'package:starwork_flutter/common/constant/app_view_parameter_keys.dart';
|
||||||
|
|
||||||
|
class EditValidityController extends BaseController {
|
||||||
|
var isLongTerm = true.obs; // 是否开启长期有效
|
||||||
|
|
||||||
|
var startDate = 0.obs; // 使用时间戳表示开始时间
|
||||||
|
var endDate = 0.obs; // 使用时间戳表示结束时间
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
// 读取参数
|
||||||
|
final args = Get.arguments;
|
||||||
|
if (args != null && args.containsKey(AppViewParameterKeys.isLongTerm)) {
|
||||||
|
isLongTerm.value = args[AppViewParameterKeys.isLongTerm];
|
||||||
|
}
|
||||||
|
if (args != null && args.containsKey(AppViewParameterKeys.startDate)) {
|
||||||
|
startDate.value = args[AppViewParameterKeys.startDate];
|
||||||
|
}
|
||||||
|
if (args != null && args.containsKey(AppViewParameterKeys.endDate)) {
|
||||||
|
endDate.value = args[AppViewParameterKeys.endDate];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
289
lib/views/team/addPerson/editValidity/edit_validity_view.dart
Normal file
289
lib/views/team/addPerson/editValidity/edit_validity_view.dart
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_datetime_picker_plus/flutter_datetime_picker_plus.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_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 'edit_validity_controller.dart';
|
||||||
|
|
||||||
|
class EditValidityView extends GetView<EditValidityController> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// 即使不使用,只是引用一下 controller 就能触发初始化
|
||||||
|
final _ = controller; // 添加这一行
|
||||||
|
return Scaffold(
|
||||||
|
appBar: CustomAppBarWidget(
|
||||||
|
title: '编辑有效期'.tr,
|
||||||
|
backgroundColor: AppColors.scaffoldBackgroundColor,
|
||||||
|
),
|
||||||
|
backgroundColor: AppColors.scaffoldBackgroundColor,
|
||||||
|
body: SafeArea(
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8.r)),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'长期有效'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16.sp,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 10.h,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'关闭后可限制通行门禁的生效-失效日期'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.sp,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
Obx(
|
||||||
|
() => CupertinoSwitch(
|
||||||
|
value: controller.isLongTerm.value,
|
||||||
|
onChanged: (bool value) {
|
||||||
|
controller.isLongTerm.value = value;
|
||||||
|
},
|
||||||
|
activeColor: Colors.blue, // 可选:打开时的颜色(iOS 默认为系统蓝色,可自定义)
|
||||||
|
trackColor: Colors.grey, // 可选:关闭时的背景轨道颜色
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Obx(
|
||||||
|
() => Visibility(
|
||||||
|
visible: controller.isLongTerm.value == false,
|
||||||
|
child: Container(
|
||||||
|
margin: EdgeInsets.only(top: 10.h),
|
||||||
|
child: CustomCellListWidget(
|
||||||
|
children: [
|
||||||
|
CustomCellWidget(
|
||||||
|
onTap: () async {
|
||||||
|
DatePicker.showDatePicker(
|
||||||
|
context,
|
||||||
|
showTitleActions: true,
|
||||||
|
minTime: DateTime.now(),
|
||||||
|
maxTime: DateTime.now().add(const Duration(days: 365 * 20)),
|
||||||
|
onChanged: (date) {},
|
||||||
|
onConfirm: (date) {
|
||||||
|
controller.startDate.value = date.millisecondsSinceEpoch;
|
||||||
|
},
|
||||||
|
currentTime: DateTime.now(),
|
||||||
|
locale: LocaleType.zh,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
leftText: '生效日期'.tr,
|
||||||
|
rightWidget: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Obx(() {
|
||||||
|
String displayText = '请选择';
|
||||||
|
if (controller.startDate.value > 0) {
|
||||||
|
displayText = DateTime.fromMillisecondsSinceEpoch(controller.startDate.value)
|
||||||
|
.toString()
|
||||||
|
.split(' ')[0]; // 只显示日期部分
|
||||||
|
}
|
||||||
|
return Text(
|
||||||
|
displayText,
|
||||||
|
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 {
|
||||||
|
DatePicker.showDatePicker(
|
||||||
|
context,
|
||||||
|
showTitleActions: true,
|
||||||
|
minTime: DateTime.now(),
|
||||||
|
maxTime: DateTime.now().add(const Duration(days: 365 * 20)),
|
||||||
|
onChanged: (date) {},
|
||||||
|
onConfirm: (date) {
|
||||||
|
controller.endDate.value = date.millisecondsSinceEpoch;
|
||||||
|
},
|
||||||
|
currentTime: DateTime.now(),
|
||||||
|
locale: LocaleType.zh,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
leftText: '失效日期'.tr,
|
||||||
|
rightWidget: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Obx(() {
|
||||||
|
String displayText = '请选择';
|
||||||
|
if (controller.endDate.value > 0) {
|
||||||
|
displayText = DateTime.fromMillisecondsSinceEpoch(controller.endDate.value)
|
||||||
|
.toString()
|
||||||
|
.split(' ')[0]; // 只显示日期部分
|
||||||
|
}
|
||||||
|
return Text(
|
||||||
|
displayText,
|
||||||
|
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],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: EdgeInsets.only(top: 10.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8.r)),
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.info_outline,
|
||||||
|
size: 16.sp,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 4.w,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'有效期为通行门禁的生效~失效日期'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 4.h,
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'使用场景举例:',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.sp,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'1.健身卡到期后自动失效无法进入健身房',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.sp,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'2.医院病房,陪护人员到期后自动失效无法通行',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.sp,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (controller.startDate.value == 0 || controller.endDate.value == 0) {
|
||||||
|
controller.showToast('请先选择有效日期'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (controller.startDate.value > controller.endDate.value) {
|
||||||
|
controller.showToast('生效日期不能大于失效日期'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (controller.startDate.value == controller.endDate.value) {
|
||||||
|
controller.showToast('生效日期不能等于失效日期'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Get.back(result: {
|
||||||
|
AppViewParameterKeys.isLongTerm: controller.isLongTerm.value,
|
||||||
|
AppViewParameterKeys.startDate: controller.startDate.value,
|
||||||
|
AppViewParameterKeys.endDate: controller.endDate.value,
|
||||||
|
});
|
||||||
|
}.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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 10.h,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -36,6 +36,8 @@ class PersonnelManageController extends BaseController {
|
|||||||
// 转换数据为树形结构
|
// 转换数据为树形结构
|
||||||
final tree = _convertToTree(response.data!.departList ?? []);
|
final tree = _convertToTree(response.data!.departList ?? []);
|
||||||
treeData.value = tree;
|
treeData.value = tree;
|
||||||
|
|
||||||
|
treeData.refresh();
|
||||||
// 统计总人数
|
// 统计总人数
|
||||||
totalPersonCount.value = _calculateTotalPersonCount(response.data!.departList ?? []);
|
totalPersonCount.value = _calculateTotalPersonCount(response.data!.departList ?? []);
|
||||||
|
|
||||||
@ -114,12 +116,7 @@ class PersonnelManageController extends BaseController {
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
requestCreateDepart() async {
|
|
||||||
var response = await teamApi.requestCreateDepart(
|
|
||||||
request: CreateNewDepartRequest(departName: '测试2', parentDepartNo: '-1', leader: ['CY93685899']),
|
|
||||||
);
|
|
||||||
if (response.isSuccess) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
void getCacheUserInfo() async {
|
void getCacheUserInfo() async {
|
||||||
String? cachedJson = await SharedPreferencesUtils.getString(CacheKeys.userAccountInfo);
|
String? cachedJson = await SharedPreferencesUtils.getString(CacheKeys.userAccountInfo);
|
||||||
|
|||||||
@ -127,204 +127,219 @@ class PersonnelManageView extends GetView<PersonnelManageController> {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Obx(
|
child: Obx(
|
||||||
() => Container(
|
() {
|
||||||
margin: EdgeInsets.symmetric(
|
return Container(
|
||||||
horizontal: 10.w,
|
margin: EdgeInsets.symmetric(
|
||||||
),
|
horizontal: 10.w,
|
||||||
decoration: const BoxDecoration(
|
),
|
||||||
color: Colors.white,
|
decoration: const BoxDecoration(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
color: Colors.white,
|
||||||
),
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
||||||
child: TreeView.simple(
|
),
|
||||||
tree: controller.treeData.value ?? TreeNode.root(),
|
child: RefreshIndicator(
|
||||||
showRootNode: false,
|
onRefresh: () async {
|
||||||
expansionIndicatorBuilder: noExpansionIndicatorBuilder,
|
await controller.requestDepartList();
|
||||||
indentation: const Indentation(style: IndentStyle.roundJoint),
|
},
|
||||||
onItemTap: (item) {},
|
color: const Color(0xFF4A90E2),
|
||||||
onTreeReady: (c) {
|
backgroundColor: Colors.white,
|
||||||
controller.treeViewController = c;
|
displacement: 60.0,
|
||||||
},
|
edgeOffset: 0.0,
|
||||||
builder: (context, node) {
|
triggerMode: RefreshIndicatorTriggerMode.onEdge,
|
||||||
String title = "";
|
strokeWidth: 2.5,
|
||||||
DepartItem departInfo = DepartItem();
|
semanticsLabel: '下拉刷新首页内容',
|
||||||
int personNum = 0;
|
semanticsValue: '刷新中...',
|
||||||
bool hasChildren = node.childrenAsList.isNotEmpty; // 判断是否有子节点
|
child: TreeView.simple(
|
||||||
bool isPersonItem = node.data is PersonItem; // 判断当前节点是否是人员节点
|
tree: controller.treeData.value ?? TreeNode.root(),
|
||||||
bool isOneself = false;
|
showRootNode: false,
|
||||||
bool isRootNode = false;
|
expansionIndicatorBuilder: noExpansionIndicatorBuilder,
|
||||||
bool isSuper = false;
|
indentation: const Indentation(style: IndentStyle.roundJoint),
|
||||||
|
onItemTap: (item) {},
|
||||||
|
onTreeReady: (c) {
|
||||||
|
controller.treeViewController = c;
|
||||||
|
},
|
||||||
|
builder: (context, node) {
|
||||||
|
String title = "";
|
||||||
|
DepartItem departInfo = DepartItem();
|
||||||
|
int personNum = 0;
|
||||||
|
bool hasChildren = node.childrenAsList.isNotEmpty; // 判断是否有子节点
|
||||||
|
bool isPersonItem = node.data is PersonItem; // 判断当前节点是否是人员节点
|
||||||
|
bool isOneself = false;
|
||||||
|
bool isRootNode = false;
|
||||||
|
bool isSuper = false;
|
||||||
|
|
||||||
if (node.data is DepartItem) {
|
if (node.data is DepartItem) {
|
||||||
final depart = node.data as DepartItem;
|
final depart = node.data as DepartItem;
|
||||||
title = depart.departName ?? "未命名部门";
|
title = depart.departName ?? "未命名部门";
|
||||||
personNum = depart.personNum ?? 0;
|
personNum = depart.personNum ?? 0;
|
||||||
departInfo = depart;
|
departInfo = depart;
|
||||||
if (hasChildren) {
|
if (hasChildren) {
|
||||||
title = title + "($personNum)";
|
title = title + "($personNum)";
|
||||||
} else {
|
} else {
|
||||||
title = title + "(0)";
|
title = title + "(0)";
|
||||||
}
|
}
|
||||||
if (depart.parentId == -1) {
|
if (depart.parentId == -1) {
|
||||||
isRootNode = true;
|
isRootNode = true;
|
||||||
}
|
}
|
||||||
} else if (node.data is PersonItem) {
|
} else if (node.data is PersonItem) {
|
||||||
// 处理人员节点
|
// 处理人员节点
|
||||||
final person = node.data as PersonItem;
|
final person = node.data as PersonItem;
|
||||||
title = person.personName ?? "未命名人员";
|
title = person.personName ?? "未命名人员";
|
||||||
var personUserId = person.userId;
|
var personUserId = person.userId;
|
||||||
person.roles?.forEach((role) {
|
person.roles?.forEach((role) {
|
||||||
if (role.isSuper == 1) {
|
if (role.isSuper == 1) {
|
||||||
isSuper = true;
|
isSuper = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (personUserId != null && personUserId == controller.cacheUserInfo.value.id) {
|
||||||
|
isOneself = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
if (personUserId != null && personUserId == controller.cacheUserInfo.value.id) {
|
|
||||||
isOneself = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 6.h),
|
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 6.h),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
!isPersonItem
|
!isPersonItem
|
||||||
? Container(
|
? Container(
|
||||||
width: 34.w,
|
width: 34.w,
|
||||||
height: 34.w,
|
height: 34.w,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey[300],
|
color: Colors.grey[300],
|
||||||
borderRadius: BorderRadius.circular(8.r),
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
child: Icon(
|
||||||
|
Icons.folder,
|
||||||
|
size: 22.w,
|
||||||
|
color: Colors.blue,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Container(
|
||||||
|
width: 34.w,
|
||||||
|
height: 34.w,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[200],
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
child: Image(
|
||||||
|
image: const AssetImage(AppImages.defaultAvatar),
|
||||||
|
width: 22.w,
|
||||||
|
height: 22.w,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
gaplessPlayback: true,
|
||||||
|
filterQuality: FilterQuality.medium,
|
||||||
|
errorBuilder: (context, error, stackTrace) {
|
||||||
|
return Icon(
|
||||||
|
Icons.person,
|
||||||
|
size: 30.sp,
|
||||||
|
color: Colors.grey[400],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 10.w,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.sp,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
child: ClipRRect(
|
maxLines: 1,
|
||||||
borderRadius: BorderRadius.circular(8.r),
|
overflow: TextOverflow.ellipsis,
|
||||||
child: Icon(
|
),
|
||||||
Icons.folder,
|
),
|
||||||
size: 22.w,
|
Visibility(
|
||||||
|
visible: isOneself,
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.blue[50],
|
||||||
|
borderRadius: BorderRadius.circular(4.r),
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.blue,
|
||||||
|
width: 1.w,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'自己',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.sp,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
: Container(
|
),
|
||||||
width: 34.w,
|
Visibility(
|
||||||
height: 34.w,
|
visible: isSuper && isOneself,
|
||||||
|
child: SizedBox(
|
||||||
|
width: 4.w,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Visibility(
|
||||||
|
visible: isSuper,
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey[200],
|
color: Colors.blue[50],
|
||||||
borderRadius: BorderRadius.circular(8.r),
|
borderRadius: BorderRadius.circular(4.r),
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.blue,
|
||||||
|
width: 1.w,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: ClipRRect(
|
child: Text(
|
||||||
borderRadius: BorderRadius.circular(8.r),
|
'超管',
|
||||||
child: Image(
|
style: TextStyle(
|
||||||
image: const AssetImage(AppImages.defaultAvatar),
|
fontSize: 12.sp,
|
||||||
width: 22.w,
|
fontWeight: FontWeight.w400,
|
||||||
height: 22.w,
|
color: Colors.blue,
|
||||||
fit: BoxFit.cover,
|
|
||||||
gaplessPlayback: true,
|
|
||||||
filterQuality: FilterQuality.medium,
|
|
||||||
errorBuilder: (context, error, stackTrace) {
|
|
||||||
return Icon(
|
|
||||||
Icons.person,
|
|
||||||
size: 30.sp,
|
|
||||||
color: Colors.grey[400],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
|
||||||
width: 10.w,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
title,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14.sp,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
),
|
||||||
maxLines: 1,
|
],
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Visibility(
|
|
||||||
visible: isOneself,
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.blue[50],
|
|
||||||
borderRadius: BorderRadius.circular(4.r),
|
|
||||||
border: Border.all(
|
|
||||||
color: Colors.blue,
|
|
||||||
width: 1.w,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
'自己',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12.sp,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
color: Colors.blue,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Visibility(
|
|
||||||
visible: isSuper && isOneself,
|
|
||||||
child: SizedBox(
|
|
||||||
width: 4.w,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Visibility(
|
|
||||||
visible: isSuper,
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.blue[50],
|
|
||||||
borderRadius: BorderRadius.circular(4.r),
|
|
||||||
border: Border.all(
|
|
||||||
color: Colors.blue,
|
|
||||||
width: 1.w,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
'超管',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12.sp,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
color: Colors.blue,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Visibility(
|
|
||||||
visible: !isPersonItem,
|
|
||||||
child: Obx(
|
|
||||||
() => Radio<DepartItem>(
|
|
||||||
value: departInfo,
|
|
||||||
groupValue: controller.selectedDepartItem.value,
|
|
||||||
activeColor: Colors.blue,
|
|
||||||
visualDensity: VisualDensity.compact,
|
|
||||||
onChanged: (value) {
|
|
||||||
controller.selectedDepartItem.value = value as DepartItem;
|
|
||||||
controller.selectedDepartItem.refresh();
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
Visibility(
|
||||||
)
|
visible: !isPersonItem,
|
||||||
],
|
child: Obx(
|
||||||
),
|
() => Radio<DepartItem>(
|
||||||
);
|
value: departInfo,
|
||||||
},
|
groupValue: controller.selectedDepartItem.value,
|
||||||
),
|
activeColor: Colors.blue,
|
||||||
),
|
visualDensity: VisualDensity.compact,
|
||||||
|
onChanged: (value) {
|
||||||
|
controller.selectedDepartItem.value = value as DepartItem;
|
||||||
|
controller.selectedDepartItem.refresh();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 10.h,
|
height: 4.h,
|
||||||
),
|
),
|
||||||
Obx(
|
Obx(
|
||||||
() => Text(
|
() => Text(
|
||||||
@ -337,7 +352,7 @@ class PersonnelManageView extends GetView<PersonnelManageController> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 10.h,
|
height: 4.h,
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
margin: EdgeInsets.symmetric(
|
margin: EdgeInsets.symmetric(
|
||||||
@ -347,14 +362,17 @@ class PersonnelManageView extends GetView<PersonnelManageController> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
if (controller.selectedDepartItem.value.departNo == null) {
|
if (controller.selectedDepartItem.value.departNo == null) {
|
||||||
controller.showToast('请先选择一个组织');
|
controller.showToast('请先选择一个组织');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Get.toNamed(AppRoutes.teamAddPerson, arguments: {
|
var result = await Get.toNamed(AppRoutes.teamAddPerson, arguments: {
|
||||||
AppViewParameterKeys.departItem: controller.selectedDepartItem.value.toJson(),
|
AppViewParameterKeys.departItem: controller.selectedDepartItem.value.toJson(),
|
||||||
});
|
});
|
||||||
|
if (result != null && result == true) {
|
||||||
|
await controller.requestDepartList();
|
||||||
|
}
|
||||||
}.debounce(),
|
}.debounce(),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.blue,
|
backgroundColor: Colors.blue,
|
||||||
@ -379,6 +397,9 @@ class PersonnelManageView extends GetView<PersonnelManageController> {
|
|||||||
controller.showToast('请先选择一个组织');
|
controller.showToast('请先选择一个组织');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Get.toNamed(AppRoutes.teamAddOrganization, arguments: {
|
||||||
|
AppViewParameterKeys.departItem: controller.selectedDepartItem.value.toJson(),
|
||||||
|
});
|
||||||
}.debounce(),
|
}.debounce(),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.grey[50],
|
backgroundColor: Colors.grey[50],
|
||||||
@ -398,7 +419,9 @@ class PersonnelManageView extends GetView<PersonnelManageController> {
|
|||||||
SizedBox(width: 10.w),
|
SizedBox(width: 10.w),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {}.debounce(),
|
onPressed: () {
|
||||||
|
controller.showFunctionNotOpen();
|
||||||
|
}.debounce(),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.grey[50],
|
backgroundColor: Colors.grey[50],
|
||||||
padding: EdgeInsets.symmetric(vertical: 10.h),
|
padding: EdgeInsets.symmetric(vertical: 10.h),
|
||||||
@ -418,7 +441,7 @@ class PersonnelManageView extends GetView<PersonnelManageController> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 10.h,
|
height: 20.h,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -65,7 +65,6 @@ class SelectOrganizationView extends GetView<SelectOrganizationController> {
|
|||||||
expansionIndicatorBuilder: noExpansionIndicatorBuilder,
|
expansionIndicatorBuilder: noExpansionIndicatorBuilder,
|
||||||
indentation: const Indentation(style: IndentStyle.roundJoint),
|
indentation: const Indentation(style: IndentStyle.roundJoint),
|
||||||
onItemTap: (item) {
|
onItemTap: (item) {
|
||||||
AppLogger.highlight('message:${item.data}');
|
|
||||||
if (item.data is DepartItem) {
|
if (item.data is DepartItem) {
|
||||||
Get.back(result: item.data);
|
Get.back(result: item.data);
|
||||||
}
|
}
|
||||||
|
|||||||
10
lib/views/team/selectPerson/select_person_binding.dart
Normal file
10
lib/views/team/selectPerson/select_person_binding.dart
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import 'select_person_controller.dart';
|
||||||
|
|
||||||
|
class SelectPersonBinding extends Bindings {
|
||||||
|
@override
|
||||||
|
void dependencies() {
|
||||||
|
Get.lazyPut(() => SelectPersonController());
|
||||||
|
}
|
||||||
|
}
|
||||||
149
lib/views/team/selectPerson/select_person_controller.dart
Normal file
149
lib/views/team/selectPerson/select_person_controller.dart
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
import 'package:animated_tree_view/animated_tree_view.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:starwork_flutter/api/model/team/request/get_depart_list_request.dart';
|
||||||
|
import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dart';
|
||||||
|
import 'package:starwork_flutter/api/service/team_api_service.dart';
|
||||||
|
import 'package:starwork_flutter/base/base_controller.dart';
|
||||||
|
|
||||||
|
class SelectPersonController extends BaseController {
|
||||||
|
final teamApi = Get.find<TeamApiService>();
|
||||||
|
final Rx<TreeNode?> treeData = Rx<TreeNode?>(null);
|
||||||
|
TreeViewController? treeViewController;
|
||||||
|
|
||||||
|
// 搜索输入框
|
||||||
|
TextEditingController searchInputController = TextEditingController();
|
||||||
|
|
||||||
|
var allPersonList = <PersonItem>[].obs;
|
||||||
|
var selectPersonNoList = <String>[].obs;
|
||||||
|
|
||||||
|
// 存储从参数传递过来的已选角色
|
||||||
|
List<PersonItem>? initialSelectedPersons;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onReady() {
|
||||||
|
super.onReady();
|
||||||
|
// 获取传递的参数
|
||||||
|
var arguments = Get.arguments;
|
||||||
|
if (arguments != null && arguments is List<PersonItem>) {
|
||||||
|
initialSelectedPersons = arguments;
|
||||||
|
}
|
||||||
|
requestDepartList();
|
||||||
|
_setInitialSelectedIndexes();
|
||||||
|
}
|
||||||
|
|
||||||
|
requestDepartList() async {
|
||||||
|
var response = await teamApi.requestDepartList(
|
||||||
|
request: GetDepartListRequest(departNo: ''),
|
||||||
|
);
|
||||||
|
if (response.isSuccess) {
|
||||||
|
// 转换数据为树形结构
|
||||||
|
final tree = _convertToTree(response.data!.departList ?? []);
|
||||||
|
treeData.value = tree;
|
||||||
|
// 提取所有人员信息并更新 personList
|
||||||
|
final allPersons = extractAllPersons();
|
||||||
|
allPersonList.value = allPersons;
|
||||||
|
|
||||||
|
treeViewController?.expandAllChildren(treeData.value ?? TreeNode.root());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode _convertToTree(List<DepartItem> departList) {
|
||||||
|
// 创建根节点
|
||||||
|
final root = TreeNode.root();
|
||||||
|
|
||||||
|
// 如果列表为空,直接返回根节点
|
||||||
|
if (departList.isEmpty) {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个映射来存储所有部门节点,方便查找
|
||||||
|
final Map<int, TreeNode> departNodeMap = {};
|
||||||
|
|
||||||
|
// 先创建所有部门节点
|
||||||
|
for (final depart in departList) {
|
||||||
|
final node = TreeNode(
|
||||||
|
key: depart.id.toString(),
|
||||||
|
data: depart,
|
||||||
|
);
|
||||||
|
departNodeMap[depart.id!] = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 建立部门间的父子关系
|
||||||
|
for (final depart in departList) {
|
||||||
|
final currentNode = departNodeMap[depart.id];
|
||||||
|
if (currentNode == null) continue;
|
||||||
|
|
||||||
|
// 建立部门间的父子关系
|
||||||
|
if (depart.parentId == -1) {
|
||||||
|
// 顶级部门添加到根节点下
|
||||||
|
root.add(currentNode);
|
||||||
|
} else {
|
||||||
|
// 子部门添加到对应父部门下
|
||||||
|
final parentNode = departNodeMap[depart.parentId];
|
||||||
|
parentNode?.add(currentNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将人员节点添加到对应的部门节点下(在所有部门结构建立完成后再添加)
|
||||||
|
for (final depart in departList) {
|
||||||
|
final currentNode = departNodeMap[depart.id];
|
||||||
|
if (currentNode == null) continue;
|
||||||
|
|
||||||
|
// 将该部门下的所有人员作为子节点添加
|
||||||
|
if (depart.persons != null && depart.persons!.isNotEmpty) {
|
||||||
|
// 对人员按某种规则排序(例如按姓名或ID)
|
||||||
|
final sortedPersons = List<PersonItem>.from(depart.persons!);
|
||||||
|
// 这里可以根据需要添加排序逻辑,例如按姓名排序:
|
||||||
|
// sortedPersons.sort((a, b) => (a.personName ?? '').compareTo(b.personName ?? ''));
|
||||||
|
|
||||||
|
for (final person in sortedPersons) {
|
||||||
|
final personNode = TreeNode(
|
||||||
|
key: 'person_${person.id}',
|
||||||
|
data: person,
|
||||||
|
);
|
||||||
|
currentNode.add(personNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取所有人员信息的方法
|
||||||
|
List<PersonItem> extractAllPersons() {
|
||||||
|
final List<PersonItem> persons = [];
|
||||||
|
|
||||||
|
// 递归遍历树节点
|
||||||
|
void traverseTree(TreeNode? node) {
|
||||||
|
if (node == null) return;
|
||||||
|
|
||||||
|
// 如果当前节点是人员节点,添加到列表中
|
||||||
|
if (node.data is PersonItem) {
|
||||||
|
persons.add(node.data as PersonItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归遍历所有子节点
|
||||||
|
for (final child in node.childrenAsList) {
|
||||||
|
traverseTree(child as TreeNode?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从根节点开始遍历
|
||||||
|
traverseTree(treeData.value);
|
||||||
|
|
||||||
|
return persons;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据初始选中的角色设置对应的索引
|
||||||
|
void _setInitialSelectedIndexes() {
|
||||||
|
if (initialSelectedPersons != null && initialSelectedPersons!.isNotEmpty) {
|
||||||
|
for (var selectedPerson in initialSelectedPersons!) {
|
||||||
|
if (!selectPersonNoList.contains(selectedPerson.personNo)) {
|
||||||
|
selectPersonNoList.add(selectedPerson.personNo!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectPersonNoList.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
332
lib/views/team/selectPerson/select_person_view.dart
Normal file
332
lib/views/team/selectPerson/select_person_view.dart
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
import 'package:animated_tree_view/animated_tree_view.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dart';
|
||||||
|
import 'package:starwork_flutter/base/app_logger.dart';
|
||||||
|
import 'package:starwork_flutter/common/constant/app_colors.dart';
|
||||||
|
import 'package:starwork_flutter/common/constant/app_images.dart';
|
||||||
|
import 'package:starwork_flutter/common/widgets/custome_app_bar_wdiget.dart';
|
||||||
|
import 'package:starwork_flutter/extension/function_extension.dart';
|
||||||
|
import 'select_person_controller.dart';
|
||||||
|
|
||||||
|
class SelectPersonView extends GetView<SelectPersonController> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.scaffoldBackgroundColor,
|
||||||
|
appBar: CustomAppBarWidget(
|
||||||
|
title: '选择用户'.tr,
|
||||||
|
backgroundColor: AppColors.scaffoldBackgroundColor,
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.clear_rounded,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10.w,
|
||||||
|
vertical: 10.h,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
_buildSearchBar(),
|
||||||
|
SizedBox(
|
||||||
|
height: 10.h,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
'组织架构',
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12.sp,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 10.h,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Obx(
|
||||||
|
() {
|
||||||
|
return Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
||||||
|
),
|
||||||
|
child: RefreshIndicator(
|
||||||
|
onRefresh: () async {
|
||||||
|
await controller.requestDepartList();
|
||||||
|
},
|
||||||
|
color: const Color(0xFF4A90E2),
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
displacement: 60.0,
|
||||||
|
edgeOffset: 0.0,
|
||||||
|
triggerMode: RefreshIndicatorTriggerMode.onEdge,
|
||||||
|
strokeWidth: 2.5,
|
||||||
|
semanticsLabel: '下拉刷新首页内容',
|
||||||
|
semanticsValue: '刷新中...',
|
||||||
|
child: TreeView.simple(
|
||||||
|
tree: controller.treeData.value ?? TreeNode.root(),
|
||||||
|
showRootNode: false,
|
||||||
|
expansionIndicatorBuilder: noExpansionIndicatorBuilder,
|
||||||
|
indentation: const Indentation(style: IndentStyle.roundJoint),
|
||||||
|
onItemTap: (item) {
|
||||||
|
if (item.data is PersonItem) {
|
||||||
|
PersonItem personInfo = item.data;
|
||||||
|
// 避免重复添加
|
||||||
|
if (!controller.selectPersonNoList.contains(personInfo.personNo) &&
|
||||||
|
personInfo.personNo != null) {
|
||||||
|
controller.selectPersonNoList.add(personInfo.personNo!);
|
||||||
|
} else {
|
||||||
|
controller.selectPersonNoList.remove(personInfo.personNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.selectPersonNoList.refresh();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onTreeReady: (c) {
|
||||||
|
controller.treeViewController = c;
|
||||||
|
},
|
||||||
|
builder: (context, node) {
|
||||||
|
String title = "";
|
||||||
|
DepartItem departInfo = DepartItem();
|
||||||
|
PersonItem personInfo = PersonItem();
|
||||||
|
int personNum = 0;
|
||||||
|
bool hasChildren = node.childrenAsList.isNotEmpty; // 判断是否有子节点
|
||||||
|
bool isPersonItem = node.data is PersonItem; // 判断当前节点是否是人员节点
|
||||||
|
bool isOneself = false;
|
||||||
|
bool isRootNode = false;
|
||||||
|
bool isSuper = false;
|
||||||
|
|
||||||
|
if (node.data is DepartItem) {
|
||||||
|
final depart = node.data as DepartItem;
|
||||||
|
title = depart.departName ?? "未命名部门";
|
||||||
|
personNum = depart.personNum ?? 0;
|
||||||
|
departInfo = depart;
|
||||||
|
if (hasChildren) {
|
||||||
|
title = title + "($personNum)";
|
||||||
|
} else {
|
||||||
|
title = title + "(0)";
|
||||||
|
}
|
||||||
|
if (depart.parentId == -1) {
|
||||||
|
isRootNode = true;
|
||||||
|
}
|
||||||
|
} else if (node.data is PersonItem) {
|
||||||
|
// 处理人员节点
|
||||||
|
personInfo = node.data as PersonItem;
|
||||||
|
title = personInfo.personName ?? "未命名人员";
|
||||||
|
|
||||||
|
personInfo.roles?.forEach((role) {
|
||||||
|
if (role.isSuper == 1) {
|
||||||
|
isSuper = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 6.h),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
!isPersonItem
|
||||||
|
? Container(
|
||||||
|
width: 34.w,
|
||||||
|
height: 34.w,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[300],
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
child: Icon(
|
||||||
|
Icons.folder,
|
||||||
|
size: 22.w,
|
||||||
|
color: Colors.blue,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Container(
|
||||||
|
width: 34.w,
|
||||||
|
height: 34.w,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[200],
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8.r),
|
||||||
|
child: Image(
|
||||||
|
image: const AssetImage(AppImages.defaultAvatar),
|
||||||
|
width: 22.w,
|
||||||
|
height: 22.w,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
gaplessPlayback: true,
|
||||||
|
filterQuality: FilterQuality.medium,
|
||||||
|
errorBuilder: (context, error, stackTrace) {
|
||||||
|
return Icon(
|
||||||
|
Icons.person,
|
||||||
|
size: 30.sp,
|
||||||
|
color: Colors.grey[400],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 10.w,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.sp,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Visibility(
|
||||||
|
visible: isPersonItem,
|
||||||
|
child: Obx(
|
||||||
|
() => Checkbox(
|
||||||
|
value: controller.selectPersonNoList.contains(personInfo.personNo),
|
||||||
|
activeColor: Colors.blue,
|
||||||
|
onChanged: (value) {
|
||||||
|
if (value == true) {
|
||||||
|
// 避免重复添加
|
||||||
|
if (!controller.selectPersonNoList.contains(personInfo.personNo) &&
|
||||||
|
personInfo.id != null) {
|
||||||
|
controller.selectPersonNoList.add(personInfo.personNo!);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
controller.selectPersonNoList.remove(personInfo.personNo);
|
||||||
|
}
|
||||||
|
controller.selectPersonNoList.refresh();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 10.h,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Obx(
|
||||||
|
() => Text(
|
||||||
|
'已选择:${controller.selectPersonNoList.length}人',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14.sp,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: Colors.blue,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 20.w,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (controller.selectPersonNoList.isEmpty) {
|
||||||
|
controller.showToast('请先选择一个用户'.tr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<PersonItem> selectPersonList = [];
|
||||||
|
// 通过controller.selectPersonNoList 判断controoler.allPersonList对应选中的personInfo
|
||||||
|
controller.selectPersonNoList.forEach((personNo) {
|
||||||
|
controller.allPersonList.forEach((personInfo) {
|
||||||
|
if (personInfo.personNo == personNo) {
|
||||||
|
selectPersonList.add(personInfo);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Get.back(result: selectPersonList);
|
||||||
|
}.debounce(),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Colors.blue,
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 12.h),
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'确定'.tr,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16.sp,
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildSearchBar() {
|
||||||
|
return TextField(
|
||||||
|
controller: controller.searchInputController,
|
||||||
|
textInputAction: TextInputAction.search,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: '请输入设备名称'.tr,
|
||||||
|
hintStyle: TextStyle(
|
||||||
|
fontSize: 14.sp,
|
||||||
|
color: const Color(0xFF999999),
|
||||||
|
),
|
||||||
|
prefixIcon: const Icon(
|
||||||
|
Icons.search,
|
||||||
|
color: Color(0xFF999999),
|
||||||
|
),
|
||||||
|
filled: true,
|
||||||
|
// 启用背景填充
|
||||||
|
fillColor: const Color(0xFFf0f0f0),
|
||||||
|
// 灰色背景(可调整色值)
|
||||||
|
border: InputBorder.none,
|
||||||
|
// 设置内边距
|
||||||
|
contentPadding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: Colors.blue,
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8.0.r),
|
||||||
|
),
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(color: Colors.transparent),
|
||||||
|
borderRadius: BorderRadius.circular(8.0.r),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -230,6 +230,14 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.1"
|
version: "5.0.1"
|
||||||
|
flutter_datetime_picker_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_datetime_picker_plus
|
||||||
|
sha256: "7d82da02c4e070bb28a9107de119ad195e2319b45c786fecc13482a9ffcc51da"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.0"
|
||||||
flutter_easyloading:
|
flutter_easyloading:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@ -40,6 +40,7 @@ dependencies:
|
|||||||
event_bus: ^2.0.1
|
event_bus: ^2.0.1
|
||||||
# 选择器
|
# 选择器
|
||||||
flutter_picker: ^2.1.0
|
flutter_picker: ^2.1.0
|
||||||
|
flutter_datetime_picker_plus: ^2.2.0
|
||||||
# 星云sdk
|
# 星云sdk
|
||||||
starcloud:
|
starcloud:
|
||||||
path: ../starcloud-sdk-flutter
|
path: ../starcloud-sdk-flutter
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user