generated from VLADIMIR/template_frontend
up
This commit is contained in:
@@ -50,6 +50,7 @@ import GameScreensPanel from '@/components/GameScreensPanel.vue'
|
||||
import GameStatePanel from '@/components/GameStatePanel.vue'
|
||||
import GameTeamsPanel from '@/components/GameTeamsPanel.vue'
|
||||
import HeaderMenu from '@/components/HeaderMenu.vue'
|
||||
import TeamReceiptModal from '@/components/TeamReceiptModal.vue'
|
||||
import TicketCheckModal from '@/components/TicketCheckModal.vue'
|
||||
import UiBlock from '@/components/UiBlock.vue'
|
||||
import { useDeviceContext } from '@/composables/useDeviceContext'
|
||||
@@ -108,6 +109,13 @@ const deletedGameName = ref('')
|
||||
const showQR = ref(false)
|
||||
const urlQR = ref('')
|
||||
const titleQR = ref('')
|
||||
const showTeamReceipt = ref(false)
|
||||
const teamReceipt = ref({ name: '', teamID: '' })
|
||||
const isPrintingReceipt = ref(false)
|
||||
const isPreparingReceipt = ref(false)
|
||||
const receiptPreview = ref('')
|
||||
const receiptPreparationError = ref('')
|
||||
let receiptPreparationVersion = 0
|
||||
const showTicketCheckModal = ref(false)
|
||||
const paymentURL =
|
||||
'https://www.sberbank.ru/ru/choise_bank?requisiteNumber=79609361994&bankCode=100000000111'
|
||||
@@ -281,6 +289,8 @@ onMounted(() => {
|
||||
})
|
||||
onUnmounted(() => {
|
||||
isDisposed = true
|
||||
receiptPreparationVersion++
|
||||
clearReceiptPreview()
|
||||
window.removeEventListener('click', enableNotificationSound)
|
||||
window.removeEventListener('keydown', enableNotificationSound)
|
||||
void notificationAudio?.close().catch((error: unknown) => {
|
||||
@@ -892,6 +902,62 @@ function openTeamQR(team: Team) {
|
||||
openQR(getTeamStoryURL(team.ID!, team.password!), 'Подсмотреть игру')
|
||||
}
|
||||
|
||||
function openTeamReceipt(team: Team) {
|
||||
if (
|
||||
uiStore.environment !== 'venue' ||
|
||||
!team.ID ||
|
||||
!team.name ||
|
||||
team.participationStatus === 'cancelled'
|
||||
) {
|
||||
message.error('У команды нет данных для печати чека')
|
||||
return
|
||||
}
|
||||
teamReceipt.value = { name: team.name, teamID: team.ID }
|
||||
showTeamReceipt.value = true
|
||||
}
|
||||
|
||||
watch(
|
||||
[showTeamReceipt, () => teamReceipt.value.teamID, canManageGame, () => uiStore.environment],
|
||||
prepareTeamReceipt,
|
||||
)
|
||||
|
||||
function clearReceiptPreview() {
|
||||
if (receiptPreview.value) URL.revokeObjectURL(receiptPreview.value)
|
||||
receiptPreview.value = ''
|
||||
}
|
||||
|
||||
async function prepareTeamReceipt() {
|
||||
const version = ++receiptPreparationVersion
|
||||
clearReceiptPreview()
|
||||
receiptPreparationError.value = ''
|
||||
isPreparingReceipt.value = false
|
||||
if (!showTeamReceipt.value || !canManageGame.value || uiStore.environment !== 'venue') return
|
||||
isPreparingReceipt.value = true
|
||||
try {
|
||||
const { blob } = await binaryClient.downloadTeamReceipt(Number(gameId), teamReceipt.value.teamID)
|
||||
if (version === receiptPreparationVersion) receiptPreview.value = URL.createObjectURL(blob)
|
||||
} catch (error) {
|
||||
if (version === receiptPreparationVersion)
|
||||
receiptPreparationError.value =
|
||||
error instanceof Error ? error.message : 'Не удалось подготовить чек'
|
||||
} finally {
|
||||
if (version === receiptPreparationVersion) isPreparingReceipt.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function printTeamReceipt() {
|
||||
if (!receiptPreview.value || isPrintingReceipt.value || isPreparingReceipt.value) return
|
||||
isPrintingReceipt.value = true
|
||||
try {
|
||||
await client.PrintTeamReceipt({ gameID: Number(gameId), teamID: teamReceipt.value.teamID })
|
||||
message.success('Чек напечатан')
|
||||
} catch (error) {
|
||||
message.error(error instanceof Error ? error.message : 'Не удалось напечатать чек')
|
||||
} finally {
|
||||
isPrintingReceipt.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function openQR(url: string, text: string) {
|
||||
urlQR.value = url
|
||||
titleQR.value = text
|
||||
@@ -1276,9 +1342,11 @@ useSimplePolling(() => {
|
||||
</n-flex>
|
||||
<GameTeamsPanel
|
||||
:teams="game.teams || []"
|
||||
:can-print-receipts="uiStore.environment === 'venue'"
|
||||
:participation-options="participationOptions"
|
||||
@add="showAddTeamModal = true"
|
||||
@open-qr="openTeamQR"
|
||||
@print="openTeamReceipt"
|
||||
@preview="(id, password) => toTeamStory(id, password, true)"
|
||||
@delete="deleteTeam"
|
||||
@give-application="giveApplication"
|
||||
@@ -1492,6 +1560,16 @@ useSimplePolling(() => {
|
||||
</div>
|
||||
|
||||
<TicketCheckModal v-if="canManageGame" v-model:show="showTicketCheckModal" />
|
||||
<TeamReceiptModal
|
||||
v-if="canManageGame && uiStore.environment === 'venue'"
|
||||
v-model:show="showTeamReceipt"
|
||||
:name="teamReceipt.name"
|
||||
:preview="receiptPreview"
|
||||
:preparation-error="receiptPreparationError"
|
||||
:is-preparing="isPreparingReceipt"
|
||||
:is-printing="isPrintingReceipt"
|
||||
@print="printTeamReceipt"
|
||||
/>
|
||||
|
||||
<!-- Окно выдачи улик -->
|
||||
<n-modal v-if="canManageGame" v-model:show="showGiveApplicationModal">
|
||||
|
||||
@@ -6,12 +6,14 @@ import UiBlock from '@/components/UiBlock.vue'
|
||||
|
||||
defineProps<{
|
||||
teams: Team[]
|
||||
canPrintReceipts: boolean
|
||||
participationOptions: { label: string; value: string }[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
add: []
|
||||
'open-qr': [team: Team]
|
||||
print: [team: Team]
|
||||
preview: [id: string, password: string]
|
||||
delete: [team: Team]
|
||||
'give-application': [team: Team, application: Application]
|
||||
@@ -47,6 +49,12 @@ const emit = defineEmits<{
|
||||
</div>
|
||||
</div>
|
||||
<n-flex justify="end">
|
||||
<n-button
|
||||
v-if="canPrintReceipts && team.participationStatus !== 'cancelled'"
|
||||
@click="emit('print', team)"
|
||||
>
|
||||
Печать чека
|
||||
</n-button>
|
||||
<n-button v-if="team.participationStatus !== 'cancelled'" @click="emit('open-qr', team)"
|
||||
>QR</n-button
|
||||
>
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<script setup lang="ts">
|
||||
import { NAlert, NButton, NCard, NFlex, NModal } from 'naive-ui'
|
||||
|
||||
defineProps<{
|
||||
show: boolean
|
||||
name: string
|
||||
preview: string
|
||||
preparationError: string
|
||||
isPreparing: boolean
|
||||
isPrinting: boolean
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
'update:show': [value: boolean]
|
||||
print: []
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-modal
|
||||
:show="show"
|
||||
:mask-closable="!isPrinting"
|
||||
:close-on-esc="!isPrinting"
|
||||
@update:show="emit('update:show', $event)"
|
||||
>
|
||||
<n-card class="receipt-modal" title="Чек команды" role="dialog" aria-modal="true">
|
||||
<n-alert v-if="preparationError" type="error">{{ preparationError }}</n-alert>
|
||||
<img
|
||||
v-else-if="preview"
|
||||
class="receipt-preview"
|
||||
:src="preview"
|
||||
:alt="`Чек команды ${name}`"
|
||||
/>
|
||||
<p v-else-if="isPreparing">Подготовка чека…</p>
|
||||
<p>Включите MXW01 рядом с сервером площадки. Сервер напечатает один чек.</p>
|
||||
<n-flex justify="end">
|
||||
<n-button :disabled="isPrinting" @click="emit('update:show', false)">Закрыть</n-button>
|
||||
<n-button
|
||||
type="primary"
|
||||
:loading="isPrinting"
|
||||
:disabled="!preview || isPreparing || isPrinting"
|
||||
@click="emit('print')"
|
||||
>Печатать</n-button
|
||||
>
|
||||
</n-flex>
|
||||
</n-card>
|
||||
</n-modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.receipt-modal {
|
||||
max-height: 90vh;
|
||||
max-width: 460px;
|
||||
overflow-y: auto;
|
||||
width: calc(100vw - 32px);
|
||||
}
|
||||
|
||||
.receipt-preview {
|
||||
display: block;
|
||||
height: auto;
|
||||
margin: 0 auto 16px;
|
||||
max-width: 100%;
|
||||
width: 384px;
|
||||
}
|
||||
|
||||
.receipt-modal p {
|
||||
margin: 16px 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user