modified: main_dc/BB/bbvue/src/App.vue

new file:   main_dc/BB/bbvue/src/components/EventCard.vue
	new file:   main_dc/BB/bbvue/src/components/RegistrationCard.vue
	modified:   main_dc/BB/bbvue/src/router/index.js
	new file:   main_dc/BB/bbvue/src/stores/event.js
	modified:   main_dc/BB/bbvue/src/stores/helpers/api.js
	new file:   main_dc/BB/bbvue/src/stores/personalBests.js
	new file:   main_dc/BB/bbvue/src/stores/stats.js
	new file:   main_dc/BB/bbvue/src/views/DetailedStats.vue
	new file:   main_dc/BB/bbvue/src/views/Events.vue
	new file:   main_dc/BB/bbvue/src/views/PersonalBests.vue
	modified:   main_dc/BB/bbvue/src/views/Profile.vue
add pages for stats, best-personal and stores
This commit is contained in:
2025-10-25 05:10:04 +05:00
parent 001a3fb0a0
commit 21487660d6
12 changed files with 3085 additions and 28 deletions
@@ -0,0 +1,227 @@
<template>
<div class="registration-card" :class="registration.status">
<div class="registration-header">
<h4>{{ registration.event.title }}</h4>
<span class="status-badge" :class="registration.status">
{{ statusLabel }}
</span>
</div>
<div class="registration-details">
<div class="detail">
<span class="label">Дата:</span>
<span class="value">{{ formatDate(registration.event.date) }}</span>
</div>
<div class="detail">
<span class="label">Место:</span>
<span class="value">{{ registration.event.location }}</span>
</div>
<div v-if="registration.notes" class="detail">
<span class="label">Заметки:</span>
<span class="value">{{ registration.notes }}</span>
</div>
<div v-if="registration.result_time" class="detail">
<span class="label">Результат:</span>
<span class="value result-time">{{ registration.result_time }}</span>
</div>
</div>
<div class="registration-actions">
<button
v-if="registration.status === 'pending'"
class="btn btn-danger btn-sm"
@click="$emit('cancel', registration.id)"
>
Отменить заявку
</button>
<button
v-else-if="registration.status === 'confirmed' && !isPast"
class="btn btn-danger btn-sm"
@click="$emit('cancel', registration.id)"
>
Отменить участие
</button>
<span v-if="isPast && !registration.result_time" class="no-result">
Результат ожидается
</span>
</div>
</div>
</template>
<script>
import { computed } from 'vue'
export default {
name: 'RegistrationCard',
props: {
registration: {
type: Object,
required: true
}
},
emits: ['cancel'],
setup(props) {
const statusLabel = computed(() => {
const labels = {
'pending': '⏳ Ожидает подтверждения',
'confirmed': '✅ Подтверждено',
'cancelled': '❌ Отменено',
'completed': '🏁 Завершено'
}
return labels[props.registration.status] || props.registration.status
})
const isPast = computed(() => {
return new Date(props.registration.event.date) <= new Date()
})
const formatDate = (dateString) => {
return new Date(dateString).toLocaleDateString('ru-RU', {
day: 'numeric',
month: 'long',
year: 'numeric',
hour: '2-digit',
minute: '2-digit'
})
}
return {
statusLabel,
isPast,
formatDate
}
}
}
</script>
<style scoped>
.registration-card {
background: white;
padding: 1.5rem;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
border-left: 4px solid #6c757d;
}
.registration-card.pending {
border-left-color: #ffc107;
}
.registration-card.confirmed {
border-left-color: #28a745;
}
.registration-card.cancelled {
border-left-color: #dc3545;
opacity: 0.7;
}
.registration-card.completed {
border-left-color: #007bff;
}
.registration-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 1rem;
}
.registration-header h4 {
margin: 0;
color: #333;
flex: 1;
margin-right: 1rem;
}
.status-badge {
padding: 0.25rem 0.75rem;
border-radius: 12px;
font-size: 0.8rem;
font-weight: 500;
white-space: nowrap;
}
.status-badge.pending {
background: #fff3cd;
color: #856404;
}
.status-badge.confirmed {
background: #d4edda;
color: #155724;
}
.status-badge.cancelled {
background: #f8d7da;
color: #721c24;
}
.status-badge.completed {
background: #cce7ff;
color: #004085;
}
.registration-details {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1rem;
}
.detail {
display: flex;
gap: 0.5rem;
}
.detail .label {
color: #666;
font-weight: 500;
min-width: 80px;
}
.detail .value {
color: #333;
flex: 1;
}
.detail .result-time {
font-weight: bold;
color: #2e8b57;
}
.registration-actions {
display: flex;
justify-content: space-between;
align-items: center;
}
.no-result {
color: #666;
font-style: italic;
font-size: 0.9rem;
}
/* Адаптивность */
@media (max-width: 768px) {
.registration-header {
flex-direction: column;
gap: 0.5rem;
align-items: flex-start;
}
.registration-header h4 {
margin-right: 0;
}
.detail {
flex-direction: column;
gap: 0.25rem;
}
.detail .label {
min-width: auto;
}
}
</style>