Three features: labor group headers, status picker, catalog import

- LaborResource: add titlePrefixedWithLabel(false) so group headers show
  just the localized category name (not "Categorie: Шины"); remove static
  cache from closure to avoid Octane cross-request locale bleed
- WorkOrderDashboard: add changeStatus() Livewire method + Alpine.js
  dropdown on the status badge so status can be changed directly from
  the dashboard without going to the full edit form
- New artisan command catalog:import-labors {company} that reads
  database/data/labor-catalog.json (386 operations, 45 leaf categories)
  and upserts labor_categories + labors for the given tenant; supports
  --force to update existing records by code
- Add "Status actualizat" translation to ru/en JSON

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-09-08 04:38:35 +00:00
parent 06fac16026
commit 5e923459f7
7 changed files with 5512 additions and 6 deletions
@@ -380,10 +380,27 @@
{{-- ── TOP BAR ── --}}
<div class="wd-topbar">
<span class="wd-wo-title">{{ __('Fișă') }} {{ $wo->number }}<x-hint key="wo.dashboard.overview" /></span>
<span class="wd-status {{ $statusClass }}">
{{ __(\App\Models\Tenant\WorkOrder::STATUSES[$wo->status] ?? $wo->status) }}
<span style="opacity:.6;">▾</span>
</span>
<div x-data="{ open: false }" style="position:relative;display:inline-flex;">
<span class="wd-status {{ $statusClass }}" @click="open = !open" style="cursor:pointer;user-select:none;">
{{ __(\App\Models\Tenant\WorkOrder::STATUSES[$wo->status] ?? $wo->status) }}
<span style="opacity:.6;">▾</span>
</span>
<div x-show="open" x-cloak @click.outside="open = false"
style="position:absolute;top:calc(100% + 6px);left:0;z-index:100;background:#fff;border:1px solid #e5e7eb;border-radius:8px;box-shadow:0 4px 20px rgba(0,0,0,.13);min-width:200px;overflow:hidden;">
@foreach (\App\Models\Tenant\WorkOrder::STATUSES as $sKey => $sLabel)
<button type="button"
wire:click="changeStatus('{{ $sKey }}')"
@click="open = false"
style="display:flex;align-items:center;gap:8px;width:100%;text-align:left;padding:9px 14px;border:none;background:{{ $sKey === $wo->status ? '#f3f4f6' : 'none' }};cursor:{{ $sKey === $wo->status ? 'default' : 'pointer' }};font-size:.875rem;color:#111827;"
@if ($sKey === $wo->status) disabled @endif
onmouseover="if(!this.disabled)this.style.background='#f9fafb'"
onmouseout="if(!this.disabled)this.style.background='{{ $sKey === $wo->status ? '#f3f4f6' : 'none' }}'">
@if ($sKey === $wo->status)<span style="color:#6b7280;font-size:.75rem;">✓</span>@endif
{{ __($sLabel) }}
</button>
@endforeach
</div>
</div>
<div class="wd-topbar-actions">
<x-hint key="wo.dashboard.topbar_actions" />
<a class="wd-btn" href="{{ url('/app/work-orders') }}" title="{{ __('Toate fișele') }}">