/** * Drama Ling - 模擬數據 * 開發和測試用的模擬數據集 */ /** * 模擬用戶數據 */ export const mockUsers = [ { id: 'user_001', email: 'demo@dramaling.com', name: '張小明', avatar: '/assets/media/images/avatar-1.png', level: '中級', joinDate: '2024-01-15', preferences: { language: 'zh-TW', theme: 'auto', soundEnabled: true, notificationsEnabled: true } }, { id: 'user_002', email: 'sarah@example.com', name: 'Sarah Chen', avatar: '/assets/media/images/avatar-2.png', level: '高級', joinDate: '2023-11-20', preferences: { language: 'zh-TW', theme: 'light', soundEnabled: false, notificationsEnabled: true } } ]; /** * 模擬用戶統計數據 */ export const mockUserStats = { totalWords: 1247, studyTime: 45, // 小時 achievements: 12, streak: 7, // 連續學習天數 diamonds: 2580, weeklyGoal: 5, // 每週學習時數目標 weeklyProgress: 3.5, // 本週已完成時數 levelProgress: 78, // 等級進度百分比 accuracy: 85, // 整體答題準確率 strongCategories: ['商務', '旅遊', '日常對話'], weakCategories: ['科技', '醫療'] }; /** * 模擬詞彙數據 */ export const mockVocabulary = [ { id: 'vocab_001', word: 'appreciate', definition: '感激;欣賞;理解', pronunciation: '/əˈpriːʃieɪt/', difficulty: 'intermediate', category: 'business', examples: [ { english: 'I appreciate your hard work.', chinese: '我很感激你的辛勤工作。' }, { english: 'Do you appreciate classical music?', chinese: '你欣賞古典音樂嗎?' } ], audioUrl: '/assets/media/audio/appreciate.mp3', imageUrl: '/assets/media/images/appreciate.jpg', tags: ['emotion', 'business', 'common'], addedDate: '2024-09-01', masteryLevel: 0.8, // 0-1,掌握程度 reviewCount: 5, correctCount: 4, lastReviewed: '2024-09-09' }, { id: 'vocab_002', word: 'definitely', definition: '當然;肯定地', pronunciation: '/ˈdefɪnətli/', difficulty: 'beginner', category: 'daily', examples: [ { english: 'I will definitely come to your party.', chinese: '我一定會參加你的派對。' }, { english: 'That was definitely the best movie I\'ve seen.', chinese: '那絕對是我看過最好的電影。' } ], audioUrl: '/assets/media/audio/definitely.mp3', imageUrl: '/assets/media/images/definitely.jpg', tags: ['adverb', 'confirmation', 'common'], addedDate: '2024-08-28', masteryLevel: 0.95, reviewCount: 8, correctCount: 8, lastReviewed: '2024-09-08' }, { id: 'vocab_003', word: 'entrepreneur', definition: '企業家;創業者', pronunciation: '/ˌɒntrəprəˈnɜː(r)/', difficulty: 'advanced', category: 'business', examples: [ { english: 'She is a successful entrepreneur.', chinese: '她是一位成功的企業家。' }, { english: 'Many entrepreneurs start with small businesses.', chinese: '許多企業家都是從小企業開始的。' } ], audioUrl: '/assets/media/audio/entrepreneur.mp3', imageUrl: '/assets/media/images/entrepreneur.jpg', tags: ['business', 'career', 'advanced'], addedDate: '2024-09-05', masteryLevel: 0.4, reviewCount: 2, correctCount: 1, lastReviewed: '2024-09-07' } ]; /** * 模擬對話場景數據 */ export const mockDialogues = [ { id: 'dialogue_001', title: '餐廳點餐', category: 'restaurant', difficulty: 'beginner', description: '在餐廳與服務生的基本對話練習', estimatedTime: 5, // 分鐘 thumbnail: '/assets/media/images/restaurant-scene.jpg', characters: [ { id: 'customer', name: '顧客', avatar: '/assets/media/images/customer-avatar.png' }, { id: 'waiter', name: '服務生', avatar: '/assets/media/images/waiter-avatar.png', isAI: true } ], conversation: [ { speaker: 'waiter', text: 'Good evening! Welcome to our restaurant. How many people?', chinese: '晚安!歡迎來到我們餐廳。請問幾位?', audioUrl: '/assets/media/audio/dialogue_001_01.mp3' }, { speaker: 'customer', text: 'Table for two, please.', chinese: '請給我們兩人桌。', audioUrl: '/assets/media/audio/dialogue_001_02.mp3', isUserResponse: true, alternatives: [ 'Two people, please.', 'A table for two.', 'Party of two.' ] }, { speaker: 'waiter', text: 'Perfect! Right this way, please. Here are your menus.', chinese: '很好!請這邊走。這是菜單。', audioUrl: '/assets/media/audio/dialogue_001_03.mp3' } ], completedBy: 1250, // 完成人數 rating: 4.8, tags: ['restaurant', 'basic', 'ordering'] }, { id: 'dialogue_002', title: '機場報到', category: 'travel', difficulty: 'intermediate', description: '在機場辦理登機手續的對話', estimatedTime: 8, thumbnail: '/assets/media/images/airport-scene.jpg', characters: [ { id: 'passenger', name: '乘客', avatar: '/assets/media/images/passenger-avatar.png' }, { id: 'checkin_agent', name: '報到人員', avatar: '/assets/media/images/agent-avatar.png', isAI: true } ], conversation: [ { speaker: 'checkin_agent', text: 'Good morning! May I have your passport and ticket, please?', chinese: '早安!請出示您的護照和機票。', audioUrl: '/assets/media/audio/dialogue_002_01.mp3' }, { speaker: 'passenger', text: 'Here you go.', chinese: '給您。', audioUrl: '/assets/media/audio/dialogue_002_02.mp3', isUserResponse: true, alternatives: [ 'Here they are.', 'Sure, here you are.', 'Of course.' ] } ], completedBy: 890, rating: 4.6, tags: ['travel', 'airport', 'procedures'] } ]; /** * 模擬學習進度數據 */ export const mockLearningProgress = { dailyStats: [ { date: '2024-09-03', wordsLearned: 15, timeSpent: 25, accuracy: 82 }, { date: '2024-09-04', wordsLearned: 12, timeSpent: 30, accuracy: 88 }, { date: '2024-09-05', wordsLearned: 18, timeSpent: 35, accuracy: 75 }, { date: '2024-09-06', wordsLearned: 20, timeSpent: 40, accuracy: 90 }, { date: '2024-09-07', wordsLearned: 16, timeSpent: 28, accuracy: 85 }, { date: '2024-09-08', wordsLearned: 14, timeSpent: 32, accuracy: 87 }, { date: '2024-09-09', wordsLearned: 22, timeSpent: 45, accuracy: 92 } ], weeklyGoals: { wordsTarget: 100, timeTarget: 5 * 60, // 5小時,以分鐘為單位 currentWords: 117, currentTime: 235 // 分鐘 }, categoryProgress: { business: { total: 150, mastered: 120, learning: 25, difficult: 5 }, daily: { total: 200, mastered: 180, learning: 15, difficult: 5 }, travel: { total: 80, mastered: 60, learning: 15, difficult: 5 }, technology: { total: 100, mastered: 45, learning: 30, difficult: 25 } }, achievements: [ { id: 'first_week', title: '初次體驗', description: '完成第一週學習', icon: '🎯', unlockedDate: '2024-01-22', rarity: 'common' }, { id: 'streak_7', title: '七日連勝', description: '連續學習7天', icon: '🔥', unlockedDate: '2024-02-01', rarity: 'rare' }, { id: 'words_1000', title: '詞彙大師', description: '學習1000個詞彙', icon: '📚', unlockedDate: '2024-08-15', rarity: 'epic' } ] }; /** * 模擬系統設定數據 */ export const mockSystemSettings = { themes: [ { id: 'auto', name: '自動', description: '跟隨系統設定' }, { id: 'light', name: '淺色', description: '淺色主題' }, { id: 'dark', name: '深色', description: '深色主題' } ], languages: [ { id: 'zh-TW', name: '繁體中文', flag: '🇹🇼' }, { id: 'zh-CN', name: '简体中文', flag: '🇨🇳' }, { id: 'en-US', name: 'English', flag: '🇺🇸' }, { id: 'ja-JP', name: '日本語', flag: '🇯🇵' } ], notificationTypes: [ { id: 'daily_reminder', name: '每日提醒', description: '提醒您每天學習' }, { id: 'streak_warning', name: '連勝警告', description: '連勝即將中斷時提醒' }, { id: 'achievement', name: '成就通知', description: '獲得新成就時通知' }, { id: 'weekly_report', name: '週報', description: '每週學習報告' } ] }; /** * 模擬 API 響應數據 */ export const mockApiResponses = { login: { success: { token: 'mock_jwt_token_12345', user: mockUsers[0], expiresIn: 86400 // 24小時 }, error: { message: '帳號或密碼錯誤', code: 'INVALID_CREDENTIALS' } }, getUserStats: { success: mockUserStats, error: { message: '無法載入用戶統計', code: 'STATS_LOAD_ERROR' } }, getVocabulary: { success: { data: mockVocabulary, total: mockVocabulary.length, page: 1, limit: 20 }, error: { message: '無法載入詞彙數據', code: 'VOCABULARY_LOAD_ERROR' } }, getDialogues: { success: { data: mockDialogues, total: mockDialogues.length, page: 1, limit: 10 }, error: { message: '無法載入對話數據', code: 'DIALOGUE_LOAD_ERROR' } } }; /** * 模擬 API 客戶端 * 用於開發環境的 API 模擬 */ export class MockApiClient { constructor() { this.delay = 300; // 模擬網路延遲 this.failureRate = 0.1; // 10% 機率失敗 } /** * 模擬 API 延遲 */ async simulateDelay() { return new Promise(resolve => { setTimeout(resolve, this.delay); }); } /** * 模擬隨機失敗 */ simulateRandomFailure() { return Math.random() < this.failureRate; } /** * 用戶登入 */ async login(email, password) { await this.simulateDelay(); if (this.simulateRandomFailure()) { throw new Error(mockApiResponses.login.error.message); } // 簡單的驗證邏輯 if (email === 'demo@dramaling.com' && password === 'password') { return mockApiResponses.login.success; } else { throw new Error(mockApiResponses.login.error.message); } } /** * 獲取用戶統計 */ async getUserStats() { await this.simulateDelay(); if (this.simulateRandomFailure()) { throw new Error(mockApiResponses.getUserStats.error.message); } return mockApiResponses.getUserStats.success; } /** * 獲取詞彙列表 */ async getVocabulary(params = {}) { await this.simulateDelay(); if (this.simulateRandomFailure()) { throw new Error(mockApiResponses.getVocabulary.error.message); } let filteredVocabulary = [...mockVocabulary]; // 模擬過濾和排序 if (params.category) { filteredVocabulary = filteredVocabulary.filter( vocab => vocab.category === params.category ); } if (params.difficulty) { filteredVocabulary = filteredVocabulary.filter( vocab => vocab.difficulty === params.difficulty ); } return { data: filteredVocabulary, total: filteredVocabulary.length, page: params.page || 1, limit: params.limit || 20 }; } /** * 獲取對話場景 */ async getDialogues(params = {}) { await this.simulateDelay(); if (this.simulateRandomFailure()) { throw new Error(mockApiResponses.getDialogues.error.message); } let filteredDialogues = [...mockDialogues]; if (params.category) { filteredDialogues = filteredDialogues.filter( dialogue => dialogue.category === params.category ); } if (params.difficulty) { filteredDialogues = filteredDialogues.filter( dialogue => dialogue.difficulty === params.difficulty ); } return { data: filteredDialogues, total: filteredDialogues.length, page: params.page || 1, limit: params.limit || 10 }; } /** * 獲取學習進度 */ async getLearningProgress() { await this.simulateDelay(); if (this.simulateRandomFailure()) { throw new Error('無法載入學習進度'); } return mockLearningProgress; } /** * 獲取當前用戶 */ async getCurrentUser() { await this.simulateDelay(); if (this.simulateRandomFailure()) { throw new Error('無法載入用戶資料'); } return mockUsers[0]; } } // 導出模擬 API 客戶端實例 export const mockApi = new MockApiClient();