// API 服務層 - 支援 mock 和真實 API 切換 export class ApiService { constructor(config = {}) { this.baseUrl = config.baseUrl || 'http://localhost:3000/api' this.useMock = config.useMock !== false // 預設使用 mock this.mockDelay = config.mockDelay || 100 // mock 延遲模擬網路請求 } // 通用請求方法 async request(endpoint, options = {}) { if (this.useMock) { return this.mockRequest(endpoint, options) } return this.realRequest(endpoint, options) } // Mock 請求(使用本地資料) async mockRequest(endpoint, options) { await this.delay(this.mockDelay) const [resource, action] = endpoint.split('/').filter(Boolean) switch (`${resource}/${action}`) { case 'pet/state': return this.getMockPetState() case 'pet/update': return this.updateMockPetState(options.body) case 'events/list': return this.getMockEvents() case 'events/trigger': return this.triggerMockEvent(options.body) case 'buffs/apply': return this.applyMockBuff(options.body) case 'deities/list': return this.getMockDeities() case 'deities/pray': return this.mockPrayToDeity(options.body) case 'fortune/draw': return this.mockDrawFortune() case 'temple/throw-jiaobei': return { localFallback: true } // 使用本地邏輯 case 'items/list': return this.getMockItems() case 'items/use': return this.mockUseItem(options.body) case 'pet/save': return this.saveMockPetState(options.body) case 'pet/delete': return this.deleteMockPetState() default: throw new Error(`Unknown endpoint: ${endpoint}`) } } // 真實 API 請求 async realRequest(endpoint, options = {}) { const url = `${this.baseUrl}/${endpoint}` const config = { method: options.method || 'GET', headers: { 'Content-Type': 'application/json', ...options.headers } } if (options.body) { config.body = JSON.stringify(options.body) } const response = await fetch(url, config) if (!response.ok) { throw new Error(`API Error: ${response.status} ${response.statusText}`) } return response.json() } // 延遲模擬 delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)) } // ========== API 端點方法 ========== // 寵物狀態相關 async getPetState() { return this.request('pet/state') } async updatePetState(updates) { return this.request('pet/update', { method: 'POST', body: updates }) } async savePetState(state) { return this.request('pet/save', { method: 'POST', body: state }) } async deletePetState() { return this.request('pet/delete', { method: 'DELETE' }) } // 事件相關 async getEvents() { return this.request('events/list') } async triggerEvent(eventId, petState) { return this.request('events/trigger', { method: 'POST', body: { eventId, petState } }) } // Buff 相關 async applyBuff(buffData) { return this.request('buffs/apply', { method: 'POST', body: buffData }) } // 神明相關 async getDeities() { return this.request('deities/list') } async prayToDeity(deityId, petState) { return this.request('deities/pray', { method: 'POST', body: { deityId, petState } }) } // 籤詩相關 async drawFortune() { return this.request('fortune/draw', { method: 'POST' }) } // 擲筊相關 async throwJiaobei(params) { return this.request('temple/throw-jiaobei', { method: 'POST', body: params }) } // 道具相關 async getItems() { return this.request('items/list') } async useItem(itemId, count = 1) { return this.request('items/use', { method: 'POST', body: { itemId, count } }) } // ========== Mock 資料方法 ========== getMockPetState() { // 從 localStorage 或預設值讀取 const stored = localStorage.getItem('petState') if (stored) { return JSON.parse(stored) } return null } updateMockPetState(updates) { const current = this.getMockPetState() const updated = { ...current, ...updates } localStorage.setItem('petState', JSON.stringify(updated)) return { success: true, data: updated } } saveMockPetState(state) { localStorage.setItem('petState', JSON.stringify(state)) return { success: true, message: '狀態已儲存' } } getMockEvents() { // 動態載入事件配置 return import('../data/events.js').then(m => m.EVENT_CONFIG) } triggerMockEvent({ eventId, petState }) { // 模擬事件觸發邏輯 return { success: true, eventId, effects: [] } } applyMockBuff(buffData) { return { success: true, buff: buffData } } async getMockDeities() { const { DEITIES } = await import('../data/deities.js') return DEITIES } mockPrayToDeity({ deityId, petState }) { return { success: true, favorIncrease: 5, message: '祈福成功' } } mockDrawFortune() { // 模擬抽籤邏輯 const grades = ['上上', '上', '中', '下', '下下'] const weights = [0.05, 0.15, 0.40, 0.30, 0.10] const random = Math.random() let sum = 0 let selectedGrade = '中' for (let i = 0; i < weights.length; i++) { sum += weights[i] if (random <= sum) { selectedGrade = grades[i] break } } return { success: true, lot: { id: Math.floor(Math.random() * 100) + 1, grade: selectedGrade, poem1: '示例籤詩', meaning: '示例解釋' } } } async getMockItems() { const { ITEMS } = await import('../data/items.js') return Object.values(ITEMS) } mockUseItem({ itemId, count }) { return { success: true, itemId, count, effects: {} } } deleteMockPetState() { localStorage.removeItem('petState') return { success: true, message: '寵物已刪除' } } } // 預設實例 export const apiService = new ApiService({ useMock: true, // 開發時使用 mock mockDelay: 100 })