This commit is contained in:
2026-09-16 02:46:07 +07:00
parent 3b383596fa
commit 521306f376
99 changed files with 3223 additions and 2914 deletions
+52 -6
View File
@@ -57,6 +57,33 @@ const game = ref<Game>({
scenario: undefined,
teams: undefined,
})
const participationFilter = ref('all')
const participationOptions = [
{ label: 'Все команды', value: 'all' },
{ label: 'Ожидает ответа', value: 'pending' },
{ label: 'Подтверждено', value: 'confirmed' },
{ label: 'Отменено', value: 'cancelled' },
]
const participationSummary = computed(() =>
participationOptions.slice(1).map((option) => {
const teams = (game.value.teams || []).filter(
(team) => team.participationStatus === option.value,
)
return {
...option,
count: teams.length,
participants: teams.reduce((sum, team) => sum + (team.participantsCount || 0), 0),
}
}),
)
const activeTeamCount = computed(
() => (game.value.teams || []).filter((team) => team.participationStatus !== 'cancelled').length,
)
const visibleTeams = computed(() =>
(game.value.teams || []).filter(
(team) => participationFilter.value === 'all' || team.participationStatus === participationFilter.value,
),
)
const screens = ref<ScreenState[]>([])
const mapItems = ref<MapItem[]>([])
const mapSaving = ref(false)
@@ -308,6 +335,10 @@ const giveApplicationTeam = ref<Team>({
applications: [],
captainEmail: undefined,
participantsCount: undefined,
participationStatus: undefined,
participationSource: undefined,
participationEmailError: undefined,
participationEmailSent: undefined,
})
const deletedTeamName = ref('')
@@ -320,6 +351,10 @@ const deletedTeam = ref<Team>({
applications: [],
captainEmail: undefined,
participantsCount: undefined,
participationStatus: undefined,
participationSource: undefined,
participationEmailError: undefined,
participationEmailSent: undefined,
})
const giveApplicationApplication = ref<Application>({
@@ -570,7 +605,7 @@ useSimplePolling(() => {
<div class="settings-block">
<n-flex justify="space-between">
<n-space>
<n-tag :bordered="false" type="info"> Команд: {{ game.teams?.length }} </n-tag>
<n-tag :bordered="false" type="info"> Участвуют команд: {{ activeTeamCount }} </n-tag>
<n-tag type="info">
{{ timeString }}
</n-tag>
@@ -588,7 +623,7 @@ useSimplePolling(() => {
</Icon>
Итоги
</n-button>
<n-button v-if="game.teams?.length" 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()">
@@ -705,7 +740,14 @@ useSimplePolling(() => {
<p class="place-image-plus">+</p>
</div>
<div v-for="team in game.teams" :key="team.id" class="team-block">
<n-space vertical>
<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-space>
<div v-for="team in visibleTeams" :key="team.id" class="team-block">
<div class="team-content-block">
<n-flex justify="space-between">
<div class="title-block">
@@ -714,14 +756,18 @@ useSimplePolling(() => {
<small v-if="team.captainEmail"> — {{ team.captainEmail }}</small>
<small v-if="team.participantsCount"> · Участников: {{ team.participantsCount }}</small>
</span>
<div>Поездки: {{ team.actionsCount }}</div>
<div>{{ 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.participationEmailSent">Письмо отправлено</div>
<div v-if="team.participationStatus !== 'cancelled'">Поездки: {{ team.actionsCount }}</div>
</div>
<n-flex justify="end">
<n-button @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 @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>