219 lines
4.6 KiB
Vue
219 lines
4.6 KiB
Vue
<script setup lang="ts">
|
||
import { ref, nextTick, watch, onMounted } from 'vue';
|
||
import { useRouter } from 'vue-router';
|
||
import { getApiUrl } from './net';
|
||
|
||
const router = useRouter();
|
||
|
||
type Application = {
|
||
name: string
|
||
}
|
||
|
||
type Action = {
|
||
id: string
|
||
place: string
|
||
name: string
|
||
text: string
|
||
applications: Application[]
|
||
}
|
||
|
||
type Team = {
|
||
actions: Action[]
|
||
}
|
||
|
||
const place = ref("")
|
||
const team = ref<Team>({actions: []})
|
||
const actions = ref<Action[]>([])
|
||
const scrollContainer = ref<HTMLDivElement | null>();
|
||
|
||
function getTeam() {
|
||
fetch(
|
||
getApiUrl("/team"),
|
||
{
|
||
method: "GET",
|
||
headers: {
|
||
"X-Id": sessionStorage.getItem("teamId") || "",
|
||
"X-Password": sessionStorage.getItem("password") || ""
|
||
},
|
||
}
|
||
)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
team.value = data
|
||
const newActions = team.value?.actions
|
||
if (actions.value.length !== newActions?.length) {
|
||
actions.value = newActions
|
||
}
|
||
})
|
||
.catch(error => {
|
||
router.push('/login');
|
||
console.error('Ошибка:', error)
|
||
});
|
||
}
|
||
|
||
function addAction() {
|
||
fetch(
|
||
getApiUrl("/team/actions"),
|
||
{
|
||
method: "POST",
|
||
headers: {
|
||
"X-Id": sessionStorage.getItem("teamId") || "",
|
||
"X-Password": sessionStorage.getItem("password") || ""
|
||
},
|
||
body: JSON.stringify({
|
||
"place": place.value
|
||
})
|
||
}
|
||
)
|
||
.then(async () => {place.value = ""})
|
||
}
|
||
|
||
const scrollToBottom = async (behavior: ScrollBehavior = 'smooth'): Promise<void> => {
|
||
await nextTick();
|
||
if (scrollContainer.value) {
|
||
scrollContainer.value.scrollTo({
|
||
top: scrollContainer.value.scrollHeight,
|
||
behavior
|
||
});
|
||
}
|
||
};
|
||
|
||
// Автоматическая прокрутка при изменении items
|
||
watch(actions, () => {
|
||
scrollToBottom();
|
||
}, { deep: true });
|
||
|
||
let intervalId = 0
|
||
onMounted(() => {
|
||
getTeam()
|
||
|
||
intervalId = setInterval(() => {getTeam()}, 2000);
|
||
|
||
router.beforeEach((to, from, next) => {
|
||
clearInterval(intervalId);
|
||
next();
|
||
});
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
|
||
<div class="body-custom">
|
||
|
||
<div class="header-block">
|
||
Вечерний детектив
|
||
</div>
|
||
|
||
<!-- Форма ввода -->
|
||
<div class="form-custom form-block">
|
||
<div class="center-block-custom">
|
||
<form @submit.prevent="addAction">
|
||
<div>
|
||
<input class="input-custom" v-model="place" type="text" placeholder="Место назначения (А-1, а-1, а1)">
|
||
</div>
|
||
<div class="button-container">
|
||
<button class="button-custom" type="submit">Поехали</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Действия -->
|
||
<div class="messages-block" ref="scrollContainer">
|
||
<div class="center-block-custom">
|
||
<div v-if="!team || !team.actions.length">
|
||
<div class="center-message">
|
||
Пора решать загадку
|
||
</div>
|
||
</div>
|
||
<div v-else>
|
||
<div v-for="action in team.actions" :key="action.id">
|
||
<div class="message-cloud">
|
||
<div class="message-header">
|
||
{{ action.place }}: {{ action.name }}
|
||
</div>
|
||
<hr class="hr"/>
|
||
<div class="message-content">
|
||
{{ action.text }}
|
||
</div>
|
||
<hr class="hr" v-if="action.applications.length"/>
|
||
<div class="message-footer" v-for="application in action.applications" :key="application.name">
|
||
Приложение: {{ application.name }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</template>
|
||
|
||
<style scoped>
|
||
body {
|
||
overflow: hidden;
|
||
}
|
||
|
||
.hr {
|
||
margin: 7px 0;
|
||
}
|
||
|
||
.body-custom {
|
||
font-size: medium;
|
||
}
|
||
|
||
.form-custom {
|
||
border: 1px solid #444444;
|
||
background-color: var(--main-back-color);
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
padding: 20px;
|
||
color: white;
|
||
}
|
||
|
||
.message-cloud {
|
||
border: 1px solid #444444;
|
||
border-radius: 15px;
|
||
margin: 12px 0;
|
||
padding: 16px;
|
||
background-color: var(--main-back-item-color);
|
||
}
|
||
|
||
.message-header {
|
||
font-size: small;
|
||
}
|
||
|
||
.message-content {
|
||
font-weight: 500;
|
||
}
|
||
|
||
.message-footer {
|
||
color: var(--second-color);
|
||
}
|
||
|
||
.form-block {
|
||
height: 140px;
|
||
}
|
||
|
||
.messages-block {
|
||
height: calc(100dvh - 140px - 50px);
|
||
overflow-y: auto;
|
||
scrollbar-width: none;
|
||
}
|
||
|
||
@media (min-width: 1025px) {
|
||
.center-block-custom {
|
||
width: 700px;
|
||
margin: 0 auto;
|
||
}
|
||
}
|
||
|
||
.center-message {
|
||
height: calc(100dvh - 140px);
|
||
}
|
||
</style>
|
||
|