162 lines
7 KiB
Vue
162 lines
7 KiB
Vue
<script setup lang="ts">
|
||
/** FR-9 UI — รายการ template ทั้งหมด (admin): ดู/แก้ไข/activate-deactivate */
|
||
import type { TemplateListItem } from '~/types/api'
|
||
|
||
const { apiJson } = useApi()
|
||
useHead({ title: 'จัดการ template — e-Court Documents Versioning' })
|
||
|
||
const templates = ref<TemplateListItem[]>([])
|
||
const loading = ref(true)
|
||
const error = ref<string | null>(null)
|
||
const showInactive = ref(false)
|
||
const busyId = ref<string | null>(null)
|
||
|
||
async function load() {
|
||
loading.value = true
|
||
error.value = null
|
||
try {
|
||
const qs = showInactive.value ? '?includeInactive=true' : ''
|
||
templates.value = (await apiJson<TemplateListItem[]>(`/api/templates${qs}`)) ?? []
|
||
} catch (err) {
|
||
error.value = err instanceof Error ? err.message : 'โหลดรายการ template ไม่สำเร็จ'
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
/** deactivate = DELETE (soft-delete), activate กลับ = PUT { isActive: true } */
|
||
async function toggleActive(t: TemplateListItem) {
|
||
const verb = t.isActive ? 'deactivate' : 'activate'
|
||
if (!window.confirm(`ยืนยัน${verb === 'deactivate' ? 'การ deactivate' : 'การ activate'} template “${t.name}”?`)) return
|
||
|
||
busyId.value = t.id
|
||
error.value = null
|
||
try {
|
||
if (t.isActive) await apiJson(`/api/templates/${t.id}`, { method: 'DELETE' })
|
||
else await apiJson(`/api/templates/${t.id}`, {
|
||
method: 'PUT',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ isActive: true }),
|
||
})
|
||
await load()
|
||
} catch (err) {
|
||
error.value = err instanceof Error ? err.message : `${verb} ไม่สำเร็จ`
|
||
} finally {
|
||
busyId.value = null
|
||
}
|
||
}
|
||
|
||
watch(showInactive, load)
|
||
onMounted(load)
|
||
</script>
|
||
|
||
<template>
|
||
<AuthGate>
|
||
<section class="space-y-6">
|
||
<div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
||
<div class="min-w-0">
|
||
<h1 class="text-page-title">จัดการ template</h1>
|
||
</div>
|
||
<div class="flex shrink-0 flex-wrap items-center gap-2">
|
||
<NuxtLink to="/templates/new" class="btn btn-primary w-full sm:w-auto">+ สร้าง template ใหม่</NuxtLink>
|
||
</div>
|
||
</div>
|
||
|
||
<label class="flex items-center gap-2 text-sm text-muted">
|
||
<input v-model="showInactive" type="checkbox" class="h-4 w-4 accent-primary" />
|
||
แสดง template ที่ deactivate ไว้ด้วย
|
||
</label>
|
||
|
||
<div v-if="loading" class="flex items-center gap-3 py-10 text-sm text-muted">
|
||
<span class="spinner" />
|
||
กำลังโหลด…
|
||
</div>
|
||
|
||
<AlertBox v-else-if="error" type="error">{{ error }}</AlertBox>
|
||
|
||
<div v-else-if="templates.length === 0" class="empty-state">
|
||
ยังไม่มี template{{ showInactive ? ' เลย' : 'ที่ active' }} —
|
||
<NuxtLink to="/templates/new" class="link">สร้าง template แรก</NuxtLink>
|
||
</div>
|
||
|
||
<template v-else>
|
||
<!-- มือถือ: card list -->
|
||
<ul class="space-y-3 md:hidden">
|
||
<li v-for="t in templates" :key="t.id" class="card space-y-3 p-4">
|
||
<div class="flex items-start justify-between gap-3">
|
||
<NuxtLink :to="`/templates/${t.id}/edit`" class="link min-w-0 break-words font-semibold">
|
||
{{ t.name }}
|
||
</NuxtLink>
|
||
<span v-if="t.isActive" class="badge badge-success shrink-0">active</span>
|
||
<span v-else class="badge badge-neutral shrink-0">deactivated</span>
|
||
</div>
|
||
<p class="line-clamp-2 text-sm text-muted">{{ t.description ?? '—' }}</p>
|
||
<p class="text-xs text-muted">
|
||
{{ t.fieldCount }} fields · อัปเดต {{ formatDateTime(t.updatedAt) }}
|
||
</p>
|
||
<div class="flex flex-wrap gap-2">
|
||
<NuxtLink :to="`/templates/${t.id}/documents`" class="btn btn-secondary btn-xs">เอกสาร</NuxtLink>
|
||
<NuxtLink :to="`/templates/${t.id}/edit`" class="btn btn-secondary btn-xs">แก้ไข</NuxtLink>
|
||
<button
|
||
type="button"
|
||
:disabled="busyId === t.id"
|
||
class="btn btn-xs"
|
||
:class="t.isActive ? 'btn-outline-danger' : 'btn-outline-success'"
|
||
@click="toggleActive(t)"
|
||
>
|
||
{{ busyId === t.id ? '…' : t.isActive ? 'deactivate' : 'activate' }}
|
||
</button>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
|
||
<!-- desktop: ตาราง -->
|
||
<div class="table-card hidden md:block">
|
||
<table class="w-full text-sm">
|
||
<thead class="table-head">
|
||
<tr>
|
||
<th class="px-4 py-3">ชื่อ</th>
|
||
<th class="px-4 py-3">คำอธิบาย</th>
|
||
<th class="px-4 py-3 text-center">fields</th>
|
||
<th class="px-4 py-3">สถานะ</th>
|
||
<th class="px-4 py-3">อัปเดตล่าสุด</th>
|
||
<th class="px-4 py-3 text-right">การกระทำ</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody class="divide-y divide-line">
|
||
<tr v-for="t in templates" :key="t.id" class="align-top">
|
||
<td class="px-4 py-3 font-medium">
|
||
<NuxtLink :to="`/templates/${t.id}/edit`" class="link">{{ t.name }}</NuxtLink>
|
||
</td>
|
||
<td class="max-w-60 px-4 py-3 text-muted">{{ t.description ?? '—' }}</td>
|
||
<td class="px-4 py-3 text-center">{{ t.fieldCount }}</td>
|
||
<td class="px-4 py-3">
|
||
<span v-if="t.isActive" class="badge badge-success">active</span>
|
||
<span v-else class="badge badge-neutral">deactivated</span>
|
||
</td>
|
||
<td class="px-4 py-3 text-muted">{{ formatDateTime(t.updatedAt) }}</td>
|
||
<td class="whitespace-nowrap px-4 py-3 text-right">
|
||
<NuxtLink :to="`/templates/${t.id}/documents`" class="btn btn-secondary btn-xs">เอกสาร</NuxtLink>
|
||
<NuxtLink :to="`/templates/${t.id}/edit`" class="btn btn-secondary btn-xs ml-2">แก้ไข</NuxtLink>
|
||
<button
|
||
type="button"
|
||
:disabled="busyId === t.id"
|
||
class="btn btn-xs ml-2"
|
||
:class="t.isActive ? 'btn-outline-danger' : 'btn-outline-success'"
|
||
@click="toggleActive(t)"
|
||
>
|
||
{{ busyId === t.id ? '…' : t.isActive ? 'deactivate' : 'activate' }}
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</template>
|
||
|
||
<p class="text-xs text-muted">
|
||
การ deactivate เป็น soft-delete — เอกสารที่สร้างจาก template นั้นไปแล้วยังใช้งานต่อได้ตามปกติ
|
||
</p>
|
||
</section>
|
||
</AuthGate>
|
||
</template>
|