전역 구조 리팩터링 및 테스트 확장
This commit is contained in:
@@ -7,6 +7,7 @@ import '../../../../../core/config/environment.dart';
|
||||
import '../../../../../core/constants/app_sections.dart';
|
||||
import '../../../../../widgets/app_layout.dart';
|
||||
import '../../../../../widgets/components/filter_bar.dart';
|
||||
import '../../../../../widgets/components/superport_dialog.dart';
|
||||
import '../../../../../widgets/spec_page.dart';
|
||||
import '../controllers/approval_step_controller.dart';
|
||||
import '../../domain/entities/approval_step_input.dart';
|
||||
@@ -528,73 +529,50 @@ class _ApprovalStepEnabledPageState extends State<_ApprovalStepEnabledPage> {
|
||||
if (!mounted) return;
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
if (detail == null) return;
|
||||
await showDialog<void>(
|
||||
final step = detail.step;
|
||||
await SuperportDialog.show<void>(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
final step = detail.step;
|
||||
final theme = ShadTheme.of(dialogContext);
|
||||
return Dialog(
|
||||
insetPadding: const EdgeInsets.all(24),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: ShadCard(
|
||||
title: Text('결재 단계 상세', style: theme.textTheme.h3),
|
||||
description: Text(
|
||||
'결재번호 ${detail.approvalNo}',
|
||||
style: theme.textTheme.muted,
|
||||
dialog: SuperportDialog(
|
||||
title: '결재 단계 상세',
|
||||
description: '결재번호 ${detail.approvalNo}',
|
||||
constraints: const BoxConstraints(maxWidth: 560),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 20,
|
||||
vertical: 18,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_DetailRow(label: '단계 순서', value: '${step.stepOrder}'),
|
||||
_DetailRow(label: '승인자', value: step.approver.name),
|
||||
_DetailRow(label: '상태', value: step.status.name),
|
||||
_DetailRow(label: '배정일시', value: _formatDate(step.assignedAt)),
|
||||
_DetailRow(
|
||||
label: '결정일시',
|
||||
value: step.decidedAt == null
|
||||
? '-'
|
||||
: _formatDate(step.decidedAt!),
|
||||
),
|
||||
footer: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
ShadButton.ghost(
|
||||
onPressed: () => Navigator.of(dialogContext).pop(),
|
||||
child: const Text('닫기'),
|
||||
),
|
||||
],
|
||||
_DetailRow(label: '템플릿', value: detail.templateName ?? '-'),
|
||||
_DetailRow(label: '트랜잭션번호', value: detail.transactionNo ?? '-'),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'비고',
|
||||
style: ShadTheme.of(
|
||||
context,
|
||||
).textTheme.small.copyWith(fontWeight: FontWeight.w600),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_DetailRow(label: '단계 순서', value: '${step.stepOrder}'),
|
||||
_DetailRow(label: '승인자', value: step.approver.name),
|
||||
_DetailRow(label: '상태', value: step.status.name),
|
||||
_DetailRow(
|
||||
label: '배정일시',
|
||||
value: _formatDate(step.assignedAt),
|
||||
),
|
||||
_DetailRow(
|
||||
label: '결정일시',
|
||||
value: step.decidedAt == null
|
||||
? '-'
|
||||
: _formatDate(step.decidedAt!),
|
||||
),
|
||||
_DetailRow(label: '템플릿', value: detail.templateName ?? '-'),
|
||||
_DetailRow(
|
||||
label: '트랜잭션번호',
|
||||
value: detail.transactionNo ?? '-',
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
'비고',
|
||||
style: theme.textTheme.small.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ShadTextarea(
|
||||
initialValue: step.note ?? '',
|
||||
readOnly: true,
|
||||
minHeight: 80,
|
||||
maxHeight: 200,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ShadTextarea(
|
||||
initialValue: step.note ?? '',
|
||||
readOnly: true,
|
||||
minHeight: 80,
|
||||
maxHeight: 200,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -724,102 +702,93 @@ class _StepFormDialogState extends State<_StepFormDialog> {
|
||||
final theme = ShadTheme.of(context);
|
||||
final materialTheme = Theme.of(context);
|
||||
|
||||
return Dialog(
|
||||
insetPadding: const EdgeInsets.all(24),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: ShadCard(
|
||||
title: Text(widget.title, style: theme.textTheme.h3),
|
||||
footer: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
return SuperportDialog(
|
||||
title: widget.title,
|
||||
constraints: const BoxConstraints(maxWidth: 560),
|
||||
primaryAction: ShadButton(
|
||||
key: const ValueKey('step_form_submit'),
|
||||
onPressed: _handleSubmit,
|
||||
child: Text(widget.submitLabel),
|
||||
),
|
||||
secondaryAction: ShadButton.ghost(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('취소'),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ShadButton.ghost(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('취소'),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
ShadButton(
|
||||
key: const ValueKey('step_form_submit'),
|
||||
onPressed: _handleSubmit,
|
||||
child: Text(widget.submitLabel),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (!widget.isEditing)
|
||||
_FormFieldBlock(
|
||||
label: '결재 ID',
|
||||
errorText: _errors['approvalId'],
|
||||
child: ShadInput(
|
||||
key: const ValueKey('step_form_approval_id'),
|
||||
controller: _approvalIdController,
|
||||
onChanged: (_) => _clearError('approvalId'),
|
||||
),
|
||||
)
|
||||
else ...[
|
||||
_FormFieldBlock(
|
||||
label: '결재 ID',
|
||||
child: ShadInput(
|
||||
controller: _approvalIdController,
|
||||
readOnly: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_FormFieldBlock(
|
||||
label: '결재번호',
|
||||
child: ShadInput(
|
||||
controller: _approvalNoController,
|
||||
readOnly: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
if (!widget.isEditing) const SizedBox(height: 16),
|
||||
if (!widget.isEditing)
|
||||
_FormFieldBlock(
|
||||
label: '단계 순서',
|
||||
errorText: _errors['stepOrder'],
|
||||
label: '결재 ID',
|
||||
errorText: _errors['approvalId'],
|
||||
child: ShadInput(
|
||||
key: const ValueKey('step_form_step_order'),
|
||||
controller: _stepOrderController,
|
||||
onChanged: (_) => _clearError('stepOrder'),
|
||||
key: const ValueKey('step_form_approval_id'),
|
||||
controller: _approvalIdController,
|
||||
onChanged: (_) => _clearError('approvalId'),
|
||||
),
|
||||
)
|
||||
else ...[
|
||||
_FormFieldBlock(
|
||||
label: '결재 ID',
|
||||
child: ShadInput(
|
||||
controller: _approvalIdController,
|
||||
readOnly: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_FormFieldBlock(
|
||||
label: '승인자 ID',
|
||||
errorText: _errors['approverId'],
|
||||
label: '결재번호',
|
||||
child: ShadInput(
|
||||
key: const ValueKey('step_form_approver_id'),
|
||||
controller: _approverIdController,
|
||||
onChanged: (_) => _clearError('approverId'),
|
||||
controller: _approvalNoController,
|
||||
readOnly: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_FormFieldBlock(
|
||||
label: '비고',
|
||||
helperText: '필요 시 단계에 대한 참고 내용을 남길 수 있습니다.',
|
||||
child: ShadTextarea(
|
||||
key: const ValueKey('step_form_note'),
|
||||
controller: _noteController,
|
||||
minHeight: 100,
|
||||
maxHeight: 200,
|
||||
),
|
||||
),
|
||||
if (_errors['form'] != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: Text(
|
||||
_errors['form']!,
|
||||
style: theme.textTheme.small.copyWith(
|
||||
color: materialTheme.colorScheme.error,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!widget.isEditing) const SizedBox(height: 16),
|
||||
_FormFieldBlock(
|
||||
label: '단계 순서',
|
||||
errorText: _errors['stepOrder'],
|
||||
child: ShadInput(
|
||||
key: const ValueKey('step_form_step_order'),
|
||||
controller: _stepOrderController,
|
||||
onChanged: (_) => _clearError('stepOrder'),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_FormFieldBlock(
|
||||
label: '승인자 ID',
|
||||
errorText: _errors['approverId'],
|
||||
child: ShadInput(
|
||||
key: const ValueKey('step_form_approver_id'),
|
||||
controller: _approverIdController,
|
||||
onChanged: (_) => _clearError('approverId'),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_FormFieldBlock(
|
||||
label: '비고',
|
||||
helperText: '필요 시 단계에 대한 참고 내용을 남길 수 있습니다.',
|
||||
child: ShadTextarea(
|
||||
key: const ValueKey('step_form_note'),
|
||||
controller: _noteController,
|
||||
minHeight: 100,
|
||||
maxHeight: 200,
|
||||
),
|
||||
),
|
||||
if (_errors['form'] != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: Text(
|
||||
_errors['form']!,
|
||||
style: theme.textTheme.small.copyWith(
|
||||
color: materialTheme.colorScheme.error,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user