This commit is contained in:
2026-10-11 13:26:52 +07:00
parent a01fd5c452
commit bdeddf679c
5 changed files with 285 additions and 52 deletions
+105
View File
@@ -15,6 +15,8 @@ import {
NTabPane,
NTabs,
NText,
NUpload,
type UploadFileInfo,
} from 'naive-ui'
import { useMessage } from 'naive-ui'
import { computed, ref } from 'vue'
@@ -54,6 +56,8 @@ import { useUIStore } from '@/stores/ui'
import { applicationFileType, applicationFileURL } from '@/utils/application'
import { formatGameDateTime, parseDateWithoutTimezone } from '@/utils/datetime'
const emit = defineEmits<{ resultsApplied: [] }>()
const client = getAuthClient()
const binaryClient = getBinaryClient()
const isDownloadingQR = ref(false)
@@ -118,6 +122,16 @@ const canExport = computed(
)
const isStartingExport = ref(false)
const isDownloadingPackage = ref(false)
const canDownloadResults = computed(
() =>
uiStore.environment === 'venue' &&
game.value.status === 'finish' &&
authStore.hasAnyRole(['admin', 'organizer', 'developer']),
)
const isDownloadingResults = ref(false)
const isApplyingResults = ref(false)
const resultsFiles = ref<UploadFileInfo[]>([])
const resultsError = ref('')
const participationOptions = [
{ label: 'Ожидает ответа', value: 'pending' },
@@ -516,6 +530,60 @@ async function downloadPackage() {
}
}
function changeResultsFile({ fileList }: { fileList: UploadFileInfo[] }) {
if (isApplyingResults.value) return
resultsFiles.value = fileList.slice(-1)
resultsError.value = ''
}
async function downloadResults() {
if (!canDownloadResults.value || isDownloadingResults.value) return
isDownloadingResults.value = true
try {
const { blob, filename } = await binaryClient.downloadGameResultsPackage(game.value.ID!)
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = filename
document.body.appendChild(link)
link.click()
link.remove()
setTimeout(() => URL.revokeObjectURL(url), 1000)
} catch (err) {
message.error(err instanceof Error ? err.message : 'Не удалось скачать результаты')
} finally {
isDownloadingResults.value = false
}
}
async function applyResults() {
if (!canExport.value || isApplyingResults.value) return
const file = resultsFiles.value[0]?.file
if (!file || file.size === 0) {
resultsError.value = 'Выберите непустой ZIP-файл'
return
}
if (!file.name.toLowerCase().endsWith('.zip')) {
resultsError.value = 'Выберите файл с расширением .zip'
return
}
if (file.size > 1024 ** 3) {
resultsError.value = 'Размер пакета не должен превышать 1 ГиБ'
return
}
isApplyingResults.value = true
resultsError.value = ''
try {
await binaryClient.applyGameResultsPackage(game.value.ID!, file)
message.success('Результаты приняты')
emit('resultsApplied')
} catch (err) {
resultsError.value = err instanceof Error ? err.message : 'Не удалось применить результаты'
} finally {
isApplyingResults.value = false
}
}
async function downloadTeamQR() {
if (isDownloadingQR.value || !game.value.teams?.length) return
isDownloadingQR.value = true
@@ -679,6 +747,7 @@ async function issueTickets() {
}
useSimplePolling(() => {
if (isApplyingResults.value) return
getGame(Number(gameId))
getGameScreens()
getGameMusic()
@@ -905,6 +974,42 @@ useSimplePolling(() => {
<n-button @click="updateGame()">Сохранить изменения</n-button>
</n-flex>
</UiBlock>
<UiBlock v-if="canDownloadResults">
<n-button
:loading="isDownloadingResults"
:disabled="isDownloadingResults"
@click="downloadResults"
>
Скачать результаты
</n-button>
</UiBlock>
<UiBlock v-if="canExport">
<p class="screens-title">Возврат результатов с площадки</p>
<n-space vertical>
<n-alert type="warning">
Команды, билеты, результаты и игровой сценарий будут заменены данными пакета.
Онлайн-правки этих данных потеряются. Оформление и музыка сохраняются.
</n-alert>
<n-upload
:file-list="resultsFiles"
:default-upload="false"
:max="1"
accept=".zip"
:disabled="isApplyingResults"
@change="changeResultsFile"
>
<n-button :disabled="isApplyingResults">Выбрать ZIP результатов</n-button>
</n-upload>
<n-alert v-if="resultsError" type="error" role="alert">{{ resultsError }}</n-alert>
<n-button
:loading="isApplyingResults"
:disabled="isApplyingResults || !resultsFiles.length"
@click="applyResults"
>
Применить ZIP и перезаписать результаты
</n-button>
</n-space>
</UiBlock>
<UiBlock v-if="canExport">
<p class="screens-title">Передача игры на площадку</p>
<n-space vertical>