feat: 增加组织架构、人员管理、角色管理、添加角色

This commit is contained in:
liyi 2025-09-29 17:11:08 +08:00
parent abe49031ac
commit 9b4d112825
43 changed files with 3123 additions and 471 deletions

View File

@ -1,6 +1,7 @@
class ApiPath {
static const String sendValidationCode = "/v1/common/sendValidationCode";
static const String validationCodeLogin = "/v1/user/codeLogin";
static const String userDetail = "/v1/user/detail";
static const String passwordLogin = "/v1/user/pwdLogin";
static const String allTeamList = "/v1/team/teamListAll";
static const String sceneList = "/v1/team/sceneList";
@ -9,4 +10,10 @@ class ApiPath {
static const String bindTeamStarCloudAccount = "/v1/team/bindStarCloudAccount";
static const String updateTeamInfo = "/v1/team/updateTeam";
static const String getInviteInfo = "/v1/team/getInviteInfo";
static const String getTeamInviteConfig = "/v1/team/teamApplyConfig";
static const String updateTeamInviteConfig = "/v1/team/teamPersonConfigUpdate";
static const String departList = "/v1/team/departList";
static const String departCreate = "/v1/team/departCreate";
static const String roleList = "/v1/team/roleList";
static const String roleCreate = "/v1/team/roleCreate";
}

View File

@ -0,0 +1,32 @@
class CreateNewDepartRequest {
String departName;
String parentDepartNo;
List<String> leader;
CreateNewDepartRequest({
required this.departName,
required this.parentDepartNo,
required this.leader,
});
Map<String, dynamic> toJson() {
return {
"departName": departName,
"parentDepartNo": parentDepartNo,
"leader": leader,
};
}
static CreateNewDepartRequest fromJson(Map<String, dynamic> json) {
return CreateNewDepartRequest(
departName: json["departName"],
parentDepartNo: json["parentDepartNo"],
leader: json["leader"],
);
}
@override
String toString() {
return 'CreateNewDepartRequest{departName: $departName, parentDepartNo: $parentDepartNo, leader: $leader}';
}
}

View File

@ -0,0 +1,32 @@
class CreateNewRoleRequest {
String roleName; //
String? roleDesc; //
List<String>? personNos; //
CreateNewRoleRequest({
required this.roleName, // 使 required
this.roleDesc, // 使 required
this.personNos, // 使 required
});
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['roleName'] = roleName;
// null JSON
if (roleDesc != null) {
data['roleDesc'] = roleDesc;
}
if (personNos != null) {
data['personNos'] = personNos;
}
return data;
}
@override
String toString() {
return 'CreateNewRoleRequest{roleName: $roleName, roleDesc: $roleDesc, personNos: $personNos}';
}
}

View File

@ -0,0 +1,19 @@
class GetDepartListRequest {
String departNo;
GetDepartListRequest({
required this.departNo,
});
Map<String, dynamic> toJson() {
return {
"departNo": departNo,
};
}
factory GetDepartListRequest.fromJson(Map<String, dynamic> json) {
return GetDepartListRequest(
departNo: json['departNo'],
);
}
}

View File

@ -0,0 +1,18 @@
class RoleListRequest {
String teamNo;
RoleListRequest({
required this.teamNo,
});
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['teamNo'] = teamNo;
return data;
}
@override
String toString() {
return 'RoleListRequest{teamNo: $teamNo}';
}
}

View File

@ -0,0 +1,27 @@
class UpdateInviteParameterConfigRequest {
final int joinTeamInputFace;
final int applyJoinTeamAudit;
final int teamInviteUserValidFalse;
UpdateInviteParameterConfigRequest({
required this.joinTeamInputFace,
required this.applyJoinTeamAudit,
required this.teamInviteUserValidFalse,
});
Map<String, dynamic> toJson() {
return {
"joinTeamInputFace": joinTeamInputFace,
"applyJoinTeamAudit": applyJoinTeamAudit,
"teamInviteUserValidFalse": teamInviteUserValidFalse,
};
}
factory UpdateInviteParameterConfigRequest.fromJson(Map<String, dynamic> json) {
return UpdateInviteParameterConfigRequest(
joinTeamInputFace: json['joinTeamInputFace'] as int,
applyJoinTeamAudit: json['applyJoinTeamAudit'] as int,
teamInviteUserValidFalse: json['teamInviteUserValidFalse'] as int,
);
}
}

View File

@ -0,0 +1,170 @@
import 'package:starwork_flutter/api/model/team/response/role_list_response.dart';
class DepartListResponse {
final List<DepartItem>? departList;
DepartListResponse({this.departList});
factory DepartListResponse.fromJson(Map<String, dynamic> json) {
if (json['departList'] == null) {
return DepartListResponse(departList: []);
}
final List<dynamic> list = json['departList'];
return DepartListResponse(
departList: list.map((item) => DepartItem.fromJson(item as Map<String, dynamic>)).toList(),
);
}
Map<String, dynamic> toJson() {
return {
'departList': departList?.map((item) => item.toJson()).toList(),
};
}
@override
String toString() {
return 'DepartListResponse{departList: $departList}';
}
}
class DepartItem {
final int? id;
final String? teamNo;
final String? departNo;
final String? departName;
final int? parentId;
final PersonItem? leader;
final int? level;
final int? sort;
final bool? hasLeaf;
final int? personNum;
final List<PersonItem>? persons; //
DepartItem({
this.id,
this.teamNo,
this.departNo,
this.departName,
this.parentId,
this.leader,
this.level,
this.sort,
this.hasLeaf,
this.personNum,
this.persons,
});
factory DepartItem.fromJson(Map<String, dynamic> json) {
List<PersonItem>? personsList;
if (json['persons'] != null && json['persons'] is List) {
personsList = (json['persons'] as List).map((item) => PersonItem.fromJson(item as Map<String, dynamic>)).toList();
}
// leader PersonItem
PersonItem? leaderItem;
if (json['leader'] != null && json['leader'] is Map) {
try {
leaderItem = PersonItem.fromJson(json['leader'] as Map<String, dynamic>);
} catch (e) {
// leaderItem null
leaderItem = null;
}
}
return DepartItem(
id: json['id'] as int?,
teamNo: json['teamNo'] as String?,
departNo: json['departNo'] as String?,
departName: json['departName'] as String?,
parentId: json['parentId'] as int?,
leader: leaderItem,
level: json['level'] as int?,
sort: json['sort'] as int?,
hasLeaf: json['hasLeaf'] as bool?,
personNum: json['personNum'] as int?,
persons: personsList,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'teamNo': teamNo,
'departNo': departNo,
'departName': departName,
'parentId': parentId,
'leader': leader?.toJson(), // leader
'level': level,
'sort': sort,
'hasLeaf': hasLeaf,
'personNum': personNum,
'persons': persons?.map((item) => item.toJson()).toList(),
};
}
@override
String toString() {
return 'DepartItem{id: $id, teamNo: $teamNo, departNo: $departNo, departName: $departName, parentId: $parentId, leader: $leader, level: $level, sort: $sort, hasLeaf: $hasLeaf, personNum: $personNum, persons: $persons}';
}
}
// PersonItem
class PersonItem {
final int? id;
final String? personName;
final int? userId;
final int? jobNumber;
final int? sex;
final String? personNo;
final String? phone;
final List<RoleListResponse>? roles;
PersonItem({
this.id,
this.personName,
this.userId,
this.jobNumber,
this.sex,
this.personNo,
this.phone,
this.roles,
});
factory PersonItem.fromJson(Map<String, dynamic> json) {
List<RoleListResponse>? rolesList;
if (json['roles'] != null && json['roles'] is List) {
rolesList = (json['roles'] as List)
.map((item) => RoleListResponse.fromJson(item as Map<String, dynamic>))
.toList();
}
return PersonItem(
id: json['id'] as int?,
personName: json['personName'] as String?,
userId: json['userId'] as int?,
jobNumber: json['jobNumber'] as int?,
sex: json['sex'] as int?,
personNo: json['personNo'] as String?,
phone: json['phone'] as String?,
roles: rolesList,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'personName': personName,
'userId': userId,
'jobNumber': jobNumber,
'sex': sex,
'personNo': personNo,
'phone': phone,
'roles': roles?.map((item) => item.toJson()).toList(),
};
}
@override
String toString() {
return 'PersonItem{id: $id, personName: $personName, userId: $userId, jobNumber: $jobNumber, sex: $sex, personNo: $personNo, phone: $phone, roles: $roles}';
}
}

View File

