feat: 사용자 관리 API 연동 구현

- UserRemoteDataSource: 사용자 CRUD, 상태 변경, 비밀번호 변경, 중복 확인 API 구현
- UserService: DTO-Model 변환 로직 및 역할/전화번호 매핑 처리
- UserListController: ChangeNotifier 패턴 적용, 페이지네이션, 검색, 필터링 기능 추가
- UserFormController: API 연동, username 중복 확인 기능 추가
- user_form.dart: username/password 필드 추가 및 실시간 검증
- user_list_redesign.dart: Provider 패턴 적용, 무한 스크롤 구현
- equipment_out_form_controller.dart: 구문 오류 수정
- API 통합 진행률: 85% (사용자 관리 100% 완료)
This commit is contained in:
JiWoong Sul
2025-07-24 19:37:58 +09:00
parent 7f491afa4f
commit 553f605e8b
15 changed files with 3808 additions and 543 deletions

View File

@@ -0,0 +1,102 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user_dto.freezed.dart';
part 'user_dto.g.dart';
enum UserRole {
@JsonValue('admin')
admin,
@JsonValue('manager')
manager,
@JsonValue('staff')
staff,
}
@freezed
class UserDto with _$UserDto {
const factory UserDto({
required int id,
required String username,
required String email,
required String name,
String? phone,
required String role,
@JsonKey(name: 'company_id') int? companyId,
@JsonKey(name: 'branch_id') int? branchId,
@JsonKey(name: 'is_active') required bool isActive,
@JsonKey(name: 'created_at') required DateTime createdAt,
@JsonKey(name: 'updated_at') required DateTime updatedAt,
}) = _UserDto;
factory UserDto.fromJson(Map<String, dynamic> json) =>
_$UserDtoFromJson(json);
}
@freezed
class CreateUserRequest with _$CreateUserRequest {
const factory CreateUserRequest({
required String username,
required String email,
required String password,
required String name,
String? phone,
required String role,
@JsonKey(name: 'company_id') int? companyId,
@JsonKey(name: 'branch_id') int? branchId,
}) = _CreateUserRequest;
factory CreateUserRequest.fromJson(Map<String, dynamic> json) =>
_$CreateUserRequestFromJson(json);
}
@freezed
class UpdateUserRequest with _$UpdateUserRequest {
const factory UpdateUserRequest({
String? name,
String? email,
String? password,
String? phone,
String? role,
@JsonKey(name: 'company_id') int? companyId,
@JsonKey(name: 'branch_id') int? branchId,
}) = _UpdateUserRequest;
factory UpdateUserRequest.fromJson(Map<String, dynamic> json) =>
_$UpdateUserRequestFromJson(json);
}
@freezed
class ChangeStatusRequest with _$ChangeStatusRequest {
const factory ChangeStatusRequest({
@JsonKey(name: 'is_active') required bool isActive,
}) = _ChangeStatusRequest;
factory ChangeStatusRequest.fromJson(Map<String, dynamic> json) =>
_$ChangeStatusRequestFromJson(json);
}
@freezed
class ChangePasswordRequest with _$ChangePasswordRequest {
const factory ChangePasswordRequest({
@JsonKey(name: 'current_password') required String currentPassword,
@JsonKey(name: 'new_password') required String newPassword,
}) = _ChangePasswordRequest;
factory ChangePasswordRequest.fromJson(Map<String, dynamic> json) =>
_$ChangePasswordRequestFromJson(json);
}
@freezed
class UserListDto with _$UserListDto {
const factory UserListDto({
required List<UserDto> users,
required int total,
required int page,
@JsonKey(name: 'per_page') required int perPage,
@JsonKey(name: 'total_pages') required int totalPages,
}) = _UserListDto;
factory UserListDto.fromJson(Map<String, dynamic> json) =>
_$UserListDtoFromJson(json);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,133 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user_dto.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$UserDtoImpl _$$UserDtoImplFromJson(Map<String, dynamic> json) =>
_$UserDtoImpl(
id: (json['id'] as num).toInt(),
username: json['username'] as String,
email: json['email'] as String,
name: json['name'] as String,
phone: json['phone'] as String?,
role: json['role'] as String,
companyId: (json['company_id'] as num?)?.toInt(),
branchId: (json['branch_id'] as num?)?.toInt(),
isActive: json['is_active'] as bool,
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
);
Map<String, dynamic> _$$UserDtoImplToJson(_$UserDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'username': instance.username,
'email': instance.email,
'name': instance.name,
'phone': instance.phone,
'role': instance.role,
'company_id': instance.companyId,
'branch_id': instance.branchId,
'is_active': instance.isActive,
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
};
_$CreateUserRequestImpl _$$CreateUserRequestImplFromJson(
Map<String, dynamic> json) =>
_$CreateUserRequestImpl(
username: json['username'] as String,
email: json['email'] as String,
password: json['password'] as String,
name: json['name'] as String,
phone: json['phone'] as String?,
role: json['role'] as String,
companyId: (json['company_id'] as num?)?.toInt(),
branchId: (json['branch_id'] as num?)?.toInt(),
);
Map<String, dynamic> _$$CreateUserRequestImplToJson(
_$CreateUserRequestImpl instance) =>
<String, dynamic>{
'username': instance.username,
'email': instance.email,
'password': instance.password,
'name': instance.name,
'phone': instance.phone,
'role': instance.role,
'company_id': instance.companyId,
'branch_id': instance.branchId,
};
_$UpdateUserRequestImpl _$$UpdateUserRequestImplFromJson(
Map<String, dynamic> json) =>
_$UpdateUserRequestImpl(
name: json['name'] as String?,
email: json['email'] as String?,
password: json['password'] as String?,
phone: json['phone'] as String?,
role: json['role'] as String?,
companyId: (json['company_id'] as num?)?.toInt(),
branchId: (json['branch_id'] as num?)?.toInt(),
);
Map<String, dynamic> _$$UpdateUserRequestImplToJson(
_$UpdateUserRequestImpl instance) =>
<String, dynamic>{
'name': instance.name,
'email': instance.email,
'password': instance.password,
'phone': instance.phone,
'role': instance.role,
'company_id': instance.companyId,
'branch_id': instance.branchId,
};
_$ChangeStatusRequestImpl _$$ChangeStatusRequestImplFromJson(
Map<String, dynamic> json) =>
_$ChangeStatusRequestImpl(
isActive: json['is_active'] as bool,
);
Map<String, dynamic> _$$ChangeStatusRequestImplToJson(
_$ChangeStatusRequestImpl instance) =>
<String, dynamic>{
'is_active': instance.isActive,
};
_$ChangePasswordRequestImpl _$$ChangePasswordRequestImplFromJson(
Map<String, dynamic> json) =>
_$ChangePasswordRequestImpl(
currentPassword: json['current_password'] as String,
newPassword: json['new_password'] as String,
);
Map<String, dynamic> _$$ChangePasswordRequestImplToJson(
_$ChangePasswordRequestImpl instance) =>
<String, dynamic>{
'current_password': instance.currentPassword,
'new_password': instance.newPassword,
};
_$UserListDtoImpl _$$UserListDtoImplFromJson(Map<String, dynamic> json) =>
_$UserListDtoImpl(
users: (json['users'] as List<dynamic>)
.map((e) => UserDto.fromJson(e as Map<String, dynamic>))
.toList(),
total: (json['total'] as num).toInt(),
page: (json['page'] as num).toInt(),
perPage: (json['per_page'] as num).toInt(),
totalPages: (json['total_pages'] as num).toInt(),
);
Map<String, dynamic> _$$UserListDtoImplToJson(_$UserListDtoImpl instance) =>
<String, dynamic>{
'users': instance.users,
'total': instance.total,
'page': instance.page,
'per_page': instance.perPage,
'total_pages': instance.totalPages,
};