feat(dashboard): 결재 역할 뱃지와 문서 정합성 반영
- doc/frontend_backend_alignment_report.md에 roles 필터 적용 배경과 UI 반영 사항을 기록 - lib/features/dashboard/data/dashboard_summary_dto.dart에서 roles 파싱과 enum 매핑 로직, 문자열 리스트 util 추가 - lib/features/dashboard/domain/entities/dashboard_pending_approval.dart에 역할 enum과 도메인 필드 추가 - lib/features/dashboard/presentation/pages/dashboard_page.dart에서 결재 카드 헤더/설명 수정 및 역할 뱃지 렌더링 지원 - test/features/dashboard/data/dashboard_summary_dto_test.dart 신규 작성해 DTO→도메인 매핑과 무시 케이스를 검증 - test/features/masters/user/presentation/pages/user_page_test.dart에서 사용되지 않는 PermissionManager import 제거
This commit is contained in:
@@ -141,6 +141,7 @@ class DashboardApprovalDto {
|
||||
required this.title,
|
||||
required this.stepSummary,
|
||||
this.requestedAt,
|
||||
this.roles = const [],
|
||||
});
|
||||
|
||||
final int? approvalId;
|
||||
@@ -148,6 +149,7 @@ class DashboardApprovalDto {
|
||||
final String title;
|
||||
final String stepSummary;
|
||||
final DateTime? requestedAt;
|
||||
final List<String> roles;
|
||||
|
||||
factory DashboardApprovalDto.fromJson(Map<String, dynamic> json) {
|
||||
num? rawId = _readNum(json, 'approval_id');
|
||||
@@ -176,16 +178,22 @@ class DashboardApprovalDto {
|
||||
title: _readString(json, 'title') ?? '',
|
||||
stepSummary: _readString(json, 'step_summary') ?? '',
|
||||
requestedAt: _parseDate(json['requested_at']),
|
||||
roles: _readStringList(json, 'roles'),
|
||||
);
|
||||
}
|
||||
|
||||
DashboardPendingApproval toEntity() {
|
||||
final parsedRoles = roles
|
||||
.map(DashboardApprovalRole.fromName)
|
||||
.whereType<DashboardApprovalRole>()
|
||||
.toList(growable: false);
|
||||
return DashboardPendingApproval(
|
||||
approvalId: approvalId,
|
||||
approvalNo: approvalNo,
|
||||
title: title,
|
||||
stepSummary: stepSummary,
|
||||
requestedAt: requestedAt,
|
||||
roles: parsedRoles,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -233,3 +241,25 @@ double? _readDouble(Map<String, dynamic>? source, String key) {
|
||||
}
|
||||
return value.toDouble();
|
||||
}
|
||||
|
||||
List<String> _readStringList(Map<String, dynamic>? source, String key) {
|
||||
if (source == null) {
|
||||
return const [];
|
||||
}
|
||||
final value = source[key];
|
||||
if (value is List) {
|
||||
return value
|
||||
.whereType<String>()
|
||||
.map((text) => text.trim())
|
||||
.where((text) => text.isNotEmpty)
|
||||
.toList(growable: false);
|
||||
}
|
||||
if (value is String) {
|
||||
final normalized = value.trim();
|
||||
if (normalized.isEmpty) {
|
||||
return const [];
|
||||
}
|
||||
return [normalized];
|
||||
}
|
||||
return const [];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user