결재 템플릿 단계 적용 구현
- ApprovalTemplate 엔티티·DTO·원격 리포지토리 추가 - ApprovalController에 템플릿 로딩/적용 상태와 assignSteps 호출 연동 - ApprovalPage 단계 탭에 템플릿 선택 UI 및 적용 확인 다이얼로그 구현 - 템플릿 적용 단위 테스트와 IMPLEMENTATION_TASKS 현황 갱신
This commit is contained in:
119
lib/features/masters/menu/domain/entities/menu.dart
Normal file
119
lib/features/masters/menu/domain/entities/menu.dart
Normal file
@@ -0,0 +1,119 @@
|
||||
/// 메뉴 엔티티
|
||||
///
|
||||
/// - 계층 구조를 표현하기 위해 상위 메뉴 정보를 포함한다.
|
||||
/// - presentation/data 레이어 세부 구현에 의존하지 않는다.
|
||||
class MenuItem {
|
||||
MenuItem({
|
||||
this.id,
|
||||
required this.menuCode,
|
||||
required this.menuName,
|
||||
this.parent,
|
||||
this.path,
|
||||
this.displayOrder,
|
||||
this.isActive = true,
|
||||
this.isDeleted = false,
|
||||
this.note,
|
||||
this.createdAt,
|
||||
this.updatedAt,
|
||||
});
|
||||
|
||||
/// PK (null 이면 신규 생성)
|
||||
final int? id;
|
||||
|
||||
/// 메뉴 코드 (고유)
|
||||
final String menuCode;
|
||||
|
||||
/// 메뉴명
|
||||
final String menuName;
|
||||
|
||||
/// 상위 메뉴 정보
|
||||
final MenuSummary? parent;
|
||||
|
||||
/// 라우트 경로
|
||||
final String? path;
|
||||
|
||||
/// 표시 순서
|
||||
final int? displayOrder;
|
||||
|
||||
/// 사용 여부
|
||||
final bool isActive;
|
||||
|
||||
/// 소프트 삭제 여부
|
||||
final bool isDeleted;
|
||||
|
||||
/// 비고
|
||||
final String? note;
|
||||
|
||||
/// 생성/수정 일시
|
||||
final DateTime? createdAt;
|
||||
final DateTime? updatedAt;
|
||||
|
||||
MenuItem copyWith({
|
||||
int? id,
|
||||
String? menuCode,
|
||||
String? menuName,
|
||||
MenuSummary? parent,
|
||||
String? path,
|
||||
int? displayOrder,
|
||||
bool? isActive,
|
||||
bool? isDeleted,
|
||||
String? note,
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
}) {
|
||||
return MenuItem(
|
||||
id: id ?? this.id,
|
||||
menuCode: menuCode ?? this.menuCode,
|
||||
menuName: menuName ?? this.menuName,
|
||||
parent: parent ?? this.parent,
|
||||
path: path ?? this.path,
|
||||
displayOrder: displayOrder ?? this.displayOrder,
|
||||
isActive: isActive ?? this.isActive,
|
||||
isDeleted: isDeleted ?? this.isDeleted,
|
||||
note: note ?? this.note,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 상위 메뉴 요약 정보
|
||||
class MenuSummary {
|
||||
MenuSummary({required this.id, required this.menuName});
|
||||
|
||||
final int id;
|
||||
final String menuName;
|
||||
}
|
||||
|
||||
/// 메뉴 생성/수정 입력 모델
|
||||
class MenuInput {
|
||||
MenuInput({
|
||||
required this.menuCode,
|
||||
required this.menuName,
|
||||
this.parentMenuId,
|
||||
this.path,
|
||||
this.displayOrder,
|
||||
this.isActive = true,
|
||||
this.note,
|
||||
});
|
||||
|
||||
final String menuCode;
|
||||
final String menuName;
|
||||
final int? parentMenuId;
|
||||
final String? path;
|
||||
final int? displayOrder;
|
||||
final bool isActive;
|
||||
final String? note;
|
||||
|
||||
Map<String, dynamic> toPayload() {
|
||||
return {
|
||||
'menu_code': menuCode,
|
||||
'menu_name': menuName,
|
||||
'parent_menu_id': parentMenuId,
|
||||
'path': path,
|
||||
'display_order': displayOrder,
|
||||
'is_active': isActive,
|
||||
'note': note,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import 'package:superport_v2/core/common/models/paginated_result.dart';
|
||||
|
||||
import '../entities/menu.dart';
|
||||
|
||||
abstract class MenuRepository {
|
||||
/// 메뉴 목록 조회
|
||||
Future<PaginatedResult<MenuItem>> list({
|
||||
int page = 1,
|
||||
int pageSize = 20,
|
||||
String? query,
|
||||
int? parentId,
|
||||
bool? isActive,
|
||||
bool includeDeleted = false,
|
||||
});
|
||||
|
||||
/// 메뉴 신규 등록
|
||||
Future<MenuItem> create(MenuInput input);
|
||||
|
||||
/// 메뉴 수정
|
||||
Future<MenuItem> update(int id, MenuInput input);
|
||||
|
||||
/// 메뉴 삭제(소프트)
|
||||
Future<void> delete(int id);
|
||||
|
||||
/// 메뉴 복구
|
||||
Future<MenuItem> restore(int id);
|
||||
}
|
||||
Reference in New Issue
Block a user