2025-12-12 13:30:09 +03:00
|
|
|
<template>
|
|
|
|
|
<div class="room-page" v-if="room">
|
|
|
|
|
<div class="room-header">
|
|
|
|
|
<h1>{{ room.name }}</h1>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="room-layout">
|
|
|
|
|
<div class="main-section">
|
|
|
|
|
<div class="queue-section card">
|
|
|
|
|
<div class="queue-header">
|
|
|
|
|
<h3>Очередь</h3>
|
|
|
|
|
<button class="btn-secondary" @click="showAddTrack = true">Добавить</button>
|
|
|
|
|
</div>
|
2025-12-12 15:02:02 +03:00
|
|
|
<Queue :queue="roomStore.queue" @play-track="playTrack" @remove-track="removeFromQueue" />
|
2025-12-12 13:30:09 +03:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="side-section">
|
|
|
|
|
<ParticipantsList :participants="roomStore.participants" />
|
2025-12-12 15:02:02 +03:00
|
|
|
<ChatWindow :room-id="roomId" />
|
2025-12-12 13:30:09 +03:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<Modal v-if="showAddTrack" title="Добавить в очередь" @close="showAddTrack = false">
|
|
|
|
|
<TrackList
|
|
|
|
|
:tracks="tracksStore.tracks"
|
|
|
|
|
selectable
|
|
|
|
|
@select="addTrackToQueue"
|
|
|
|
|
/>
|
|
|
|
|
</Modal>
|
|
|
|
|
</div>
|
|
|
|
|
<div v-else class="loading">Загрузка...</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
2025-12-12 15:02:02 +03:00
|
|
|
import { ref, onMounted } from 'vue'
|
|
|
|
|
import { useRoute } from 'vue-router'
|
2025-12-12 13:30:09 +03:00
|
|
|
import { useRoomStore } from '../stores/room'
|
|
|
|
|
import { useTracksStore } from '../stores/tracks'
|
2025-12-12 15:02:02 +03:00
|
|
|
import { useActiveRoomStore } from '../stores/activeRoom'
|
2025-12-12 13:30:09 +03:00
|
|
|
import Queue from '../components/room/Queue.vue'
|
|
|
|
|
import ParticipantsList from '../components/room/ParticipantsList.vue'
|
|
|
|
|
import ChatWindow from '../components/chat/ChatWindow.vue'
|
|
|
|
|
import TrackList from '../components/tracks/TrackList.vue'
|
|
|
|
|
import Modal from '../components/common/Modal.vue'
|
|
|
|
|
|
|
|
|
|
const route = useRoute()
|
|
|
|
|
const roomStore = useRoomStore()
|
|
|
|
|
const tracksStore = useTracksStore()
|
2025-12-12 15:02:02 +03:00
|
|
|
const activeRoomStore = useActiveRoomStore()
|
2025-12-12 13:30:09 +03:00
|
|
|
|
|
|
|
|
const roomId = route.params.id
|
|
|
|
|
const room = ref(null)
|
|
|
|
|
const showAddTrack = ref(false)
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
await roomStore.fetchRoom(roomId)
|
|
|
|
|
room.value = roomStore.currentRoom
|
|
|
|
|
|
|
|
|
|
await roomStore.joinRoom(roomId)
|
|
|
|
|
await roomStore.fetchQueue(roomId)
|
|
|
|
|
await tracksStore.fetchTracks()
|
|
|
|
|
|
2025-12-12 15:02:02 +03:00
|
|
|
// Connect to room via global store
|
|
|
|
|
activeRoomStore.connect(roomId, room.value.name)
|
2025-12-12 13:30:09 +03:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
function playTrack(track) {
|
2025-12-12 15:02:02 +03:00
|
|
|
activeRoomStore.sendPlayerAction('set_track', null, track.id)
|
2025-12-12 13:30:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function addTrackToQueue(track) {
|
|
|
|
|
await roomStore.addToQueue(roomId, track.id)
|
|
|
|
|
showAddTrack.value = false
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-12 15:02:02 +03:00
|
|
|
async function removeFromQueue(track) {
|
|
|
|
|
await roomStore.removeFromQueue(roomId, track.id)
|
2025-12-12 13:30:09 +03:00
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.room-page {
|
|
|
|
|
padding-top: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.room-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-bottom: 24px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.room-header h1 {
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.room-layout {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: 1fr 350px;
|
|
|
|
|
gap: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.main-section {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.side-section {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.queue-section {
|
|
|
|
|
flex: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.queue-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-bottom: 16px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.queue-header h3 {
|
|
|
|
|
margin: 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.loading {
|
|
|
|
|
text-align: center;
|
|
|
|
|
padding: 40px;
|
|
|
|
|
color: #aaa;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@media (max-width: 900px) {
|
|
|
|
|
.room-layout {
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|