Files
tp/serv_nginx/bbvue/src/stores/user_store.js
T
valitovgaziz b75c0b4f2b modified: serv_nginx/bbvue/src/stores/auth.js
renamed:    serv_nginx/bbvue/src/stores/user.js -> serv_nginx/bbvue/src/stores/user_store.js
	modified:   serv_nginx/bbvue/src/views/Members.vue
search-input width is corrected
2025-10-20 20:54:53 +05:00

379 lines
12 KiB
JavaScript

// stores/user.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { apiClient, handleApiError } from './helpers/api'
export const useUserStore = defineStore('user', () => {
// State
const userStats = ref(null)
const userTraining = ref(null)
const userAchievements = ref([])
const personalBests = ref([])
const upcomingEvents = ref([])
const currentTrainingPlan = ref(null)
const workoutHistory = ref([])
const loading = ref(false)
const error = ref('')
// Getters
const completedAchievements = computed(() =>
userAchievements.value.filter(achievement => achievement.verified || achievement.achieved)
)
const pendingAchievements = computed(() =>
userAchievements.value.filter(achievement => !(achievement.verified || achievement.achieved))
)
const achievementProgress = computed(() => {
if (!userAchievements.value.length) return 0
return Math.round((completedAchievements.value.length / userAchievements.value.length) * 100)
})
const verifiedPersonalBests = computed(() =>
personalBests.value.filter(best => best.verified)
)
const confirmedEvents = computed(() =>
upcomingEvents.value.filter(event => event.registrationStatus === 'confirmed')
)
const totalWorkouts = computed(() =>
userStats.value?.workoutsCount || workoutHistory.value.length
)
const totalCalories = computed(() =>
workoutHistory.value.reduce((sum, workout) => sum + (workout.calories || 0), 0)
)
// Вспомогательная функция для обработки loading/error
const withStoreLoading = async (fn) => {
loading.value = true
error.value = ''
try {
return await fn()
} catch (err) {
const result = handleApiError(err)
error.value = result.error
return result
} finally {
loading.value = false
}
}
// Actions - Основные данные пользователя
const fetchUserStats = async () => {
return withStoreLoading(async () => {
try {
const response = await apiClient.get('/user/stats')
console.log("debug /user/stats " + response.data)
userStats.value = response.data
return { success: true, data: userStats.value }
} catch (error) {
// Fallback на мок данные если endpoint не готов
console.warn('Stats endpoint not available, using mock data', error)
userStats.value = {
totalDistance: 245.5,
totalTime: 12540,
avgPace: '5:15',
workoutsCount: 36,
currentStreak: 7,
longestStreak: 21,
weeklyDistance: 25.8,
monthlyDistance: 98.2,
personal_bests: {
best_5k: '23:45',
best_10k: '48:15',
best_half: '1:48:30',
best_marathon: null
}
}
return { success: true, data: userStats.value }
}
})
}
const fetchUserAchievements = async () => {
return withStoreLoading(async () => {
try {
const response = await apiClient.get('/user/achievements')
console.log("debug /user/achievements " + response.data)
userAchievements.value = response.data || []
return { success: true, data: userAchievements.value }
} catch (error) {
console.warn('Achievements endpoint not available, using mock data', error)
userAchievements.value = [
{
id: 1,
type: 'distance',
title: 'Первый забег',
description: 'Пробежать первую 5км',
verified: true,
date: '2024-01-20',
badgeImage: '/badges/first-run.png'
},
{
id: 2,
type: 'consistency',
title: 'Неделя тренировок',
description: 'Тренироваться 7 дней подряд',
verified: true,
date: '2024-02-15',
badgeImage: '/badges/week-streak.png'
},
{
id: 3,
type: 'distance',
title: '100 км',
description: 'Пробежать 100 км',
verified: true,
date: '2024-03-01',
badgeImage: '/badges/100km.png'
},
{
id: 4,
type: 'distance',
title: 'Полумарафон',
description: 'Пробежать 21.1 км',
verified: false,
badgeImage: '/badges/half-marathon.png'
},
{
id: 5,
type: 'speed',
title: 'Скорость',
description: 'Пробежать 5км быстрее 25 минут',
verified: false,
badgeImage: '/badges/speedster.png'
}
]
return { success: true, data: userAchievements.value }
}
})
}
// Новые actions для дополнительных данных
const fetchPersonalBests = async () => {
return withStoreLoading(async () => {
try {
const response = await apiClient.get('/user/personal-bests')
console.log("debug /user/personal-bests " + response.data)
personalBests.value = response.data
return { success: true, data: personalBests.value }
} catch (error) {
console.warn('Personal bests 1endpoint not available, using mock data', error)
personalBests.value = []
return { success: true, data: personalBests.value }
}
})
}
const fetchUpcomingEvents = async () => {
return withStoreLoading(async () => {
try {
const response = await apiClient.get('/events/upcoming')
console.log("debug /events/upcoming " + response.data)
upcomingEvents.value = response.data
return { success: true, data: upcomingEvents.value }
} catch (error) {
console.warn('Events endpoint not available, using mock data', error)
upcomingEvents.value = [
{
id: 1,
title: 'Летний забег 10км',
date: '2024-06-15T09:00:00',
location: 'Городской парк',
type: 'race',
distance: '10 км',
registrationStatus: 'confirmed'
},
{
id: 2,
title: 'Тренировка для начинающих',
date: '2024-06-20T18:30:00',
location: 'Стадион "Спартак"',
type: 'training',
registrationStatus: 'confirmed'
}
]
return { success: true, data: upcomingEvents.value }
}
})
}
const fetchCurrentTrainingPlan = async () => {
return withStoreLoading(async () => {
try {
const response = await apiClient.get('/user/training-plans')
console.log("debug /user/training-plans/active " + response.data)
currentTrainingPlan.value = response.data
return { success: true, data: currentTrainingPlan.value }
} catch (error) {
console.warn('Training plan endpoint not available, using mock data', error)
currentTrainingPlan.value = {
id: 1,
title: 'Подготовка к полумарафону',
description: '12-недельный план подготовки к первому полумарафону',
weeks: 12,
currentWeek: 4,
workoutsPerWeek: 3,
targetDistance: '21.1 км',
targetDate: '2024-08-15',
completed: false,
workouts: [
{ id: 1, week: 4, day: 1, type: 'easy', distance: 5, completed: true },
{ id: 2, week: 4, day: 3, type: 'tempo', distance: 8, completed: false },
{ id: 3, week: 4, day: 5, type: 'long', distance: 12, completed: false }
]
}
return { success: true, data: currentTrainingPlan.value }
}
})
}
const fetchWorkoutHistory = async (limit = 10) => {
return withStoreLoading(async () => {
try {
const response = await apiClient.get(`/workouts?limit=${limit}`)
workoutHistory.value = response.data
return { success: true, data: workoutHistory.value }
} catch (error) {
console.warn('Workouts endpoint not available, using mock data', error)
workoutHistory.value = [
{
id: 1,
type: 'easy',
distance_km: 5.2,
duration_min: 28,
pace: '5:23',
calories: 320,
date: '2024-03-18'
},
{
id: 2,
type: 'interval',
distance_km: 8.1,
duration_min: 42,
pace: '5:11',
calories: 510,
date: '2024-03-16'
},
{
id: 3,
type: 'long',
distance_km: 15.5,
duration_min: 85,
pace: '5:29',
calories: 980,
date: '2024-03-14'
}
]
return { success: true, data: workoutHistory.value }
}
})
}
// Специализированные методы для обновления данных
const addPersonalBest = async (bestData) => {
return withStoreLoading(async () => {
try {
const response = await apiClient.post('/personal-bests', bestData)
personalBests.value.push(response.data)
return { success: true, data: response.data }
} catch (error) {
return { success: false, error: error.message }
}
})
}
const registerForEvent = async (eventId) => {
return withStoreLoading(async () => {
try {
const response = await apiClient.post('/events/register', { event_id: eventId })
// Обновляем список событий
await fetchUpcomingEvents()
return { success: true, data: response.data }
} catch (error) {
return { success: false, error: error.message }
}
})
}
const completeWorkout = async (workoutId) => {
return withStoreLoading(async () => {
try {
const response = await apiClient.patch(`/workouts/${workoutId}/complete`)
// Обновляем историю тренировок и статистику
await Promise.all([
fetchWorkoutHistory(),
fetchUserStats()
])
return { success: true, data: response.data }
} catch (error) {
return { success: false, error: error.message }
}
})
}
// Пакетная загрузка всех данных пользователя
const fetchAllUserData = async () => {
return withStoreLoading(async () => {
await Promise.all([
fetchUserStats(),
fetchUserAchievements(),
fetchPersonalBests(),
fetchUpcomingEvents(),
fetchCurrentTrainingPlan(),
fetchWorkoutHistory()
])
return { success: true }
})
}
// Сброс store
const resetUserStore = () => {
userStats.value = null
userTraining.value = null
userAchievements.value = []
personalBests.value = []
upcomingEvents.value = []
currentTrainingPlan.value = null
workoutHistory.value = []
loading.value = false
error.value = ''
}
return {
// State
userStats,
userTraining,
userAchievements,
personalBests,
upcomingEvents,
currentTrainingPlan,
workoutHistory,
loading,
error,
// Getters
completedAchievements,
pendingAchievements,
achievementProgress,
verifiedPersonalBests,
confirmedEvents,
totalWorkouts,
totalCalories,
// Actions
fetchUserStats,
fetchUserAchievements,
fetchPersonalBests,
fetchUpcomingEvents,
fetchCurrentTrainingPlan,
fetchWorkoutHistory,
fetchAllUserData,
addPersonalBest,
registerForEvent,
completeWorkout,
resetUserStore
}
})