/** * @interface Category * @description โครงสร้างข้อมูลหมวดหมู่ (Category) */ export interface Category { id: number name: { // ชื่อหมวดหมู่รองรับ 2 ภาษา th: string en: string [key: string]: string } slug: string // Slug สำหรับใช้งานบน URL description: { // รายละเอียดหมวดหมู่ th: string en: string [key: string]: string } icon: string // ไอคอนของหมวดหมู่อ้างอิงจาก Material Icons sort_order: number is_active: boolean created_at: string updated_at: string } export interface CategoryData { total: number // จำนวนหมวดหมู่ทั้งหมด categories: Category[] } interface CategoryResponse { code: number message: string data: CategoryData } /** * @composable useCategory * @description จัดการข้อมูลหมวดหมู่ (Categories) การดึงข้อมูล และการจัดการ Cache (เก็บข้อมูลจำลองชั่วคราว) */ export const useCategory = () => { const config = useRuntimeConfig() const API_BASE_URL = config.public.apiBase as string const { token } = useAuth() // เก็บ Cache การดึงข้อมูลหมวดหมู่ในระดับ Global (ใช้ข้าม Component ได้โดยไม่ต้องโหลดใหม่) const categoriesState = useState('categories_cache', () => []) const isLoaded = useState('categories_loaded', () => false) /** * @function fetchCategories * @description ดึงรายการหมวดหมู่ทั้งหมดจาก API (GET /categories) * หากมีแคชอยู่แล้วจะดึงจาก State ทันที แต่อาจบังคับให้โหลดใหม่ (forceRefresh) ได้ */ const fetchCategories = async (forceRefresh = false) => { // ถ้ามีข้อมูลอยู่แล้วและไม่สั่งบังคับโหลดใหม่ ให้ใช้ข้อมูลเดิมทันที if (isLoaded.value && !forceRefresh && categoriesState.value.length > 0) { return { success: true, data: categoriesState.value, total: categoriesState.value.length } } try { const response = await $fetch(`${API_BASE_URL}/categories`, { method: 'GET', headers: token.value ? { Authorization: `Bearer ${token.value}` } : {} }) const categories = response.data?.categories || [] // บันทึกรายการหมวดหมู่ลง State Cache categoriesState.value = categories isLoaded.value = true return { success: true, data: categories, total: response.data?.total || 0 } } catch (err: any) { console.error('Fetch categories failed:', err) // กรณีเกิด Error 429 ระบบจะทำการหน่วงเวลา (1.5 วิ) และลองโหลดข้อมูลใหม่อีก 1 ครั้ง (Retry) if (err.statusCode === 429 || err.status === 429) { await new Promise(resolve => setTimeout(resolve, 1500)); // หน่วงเวลา 1.5 วินาที try { const retryRes = await $fetch(`${API_BASE_URL}/categories`, { method: 'GET', headers: token.value ? { Authorization: `Bearer ${token.value}` } : {} }) const cats = retryRes.data?.categories || [] categoriesState.value = cats isLoaded.value = true return { success: true, data: cats, total: retryRes.data?.total || 0 } } catch (retryErr) { console.error('Retry fetch categories failed:', retryErr) } } return { success: false, error: err.data?.message || err.message || 'Error fetching categories' } } } return { fetchCategories, categories: computed(() => categoriesState.value) // ส่งข้อมูลออกมาเป็น Computed เพื่อให้ UI อัปเดตตามอัตโนมัติ } }