feat: подготовил дизайн (изменения из другого репозитория)
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 5s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 8s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 3s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 5s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 8s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 3s
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import GlassCard from '@/components/ui/GlassCard.vue'
|
||||
import CoinChip from '@/components/ui/CoinChip.vue'
|
||||
import ProgressBar from '@/components/ui/ProgressBar.vue'
|
||||
import AchievementBadge from '@/components/ui/AchievementBadge.vue'
|
||||
import DataTable from '@/components/ui/DataTable.vue'
|
||||
|
||||
const auth = useAuthStore()
|
||||
const userStore = useUserStore()
|
||||
const user = computed(() => auth.user!)
|
||||
const interestTags = ref([
|
||||
{ label: '#ML', active: true },
|
||||
{ label: '#ИИ', active: true },
|
||||
{ label: '#дизайн', active: false },
|
||||
{ label: '#право', active: false },
|
||||
{ label: '#биоинформатика', active: false },
|
||||
{ label: '#маркетинг', active: true },
|
||||
])
|
||||
|
||||
const notificationSettings = ref({ email: true, web: true, telegram: false })
|
||||
|
||||
const historyColumns = [
|
||||
{ key: 'date', label: 'Дата' },
|
||||
{ key: 'description', label: 'Описание' },
|
||||
{ key: 'amount', label: 'Монеты', align: 'right' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="profile page-content">
|
||||
<div class="header">
|
||||
<h1 class="page-title">Профиль студента</h1>
|
||||
<CoinChip :amount="user.coins" />
|
||||
</div>
|
||||
|
||||
<div class="profile-grid">
|
||||
<GlassCard>
|
||||
<div class="user-info">
|
||||
<div class="avatar">👤</div>
|
||||
<div>
|
||||
<div class="name">{{ user.name }}</div>
|
||||
<div class="email">{{ user.email }}</div>
|
||||
<div class="meta">{{ user.institute }} · {{ user.direction }}</div>
|
||||
<div class="meta">{{ user.year }} курс</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="level">
|
||||
<div class="level-header">
|
||||
<span>Уровень {{ user.level }}</span>
|
||||
<span>{{ user.xp }} / 200 XP</span>
|
||||
</div>
|
||||
<ProgressBar :value="user.xp ?? 0" :max="200" />
|
||||
</div>
|
||||
<div class="tags">
|
||||
<div class="section-title">Интересы</div>
|
||||
<div class="tags-grid">
|
||||
<button
|
||||
v-for="tag in interestTags"
|
||||
:key="tag.label"
|
||||
class="tag-chip"
|
||||
:class="{ active: tag.active }"
|
||||
@click="tag.active = !tag.active"
|
||||
>
|
||||
{{ tag.label }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
<GlassCard>
|
||||
<div class="section-title">Настройки уведомлений</div>
|
||||
<div class="settings">
|
||||
<label class="setting">
|
||||
<input type="checkbox" v-model="notificationSettings.email" />
|
||||
Email уведомления
|
||||
</label>
|
||||
<label class="setting">
|
||||
<input type="checkbox" v-model="notificationSettings.web" />
|
||||
Web push
|
||||
</label>
|
||||
<label class="setting">
|
||||
<input type="checkbox" v-model="notificationSettings.telegram" />
|
||||
Telegram бот @universe_sfedu
|
||||
</label>
|
||||
</div>
|
||||
<div class="section-title">Достижения</div>
|
||||
<div class="achievements">
|
||||
<AchievementBadge
|
||||
v-for="a in userStore.achievements.slice(0, 3)"
|
||||
:key="a.id"
|
||||
:icon="a.icon"
|
||||
:title="a.title"
|
||||
:description="a.description"
|
||||
:unlocked="a.unlocked"
|
||||
:unlockedAt="a.unlockedAt"
|
||||
:coins="a.coins"
|
||||
/>
|
||||
</div>
|
||||
</GlassCard>
|
||||
</div>
|
||||
|
||||
<GlassCard>
|
||||
<div class="section-title">История начисления монет</div>
|
||||
<DataTable :columns="historyColumns" :rows="userStore.coinHistory">
|
||||
<template #amount="{ value }">
|
||||
<span :class="value > 0 ? 'positive' : 'negative'">{{ value > 0 ? `+${value}` : value }}</span>
|
||||
</template>
|
||||
</DataTable>
|
||||
</GlassCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.profile { display: flex; flex-direction: column; gap: 20px; }
|
||||
.header { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
|
||||
.profile-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 16px; }
|
||||
.user-info { display: flex; gap: 14px; align-items: center; margin-bottom: 16px; }
|
||||
.avatar { font-size: 38px; background: rgba(34,197,94,0.15); border-radius: 16px; padding: 12px; }
|
||||
.name { font-weight: 700; font-size: 18px; }
|
||||
.email, .meta { font-size: 13px; color: var(--color-text-secondary); }
|
||||
.level { margin: 16px 0; }
|
||||
.level-header { display: flex; justify-content: space-between; font-size: 12px; color: var(--color-text-secondary); margin-bottom: 6px; }
|
||||
.tags-grid { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
|
||||
.settings { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
|
||||
.setting { font-size: 13px; color: var(--color-text-secondary); display: flex; gap: 8px; align-items: center; }
|
||||
.achievements { display: flex; flex-direction: column; gap: 12px; margin-top: 10px; }
|
||||
.positive { color: #166534; font-weight: 600; }
|
||||
.negative { color: #991B1B; font-weight: 600; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user