2026-01-17 11:41:46 +07:00
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { ref, onMounted } from 'vue'
|
|
|
|
|
import { useRouter } from 'vue-router'
|
|
|
|
|
|
|
|
|
|
const router = useRouter()
|
|
|
|
|
const countdown = ref(3)
|
|
|
|
|
const showResult = ref(false)
|
|
|
|
|
const photos = ref<string[]>([])
|
|
|
|
|
const layout = ref<'1x4' | '2x2'>('1x4')
|
|
|
|
|
const frame = ref<number>(0)
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
// โหลดข้อมูลจาก localStorage
|
|
|
|
|
const savedPhotos = localStorage.getItem('photobooth-photos')
|
|
|
|
|
const savedLayout = localStorage.getItem('photobooth-layout')
|
|
|
|
|
const savedFrame = localStorage.getItem('photobooth-frame')
|
|
|
|
|
|
|
|
|
|
if (savedPhotos) {
|
|
|
|
|
photos.value = JSON.parse(savedPhotos)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (savedLayout) {
|
|
|
|
|
layout.value = savedLayout as '1x4' | '2x2'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (savedFrame) {
|
|
|
|
|
frame.value = parseInt(savedFrame)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// เริ่มนับถอยหลัง
|
|
|
|
|
startCountdown()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const startCountdown = () => {
|
|
|
|
|
const timer = setInterval(() => {
|
|
|
|
|
countdown.value--
|
|
|
|
|
if (countdown.value <= 0) {
|
|
|
|
|
clearInterval(timer)
|
|
|
|
|
showResult.value = true
|
|
|
|
|
|
|
|
|
|
// หลังจากแสดงผล 3 วินาที ให้ไปหน้า pickup
|
|
|
|
|
setTimeout(() => {
|
2026-01-18 00:52:50 +07:00
|
|
|
// router.push('/pickup')
|
2026-01-17 11:41:46 +07:00
|
|
|
}, 3000)
|
|
|
|
|
}
|
|
|
|
|
}, 1000)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getGridStyle = () => {
|
|
|
|
|
if (layout.value === '1x4') {
|
|
|
|
|
return {
|
|
|
|
|
display: 'grid',
|
|
|
|
|
gridTemplateColumns: '1fr',
|
|
|
|
|
gridTemplateRows: 'repeat(4, 1fr)',
|
2026-01-17 13:20:17 +07:00
|
|
|
gap: '8px',
|
|
|
|
|
aspectRatio: '1/5' // ทำให้แต่ละภาพยาวขึ้น (1:2 aspect ratio รวม)
|
2026-01-17 11:41:46 +07:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return {
|
|
|
|
|
display: 'grid',
|
|
|
|
|
gridTemplateColumns: 'repeat(2, 1fr)',
|
|
|
|
|
gridTemplateRows: 'repeat(2, 1fr)',
|
2026-01-17 13:20:17 +07:00
|
|
|
gap: '8px',
|
|
|
|
|
aspectRatio: '1/1' // 2x2 เป็น square
|
2026-01-17 11:41:46 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<div class="print-container">
|
|
|
|
|
<div v-if="!showResult" class="countdown-section">
|
|
|
|
|
<div class="countdown-display">
|
|
|
|
|
<div class="countdown-number">{{ countdown }}</div>
|
|
|
|
|
<div class="processing-text">กำลังประมวลผล...</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="progress-bar">
|
|
|
|
|
<div class="progress-fill" :style="{ width: `${((4 - countdown) / 4) * 100}%` }"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-else class="result-section">
|
|
|
|
|
<div class="result-header">
|
|
|
|
|
<h1>เสร็จแล้ว!</h1>
|
|
|
|
|
<p>กำลังเตรียมไฟล์สำหรับดาวน์โหลด...</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="photo-result">
|
|
|
|
|
<div class="photo-frame" :class="`frame-${frame}`">
|
|
|
|
|
<div class="photo-grid" :style="getGridStyle()">
|
|
|
|
|
<div
|
|
|
|
|
v-for="(photo, index) in photos"
|
|
|
|
|
:key="index"
|
|
|
|
|
class="photo-cell"
|
|
|
|
|
>
|
|
|
|
|
<img :src="photo" :alt="`Photo ${index + 1}`" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="loading-indicator">
|
|
|
|
|
<div class="spinner"></div>
|
|
|
|
|
<span>กำลังสร้างไฟล์...</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.print-container {
|
|
|
|
|
min-height: 100vh;
|
|
|
|
|
background: #000;
|
|
|
|
|
color: white;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
padding: 2rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.countdown-section {
|
|
|
|
|
text-align: center;
|
|
|
|
|
animation: fadeIn 0.5s ease-in-out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.countdown-display {
|
|
|
|
|
margin-bottom: 2rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.countdown-number {
|
|
|
|
|
font-size: 8rem;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #ff6b6b;
|
|
|
|
|
margin-bottom: 1rem;
|
|
|
|
|
animation: scalePulse 1s ease-in-out infinite;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.processing-text {
|
|
|
|
|
font-size: 1.5rem;
|
|
|
|
|
color: #ccc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.progress-bar {
|
|
|
|
|
width: 300px;
|
|
|
|
|
height: 8px;
|
|
|
|
|
background: rgba(255,255,255,0.2);
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.progress-fill {
|
|
|
|
|
height: 100%;
|
|
|
|
|
background: linear-gradient(90deg, #ff6b6b, #4ecdc4);
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
transition: width 1s ease-in-out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.result-section {
|
|
|
|
|
text-align: center;
|
|
|
|
|
animation: slideUp 0.8s ease-out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.result-header h1 {
|
|
|
|
|
font-size: 3rem;
|
|
|
|
|
margin-bottom: 0.5rem;
|
|
|
|
|
background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
|
|
|
|
|
-webkit-background-clip: text;
|
|
|
|
|
-webkit-text-fill-color: transparent;
|
|
|
|
|
background-clip: text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.result-header p {
|
|
|
|
|
font-size: 1.2rem;
|
|
|
|
|
color: #ccc;
|
|
|
|
|
margin-bottom: 2rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.photo-result {
|
|
|
|
|
margin: 2rem 0;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.photo-frame {
|
|
|
|
|
background: white;
|
|
|
|
|
padding: 20px;
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
box-shadow: 0 8px 32px rgba(255,255,255,0.1);
|
|
|
|
|
max-width: 400px;
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.photo-grid {
|
|
|
|
|
background: #f8f9fa;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
padding: 12px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.photo-cell {
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.photo-cell img {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
display: block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loading-indicator {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
gap: 1rem;
|
|
|
|
|
margin-top: 2rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.spinner {
|
|
|
|
|
width: 24px;
|
|
|
|
|
height: 24px;
|
|
|
|
|
border: 3px solid rgba(255,255,255,0.3);
|
|
|
|
|
border-top: 3px solid #ff6b6b;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
animation: spin 1s linear infinite;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loading-indicator span {
|
|
|
|
|
color: #ccc;
|
|
|
|
|
font-size: 1.1rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes fadeIn {
|
|
|
|
|
from { opacity: 0; }
|
|
|
|
|
to { opacity: 1; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes scalePulse {
|
|
|
|
|
0%, 100% { transform: scale(1); }
|
|
|
|
|
50% { transform: scale(1.1); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes slideUp {
|
|
|
|
|
from {
|
|
|
|
|
opacity: 0;
|
|
|
|
|
transform: translateY(50px);
|
|
|
|
|
}
|
|
|
|
|
to {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
transform: translateY(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@keyframes spin {
|
|
|
|
|
0% { transform: rotate(0deg); }
|
|
|
|
|
100% { transform: rotate(360deg); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Frame styles */
|
|
|
|
|
.frame-0 {
|
|
|
|
|
/* Classic frame - default white */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.frame-1 {
|
|
|
|
|
/* Modern frame */
|
|
|
|
|
background: linear-gradient(45deg, #667eea, #764ba2);
|
|
|
|
|
color: white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.frame-2 {
|
|
|
|
|
/* Vintage frame */
|
|
|
|
|
background: linear-gradient(45deg, #f093fb, #f5576c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.frame-3 {
|
|
|
|
|
/* Colorful frame */
|
|
|
|
|
background: linear-gradient(45deg, #4facfe, #00f2fe);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.frame-4 {
|
|
|
|
|
/* Minimal frame */
|
|
|
|
|
background: #f8f9fa;
|
|
|
|
|
border: 2px solid #dee2e6;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 768px) {
|
|
|
|
|
.countdown-number {
|
|
|
|
|
font-size: 6rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.result-header h1 {
|
|
|
|
|
font-size: 2rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.photo-frame {
|
|
|
|
|
max-width: 300px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|