2026-03-28 03:10:14 +07:00

273 lines
6.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import router from '@/router';
import type { Application, Game, Team, Teams } from './models';
import { apiGetTeams, apiAddTeam, apiGetGame, apiStartGame, apiStopGame, apiGaveApplication, apiDownloadQrCodesFile } from './client';
import TeamQRCode from '../components/TeamQRCode.vue'
import HeaderBlock from './HeaderBlock.vue';
import ModalWindow from './ModalWindow.vue';
const qrurl = ref("-")
const qrteam = ref("-")
const isOpenModal = ref(false)
const gameState = ref("")
const game = ref<Game | undefined>()
const teams = ref<Teams>({ teams: [] })
const teamName = ref("")
async function addTeam() {
await apiAddTeam(teamName.value)
teamName.value = ""
}
async function startGame() {
gameState.value = "Загрузка..."
await apiStartGame()
}
async function stopGame() {
gameState.value = "Загрузка..."
await apiStopGame()
}
async function getGame() {
game.value = await apiGetGame()
if (game.value.state === "NEW") {
gameState.value = "Игра ещё не началась"
}
if (game.value.state === "RUN") {
gameState.value = "Игра идет с " + game.value?.startAt.substring(11)
}
if (game.value.state === "STOP") {
gameState.value = "Игра остановлена " + game.value?.startAt.substring(11) + " - " + game.value?.endAt.substring(11)
}
}
function compareTeams(a: Team, b: Team): number {
return b.applications.length - a.applications.length
}
let intervalId = 0
onMounted(async () => {
teams.value = await apiGetTeams()
intervalId = setInterval(async () => {
teams.value = await apiGetTeams()
teams.value.teams.sort(compareTeams)
await getGame()
}, 2000);
router.beforeEach((to, from, next) => {
clearInterval(intervalId);
next();
});
});
const gaveApplicationTeam = ref<Team>({
id: 0,
name: '',
password: '',
url: '',
spendTime: 0,
applications: []
})
const gaveApplicationApplication = ref<Application>({
id: 0,
name: ''
})
function gaveApplication(team: Team, application: Application) {
gaveApplicationTeam.value = team
gaveApplicationApplication.value = application
isOpenModal.value = true
}
async function confirm() {
console.log("confirm")
await apiGaveApplication(gaveApplicationTeam.value.id, gaveApplicationApplication.value.id)
isOpenModal.value = false
}
function close() {
console.log("close")
isOpenModal.value = false
}
</script>
<template>
<HeaderBlock>
<div>
Вечерний детектив - {{ gameState }}
</div>
<div class="buttons-block">
<button v-on:click="router.push('/editor')" class="button-menu button-custom-inline">Редактор</button>
<button v-on:click="startGame" class="button-menu button-custom-inline">Начать</button>
<button v-on:click="stopGame" class="button-menu button-custom-inline">Остановить</button>
<button v-on:click="apiDownloadQrCodesFile" class="button-menu button-custom-inline">Скачать&nbsp;qrы</button>
</div>
</HeaderBlock>
<TeamQRCode :data="qrurl" :title="qrteam" />
<div class="center-block-custom content-block">
<div class="team-header-block">Команды</div>
<div class="team-block" v-for="team in teams.teams" :key="team.name">
<div class="team-content-block">
<div class="team-name-block">
<a v-on:click="qrurl = team.url, qrteam = team.name">
QR
</a>
<a :href="team.url" class="url-block" target="_blank">
URL
</a>
{{ team.name }}
</div>
<div>Поездки: {{ team.spendTime }}</div>
</div>
<div v-for="application in team.applications" :key="application.id" class="link-button"
@click="gaveApplication(team, application)">
Выдать: {{ application.name }}
</div>
</div>
<form @submit.prevent="addTeam">
<div>
<input class="input-custom" v-model="teamName" type="text" placeholder="Название команды">
</div>
<div class="button-container">
<button class="button-custom" type="submit">Добавить</button>
</div>
</form>
</div>
<ModalWindow :is-open="isOpenModal" @confirm="confirm" @close="close">
<div>
Команда: {{ gaveApplicationTeam.name }}
</div>
<div>
Приложение: {{ gaveApplicationApplication.name }}
</div>
</ModalWindow>
</template>
<style scoped>
.buttons-block {
padding-top: 5px;
}
.button-menu {
margin: 5px 10px 5px 0;
}
.url-block {
margin: 5px 0;
}
.link-button {
/* Основные стили */
border: none;
color: white;
background-color: var(--main-color);
padding: 15px;
margin: 0;
font: inherit;
cursor: pointer;
/* Стандартный цвет ссылки */
font-weight: 600;
/* Убираем стандартное оформление кнопки */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
/* Дополнительные свойства для лучшего отображения */
line-height: inherit;
text-align: center;
}
/* Состояние при наведении */
.link-button:hover {
color: #ccc;
/* Немного темнее */
text-decoration: none;
background-color: var(--second-color);
}
/* Состояние при активации (нажатии) */
.link-button:active {
color: #003366;
/* Еще темнее */
}
/* Состояние фокуса (для доступности) */
.link-button:focus {
outline: none;
/* Убираем стандартный outline */
text-decoration: none;
box-shadow: 0 0 0 2px rgba(0, 102, 204, 0.3);
/* Кастомный фокус */
}
a {
/* Основные стили */
color: var(--second-color);
text-decoration: none;
transition: all 0.2s ease;
cursor: pointer;
/* Подчеркивание только при наведении */
&:hover {
text-decoration: underline;
text-decoration-thickness: 2px;
text-underline-offset: 3px;
}
/* Состояние фокуса для доступности */
&:focus-visible {
outline: 2px solid #3182ce;
outline-offset: 2px;
border-radius: 2px;
}
/* Отключенное состояние */
&[disabled] {
color: #a0aec0;
pointer-events: none;
cursor: not-allowed;
}
}
.button-container {
margin-bottom: 30px;
}
.content-block {
padding: 10px;
}
.team-header-block {
font-weight: 700;
font-size: 30px;
}
.team-block {
border: solid 1px #003366;
border-radius: 5px;
margin: 15px 0;
}
.team-content-block {
padding: 10px;
}
.team-name-block {
font-weight: 600;
font-size: 20px;
}
</style>