203 lines
8.1 KiB
Vue
203 lines
8.1 KiB
Vue
<script setup>
|
|
import AppLayout from '@/Layouts/AppLayout.vue';
|
|
import { Link, useForm } from '@inertiajs/vue3'
|
|
import { computed, ref } from 'vue'
|
|
|
|
const props = defineProps({
|
|
setting: Object,
|
|
contracts: Array,
|
|
users: Array,
|
|
assignments: Object,
|
|
});
|
|
|
|
const form = useForm({
|
|
contract_uuid: null,
|
|
assigned_user_id: null,
|
|
start_date: null,
|
|
end_date: null,
|
|
});
|
|
|
|
// Format helpers (Slovenian formatting)
|
|
function formatDate(value) {
|
|
if (!value) { return '-'; }
|
|
const d = new Date(value);
|
|
if (isNaN(d)) { return value; }
|
|
const dd = String(d.getDate()).padStart(2, '0');
|
|
const mm = String(d.getMonth() + 1).padStart(2, '0');
|
|
const yyyy = d.getFullYear();
|
|
return `${dd}.${mm}.${yyyy}`;
|
|
}
|
|
|
|
function formatCurrencyEUR(value) {
|
|
if (value === null || value === undefined) { return '-'; }
|
|
const n = Number(value);
|
|
if (isNaN(n)) { return String(value); }
|
|
// Thousands separator as dot, decimal as comma, with € suffix
|
|
return n.toLocaleString('sl-SI', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' €';
|
|
}
|
|
|
|
function assign(contract) {
|
|
form.contract_uuid = contract.uuid
|
|
// minimal UX: if no user selected yet, just post will fail with error; page can be enhanced later with dropdown.
|
|
form.post(route('fieldjobs.assign'))
|
|
}
|
|
|
|
function cancelAssignment(contract) {
|
|
const payload = { contract_uuid: contract.uuid }
|
|
form.transform(() => payload).post(route('fieldjobs.cancel'))
|
|
}
|
|
|
|
function isAssigned(contract) {
|
|
return !!(props.assignments && props.assignments[contract.uuid])
|
|
}
|
|
|
|
function assignedTo(contract) {
|
|
return props.assignments?.[contract.uuid]?.assigned_to?.name || null
|
|
}
|
|
|
|
function assignedBy(contract) {
|
|
return props.assignments?.[contract.uuid]?.assigned_by?.name || null
|
|
}
|
|
|
|
// removed window.open behavior; default SPA navigation via Inertia Link
|
|
|
|
// Derived lists
|
|
const unassignedContracts = computed(() => {
|
|
return (props.contracts || []).filter(c => !isAssigned(c))
|
|
})
|
|
|
|
const assignedContracts = computed(() => {
|
|
return (props.contracts || []).filter(c => isAssigned(c))
|
|
})
|
|
|
|
// Filter for assigned table
|
|
const assignedFilterUserId = ref('')
|
|
const assignedContractsFiltered = computed(() => {
|
|
const list = assignedContracts.value
|
|
if (!assignedFilterUserId.value) {
|
|
return list
|
|
}
|
|
return list.filter(c => {
|
|
const uid = props.assignments?.[c.uuid]?.assigned_to?.id
|
|
return String(uid) === String(assignedFilterUserId.value)
|
|
})
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<AppLayout title="Dodeljevanje terenskih opravil">
|
|
<template #header></template>
|
|
<div class="pt-12">
|
|
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
|
<div v-if="!setting" class="bg-yellow-50 border border-yellow-200 text-yellow-800 rounded p-4 mb-6">
|
|
Nastavitev za terenska opravila ni najdena. Najprej jo ustvarite v Nastavitve → Nastavitve terenskih opravil.
|
|
</div>
|
|
<!-- Unassigned (Assignable) Contracts -->
|
|
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg p-6 mb-8">
|
|
<h2 class="text-xl font-semibold mb-4">Pogodbe (nedodeljene)</h2>
|
|
<div class="mb-4">
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Dodeli uporabniku</label>
|
|
<select v-model="form.assigned_user_id" class="border rounded px-3 py-2 w-full max-w-xs">
|
|
<option :value="null" disabled>Izberite uporabnika</option>
|
|
<option v-for="u in users || []" :key="u.id" :value="u.id">{{ u.name }}</option>
|
|
</select>
|
|
<div v-if="form.errors.assigned_user_id" class="text-red-600 text-sm mt-1">{{ form.errors.assigned_user_id }}</div>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full text-left text-sm">
|
|
<thead>
|
|
<tr class="border-b">
|
|
<th class="py-2 pr-4">Sklic</th>
|
|
<th class="py-2 pr-4">Stranka</th>
|
|
<th class="py-2 pr-4">Vrsta</th>
|
|
<th class="py-2 pr-4">Začetek</th>
|
|
<th class="py-2 pr-4">Konec</th>
|
|
<th class="py-2 pr-4">Stanje</th>
|
|
<th class="py-2 pr-4">Dejanje</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="c in unassignedContracts" :key="c.uuid" class="border-b last:border-0">
|
|
<td class="py-2 pr-4">{{ c.reference }}</td>
|
|
<td class="py-2 pr-4">
|
|
<Link
|
|
v-if="c.client_case?.uuid"
|
|
:href="route('clientCase.show', { client_case: c.client_case.uuid })"
|
|
class="text-indigo-600 hover:underline"
|
|
>
|
|
{{ c.client_case?.person?.full_name || 'Primer stranke' }}
|
|
</Link>
|
|
<span v-else>{{ c.client_case?.person?.full_name || '-' }}</span>
|
|
</td>
|
|
<td class="py-2 pr-4">{{ c.type?.name }}</td>
|
|
<td class="py-2 pr-4">{{ formatDate(c.start_date) }}</td>
|
|
<td class="py-2 pr-4">{{ formatDate(c.end_date) }}</td>
|
|
<td class="py-2 pr-4">{{ formatCurrencyEUR(c.account?.balance_amount) }}</td>
|
|
<td class="py-2 pr-4 flex items-center gap-2">
|
|
<button
|
|
class="px-3 py-1 text-sm rounded bg-indigo-600 text-white"
|
|
@click="assign(c)"
|
|
>Dodeli</button>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Assigned Contracts -->
|
|
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg p-6">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h2 class="text-xl font-semibold">Dodeljene pogodbe</h2>
|
|
<div class="flex items-center gap-2">
|
|
<label class="text-sm text-gray-700">Filter po uporabniku</label>
|
|
<select v-model="assignedFilterUserId" class="border rounded px-3 py-2">
|
|
<option value="">Vsi</option>
|
|
<option v-for="u in users || []" :key="u.id" :value="u.id">{{ u.name }}</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full text-left text-sm">
|
|
<thead>
|
|
<tr class="border-b">
|
|
<th class="py-2 pr-4">Sklic</th>
|
|
<th class="py-2 pr-4">Stranka</th>
|
|
<th class="py-2 pr-4">Dodeljeno dne</th>
|
|
<th class="py-2 pr-4">Dodeljeno komu</th>
|
|
<th class="py-2 pr-4">Stanje</th>
|
|
<th class="py-2 pr-4">Dejanje</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="c in assignedContractsFiltered" :key="c.uuid" class="border-b last:border-0">
|
|
<td class="py-2 pr-4">{{ c.reference }}</td>
|
|
<td class="py-2 pr-4">
|
|
<Link
|
|
v-if="c.client_case?.uuid"
|
|
:href="route('clientCase.show', { client_case: c.client_case.uuid })"
|
|
class="text-indigo-600 hover:underline"
|
|
>
|
|
{{ c.client_case?.person?.full_name || 'Primer stranke' }}
|
|
</Link>
|
|
<span v-else>{{ c.client_case?.person?.full_name || '-' }}</span>
|
|
</td>
|
|
<td class="py-2 pr-4">{{ formatDate(props.assignments?.[c.uuid]?.assigned_at) }}</td>
|
|
<td class="py-2 pr-4">{{ assignedTo(c) || '-' }}</td>
|
|
<td class="py-2 pr-4">{{ formatCurrencyEUR(c.account?.balance_amount) }}</td>
|
|
<td class="py-2 pr-4">
|
|
<button class="px-3 py-1 text-sm rounded bg-red-600 text-white" @click="cancelAssignment(c)">Prekliči</button>
|
|
</td>
|
|
</tr>
|
|
<tr v-if="assignedContractsFiltered.length === 0">
|
|
<td colspan="6" class="py-4 text-gray-500">Ni dodeljenih pogodb za izbran filter.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</AppLayout>
|
|
</template>
|