@ -0,0 +1,79 @@
import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dart';
class RoleListResponse {
int? id;
String? teamNo;
String? roleName;
String? roleDesc;
int? roleStatus;
String? roleStatusName;
int? isDefault;
int? isSuper;
int? isOperationRole;
List<PersonItem>? personList; // personList
RoleListResponse({
this.id,
this.teamNo,
this.roleName,
this.roleDesc,
this.roleStatus,
this.roleStatusName,
this.isDefault,
this.isSuper,
this.isOperationRole,
});
RoleListResponse.fromJson(Map<String, dynamic> json) {
id = json['id'];
teamNo = json['teamNo'];
roleName = json['roleName'];
roleDesc = json['roleDesc'];
roleStatus = json['roleStatus'];
roleStatusName = json['roleStatusName'];
isDefault = json['isDefault'];
isSuper = json['isSuper'];
isOperationRole = json['isOperationRole'];
// personList
if (json['personList'] != null && json['personList'] is List) {
personList = (json['personList'] as List)
.map((item) => PersonItem.fromJson(item as Map<String, dynamic>))
.toList();
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['teamNo'] = teamNo;
data['roleName'] = roleName;
data['roleDesc'] = roleDesc;
data['roleStatus'] = roleStatus;
data['roleStatusName'] = roleStatusName;
data['isDefault'] = isDefault;
data['isSuper'] = isSuper;
data['isOperationRole'] = isOperationRole;
// personList
if (personList != null) {
data['personList'] = personList!.map((item) => item.toJson()).toList();
}
return data;
}
// List<Map<String, dynamic>>
static List<Map<String, dynamic>> toJsonList(List<RoleListResponse> items) {
return items.map((item) => item.toJson()).toList();
}
// List<dynamic> List<RoleListResponse>
static List<RoleListResponse> fromJsonList(List<dynamic> jsonList) {
return jsonList.map((item) => RoleListResponse.fromJson(item as Map<String, dynamic>)).toList();
}
@override
String toString() {
return 'RoleListResponse{id: $id, teamNo: $teamNo, roleName: $roleName, roleDesc: $roleDesc, roleStatus: $roleStatus, roleStatusName: $roleStatusName, isDefault: $isDefault, isSuper: $isSuper, isOperationRole: $isOperationRole}';
}
}

View File

@ -0,0 +1,36 @@
class TeamInviteParameterConfigResponse {
String? teamNo;
int? applyJoinTeamAudit;
int? joinTeamInputFace;
int? teamInviteUserValidFalse;
TeamInviteParameterConfigResponse({
this.teamNo,
this.applyJoinTeamAudit,
this.joinTeamInputFace,
this.teamInviteUserValidFalse,
});
factory TeamInviteParameterConfigResponse.fromJson(Map<String, dynamic> json) {
return TeamInviteParameterConfigResponse(
teamNo: json['teamNo'] as String?,
applyJoinTeamAudit: json['applyJoinTeamAudit'] as int?,
joinTeamInputFace: json['joinTeamInputFace'] as int?,
teamInviteUserValidFalse: json['teamInviteUserValidFalse'] as int?,
);
}
Map<String, dynamic> toJson() {
return {
'teamNo': teamNo,
'applyJoinTeamAudit': applyJoinTeamAudit,
'joinTeamInputFace': joinTeamInputFace,
'teamInviteUserValidFalse': teamInviteUserValidFalse,
};
}
@override
String toString() {
return 'TeamInviteParameterConfigResponse{teamNo: $teamNo, applyJoinTeamAudit: $applyJoinTeamAudit, joinTeamInputFace: $joinTeamInputFace, teamInviteUserValidFalse: $teamInviteUserValidFalse}';
}
}

View File

@ -0,0 +1,132 @@
class UserInfoResponse {
final int? id;
final String? accountNo;
final String? countryCode;
final String? phone;
final String? nickname;
final String? headUrl;
final String? createdAt;
final String? lastLoginTime;
final String? currentTeamNo;
final List<TeamInfo>? teamList;
UserInfoResponse({
this.id,
this.accountNo,
this.countryCode,
this.phone,
this.nickname,
this.headUrl,
this.createdAt,
this.lastLoginTime,
this.currentTeamNo,
this.teamList,
});
factory UserInfoResponse.fromJson(Map<String, dynamic> json) {
List<TeamInfo>? teamList;
if (json['teamList'] != null && json['teamList'] is List) {
teamList = (json['teamList'] as List)
.map((item) => TeamInfo.fromJson(item as Map<String, dynamic>))
.toList();
}
return UserInfoResponse(
id: json['id'] as int?,
accountNo: json['accountNo'] as String?,
countryCode: json['countryCode'] as String?,
phone: json['phone'] as String?,
nickname: json['nickname'] as String?,
headUrl: json['headUrl'] as String?,
createdAt: json['createdAt'] as String?,
lastLoginTime: json['lastLoginTime'] as String?,
currentTeamNo: json['currentTeamNo'] as String?,
teamList: teamList,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'accountNo': accountNo,
'countryCode': countryCode,
'phone': phone,
'nickname': nickname,
'headUrl': headUrl,
'createdAt': createdAt,
'lastLoginTime': lastLoginTime,
'currentTeamNo': currentTeamNo,
'teamList': teamList?.map((item) => item.toJson()).toList(),
};
}
@override
String toString() {
return 'UserInfoResponse{id: $id, accountNo: $accountNo, countryCode: $countryCode, phone: $phone, nickname: $nickname, headUrl: $headUrl, createdAt: $createdAt, lastLoginTime: $lastLoginTime, currentTeamNo: $currentTeamNo, teamList: $teamList}';
}
}
class TeamInfo {
final int? id;
final String? teamNo;
final String? teamName;
final String? teamCode;
final String? owner;
final String? createdAt;
final int? scene;
final String? sceneCustomName;
final String? personNo;
final String? personName;
final bool? isOwner;
TeamInfo({
this.id,
this.teamNo,
this.teamName,
this.teamCode,
this.owner,
this.createdAt,
this.scene,
this.sceneCustomName,
this.personNo,
this.personName,
this.isOwner,
});
factory TeamInfo.fromJson(Map<String, dynamic> json) {
return TeamInfo(
id: json['id'] as int?,
teamNo: json['teamNo'] as String?,
teamName: json['teamName'] as String?,
teamCode: json['teamCode'] as String?,
owner: json['owner'] as String?,
createdAt: json['createdAt'] as String?,
scene: json['scene'] as int?,
sceneCustomName: json['sceneCustomName'] as String?,
personNo: json['personNo'] as String?,
personName: json['personName'] as String?,
isOwner: json['isOwner'] as bool?,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'teamNo': teamNo,
'teamName': teamName,
'teamCode': teamCode,
'owner': owner,
'createdAt': createdAt,
'scene': scene,
'sceneCustomName': sceneCustomName,
'personNo': personNo,
'personName': personName,
'isOwner': isOwner,
};
}
@override
String toString() {
return 'TeamInfo{id: $id, teamNo: $teamNo, teamName: $teamName, teamCode: $teamCode, owner: $owner, createdAt: $createdAt, scene: $scene, sceneCustomName: $sceneCustomName, personNo: $personNo, personName: $personName, isOwner: $isOwner}';
}
}

View File

@ -4,13 +4,21 @@ import 'package:starwork_flutter/api/api_response.dart';
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/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_role_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/invite_info_request.dart';
import 'package:starwork_flutter/api/model/team/request/role_list_request.dart';
import 'package:starwork_flutter/api/model/team/request/update_invite_parameter_config_request.dart';
import 'package:starwork_flutter/api/model/team/request/update_team_info_request.dart';
import 'package:starwork_flutter/api/model/team/response/all_team_list_response.dart';
import 'package:starwork_flutter/api/model/team/response/create_team_response.dart';
import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dart';
import 'package:starwork_flutter/api/model/team/response/invite_info_response.dart';
import 'package:starwork_flutter/api/model/team/response/role_list_response.dart';
import 'package:starwork_flutter/api/model/team/response/scene_info_response.dart';
import 'package:starwork_flutter/api/model/team/response/team_invite_parameter_config_response.dart';
import 'package:starwork_flutter/api/model/user/request/validation_code_login.dart';
import 'package:starwork_flutter/api/model/user/response/token_response.dart';
import 'package:starwork_flutter/common/constant/http_constant.dart';
@ -25,7 +33,6 @@ class TeamApiService {
required CreateTeamRequest request,
}) {
return _api.makeRequest(
//
path: ApiPath.createTeam,
method: HttpConstant.post,
data: request.toJson(),
@ -36,7 +43,6 @@ class TeamApiService {
//
Future<ApiResponse<AllTeamListResponse>> requestAllTeamInfoList() {
return _api.makeRequest(
//
path: ApiPath.allTeamList,
method: HttpConstant.post,
fromJson: (data) => AllTeamListResponse.fromJson(data),
@ -46,7 +52,6 @@ class TeamApiService {
// 使
Future<ApiResponse<SceneInfoResponseList>> requestAllSceneInfoList() {
return _api.makeRequest(
//
path: ApiPath.sceneList,
method: HttpConstant.post,
fromJson: (data) => SceneInfoResponseList.fromJson(data),
@ -58,7 +63,6 @@ class TeamApiService {
required ChangeCurrentTeamRequest request,
}) {
return _api.makeRequest(
//
path: ApiPath.changeTeam,
method: HttpConstant.post,
data: request.toJson(),
@ -71,7 +75,6 @@ class TeamApiService {
required BindTeamStarCloudAccountRequest request,
}) {
return _api.makeRequest(
//
path: ApiPath.bindTeamStarCloudAccount,
method: HttpConstant.post,
data: request.toJson(),
@ -84,7 +87,6 @@ class TeamApiService {
required UpdateTeamInfoRequest request,
}) {
return _api.makeRequest(
//
path: ApiPath.updateTeamInfo,
method: HttpConstant.post,
data: request.toJson(),
@ -97,11 +99,76 @@ class TeamApiService {
required InviteInfoRequest request,
}) {
return _api.makeRequest(
//
path: ApiPath.getInviteInfo,
method: HttpConstant.post,
data: request.toJson(),
fromJson: (data) => InviteInfoResponse.fromJson(data),
);
}
//
Future<ApiResponse<TeamInviteParameterConfigResponse>> requestInviteParameterConfig() {
return _api.makeRequest(
path: ApiPath.getTeamInviteConfig,
method: HttpConstant.post,
fromJson: (data) => TeamInviteParameterConfigResponse.fromJson(data),
);
}
//
Future<ApiResponse<void>> requestUpdateInviteParameterConfig({
required UpdateInviteParameterConfigRequest request,
}) {
return _api.makeRequest(
path: ApiPath.updateTeamInviteConfig,
method: HttpConstant.post,
data: request.toJson(),
fromJson: (data) {},
);
}
//
Future<ApiResponse<DepartListResponse>> requestDepartList({
required GetDepartListRequest request,
}) {
return _api.makeRequest(
path: ApiPath.departList,
method: HttpConstant.post,
data: request.toJson(),
fromJson: (data) => DepartListResponse.fromJson(data),
);
}
//
Future<ApiResponse<void>> requestCreateDepart({
required CreateNewDepartRequest request,
}) {
return _api.makeRequest(
path: ApiPath.departCreate,
method: HttpConstant.post,
data: request.toJson(),
fromJson: (data) {},
);
}
//
Future<ApiResponse<List<RoleListResponse>>> requestTeamRoleList() {
return _api.makeRequest(
path: ApiPath.roleList,
method: HttpConstant.post,
fromJson: (data) => RoleListResponse.fromJsonList(data),
);
}
//
Future<ApiResponse<void>> requestCreateTeamRole({
required CreateNewRoleRequest request,
}) {
return _api.makeRequest(
path: ApiPath.roleCreate,
method: HttpConstant.post,
data: request.toJson(),
fromJson: (data) {},
);
}
}

View File

@ -4,6 +4,7 @@ import 'package:starwork_flutter/api/api_response.dart';
import 'package:starwork_flutter/api/base_api_service.dart';
import 'package:starwork_flutter/api/model/user/request/validation_code_login.dart';
import 'package:starwork_flutter/api/model/user/response/token_response.dart';
import 'package:starwork_flutter/api/model/user/response/user_info_response.dart';
import 'package:starwork_flutter/common/constant/http_constant.dart';
class UserApiService {
@ -23,4 +24,14 @@ class UserApiService {
fromJson: (data) => LoginResponse.fromJson(data),
);
}
//
Future<ApiResponse<UserInfoResponse>> requestUserInfo() {
return _api.makeRequest(
//
path: ApiPath.userDetail,
method: HttpConstant.post,
fromJson: (data) => UserInfoResponse.fromJson(data),
);
}
}

View File

@ -40,14 +40,14 @@ class _AppState extends State<App> {
checkboxTheme: CheckboxThemeData(
side: const BorderSide(
color: Colors.grey,
width: 1, //
width: 0.5, //
),
visualDensity: VisualDensity.compact,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.r),
borderRadius: BorderRadius.circular(10.r),
),
checkColor: MaterialStateProperty.all(Colors.white),
fillColor: MaterialStateProperty.all(Colors.blue),
fillColor: MaterialStateProperty.all(Colors.white),
),
appBarTheme: AppBarTheme(
backgroundColor: Colors.white,

View File

@ -3,5 +3,6 @@ class AppViewParameterKeys {
static const String lockInfo = "lockInfo";
static const String networkInfo = "networkInfo";
static const String teamInfo = "teamInfo";
static const String departItem = "departItem";
}

View File

@ -8,5 +8,6 @@ class CacheKeys {
static const String starCloudPassword = 'starCloudPassword';
static const String starCloudUid = 'starCloudUid';
static const String starCloudUserLoginInfo = 'starCloudUserLoginInfo';
static const String userAccountInfo = 'userAccountInfo';
}

View File

@ -21,7 +21,7 @@ class F {
// Release环境的API地址
switch (appFlavor) {
case Flavor.sky:
return 'https://192.168.1.138:8112/api'; // API
return 'https://192.168.1.137:8112/api'; // API
case Flavor.xhj:
return 'https://api.xhjcn.ltd/api'; // API
}
@ -29,7 +29,7 @@ class F {
// Debug/Profile环境的API地址
switch (appFlavor) {
case Flavor.sky:
return 'http://192.168.1.138:8112/api';
return 'http://192.168.1.137:8112/api';
case Flavor.xhj:
return 'https://loacl.work.star-lock.cn/api';
}
@ -67,7 +67,7 @@ class F {
// Debug/Profile环境的StarCloud地址
switch (appFlavor) {
case Flavor.sky:
return 'http://192.168.1.138:8111/sdk';
return 'http://192.168.1.137:8111/sdk';
case Flavor.xhj:
return 'http://local.cloud.star-lock.cn';
}

View File

@ -36,12 +36,22 @@ import 'package:starwork_flutter/views/main/main_binding.dart';
import 'package:starwork_flutter/views/main/main_view.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/selectRole/select_role_binding.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_view.dart';
import 'package:starwork_flutter/views/team/inviteTeamMember/invitationSettings/invitation_settings_binding.dart';
import 'package:starwork_flutter/views/team/inviteTeamMember/invitationSettings/invitation_settings_view.dart';
import 'package:starwork_flutter/views/team/inviteTeamMember/invite_team_member_binding.dart';
import 'package:starwork_flutter/views/team/inviteTeamMember/invite_team_member_view.dart';
import 'package:starwork_flutter/views/team/joinTeam/join_team_binding.dart';
import 'package:starwork_flutter/views/team/joinTeam/join_team_view.dart';
import 'package:starwork_flutter/views/team/personnelManage/personnel_manage_binding.dart';
import 'package:starwork_flutter/views/team/personnelManage/personnel_manage_view.dart';
import 'package:starwork_flutter/views/team/roleManage/role_manage_binding.dart';
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_view.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/team_manage_binding.dart';
@ -207,5 +217,30 @@ class AppPages {
page: () => AddPersonView(),
binding: AddPersonBinding(),
),
GetPage(
name: AppRoutes.teamRoleManage,
page: () => RoleManageView(),
binding: RoleManageBinding(),
),
GetPage(
name: AppRoutes.teamPersonnelManage,
page: () => PersonnelManageView(),
binding: PersonnelManageBinding(),
),
GetPage(
name: AppRoutes.teamSelectOrganization,
page: () => SelectOrganizationView(),
binding: SelectOrganizationBinding(),
),
GetPage(
name: AppRoutes.teamAddRole,
page: () => AddRoleView(),
binding: AddRoleBinding(),
),
GetPage(
name: AppRoutes.teamSelectRole,
page: () => SelectRoleView(),
binding: SelectRoleBinding(),
),
];
}

View File

@ -18,6 +18,11 @@ class AppRoutes{
static const String teamInviteTeamMember = '/team/inviteTeamMember';
static const String teamInvitationSettings = '/team/invitationSettings';
static const String teamAddPerson = '/team/addPerson';
static const String teamRoleManage = '/team/roleManage';
static const String teamSelectOrganization = '/team/selectOrganization';
static const String teamPersonnelManage = '/team/personnelManage';
static const String teamAddRole = '/team/addRole';
static const String teamSelectRole = '/team/selectRole';
static const String deviceManage = '/device/deviceManage';
static const String searchDevice = '/device/searchDevice';
static const String confirmPairDevice = '/device/confirmPairDevice';

View File

@ -24,6 +24,9 @@ class HomeStatisticsRowWidget extends StatelessWidget {
backgroundColor: const Color(0xFFCEF2F5),
textColor: const Color(0xFF134347),
buttonText: '人员管理',
onTap: () {
Get.toNamed(AppRoutes.teamPersonnelManage);
},
),
SizedBox(width: 8.w), //
_buildStatisticsCard(
@ -33,6 +36,9 @@ class HomeStatisticsRowWidget extends StatelessWidget {
backgroundColor: const Color(0xFFD4E0FF),
textColor: const Color(0xFF172A5B),
buttonText: '设备管理',
onTap: () {
Get.toNamed(AppRoutes.deviceManage);
},
),
],
);
@ -45,13 +51,12 @@ class HomeStatisticsRowWidget extends StatelessWidget {
required Color backgroundColor,
required Color textColor,
required String buttonText,
required GestureTapCallback onTap,
}) {
return Expanded(
// 使Expanded让卡片自适应宽度
child: GestureDetector(
onTap: (){
Get.toNamed(AppRoutes.deviceManage);
},
onTap: onTap,
child: Container(
height: 62.h,
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
@ -11,12 +12,16 @@ import 'package:starcloud/sdk/starcloud.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/response/team_info_response.dart';
import 'package:starwork_flutter/api/model/user/response/user_info_response.dart';
import 'package:starwork_flutter/api/service/team_api_service.dart';
import 'package:starwork_flutter/api/service/user_api_service.dart';
import 'package:starwork_flutter/base/app_logger.dart';
import 'package:starwork_flutter/base/base_controller.dart';
import 'package:starwork_flutter/common/constant/app_images.dart';
import 'package:starwork_flutter/common/constant/cache_keys.dart';
import 'package:starwork_flutter/common/events/refresh_device_list_event.dart';
import 'package:starwork_flutter/common/utils/event_bus_util.dart';
import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart';
import 'package:starwork_flutter/routes/app_routes.dart';
import 'package:starwork_flutter/views/home/home_controller.dart';
import 'package:starwork_flutter/views/home/home_view.dart';
@ -25,6 +30,7 @@ import 'package:starwork_flutter/views/mine/mine_view.dart';
class MainController extends BaseController {
final teamApi = Get.find<TeamApiService>();
final userApi = Get.find<UserApiService>();
GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
@ -62,6 +68,9 @@ class MainController extends BaseController {
///
_requestTeamDeviceList();
///
requestUserAccountInfo();
//
_refreshDeviceListSubscription = EventBusUtil().instance.on<RefreshDeviceListEvent>().listen((event) {
_requestTeamDeviceList();
@ -232,4 +241,23 @@ class MainController extends BaseController {
},
);
}
void requestUserAccountInfo() async {
var userInfo = await userApi.requestUserInfo();
if (userInfo.isSuccess) {
//
// 1: JSON
await SharedPreferencesUtils.setString(CacheKeys.userAccountInfo, jsonEncode(userInfo.data!.toJson()));
//
// String? cachedJson = await SharedPreferencesUtils.getString(CacheKeys.userAccountInfo);
// if (cachedJson != null) {
// try {
// Map<String, dynamic> jsonMap = jsonDecode(cachedJson);
// UserInfoResponse userInfoResponse = UserInfoResponse.fromJson(jsonMap);
// } catch (e) {
// AppLogger.error('JSON 解析错误: $e');
// }
// }
}
}
}

View File

@ -1,8 +1,44 @@
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
import 'package:get/get_rx/get_rx.dart';
import 'package:get/get_rx/src/rx_types/rx_types.dart';
import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dart';
import 'package:starwork_flutter/api/model/team/response/role_list_response.dart';
import 'package:starwork_flutter/base/base_controller.dart';
import 'package:starwork_flutter/common/constant/app_view_parameter_keys.dart';
class AddPersonController extends BaseController {
RxString selectedGender = 'male'.obs;
var selectedDepartItem = DepartItem().obs; //
TextEditingController nameInputController = TextEditingController();
TextEditingController jobNoInputController = TextEditingController(); //
TextEditingController postInputController = TextEditingController(); //
TextEditingController idCardInputController = TextEditingController(); //
var isOpeningAccount = false.obs; //
var selectedRoles = <RoleListResponse>[].obs;
@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 getSelectedRoleDisplayText() {
if (selectedRoles.isEmpty) {
return '请选择'; // "请选择"
} else {
//
return selectedRoles
.map((role) => role.roleName ?? '')
.join(''); // 使
}
}
}

View File

@ -2,460 +2,501 @@ import 'package:flutter/cupertino.dart';
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/api/model/team/response/role_list_response.dart';
import 'package:starwork_flutter/base/app_logger.dart';
import 'package:starwork_flutter/common/constant/app_colors.dart';
import 'package:starwork_flutter/common/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_person_controller.dart';
class AddPersonView extends GetView<AddPersonController> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.scaffoldBackgroundColor,
appBar: CustomAppBarWidget(
title: '添加人员'.tr,
return GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Scaffold(
backgroundColor: AppColors.scaffoldBackgroundColor,
),
body: SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(
left: 10.w,
right: 10.w,
bottom: 10.h,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'基本信息'.tr,
style: TextStyle(
fontSize: 12.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
),
SizedBox(
height: 6.h,
),
CustomCellListWidget(
children: [
CustomCellWidget(
onTap: () {},
leftText: '组织'.tr,
leftIcon: Icon(
Icons.circle,
size: 4.w,
color: Colors.red,
),
rightWidget: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'请选择',
style: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
),
SizedBox(
width: 4.w,
),
Icon(
Icons.arrow_forward_ios_rounded,
size: 16.sp,
color: Colors.grey[300],
)
],
),
),
CustomCellWidget(
onTap: () {},
leftText: '姓名'.tr,
leftIcon: Icon(
Icons.circle,
size: 4.w,
color: Colors.red,
),
rightWidget: Expanded(
flex: 3,
child: TextField(
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,
leftSubText: '可登录并使用应用或管理功能',
leftIcon: Icon(
Icons.circle,
size: 4.w,
color: Colors.red,
),
rightWidget: CupertinoSwitch(
value: false,
onChanged: (bool value) {},
activeColor: Colors.blue, // iOS
trackColor: Colors.grey, //
),
),
CustomCellWidget(
onTap: () {},
leftText: '分配权限'.tr,
leftIcon: Icon(
Icons.circle,
size: 4.w,
color: Colors.red,
),
rightWidget: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'企业员工',
style: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
),
SizedBox(
width: 4.w,
),
Icon(
Icons.arrow_forward_ios_rounded,
size: 16.sp,
color: Colors.grey[300],
)
],
),
)
],
),
SizedBox(
height: 10.h,
),
Text(
'扩展信息'.tr,
style: TextStyle(
fontSize: 12.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
),
SizedBox(
height: 10.h,
),
CustomCellListWidget(
children: [
CustomCellWidget(
onTap: () {},
leftText: '工号'.tr,
rightWidget: Expanded(
flex: 3,
child: TextField(
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 14.sp,
),
decoration: InputDecoration(
isCollapsed: true,
hintText: '选填'.tr,
hintStyle: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
//
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
//
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
),
),
CustomCellWidget(
onTap: () {},
leftText: '性别'.tr,
rightWidget: Obx(
() => Row(
children: [
Radio<String>(
value: 'male',
activeColor: Colors.blue,
groupValue: controller.selectedGender.value,
visualDensity: VisualDensity.compact,
onChanged: (value) {
controller.selectedGender.value = value!;
},
),
Text(''),
Radio<String>(
value: 'female',
activeColor: Colors.blue,
groupValue: controller.selectedGender.value,
visualDensity: VisualDensity.compact,
onChanged: (value) {
controller.selectedGender.value = value!;
},
),
Text(''),
],
),
),
),
CustomCellWidget(
onTap: () {},
leftText: '有效期'.tr,
rightWidget: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'请选择',
style: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
),
SizedBox(
width: 4.w,
),
Icon(
Icons.arrow_forward_ios_rounded,
size: 16.sp,
color: Colors.grey[300],
)
],
),
),
CustomCellWidget(
onTap: () {},
leftText: '职务'.tr,
rightWidget: Expanded(
flex: 3,
child: TextField(
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 14.sp,
),
decoration: InputDecoration(
isCollapsed: true,
hintText: '选填'.tr,
hintStyle: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
//
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
//
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
),
),
CustomCellWidget(
onTap: () {},
leftText: '备注'.tr,
rightWidget: Expanded(
flex: 3,
child: TextField(
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 14.sp,
),
decoration: InputDecoration(
isCollapsed: true,
hintText: '选填'.tr,
hintStyle: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
//
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
//
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
),
),
CustomCellWidget(
onTap: () {},
leftText: '身份证号码'.tr,
rightWidget: Expanded(
flex: 3,
child: TextField(
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,
),
),
),
),
],
),
SizedBox(
height: 10.h,
),
SizedBox(
width: double.infinity,
child: Text(
textAlign: TextAlign.center,
'温馨提示:人脸/指纹/卡片信息需先保存后录入',
appBar: CustomAppBarWidget(
title: '添加人员'.tr,
backgroundColor: AppColors.scaffoldBackgroundColor,
),
body: SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(
left: 10.w,
right: 10.w,
bottom: 10.h,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'基本信息'.tr,
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
),
),
SizedBox(
height: 10.h,
),
CustomCellListWidget(
children: [
CustomCellWidget(
onTap: () {
controller.showFunctionNotOpen();
},
leftText: '其他添加方式'.tr,
rightWidget: Icon(
Icons.arrow_forward_ios_rounded,
size: 16.sp,
color: Colors.grey,
),
),
],
),
],
),
Column(
children: [
Row(
children: [
Checkbox(
value: true,
// bool
onChanged: (bool? value) {},
),
Text(
'向用户发送短信邀请通知',
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey,
fontWeight: FontWeight.w400,
),
)
],
),
SizedBox(
width: double.infinity,
child: Row(
SizedBox(
height: 6.h,
),
CustomCellListWidget(
children: [
Expanded(
child: ElevatedButton(
onPressed: () {}.debounce(),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[100],
padding: EdgeInsets.symmetric(vertical: 12.h),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.r),
CustomCellWidget(
onTap: () async {
final result = await Get.toNamed(AppRoutes.teamSelectOrganization);
if (result != null) {
AppLogger.highlight('result${result}');
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 ?? '请选择',
style: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
),
),
),
child: Text(
'保存'.tr,
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: 16.sp,
color: Colors.blue,
fontWeight: FontWeight.w500,
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,
),
),
),
),
SizedBox(
width: 10.w,
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, //
),
),
Expanded(
child: ElevatedButton(
onPressed: () {}.debounce(),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
padding: EdgeInsets.symmetric(vertical: 12.h),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)),
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: Text(
'保存并继续添加'.tr,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Obx(
() => Expanded(
child: Text(
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(
height: 10.h,
),
Text(
'扩展信息'.tr,
style: TextStyle(
fontSize: 12.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
),
SizedBox(
height: 10.h,
),
CustomCellListWidget(
children: [
CustomCellWidget(
onTap: () {},
leftText: '工号'.tr,
rightWidget: Expanded(
flex: 3,
child: TextField(
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 16.sp,
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 14.sp,
),
decoration: InputDecoration(
isCollapsed: true,
hintText: '选填'.tr,
hintStyle: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
//
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
//
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
),
),
CustomCellWidget(
onTap: () {},
leftText: '性别'.tr,
rightWidget: Obx(
() => Row(
children: [
Radio<String>(
value: 'male',
activeColor: Colors.blue,
groupValue: controller.selectedGender.value,
visualDensity: VisualDensity.compact,
onChanged: (value) {
controller.selectedGender.value = value!;
},
),
Text(''),
Radio<String>(
value: 'female',
activeColor: Colors.blue,
groupValue: controller.selectedGender.value,
visualDensity: VisualDensity.compact,
onChanged: (value) {
controller.selectedGender.value = value!;
},
),
Text(''),
],
),
),
),
CustomCellWidget(
onTap: () {},
leftText: '有效期'.tr,
rightWidget: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'请选择',
style: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
),
SizedBox(
width: 4.w,
),
Icon(
Icons.arrow_forward_ios_rounded,
size: 16.sp,
color: Colors.grey[300],
)
],
),
),
CustomCellWidget(
onTap: () {},
leftText: '职务'.tr,
rightWidget: Expanded(
flex: 3,
child: TextField(
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 14.sp,
),
decoration: InputDecoration(
isCollapsed: true,
hintText: '选填'.tr,
hintStyle: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
//
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
//
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
),
),
CustomCellWidget(
onTap: () {},
leftText: '备注'.tr,
rightWidget: Expanded(
flex: 3,
child: TextField(
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 14.sp,
),
decoration: InputDecoration(
isCollapsed: true,
hintText: '选填'.tr,
hintStyle: TextStyle(
fontSize: 14.sp,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
//
border: InputBorder.none,
contentPadding: EdgeInsets.zero,
//
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
),
),
),
CustomCellWidget(
onTap: () {},
leftText: '身份证号码'.tr,
rightWidget: Expanded(
flex: 3,
child: TextField(
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,
),
),
),
),
],
),
),
],
)
],
SizedBox(
height: 10.h,
),
SizedBox(
width: double.infinity,
child: Text(
textAlign: TextAlign.center,
'温馨提示:人脸/指纹/卡片信息需先保存后录入',
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey,
fontWeight: FontWeight.w400,
),
),
),
SizedBox(
height: 10.h,
),
CustomCellListWidget(
children: [
CustomCellWidget(
onTap: () {
controller.showFunctionNotOpen();
},
leftText: '其他添加方式'.tr,
rightWidget: Icon(
Icons.arrow_forward_ios_rounded,
size: 16.sp,
color: Colors.grey,
),
),
],
),
],
),
Column(
children: [
Row(
children: [
Checkbox(
value: true,
// bool
onChanged: (bool? value) {},
),
Text(
'向用户发送短信邀请通知',
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey,
fontWeight: FontWeight.w400,
),
)
],
),
SizedBox(
width: double.infinity,
child: Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: () {}.debounce(),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[100],
padding: EdgeInsets.symmetric(vertical: 12.h),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.r),
),
),
child: Text(
'保存'.tr,
style: TextStyle(
fontSize: 16.sp,
color: Colors.blue,
fontWeight: FontWeight.w500,
),
),
),
),
SizedBox(
width: 10.w,
),
Expanded(
child: ElevatedButton(
onPressed: () {}.debounce(),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.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,
),
),
),
),
],
),
),
],
)
],
),
),
),
),

