265 lines
6.2 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 { 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';
const qrurl = ref("-")
const qrteam = ref("-")
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();
});
});
</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" />
<table>
<thead>
<tr>
<th></th>
<th>Название команды</th>
<th>Поездки</th>
<th>Приложения</th>
<th>Qr</th>
</tr>
</thead>
<tbody>
<tr v-for="(team, number) in teams.teams" :key="team.name">
<td>
{{ number + 1 }}
</td>
<td class="team-name">{{ team.name }}
<a :href="team.url" target="_blank">[url]</a>
</td>
<td class="cell-center">{{ team.spendTime }}</td>
<td>
<div v-for="application in team.applications" :key="application.id">
{{ application.name }} <button class="link-button"
@click="apiGaveApplication(team.id, application.id)">Выдано</button>
</div>
</td>
<td class="cell-center">
<a v-on:click="qrurl = team.url, qrteam = team.name">QR</a>
</td>
</tr>
</tbody>
</table>
<div class="form-custom form-block">
<div class="center-block-custom">
<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>
</div>
</template>
<style scoped>
.buttons-block {
padding-top: 5px;
}
.button-menu {
margin: 5px 10px 5px 0;
}
table {
width: 700px;
border-collapse: collapse;
margin: 30px auto;
border: 1px solid #444444;
}
th,
td {
padding: 12px;
text-align: left;
}
th {
background-color: var(--main-color);
color: white;
font-weight: bold;
}
tr:nth-child(odd) {
background-color: rgb(239, 239, 239);
}
tr:nth-child(even) {
background-color: rgb(255, 255, 255);
}
tr:hover {
background-color: rgb(207, 207, 207);
}
.time {
white-space: nowrap;
}
.team-name {
font-weight: 600;
}
.link-button {
/* Основные стили */
display: inline;
border: none;
background: none;
padding: 0;
margin: 0;
font: inherit;
cursor: pointer;
color: var(--main-color);
/* Стандартный цвет ссылки */
text-decoration: underline;
font-weight: 600;
/* Убираем стандартное оформление кнопки */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
/* Дополнительные свойства для лучшего отображения */
line-height: inherit;
text-align: left;
}
/* Состояние при наведении */
.link-button:hover {
color: var(--second-color);
/* Немного темнее */
text-decoration: none;
}
/* Состояние при активации (нажатии) */
.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);
/* Кастомный фокус */
}
.form-block {
width: 700px;
margin: 0 auto;
}
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;
}
.cell-center {
text-align: center;
}
</style>