Apply clinic lab workflow feedback
This commit is contained in:
@@ -418,10 +418,32 @@ class _LabJobDetailScreenState extends ConsumerState<LabJobDetailScreen> {
|
||||
icon: Icons.notes,
|
||||
label: 'Açıklama',
|
||||
value: job.description!),
|
||||
if (job.workflowType == JobWorkflowType.arjinat ||
|
||||
job.workflowType == JobWorkflowType.geleneksel) ...[
|
||||
const SizedBox(height: 10),
|
||||
_WorkflowAttentionBanner(type: job.workflowType!),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
FutureBuilder<List<JobHistoryEntry>>(
|
||||
future: _historyFuture,
|
||||
builder: (context, snapshot) {
|
||||
final entries = snapshot.data ?? const <JobHistoryEntry>[];
|
||||
final revisions = entries
|
||||
.where((entry) =>
|
||||
entry.action == JobHistoryAction.revisionRequested &&
|
||||
entry.note?.trim().isNotEmpty == true)
|
||||
.toList();
|
||||
if (revisions.isEmpty) return const SizedBox.shrink();
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: _LatestRevisionBanner(entry: revisions.last),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Stepper
|
||||
@@ -549,6 +571,106 @@ class _LabJobDetailScreenState extends ConsumerState<LabJobDetailScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
class _WorkflowAttentionBanner extends StatelessWidget {
|
||||
const _WorkflowAttentionBanner({required this.type});
|
||||
|
||||
final JobWorkflowType type;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isArjinat = type == JobWorkflowType.arjinat;
|
||||
final color = isArjinat ? AppColors.pending : AppColors.accent;
|
||||
final bg = isArjinat ? AppColors.pendingBg : AppColors.inProgressBg;
|
||||
final text = isArjinat
|
||||
? 'Arjinat ölçü: ölçü/model kontrolünü daha dikkatli doğrulayın.'
|
||||
: 'Geleneksel ölçü: fiziksel ölçü ve kapanış kaydı kontrolü beklenir.';
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: bg,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: color.withValues(alpha: 0.35)),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
isArjinat
|
||||
? Icons.priority_high_rounded
|
||||
: Icons.assignment_turned_in_outlined,
|
||||
color: color,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: color,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _LatestRevisionBanner extends StatelessWidget {
|
||||
const _LatestRevisionBanner({required this.entry});
|
||||
|
||||
final JobHistoryEntry entry;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.cancelledBg,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: AppColors.cancelled.withValues(alpha: 0.25)),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Icon(Icons.loop_rounded, color: AppColors.cancelled, size: 20),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
entry.step == null
|
||||
? 'Revizyon Notu'
|
||||
: 'Revizyon Notu · ${entry.step!.label}',
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: AppColors.cancelled,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
Text(
|
||||
entry.note!.trim(),
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
height: 1.35,
|
||||
color: AppColors.textPrimary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Hand to Clinic Sheet ─────────────────────────────────────────────────────
|
||||
|
||||
class _HandToClinicSheet extends StatefulWidget {
|
||||
@@ -578,11 +700,14 @@ class _HandToClinicSheetState extends State<_HandToClinicSheet> {
|
||||
final isLast = widget.job.isLastStep;
|
||||
final stepLabel = currentStep?.label ?? '';
|
||||
final requiresClinicApproval = currentStep?.requiresClinicApproval ?? true;
|
||||
final continuesInLab = !widget.job.provaRequired &&
|
||||
currentStep == JobStep.olcuKontrol &&
|
||||
widget.job.nextStep == JobStep.cilaBitim;
|
||||
final buttonLabel = isLast
|
||||
? (widget.job.provaRequired
|
||||
? 'Son Prova · Teslime Gönder'
|
||||
: 'Teslime Gönder')
|
||||
: requiresClinicApproval
|
||||
: requiresClinicApproval && !continuesInLab
|
||||
? '$stepLabel için Kliniğe Gönder'
|
||||
: '$stepLabel tamamlandı, sonraki adıma geç';
|
||||
final buttonColor = isLast ? AppColors.success : AppColors.inProgress;
|
||||
@@ -613,7 +738,7 @@ class _HandToClinicSheetState extends State<_HandToClinicSheet> {
|
||||
Text(
|
||||
isLast
|
||||
? 'İş teslim edilecek olarak işaretlenecek.'
|
||||
: requiresClinicApproval
|
||||
: requiresClinicApproval && !continuesInLab
|
||||
? 'İş klinikteki prova veya onay için gönderilecek.'
|
||||
: 'Bu iç adım tamamlanacak ve iş laboratuvarda ilerleyecek.',
|
||||
style: const TextStyle(color: AppColors.textSecondary),
|
||||
@@ -649,7 +774,7 @@ class _HandToClinicSheetState extends State<_HandToClinicSheet> {
|
||||
SnackBar(
|
||||
content: Text(isLast
|
||||
? 'İş teslim için gönderildi'
|
||||
: requiresClinicApproval
|
||||
: requiresClinicApproval && !continuesInLab
|
||||
? 'Onay için kliniğe gönderildi'
|
||||
: 'İş bir sonraki iç adıma geçirildi')),
|
||||
);
|
||||
|
||||
@@ -28,6 +28,7 @@ class LabJobsRepository {
|
||||
perPage: limit,
|
||||
filter: filterParts.join(' && '),
|
||||
expand: _listExpand,
|
||||
sort: '-created',
|
||||
);
|
||||
return (result.items.map((r) => Job.fromJson(r.toJson())).toList()
|
||||
..sort((a, b) => b.dateCreated.compareTo(a.dateCreated)));
|
||||
@@ -44,6 +45,7 @@ class LabJobsRepository {
|
||||
perPage: limit,
|
||||
filter: filterParts.join(' && '),
|
||||
expand: _listExpand,
|
||||
sort: location == null ? '-created' : null,
|
||||
);
|
||||
return (result.items.map((r) => Job.fromJson(r.toJson())).toList()
|
||||
..sort((a, b) {
|
||||
@@ -89,9 +91,12 @@ class LabJobsRepository {
|
||||
|
||||
final isFinal = currentStep == JobStep.cilaBitim;
|
||||
final nextStep = job.nextStep;
|
||||
final shouldStayAtLabAfterMeasure = !job.provaRequired &&
|
||||
currentStep == JobStep.olcuKontrol &&
|
||||
nextStep == JobStep.cilaBitim;
|
||||
final patch = isFinal
|
||||
? {'status': 'sent', 'location': 'at_clinic'}
|
||||
: currentStep.requiresClinicApproval
|
||||
: currentStep.requiresClinicApproval && !shouldStayAtLabAfterMeasure
|
||||
? {'location': 'at_clinic'}
|
||||
: {
|
||||
'current_step': nextStep?.value,
|
||||
@@ -104,7 +109,9 @@ class LabJobsRepository {
|
||||
jobId: jobId,
|
||||
clinicTenantId: job.clinicTenantId,
|
||||
labTenantId: job.labTenantId,
|
||||
action: currentStep.requiresClinicApproval || isFinal
|
||||
action: (currentStep.requiresClinicApproval &&
|
||||
!shouldStayAtLabAfterMeasure) ||
|
||||
isFinal
|
||||
? JobHistoryAction.handedToClinic
|
||||
: JobHistoryAction.stepCompleted,
|
||||
step: currentStep,
|
||||
|
||||
Reference in New Issue
Block a user