View File

@ -0,0 +1,10 @@
import 'package:get/get.dart';
import 'select_role_controller.dart';
class SelectRoleBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => SelectRoleController());
}
}

View File

@ -0,0 +1,58 @@
import 'package:get/get.dart';
import 'package:starwork_flutter/api/model/team/response/role_list_response.dart';
import 'package:starwork_flutter/api/service/team_api_service.dart';
import 'package:starwork_flutter/base/app_logger.dart';
import 'package:starwork_flutter/base/base_controller.dart';
class SelectRoleController extends BaseController {
final teamApi = Get.find<TeamApiService>();
var roleList = <RoleListResponse>[].obs;
var selectRoleIndexList = <int>[].obs;
//
List<RoleListResponse>? initialSelectedRoles;
@override
void onInit() {
super.onInit();
//
var arguments = Get.arguments;
if (arguments != null && arguments is List<RoleListResponse>) {
initialSelectedRoles = arguments;
}
requestRoleList();
}
@override
void onReady() {
super.onReady();
}
void requestRoleList() async {
var response = await teamApi.requestTeamRoleList();
if (response.isSuccess) {
roleList.value = response.data ?? [];
roleList.refresh();
_setInitialSelectedIndexes();
}
}
//
void _setInitialSelectedIndexes() {
if (initialSelectedRoles != null && initialSelectedRoles!.isNotEmpty) {
for (var selectedRole in initialSelectedRoles!) {
//
for (int i = 0; i < roleList.length; i++) {
if (roleList[i].id == selectedRole.id) {
if (!selectRoleIndexList.contains(i)) {
selectRoleIndexList.add(i);
}
break;
}
}
}
}
selectRoleIndexList.refresh();
}
}

