- Pinia stores: orders (CRUD, line management, totals recalc, stats) and vehicles (CRUD, search, marca/model cascade) - useSync composable: auto-sync on window focus + periodic 60s interval - VehiclePicker component: debounced autocomplete search by nr. inmatriculare or client name - OrderLineForm component: manopera/material toggle with live total preview - DashboardView: stats cards (orders, vehicles, revenue), recent orders list - OrdersListView: filterable table (all/draft/validat/facturat), clickable rows - OrderCreateView: vehicle picker + inline new vehicle form, tip deviz select, km/observatii - OrderDetailView: order info, lines table with add/remove, totals, validate action - VehiclesListView: searchable table, inline create form with marca/model cascade - AppLayout: mobile hamburger menu with slide-in sidebar overlay Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
111 lines
3.7 KiB
Vue
111 lines
3.7 KiB
Vue
<template>
|
|
<div>
|
|
<div class="flex items-center justify-between mb-6">
|
|
<h1 class="text-2xl font-bold text-gray-900">Comenzi</h1>
|
|
<router-link
|
|
to="/orders/new"
|
|
class="px-4 py-2 bg-blue-600 text-white text-sm rounded-md hover:bg-blue-700"
|
|
>
|
|
+ Comanda noua
|
|
</router-link>
|
|
</div>
|
|
|
|
<!-- Filters -->
|
|
<div class="flex gap-2 mb-4">
|
|
<button
|
|
v-for="f in filters"
|
|
:key="f.value"
|
|
@click="activeFilter = f.value"
|
|
class="px-3 py-1.5 text-sm rounded-md"
|
|
:class="activeFilter === f.value
|
|
? 'bg-blue-600 text-white'
|
|
: 'bg-white text-gray-700 border border-gray-300 hover:bg-gray-50'"
|
|
>
|
|
{{ f.label }}
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Orders table -->
|
|
<div class="bg-white rounded-lg shadow overflow-hidden">
|
|
<div v-if="loading" class="p-4 text-center text-gray-500">Se incarca...</div>
|
|
<div v-else-if="orders.length === 0" class="p-8 text-center text-gray-500">
|
|
Nicio comanda gasita.
|
|
</div>
|
|
<table v-else class="min-w-full divide-y divide-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Nr. comanda</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Nr. auto</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase hidden md:table-cell">Client</th>
|
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Status</th>
|
|
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">Total</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-gray-100">
|
|
<tr
|
|
v-for="o in orders"
|
|
:key="o.id"
|
|
class="hover:bg-gray-50 cursor-pointer"
|
|
@click="$router.push(`/orders/${o.id}`)"
|
|
>
|
|
<td class="px-4 py-3 text-sm font-medium text-gray-900">{{ o.nr_comanda }}</td>
|
|
<td class="px-4 py-3 text-sm text-gray-600">{{ o.nr_auto || '-' }}</td>
|
|
<td class="px-4 py-3 text-sm text-gray-600 hidden md:table-cell">{{ o.client_nume || '-' }}</td>
|
|
<td class="px-4 py-3">
|
|
<span
|
|
class="inline-block px-2 py-0.5 rounded-full text-xs font-medium"
|
|
:class="statusClass(o.status)"
|
|
>
|
|
{{ o.status }}
|
|
</span>
|
|
</td>
|
|
<td class="px-4 py-3 text-sm text-right font-medium text-gray-900">
|
|
{{ (o.total_general || 0).toFixed(2) }}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, watch, onMounted } from 'vue'
|
|
import { useOrdersStore } from '../../stores/orders.js'
|
|
import { onTableChange } from '../../db/database.js'
|
|
|
|
const ordersStore = useOrdersStore()
|
|
const orders = ref([])
|
|
const loading = ref(true)
|
|
const activeFilter = ref(null)
|
|
|
|
const filters = [
|
|
{ label: 'Toate', value: null },
|
|
{ label: 'Draft', value: 'DRAFT' },
|
|
{ label: 'Validate', value: 'VALIDAT' },
|
|
{ label: 'Facturate', value: 'FACTURAT' },
|
|
]
|
|
|
|
async function loadOrders() {
|
|
loading.value = true
|
|
orders.value = await ordersStore.getAll(activeFilter.value)
|
|
loading.value = false
|
|
}
|
|
|
|
watch(activeFilter, loadOrders)
|
|
|
|
onMounted(() => {
|
|
loadOrders()
|
|
onTableChange('orders', loadOrders)
|
|
})
|
|
|
|
function statusClass(status) {
|
|
switch (status) {
|
|
case 'DRAFT': return 'bg-yellow-100 text-yellow-800'
|
|
case 'VALIDAT': return 'bg-green-100 text-green-800'
|
|
case 'FACTURAT': return 'bg-blue-100 text-blue-800'
|
|
default: return 'bg-gray-100 text-gray-800'
|
|
}
|
|
}
|
|
</script>
|