Admin panel updated with shadcn-vue components
This commit is contained in:
@@ -1,327 +1,352 @@
|
||||
<template>
|
||||
<AdminLayout title="Uredi predlogo">
|
||||
<div class="mb-6 flex flex-col lg:flex-row lg:items-start gap-6">
|
||||
<div class="flex-1 min-w-[320px]">
|
||||
<div class="flex items-start justify-between gap-4 mb-4">
|
||||
<div>
|
||||
<h1 class="text-2xl font-semibold tracking-tight">{{ template.name }}</h1>
|
||||
<p class="text-xs text-gray-500 mt-1 flex flex-wrap gap-3">
|
||||
<span class="inline-flex items-center gap-1"
|
||||
><span class="text-gray-400">Slug:</span
|
||||
><span class="font-medium">{{ template.slug }}</span></span
|
||||
>
|
||||
<span class="inline-flex items-center gap-1"
|
||||
><span class="text-gray-400">Verzija:</span
|
||||
><span class="font-medium">v{{ template.version }}</span></span
|
||||
>
|
||||
<span
|
||||
class="inline-flex items-center gap-1"
|
||||
:class="template.active ? 'text-emerald-600' : 'text-gray-400'"
|
||||
><span
|
||||
class="w-1.5 h-1.5 rounded-full"
|
||||
:class="template.active ? 'bg-emerald-500' : 'bg-gray-300'"
|
||||
/>
|
||||
{{ template.active ? "Aktivna" : "Neaktivna" }}</span
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
<form @submit.prevent="toggleActive" class="flex items-center gap-2">
|
||||
<button
|
||||
type="submit"
|
||||
:class="[btnBase, template.active ? btnWarn : btnOutline]"
|
||||
:disabled="toggleForm.processing"
|
||||
>
|
||||
<span v-if="toggleForm.processing">...</span>
|
||||
<span v-else>{{ template.active ? "Deaktiviraj" : "Aktiviraj" }}</span>
|
||||
</button>
|
||||
<Link
|
||||
:href="route('admin.document-templates.show', template.id)"
|
||||
:class="[btnBase, btnOutline]"
|
||||
>Ogled</Link
|
||||
>
|
||||
</form>
|
||||
</div>
|
||||
<div class="flex-1 min-w-[320px] space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="inline-flex items-center justify-center h-10 w-10 rounded-lg bg-primary/10 text-primary">
|
||||
<FileTextIcon class="h-5 w-5" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>{{ template.name }}</CardTitle>
|
||||
<CardDescription class="flex flex-wrap gap-3 mt-1">
|
||||
<span class="inline-flex items-center gap-1">
|
||||
<span>Slug:</span>
|
||||
<Badge variant="secondary" class="text-xs">{{ template.slug }}</Badge>
|
||||
</span>
|
||||
<span class="inline-flex items-center gap-1">
|
||||
<span>Verzija:</span>
|
||||
<Badge variant="secondary" class="text-xs">v{{ template.version }}</Badge>
|
||||
</span>
|
||||
<Badge :variant="template.active ? 'default' : 'outline'" class="text-xs">
|
||||
{{ template.active ? "Aktivna" : "Neaktivna" }}
|
||||
</Badge>
|
||||
</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<form @submit.prevent="toggleActive">
|
||||
<Button
|
||||
type="submit"
|
||||
:variant="template.active ? 'destructive' : 'default'"
|
||||
size="sm"
|
||||
:disabled="toggleForm.processing"
|
||||
>
|
||||
<PowerOffIcon v-if="template.active" class="h-4 w-4 mr-2" />
|
||||
<Power v-else class="h-4 w-4 mr-2" />
|
||||
{{ template.active ? "Deaktiviraj" : "Aktiviraj" }}
|
||||
</Button>
|
||||
</form>
|
||||
<Button size="sm" variant="outline" as-child>
|
||||
<Link :href="route('admin.document-templates.show', template.id)">
|
||||
<EyeIcon class="h-4 w-4 mr-2" />
|
||||
Ogled
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
|
||||
<form @submit.prevent="submit" class="space-y-8">
|
||||
<form @submit.prevent="submit" class="space-y-6">
|
||||
<!-- Osnovno -->
|
||||
<div class="bg-white border rounded-lg shadow-sm p-5 space-y-5">
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-sm font-semibold tracking-wide text-gray-700 uppercase">
|
||||
Osnovne nastavitve
|
||||
</h2>
|
||||
</div>
|
||||
<div class="grid md:grid-cols-2 gap-6">
|
||||
<label class="space-y-1 block">
|
||||
<span class="text-xs font-medium text-gray-600"
|
||||
>Izlazna datoteka (pattern)</span
|
||||
>
|
||||
<input
|
||||
v-model="form.output_filename_pattern"
|
||||
type="text"
|
||||
class="input input-bordered w-full input-sm"
|
||||
placeholder="POVRACILO_{contract.reference}"
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div class="flex items-center gap-2">
|
||||
<Settings2Icon class="h-4 w-4" />
|
||||
<CardTitle class="text-base">Osnovne nastavitve</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent class="space-y-4">
|
||||
<div class="grid md:grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="output_filename_pattern">Izlazna datoteka (pattern)</Label>
|
||||
<Input
|
||||
id="output_filename_pattern"
|
||||
v-model="form.output_filename_pattern"
|
||||
placeholder="POVRACILO_{contract.reference}"
|
||||
class="font-mono text-sm"
|
||||
/>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Tokens npr. {contract.reference}
|
||||
</p>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="date_format">Privzeti format datuma</Label>
|
||||
<Input
|
||||
id="date_format"
|
||||
v-model="form.date_format"
|
||||
placeholder="d.m.Y"
|
||||
class="font-mono text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id="fail_on_unresolved"
|
||||
:default-value="form.fail_on_unresolved"
|
||||
@update:model-value="(val) => (form.fail_on_unresolved = val)"
|
||||
/>
|
||||
<span class="text-[11px] text-gray-500"
|
||||
>Tokens npr. {contract.reference}</span
|
||||
>
|
||||
</label>
|
||||
<label class="space-y-1 block">
|
||||
<span class="text-xs font-medium text-gray-600"
|
||||
>Privzeti format datuma</span
|
||||
>
|
||||
<input
|
||||
v-model="form.date_format"
|
||||
type="text"
|
||||
class="input input-bordered w-full input-sm"
|
||||
placeholder="d.m.Y"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<label class="flex items-center gap-2 text-xs font-medium text-gray-600">
|
||||
<input
|
||||
id="fail_on_unresolved"
|
||||
type="checkbox"
|
||||
v-model="form.fail_on_unresolved"
|
||||
class="checkbox checkbox-xs"
|
||||
/>
|
||||
<span>Prekini če token ni rešen (fail on unresolved)</span>
|
||||
</label>
|
||||
</div>
|
||||
<Label for="fail_on_unresolved" class="cursor-pointer font-normal">
|
||||
Prekini če token ni rešen (fail on unresolved)
|
||||
</Label>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<!-- Formatiranje -->
|
||||
<div class="bg-white border rounded-lg shadow-sm p-5 space-y-5">
|
||||
<h2 class="text-sm font-semibold tracking-wide text-gray-700 uppercase">
|
||||
Formatiranje
|
||||
</h2>
|
||||
<div class="grid md:grid-cols-3 gap-5">
|
||||
<label class="space-y-1 block">
|
||||
<span class="text-xs font-medium text-gray-600">Decimalna mesta</span>
|
||||
<input
|
||||
v-model.number="form.number_decimals"
|
||||
type="number"
|
||||
min="0"
|
||||
max="6"
|
||||
class="input input-bordered w-full input-sm"
|
||||
/>
|
||||
</label>
|
||||
<label class="space-y-1 block">
|
||||
<span class="text-xs font-medium text-gray-600">Decimalni separator</span>
|
||||
<input
|
||||
v-model="form.decimal_separator"
|
||||
type="text"
|
||||
maxlength="2"
|
||||
class="input input-bordered w-full input-sm"
|
||||
/>
|
||||
</label>
|
||||
<label class="space-y-1 block">
|
||||
<span class="text-xs font-medium text-gray-600">Tisocice separator</span>
|
||||
<input
|
||||
v-model="form.thousands_separator"
|
||||
type="text"
|
||||
maxlength="2"
|
||||
class="input input-bordered w-full input-sm"
|
||||
/>
|
||||
</label>
|
||||
<label class="space-y-1 block">
|
||||
<span class="text-xs font-medium text-gray-600">Znak valute</span>
|
||||
<input
|
||||
v-model="form.currency_symbol"
|
||||
type="text"
|
||||
maxlength="8"
|
||||
class="input input-bordered w-full input-sm"
|
||||
/>
|
||||
</label>
|
||||
<label class="space-y-1 block">
|
||||
<span class="text-xs font-medium text-gray-600">Pozicija valute</span>
|
||||
<select
|
||||
v-model="form.currency_position"
|
||||
class="select select-bordered select-sm w-full"
|
||||
>
|
||||
<option :value="null">(privzeto)</option>
|
||||
<option value="before">Pred</option>
|
||||
<option value="after">Za</option>
|
||||
</select>
|
||||
</label>
|
||||
<label
|
||||
class="flex items-center gap-2 space-y-0 pt-6 text-xs font-medium text-gray-600"
|
||||
>
|
||||
<input
|
||||
id="currency_space"
|
||||
type="checkbox"
|
||||
v-model="form.currency_space"
|
||||
class="checkbox checkbox-xs"
|
||||
/>
|
||||
<span>Presledek pred/za valuto</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div class="flex items-center gap-2">
|
||||
<FileTextIcon class="h-4 w-4" />
|
||||
<CardTitle class="text-base">Formatiranje</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div class="grid md:grid-cols-3 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="number_decimals">Decimalna mesta</Label>
|
||||
<Input
|
||||
id="number_decimals"
|
||||
v-model.number="form.number_decimals"
|
||||
type="number"
|
||||
min="0"
|
||||
max="6"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="decimal_separator">Decimalni separator</Label>
|
||||
<Input
|
||||
id="decimal_separator"
|
||||
v-model="form.decimal_separator"
|
||||
maxlength="2"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="thousands_separator">Tisočice separator</Label>
|
||||
<Input
|
||||
id="thousands_separator"
|
||||
v-model="form.thousands_separator"
|
||||
maxlength="2"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="currency_symbol">Znak valute</Label>
|
||||
<Input
|
||||
id="currency_symbol"
|
||||
v-model="form.currency_symbol"
|
||||
maxlength="8"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="currency_position">Pozicija valute</Label>
|
||||
<Select v-model="form.currency_position">
|
||||
<SelectTrigger id="currency_position">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem :value="null">(privzeto)</SelectItem>
|
||||
<SelectItem value="before">Pred</SelectItem>
|
||||
<SelectItem value="after">Za</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 pt-8">
|
||||
<Checkbox
|
||||
id="currency_space"
|
||||
:default-value="form.currency_space"
|
||||
@update:model-value="(val) => (form.currency_space = val)"
|
||||
/>
|
||||
<Label for="currency_space" class="cursor-pointer font-normal">
|
||||
Presledek pred/za valuto
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<!-- Aktivnost -->
|
||||
<div class="bg-white border rounded-lg shadow-sm p-5 space-y-5">
|
||||
<h2 class="text-sm font-semibold tracking-wide text-gray-700 uppercase">
|
||||
Aktivnost
|
||||
</h2>
|
||||
<div class="grid md:grid-cols-2 gap-6">
|
||||
<label class="space-y-1 block">
|
||||
<span class="text-xs font-medium text-gray-600">Akcija</span>
|
||||
<select
|
||||
v-model="form.action_id"
|
||||
class="select select-bordered select-sm w-full"
|
||||
@change="handleActionChange"
|
||||
>
|
||||
<option :value="null">(brez)</option>
|
||||
<option v-for="a in actions" :key="a.id" :value="a.id">
|
||||
{{ a.name }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="space-y-1 block">
|
||||
<span class="text-xs font-medium text-gray-600">Odločitev</span>
|
||||
<select
|
||||
v-model="form.decision_id"
|
||||
class="select select-bordered select-sm w-full"
|
||||
:disabled="!currentActionDecisions.length"
|
||||
>
|
||||
<option :value="null">(brez)</option>
|
||||
<option v-for="d in currentActionDecisions" :key="d.id" :value="d.id">
|
||||
{{ d.name }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="space-y-1 md:col-span-2 block">
|
||||
<span class="text-xs font-medium text-gray-600"
|
||||
>Predloga opombe aktivnosti</span
|
||||
>
|
||||
<textarea
|
||||
v-model="form.activity_note_template"
|
||||
rows="3"
|
||||
class="textarea textarea-bordered w-full text-xs"
|
||||
placeholder="Besedilo aktivnosti..."
|
||||
/>
|
||||
<span class="text-[11px] text-gray-500"
|
||||
>Tokeni npr. {contract.reference}</span
|
||||
>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div class="flex items-center gap-2">
|
||||
<ActivityIcon class="h-4 w-4" />
|
||||
<CardTitle class="text-base">Aktivnost</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent class="space-y-4">
|
||||
<div class="grid md:grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="action_id">Akcija</Label>
|
||||
<Select v-model="form.action_id" @update:model-value="handleActionChange">
|
||||
<SelectTrigger id="action_id">
|
||||
<SelectValue placeholder="(brez)" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem :value="null">(brez)</SelectItem>
|
||||
<SelectItem v-for="a in actions" :key="a.id" :value="a.id">
|
||||
{{ a.name }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="decision_id">Odločitev</Label>
|
||||
<Select v-model="form.decision_id" :disabled="!currentActionDecisions.length">
|
||||
<SelectTrigger id="decision_id">
|
||||
<SelectValue placeholder="(brez)" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem :value="null">(brez)</SelectItem>
|
||||
<SelectItem v-for="d in currentActionDecisions" :key="d.id" :value="d.id">
|
||||
{{ d.name }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="space-y-2 md:col-span-2">
|
||||
<Label for="activity_note_template">Predloga opombe aktivnosti</Label>
|
||||
<Textarea
|
||||
id="activity_note_template"
|
||||
v-model="form.activity_note_template"
|
||||
rows="3"
|
||||
placeholder="Besedilo aktivnosti..."
|
||||
/>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Tokeni npr. {contract.reference}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<!-- Custom tokens defaults -->
|
||||
<div class="bg-white border rounded-lg shadow-sm p-5 space-y-5">
|
||||
<h2 class="text-sm font-semibold tracking-wide text-gray-700 uppercase">
|
||||
Custom tokens (privzete vrednosti)
|
||||
</h2>
|
||||
<div class="space-y-3">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" :class="[btnBase, btnOutline]" @click="addCustomDefault">
|
||||
Dodaj vrstico
|
||||
</button>
|
||||
<CodeIcon class="h-4 w-4" />
|
||||
<CardTitle class="text-base">Custom tokens (privzete vrednosti)</CardTitle>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
</CardHeader>
|
||||
<CardContent class="space-y-4">
|
||||
<Button type="button" variant="outline" size="sm" @click="addCustomDefault">
|
||||
Dodaj vrstico
|
||||
</Button>
|
||||
<div class="grid grid-cols-1 gap-3">
|
||||
<div
|
||||
v-for="(row, idx) in customRows"
|
||||
:key="idx"
|
||||
class="grid grid-cols-12 items-center gap-2"
|
||||
class="grid grid-cols-12 items-start gap-2"
|
||||
>
|
||||
<input
|
||||
v-model="row.key"
|
||||
type="text"
|
||||
class="input input-bordered input-sm w-full col-span-4"
|
||||
placeholder="custom ključ (npr. order_id)"
|
||||
/>
|
||||
<template v-if="row.type === 'text'">
|
||||
<textarea
|
||||
<div class="col-span-4 space-y-1">
|
||||
<Input
|
||||
v-model="row.key"
|
||||
placeholder="custom ključ (npr. order_id)"
|
||||
class="font-mono text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-span-5 space-y-1">
|
||||
<Textarea
|
||||
v-if="row.type === 'text'"
|
||||
v-model="row.value"
|
||||
rows="3"
|
||||
class="textarea textarea-bordered w-full text-xs col-span-5"
|
||||
placeholder="privzeta vrednost"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<input
|
||||
<Input
|
||||
v-else
|
||||
v-model="row.value"
|
||||
type="text"
|
||||
class="input input-bordered input-sm w-full col-span-5"
|
||||
placeholder="privzeta vrednost"
|
||||
/>
|
||||
</template>
|
||||
<select v-model="row.type" class="select select-bordered select-sm w-full col-span-2">
|
||||
<option value="string">string</option>
|
||||
<option value="number">number</option>
|
||||
<option value="date">date</option>
|
||||
<option value="text">text</option>
|
||||
</select>
|
||||
<button type="button" class="btn btn-ghost btn-xs col-span-1" @click="removeCustomDefault(idx)">✕</button>
|
||||
</div>
|
||||
<div class="col-span-2 space-y-1">
|
||||
<Select v-model="row.type">
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="string">string</SelectItem>
|
||||
<SelectItem value="number">number</SelectItem>
|
||||
<SelectItem value="date">date</SelectItem>
|
||||
<SelectItem value="text">text</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="col-span-1 flex items-center pt-2">
|
||||
<Button type="button" variant="ghost" size="icon" @click="removeCustomDefault(idx)">
|
||||
<XIcon class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-[11px] text-gray-500">
|
||||
Uporabite v predlogi kot <code v-pre>{{custom.your_key}}</code>. Manjkajoče vrednosti se privzeto izpraznijo.
|
||||
<p class="text-xs text-muted-foreground">
|
||||
Uporabite v predlogi kot <code class="px-1 py-0.5 bg-muted rounded text-xs" v-pre>{{custom.your_key}}</code>. Manjkajoče vrednosti se privzeto izpraznijo.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div class="flex items-center gap-3 pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
:class="[btnBase, btnPrimary]"
|
||||
:disabled="form.processing"
|
||||
>
|
||||
<span v-if="form.processing">Shranjevanje…</span>
|
||||
<span v-else>Shrani spremembe</span>
|
||||
</button>
|
||||
<Link
|
||||
:href="route('admin.document-templates.show', template.id)"
|
||||
:class="[btnBase, btnOutline]"
|
||||
>Prekliči</Link
|
||||
>
|
||||
<Button type="submit" :disabled="form.processing">
|
||||
<SaveIcon class="h-4 w-4 mr-2" />
|
||||
{{ form.processing ? "Shranjevanje…" : "Shrani spremembe" }}
|
||||
</Button>
|
||||
<Button variant="outline" as-child>
|
||||
<Link :href="route('admin.document-templates.show', template.id)">
|
||||
<XIcon class="h-4 w-4 mr-2" />
|
||||
Prekliči
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Side meta panel -->
|
||||
<aside class="w-full lg:w-72 space-y-6">
|
||||
<div class="bg-white border rounded-lg shadow-sm p-4 space-y-3">
|
||||
<h3 class="text-xs font-semibold tracking-wide text-gray-600 uppercase">
|
||||
Meta
|
||||
</h3>
|
||||
<ul class="text-xs text-gray-600 space-y-1">
|
||||
<li>
|
||||
<span class="text-gray-400">Velikost:</span>
|
||||
<span class="font-medium"
|
||||
>{{ (template.file_size / 1024).toFixed(1) }} KB</span
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle class="text-sm">Meta podatki</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="space-y-4">
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Velikost:</span>
|
||||
<Badge variant="secondary">{{ (template.file_size / 1024).toFixed(1) }} KB</Badge>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Hash:</span>
|
||||
<code class="text-xs">{{ template.file_hash?.substring(0, 12) }}…</code>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Engine:</span>
|
||||
<Badge variant="outline">{{ template.engine }}</Badge>
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<Button variant="outline" size="sm" class="w-full" as-child>
|
||||
<a :href="'/storage/' + template.file_path" target="_blank">
|
||||
Prenesi izvorni DOCX
|
||||
</a>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card v-if="template.tokens?.length">
|
||||
<CardHeader>
|
||||
<CardTitle class="text-sm">Tokens</CardTitle>
|
||||
<CardDescription>{{ template.tokens.length }} tokenov</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div class="flex flex-wrap gap-1.5 max-h-48 overflow-auto">
|
||||
<Badge
|
||||
v-for="t in template.tokens"
|
||||
:key="t"
|
||||
variant="secondary"
|
||||
class="font-mono text-xs"
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-gray-400">Hash:</span>
|
||||
<span class="font-mono">{{ template.file_hash?.substring(0, 12) }}…</span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-gray-400">Engine:</span>
|
||||
<span class="font-medium">{{ template.engine }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<a
|
||||
:href="'/storage/' + template.file_path"
|
||||
target="_blank"
|
||||
class="text-[11px] inline-flex items-center gap-1 text-indigo-600 hover:underline"
|
||||
>Prenesi izvorni DOCX →</a
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
v-if="template.tokens?.length"
|
||||
class="bg-white border rounded-lg shadow-sm p-4"
|
||||
>
|
||||
<h3 class="text-xs font-semibold tracking-wide text-gray-600 uppercase mb-2">
|
||||
Tokens ({{ template.tokens.length }})
|
||||
</h3>
|
||||
<div class="flex flex-wrap gap-1.5 max-h-48 overflow-auto pr-1">
|
||||
<span
|
||||
v-for="t in template.tokens"
|
||||
:key="t"
|
||||
class="px-1.5 py-0.5 bg-gray-100 rounded text-[11px] font-mono"
|
||||
>{{ t }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{{ t }}
|
||||
</Badge>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</aside>
|
||||
</div>
|
||||
</AdminLayout>
|
||||
@@ -331,6 +356,16 @@
|
||||
import { computed, reactive } from "vue";
|
||||
import { useForm, Link, router } from "@inertiajs/vue3";
|
||||
import AdminLayout from "@/Layouts/AdminLayout.vue";
|
||||
import { Settings2Icon, FileTextIcon, ActivityIcon, CodeIcon, SaveIcon, XIcon, EyeIcon, Power, PowerOffIcon } from "lucide-vue-next";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/Components/ui/card";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import { Input } from "@/Components/ui/input";
|
||||
import { Label } from "@/Components/ui/label";
|
||||
import { Textarea } from "@/Components/ui/textarea";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/Components/ui/select";
|
||||
import { Checkbox } from "@/Components/ui/checkbox";
|
||||
import { Badge } from "@/Components/ui/badge";
|
||||
import { Separator } from "@/Components/ui/separator";
|
||||
|
||||
// Button style utility classes
|
||||
const btnBase =
|
||||
|
||||
@@ -2,6 +2,34 @@
|
||||
import AdminLayout from "@/Layouts/AdminLayout.vue";
|
||||
import { Link, useForm } from "@inertiajs/vue3";
|
||||
import { computed, ref } from "vue";
|
||||
import {
|
||||
UploadIcon,
|
||||
FileTextIcon,
|
||||
Power,
|
||||
PowerOffIcon,
|
||||
PencilIcon,
|
||||
CheckIcon,
|
||||
XIcon,
|
||||
} from "lucide-vue-next";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/Components/ui/card";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import { Input } from "@/Components/ui/input";
|
||||
import { Label } from "@/Components/ui/label";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/Components/ui/select";
|
||||
import { Badge } from "@/Components/ui/badge";
|
||||
import { Progress } from "@/Components/ui/progress";
|
||||
|
||||
const props = defineProps({
|
||||
templates: { type: Array, default: () => [] },
|
||||
@@ -9,7 +37,7 @@ const props = defineProps({
|
||||
|
||||
// Upload form state
|
||||
const uploadForm = useForm({ name: "", slug: "", file: null });
|
||||
const selectedSlug = ref("");
|
||||
const selectedSlug = ref(null);
|
||||
const uniqueSlugs = computed(() => {
|
||||
const s = new Set(props.templates.map((t) => t.slug));
|
||||
return Array.from(s).sort();
|
||||
@@ -60,186 +88,164 @@ const groups = computed(() => {
|
||||
|
||||
<template>
|
||||
<AdminLayout title="Dokumentne predloge">
|
||||
<div class="mb-8 space-y-6">
|
||||
<div class="space-y-6">
|
||||
<!-- Header & Upload -->
|
||||
<div class="flex flex-col xl:flex-row xl:items-start gap-6">
|
||||
<div class="flex-1 min-w-[280px]">
|
||||
<h1 class="text-2xl font-semibold tracking-tight flex items-center gap-2">
|
||||
<span>Dokumentne predloge</span>
|
||||
<span
|
||||
class="text-xs font-medium bg-gray-200 text-gray-600 px-2 py-0.5 rounded"
|
||||
>{{ groups.length }} skupin</span
|
||||
>
|
||||
</h1>
|
||||
<p class="text-sm text-gray-500 mt-1 max-w-prose">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<h1 class="text-2xl font-semibold tracking-tight">Dokumentne predloge</h1>
|
||||
<Badge variant="secondary">{{ groups.length }} skupin</Badge>
|
||||
</div>
|
||||
<p class="text-sm text-muted-foreground max-w-prose">
|
||||
Upravljaj verzije DOCX predlog. Naloži novo verzijo obstoječega sluga ali
|
||||
ustvari popolnoma novo predlogo.
|
||||
</p>
|
||||
</div>
|
||||
<form
|
||||
@submit.prevent="submitUpload"
|
||||
class="flex-1 bg-white/70 backdrop-blur border rounded-lg shadow-sm p-4 flex flex-col gap-3"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-sm font-semibold text-gray-700 flex items-center gap-2">
|
||||
<span class="i-lucide-upload-cloud w-4 h-4" /> Nova / nova verzija
|
||||
</h2>
|
||||
<div
|
||||
v-if="uploadForm.progress"
|
||||
class="w-40 h-1 bg-gray-200 rounded overflow-hidden"
|
||||
>
|
||||
<div
|
||||
class="h-full bg-indigo-500 transition-all"
|
||||
:style="{ width: uploadForm.progress.percentage + '%' }"
|
||||
<Card class="flex-1">
|
||||
<CardHeader>
|
||||
<div class="flex items-center justify-between">
|
||||
<CardTitle class="text-base flex items-center gap-2">
|
||||
<UploadIcon class="h-4 w-4" />
|
||||
Nova / nova verzija
|
||||
</CardTitle>
|
||||
<Progress
|
||||
v-if="uploadForm.progress"
|
||||
:model-value="uploadForm.progress.percentage"
|
||||
class="w-40 h-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid md:grid-cols-5 gap-3 text-xs">
|
||||
<div class="md:col-span-1">
|
||||
<label class="block font-medium mb-1">Obstoječi slug</label>
|
||||
<select
|
||||
v-model="selectedSlug"
|
||||
class="select select-bordered select-sm w-full"
|
||||
>
|
||||
<option value="">(nov)</option>
|
||||
<option v-for="s in uniqueSlugs" :key="s" :value="s">{{ s }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="md:col-span-1">
|
||||
<label class="block font-medium mb-1">Nov slug</label>
|
||||
<input
|
||||
v-model="uploadForm.slug"
|
||||
:disabled="!!selectedSlug"
|
||||
type="text"
|
||||
class="input input-bordered input-sm w-full"
|
||||
placeholder="opomin"
|
||||
/>
|
||||
</div>
|
||||
<div class="md:col-span-1">
|
||||
<label class="block font-medium mb-1">Naziv</label>
|
||||
<input
|
||||
v-model="uploadForm.name"
|
||||
type="text"
|
||||
class="input input-bordered input-sm w-full"
|
||||
placeholder="Ime predloge"
|
||||
/>
|
||||
</div>
|
||||
<div class="md:col-span-2 flex items-end">
|
||||
<label class="w-full">
|
||||
<input
|
||||
id="docx-upload-input"
|
||||
@change="handleFile"
|
||||
type="file"
|
||||
accept=".docx"
|
||||
class="file-input file-input-bordered file-input-sm w-full"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-end gap-3 pt-1">
|
||||
<span class="text-[11px] text-gray-500" v-if="!uploadForm.file"
|
||||
>Izberi DOCX datoteko…</span
|
||||
>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-sm btn-primary"
|
||||
:disabled="
|
||||
uploadForm.processing ||
|
||||
!uploadForm.file ||
|
||||
(!uploadForm.slug && !selectedSlug)
|
||||
"
|
||||
>
|
||||
<span v-if="uploadForm.processing">Nalaganje…</span>
|
||||
<span v-else>Shrani verzijo</span>
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="uploadForm.errors.file" class="text-rose-600 text-xs">
|
||||
{{ uploadForm.errors.file }}
|
||||
</div>
|
||||
</form>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form @submit.prevent="submitUpload" class="space-y-4">
|
||||
<div class="grid md:grid-cols-5 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="existing_slug">Obstoječi slug</Label>
|
||||
<Select v-model="selectedSlug">
|
||||
<SelectTrigger id="existing_slug">
|
||||
<SelectValue placeholder="(nov)" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem v-for="s in uniqueSlugs" :key="s" :value="s">{{
|
||||
s
|
||||
}}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="new_slug">Nov slug</Label>
|
||||
<Input
|
||||
id="new_slug"
|
||||
v-model="uploadForm.slug"
|
||||
:disabled="!!selectedSlug"
|
||||
placeholder="opomin"
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="template_name">Naziv</Label>
|
||||
<Input
|
||||
id="template_name"
|
||||
v-model="uploadForm.name"
|
||||
placeholder="Ime predloge"
|
||||
/>
|
||||
</div>
|
||||
<div class="md:col-span-2 space-y-2">
|
||||
<Label for="docx-upload-input">DOCX datoteka</Label>
|
||||
<Input
|
||||
id="docx-upload-input"
|
||||
@change="handleFile"
|
||||
type="file"
|
||||
accept=".docx"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-end gap-3">
|
||||
<span class="text-xs text-muted-foreground" v-if="!uploadForm.file">
|
||||
Izberi DOCX datoteko…
|
||||
</span>
|
||||
<Button
|
||||
type="submit"
|
||||
size="sm"
|
||||
:disabled="
|
||||
uploadForm.processing ||
|
||||
!uploadForm.file ||
|
||||
(!uploadForm.slug && !selectedSlug)
|
||||
"
|
||||
>
|
||||
<UploadIcon class="h-4 w-4 mr-2" />
|
||||
{{ uploadForm.processing ? "Nalaganje…" : "Shrani verzijo" }}
|
||||
</Button>
|
||||
</div>
|
||||
<p v-if="uploadForm.errors.file" class="text-sm text-destructive">
|
||||
{{ uploadForm.errors.file }}
|
||||
</p>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<!-- Groups -->
|
||||
<div v-if="groups.length" class="grid gap-6 md:grid-cols-2 xl:grid-cols-3">
|
||||
<div
|
||||
v-for="g in groups"
|
||||
:key="g.slug"
|
||||
class="group relative flex flex-col bg-white border rounded-lg shadow-sm overflow-hidden"
|
||||
>
|
||||
<div
|
||||
class="px-4 py-3 border-b bg-gradient-to-r from-gray-50 to-white flex items-start justify-between gap-3"
|
||||
>
|
||||
<div class="min-w-0">
|
||||
<h3 class="font-medium text-sm leading-5 truncate">{{ g.name }}</h3>
|
||||
<div
|
||||
class="flex flex-wrap items-center gap-2 mt-1 text-[11px] text-gray-500"
|
||||
>
|
||||
<span class="px-1.5 py-0.5 bg-gray-100 rounded">{{ g.slug }}</span>
|
||||
<span>Zadnja: v{{ g.versions[0].version }}</span>
|
||||
<span
|
||||
class="flex items-center gap-1"
|
||||
:class="
|
||||
g.versions.filter((v) => v.active).length
|
||||
? 'text-emerald-600'
|
||||
: 'text-gray-400'
|
||||
"
|
||||
>
|
||||
<span
|
||||
class="w-1.5 h-1.5 rounded-full"
|
||||
:class="
|
||||
g.versions.filter((v) => v.active).length
|
||||
? 'bg-emerald-500'
|
||||
: 'bg-gray-300'
|
||||
<Card v-for="g in groups" :key="g.slug">
|
||||
<CardHeader>
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="min-w-0 flex-1">
|
||||
<CardTitle class="text-base truncate">{{ g.name }}</CardTitle>
|
||||
<CardDescription class="flex flex-wrap items-center gap-2 mt-1">
|
||||
<Badge variant="secondary" class="text-xs">{{ g.slug }}</Badge>
|
||||
<span class="text-xs">Zadnja: v{{ g.versions[0].version }}</span>
|
||||
<Badge
|
||||
:variant="
|
||||
g.versions.filter((v) => v.active).length ? 'default' : 'outline'
|
||||
"
|
||||
/>
|
||||
{{ g.versions.filter((v) => v.active).length }} aktivnih
|
||||
</span>
|
||||
class="text-xs"
|
||||
>
|
||||
{{ g.versions.filter((v) => v.active).length }} aktivnih
|
||||
</Badge>
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Button size="sm" variant="ghost" as-child>
|
||||
<Link :href="route('admin.document-templates.show', g.versions[0].id)">
|
||||
Detalji
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
<Link
|
||||
:href="route('admin.document-templates.show', g.versions[0].id)"
|
||||
class="text-xs text-indigo-600 hover:underline whitespace-nowrap mt-1"
|
||||
>Detalji</Link
|
||||
>
|
||||
</div>
|
||||
<div class="p-3 flex-1 flex flex-col gap-2">
|
||||
</CardHeader>
|
||||
<CardContent class="flex flex-col gap-4">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<div v-for="v in g.versions" :key="v.id" class="flex items-center gap-1">
|
||||
<Link
|
||||
:href="route('admin.document-templates.edit', v.id)"
|
||||
class="px-2 py-0.5 rounded-md border text-[11px] font-medium transition-colors"
|
||||
:class="
|
||||
v.active
|
||||
? 'border-emerald-500/60 bg-emerald-50 text-emerald-700 hover:bg-emerald-100'
|
||||
: 'border-gray-300 bg-white text-gray-600 hover:bg-gray-50'
|
||||
"
|
||||
>v{{ v.version }}</Link
|
||||
<Button
|
||||
size="sm"
|
||||
:variant="v.active ? 'default' : 'outline'"
|
||||
class="h-7 px-2 text-xs"
|
||||
as-child
|
||||
>
|
||||
<button
|
||||
<Link :href="route('admin.document-templates.edit', v.id)">
|
||||
v{{ v.version }}
|
||||
</Link>
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
size="icon"
|
||||
:variant="v.active ? 'destructive' : 'outline'"
|
||||
class="h-7 w-7"
|
||||
@click="toggle(v.id)"
|
||||
class="rounded-md border px-1.5 py-0.5 text-[10px] font-medium transition-colors"
|
||||
:class="
|
||||
v.active
|
||||
? 'bg-amber-500 border-amber-500 text-white hover:bg-amber-600'
|
||||
: 'bg-gray-100 border-gray-300 text-gray-600 hover:bg-gray-200'
|
||||
"
|
||||
>
|
||||
{{ v.active ? "✕" : "✓" }}
|
||||
</button>
|
||||
<XIcon v-if="v.active" class="h-3 w-3" />
|
||||
<CheckIcon v-else class="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-auto pt-2 border-t flex justify-end">
|
||||
<Link
|
||||
:href="route('admin.document-templates.edit', g.versions[0].id)"
|
||||
class="text-[11px] text-indigo-600 hover:underline"
|
||||
>Uredi zadnjo verzijo →</Link
|
||||
>
|
||||
<div class="pt-2 border-t flex justify-end">
|
||||
<Button size="sm" variant="link" class="h-auto p-0" as-child>
|
||||
<Link :href="route('admin.document-templates.edit', g.versions[0].id)">
|
||||
Uredi zadnjo verziju →
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<p v-else class="text-sm text-gray-500">Ni predlog.</p>
|
||||
<p v-else class="text-sm text-muted-foreground">Ni predlog.</p>
|
||||
</div>
|
||||
</AdminLayout>
|
||||
</template>
|
||||
|
||||
@@ -2,231 +2,294 @@
|
||||
<AdminLayout title="Predloga">
|
||||
<div class="flex flex-col lg:flex-row gap-6 items-start">
|
||||
<div class="flex-1 min-w-[320px] space-y-6">
|
||||
<div class="bg-white border rounded-lg shadow-sm p-5 flex flex-col gap-4">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<h1 class="text-2xl font-semibold tracking-tight">{{ template.name }}</h1>
|
||||
<p class="text-xs text-gray-500 mt-1 flex flex-wrap gap-3">
|
||||
<span class="inline-flex items-center gap-1"
|
||||
><span class="text-gray-400">Slug:</span
|
||||
><span class="font-medium">{{ template.slug }}</span></span
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<div
|
||||
class="inline-flex items-center justify-center h-10 w-10 rounded-lg bg-primary/10 text-primary"
|
||||
>
|
||||
<span class="inline-flex items-center gap-1"
|
||||
><span class="text-gray-400">Verzija:</span
|
||||
><span class="font-medium">v{{ template.version }}</span></span
|
||||
>
|
||||
<span
|
||||
class="inline-flex items-center gap-1"
|
||||
:class="template.active ? 'text-emerald-600' : 'text-gray-400'"
|
||||
>
|
||||
<span
|
||||
class="w-1.5 h-1.5 rounded-full"
|
||||
:class="template.active ? 'bg-emerald-500' : 'bg-gray-300'"
|
||||
/>
|
||||
{{ template.active ? "Aktivna" : "Neaktivna" }}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<form @submit.prevent="toggleActive" class="flex items-center gap-2">
|
||||
<button
|
||||
type="submit"
|
||||
:class="[btnBase, template.active ? btnWarn : btnOutline]"
|
||||
:disabled="toggleForm.processing"
|
||||
>
|
||||
<span v-if="toggleForm.processing">...</span>
|
||||
<span v-else>{{ template.active ? "Deaktiviraj" : "Aktiviraj" }}</span>
|
||||
</button>
|
||||
<Link
|
||||
:href="route('admin.document-templates.edit', template.id)"
|
||||
:class="[btnBase, btnPrimary]"
|
||||
>Uredi</Link
|
||||
>
|
||||
<Link
|
||||
:href="route('admin.document-templates.index')"
|
||||
:class="[btnBase, btnOutline]"
|
||||
>Nazaj</Link
|
||||
>
|
||||
</form>
|
||||
</div>
|
||||
<div class="grid md:grid-cols-3 gap-6 text-xs">
|
||||
<div class="space-y-2">
|
||||
<h3 class="uppercase font-semibold tracking-wide text-gray-600">
|
||||
Datoteka
|
||||
</h3>
|
||||
<ul class="space-y-1 text-gray-600">
|
||||
<li>
|
||||
<span class="text-gray-400">Velikost:</span>
|
||||
<span class="font-medium"
|
||||
>{{ (template.file_size / 1024).toFixed(1) }} KB</span
|
||||
<FileTextIcon class="h-5 w-5" />
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>{{ template.name }}</CardTitle>
|
||||
<CardDescription class="flex flex-wrap gap-3 mt-1">
|
||||
<span class="inline-flex items-center gap-1">
|
||||
<span>Slug:</span>
|
||||
<Badge variant="secondary" class="text-xs">{{
|
||||
template.slug
|
||||
}}</Badge>
|
||||
</span>
|
||||
<span class="inline-flex items-center gap-1">
|
||||
<span>Verzija:</span>
|
||||
<Badge variant="secondary" class="text-xs"
|
||||
>v{{ template.version }}</Badge
|
||||
>
|
||||
</span>
|
||||
<Badge
|
||||
:variant="template.active ? 'default' : 'outline'"
|
||||
class="text-xs"
|
||||
>
|
||||
{{ template.active ? "Aktivna" : "Neaktivna" }}
|
||||
</Badge>
|
||||
</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<form @submit.prevent="toggleActive">
|
||||
<Button
|
||||
type="submit"
|
||||
:variant="template.active ? 'destructive' : 'default'"
|
||||
size="sm"
|
||||
:disabled="toggleForm.processing"
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-gray-400">Hash:</span>
|
||||
<span class="font-mono"
|
||||
>{{ template.file_hash?.substring(0, 12) }}…</span
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-gray-400">Engine:</span>
|
||||
<span class="font-medium">{{ template.engine }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<a
|
||||
:href="'/storage/' + template.file_path"
|
||||
target="_blank"
|
||||
class="text-[11px] inline-flex items-center gap-1 text-indigo-600 hover:underline"
|
||||
>Prenesi DOCX →</a
|
||||
<PowerOffIcon v-if="template.active" class="h-4 w-4 mr-2" />
|
||||
<Power v-else class="h-4 w-4 mr-2" />
|
||||
{{ template.active ? "Deaktiviraj" : "Aktiviraj" }}
|
||||
</Button>
|
||||
</form>
|
||||
<Button size="sm" as-child>
|
||||
<Link :href="route('admin.document-templates.edit', template.id)">
|
||||
<PencilIcon class="h-4 w-4 mr-2" />
|
||||
Uredi
|
||||
</Link>
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" as-child>
|
||||
<Link :href="route('admin.document-templates.index')">
|
||||
<ArrowLeftIcon class="h-4 w-4 mr-2" />
|
||||
Nazaj
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div class="grid md:grid-cols-3 gap-6 text-sm">
|
||||
<div class="space-y-3">
|
||||
<h3 class="font-semibold flex items-center gap-2">
|
||||
<FileTextIcon class="h-4 w-4" />
|
||||
Datoteka
|
||||
</h3>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Velikost:</span>
|
||||
<Badge variant="secondary"
|
||||
>{{ (template.file_size / 1024).toFixed(1) }} KB</Badge
|
||||
>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Hash:</span>
|
||||
<code class="text-xs"
|
||||
>{{ template.file_hash?.substring(0, 12) }}…</code
|
||||
>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Engine:</span>
|
||||
<Badge variant="outline">{{ template.engine }}</Badge>
|
||||
</div>
|
||||
</div>
|
||||
<Button size="sm" variant="outline" class="w-full" as-child>
|
||||
<a :href="'/storage/' + template.file_path" target="_blank">
|
||||
<DownloadIcon class="h-4 w-4 mr-2" />
|
||||
Prenesi DOCX
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<h3 class="font-semibold flex items-center gap-2">
|
||||
<HashIcon class="h-4 w-4" />
|
||||
Formatiranje
|
||||
</h3>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Datum:</span>
|
||||
<code class="text-xs">{{
|
||||
template.settings?.date_format || "d.m.Y"
|
||||
}}</code>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Decimalna mesta:</span>
|
||||
<span>{{ template.settings?.number_decimals ?? "-" }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Separators:</span>
|
||||
<code class="text-xs">
|
||||
{{ template.settings?.decimal_separator || "." }} /
|
||||
{{ template.settings?.thousands_separator || " " }}
|
||||
</code>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Valuta:</span>
|
||||
<span class="text-xs">
|
||||
{{ template.settings?.currency_symbol || "€" }} ({{
|
||||
template.settings?.currency_position || "before"
|
||||
}})
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-3">
|
||||
<h3 class="font-semibold">Aktivnost</h3>
|
||||
<div class="space-y-2 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Akcija:</span>
|
||||
<Badge variant="outline">{{ template.action?.name || "-" }}</Badge>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Odločitev:</span>
|
||||
<Badge variant="outline">{{ template.decision?.name || "-" }}</Badge>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<span class="text-muted-foreground">Fail unresolved:</span>
|
||||
<Badge
|
||||
:variant="
|
||||
template.settings?.fail_on_unresolved
|
||||
? 'destructive'
|
||||
: 'secondary'
|
||||
"
|
||||
>
|
||||
{{ template.settings?.fail_on_unresolved ? "DA" : "NE" }}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card v-if="template.settings?.activity_note_template">
|
||||
<CardHeader>
|
||||
<CardTitle class="text-base">Predloga opombe aktivnosti</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre
|
||||
class="bg-muted p-3 rounded border text-xs leading-relaxed whitespace-pre-wrap font-mono"
|
||||
>{{ template.settings.activity_note_template }}</pre
|
||||
>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card v-if="template.tokens?.length">
|
||||
<CardHeader>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<CardTitle class="text-base">Tokens</CardTitle>
|
||||
<CardDescription>{{ template.tokens.length }} tokenov</CardDescription>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
@click="expandedTokens = !expandedTokens"
|
||||
>
|
||||
{{ expandedTokens ? "Skrij" : "Prikaži vse" }}
|
||||
</Button>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h3 class="uppercase font-semibold tracking-wide text-gray-600">
|
||||
Formatiranje
|
||||
</h3>
|
||||
<ul class="space-y-1 text-gray-600">
|
||||
<li>
|
||||
<span class="text-gray-400">Datum:</span>
|
||||
{{ template.settings?.date_format || "d.m.Y" }}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-gray-400">Decimalna mesta:</span>
|
||||
{{ template.settings?.number_decimals ?? "-" }}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-gray-400">Separators:</span>
|
||||
{{ template.settings?.decimal_separator || "." }} /
|
||||
{{ template.settings?.thousands_separator || " " }}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-gray-400">Valuta:</span>
|
||||
{{ template.settings?.currency_symbol || "€" }} ({{
|
||||
template.settings?.currency_position || "before"
|
||||
}})
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<h3 class="uppercase font-semibold tracking-wide text-gray-600">
|
||||
Aktivnost
|
||||
</h3>
|
||||
<ul class="space-y-1 text-gray-600">
|
||||
<li>
|
||||
<span class="text-gray-400">Akcija:</span>
|
||||
{{ template.action?.name || "-" }}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-gray-400">Odločitev:</span>
|
||||
{{ template.decision?.name || "-" }}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-gray-400">Fail unresolved:</span>
|
||||
{{ template.settings?.fail_on_unresolved ? "DA" : "NE" }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="template.settings?.activity_note_template"
|
||||
class="bg-white border rounded-lg shadow-sm p-5 space-y-2 text-xs"
|
||||
>
|
||||
<h2 class="uppercase font-semibold tracking-wide text-gray-600">
|
||||
Predloga opombe aktivnosti
|
||||
</h2>
|
||||
<pre
|
||||
class="bg-gray-50 p-3 rounded border text-[11px] leading-relaxed whitespace-pre-wrap"
|
||||
>{{ template.settings.activity_note_template }}</pre
|
||||
>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="template.tokens?.length"
|
||||
class="bg-white border rounded-lg shadow-sm p-5"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<h2 class="uppercase font-semibold tracking-wide text-gray-600 text-xs">
|
||||
Tokens ({{ template.tokens.length }})
|
||||
</h2>
|
||||
<button
|
||||
type="button"
|
||||
@click="expandedTokens = !expandedTokens"
|
||||
class="text-[11px] text-indigo-600 hover:underline"
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div
|
||||
class="flex flex-wrap gap-1.5 overflow-auto"
|
||||
:class="!expandedTokens && 'max-h-32'"
|
||||
>
|
||||
{{ expandedTokens ? "Skrij" : "Prikaži vse" }}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-wrap gap-1.5 max-h-56 overflow-auto pr-1"
|
||||
:class="!expandedTokens && 'max-h-32'"
|
||||
>
|
||||
<span
|
||||
v-for="t in template.tokens"
|
||||
:key="t"
|
||||
class="px-1.5 py-0.5 bg-gray-100 rounded text-[11px] font-mono"
|
||||
>{{ t }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<Badge
|
||||
v-for="t in template.tokens"
|
||||
:key="t"
|
||||
variant="secondary"
|
||||
class="font-mono text-xs"
|
||||
>
|
||||
{{ t }}
|
||||
</Badge>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<aside class="w-full lg:w-72 space-y-6">
|
||||
<div class="bg-white border rounded-lg shadow-sm p-4 space-y-3 text-xs">
|
||||
<h3 class="uppercase font-semibold tracking-wide text-gray-600">
|
||||
Hitra dejanja
|
||||
</h3>
|
||||
<div class="flex flex-col gap-2">
|
||||
<Link
|
||||
:href="route('admin.document-templates.edit', template.id)"
|
||||
:class="[btnBase, btnPrimary]"
|
||||
>Uredi nastavitve</Link
|
||||
>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle class="text-sm">Hitra dejanja</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="flex flex-col gap-2">
|
||||
<Button size="sm" as-child>
|
||||
<Link :href="route('admin.document-templates.edit', template.id)">
|
||||
<PencilIcon class="h-4 w-4 mr-2" />
|
||||
Uredi nastavitve
|
||||
</Link>
|
||||
</Button>
|
||||
<form @submit.prevent="toggleActive">
|
||||
<button
|
||||
<Button
|
||||
type="submit"
|
||||
:class="[btnBase, template.active ? btnWarn : btnOutline]"
|
||||
size="sm"
|
||||
:variant="template.active ? 'destructive' : 'default'"
|
||||
:disabled="toggleForm.processing"
|
||||
class="w-full"
|
||||
>
|
||||
<PowerOffIcon v-if="template.active" class="h-4 w-4 mr-2" />
|
||||
<Power v-else class="h-4 w-4 mr-2" />
|
||||
{{ template.active ? "Deaktiviraj" : "Aktiviraj" }}
|
||||
</button>
|
||||
</Button>
|
||||
</form>
|
||||
<form @submit.prevent="rescan">
|
||||
<button type="submit" :class="[btnBase, btnOutline]" :disabled="rescanForm.processing">
|
||||
<span v-if="rescanForm.processing">Pregledujem…</span>
|
||||
<span v-else>Ponovno preglej tokene</span>
|
||||
</button>
|
||||
</form>
|
||||
<Link
|
||||
:href="route('admin.document-templates.index')"
|
||||
:class="[btnBase, btnOutline]"
|
||||
>Vse predloge</Link
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="bg-white border rounded-lg shadow-sm p-4 space-y-2 text-[11px] text-gray-600"
|
||||
>
|
||||
<h3 class="uppercase font-semibold tracking-wide text-gray-600 text-xs">
|
||||
Opombe
|
||||
</h3>
|
||||
<p>
|
||||
Uporabi to stran za hiter pregled meta podatkov predloge ter njenih tokenov.
|
||||
</p>
|
||||
</div>
|
||||
<form @submit.prevent="rescan">
|
||||
<Button
|
||||
type="submit"
|
||||
size="sm"
|
||||
variant="outline"
|
||||
:disabled="rescanForm.processing"
|
||||
class="w-full"
|
||||
>
|
||||
<RefreshCwIcon class="h-4 w-4 mr-2" />
|
||||
{{ rescanForm.processing ? "Pregledujem…" : "Ponovno preglej tokene" }}
|
||||
</Button>
|
||||
</form>
|
||||
<Button size="sm" variant="outline" as-child>
|
||||
<Link :href="route('admin.document-templates.index')">
|
||||
<ArrowLeftIcon class="h-4 w-4 mr-2" />
|
||||
Vse predloge
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle class="text-sm">Opombe</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="text-sm text-muted-foreground">
|
||||
<p>
|
||||
Uporabi to stran za hiter pregled meta podatkov predloge ter njenih tokenov.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</aside>
|
||||
</div>
|
||||
</AdminLayout>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { Link, useForm } from "@inertiajs/vue3";
|
||||
import AdminLayout from "@/Layouts/AdminLayout.vue";
|
||||
import {
|
||||
FileTextIcon,
|
||||
Power,
|
||||
PowerOffIcon,
|
||||
PencilIcon,
|
||||
ArrowLeftIcon,
|
||||
RefreshCwIcon,
|
||||
DownloadIcon,
|
||||
HashIcon,
|
||||
} from "lucide-vue-next";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/Components/ui/card";
|
||||
import { Button } from "@/Components/ui/button";
|
||||
import { Badge } from "@/Components/ui/badge";
|
||||
import { Separator } from "@/Components/ui/separator";
|
||||
|
||||
// Button style utility classes
|
||||
const btnBase =
|
||||
"inline-flex items-center justify-center gap-1 rounded-md border text-xs font-medium px-3 py-1.5 transition-colors focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-1 disabled:opacity-50 disabled:cursor-not-allowed";
|
||||
const btnPrimary = "bg-indigo-600 border-indigo-600 text-white hover:bg-indigo-500";
|
||||
const btnOutline = "bg-white text-gray-700 border-gray-300 hover:bg-gray-50";
|
||||
const btnWarn = "bg-amber-500 border-amber-500 text-white hover:bg-amber-400";
|
||||
const expandedTokens = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
template: Object,
|
||||
|
||||
Reference in New Issue
Block a user