View File

@ -0,0 +1,236 @@
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/role_list_response.dart';
import 'package:starwork_flutter/base/app_logger.dart';
import 'package:starwork_flutter/common/constant/app_colors.dart';
import 'package:starwork_flutter/common/widgets/custome_app_bar_wdiget.dart';
import 'package:starwork_flutter/extension/function_extension.dart';
import 'package:starwork_flutter/routes/app_routes.dart';
import 'select_role_controller.dart';
class SelectRoleView extends GetView<SelectRoleController> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBarWidget(
title: '按照角色分配权限'.tr,
backgroundColor: AppColors.scaffoldBackgroundColor,
),
backgroundColor: AppColors.scaffoldBackgroundColor,
body: SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () async {
var result = await Get.toNamed(AppRoutes.teamAddRole);
if (result != null && result == true) {
controller.requestRoleList();
}
},
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.r),
),
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'新建角色并分配'.tr,
style: TextStyle(
fontSize: 16.sp,
color: Colors.black,
),
),
Text(
'按新角色的权限分配'.tr,
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey,
),
),
],
),
const Spacer(),
Icon(
Icons.arrow_forward_ios_rounded,
size: 20.w,
color: Colors.grey,
)
],
),
),
),
SizedBox(
height: 10.h,
),
Text(
'按以下已有角色的权限分配'.tr,
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey,
),
),
SizedBox(
height: 10.h,
),
Obx(
() => Flexible(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.r),
),
child: ListView.separated(
shrinkWrap: true,
itemBuilder: (context, index) {
RoleListResponse roleList = controller.roleList[index];
return GestureDetector(
onTap: () {
//
if (!controller.selectRoleIndexList.contains(index)) {
controller.selectRoleIndexList.add(index);
} else {
controller.selectRoleIndexList.remove(index);
}
controller.selectRoleIndexList.refresh();
},
child: Padding(
padding: EdgeInsets.symmetric(
vertical: 10.h,
horizontal: 10.w,
),
child: Row(
children: [
Obx(
() => Checkbox(
value: controller.selectRoleIndexList.contains(index),
activeColor: Colors.blue,
onChanged: (value) {
if (value == true) {
//
if (!controller.selectRoleIndexList.contains(index)) {
controller.selectRoleIndexList.add(index);
}
} else {
controller.selectRoleIndexList.remove(index);
}
controller.selectRoleIndexList.refresh();
},
),
),
Container(
decoration: BoxDecoration(
color: Colors.blue[50],
borderRadius: BorderRadius.circular(8.r),
),
width: 36.w,
height: 36.w,
child: const Icon(
Icons.group_rounded,
color: Colors.blue,
),
),
SizedBox(
width: 10.w,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
roleList.roleName ?? '',
style: TextStyle(
fontSize: 16.sp,
color: Colors.black,
),
),
Text(
roleList.roleDesc ?? '',
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey,
),
maxLines: 3,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
),
);
},
separatorBuilder: (context, index) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: 10.w,
),
child: Divider(
height: 0.5.h,
thickness: 0.5.h,
color: Colors.grey[100],
),
);
},
itemCount: controller.roleList.length,
),
),
),
),
SizedBox(
height: 10.h,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Obx(
() => Text(
'已选中:${controller.selectRoleIndexList.length}',
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey,
),
),
),
ElevatedButton(
onPressed: () {
Get.back(
result: controller.selectRoleIndexList.map((e) => controller.roleList[e]).toList(),
);
}.debounce(),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.r),
),
),
child: Text(
'确认'.tr,
style: TextStyle(
fontSize: 16.sp,
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
)
],
)
],
),
),
),
);
}
}

