generated from VLADIMIR/template_frontend
update
This commit is contained in:
+275
-69
@@ -2,7 +2,17 @@
|
||||
import { Flag, Pause, Play, Reset, Settings, Trophy } from '@vicons/carbon'
|
||||
import { Icon } from '@vicons/utils'
|
||||
import { NButton, NTag } from 'naive-ui'
|
||||
import { NCard, NFlex, NInput, NInputNumber, NModal, NQrCode, NSelect, NSpace, NText } from 'naive-ui'
|
||||
import {
|
||||
NCard,
|
||||
NFlex,
|
||||
NInput,
|
||||
NInputNumber,
|
||||
NModal,
|
||||
NQrCode,
|
||||
NSelect,
|
||||
NSpace,
|
||||
NText,
|
||||
} from 'naive-ui'
|
||||
import { useMessage } from 'naive-ui'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
@@ -67,7 +77,9 @@ const participationOptions = [
|
||||
const participationSummary = computed(() =>
|
||||
participationOptions.slice(1).map((option) => {
|
||||
const teams = (game.value.teams || []).filter(
|
||||
(team) => team.participationStatus === option.value,
|
||||
(team) =>
|
||||
team.participationStatus === option.value &&
|
||||
(option.value !== 'pending' || Boolean(team.captainEmail)),
|
||||
)
|
||||
return {
|
||||
...option,
|
||||
@@ -81,7 +93,8 @@ const activeTeamCount = computed(
|
||||
)
|
||||
const visibleTeams = computed(() =>
|
||||
(game.value.teams || []).filter(
|
||||
(team) => participationFilter.value === 'all' || team.participationStatus === participationFilter.value,
|
||||
(team) =>
|
||||
participationFilter.value === 'all' || team.participationStatus === participationFilter.value,
|
||||
),
|
||||
)
|
||||
const screens = ref<ScreenState[]>([])
|
||||
@@ -96,7 +109,8 @@ const currentScreenMode = computed<ScreenMode | undefined>(() => {
|
||||
})
|
||||
const mapScale = ref(1)
|
||||
const mapOffset = ref({ x: 0, y: 0 })
|
||||
let dragState: { item: MapItem; startX: number; startY: number; itemX: number; itemY: number } | undefined
|
||||
let dragState:
|
||||
{ item: MapItem; startX: number; startY: number; itemX: number; itemY: number } | undefined
|
||||
let panState: { startX: number; startY: number; offsetX: number; offsetY: number } | undefined
|
||||
|
||||
async function getGame(id: number) {
|
||||
@@ -154,7 +168,14 @@ getGameMap()
|
||||
async function saveMapItem(item: MapItem, hidden = item.hidden) {
|
||||
mapSaving.value = true
|
||||
try {
|
||||
const res = await client.UpdateGameMapItem({ gameId: Number(gameId), kind: item.kind, itemId: item.itemId, x: Math.round(item.x || 0), y: Math.round(item.y || 0), hidden })
|
||||
const res = await client.UpdateGameMapItem({
|
||||
gameId: Number(gameId),
|
||||
kind: item.kind,
|
||||
itemId: item.itemId,
|
||||
x: Math.round(item.x || 0),
|
||||
y: Math.round(item.y || 0),
|
||||
hidden,
|
||||
})
|
||||
if (res.error != '') message.error(res.error || 'Не удалось сохранить координаты')
|
||||
} finally {
|
||||
mapSaving.value = false
|
||||
@@ -204,7 +225,12 @@ function resetMapView() {
|
||||
|
||||
function startMapPan(event: PointerEvent) {
|
||||
if (event.button !== 0) return
|
||||
panState = { startX: event.clientX, startY: event.clientY, offsetX: mapOffset.value.x, offsetY: mapOffset.value.y }
|
||||
panState = {
|
||||
startX: event.clientX,
|
||||
startY: event.clientY,
|
||||
offsetX: mapOffset.value.x,
|
||||
offsetY: mapOffset.value.y,
|
||||
}
|
||||
window.addEventListener('pointermove', moveMapPan)
|
||||
window.addEventListener('pointerup', endMapPan, { once: true })
|
||||
}
|
||||
@@ -623,7 +649,13 @@ useSimplePolling(() => {
|
||||
</Icon>
|
||||
Итоги
|
||||
</n-button>
|
||||
<n-button v-if="activeTeamCount" quaternary :loading="isDownloadingQR" :disabled="isDownloadingQR" @click="downloadTeamQR()">
|
||||
<n-button
|
||||
v-if="activeTeamCount"
|
||||
quaternary
|
||||
:loading="isDownloadingQR"
|
||||
:disabled="isDownloadingQR"
|
||||
@click="downloadTeamQR()"
|
||||
>
|
||||
QR команд
|
||||
</n-button>
|
||||
<n-button quaternary @click="openSettings()">
|
||||
@@ -632,7 +664,12 @@ useSimplePolling(() => {
|
||||
</Icon>
|
||||
Настройки
|
||||
</n-button>
|
||||
<n-button v-if="(game.teams?.length || 0) == 0" type="error" quaternary @click="showDeleteGameModal = true">
|
||||
<n-button
|
||||
v-if="(game.teams?.length || 0) == 0"
|
||||
type="error"
|
||||
quaternary
|
||||
@click="showDeleteGameModal = true"
|
||||
>
|
||||
Удалить игру
|
||||
</n-button>
|
||||
|
||||
@@ -678,31 +715,72 @@ useSimplePolling(() => {
|
||||
<n-flex justify="end">
|
||||
<n-tag v-if="screen.soundEnabled" type="success">Со звуком</n-tag>
|
||||
<n-button v-else size="small" @click="setSoundScreen(screen)">Назначить звук</n-button>
|
||||
<n-button size="small" type="error" ghost @click="unbindScreen(screen)">Отвязать</n-button>
|
||||
<n-button size="small" type="error" ghost @click="unbindScreen(screen)"
|
||||
>Отвязать</n-button
|
||||
>
|
||||
</n-flex>
|
||||
</div>
|
||||
<n-space class="screen-mode-controls">
|
||||
<n-button size="small" :type="currentScreenMode === 'SCREEN_MODE_COVER' ? 'primary' : 'default'" @click="setScreenMode('SCREEN_MODE_COVER')">Обложка</n-button>
|
||||
<n-button size="small" :type="currentScreenMode === 'SCREEN_MODE_INTRO' ? 'primary' : 'default'" @click="setScreenMode('SCREEN_MODE_INTRO')">Введение</n-button>
|
||||
<n-button size="small" :type="currentScreenMode === 'SCREEN_MODE_INTRO_DONE' ? 'primary' : 'default'" @click="setScreenMode('SCREEN_MODE_INTRO_DONE')">Успехов</n-button>
|
||||
<n-button size="small" :type="currentScreenMode === 'SCREEN_MODE_CONCLUSION' ? 'primary' : 'default'" @click="setScreenMode('SCREEN_MODE_CONCLUSION')">Закрывашка</n-button>
|
||||
<n-button size="small" :type="currentScreenMode === 'SCREEN_MODE_CONCLUSION_DONE' ? 'primary' : 'default'" @click="setScreenMode('SCREEN_MODE_CONCLUSION_DONE')">Спасибо за игру!</n-button>
|
||||
<n-button v-if="game.status === 'finish'" size="small" :type="currentScreenMode === 'SCREEN_MODE_RESULTS' ? 'primary' : 'default'" @click="setScreenMode('SCREEN_MODE_RESULTS')">Результаты</n-button>
|
||||
<n-button
|
||||
size="small"
|
||||
:type="currentScreenMode === 'SCREEN_MODE_COVER' ? 'primary' : 'default'"
|
||||
@click="setScreenMode('SCREEN_MODE_COVER')"
|
||||
>Обложка</n-button
|
||||
>
|
||||
<n-button
|
||||
size="small"
|
||||
:type="currentScreenMode === 'SCREEN_MODE_INTRO' ? 'primary' : 'default'"
|
||||
@click="setScreenMode('SCREEN_MODE_INTRO')"
|
||||
>Введение</n-button
|
||||
>
|
||||
<n-button
|
||||
size="small"
|
||||
:type="currentScreenMode === 'SCREEN_MODE_INTRO_DONE' ? 'primary' : 'default'"
|
||||
@click="setScreenMode('SCREEN_MODE_INTRO_DONE')"
|
||||
>Успехов</n-button
|
||||
>
|
||||
<n-button
|
||||
size="small"
|
||||
:type="currentScreenMode === 'SCREEN_MODE_CONCLUSION' ? 'primary' : 'default'"
|
||||
@click="setScreenMode('SCREEN_MODE_CONCLUSION')"
|
||||
>Закрывашка</n-button
|
||||
>
|
||||
<n-button
|
||||
size="small"
|
||||
:type="currentScreenMode === 'SCREEN_MODE_CONCLUSION_DONE' ? 'primary' : 'default'"
|
||||
@click="setScreenMode('SCREEN_MODE_CONCLUSION_DONE')"
|
||||
>Спасибо за игру!</n-button
|
||||
>
|
||||
<n-button
|
||||
v-if="game.status === 'finish'"
|
||||
size="small"
|
||||
:type="currentScreenMode === 'SCREEN_MODE_RESULTS' ? 'primary' : 'default'"
|
||||
@click="setScreenMode('SCREEN_MODE_RESULTS')"
|
||||
>Результаты</n-button
|
||||
>
|
||||
</n-space>
|
||||
<n-space class="screen-mode-controls">
|
||||
<n-button size="small" @click="sendScreenCommand('SCREEN_COMMAND_PLAY')">Запуск</n-button>
|
||||
<n-button size="small" @click="sendScreenCommand('SCREEN_COMMAND_PAUSE')">Пауза</n-button>
|
||||
<n-button size="small" @click="sendScreenCommand('SCREEN_COMMAND_RESUME')">Продолжить</n-button>
|
||||
<n-button size="small" @click="sendScreenCommand('SCREEN_COMMAND_RESUME')"
|
||||
>Продолжить</n-button
|
||||
>
|
||||
<n-button size="small" @click="sendScreenCommand('SCREEN_COMMAND_STOP')">Стоп</n-button>
|
||||
<n-button size="small" @click="sendScreenCommand('SCREEN_COMMAND_REPLAY')">Повтор</n-button>
|
||||
<n-button size="small" @click="sendScreenCommand('SCREEN_COMMAND_REPLAY')"
|
||||
>Повтор</n-button
|
||||
>
|
||||
</n-space>
|
||||
<n-space class="screen-mode-controls" align="center">
|
||||
<n-text>Громкость</n-text>
|
||||
<n-input-number v-model:value="screenVolume" :min="0" :max="100" :step="5" size="small" />
|
||||
<n-button size="small" @click="sendScreenCommand('SCREEN_COMMAND_VOLUME')">Применить</n-button>
|
||||
<n-button size="small" @click="sendScreenCommand('SCREEN_COMMAND_VOLUME')"
|
||||
>Применить</n-button
|
||||
>
|
||||
<n-text>Позиция, сек.</n-text>
|
||||
<n-input-number v-model:value="screenPosition" :min="0" :step="5" size="small" />
|
||||
<n-button size="small" @click="sendScreenCommand('SCREEN_COMMAND_SEEK')">Перемотать</n-button>
|
||||
<n-button size="small" @click="sendScreenCommand('SCREEN_COMMAND_SEEK')"
|
||||
>Перемотать</n-button
|
||||
>
|
||||
</n-space>
|
||||
</div>
|
||||
|
||||
@@ -717,20 +795,36 @@ useSimplePolling(() => {
|
||||
</n-space>
|
||||
</n-flex>
|
||||
<div class="map-field" @pointerdown="startMapPan" @wheel="zoomMap">
|
||||
<div class="map-canvas" :style="{ transform: `translate(${mapOffset.x}px, ${mapOffset.y}px) scale(${mapScale})` }">
|
||||
<div v-for="item in mapItems" v-show="!item.hidden" :key="`${item.kind}-${item.itemId}`"
|
||||
class="map-item" :class="item.kind === 'screen' ? 'map-screen' : 'map-team'"
|
||||
<div
|
||||
class="map-canvas"
|
||||
:style="{
|
||||
transform: `translate(${mapOffset.x}px, ${mapOffset.y}px) scale(${mapScale})`,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
v-for="item in mapItems"
|
||||
v-show="!item.hidden"
|
||||
:key="`${item.kind}-${item.itemId}`"
|
||||
class="map-item"
|
||||
:class="item.kind === 'screen' ? 'map-screen' : 'map-team'"
|
||||
:style="{ left: `${item.x || 0}px`, top: `${item.y || 0}px` }"
|
||||
@pointerdown.stop="startMapDrag(item, $event)">
|
||||
@pointerdown.stop="startMapDrag(item, $event)"
|
||||
>
|
||||
<span>{{ item.label }}</span>
|
||||
<small v-if="item.kind === 'screen'">{{ item.status }}{{ item.soundEnabled ? ' · звук' : '' }}</small>
|
||||
<small v-if="item.kind === 'screen'"
|
||||
>{{ item.status }}{{ item.soundEnabled ? ' · звук' : '' }}</small
|
||||
>
|
||||
<button type="button" @pointerdown.stop @click.stop="toggleMapItem(item)">×</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<n-space v-if="mapItems.some(item => item.hidden)" class="map-hidden-items">
|
||||
<n-button v-for="item in mapItems.filter(item => item.hidden)" :key="`hidden-${item.kind}-${item.itemId}`"
|
||||
size="small" @click="toggleMapItem(item)">
|
||||
<n-space v-if="mapItems.some((item) => item.hidden)" class="map-hidden-items">
|
||||
<n-button
|
||||
v-for="item in mapItems.filter((item) => item.hidden)"
|
||||
:key="`hidden-${item.kind}-${item.itemId}`"
|
||||
size="small"
|
||||
@click="toggleMapItem(item)"
|
||||
>
|
||||
Добавить {{ item.label }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
@@ -744,7 +838,11 @@ useSimplePolling(() => {
|
||||
<n-tag v-for="item in participationSummary" :key="item.value">
|
||||
{{ item.label }}: {{ item.count }} команд · {{ item.participants }} участников
|
||||
</n-tag>
|
||||
<n-select v-model:value="participationFilter" :options="participationOptions" aria-label="Статус участия" />
|
||||
<n-select
|
||||
v-model:value="participationFilter"
|
||||
:options="participationOptions"
|
||||
aria-label="Статус участия"
|
||||
/>
|
||||
</n-space>
|
||||
|
||||
<div v-for="team in visibleTeams" :key="team.id" class="team-block">
|
||||
@@ -754,28 +852,49 @@ useSimplePolling(() => {
|
||||
<span class="team-name-block">
|
||||
{{ team.name }}
|
||||
<small v-if="team.captainEmail"> — {{ team.captainEmail }}</small>
|
||||
<small v-if="team.participantsCount"> · Участников: {{ team.participantsCount }}</small>
|
||||
<small v-if="team.participantsCount">
|
||||
· Участников: {{ team.participantsCount }}</small
|
||||
>
|
||||
</span>
|
||||
<div>{{ participationOptions.find((option) => option.value === team.participationStatus)?.label }}<span v-if="team.participationSource === 'automatic'"> · автоматически</span></div>
|
||||
<div v-if="team.captainEmail || team.participationStatus !== 'pending'">
|
||||
{{
|
||||
participationOptions.find((option) => option.value === team.participationStatus)
|
||||
?.label
|
||||
}}<span v-if="team.participationSource === 'automatic'"> · автоматически</span>
|
||||
</div>
|
||||
<div v-if="!team.captainEmail">Почта капитана не указана</div>
|
||||
<div v-else-if="team.participationEmailError">Ошибка отправки: {{ team.participationEmailError }}</div>
|
||||
<div v-else-if="team.participationEmailError">
|
||||
Ошибка отправки: {{ team.participationEmailError }}
|
||||
</div>
|
||||
<div v-else-if="team.participationEmailSent">Письмо отправлено</div>
|
||||
<div v-if="team.participationStatus !== 'cancelled'">Поездки: {{ team.actionsCount }}</div>
|
||||
<div v-if="team.participationStatus !== 'cancelled'">
|
||||
Поездки: {{ team.actionsCount }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<n-flex justify="end">
|
||||
<n-button v-if="team.participationStatus !== 'cancelled'" @click="openQR(getTeamStoryURL(team.id!, team.password!), 'Подсмотреть игру')">
|
||||
<n-button
|
||||
v-if="team.participationStatus !== 'cancelled'"
|
||||
@click="openQR(getTeamStoryURL(team.id!, team.password!), 'Подсмотреть игру')"
|
||||
>
|
||||
QR
|
||||
</n-button>
|
||||
<n-button v-if="team.participationStatus !== 'cancelled'" @click="toTeamStory(team.id!, team.password!, true)">
|
||||
<n-button
|
||||
v-if="team.participationStatus !== 'cancelled'"
|
||||
@click="toTeamStory(team.id!, team.password!, true)"
|
||||
>
|
||||
Подсмотреть игру
|
||||
</n-button>
|
||||
<n-button type="error" ghost @click="deleteTeam(team)"> Удалить </n-button>
|
||||
</n-flex>
|
||||
</n-flex>
|
||||
|
||||
<n-button v-for="application in team.applications" :key="application.name" class="link-button"
|
||||
@click="giveApplication(team, application)">
|
||||
<n-button
|
||||
v-for="application in team.applications"
|
||||
:key="application.name"
|
||||
class="link-button"
|
||||
@click="giveApplication(team, application)"
|
||||
>
|
||||
Выдать: {{ application.name }}
|
||||
</n-button>
|
||||
</div>
|
||||
@@ -785,23 +904,41 @@ useSimplePolling(() => {
|
||||
|
||||
<!-- Окно настроек -->
|
||||
<n-modal v-model:show="showSettingsModal">
|
||||
<n-card style="width: 600px" title="Настройки игры" :bordered="false" size="huge" role="dialog" aria-modal="true">
|
||||
<n-card
|
||||
style="width: 600px"
|
||||
title="Настройки игры"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<template #header-extra>
|
||||
<n-button @click="closeSettings()"> x </n-button>
|
||||
</template>
|
||||
<n-space vertical>
|
||||
<p>Название</p>
|
||||
<n-input v-model:value="settingsDraft.name" type="text" placeholder='Дело №0 "Следствие ведут овечки"' />
|
||||
<n-input
|
||||
v-model:value="settingsDraft.name"
|
||||
type="text"
|
||||
placeholder='Дело №0 "Следствие ведут овечки"'
|
||||
/>
|
||||
|
||||
<p class="settings-header">Формат игры</p>
|
||||
<n-select
|
||||
v-model:value="settingsDraft.format"
|
||||
:options="[{ label: 'Online', value: 'online' }, { label: 'Offline', value: 'offline' }]"
|
||||
:options="[
|
||||
{ label: 'Online', value: 'online' },
|
||||
{ label: 'Offline', value: 'offline' },
|
||||
]"
|
||||
aria-label="Формат игры"
|
||||
/>
|
||||
|
||||
<p class="settings-header">Описание</p>
|
||||
<n-input v-model:value="settingsDraft.description" type="textarea" placeholder="Убийство пастуха..." />
|
||||
<n-input
|
||||
v-model:value="settingsDraft.description"
|
||||
type="textarea"
|
||||
placeholder="Убийство пастуха..."
|
||||
/>
|
||||
</n-space>
|
||||
<template #footer>
|
||||
<n-flex justify="end">
|
||||
@@ -813,7 +950,14 @@ useSimplePolling(() => {
|
||||
|
||||
<!-- Окно выдачи улик -->
|
||||
<n-modal v-model:show="showGiveApplicationModal">
|
||||
<n-card style="width: 600px" title="Настройки игры" :bordered="false" size="huge" role="dialog" aria-modal="true">
|
||||
<n-card
|
||||
style="width: 600px"
|
||||
title="Настройки игры"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<template #header-extra>
|
||||
<n-button @click="showGiveApplicationModal = false"> x </n-button>
|
||||
</template>
|
||||
@@ -824,22 +968,38 @@ useSimplePolling(() => {
|
||||
<p>Улика</p>
|
||||
<h3>{{ giveApplicationApplication.name }}</h3>
|
||||
|
||||
<div v-if="
|
||||
applicationFileType(giveApplicationApplication) == 'image' &&
|
||||
giveApplicationApplication.image
|
||||
" class="give-application-image-block">
|
||||
<img :src="applicationFileURL(giveApplicationApplication.image)" class="give-application-image" />
|
||||
<div
|
||||
v-if="
|
||||
applicationFileType(giveApplicationApplication) == 'image' &&
|
||||
giveApplicationApplication.image
|
||||
"
|
||||
class="give-application-image-block"
|
||||
>
|
||||
<img
|
||||
:src="applicationFileURL(giveApplicationApplication.image)"
|
||||
class="give-application-image"
|
||||
/>
|
||||
</div>
|
||||
<audio v-else-if="
|
||||
applicationFileType(giveApplicationApplication) == 'audio' &&
|
||||
giveApplicationApplication.image
|
||||
" :src="applicationFileURL(giveApplicationApplication.image)" controls preload="none"
|
||||
class="give-application-audio"></audio>
|
||||
<a v-else-if="
|
||||
applicationFileType(giveApplicationApplication) == 'pdf' &&
|
||||
giveApplicationApplication.image
|
||||
" :href="applicationFileURL(giveApplicationApplication.image)" target="_blank" rel="noopener"
|
||||
class="give-application-pdf-link">
|
||||
<audio
|
||||
v-else-if="
|
||||
applicationFileType(giveApplicationApplication) == 'audio' &&
|
||||
giveApplicationApplication.image
|
||||
"
|
||||
:src="applicationFileURL(giveApplicationApplication.image)"
|
||||
controls
|
||||
preload="none"
|
||||
class="give-application-audio"
|
||||
></audio>
|
||||
<a
|
||||
v-else-if="
|
||||
applicationFileType(giveApplicationApplication) == 'pdf' &&
|
||||
giveApplicationApplication.image
|
||||
"
|
||||
:href="applicationFileURL(giveApplicationApplication.image)"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
class="give-application-pdf-link"
|
||||
>
|
||||
PDF
|
||||
</a>
|
||||
</n-space>
|
||||
@@ -853,7 +1013,14 @@ useSimplePolling(() => {
|
||||
|
||||
<!-- Окно создания команды -->
|
||||
<n-modal v-model:show="showAddTeamModal">
|
||||
<n-card style="width: 600px" title="Создание команды" :bordered="false" size="huge" role="dialog" aria-modal="true">
|
||||
<n-card
|
||||
style="width: 600px"
|
||||
title="Создание команды"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<template #header-extra>
|
||||
<n-button @click="showAddTeamModal = false"> x </n-button>
|
||||
</template>
|
||||
@@ -868,7 +1035,14 @@ useSimplePolling(() => {
|
||||
|
||||
<!-- Окно создания команды -->
|
||||
<n-modal v-model:show="showDeleteTeamModal">
|
||||
<n-card style="width: 600px" title="Удаление команды" :bordered="false" size="huge" role="dialog" aria-modal="true">
|
||||
<n-card
|
||||
style="width: 600px"
|
||||
title="Удаление команды"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<template #header-extra>
|
||||
<n-button @click="showDeleteTeamModal = false"> x </n-button>
|
||||
</template>
|
||||
@@ -892,7 +1066,14 @@ useSimplePolling(() => {
|
||||
|
||||
<!-- Окно удаления игры -->
|
||||
<n-modal v-model:show="showDeleteGameModal">
|
||||
<n-card style="width: 600px" title="Удаление игры" :bordered="false" size="huge" role="dialog" aria-modal="true">
|
||||
<n-card
|
||||
style="width: 600px"
|
||||
title="Удаление игры"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<template #header-extra>
|
||||
<n-button @click="showDeleteGameModal = false"> x </n-button>
|
||||
</template>
|
||||
@@ -901,7 +1082,11 @@ useSimplePolling(() => {
|
||||
Введите название игры
|
||||
<n-text class="name-text" strong>{{ game.name }}</n-text> чтобы удалить её
|
||||
</p>
|
||||
<n-input v-model:value="deletedGameName" type="text" placeholder='Дело №0 "Следствие ведут овечки"' />
|
||||
<n-input
|
||||
v-model:value="deletedGameName"
|
||||
type="text"
|
||||
placeholder='Дело №0 "Следствие ведут овечки"'
|
||||
/>
|
||||
</n-space>
|
||||
|
||||
<template #footer>
|
||||
@@ -916,7 +1101,14 @@ useSimplePolling(() => {
|
||||
|
||||
<!-- Окно qr -->
|
||||
<n-modal v-model:show="showQR">
|
||||
<n-card style="width: 600px" :title="titleQR" :bordered="false" size="huge" role="dialog" aria-modal="true">
|
||||
<n-card
|
||||
style="width: 600px"
|
||||
:title="titleQR"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<template #header-extra>
|
||||
<n-button @click="showQR = false"> x </n-button>
|
||||
</template>
|
||||
@@ -932,8 +1124,15 @@ useSimplePolling(() => {
|
||||
|
||||
<!-- Окно ответов команд и оценки -->
|
||||
<n-modal v-model:show="showAnswersModal">
|
||||
<n-card style="width: min(94vw, 900px)" title="Ответы команд" :bordered="false" size="huge" role="dialog"
|
||||
aria-modal="true" :content-style="{ maxHeight: '70vh', overflow: 'auto' }">
|
||||
<n-card
|
||||
style="width: min(94vw, 900px)"
|
||||
title="Ответы команд"
|
||||
:bordered="false"
|
||||
size="huge"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
:content-style="{ maxHeight: '70vh', overflow: 'auto' }"
|
||||
>
|
||||
<template #header-extra>
|
||||
<n-button @click="showAnswersModal = false"> x </n-button>
|
||||
</template>
|
||||
@@ -952,9 +1151,12 @@ useSimplePolling(() => {
|
||||
<div class="answers-team-answer">
|
||||
{{ teamAnswer(team, question.code) || '—' }}
|
||||
</div>
|
||||
<n-input-number :value="scores[scoreKey(team.team?.id, question.code)]"
|
||||
@update:value="onScoreUpdate(scoreKey(team.team?.id, question.code), $event)" placeholder="Балл"
|
||||
class="answers-score-input" />
|
||||
<n-input-number
|
||||
:value="scores[scoreKey(team.team?.id, question.code)]"
|
||||
@update:value="onScoreUpdate(scoreKey(team.team?.id, question.code), $event)"
|
||||
placeholder="Балл"
|
||||
class="answers-score-input"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
@@ -1161,7 +1363,9 @@ useSimplePolling(() => {
|
||||
}
|
||||
|
||||
.map-canvas {
|
||||
background-image: linear-gradient(rgb(255 255 255 / 8%) 1px, transparent 1px), linear-gradient(90deg, rgb(255 255 255 / 8%) 1px, transparent 1px);
|
||||
background-image:
|
||||
linear-gradient(rgb(255 255 255 / 8%) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgb(255 255 255 / 8%) 1px, transparent 1px);
|
||||
background-size: 20px 20px;
|
||||
height: 1000px;
|
||||
position: absolute;
|
||||
@@ -1192,7 +1396,7 @@ useSimplePolling(() => {
|
||||
|
||||
.map-item small {
|
||||
display: block;
|
||||
opacity: .75;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.map-item button {
|
||||
@@ -1205,5 +1409,7 @@ useSimplePolling(() => {
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
}
|
||||
.map-hidden-items { margin-top: 10px; }
|
||||
.map-hidden-items {
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user