feat(dialog): 상세 팝업 SuperportDetailDialog 통합
- SuperportDetailDialog 위젯과 showSuperportDetailDialog 헬퍼를 추가하고 metadata/섹션 패턴을 표준화 - 결재/재고/마스터 각 상세 다이얼로그를 dialogs 디렉터리에 신설하고 기존 페이지를 신규 팝업으로 전환 - SuperportTable 행 선택과 우편번호 검색 다이얼로그 onRowTap 보정을 통해 헤더 오프셋 버그를 제거 - 상세 다이얼로그 및 트랜잭션/상세 뷰 전용 위젯 테스트와 tester_extensions 유틸을 추가하여 회귀를 방지 - detail_dialog_unification_plan.md로 작업 배경과 필드 통합 계획을 문서화
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
import 'package:lucide_icons_flutter/lucide_icons.dart' as lucide;
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
@@ -11,8 +12,10 @@ import '../../../../../widgets/app_layout.dart';
|
||||
import '../../../../../widgets/components/filter_bar.dart';
|
||||
import '../../../../../widgets/components/superport_dialog.dart';
|
||||
import '../../../../../widgets/components/superport_pagination_controls.dart';
|
||||
import '../../../../../widgets/components/superport_table.dart';
|
||||
import '../../../../../widgets/components/feature_disabled_placeholder.dart';
|
||||
import '../controllers/approval_step_controller.dart';
|
||||
import '../dialogs/approval_step_detail_dialog.dart';
|
||||
import '../../domain/entities/approval_step_input.dart';
|
||||
import '../../domain/entities/approval_step_record.dart';
|
||||
import '../../domain/repositories/approval_step_repository.dart';
|
||||
@@ -70,7 +73,7 @@ class _ApprovalStepEnabledPageState extends State<_ApprovalStepEnabledPage> {
|
||||
late final ApprovalStepController _controller;
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
final FocusNode _searchFocus = FocusNode();
|
||||
final DateFormat _dateFormat = DateFormat('yyyy-MM-dd HH:mm');
|
||||
final intl.DateFormat _dateFormat = intl.DateFormat('yyyy-MM-dd HH:mm');
|
||||
String? _lastError;
|
||||
|
||||
@override
|
||||
@@ -253,154 +256,77 @@ class _ApprovalStepEnabledPageState extends State<_ApprovalStepEnabledPage> {
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 480,
|
||||
child: ShadTable.list(
|
||||
header:
|
||||
[
|
||||
'ID',
|
||||
'결재번호',
|
||||
'단계순서',
|
||||
'승인자',
|
||||
'상태',
|
||||
'배정일시',
|
||||
'결정일시',
|
||||
'동작',
|
||||
]
|
||||
.map(
|
||||
(label) => ShadTableCell.header(
|
||||
child: Text(label),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
columnSpanExtent: (index) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
return const FixedTableSpanExtent(160);
|
||||
case 2:
|
||||
return const FixedTableSpanExtent(100);
|
||||
case 3:
|
||||
return const FixedTableSpanExtent(150);
|
||||
case 4:
|
||||
return const FixedTableSpanExtent(120);
|
||||
case 5:
|
||||
case 6:
|
||||
return const FixedTableSpanExtent(160);
|
||||
case 7:
|
||||
return const FixedTableSpanExtent(110);
|
||||
default:
|
||||
return const FixedTableSpanExtent(90);
|
||||
}
|
||||
},
|
||||
children: records.map((record) {
|
||||
final step = record.step;
|
||||
final isDeleted = step.isDeleted;
|
||||
return [
|
||||
ShadTableCell(
|
||||
child: Text(step.id?.toString() ?? '-'),
|
||||
),
|
||||
ShadTableCell(child: Text(record.approvalNo)),
|
||||
ShadTableCell(child: Text('${step.stepOrder}')),
|
||||
ShadTableCell(child: Text(step.approver.name)),
|
||||
ShadTableCell(
|
||||
child: ShadBadge(child: Text(step.status.name)),
|
||||
),
|
||||
ShadTableCell(
|
||||
child: Text(_formatDate(step.assignedAt)),
|
||||
),
|
||||
ShadTableCell(
|
||||
child: Text(
|
||||
step.decidedAt == null
|
||||
? '-'
|
||||
: _formatDate(step.decidedAt!),
|
||||
),
|
||||
),
|
||||
ShadTableCell(
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Wrap(
|
||||
spacing: 8,
|
||||
children: [
|
||||
PermissionGate(
|
||||
resource: _stepResourcePath,
|
||||
action: PermissionAction.view,
|
||||
child: ShadButton.outline(
|
||||
key: ValueKey(
|
||||
'step_detail_${step.id ?? record.approvalId}_${step.stepOrder}',
|
||||
),
|
||||
size: ShadButtonSize.sm,
|
||||
onPressed:
|
||||
step.id == null ||
|
||||
_controller.isLoading ||
|
||||
isSaving
|
||||
? null
|
||||
: () => _openDetail(record),
|
||||
child: const Text('상세'),
|
||||
),
|
||||
),
|
||||
if (step.id != null && !isDeleted)
|
||||
PermissionGate(
|
||||
resource: _stepResourcePath,
|
||||
action: PermissionAction.edit,
|
||||
child: ShadButton(
|
||||
key: ValueKey(
|
||||
'step_edit_${step.id}_${step.stepOrder}',
|
||||
),
|
||||
size: ShadButtonSize.sm,
|
||||
onPressed:
|
||||
_controller.isLoading ||
|
||||
isSaving
|
||||
? null
|
||||
: () =>
|
||||
_openEditStepForm(record),
|
||||
child: const Text('수정'),
|
||||
),
|
||||
),
|
||||
if (step.id != null && !isDeleted)
|
||||
PermissionGate(
|
||||
resource: _stepResourcePath,
|
||||
action: PermissionAction.delete,
|
||||
child: ShadButton.destructive(
|
||||
key: ValueKey(
|
||||
'step_delete_${step.id}_${step.stepOrder}',
|
||||
),
|
||||
size: ShadButtonSize.sm,
|
||||
onPressed:
|
||||
_controller.isLoading ||
|
||||
isSaving
|
||||
? null
|
||||
: () => _confirmDeleteStep(
|
||||
record,
|
||||
),
|
||||
child: const Text('삭제'),
|
||||
),
|
||||
),
|
||||
if (step.id != null && isDeleted)
|
||||
PermissionGate(
|
||||
resource: _stepResourcePath,
|
||||
action: PermissionAction.restore,
|
||||
child: ShadButton.outline(
|
||||
key: ValueKey(
|
||||
'step_restore_${step.id}_${step.stepOrder}',
|
||||
),
|
||||
size: ShadButtonSize.sm,
|
||||
onPressed:
|
||||
_controller.isLoading ||
|
||||
isSaving
|
||||
? null
|
||||
: () => _confirmRestoreStep(
|
||||
record,
|
||||
),
|
||||
child: const Text('복구'),
|
||||
),
|
||||
),
|
||||
],
|
||||
SuperportTable(
|
||||
columns: const [
|
||||
Text('ID'),
|
||||
Text('결재번호'),
|
||||
Text('단계순서'),
|
||||
Text('승인자'),
|
||||
Text('상태'),
|
||||
Text('배정일시'),
|
||||
Text('결정일시'),
|
||||
],
|
||||
rows: records.map((record) {
|
||||
final step = record.step;
|
||||
final isDeleted = step.isDeleted;
|
||||
final decidedAt = step.decidedAt;
|
||||
return [
|
||||
Text(step.id?.toString() ?? '-'),
|
||||
Text(record.approvalNo),
|
||||
Text('${step.stepOrder}'),
|
||||
Text(step.approver.name),
|
||||
Row(
|
||||
children: [
|
||||
ShadBadge(child: Text(step.status.name)),
|
||||
if (isDeleted) ...[
|
||||
const SizedBox(width: 8),
|
||||
const ShadBadge.destructive(
|
||||
child: Text('삭제됨'),
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
}).toList(),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
Text(_formatDate(step.assignedAt)),
|
||||
Text(
|
||||
decidedAt == null ? '-' : _formatDate(decidedAt),
|
||||
),
|
||||
];
|
||||
}).toList(),
|
||||
rowHeight: 56,
|
||||
maxHeight: 520,
|
||||
columnSpanExtent: (index) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
return const FixedTableSpanExtent(160);
|
||||
case 2:
|
||||
return const FixedTableSpanExtent(100);
|
||||
case 3:
|
||||
return const FixedTableSpanExtent(150);
|
||||
case 4:
|
||||
return const FixedTableSpanExtent(200);
|
||||
case 5:
|
||||
case 6:
|
||||
return const FixedTableSpanExtent(160);
|
||||
default:
|
||||
return const FixedTableSpanExtent(90);
|
||||
}
|
||||
},
|
||||
onRowTap: (_controller.isLoading || isSaving)
|
||||
? null
|
||||
: (index) {
|
||||
if (records.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final int safeIndex;
|
||||
if (index < 0) {
|
||||
safeIndex = 0;
|
||||
} else if (index >= records.length) {
|
||||
safeIndex = records.length - 1;
|
||||
} else {
|
||||
safeIndex = index;
|
||||
}
|
||||
_openDetail(records[safeIndex]);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
@@ -471,11 +397,7 @@ class _ApprovalStepEnabledPageState extends State<_ApprovalStepEnabledPage> {
|
||||
final input = await showDialog<ApprovalStepInput>(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return _StepFormDialog(
|
||||
title: '결재 단계 추가',
|
||||
submitLabel: '저장',
|
||||
isEditing: false,
|
||||
);
|
||||
return _StepFormDialog(title: '결재 단계 추가', submitLabel: '저장');
|
||||
},
|
||||
);
|
||||
|
||||
@@ -494,43 +416,6 @@ class _ApprovalStepEnabledPageState extends State<_ApprovalStepEnabledPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _openEditStepForm(ApprovalStepRecord record) async {
|
||||
final stepId = record.step.id;
|
||||
if (stepId == null) {
|
||||
final messenger = ScaffoldMessenger.maybeOf(context);
|
||||
messenger?.showSnackBar(
|
||||
const SnackBar(content: Text('저장되지 않은 단계는 수정할 수 없습니다.')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final input = await showDialog<ApprovalStepInput>(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return _StepFormDialog(
|
||||
title: '결재 단계 수정',
|
||||
submitLabel: '저장',
|
||||
isEditing: true,
|
||||
initialRecord: record,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (!mounted || input == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final updated = await _controller.updateStep(stepId, input);
|
||||
if (!mounted || updated == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final messenger = ScaffoldMessenger.maybeOf(context);
|
||||
messenger?.showSnackBar(
|
||||
SnackBar(content: Text('결재번호 ${updated.approvalNo} 단계 정보를 수정했습니다.')),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _openDetail(ApprovalStepRecord record) async {
|
||||
final stepId = record.step.id;
|
||||
if (stepId == null) {
|
||||
@@ -548,146 +433,44 @@ class _ApprovalStepEnabledPageState extends State<_ApprovalStepEnabledPage> {
|
||||
final detail = await _controller.fetchDetail(stepId);
|
||||
if (!mounted) return;
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
if (detail == null) return;
|
||||
final step = detail.step;
|
||||
await SuperportDialog.show<void>(
|
||||
context: context,
|
||||
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!),
|
||||
),
|
||||
_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),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ShadTextarea(
|
||||
initialValue: step.note ?? '',
|
||||
readOnly: true,
|
||||
minHeight: 80,
|
||||
maxHeight: 200,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (detail == null) {
|
||||
final error = _controller.errorMessage;
|
||||
if (error != null) {
|
||||
final messenger = ScaffoldMessenger.maybeOf(context);
|
||||
messenger?.showSnackBar(SnackBar(content: Text(error)));
|
||||
_controller.clearError();
|
||||
}
|
||||
return;
|
||||
}
|
||||
final permissionManager = PermissionScope.of(context);
|
||||
final canEdit = permissionManager.can(
|
||||
_stepResourcePath,
|
||||
PermissionAction.edit,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _confirmDeleteStep(ApprovalStepRecord record) async {
|
||||
final stepId = record.step.id;
|
||||
if (stepId == null) {
|
||||
final messenger = ScaffoldMessenger.maybeOf(context);
|
||||
messenger?.showSnackBar(
|
||||
const SnackBar(content: Text('저장되지 않은 단계는 삭제할 수 없습니다.')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final confirmed = await SuperportDialog.show<bool>(
|
||||
context: context,
|
||||
dialog: SuperportDialog(
|
||||
title: '결재 단계 삭제',
|
||||
description:
|
||||
'결재번호 ${record.approvalNo}의 ${record.step.stepOrder}단계를 삭제하시겠습니까? 삭제 후 복구할 수 있습니다.',
|
||||
actions: [
|
||||
ShadButton.ghost(
|
||||
onPressed: () =>
|
||||
Navigator.of(context, rootNavigator: true).pop(false),
|
||||
child: const Text('취소'),
|
||||
),
|
||||
ShadButton.destructive(
|
||||
onPressed: () =>
|
||||
Navigator.of(context, rootNavigator: true).pop(true),
|
||||
child: const Text('삭제'),
|
||||
),
|
||||
],
|
||||
),
|
||||
final canDelete = permissionManager.can(
|
||||
_stepResourcePath,
|
||||
PermissionAction.delete,
|
||||
);
|
||||
|
||||
if (confirmed != true) {
|
||||
return;
|
||||
}
|
||||
|
||||
final success = await _controller.deleteStep(stepId);
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
if (success) {
|
||||
final messenger = ScaffoldMessenger.maybeOf(context);
|
||||
messenger?.showSnackBar(
|
||||
SnackBar(content: Text('결재번호 ${record.approvalNo} 단계가 삭제되었습니다.')),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _confirmRestoreStep(ApprovalStepRecord record) async {
|
||||
final stepId = record.step.id;
|
||||
if (stepId == null) {
|
||||
final messenger = ScaffoldMessenger.maybeOf(context);
|
||||
messenger?.showSnackBar(
|
||||
const SnackBar(content: Text('단계 식별자가 없어 복구할 수 없습니다.')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final confirmed = await SuperportDialog.show<bool>(
|
||||
context: context,
|
||||
dialog: SuperportDialog(
|
||||
title: '결재 단계 복구',
|
||||
description:
|
||||
'결재번호 ${record.approvalNo}의 ${record.step.stepOrder}단계를 복구하시겠습니까?',
|
||||
actions: [
|
||||
ShadButton.ghost(
|
||||
onPressed: () =>
|
||||
Navigator.of(context, rootNavigator: true).pop(false),
|
||||
child: const Text('취소'),
|
||||
),
|
||||
ShadButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(context, rootNavigator: true).pop(true),
|
||||
child: const Text('복구'),
|
||||
),
|
||||
],
|
||||
),
|
||||
final canRestore = permissionManager.can(
|
||||
_stepResourcePath,
|
||||
PermissionAction.restore,
|
||||
);
|
||||
|
||||
if (confirmed != true) {
|
||||
final result = await showApprovalStepDetailDialog(
|
||||
context: context,
|
||||
record: detail,
|
||||
dateFormat: _dateFormat,
|
||||
onUpdate: (id, input) => _controller.updateStep(id, input),
|
||||
onDelete: (id) => _controller.deleteStep(id),
|
||||
onRestore: (id) => _controller.restoreStep(id),
|
||||
canEdit: canEdit,
|
||||
canDelete: canDelete,
|
||||
canRestore: canRestore,
|
||||
);
|
||||
if (!mounted || result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final restored = await _controller.restoreStep(stepId);
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
if (restored != null) {
|
||||
final messenger = ScaffoldMessenger.maybeOf(context);
|
||||
messenger?.showSnackBar(
|
||||
SnackBar(content: Text('결재번호 ${restored.approvalNo} 단계가 복구되었습니다.')),
|
||||
);
|
||||
}
|
||||
final messenger = ScaffoldMessenger.maybeOf(context);
|
||||
messenger?.showSnackBar(SnackBar(content: Text(result.message)));
|
||||
}
|
||||
|
||||
String _formatDate(DateTime date) {
|
||||
@@ -725,48 +508,11 @@ class _ApproverOption {
|
||||
int get hashCode => id.hashCode;
|
||||
}
|
||||
|
||||
class _DetailRow extends StatelessWidget {
|
||||
const _DetailRow({required this.label, required this.value});
|
||||
|
||||
final String label;
|
||||
final String value;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ShadTheme.of(context);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 120,
|
||||
child: Text(
|
||||
label,
|
||||
style: theme.textTheme.small.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(child: Text(value, style: theme.textTheme.small)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _StepFormDialog extends StatefulWidget {
|
||||
const _StepFormDialog({
|
||||
required this.title,
|
||||
required this.submitLabel,
|
||||
required this.isEditing,
|
||||
this.initialRecord,
|
||||
});
|
||||
const _StepFormDialog({required this.title, required this.submitLabel});
|
||||
|
||||
final String title;
|
||||
final String submitLabel;
|
||||
final bool isEditing;
|
||||
final ApprovalStepRecord? initialRecord;
|
||||
|
||||
@override
|
||||
State<_StepFormDialog> createState() => _StepFormDialogState();
|
||||
@@ -774,7 +520,6 @@ class _StepFormDialog extends StatefulWidget {
|
||||
|
||||
class _StepFormDialogState extends State<_StepFormDialog> {
|
||||
late final TextEditingController _approvalIdController;
|
||||
late final TextEditingController _approvalNoController;
|
||||
late final TextEditingController _stepOrderController;
|
||||
late final TextEditingController _approverIdController;
|
||||
late final TextEditingController _noteController;
|
||||
@@ -783,28 +528,15 @@ class _StepFormDialogState extends State<_StepFormDialog> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final record = widget.initialRecord;
|
||||
_approvalIdController = TextEditingController(
|
||||
text: widget.isEditing && record != null
|
||||
? record.approvalId.toString()
|
||||
: '',
|
||||
);
|
||||
_approvalNoController = TextEditingController(
|
||||
text: record?.approvalNo ?? '',
|
||||
);
|
||||
_stepOrderController = TextEditingController(
|
||||
text: record?.step.stepOrder.toString() ?? '',
|
||||
);
|
||||
_approverIdController = TextEditingController(
|
||||
text: record?.step.approver.id.toString() ?? '',
|
||||
);
|
||||
_noteController = TextEditingController(text: record?.step.note ?? '');
|
||||
_approvalIdController = TextEditingController();
|
||||
_stepOrderController = TextEditingController();
|
||||
_approverIdController = TextEditingController();
|
||||
_noteController = TextEditingController();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_approvalIdController.dispose();
|
||||
_approvalNoController.dispose();
|
||||
_stepOrderController.dispose();
|
||||
_approverIdController.dispose();
|
||||
_noteController.dispose();
|
||||
@@ -834,34 +566,16 @@ class _StepFormDialogState extends State<_StepFormDialog> {
|
||||
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,
|
||||
),
|
||||
_FormFieldBlock(
|
||||
label: '결재 ID',
|
||||
errorText: _errors['approvalId'],
|
||||
child: ShadInput(
|
||||
key: const ValueKey('step_form_approval_id'),
|
||||
controller: _approvalIdController,
|
||||
onChanged: (_) => _clearError('approvalId'),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_FormFieldBlock(
|
||||
label: '결재번호',
|
||||
child: ShadInput(
|
||||
controller: _approvalNoController,
|
||||
readOnly: true,
|
||||
),
|
||||
),
|
||||
],
|
||||
if (!widget.isEditing) const SizedBox(height: 16),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_FormFieldBlock(
|
||||
label: '단계 순서',
|
||||
errorText: _errors['stepOrder'],
|
||||
@@ -910,14 +624,9 @@ class _StepFormDialogState extends State<_StepFormDialog> {
|
||||
|
||||
void _handleSubmit() {
|
||||
final Map<String, String?> nextErrors = {};
|
||||
int? approvalId;
|
||||
if (widget.isEditing) {
|
||||
approvalId = widget.initialRecord?.approvalId;
|
||||
} else {
|
||||
approvalId = int.tryParse(_approvalIdController.text.trim());
|
||||
if (approvalId == null || approvalId <= 0) {
|
||||
nextErrors['approvalId'] = '결재 ID를 1 이상의 숫자로 입력하세요.';
|
||||
}
|
||||
final approvalId = int.tryParse(_approvalIdController.text.trim());
|
||||
if (approvalId == null || approvalId <= 0) {
|
||||
nextErrors['approvalId'] = '결재 ID를 1 이상의 숫자로 입력하세요.';
|
||||
}
|
||||
|
||||
final stepOrder = int.tryParse(_stepOrderController.text.trim());
|
||||
@@ -941,7 +650,6 @@ class _StepFormDialogState extends State<_StepFormDialog> {
|
||||
stepOrder: stepOrder!,
|
||||
approverId: approverId!,
|
||||
note: note.isEmpty ? null : note,
|
||||
statusId: widget.initialRecord?.step.status.id,
|
||||
);
|
||||
|
||||
Navigator.of(context, rootNavigator: true).pop(input);
|
||||
|
||||
Reference in New Issue
Block a user