2026-08-20 06:20:16 +07:00
|
|
|
<script setup lang="ts">
|
|
|
|
|
/** FR-9 UI — upload template ใหม่: ระบบ detect fields (SDT tags) จากไฟล์ให้อัตโนมัติ */
|
|
|
|
|
import type { CreateTemplateResponse } from '~/types/api'
|
|
|
|
|
|
|
|
|
|
const { apiUpload } = useApi()
|
|
|
|
|
useHead({ title: 'สร้าง template ใหม่ — e-Court Documents Versioning' })
|
|
|
|
|
|
|
|
|
|
const name = ref('')
|
|
|
|
|
const description = ref('')
|
|
|
|
|
const file = ref<File | null>(null)
|
|
|
|
|
const fileInput = ref<HTMLInputElement | null>(null)
|
|
|
|
|
|
|
|
|
|
const submitting = ref(false)
|
|
|
|
|
const error = ref<string | null>(null)
|
|
|
|
|
const created = ref<CreateTemplateResponse | null>(null)
|
|
|
|
|
|
|
|
|
|
function onFileChange(e: Event) {
|
|
|
|
|
const input = e.target as HTMLInputElement
|
|
|
|
|
file.value = input.files?.[0] ?? null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function submit() {
|
|
|
|
|
error.value = null
|
|
|
|
|
if (!name.value.trim()) {
|
|
|
|
|
error.value = 'กรอกชื่อ template ด้วย'
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (!file.value) {
|
|
|
|
|
error.value = 'เลือกไฟล์ .docx ของ template ด้วย'
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (!file.value.name.toLowerCase().endsWith('.docx')) {
|
|
|
|
|
error.value = 'รองรับเฉพาะไฟล์ .docx เท่านั้น'
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const form = new FormData()
|
|
|
|
|
form.append('name', name.value.trim())
|
|
|
|
|
if (description.value.trim()) form.append('description', description.value.trim())
|
|
|
|
|
form.append('file', file.value)
|
|
|
|
|
|
|
|
|
|
submitting.value = true
|
|
|
|
|
try {
|
|
|
|
|
created.value = await apiUpload<CreateTemplateResponse>('/api/templates', form)
|
|
|
|
|
} catch (err) {
|
|
|
|
|
error.value = err instanceof Error ? err.message : 'อัปโหลด template ไม่สำเร็จ'
|
|
|
|
|
} finally {
|
|
|
|
|
submitting.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** เคลียร์ฟอร์มเพื่ออัปโหลดไฟล์ถัดไป */
|
|
|
|
|
function resetForm() {
|
|
|
|
|
created.value = null
|
|
|
|
|
name.value = ''
|
|
|
|
|
description.value = ''
|
|
|
|
|
file.value = null
|
|
|
|
|
if (fileInput.value) fileInput.value.value = ''
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<AuthGate>
|
2026-08-20 21:34:45 +07:00
|
|
|
<section class="mx-auto max-w-xl space-y-6">
|
|
|
|
|
<h1 class="text-page-title">สร้าง template ใหม่</h1>
|
2026-08-20 06:20:16 +07:00
|
|
|
|
|
|
|
|
<!-- ผลลัพธ์หลังอัปโหลดสำเร็จ: field list ที่ detect ได้จากไฟล์ -->
|
|
|
|
|
<template v-if="created">
|
|
|
|
|
<AlertBox type="success">
|
|
|
|
|
อัปโหลดสำเร็จ — ตรวจพบ <strong>{{ created.fields.length }}</strong> fields จากไฟล์
|
|
|
|
|
</AlertBox>
|
|
|
|
|
|
2026-08-20 21:34:45 +07:00
|
|
|
<!-- มือถือ: card list -->
|
|
|
|
|
<ul class="space-y-3 md:hidden">
|
|
|
|
|
<li v-for="f in created.fields" :key="f.key" class="card space-y-1 p-4">
|
|
|
|
|
<p class="font-mono text-xs text-muted">{{ f.key }}</p>
|
|
|
|
|
<p class="text-sm font-medium">{{ f.label }}</p>
|
|
|
|
|
<p class="text-xs text-muted">type: {{ f.type }}</p>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
<!-- desktop: ตาราง -->
|
|
|
|
|
<div class="table-card hidden md:block">
|
2026-08-20 06:20:16 +07:00
|
|
|
<table class="w-full text-sm">
|
2026-08-20 21:34:45 +07:00
|
|
|
<thead class="table-head">
|
2026-08-20 06:20:16 +07:00
|
|
|
<tr>
|
|
|
|
|
<th class="px-4 py-3">key (SDT tag)</th>
|
|
|
|
|
<th class="px-4 py-3">label เริ่มต้น</th>
|
|
|
|
|
<th class="px-4 py-3">type เริ่มต้น</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
2026-08-20 21:34:45 +07:00
|
|
|
<tbody class="divide-y divide-line">
|
2026-08-20 06:20:16 +07:00
|
|
|
<tr v-for="f in created.fields" :key="f.key">
|
|
|
|
|
<td class="px-4 py-2 font-mono text-xs">{{ f.key }}</td>
|
|
|
|
|
<td class="px-4 py-2">{{ f.label }}</td>
|
|
|
|
|
<td class="px-4 py-2">{{ f.type }}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-08-20 21:34:45 +07:00
|
|
|
<div class="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
|
|
|
|
|
<button type="button" class="btn btn-secondary w-full sm:w-auto" @click="resetForm">
|
2026-08-20 06:20:16 +07:00
|
|
|
อัปโหลดอีกไฟล์
|
|
|
|
|
</button>
|
2026-08-20 21:34:45 +07:00
|
|
|
<NuxtLink :to="`/templates/${created.id}/edit`" class="btn btn-primary w-full sm:w-auto">
|
2026-08-22 09:17:15 +07:00
|
|
|
ตั้งค่า label/type/editor/required ต่อ →
|
2026-08-20 21:34:45 +07:00
|
|
|
</NuxtLink>
|
2026-08-20 06:20:16 +07:00
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<form v-else class="space-y-4" @submit.prevent="submit">
|
|
|
|
|
<AlertBox v-if="error" type="error">{{ error }}</AlertBox>
|
|
|
|
|
|
|
|
|
|
<div>
|
2026-08-20 21:34:45 +07:00
|
|
|
<label for="tpl-name" class="label">ชื่อ template <span class="text-error-strong">*</span></label>
|
2026-08-20 06:20:16 +07:00
|
|
|
<input
|
|
|
|
|
id="tpl-name"
|
|
|
|
|
v-model="name"
|
|
|
|
|
type="text"
|
|
|
|
|
required
|
|
|
|
|
placeholder="เช่น สัญญาจ้างงาน"
|
2026-08-20 21:34:45 +07:00
|
|
|
class="input"
|
2026-08-20 06:20:16 +07:00
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div>
|
2026-08-20 21:34:45 +07:00
|
|
|
<label for="tpl-desc" class="label">คำอธิบาย</label>
|
2026-08-20 06:20:16 +07:00
|
|
|
<textarea
|
|
|
|
|
id="tpl-desc"
|
|
|
|
|
v-model="description"
|
|
|
|
|
rows="2"
|
|
|
|
|
placeholder="คำอธิบายสั้นๆ ว่าเอกสารนี้ใช้ทำอะไร"
|
2026-08-20 21:34:45 +07:00
|
|
|
class="input"
|
2026-08-20 06:20:16 +07:00
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div>
|
2026-08-20 21:34:45 +07:00
|
|
|
<label for="tpl-file" class="label">ไฟล์ template (.docx) <span class="text-error-strong">*</span></label>
|
2026-08-20 06:20:16 +07:00
|
|
|
<input
|
|
|
|
|
id="tpl-file"
|
|
|
|
|
ref="fileInput"
|
|
|
|
|
type="file"
|
|
|
|
|
accept=".docx"
|
|
|
|
|
required
|
2026-08-20 21:34:45 +07:00
|
|
|
class="input file:mr-3 file:rounded-pill file:border-0 file:bg-surface-muted file:px-3 file:py-1 file:text-sm file:font-medium"
|
2026-08-20 06:20:16 +07:00
|
|
|
@change="onFileChange"
|
|
|
|
|
/>
|
2026-08-20 21:34:45 +07:00
|
|
|
<p class="mt-1 text-xs text-muted">
|
2026-08-20 06:20:16 +07:00
|
|
|
สร้างไฟล์ด้วย Word แล้วใส่
|
|
|
|
|
<strong>Content Controls</strong> (Developer → Rich Text/Plain Text Control) โดยตั้งค่า
|
|
|
|
|
<span class="font-mono">Tag</span> ของแต่ละ control เป็น field key — ระบบจะ detect tags
|
|
|
|
|
ออกมาเป็นรายการ fields ให้อัตโนมัติ
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-08-20 21:34:45 +07:00
|
|
|
<div class="flex flex-col-reverse gap-2 pt-2 sm:flex-row sm:justify-end">
|
|
|
|
|
<button type="submit" :disabled="submitting" class="btn btn-primary w-full sm:w-auto">
|
|
|
|
|
{{ submitting ? 'กำลังอัปโหลด…' : 'อัปโหลด template' }}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
2026-08-20 06:20:16 +07:00
|
|
|
</form>
|
|
|
|
|
</section>
|
|
|
|
|
</AuthGate>
|
|
|
|
|
</template>
|