View File

@ -0,0 +1,10 @@
import 'package:get/get.dart';
import 'add_role_controller.dart';
class AddRoleBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => AddRoleController());
}
}

View File

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:starwork_flutter/api/model/team/request/create_new_role_request.dart';
import 'package:starwork_flutter/api/service/team_api_service.dart';
import 'package:starwork_flutter/base/base_controller.dart';
class AddRoleController extends BaseController {
final teamApi = Get.find<TeamApiService>();
TextEditingController roleNameInputController = TextEditingController();
TextEditingController roleDescribeInputController = TextEditingController();
void createTeamRole() async {
var response = await teamApi.requestCreateTeamRole(
request: CreateNewRoleRequest(
roleName: roleNameInputController.text.trim(),
roleDesc: roleDescribeInputController.text.trim(),
),
);
if (response.isSuccess) {
showSuccess(message: '创建成功');
Get.back(result: true);
} else {
showError(message: response.errorMsg!);
}
}
}

View File

@ -0,0 +1,157 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:starwork_flutter/common/constant/app_colors.dart';
import 'package:starwork_flutter/common/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 'add_role_controller.dart';
class AddRoleView extends GetView<AddRoleController> {
@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: Padding(
padding: EdgeInsets.symmetric(
horizontal: 10.w,
vertical: 10.h,
),
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.roleNameInputController,
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,
),
),
),
)
],
),
SizedBox(
height: 10.h,
),
CustomCellListWidget(
children: [
CustomCellWidget(
onTap: () {},
leftText: '角色描述'.tr,
leftIcon: Icon(
Icons.circle,
size: 4.w,
color: Colors.red,
),
rightWidget: Expanded(
flex: 3,
child: TextField(
controller: controller.roleDescribeInputController,
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,
),
),
),
)
],
),
SizedBox(
height: 10.h,
),
Spacer(),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
if (controller.roleNameInputController.text.isEmpty) {
controller.showToast('请先输入角色名称');
return;
}
if (controller.roleDescribeInputController.text.isEmpty) {
controller.showToast('请先输入角色描述');
return;
}
controller.createTeamRole();
}.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,
),
),
),
)
],
),
),
),
),
);
}
}

