production #1
|
|
@ -26,10 +26,13 @@ public function index(Request $request)
|
|||
])->filter()->unique()->values();
|
||||
|
||||
$search = $request->input('search');
|
||||
$searchAssigned = $request->input('search_assigned');
|
||||
$assignedUserId = $request->input('assigned_user_id');
|
||||
$unassignedClientUuids = $request->input('unassigned_client_uuids');
|
||||
$assignedClientUuids = $request->input('assigned_client_uuids');
|
||||
|
||||
$unassignedContracts = Contract::query()
|
||||
->with(['clientCase.person.addresses', 'clientCase.client.person', 'type', 'account'])
|
||||
->with(['clientCase.person.addresses', 'clientCase.client.person:id,uuid,full_name', 'type', 'account'])
|
||||
->when($segmentIds->isNotEmpty(), fn($q) =>
|
||||
$q->whereHas('segments', fn($rq) => $rq->whereIn('segments.id', $segmentIds)),
|
||||
fn($q) => $q->whereRaw('1 = 0')
|
||||
|
|
@ -45,50 +48,83 @@ public function index(Request $request)
|
|||
)
|
||||
)
|
||||
)
|
||||
->when(!empty($unassignedClientUuids) && is_array($unassignedClientUuids), fn ($q) =>
|
||||
$q->whereHas('clientCase.client', fn($cq) =>
|
||||
$cq->whereIn('uuid', $unassignedClientUuids)
|
||||
)
|
||||
)
|
||||
->whereDoesntHave('fieldJobs', fn ($q) =>
|
||||
$q->whereNull('completed_at')
|
||||
->whereNull('cancelled_at')
|
||||
)
|
||||
->latest('id')
|
||||
->paginate(
|
||||
$request->input('per_page_contracts', 10),
|
||||
['*'],
|
||||
'page_contracts',
|
||||
$request->input('page_contracts', 1)
|
||||
);
|
||||
->latest('id');
|
||||
|
||||
$unassignedClients = $unassignedContracts->get()
|
||||
->pluck('clientCase.client')
|
||||
->filter()
|
||||
->unique('id');
|
||||
|
||||
|
||||
$assignedContracts = Contract::query()
|
||||
->with(['clientCase.person.addresses', 'clientCase.client.person', 'type', 'account', 'lastFieldJobs', 'lastFieldJobs.assignedUser', 'lastFieldJobs.user'])
|
||||
->with(['clientCase.person.addresses', 'clientCase.client.person:id,uuid,full_name', 'type', 'account', 'lastFieldJobs', 'lastFieldJobs.assignedUser', 'lastFieldJobs.user'])
|
||||
->when($segmentIds->isNotEmpty(), fn($q) =>
|
||||
$q->whereHas('segments', fn($rq) => $rq->whereIn('segments.id', $segmentIds)),
|
||||
fn($q) => $q->whereRaw('1 = 0')
|
||||
)
|
||||
->when( !empty($searchAssigned), fn ($q) =>
|
||||
$q->where(fn($sq) =>
|
||||
$sq->where('reference', 'like', "%{$searchAssigned}%")
|
||||
->orWhereHas('clientCase.person', fn($psq) =>
|
||||
$psq->where('full_name', 'ilike', "%{$searchAssigned}%")
|
||||
)
|
||||
->orWhereHas('clientCase.person.addresses', fn ($ccpaq) =>
|
||||
$ccpaq->where('address', 'ilike', "%{$searchAssigned}")
|
||||
)
|
||||
)
|
||||
)
|
||||
->when(!empty($assignedClientUuids) && is_array($assignedClientUuids), fn ($q) =>
|
||||
$q->whereHas('clientCase.client', fn($cq) =>
|
||||
$cq->whereIn('uuid', $assignedClientUuids)
|
||||
)
|
||||
)
|
||||
->whereHas('lastFieldJobs', fn ($q) =>
|
||||
$q->whereNull('completed_at')
|
||||
->whereNull('cancelled_at')
|
||||
->when($assignedUserId && $assignedUserId !== 'all', fn ($jq) =>
|
||||
$jq->where('assigned_user_id', $assignedUserId))
|
||||
)
|
||||
->latest('id')
|
||||
->paginate(
|
||||
$request->input('per_page_assignments', 10),
|
||||
['*'],
|
||||
'page_assignments',
|
||||
$request->input('page_assignments', 1)
|
||||
);
|
||||
->latest('id');
|
||||
|
||||
$assignedClients = $assignedContracts->get()
|
||||
->pluck('clientCase.client')
|
||||
->filter()
|
||||
->unique('id');
|
||||
|
||||
$users = User::query()->orderBy('name')->get(['id', 'name']);
|
||||
|
||||
return Inertia::render('FieldJob/Index', [
|
||||
'setting' => $setting,
|
||||
'unassignedContracts' => $unassignedContracts,
|
||||
'assignedContracts' => $assignedContracts,
|
||||
'unassignedContracts' => $unassignedContracts->paginate(
|
||||
$request->input('per_page_contracts', 10),
|
||||
['*'],
|
||||
'page_contracts',
|
||||
$request->input('page_contracts', 1)
|
||||
),
|
||||
'assignedContracts' => $assignedContracts->paginate(
|
||||
$request->input('per_page_assignments', 10),
|
||||
['*'],
|
||||
'page_assignments',
|
||||
$request->input('page_assignments', 1)
|
||||
),
|
||||
'unassignedClients' => $unassignedClients,
|
||||
'assignedClients' => $assignedClients,
|
||||
'users' => $users,
|
||||
'filters' => [
|
||||
'search' => $search,
|
||||
'search_assigned' => $searchAssigned,
|
||||
'assigned_user_id' => $assignedUserId,
|
||||
'unassigned_client_uuids' => $unassignedClientUuids,
|
||||
'assigned_client_uuids' => $assignedClientUuids,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import AppLayout from "@/Layouts/AppLayout.vue";
|
|||
import { Link, useForm, router } from "@inertiajs/vue3";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import DataTable from "@/Components/DataTable/DataTableNew2.vue";
|
||||
import { Card } from "@/Components/ui/card";
|
||||
import { Card, CardTitle } from "@/Components/ui/card";
|
||||
import { Input } from "@/Components/ui/input";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import { Label } from "@/Components/ui/label";
|
||||
|
|
@ -15,19 +15,45 @@ import {
|
|||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/Components/ui/select";
|
||||
import { AlertCircle } from "lucide-vue-next";
|
||||
import { AlertCircle, FileCheckCornerIcon, FilesIcon, Filter } from "lucide-vue-next";
|
||||
import Checkbox from "@/Components/ui/checkbox/Checkbox.vue";
|
||||
import Pagination from "@/Components/Pagination.vue";
|
||||
import { watchDebounced } from "@vueuse/core";
|
||||
import Dropdown from "@/Components/Dropdown.vue";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/Components/ui/dropdown-menu";
|
||||
import AppPopover from "@/Components/app/ui/AppPopover.vue";
|
||||
import InputLabel from "@/Components/InputLabel.vue";
|
||||
import AppMultiSelect from "@/Components/app/ui/AppMultiSelect.vue";
|
||||
import AppCard from "@/Components/app/ui/card/AppCard.vue";
|
||||
|
||||
const props = defineProps({
|
||||
setting: Object,
|
||||
unassignedContracts: Object,
|
||||
assignedContracts: Object,
|
||||
users: Array,
|
||||
unassignedClients: Array,
|
||||
assignedClients: Array,
|
||||
filters: Object,
|
||||
});
|
||||
|
||||
const filterUnassignedContracts = ref(false);
|
||||
const filterAssignedContracts = ref(false);
|
||||
const filterUnassignedSelectedClient = ref(
|
||||
Array.isArray(props.filters?.unassigned_client_uuids)
|
||||
? props.filters.unassigned_client_uuids
|
||||
: []
|
||||
);
|
||||
const filterAssignedSelectedClient = ref(
|
||||
Array.isArray(props.filters?.assigned_client_uuids)
|
||||
? props.filters.assigned_client_uuids
|
||||
: []
|
||||
);
|
||||
|
||||
const form = useForm({
|
||||
contract_uuid: null,
|
||||
assigned_user_id: null,
|
||||
|
|
@ -85,6 +111,7 @@ function toggleContractSelection(uuid, checked) {
|
|||
|
||||
// Initialize search and filter from URL params
|
||||
const search = ref(props.filters?.search || "");
|
||||
const searchAssigned = ref(props.filters?.search_assigned || "");
|
||||
const assignedFilterUserId = ref(props.filters?.assigned_user_id || "all");
|
||||
|
||||
// Navigation helpers
|
||||
|
|
@ -128,6 +155,37 @@ watchDebounced(
|
|||
}
|
||||
);
|
||||
|
||||
const applySearchAssigned = async function () {
|
||||
const params = Object.fromEntries(
|
||||
new URLSearchParams(window.location.search).entries()
|
||||
);
|
||||
|
||||
const term = (searchAssigned.value || "").trim();
|
||||
if (term) {
|
||||
params.search_assigned = term;
|
||||
} else {
|
||||
delete params.search_assigned;
|
||||
}
|
||||
delete params.page_assignments;
|
||||
router.get(route("fieldjobs.index"), params, {
|
||||
preserveState: true,
|
||||
replace: true,
|
||||
preserveScroll: true,
|
||||
only: ["assignedContracts", "filters"],
|
||||
});
|
||||
};
|
||||
|
||||
watchDebounced(
|
||||
() => searchAssigned.value,
|
||||
(val) => {
|
||||
applySearchAssigned();
|
||||
},
|
||||
{
|
||||
debounce: 200,
|
||||
maxWait: 1000,
|
||||
}
|
||||
);
|
||||
|
||||
// Watch search and filter changes
|
||||
/*watch(search, (value) => {
|
||||
navigateWithParams({
|
||||
|
|
@ -143,6 +201,44 @@ watch(assignedFilterUserId, (value) => {
|
|||
navigateWithParams({
|
||||
search: search.value || undefined,
|
||||
assigned_user_id: value !== "all" ? value : undefined,
|
||||
unassigned_client_uuids:
|
||||
filterUnassignedSelectedClient.value?.length > 0
|
||||
? filterUnassignedSelectedClient.value
|
||||
: undefined,
|
||||
assigned_client_uuids:
|
||||
filterAssignedSelectedClient.value?.length > 0
|
||||
? filterAssignedSelectedClient.value
|
||||
: undefined,
|
||||
page_contracts: props.unassignedContracts?.current_page,
|
||||
page_assignments: 1, // Reset to first page on filter change
|
||||
});
|
||||
});
|
||||
|
||||
watch(filterUnassignedSelectedClient, (value) => {
|
||||
navigateWithParams({
|
||||
search: search.value || undefined,
|
||||
assigned_user_id:
|
||||
assignedFilterUserId.value !== "all" ? assignedFilterUserId.value : undefined,
|
||||
unassigned_client_uuids: value?.length > 0 ? value : undefined,
|
||||
assigned_client_uuids:
|
||||
filterAssignedSelectedClient.value?.length > 0
|
||||
? filterAssignedSelectedClient.value
|
||||
: undefined,
|
||||
page_contracts: 1, // Reset to first page on filter change
|
||||
page_assignments: props.assignedContracts?.current_page,
|
||||
});
|
||||
});
|
||||
|
||||
watch(filterAssignedSelectedClient, (value) => {
|
||||
navigateWithParams({
|
||||
search: search.value || undefined,
|
||||
assigned_user_id:
|
||||
assignedFilterUserId.value !== "all" ? assignedFilterUserId.value : undefined,
|
||||
unassigned_client_uuids:
|
||||
filterUnassignedSelectedClient.value?.length > 0
|
||||
? filterUnassignedSelectedClient.value
|
||||
: undefined,
|
||||
assigned_client_uuids: value?.length > 0 ? value : undefined,
|
||||
page_contracts: props.unassignedContracts?.current_page,
|
||||
page_assignments: 1, // Reset to first page on filter change
|
||||
});
|
||||
|
|
@ -248,7 +344,7 @@ const unassignedRows = computed(() =>
|
|||
? null
|
||||
: Number(c.account.balance_amount),
|
||||
case_person: c.client_case?.person?.full_name || null,
|
||||
client_person: c.client?.person?.full_name || null,
|
||||
client_person: c.client_case?.client?.person?.full_name || null,
|
||||
address: primaryCaseAddress(c) || null,
|
||||
}))
|
||||
);
|
||||
|
|
@ -261,7 +357,7 @@ const assignedRows = computed(() =>
|
|||
? null
|
||||
: Number(c.account.balance_amount),
|
||||
case_person: c.client_case?.person?.full_name || null,
|
||||
client_person: c.client?.person?.full_name || null,
|
||||
client_person: c.client_case?.client?.person?.full_name || null,
|
||||
address: primaryCaseAddress(c) || null,
|
||||
assigned_to: c.last_field_jobs.assigned_user.name || null,
|
||||
assigned_at_formatted: formatDate(c.last_field_jobs.assigned_at),
|
||||
|
|
@ -272,130 +368,181 @@ const assignedRows = computed(() =>
|
|||
<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="mb-6 flex items-start gap-3 rounded-lg border border-yellow-200 bg-yellow-50 p-4"
|
||||
<div class="pt-6">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6">
|
||||
<AppCard
|
||||
title=""
|
||||
padding="none"
|
||||
class="p-0! gap-0"
|
||||
header-class="p-3! px-4 gap-0 text-muted-foreground"
|
||||
body-class=""
|
||||
>
|
||||
<AlertCircle class="h-5 w-5 text-yellow-600 shrink-0 mt-0.5" />
|
||||
<p class="text-sm text-yellow-800">
|
||||
Nastavitev za terenska opravila ni najdena. Najprej jo ustvarite v Nastavitve
|
||||
→ Nastavitve terenskih opravil.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Unassigned (Assignable) Contracts -->
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg mb-8">
|
||||
<div class="p-4 border-b">
|
||||
<h2 class="text-xl font-semibold">Pogodbe (nedodeljene)</h2>
|
||||
</div>
|
||||
<div class="p-4 border-b space-y-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="assign-user">Dodeli uporabniku</Label>
|
||||
<Select v-model="form.assigned_user_id">
|
||||
<SelectTrigger id="assign-user" class="max-w-xs">
|
||||
<SelectValue placeholder="Izberite uporabnika" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem v-for="u in users || []" :key="u.id" :value="u.id">
|
||||
{{ u.name }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div v-if="form.errors.assigned_user_id" class="text-red-600 text-sm">
|
||||
{{ form.errors.assigned_user_id }}
|
||||
</div>
|
||||
</div>
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button
|
||||
:disabled="!selectedContractUuids.length || !form.assigned_user_id"
|
||||
@click="assignSelected"
|
||||
>
|
||||
Dodeli izbrane
|
||||
<Badge
|
||||
v-if="selectedContractUuids.length"
|
||||
variant="secondary"
|
||||
class="ml-2"
|
||||
>
|
||||
{{ selectedContractUuids.length }}
|
||||
</Badge>
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
:disabled="!selectedContractUuids.length"
|
||||
@click="selectedContractUuids = []"
|
||||
>
|
||||
Počisti izbor
|
||||
</Button>
|
||||
<FilesIcon size="18" />
|
||||
<CardTitle class="uppercase">Pogodbe (nedodeljene)</CardTitle>
|
||||
</div>
|
||||
</div>
|
||||
<DataTable
|
||||
:columns="unassignedColumns"
|
||||
:data="unassignedRows"
|
||||
:meta="{
|
||||
current_page: unassignedContracts.current_page,
|
||||
per_page: unassignedContracts.per_page,
|
||||
total: unassignedContracts.total,
|
||||
last_page: unassignedContracts.last_page,
|
||||
from: unassignedContracts.from,
|
||||
to: unassignedContracts.to,
|
||||
links: unassignedContracts.links,
|
||||
}"
|
||||
row-key="uuid"
|
||||
:page-size="props.unassignedContracts?.per_page || 10"
|
||||
:page-size-options="[10, 15, 25, 50, 100]"
|
||||
:show-toolbar="true"
|
||||
route-name="fieldjobs.index"
|
||||
page-param-name="page_contracts"
|
||||
per-page-param-name="per_page_contracts"
|
||||
</template>
|
||||
<div
|
||||
v-if="!setting"
|
||||
class="mb-6 flex items-start gap-3 rounded-lg border border-yellow-200 bg-yellow-50 p-4"
|
||||
>
|
||||
<template #toolbar-filters>
|
||||
<div class="flex items-center gap-2 w-full">
|
||||
<Input
|
||||
v-model="search"
|
||||
placeholder="Išči po pogodbi, primeru, stranki, naslovu..."
|
||||
class="w-[320px]"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #cell-_select="{ row }">
|
||||
<Checkbox
|
||||
@update:model-value="
|
||||
(checked) => toggleContractSelection(row.uuid, checked)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<template #cell-case_person="{ row }">
|
||||
<Link
|
||||
v-if="row.client_case?.uuid"
|
||||
:href="route('clientCase.show', { client_case: row.client_case.uuid })"
|
||||
class="font-semibold hover:underline text-primary-700"
|
||||
>
|
||||
{{ row.client_case?.person?.full_name || "Primer stranke" }}
|
||||
</Link>
|
||||
<span v-else>{{ row.client_case?.person?.full_name || "-" }}</span>
|
||||
</template>
|
||||
<template #cell-start_date="{ row }">
|
||||
{{ formatDate(row.start_date) }}
|
||||
</template>
|
||||
<template #cell-balance_amount="{ row }">
|
||||
<div class="text-right">
|
||||
{{ formatCurrencyEUR(row.account?.balance_amount) }}
|
||||
</div>
|
||||
</template>
|
||||
<template #cell-_actions="{ row }">
|
||||
<Button size="sm" @click="assign(row)">Dodeli</Button>
|
||||
</template>
|
||||
</DataTable>
|
||||
</div>
|
||||
|
||||
<!-- Assigned Contracts -->
|
||||
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
|
||||
<div class="p-4 border-b">
|
||||
<h2 class="text-xl font-semibold">Dodeljene pogodbe</h2>
|
||||
<AlertCircle class="h-5 w-5 text-yellow-600 shrink-0 mt-0.5" />
|
||||
<p class="text-sm text-yellow-800">
|
||||
Nastavitev za terenska opravila ni najdena. Najprej jo ustvarite v
|
||||
Nastavitve → Nastavitve terenskih opravil.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Unassigned (Assignable) Contracts -->
|
||||
<div class="overflow-hidden mb-8 border-t">
|
||||
<div class="p-4 flex flex-row gap-2 items-end">
|
||||
<div class="space-y-2">
|
||||
<Label for="assign-user">Dodeli uporabniku</Label>
|
||||
<Select v-model="form.assigned_user_id">
|
||||
<SelectTrigger id="assign-user" class="max-w-xs min-w-60">
|
||||
<SelectValue placeholder="Izberite uporabnika" />
|
||||
</SelectTrigger>
|
||||
<SelectContent class="min-w-60">
|
||||
<SelectItem v-for="u in users || []" :key="u.id" :value="u.id">
|
||||
{{ u.name }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div v-if="form.errors.assigned_user_id" class="text-red-600 text-sm">
|
||||
{{ form.errors.assigned_user_id }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button
|
||||
:disabled="!selectedContractUuids.length || !form.assigned_user_id"
|
||||
@click="assignSelected"
|
||||
>
|
||||
Dodeli izbrane
|
||||
<Badge
|
||||
v-if="selectedContractUuids.length"
|
||||
variant="secondary"
|
||||
class="ml-2"
|
||||
>
|
||||
{{ selectedContractUuids.length }}
|
||||
</Badge>
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
:disabled="!selectedContractUuids.length"
|
||||
@click="selectedContractUuids = []"
|
||||
>
|
||||
Počisti izbor
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<DataTable
|
||||
:columns="unassignedColumns"
|
||||
:data="unassignedRows"
|
||||
:meta="{
|
||||
current_page: unassignedContracts.current_page,
|
||||
per_page: unassignedContracts.per_page,
|
||||
total: unassignedContracts.total,
|
||||
last_page: unassignedContracts.last_page,
|
||||
from: unassignedContracts.from,
|
||||
to: unassignedContracts.to,
|
||||
links: unassignedContracts.links,
|
||||
}"
|
||||
row-key="uuid"
|
||||
:page-size="props.unassignedContracts?.per_page || 10"
|
||||
:page-size-options="[10, 15, 25, 50, 100]"
|
||||
:show-toolbar="true"
|
||||
route-name="fieldjobs.index"
|
||||
page-param-name="page_contracts"
|
||||
per-page-param-name="per_page_contracts"
|
||||
>
|
||||
<template #toolbar-filters>
|
||||
<div class="flex items-center gap-2 w-full">
|
||||
<AppPopover
|
||||
v-model:open="filterUnassignedContracts"
|
||||
align="start"
|
||||
content-class="w-[350px]"
|
||||
>
|
||||
<template #trigger>
|
||||
<Button variant="outline"
|
||||
><Filter class="h-4 w-4" /> Filtri
|
||||
</Button>
|
||||
</template>
|
||||
<div class="space-y-3">
|
||||
<div class="space-y-1.5">
|
||||
<InputLabel>Iskanje</InputLabel>
|
||||
<Input
|
||||
v-model="search"
|
||||
placeholder="Išči po pogodbi, primeru, stranki, naslovu..."
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-1.5">
|
||||
<InputLabel>Stranke</InputLabel>
|
||||
<AppMultiSelect
|
||||
v-model="filterUnassignedSelectedClient"
|
||||
:items="
|
||||
(props.unassignedClients || []).map((client) => ({
|
||||
value: client.uuid,
|
||||
label: client.person.full_name,
|
||||
}))
|
||||
"
|
||||
placeholder="Vse stranke"
|
||||
search-placeholder="Išči stranko..."
|
||||
empty-text="Ni strank"
|
||||
chip-variant="secondary"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</AppPopover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #cell-_select="{ row }">
|
||||
<Checkbox
|
||||
@update:model-value="
|
||||
(checked) => toggleContractSelection(row.uuid, checked)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<template #cell-case_person="{ row }">
|
||||
<Link
|
||||
v-if="row.client_case?.uuid"
|
||||
:href="route('clientCase.show', { client_case: row.client_case.uuid })"
|
||||
class="font-semibold hover:underline text-primary-700"
|
||||
>
|
||||
{{ row.client_case?.person?.full_name || "Primer stranke" }}
|
||||
</Link>
|
||||
<span v-else>{{ row.client_case?.person?.full_name || "-" }}</span>
|
||||
</template>
|
||||
<template #cell-start_date="{ row }">
|
||||
{{ formatDate(row.start_date) }}
|
||||
</template>
|
||||
<template #cell-balance_amount="{ row }">
|
||||
<div class="text-right">
|
||||
{{ formatCurrencyEUR(row.account?.balance_amount) }}
|
||||
</div>
|
||||
</template>
|
||||
<template #cell-_actions="{ row }">
|
||||
<Button size="sm" @click="assign(row)">Dodeli</Button>
|
||||
</template>
|
||||
</DataTable>
|
||||
</div>
|
||||
</AppCard>
|
||||
<!-- Assigned Contracts -->
|
||||
<AppCard
|
||||
title=""
|
||||
padding="none"
|
||||
class="p-0! gap-0"
|
||||
header-class="p-3! px-4 gap-0 text-muted-foreground"
|
||||
body-class=""
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center gap-2">
|
||||
<FileCheckCornerIcon size="18" />
|
||||
<CardTitle class="uppercase">Dodeljene pogodbe</CardTitle>
|
||||
</div>
|
||||
</template>
|
||||
<DataTable
|
||||
:columns="assignedColumns"
|
||||
:data="assignedRows"
|
||||
|
|
@ -418,31 +565,59 @@ const assignedRows = computed(() =>
|
|||
>
|
||||
<template #toolbar-filters>
|
||||
<div class="flex items-center gap-2 w-full">
|
||||
<Input
|
||||
v-model="search_contract"
|
||||
placeholder="Išči po pogodbi, primeru, stranki..."
|
||||
class="w-[320px]"
|
||||
/>
|
||||
<div class="flex items-center gap-2 ml-4">
|
||||
<Label for="filter-user" class="text-sm whitespace-nowrap"
|
||||
>Filter po uporabniku</Label
|
||||
>
|
||||
<Select v-model="assignedFilterUserId">
|
||||
<SelectTrigger id="filter-user" class="w-48">
|
||||
<SelectValue placeholder="Vsi" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Vsi</SelectItem>
|
||||
<SelectItem
|
||||
v-for="u in users || []"
|
||||
:key="u.id"
|
||||
:value="String(u.id)"
|
||||
>
|
||||
{{ u.name }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<AppPopover
|
||||
v-model:open="filterAssignedContracts"
|
||||
align="start"
|
||||
content-class="w-[350px]"
|
||||
>
|
||||
<template #trigger>
|
||||
<Button variant="outline"><Filter class="h-4 w-4" /> Filtri </Button>
|
||||
</template>
|
||||
<div class="space-y-3">
|
||||
<div class="space-y-1.5">
|
||||
<InputLabel>Iskanje</InputLabel>
|
||||
<Input
|
||||
v-model="searchAssigned"
|
||||
placeholder="Išči po pogodbi, primeru, stranki, naslovu..."
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-1.5">
|
||||
<InputLabel>Filter po uporabniku</InputLabel>
|
||||
<Select v-model="assignedFilterUserId">
|
||||
<SelectTrigger id="filter-user">
|
||||
<SelectValue placeholder="Vsi" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Vsi</SelectItem>
|
||||
<SelectItem
|
||||
v-for="u in users || []"
|
||||
:key="u.id"
|
||||
:value="String(u.id)"
|
||||
>
|
||||
{{ u.name }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="space-y-1.5">
|
||||
<InputLabel>Stranke</InputLabel>
|
||||
<AppMultiSelect
|
||||
v-model="filterAssignedSelectedClient"
|
||||
:items="
|
||||
(props.assignedClients || []).map((client) => ({
|
||||
value: client.uuid,
|
||||
label: client.person.full_name,
|
||||
}))
|
||||
"
|
||||
placeholder="Vse stranke"
|
||||
search-placeholder="Išči stranko..."
|
||||
empty-text="Ni strank"
|
||||
chip-variant="secondary"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</AppPopover>
|
||||
</div>
|
||||
</template>
|
||||
<template #cell-case_person="{ row }">
|
||||
|
|
@ -469,7 +644,7 @@ const assignedRows = computed(() =>
|
|||
</Button>
|
||||
</template>
|
||||
</DataTable>
|
||||
</div>
|
||||
</AppCard>
|
||||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@ const filteredTemplates = computed(() => {
|
|||
if (!form.client_uuid) {
|
||||
return props.templates.filter((t) => !t.client_id);
|
||||
}
|
||||
return props.templates.filter((t) => t.client_uuid === form.client_uuid || !t.client_id);
|
||||
return props.templates.filter(
|
||||
(t) => t.client_uuid === form.client_uuid || !t.client_id
|
||||
);
|
||||
});
|
||||
|
||||
const uploading = ref(false);
|
||||
|
|
@ -153,7 +155,30 @@ async function startImport() {
|
|||
<Label>Predloga</Label>
|
||||
<Select v-model="form.import_template_id">
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Izberite predlogo..." />
|
||||
<SelectValue placeholder="Izberite predlogo...">
|
||||
<template v-if="form.import_template_id">
|
||||
<div class="flex w-full items-center justify-between">
|
||||
<span class="truncate">
|
||||
{{
|
||||
filteredTemplates.find(
|
||||
(t) => t.id === form.import_template_id
|
||||
)?.name
|
||||
}}
|
||||
</span>
|
||||
<span
|
||||
class="ml-2 rounded bg-gray-100 px-1.5 py-0.5 text-[10px] text-gray-600 dark:bg-gray-700 dark:text-gray-300"
|
||||
>
|
||||
{{
|
||||
filteredTemplates.find(
|
||||
(t) => t.id === form.import_template_id
|
||||
)?.client_id
|
||||
? "Client"
|
||||
: "Global"
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
|
|
@ -209,7 +234,9 @@ async function startImport() {
|
|||
<span class="text-xs text-gray-500">
|
||||
{{ (form.file.size / 1024).toFixed(1) }} kB
|
||||
</span>
|
||||
<span class="inline-block rounded bg-gray-100 px-1.5 py-0.5 text-[10px]">
|
||||
<span
|
||||
class="inline-block rounded bg-gray-100 px-1.5 py-0.5 text-[10px]"
|
||||
>
|
||||
Zamenjaj
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user