Changes to import / template pages frontend updated design
This commit is contained in:
@@ -1,9 +1,29 @@
|
||||
<script setup>
|
||||
import AppLayout from "@/Layouts/AppLayout.vue";
|
||||
import { ref } from "vue";
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { useForm } from "@inertiajs/vue3";
|
||||
import Multiselect from "vue-multiselect";
|
||||
import { computed, watch } from "vue";
|
||||
import AppMultiSelect from "@/Components/app/ui/AppMultiSelect.vue";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/Components/ui/card";
|
||||
import { Label } from "@/Components/ui/label";
|
||||
import { Input } from "@/Components/ui/input";
|
||||
import { Textarea } from "@/Components/ui/textarea";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import { Checkbox } from "@/Components/ui/checkbox";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/Components/ui/select";
|
||||
import { Badge } from "@/Components/ui/badge";
|
||||
import { Separator } from "@/Components/ui/separator";
|
||||
|
||||
const props = defineProps({
|
||||
clients: Array,
|
||||
@@ -28,8 +48,8 @@ const form = useForm({
|
||||
delimiter: "",
|
||||
// Payments import mode
|
||||
payments_import: false,
|
||||
// History import mode
|
||||
history_import: false,
|
||||
// History import mode
|
||||
history_import: false,
|
||||
// For payments mode: how to locate Contract - use single key 'reference'
|
||||
contract_key_mode: null,
|
||||
},
|
||||
@@ -88,7 +108,14 @@ watch(
|
||||
form.meta.payments_import = false;
|
||||
form.meta.contract_key_mode = null;
|
||||
}
|
||||
const allowed = ["person", "person_addresses", "person_phones", "contracts", "activities", "client_cases"];
|
||||
const allowed = [
|
||||
"person",
|
||||
"person_addresses",
|
||||
"person_phones",
|
||||
"contracts",
|
||||
"activities",
|
||||
"client_cases",
|
||||
];
|
||||
if (enabled) {
|
||||
const current = Array.isArray(form.entities) ? [...form.entities] : [];
|
||||
let filtered = current.filter((e) => allowed.includes(e));
|
||||
@@ -103,7 +130,12 @@ watch(
|
||||
watch(
|
||||
() => form.entities,
|
||||
(vals) => {
|
||||
if (form.meta.history_import && Array.isArray(vals) && vals.includes("contracts") && ! vals.includes("accounts")) {
|
||||
if (
|
||||
form.meta.history_import &&
|
||||
Array.isArray(vals) &&
|
||||
vals.includes("contracts") &&
|
||||
!vals.includes("accounts")
|
||||
) {
|
||||
form.entities = [...vals, "accounts"];
|
||||
}
|
||||
}
|
||||
@@ -111,254 +143,278 @@ watch(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppLayout title="Create Import Template">
|
||||
<template #header>
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
Create Import Template
|
||||
</h2>
|
||||
</template>
|
||||
<AppLayout title="Ustvari predlogo uvoza">
|
||||
<template #header> </template>
|
||||
|
||||
<div class="py-6">
|
||||
<div class="max-w-3xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white shadow sm:rounded-lg p-6 space-y-6">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700"
|
||||
>Client (optional)</label
|
||||
>
|
||||
<Multiselect
|
||||
v-model="form.client_uuid"
|
||||
:options="props.clients || []"
|
||||
:reduce="(c) => c.uuid"
|
||||
track-by="uuid"
|
||||
label="name"
|
||||
placeholder="Global (no client)"
|
||||
:searchable="true"
|
||||
:allow-empty="true"
|
||||
class="mt-1"
|
||||
/>
|
||||
<p class="text-xs text-gray-500 mt-1">
|
||||
Leave empty to make this template global (visible to all clients).
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center justify-between">
|
||||
<label class="block text-sm font-medium text-gray-700"
|
||||
>Entities (tables)</label
|
||||
>
|
||||
<div class="flex items-center gap-4 text-sm">
|
||||
<label class="inline-flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="form.meta.history_import"
|
||||
class="rounded"
|
||||
/>
|
||||
<span>History import</span>
|
||||
</label>
|
||||
<label class="inline-flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="form.meta.payments_import"
|
||||
class="rounded"
|
||||
/>
|
||||
<span>Payments import</span>
|
||||
</label>
|
||||
</div>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Konfiguracija predloge</CardTitle>
|
||||
<CardDescription
|
||||
>Določite nastavitve predloge uvoza in ciljne entitete</CardDescription
|
||||
>
|
||||
</CardHeader>
|
||||
<CardContent class="space-y-6">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="client">Stranka (izbirno)</Label>
|
||||
<Select v-model="form.client_uuid">
|
||||
<SelectTrigger id="client">
|
||||
<SelectValue placeholder="Globalno (brez stranke)" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem :value="null">Globalno (brez stranke)</SelectItem>
|
||||
<SelectItem
|
||||
v-for="c in props.clients || []"
|
||||
:key="c.uuid"
|
||||
:value="c.uuid"
|
||||
>
|
||||
{{ c.name }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Pustite prazno za globalno predlogo (vidno vsem strankam).
|
||||
</p>
|
||||
</div>
|
||||
<template v-if="!form.meta.payments_import">
|
||||
<Multiselect
|
||||
v-model="form.entities"
|
||||
:options="[
|
||||
{ value: 'person', label: 'Person' },
|
||||
{ value: 'person_addresses', label: 'Person Addresses' },
|
||||
{ value: 'person_phones', label: 'Person Phones' },
|
||||
{ value: 'client_cases', label: 'Client Cases' },
|
||||
{ value: 'emails', label: 'Emails' },
|
||||
{ value: 'accounts', label: 'Accounts' },
|
||||
{ value: 'contracts', label: 'Contracts' },
|
||||
{ value: 'case_objects', label: 'Case Objects' },
|
||||
{ value: 'payments', label: 'Payments' },
|
||||
{ value: 'activities', label: 'Activities' },
|
||||
]"
|
||||
:multiple="true"
|
||||
track-by="value"
|
||||
label="label"
|
||||
:reduce="(o) => o.value"
|
||||
placeholder="Select one or more entities"
|
||||
:searchable="false"
|
||||
class="mt-1"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="mt-1">
|
||||
<div class="space-y-2">
|
||||
<Label>Entitete (tabele)</Label>
|
||||
<template v-if="!form.meta.payments_import">
|
||||
<AppMultiSelect
|
||||
v-model="form.entities"
|
||||
:items="[
|
||||
{ value: 'person', label: 'Oseba' },
|
||||
{ value: 'person_addresses', label: 'Naslov' },
|
||||
{ value: 'person_phones', label: 'Telefon' },
|
||||
{ value: 'client_cases', label: 'Primer' },
|
||||
{ value: 'emails', label: 'E-pošta' },
|
||||
{ value: 'accounts', label: 'Računi' },
|
||||
{ value: 'contracts', label: 'Pogodbe' },
|
||||
{ value: 'case_objects', label: 'Predmet' },
|
||||
{ value: 'payments', label: 'Plačilo' },
|
||||
{ value: 'activities', label: 'Aktivnost' },
|
||||
]"
|
||||
placeholder="Izberite eno ali več entitet"
|
||||
search-placeholder="Iskanje entitet..."
|
||||
content-class="p-0 w-full"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<span class="inline-flex items-center rounded-full bg-emerald-100 text-emerald-800 px-3 py-1 text-xs font-medium">Contracts</span>
|
||||
<span class="inline-flex items-center rounded-full bg-emerald-100 text-emerald-800 px-3 py-1 text-xs font-medium">Accounts</span>
|
||||
<span class="inline-flex items-center rounded-full bg-emerald-100 text-emerald-800 px-3 py-1 text-xs font-medium">Payments</span>
|
||||
<Badge variant="secondary">Pogodbe</Badge>
|
||||
<Badge variant="secondary">Računi</Badge>
|
||||
<Badge variant="secondary">Plačila</Badge>
|
||||
</div>
|
||||
</template>
|
||||
<p class="text-xs text-muted-foreground mt-1">
|
||||
Izberite katere tabele ta predloga cilja. Preslikave stolpcev lahko
|
||||
dodate kasneje.
|
||||
</p>
|
||||
|
||||
<!-- Import Mode Toggles -->
|
||||
<div class="flex items-center gap-6 pt-2">
|
||||
<label class="inline-flex items-center gap-2">
|
||||
<Checkbox
|
||||
:checked="form.meta.history_import"
|
||||
@update:checked="form.meta.history_import = $event"
|
||||
/>
|
||||
<span class="text-sm">Uvoz zgodovine</span>
|
||||
</label>
|
||||
<label class="inline-flex items-center gap-2">
|
||||
<Checkbox
|
||||
:checked="form.meta.payments_import"
|
||||
@update:checked="form.meta.payments_import = $event"
|
||||
/>
|
||||
<span class="text-sm">Uvoz plačil</span>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<p class="text-xs text-gray-500 mt-1">
|
||||
Choose which tables this template targets. You can still define per-column
|
||||
mappings later.
|
||||
</p>
|
||||
<div v-if="form.meta.history_import" class="mt-2 text-xs text-gray-600">
|
||||
History mode allows only person/address/phone/contracts/activities/client cases. Accounts are auto-added when contracts are present and balances stay unchanged.
|
||||
</div>
|
||||
<div v-if="form.meta.payments_import" class="mt-2 text-xs text-gray-600">
|
||||
Payments mode locks entities to:
|
||||
<span class="font-medium">Contracts → Accounts → Payments</span> and
|
||||
optimizes matching for payments import.
|
||||
</div>
|
||||
<div v-if="form.meta.payments_import" class="mt-3">
|
||||
<label class="block text-sm font-medium text-gray-700"
|
||||
>Contract match key</label
|
||||
|
||||
<div
|
||||
v-if="form.meta.history_import"
|
||||
class="mt-2 text-xs text-muted-foreground"
|
||||
>
|
||||
<select
|
||||
v-model="form.meta.contract_key_mode"
|
||||
class="mt-1 block w-full border rounded p-2"
|
||||
Način zgodovine dovoljuje samo
|
||||
oseba/naslovi/telefoni/pogodbe/aktivnosti/primeri strank. Računi so
|
||||
samodejno dodani, ko so prisotne pogodbe in stanja ostanejo
|
||||
nespremenjena.
|
||||
</div>
|
||||
<div
|
||||
v-if="form.meta.payments_import"
|
||||
class="mt-2 text-xs text-muted-foreground"
|
||||
>
|
||||
<option value="reference">
|
||||
Reference (use only contract.reference to locate records)
|
||||
</option>
|
||||
</select>
|
||||
<p class="text-xs text-gray-500 mt-1">
|
||||
When importing payments, Contract records are located using the selected
|
||||
key. Use your CSV mapping to map the appropriate column to the contract
|
||||
reference.
|
||||
Način plačil zaklene entitete na:
|
||||
<span class="font-medium">Pogodbe → Računi → Plačila</span> in
|
||||
optimizira ujemanje za uvoz plačil.
|
||||
</div>
|
||||
<div v-if="form.meta.payments_import" class="mt-3 space-y-2">
|
||||
<Label>Ključ ujemanja pogodb</Label>
|
||||
<Select v-model="form.meta.contract_key_mode">
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Izberite ključ pogodbe" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="reference">
|
||||
Referenca (uporabi samo contract.reference za iskanje zapisov)
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Pri uvozu plačil se zapisi pogodb najdejo z uporabo izbranega ključa.
|
||||
Uporabite CSV preslikavo za povezavo ustreznega stolpca z referenco
|
||||
pogodbe.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<!-- Defaults: Segment / Decision / Action -->
|
||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label>Privzeti segment</Label>
|
||||
<Select v-model="form.meta.segment_id">
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="(brez)" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem :value="null">(brez)</SelectItem>
|
||||
<SelectItem
|
||||
v-for="s in props.segments || []"
|
||||
:key="s.id"
|
||||
:value="s.id"
|
||||
>
|
||||
{{ s.name }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label>Privzeto dejanje (za aktivnost)</Label>
|
||||
<Select v-model="form.meta.action_id">
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="(brez)" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem :value="null">(brez)</SelectItem>
|
||||
<SelectItem
|
||||
v-for="a in props.actions || []"
|
||||
:key="a.id"
|
||||
:value="a.id"
|
||||
>
|
||||
{{ a.name }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label>Privzeta odločitev</Label>
|
||||
<Select v-model="form.meta.decision_id" :disabled="!form.meta.action_id">
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="(brez)" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem :value="null">(brez)</SelectItem>
|
||||
<SelectItem
|
||||
v-for="d in decisionsForSelectedAction"
|
||||
:key="d.id"
|
||||
:value="d.id"
|
||||
>
|
||||
{{ d.name }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p v-if="!form.meta.action_id" class="text-xs text-muted-foreground">
|
||||
Izberite dejanje za ogled njegovih odločitev.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Defaults: Segment / Decision / Action -->
|
||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700"
|
||||
>Default Segment</label
|
||||
>
|
||||
<select
|
||||
v-model="form.meta.segment_id"
|
||||
class="mt-1 block w-full border rounded p-2"
|
||||
>
|
||||
<option :value="null">(none)</option>
|
||||
<option v-for="s in props.segments || []" :key="s.id" :value="s.id">
|
||||
{{ s.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700"
|
||||
>Default Action (for Activity)</label
|
||||
>
|
||||
<select
|
||||
v-model="form.meta.action_id"
|
||||
class="mt-1 block w-full border rounded p-2"
|
||||
>
|
||||
<option :value="null">(none)</option>
|
||||
<option v-for="a in props.actions || []" :key="a.id" :value="a.id">
|
||||
{{ a.name }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700"
|
||||
>Default Decision</label
|
||||
>
|
||||
<select
|
||||
v-model="form.meta.decision_id"
|
||||
class="mt-1 block w-full border rounded p-2"
|
||||
:disabled="!form.meta.action_id"
|
||||
>
|
||||
<option :value="null">(none)</option>
|
||||
<option v-for="d in decisionsForSelectedAction" :key="d.id" :value="d.id">
|
||||
{{ d.name }}
|
||||
</option>
|
||||
</select>
|
||||
<p v-if="!form.meta.action_id" class="text-xs text-gray-500 mt-1">
|
||||
Select an Action to see its Decisions.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Name</label>
|
||||
<input
|
||||
v-model="form.name"
|
||||
type="text"
|
||||
class="mt-1 block w-full border rounded p-2"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Description</label>
|
||||
<textarea
|
||||
v-model="form.description"
|
||||
class="mt-1 block w-full border rounded p-2"
|
||||
rows="3"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Source Type</label>
|
||||
<select
|
||||
v-model="form.source_type"
|
||||
class="mt-1 block w-full border rounded p-2"
|
||||
>
|
||||
<option value="csv">CSV</option>
|
||||
<option value="xml">XML</option>
|
||||
<option value="xls">XLS</option>
|
||||
<option value="xlsx">XLSX</option>
|
||||
<option value="json">JSON</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700"
|
||||
>Default Record Type (optional)</label
|
||||
>
|
||||
<input
|
||||
v-model="form.default_record_type"
|
||||
<Separator />
|
||||
<div class="space-y-2">
|
||||
<Label for="name">Ime</Label>
|
||||
<Input
|
||||
id="name"
|
||||
v-model="form.name"
|
||||
type="text"
|
||||
class="mt-1 block w-full border rounded p-2"
|
||||
placeholder="e.g., account, person"
|
||||
placeholder="Vnesite ime predloge"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<input
|
||||
id="is_active"
|
||||
v-model="form.is_active"
|
||||
type="checkbox"
|
||||
class="rounded"
|
||||
/>
|
||||
<label for="is_active" class="text-sm font-medium text-gray-700"
|
||||
>Active</label
|
||||
>
|
||||
<div class="flex items-center gap-2 ml-6">
|
||||
<input id="reactivate" v-model="form.reactivate" type="checkbox" class="rounded" />
|
||||
<label for="reactivate" class="text-sm font-medium text-gray-700">Reactivation import</label>
|
||||
<div class="space-y-2">
|
||||
<Label for="description">Opis</Label>
|
||||
<Textarea
|
||||
id="description"
|
||||
v-model="form.description"
|
||||
placeholder="Vnesite opis predloge"
|
||||
rows="3"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pt-4">
|
||||
<button
|
||||
@click.prevent="submit"
|
||||
class="px-4 py-2 bg-emerald-600 text-white rounded"
|
||||
:disabled="form.processing"
|
||||
>
|
||||
{{ form.processing ? "Saving…" : "Create Template" }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="source-type">Tip vira</Label>
|
||||
<Select v-model="form.source_type">
|
||||
<SelectTrigger id="source-type">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="csv">CSV</SelectItem>
|
||||
<SelectItem value="xml">XML</SelectItem>
|
||||
<SelectItem value="xls">XLS</SelectItem>
|
||||
<SelectItem value="xlsx">XLSX</SelectItem>
|
||||
<SelectItem value="json">JSON</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="record-type">Privzeti tip zapisa (izbirno)</Label>
|
||||
<Input
|
||||
id="record-type"
|
||||
v-model="form.default_record_type"
|
||||
type="text"
|
||||
placeholder="npr. račun, oseba"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="form.errors && Object.keys(form.errors).length"
|
||||
class="text-sm text-red-600"
|
||||
>
|
||||
<div v-for="(msg, key) in form.errors" :key="key">{{ msg }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-6">
|
||||
<div class="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id="is_active"
|
||||
:checked="form.is_active"
|
||||
@update:checked="form.is_active = $event"
|
||||
/>
|
||||
<Label for="is_active" class="cursor-pointer">Aktivno</Label>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id="reactivate"
|
||||
:checked="form.reactivate"
|
||||
@update:checked="form.reactivate = $event"
|
||||
/>
|
||||
<Label for="reactivate" class="cursor-pointer">Uvoz reaktivacije</Label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div class="flex items-center justify-between pt-2">
|
||||
<div
|
||||
v-if="form.errors && Object.keys(form.errors).length"
|
||||
class="text-sm text-destructive"
|
||||
>
|
||||
<div v-for="(msg, key) in form.errors" :key="key">{{ msg }}</div>
|
||||
</div>
|
||||
<Button @click.prevent="submit" :disabled="form.processing" class="ml-auto">
|
||||
{{ form.processing ? "Shranjevanje…" : "Ustvari predlogo" }}
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
|
||||
Reference in New Issue
Block a user