View File

@ -25,6 +25,8 @@ class CreateTeamController extends BaseController {
requestAllSceneInfoList();
}
/// 使
void requestAllSceneInfoList() async {
showLoading();

View File

@ -1,6 +1,40 @@
import 'package:get/get.dart';
import 'package:starwork_flutter/api/model/team/request/update_invite_parameter_config_request.dart';
import 'package:starwork_flutter/api/model/team/response/team_invite_parameter_config_response.dart';
import 'package:starwork_flutter/api/service/team_api_service.dart';
import 'package:starwork_flutter/base/base_controller.dart';
import 'package:starwork_flutter/views/main/main_controller.dart';
class InvitationSettingsController extends BaseController {
// TODO:
}
final teamApi = Get.find<TeamApiService>();
final mainController = Get.find<MainController>();
var inviteConfig = TeamInviteParameterConfigResponse().obs;
@override
void onReady() {
super.onReady();
requestInvitationSettings();
}
requestInvitationSettings() async {
var response = await teamApi.requestInviteParameterConfig();
if (response.isSuccess) {
inviteConfig.value = response.data!;
}
}
requestUpdateInvitationSettings() async {
var response = await teamApi.requestUpdateInviteParameterConfig(
request: UpdateInviteParameterConfigRequest(
joinTeamInputFace: inviteConfig.value.joinTeamInputFace!,
applyJoinTeamAudit: inviteConfig.value.applyJoinTeamAudit!,
teamInviteUserValidFalse: inviteConfig.value.teamInviteUserValidFalse!,
),
);
if (response.isSuccess) {
inviteConfig.refresh();
} else {
showError(message: response.errorMsg!);
}
}
}

View File

