Teren-app/resources/js/Pages/Imports/Create.vue
Simon Pocrnjič dea7432deb changes
2025-12-26 22:39:58 +01:00

266 lines
8.8 KiB
Vue

<script setup>
import AppLayout from "@/Layouts/AppLayout.vue";
import { useForm, router } from "@inertiajs/vue3";
import { ref, computed } from "vue";
import axios from "axios";
import { Button } from "@/Components/ui/button";
import { Label } from "@/Components/ui/label";
import { Checkbox } from "@/Components/ui/checkbox";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/Components/ui/select";
const props = defineProps({
templates: Array,
clients: Array,
});
const form = useForm({
client_uuid: null,
import_template_id: null,
has_header: true,
file: null,
});
// Filter templates: show globals when no client; when client selected show only that client's templates
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);
});
const uploading = ref(false);
const dragActive = ref(false);
const uploadError = ref(null);
function onFileChange(e) {
const files = e.target.files;
if (files?.length) {
form.file = files[0];
uploadError.value = null;
}
}
function onFileDrop(e) {
const files = e.dataTransfer?.files;
if (files?.length) {
form.file = files[0];
uploadError.value = null;
}
dragActive.value = false;
}
function clearFile() {
form.file = null;
uploadError.value = null;
}
async function startImport() {
uploadError.value = null;
if (!form.file) {
uploadError.value = "Najprej izberite datoteko.";
return;
}
uploading.value = true;
try {
const fd = new FormData();
fd.append("file", form.file);
if (form.import_template_id) {
fd.append("import_template_id", String(form.import_template_id));
}
if (form.client_uuid) {
fd.append("client_uuid", form.client_uuid);
}
fd.append("has_header", form.has_header ? "1" : "0");
const { data } = await axios.post(route("imports.store"), fd, {
headers: { Accept: "application/json" },
withCredentials: true,
});
if (data?.uuid) {
router.visit(route("imports.continue", { import: data.uuid }));
} else if (data?.id) {
router.visit(route("imports.continue", { import: data.id }));
} else {
uploadError.value = "Nepričakovan odgovor strežnika.";
}
} catch (e) {
uploadError.value = e.response?.data?.message || "Nalaganje ni uspelo.";
console.error("Import upload failed", e.response?.status, e.response?.data || e);
} finally {
uploading.value = false;
}
}
</script>
<template>
<AppLayout title="Nov uvoz">
<template #header>
<h2 class="text-xl font-semibold leading-tight text-gray-800">Nov uvoz</h2>
</template>
<div class="py-6">
<div class="mx-auto max-w-4xl sm:px-6 lg:px-8">
<div class="space-y-8 rounded-lg bg-white p-6 shadow sm:rounded-lg">
<!-- Intro -->
<div class="text-sm leading-relaxed text-gray-600">
<p class="mb-2">
1) Izberite stranko (opcijsko) in predlogo (če obstaja), 2) izberite
datoteko (CSV, TXT, XLSX*) in 3) kliknite Začni uvoz. Nadaljnje preslikave
in simulacija bodo na naslednji strani.
</p>
<p class="text-xs text-gray-500">
* XLSX podpora je odvisna od konfiguracije strežnika.
</p>
</div>
<!-- Client & Template selection -->
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
<!-- Client Select -->
<div class="space-y-2">
<Label>Stranka</Label>
<Select v-model="form.client_uuid">
<SelectTrigger>
<SelectValue placeholder="Izberite stranko..." />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="client in clients"
:key="client.uuid"
:value="client.uuid"
>
{{ client.name }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<p class="text-xs text-gray-500">
Če stranka ni izbrana, bo uvoz globalen.
</p>
</div>
<!-- Template Select -->
<div class="space-y-2">
<Label>Predloga</Label>
<Select v-model="form.import_template_id">
<SelectTrigger>
<SelectValue placeholder="Izberite predlogo..." />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="template in filteredTemplates"
:key="template.id"
:value="template.id"
>
<div class="flex w-full items-center justify-between">
<span class="truncate">{{ template.name }}</span>
<span
class="ml-2 rounded bg-gray-100 px-1.5 py-0.5 text-[10px] text-gray-600"
>
{{ template.client_id ? "Client" : "Global" }}
</span>
</div>
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<p v-if="!form.client_uuid" class="mt-1 text-xs text-gray-500">
Prikazane so samo globalne predloge dokler ne izberete stranke.
</p>
</div>
</div>
<!-- File Upload -->
<div class="space-y-4">
<Label>Datoteka</Label>
<div
class="cursor-pointer rounded-md border-2 border-dashed p-6 text-center transition-colors"
:class="{
'border-indigo-400 bg-indigo-50': dragActive,
'border-gray-300 hover:border-gray-400': !dragActive,
}"
@dragover.prevent="dragActive = true"
@dragleave.prevent="dragActive = false"
@drop.prevent="onFileDrop"
>
<input
id="import-file-input"
type="file"
class="hidden"
@change="onFileChange"
/>
<label for="import-file-input" class="block cursor-pointer select-none">
<div v-if="!form.file" class="text-sm text-gray-600">
Povlecite datoteko sem ali
<span class="text-indigo-600 underline">kliknite za izbiro</span>
</div>
<div v-else class="flex flex-col gap-1 text-sm text-gray-800">
<span class="font-medium">{{ form.file.name }}</span>
<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]">
Zamenjaj
</span>
</div>
</label>
</div>
<!-- Has Header Checkbox -->
<div class="flex items-center space-x-2">
<Checkbox id="has-header" v-model:checked="form.has_header" />
<Label
for="has-header"
class="cursor-pointer text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Prva vrstica je glava
</Label>
</div>
<p class="text-xs leading-relaxed text-gray-500">
Če ni označeno, bodo stolpci poimenovani po zaporedju (A, B, C ...).
</p>
</div>
<!-- Error Message -->
<div v-if="uploadError" class="rounded-md bg-red-50 p-3 text-sm text-red-600">
{{ uploadError }}
</div>
<!-- Actions -->
<div class="flex flex-wrap justify-end gap-3 border-t pt-4">
<Button
variant="outline"
:disabled="uploading || !form.file"
@click="clearFile"
>
Počisti
</Button>
<Button :disabled="uploading" @click="startImport">
<span
v-if="uploading"
class="mr-2 h-4 w-4 animate-spin rounded-full border-2 border-white/60 border-t-transparent"
/>
{{ uploading ? "Nalagam..." : "Začni uvoz" }}
</Button>
</div>
<div class="border-t pt-4 text-xs text-gray-400">
Po nalaganju boste preusmerjeni na nadaljevanje uvoza, kjer lahko izvedete
preslikave, simulacijo in končno obdelavo.
</div>
</div>
</div>
</div>
</AppLayout>
</template>