@ -11,6 +11,9 @@ import 'invitation_settings_controller.dart';
class InvitationSettingsView extends GetView<InvitationSettingsController> {
@override
Widget build(BuildContext context) {
// 使使 controller
final _ = controller; //
return Scaffold(
backgroundColor: AppColors.scaffoldBackgroundColor,
appBar: CustomAppBarWidget(
@ -31,31 +34,58 @@ class InvitationSettingsView extends GetView<InvitationSettingsController> {
onTap: () {},
leftText: '人员配置'.tr,
leftSubText: '关闭审核后,新申请的用户无需审核即可加入成功',
rightWidget: CupertinoSwitch(
value: false,
onChanged: (bool value) {},
activeColor: Colors.blue, // iOS
trackColor: Colors.grey, //
rightWidget: Obx(
() => CupertinoSwitch(
value: controller.inviteConfig.value.applyJoinTeamAudit == 1,
onChanged: (bool value) {
if (value) {
controller.inviteConfig.value.applyJoinTeamAudit = 1;
} else {
controller.inviteConfig.value.applyJoinTeamAudit = 2;
}
controller.requestUpdateInvitationSettings();
},
activeColor: Colors.blue,
trackColor: Colors.grey,
),
),
),
CustomCellWidget(
onTap: () {},
leftText: '申请加入时可录入人脸'.tr,
rightWidget: CupertinoSwitch(
value: false,
onChanged: (bool value) {},
activeColor: Colors.blue, // iOS
trackColor: Colors.grey, //
rightWidget: Obx(
() => CupertinoSwitch(
value: controller.inviteConfig.value.joinTeamInputFace == 1,
onChanged: (bool value) {
if (value) {
controller.inviteConfig.value.joinTeamInputFace = 1;
} else {
controller.inviteConfig.value.joinTeamInputFace = 2;
}
controller.requestUpdateInvitationSettings();
},
activeColor: Colors.blue,
trackColor: Colors.grey,
),
),
),
CustomCellWidget(
onTap: () {},
leftText: '邀请信息30天后自动失效'.tr,
rightWidget: CupertinoSwitch(
value: false,
onChanged: (bool value) {},
activeColor: Colors.blue, // iOS
trackColor: Colors.grey, //
rightWidget: Obx(
() => CupertinoSwitch(
value: controller.inviteConfig.value.teamInviteUserValidFalse == 1,
onChanged: (bool value) {
if (value) {
controller.inviteConfig.value.teamInviteUserValidFalse = 1;
} else {
controller.inviteConfig.value.teamInviteUserValidFalse = 2;
}
controller.requestUpdateInvitationSettings();
},
activeColor: Colors.blue, // iOS
trackColor: Colors.grey, //
),
),
),
],

View File

@ -82,22 +82,25 @@ class InviteTeamMemberView extends GetView<InviteTeamMemberController> {
),
),
SizedBox(height: 10.h),
Container(
padding: EdgeInsets.all(10.r), //
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.r), // Container
color: Colors.white, //
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.r),
child: Obx(
() => Image(
width: 200.w, // 200 padding
height: 200.w,
image: NetworkImage(
controller.inviteInfo.value.inviteInfo ?? '',
Obx(
() => Visibility(
visible: controller.inviteInfo.value.inviteInfo != null,
child: Container(
padding: EdgeInsets.all(10.r), //
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.r), // Container
color: Colors.white, //
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.r),
child: Image(
width: 200.w, // 200 padding
height: 200.w,
image: NetworkImage(
controller.inviteInfo.value.inviteInfo ?? '',
),
fit: BoxFit.cover,
),
fit: BoxFit.cover,
),
),
),

View File

@ -0,0 +1,10 @@
import 'package:get/get.dart';
import 'personnel_manage_controller.dart';
class PersonnelManageBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => PersonnelManageController());
}
}

View File

@ -0,0 +1,137 @@
import 'dart:convert';
import 'package:animated_tree_view/animated_tree_view.dart';
import 'package:animated_tree_view/tree_view/tree_node.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/request/get_depart_list_request.dart';
import 'package:starwork_flutter/api/model/team/response/depart_list_reponse.dart';
import 'package:starwork_flutter/api/model/user/response/user_info_response.dart';
import 'package:starwork_flutter/api/service/team_api_service.dart';
import 'package:starwork_flutter/base/app_logger.dart';
import 'package:starwork_flutter/base/base_controller.dart';
import 'package:starwork_flutter/common/constant/cache_keys.dart';
import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart';
class PersonnelManageController extends BaseController {
final teamApi = Get.find<TeamApiService>();
final Rx<TreeNode?> treeData = Rx<TreeNode?>(null);
TreeViewController? treeViewController;
var selectedDepartItem = DepartItem().obs; //
var cacheUserInfo = UserInfoResponse().obs; //
final RxInt totalPersonCount = 0.obs;
@override
void onReady() {
super.onReady();
requestDepartList();
getCacheUserInfo();
}
requestDepartList() async {
var response = await teamApi.requestDepartList(
request: GetDepartListRequest(departNo: ''),
);
if (response.isSuccess) {
//
final tree = _convertToTree(response.data!.departList ?? []);
treeData.value = tree;
//
totalPersonCount.value = _calculateTotalPersonCount(response.data!.departList ?? []);
treeViewController?.expandAllChildren(treeData.value ?? TreeNode.root());
}
}
//
int _calculateTotalPersonCount(List<DepartItem> departList) {
int total = 0;
for (final depart in departList) {
total += depart.personNum ?? 0;
}
return total;
}
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;
}
requestCreateDepart() async {
var response = await teamApi.requestCreateDepart(
request: CreateNewDepartRequest(departName: '测试2', parentDepartNo: '-1', leader: ['CY93685899']),
);
if (response.isSuccess) {}
}
void getCacheUserInfo() async {
String? cachedJson = await SharedPreferencesUtils.getString(CacheKeys.userAccountInfo);
if (cachedJson != null) {
try {
Map<String, dynamic> jsonMap = jsonDecode(cachedJson);
UserInfoResponse userInfoResponse = UserInfoResponse.fromJson(jsonMap);
cacheUserInfo.value = userInfoResponse;
cacheUserInfo.refresh();
} catch (e) {
AppLogger.error('JSON 解析错误: $e');
}
}
}
}

View File

@ -0,0 +1,428 @@
import 'package:animated_tree_view/animated_tree_view.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.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/constant/app_view_parameter_keys.dart';
import 'package:starwork_flutter/common/widgets/custome_app_bar_wdiget.dart';
import 'package:starwork_flutter/extension/function_extension.dart';
import 'package:starwork_flutter/routes/app_routes.dart';
import 'personnel_manage_controller.dart';
class PersonnelManageView extends GetView<PersonnelManageController> {
PersonnelManageView({super.key});
@override
Widget build(BuildContext context) {
// 使使 controller
final _ = controller; //
return Scaffold(
backgroundColor: AppColors.scaffoldBackgroundColor,
appBar: CustomAppBarWidget(
title: '人员管理'.tr,
backgroundColor: AppColors.scaffoldBackgroundColor,
),
body: SafeArea(
child: Column(
children: [
Container(
margin: EdgeInsets.symmetric(
horizontal: 10.w,
vertical: 10.h,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.r),
),
padding: EdgeInsets.symmetric(
horizontal: 10.w,
vertical: 10.h,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
children: [
Icon(
Icons.person,
),
SizedBox(
height: 4.h,
),
Text(
'人脸信息'.tr,
style: TextStyle(
fontSize: 10.sp,
fontWeight: FontWeight.w500,
),
),
],
),
GestureDetector(
onTap: () {
Get.toNamed(AppRoutes.teamRoleManage);
},
child: Column(
children: [
Icon(
Icons.person,
),
SizedBox(
height: 4.h,
),
Text(
'角色管理'.tr,
style: TextStyle(
fontSize: 10.sp,
fontWeight: FontWeight.w500,
),
),
],
),
),
Column(
children: [
Icon(
Icons.person,
),
SizedBox(
height: 4.h,
),
Text(
'新用户审核'.tr,
style: TextStyle(
fontSize: 10.sp,
fontWeight: FontWeight.w500,
),
),
],
)
],
),
),
Container(
margin: EdgeInsets.symmetric(
horizontal: 10.w,
),
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(
() => Container(
margin: EdgeInsets.symmetric(
horizontal: 10.w,
),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
child: TreeView.simple(
tree: controller.treeData.value ?? TreeNode.root(),
showRootNode: false,
expansionIndicatorBuilder: noExpansionIndicatorBuilder,
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) {
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) {
//
final person = node.data as PersonItem;
title = person.personName ?? "未命名人员";
var personUserId = person.userId;
person.roles?.forEach((role) {
if (role.isSuper == 1) {
isSuper = true;
}
});
if (personUserId != null && personUserId == controller.cacheUserInfo.value.id) {
isOneself = 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: 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();
},
),
),
)
],
),
);
},
),
),
),
),
SizedBox(
height: 10.h,
),
Obx(
() => Text(
'${controller.totalPersonCount.value}',
style: TextStyle(
fontSize: 14.sp,
color: Colors.grey[500],
fontWeight: FontWeight.w500,
),
),
),
SizedBox(
height: 10.h,
),
Container(
margin: EdgeInsets.symmetric(
horizontal: 10.w,
),
child: Row(
children: [
Expanded(
child: ElevatedButton(
onPressed: () {
if (controller.selectedDepartItem.value.departNo == null) {
controller.showToast('请先选择一个组织');
return;
}
Get.toNamed(AppRoutes.teamAddPerson, arguments: {
AppViewParameterKeys.departItem: controller.selectedDepartItem.value.toJson(),
});
}.debounce(),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
padding: EdgeInsets.symmetric(vertical: 10.h),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)),
),
child: Text(
'添加人员'.tr,
style: TextStyle(
fontSize: 16.sp,
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
),
),
SizedBox(width: 10.w),
Expanded(
child: ElevatedButton(
onPressed: () {
if (controller.selectedDepartItem.value.departNo == null) {
controller.showToast('请先选择一个组织');
return;
}
}.debounce(),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[50],
padding: EdgeInsets.symmetric(vertical: 10.h),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)),
),
child: Text(
'添加子组织'.tr,
style: TextStyle(
fontSize: 16.sp,
color: Colors.blue,
fontWeight: FontWeight.w500,
),
),
),
),
SizedBox(width: 10.w),
Expanded(
child: ElevatedButton(
onPressed: () {}.debounce(),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[50],
padding: EdgeInsets.symmetric(vertical: 10.h),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.r)),
),
child: Text(
'更多管理'.tr,
style: TextStyle(
fontSize: 16.sp,
color: Colors.blue,
fontWeight: FontWeight.w500,
),
),
),
)
],
),
),
SizedBox(
height: 10.h,
),
],
),
),
);
}
}

View File

@ -0,0 +1,10 @@
import 'package:get/get.dart';
import 'role_manage_controller.dart';
class RoleManageBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => RoleManageController());
}
}

View File

@ -0,0 +1,42 @@
import 'dart:convert';
import 'package:get/get.dart';
import 'package:starwork_flutter/api/model/team/request/role_list_request.dart';
import 'package:starwork_flutter/api/model/team/response/role_list_response.dart';
import 'package:starwork_flutter/api/model/user/response/user_info_response.dart';
import 'package:starwork_flutter/api/service/team_api_service.dart';
import 'package:starwork_flutter/base/app_logger.dart';
import 'package:starwork_flutter/base/base_controller.dart';
import 'package:starwork_flutter/common/constant/cache_keys.dart';
import 'package:starwork_flutter/common/utils/shared_preferences_utils.dart';
class RoleManageController extends BaseController {
final teamApi = Get.find<TeamApiService>();
var roleList = <RoleListResponse>[].obs;
var cacheUserInfo = UserInfoResponse().obs; //
@override
void onReady() async {
super.onReady();
requestRoleList();
String? cachedJson = await SharedPreferencesUtils.getString(CacheKeys.userAccountInfo);
if (cachedJson != null) {
try {
Map<String, dynamic> jsonMap = jsonDecode(cachedJson);
UserInfoResponse userInfoResponse = UserInfoResponse.fromJson(jsonMap);
cacheUserInfo.value = userInfoResponse;
cacheUserInfo.refresh();
} catch (e) {
AppLogger.error('JSON 解析错误: $e');
}
}
}
void requestRoleList() async {
var response = await teamApi.requestTeamRoleList();
if (response.isSuccess) {
roleList.value = response.data ?? [];
roleList.refresh();
}
}
}

View File

@ -0,0 +1,345 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:starwork_flutter/api/model/team/response/role_list_response.dart';
import 'package:starwork_flutter/common/constant/app_colors.dart';
import 'package:starwork_flutter/common/widgets/custome_app_bar_wdiget.dart';
import 'package:starwork_flutter/extension/function_extension.dart';
import 'package:starwork_flutter/routes/app_routes.dart';
import 'role_manage_controller.dart';
class RoleManageView extends GetView<RoleManageController> {
@override
Widget build(BuildContext context) {
// 使使 controller
final _ = controller; //
return Scaffold(
backgroundColor: AppColors.scaffoldBackgroundColor,
appBar: CustomAppBarWidget(
title: '角色分配'.tr,
backgroundColor: AppColors.scaffoldBackgroundColor,
),
body: SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: 10.w,
),
child: Column(
children: [
Row(
children: [
RichText(
text: TextSpan(
children: [
TextSpan(
text: '超级管理员'.tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
const TextSpan(
text: ' ',
),
TextSpan(
text: '具有团队全部管理权限'.tr,
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w400,
color: Colors.grey[500],
),
),
],
),
)
],
),
SizedBox(
height: 10.h,
),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.r),
),
padding: EdgeInsets.symmetric(
horizontal: 10.w,
vertical: 10.h,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Obx(
() => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
controller.cacheUserInfo.value.nickname ?? '',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
Text(
controller.cacheUserInfo.value.accountNo ?? '',
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w400,
color: Colors.grey[500],
),
),
],
),
),
ElevatedButton(
onPressed: () {
controller.showFunctionNotOpen();
}.debounce(),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
padding: EdgeInsets.zero,
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,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
RichText(
text: TextSpan(
children: [
TextSpan(
text: '角色'.tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
const TextSpan(
text: ' ',
),
TextSpan(
text: '用于给其他用户快捷分配权限'.tr,
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w400,
color: Colors.grey[500],
),
),
],
),
),
GestureDetector(
onTap: () async {
var result = await Get.toNamed(AppRoutes.teamAddRole);
if (result != null && result == true) {
controller.requestRoleList();
}
},
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'新建角色',
style: TextStyle(
fontSize: 14.sp,
color: Colors.blue,
),
),
],
),
),
],
),
SizedBox(
height: 10.h,
),
_buildRoleList(),
],
),
),
),
);
}
_buildRoleList() {
return Obx(
() => Flexible(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.r),
),
child: ListView.separated(
shrinkWrap: true,
itemCount: controller.roleList.length,
itemBuilder: (context, index) {
RoleListResponse role = controller.roleList[index];
return _buildRoleItem(role);
},
separatorBuilder: (context, index) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: 10.w,
),
child: Divider(
height: 0.5.h,
thickness: 0.5.h,
color: Colors.grey[100],
),
);
},
),
),
),
);
}
_buildRoleItem(RoleListResponse role) {
// role personList person personName
//
String personNames = '';
// role.personList
if (role.personList != null && role.personList!.isNotEmpty) {
// personName
personNames = role.personList!.map((person) => person.personName ?? '').join(','); // 使
} else {
//
personNames = '暂无用户';
}
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(
horizontal: 10.w,
vertical: 10.h,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(
Icons.group_rounded,
color: Colors.blue,
),
SizedBox(
width: 6.w,
),
Text(
role.roleName ?? '',
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w600,
),
),
const Spacer(),
Icon(
Icons.arrow_forward_ios_rounded,
color: Colors.grey,
size: 16.sp,
)
],
),
SizedBox(
height: 10.h,
),
RichText(
textAlign: TextAlign.left,
maxLines: 1,
overflow: TextOverflow.ellipsis,
text: TextSpan(
children: [
TextSpan(
text: '角色用户:'.tr,
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w400,
color: Colors.grey[500],
),
),
TextSpan(
text: personNames,
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w400,
color: Colors.black,
),
)
],
),
),
RichText(
textAlign: TextAlign.left,
maxLines: 1,
overflow: TextOverflow.ellipsis,
text: TextSpan(
children: [
TextSpan(
text: '分配权限:'.tr,
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w400,
color: Colors.grey[500],
),
),
TextSpan(
text: '全部权限'.tr,
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w400,
color: Colors.black,
),
)
],
),
),
RichText(
textAlign: TextAlign.left,
maxLines: 2,
overflow: TextOverflow.ellipsis,
text: TextSpan(
children: [
TextSpan(
text: '角色描述:'.tr,
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w400,
color: Colors.grey[500],
),
),
TextSpan(
text: role.roleDesc ?? '',
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w400,
color: Colors.black,
),
)
],
),
)
],
),
);
}
}

View File

@ -0,0 +1,10 @@
import 'package:get/get.dart';
import 'select_organization_controller.dart';
class SelectOrganizationBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => SelectOrganizationController());
}
}

View File

@ -0,0 +1,76 @@
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 SelectOrganizationController extends BaseController {
final teamApi = Get.find<TeamApiService>();
final Rx<TreeNode?> treeData = Rx<TreeNode?>(null);
TreeViewController? treeViewController;
//
TextEditingController searchInputController = TextEditingController();
@override
void onReady() {
super.onReady();
requestDepartList();
}
requestDepartList() async {
var response = await teamApi.requestDepartList(
request: GetDepartListRequest(departNo: ''),
);
if (response.isSuccess) {
//
final tree = _convertToTree(response.data!.departList ?? []);
treeData.value = tree;
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);
}
}
return root;
}
}

View File

@ -0,0 +1,204 @@
import 'package:animated_tree_view/animated_tree_view.dart';
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/constant/app_images.dart';
import 'package:starwork_flutter/common/widgets/custome_app_bar_wdiget.dart';
import 'select_organization_controller.dart';
class SelectOrganizationView extends GetView<SelectOrganizationController> {
@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(
() => Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
child: TreeView.simple(
tree: controller.treeData.value ?? TreeNode.root(),
showRootNode: false,
expansionIndicatorBuilder: noExpansionIndicatorBuilder,
indentation: const Indentation(style: IndentStyle.roundJoint),
onItemTap: (item) {
AppLogger.highlight('message:${item.data}');
if (item.data is DepartItem) {
Get.back(result: item.data);
}
},
onTreeReady: (c) {
controller.treeViewController = c;
},
builder: (context, node) {
String title = "";
DepartItem departInfo = DepartItem();
bool isPersonItem = node.data is PersonItem; //
if (node.data is DepartItem) {
final depart = node.data as DepartItem;
title = depart.departName ?? "未命名部门";
}
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,
),
),
],
),
),
],
),
);
},
),
),
),
)
],
),
),
),
);
}
_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),
),
),
);
}
}

View File

@ -1,6 +1,14 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
animated_tree_view:
dependency: "direct main"
description:
name: animated_tree_view
sha256: ed982be7fa2cf51b62bb76e95b6a0f423cde12f1da8745a1da938e82a7baacf2
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.3.0"
archive:
dependency: transitive
description:
@ -105,6 +113,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.7.11"
diffutil_dart:
dependency: transitive
description:
name: diffutil_dart
sha256: "5e74883aedf87f3b703cb85e815bdc1ed9208b33501556e4a8a5572af9845c81"
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.1"
dio:
dependency: "direct main"
description:
@ -153,6 +169,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.1"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.1"
flutter:
dependency: "direct main"
description: flutter
@ -509,6 +533,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.28.0"
scroll_to_index:
dependency: transitive
description:
name: scroll_to_index
sha256: b707546e7500d9f070d63e5acf74fd437ec7eeeb68d3412ef7b0afada0b4f176
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.1"
shared_preferences:
dependency: "direct main"
description:
@ -657,6 +689,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
uuid:
dependency: transitive
description:
name: uuid
sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.5.1"
vector_math:
dependency: transitive
description:

View File

@ -43,7 +43,8 @@ dependencies:
# 星云sdk
starcloud:
path: ../starcloud-sdk-flutter
# 树形结构
animated_tree_view: ^2.3.0