This commit is contained in:
2026-10-01 14:20:30 +07:00
parent da7f9505d0
commit 38bad7fd00
102 changed files with 667 additions and 661 deletions
+2 -2
View File
@@ -32,8 +32,8 @@ getScenarios()
<div
class="scenario-block"
v-for="scenario in scenarios"
@click="toScenarioInfo(scenario.id!)"
v-bind:key="scenario.id"
@click="toScenarioInfo(scenario.ID!)"
v-bind:key="scenario.ID"
>
<div
class="scenario-image-block scenario-image"
+66 -66
View File
@@ -69,7 +69,7 @@ const issuedTickets = ref<Ticket[]>([])
const isIssuingTickets = ref(false)
const game = ref<Game>({
id: undefined,
ID: undefined,
name: undefined,
description: undefined,
startAt: undefined,
@@ -92,7 +92,7 @@ const teamsNeedingApplications = computed(
new Map(
(game.value.teams || [])
.filter((team) => team.applications?.length)
.map((team) => [team.id, team]),
.map((team) => [team.ID, team]),
),
)
const screens = ref<ScreenState[]>([])
@@ -135,7 +135,7 @@ let dragState:
let panState: { startX: number; startY: number; offsetX: number; offsetY: number } | undefined
async function getGame(id: number) {
const res = await client.GetGame({ id: id })
const res = await client.GetGame({ ID: id })
if (res.error != '') {
message.error(res.error!)
return
@@ -171,7 +171,7 @@ async function getGame(id: number) {
getGame(Number(gameId))
async function getGameScreens() {
const res = await client.GetGameScreens({ gameId: Number(gameId) })
const res = await client.GetGameScreens({ gameID: Number(gameId) })
if (res.error != '') {
return
}
@@ -182,7 +182,7 @@ async function getGameScreens() {
timerFormInitialized.value = true
}
if (previewScreen.value?.mode === 'SCREEN_MODE_RESULTS') {
const result = await client.GetGameResults({ gameId: Number(gameId) })
const result = await client.GetGameResults({ gameID: Number(gameId) })
if (result.error == '') {
previewQuestions.value = result.questions || []
previewTeams.value = result.teams || []
@@ -196,7 +196,7 @@ getGameScreens()
async function getGameMap() {
if (dragState || mapSaving.value) return
const res = await client.GetGameMap({ gameId: Number(gameId) })
const res = await client.GetGameMap({ gameID: Number(gameId) })
if (res.error == '') mapItems.value = res.items || []
}
getGameMap()
@@ -205,9 +205,9 @@ async function saveMapItem(item: MapItem, hidden = item.hidden) {
mapSaving.value = true
try {
const res = await client.UpdateGameMapItem({
gameId: Number(gameId),
gameID: Number(gameId),
kind: item.kind,
itemId: item.itemId,
itemID: item.itemID,
x: Math.round(item.x || 0),
y: Math.round(item.y || 0),
hidden,
@@ -295,7 +295,7 @@ function zoomMap(event: WheelEvent) {
}
async function setSoundScreen(screen: ScreenState) {
const res = await client.SetScreenSound({ screenId: screen.id, soundEnabled: true })
const res = await client.SetScreenSound({ screenID: screen.ID, soundEnabled: true })
if (res.error != '') {
message.error(res.error!)
return
@@ -304,7 +304,7 @@ async function setSoundScreen(screen: ScreenState) {
}
async function unbindScreen(screen: ScreenState) {
const res = await client.UnbindScreen({ screenId: screen.id })
const res = await client.UnbindScreen({ screenID: screen.ID })
if (res.error != '') {
message.error(res.error!)
return
@@ -313,7 +313,7 @@ async function unbindScreen(screen: ScreenState) {
}
async function setScreenMode(mode: ScreenMode) {
const res = await client.SetScreenMode({ gameId: Number(gameId), mode })
const res = await client.SetScreenMode({ gameID: Number(gameId), mode })
if (res.error != '') message.error(res.error || 'Не удалось изменить режим экранов')
}
@@ -325,7 +325,7 @@ async function configureScreenTimer() {
return
}
const res = await client.SetScreenTimer({
gameId: Number(gameId),
gameID: Number(gameId),
durationSeconds: Math.round(durationMinutes * 60),
label,
})
@@ -341,7 +341,7 @@ async function sendScreenCommand(command: ScreenCommand) {
if (!window.confirm('Запустить медиа на всех экранах?')) return
}
const res = await client.SendScreenCommand({
gameId: Number(gameId),
gameID: Number(gameId),
command,
positionMs: Math.max(0, Math.round(screenPosition.value * 1000)),
volume: Math.max(0, Math.min(100, Math.round(screenVolume.value))),
@@ -362,7 +362,7 @@ async function downloadTeamQR() {
if (isDownloadingQR.value || !game.value.teams?.length) return
isDownloadingQR.value = true
try {
const { blob, filename } = await binaryClient.downloadTeamQR(game.value.id!)
const { blob, filename } = await binaryClient.downloadTeamQR(game.value.ID!)
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
@@ -398,24 +398,24 @@ function closeSettings() {
async function updateGame() {
const res = await client.UpdateGame({
id: game.value.id,
ID: game.value.ID,
name: settingsDraft.value.name,
description: settingsDraft.value.description,
format: settingsDraft.value.format,
location: settingsDraft.value.location.trim(),
startAt: game.value.startAt,
scenarioId: game.value.scenario?.id,
scenarioID: game.value.scenario?.ID,
})
if (res.error != '') {
message.error(res.error!)
return
}
await getGame(game.value.id!)
await getGame(game.value.ID!)
showSettingsModal.value = false
}
const giveApplicationTeam = ref<Team>({
id: 0,
ID: 0,
name: '',
status: '',
password: '',
@@ -431,7 +431,7 @@ const giveApplicationTeam = ref<Team>({
const deletedTeamName = ref('')
const deletedTeam = ref<Team>({
id: 0,
ID: 0,
name: '',
status: '',
password: '',
@@ -461,7 +461,7 @@ function giveApplication(team: Team, application: Application) {
async function addTeam() {
const res = await client.AddTeam({
gameId: game.value.id,
gameID: game.value.ID,
name: newTeamName.value,
captainEmail: newTeamEmail.value.trim(),
})
@@ -469,21 +469,21 @@ async function addTeam() {
message.error(res.error!)
return
}
await getGame(game.value.id!)
await getGame(game.value.ID!)
showAddTeamModal.value = false
newTeamEmail.value = ''
}
async function confirmGiveApplication() {
const res = await client.GiveTeamApplications({
id: giveApplicationTeam.value.id,
ID: giveApplicationTeam.value.ID,
name: giveApplicationApplication.value.name,
})
if (res.error != '') {
message.error(res.error!)
return
}
await getGame(game.value.id!)
await getGame(game.value.ID!)
showGiveApplicationModal.value = false
}
@@ -494,19 +494,19 @@ async function deleteTeam(team: Team) {
async function confirmDeleteTeam() {
const res = await client.DeleteTeam({
id: deletedTeam.value.id,
ID: deletedTeam.value.ID,
})
if (res.error != '') {
message.error(res.error!)
return
}
await getGame(game.value.id!)
await getGame(game.value.ID!)
showDeleteTeamModal.value = false
}
async function deleteGame() {
const res = await client.DeleteGame({
id: game.value.id,
ID: game.value.ID,
})
if (res.error != '') {
message.error(res.error!)
@@ -533,11 +533,11 @@ function openIssueTickets() {
}
async function issueTickets() {
if (isIssuingTickets.value || !game.value.id) return
if (isIssuingTickets.value || !game.value.ID) return
isIssuingTickets.value = true
try {
const res = await client.IssueGameTickets({
gameId: game.value.id,
gameID: game.value.ID,
count: ticketCount.value,
})
if (res.error != '') {
@@ -561,57 +561,57 @@ useSimplePolling(() => {
async function resetGame() {
const res = await client.ResetGame({
id: game.value.id,
ID: game.value.ID,
})
if (res.error != '') {
message.error(res.error!)
return
}
await getGame(game.value.id!)
await getGame(game.value.ID!)
}
async function startGame() {
const res = await client.StartGame({
id: game.value.id,
ID: game.value.ID,
})
if (res.error != '') {
message.error(res.error!)
return
}
await getGame(game.value.id!)
await getGame(game.value.ID!)
}
async function pauseGame() {
const res = await client.PauseGame({
id: game.value.id,
ID: game.value.ID,
})
if (res.error != '') {
message.error(res.error!)
return
}
await getGame(game.value.id!)
await getGame(game.value.ID!)
}
async function playGame() {
const res = await client.PlayGame({
id: game.value.id,
ID: game.value.ID,
})
if (res.error != '') {
message.error(res.error!)
return
}
await getGame(game.value.id!)
await getGame(game.value.ID!)
}
async function finishGame() {
const res = await client.FinishGame({
id: game.value.id,
ID: game.value.ID,
})
if (res.error != '') {
message.error(res.error!)
return
}
await getGame(game.value.id!)
await getGame(game.value.ID!)
}
// ===== Ответы команд и оценка организатором =====
@@ -623,11 +623,11 @@ const reviewsCount = ref(0)
const answersQuestions = ref<Question[]>([])
const answersTeams = ref<TeamAnswers[]>([])
// Баллы по ключу "teamId:questionCode" (undefined — балл не выставлен)
// Баллы по ключу "teamID:questionCode" (undefined — балл не выставлен)
const scores = ref<Record<string, number | undefined>>({})
function scoreKey(teamId: number | undefined, questionCode: string | undefined): string {
return (teamId ?? '') + ':' + (questionCode ?? '')
function scoreKey(teamID: number | undefined, questionCode: string | undefined): string {
return (teamID ?? '') + ':' + (questionCode ?? '')
}
function teamAnswer(team: TeamAnswers, questionCode: string | undefined): string {
@@ -639,7 +639,7 @@ function onScoreUpdate(key: string, value: number | null) {
}
async function loadGameAnswers() {
const res = await client.GetGameAnswers({ gameId: Number(gameId) })
const res = await client.GetGameAnswers({ gameID: Number(gameId) })
if (res.error != '') {
message.error(res.error!)
return
@@ -649,7 +649,7 @@ async function loadGameAnswers() {
const next: Record<string, number | undefined> = {}
for (const team of answersTeams.value) {
for (const answer of team.answers || []) {
next[scoreKey(team.team?.id, answer.questionCode)] = answer.score
next[scoreKey(team.team?.ID, answer.questionCode)] = answer.score
}
}
scores.value = next
@@ -662,7 +662,7 @@ async function openAnswersModal() {
async function openReviewsModal() {
showReviewsModal.value = true
const res = await client.GetGameReviewsForModeration({ gameId: Number(gameId) })
const res = await client.GetGameReviewsForModeration({ gameID: Number(gameId) })
if (res.error != '') {
message.error(res.error!)
return
@@ -673,7 +673,7 @@ async function openReviewsModal() {
}
async function moderateReview(review: GameReview, status: string) {
const res = await client.ModerateGameReview({ id: review.id, status })
const res = await client.ModerateGameReview({ ID: review.ID, status })
if (res.error != '') {
message.error(res.error!)
return
@@ -685,9 +685,9 @@ async function moderateReview(review: GameReview, status: string) {
async function saveAllScores() {
for (const question of answersQuestions.value) {
for (const team of answersTeams.value) {
const score = scores.value[scoreKey(team.team?.id, question.code)]
const score = scores.value[scoreKey(team.team?.ID, question.code)]
const res = await client.SetTeamAnswerScore({
id: team.team?.id,
ID: team.team?.ID,
questionCode: question.code,
score: score === undefined || score === null ? undefined : score,
})
@@ -823,9 +823,9 @@ useSimplePolling(() => {
<div v-if="screens.length > 0" class="screens-block">
<p class="screens-title">Экраны</p>
<div v-for="screen in screens" :key="screen.id" class="screen-row">
<div v-for="screen in screens" :key="screen.ID" class="screen-row">
<div>
<div>Экран {{ screen.id }}</div>
<div>Экран {{ screen.ID }}</div>
<div class="screen-status">{{ screen.status }}</div>
<div v-if="screen.error" class="screen-error">{{ screen.error }}</div>
</div>
@@ -948,7 +948,7 @@ useSimplePolling(() => {
<div
v-for="item in mapItems"
v-show="!item.hidden"
:key="`${item.kind}-${item.itemId}`"
:key="`${item.kind}-${item.itemID}`"
class="map-item"
:class="[
item.kind === 'screen'
@@ -958,7 +958,7 @@ useSimplePolling(() => {
: 'map-team',
{
'map-team-needs-applications':
item.kind === 'team' && teamsNeedingApplications.has(item.itemId),
item.kind === 'team' && teamsNeedingApplications.has(item.itemID),
},
]"
:style="{ left: `${item.x || 0}px`, top: `${item.y || 0}px` }"
@@ -971,15 +971,15 @@ useSimplePolling(() => {
/>
<span>{{ item.label }}</span>
<n-space
v-if="item.kind === 'team' && teamsNeedingApplications.has(item.itemId)"
v-if="item.kind === 'team' && teamsNeedingApplications.has(item.itemID)"
class="map-team-applications"
vertical
>
<n-button
v-for="application in teamsNeedingApplications.get(item.itemId)?.applications"
v-for="application in teamsNeedingApplications.get(item.itemID)?.applications"
:key="application.name"
size="small"
@click="giveApplication(teamsNeedingApplications.get(item.itemId)!, application)"
@click="giveApplication(teamsNeedingApplications.get(item.itemID)!, application)"
>
Выдать: {{ application.name }}
</n-button>
@@ -1001,7 +1001,7 @@ useSimplePolling(() => {
<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}`"
:key="`hidden-${item.kind}-${item.itemID}`"
size="small"
@click="toggleMapItem(item)"
>
@@ -1025,7 +1025,7 @@ useSimplePolling(() => {
<p class="place-image-plus">+</p>
</div>
<div v-for="team in game.teams" :key="team.id" class="team-block">
<div v-for="team in game.teams" :key="team.ID" class="team-block">
<div class="team-content-block">
<n-flex justify="space-between">
<div class="title-block">
@@ -1055,13 +1055,13 @@ useSimplePolling(() => {
<n-flex justify="end">
<n-button
v-if="team.participationStatus !== 'cancelled'"
@click="openQR(getTeamStoryURL(team.id!, team.password!), 'Подсмотреть игру')"
@click="openQR(getTeamStoryURL(team.ID!, team.password!), 'Подсмотреть игру')"
>
QR
</n-button>
<n-button
v-if="team.participationStatus !== 'cancelled'"
@click="toTeamStory(team.id!, team.password!, true)"
@click="toTeamStory(team.ID!, team.password!, true)"
>
Подсмотреть игру
</n-button>
@@ -1317,10 +1317,10 @@ useSimplePolling(() => {
>
Выпустить
</n-button>
<div v-for="ticket in issuedTickets" :key="ticket.id" class="issued-ticket">
<div>Билет №{{ ticket.id }}</div>
<a :href="ticket.url" target="_blank" rel="noreferrer">Открыть страницу билета</a>
<n-button size="small" @click="openQR(ticket.url!, `Билет №${ticket.id}`)">
<div v-for="ticket in issuedTickets" :key="ticket.ID" class="issued-ticket">
<div>Билет №{{ ticket.ID }}</div>
<a :href="ticket.URL" target="_blank" rel="noreferrer">Открыть страницу билета</a>
<n-button size="small" @click="openQR(ticket.URL!, `Билет №${ticket.ID}`)">
Показать QR
</n-button>
</div>
@@ -1372,7 +1372,7 @@ useSimplePolling(() => {
<p class="answers-question-answer">
Правильный ответ:<br /><span class="correct-answer">{{ question.answer || '—' }}</span>
</p>
<div v-for="team in answersTeams" :key="team.team?.id" class="answers-team-row">
<div v-for="team in answersTeams" :key="team.team?.ID" class="answers-team-row">
<div class="answers-team-name">
{{ team.team?.name }}
</div>
@@ -1380,8 +1380,8 @@ useSimplePolling(() => {
{{ 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)"
:value="scores[scoreKey(team.team?.ID, question.code)]"
@update:value="onScoreUpdate(scoreKey(team.team?.ID, question.code), $event)"
placeholder="Балл"
class="answers-score-input"
/>
@@ -1415,7 +1415,7 @@ useSimplePolling(() => {
<span>{{ reviewsCount ? `${reviewsAverage.toFixed(1)} · ${reviewsCount}` : 'Пока нет отзывов' }}</span>
</n-flex>
<div v-if="gameReviews.length == 0" class="answers-empty">Отзывов пока нет.</div>
<div v-for="review in gameReviews" :key="review.id" class="review-row">
<div v-for="review in gameReviews" :key="review.ID" class="review-row">
<n-flex justify="space-between" align="center">
<strong>{{ review.teamName }}</strong>
<n-tag>{{ review.status }}</n-tag>
+3 -3
View File
@@ -40,7 +40,7 @@ async function loadGameResults() {
needLogin.value = false
sessionIssue.value = false
try {
const res = await client.GetGameResults({ gameId: Number(gameId) })
const res = await client.GetGameResults({ gameID: Number(gameId) })
if (res.error != '') {
// res.error может отсутствовать, если сервер ответил не-Rsp-ошибкой (например, 403)
loadError.value = res.error || 'Не удалось загрузить результаты'
@@ -70,7 +70,7 @@ loadGameResults()
// при ошибке/отсутствии доступа молча пропускаем (заголовок без названия допустим)
async function loadGameName() {
try {
const res = await client.GetGame({ id: Number(gameId) })
const res = await client.GetGame({ ID: Number(gameId) })
gameName.value = res.game?.name || ''
} catch {
// молча: название не критично
@@ -196,7 +196,7 @@ function goBack() {
</tr>
</thead>
<tbody>
<tr v-for="team in teams" :key="team.team?.id">
<tr v-for="team in teams" :key="team.team?.ID">
<td class="place-col">
<span
v-if="team.place != null && team.place >= 1 && team.place <= 3"
+6 -6
View File
@@ -59,8 +59,8 @@ const catalogScenarios = ref<Scenario[]>([])
// Опубликованные сценарии каталога — кандидаты для новой игры
const catalogOptions = computed(() =>
catalogScenarios.value
.filter((scenario) => scenario.status == 'public' && scenario.id != undefined)
.map((scenario) => ({ label: scenario.name || '', value: scenario.id! })),
.filter((scenario) => scenario.status == 'public' && scenario.ID != undefined)
.map((scenario) => ({ label: scenario.name || '', value: scenario.ID! })),
)
async function getCatalogScenarios() {
@@ -109,7 +109,7 @@ async function createGame() {
format: newGameFormat.value,
// Сервер парсит startAt как google.protobuf.Timestamp — нужен RFC 3339 с таймзоной
startAt: new Date(startAtMs).toISOString(),
scenarioId: scenarioId,
scenarioID: scenarioId,
})
if (res.error != '') {
message.error(res.error!)
@@ -117,7 +117,7 @@ async function createGame() {
}
message.success('Игра создана')
showCreateGameModal.value = false
router.push('/games/' + res.id!)
router.push('/games/' + res.ID!)
} catch (err) {
message.error(err instanceof Error ? err.message : 'Не удалось создать игру')
} finally {
@@ -136,7 +136,7 @@ async function createGame() {
</div>
</div>
<div v-for="game in games" :key="game.id" class="game-block" @click="toGame(game.id!)">
<div v-for="game in games" :key="game.ID" class="game-block" @click="toGame(game.ID!)">
<div class="game-title">
{{ game.name }} — {{ game.format === 'offline' ? 'Offline' : 'Online' }}
</div>
@@ -148,7 +148,7 @@ async function createGame() {
</div>
<div v-if="game.location" class="game-date">Место: {{ game.location }}</div>
<div v-if="game.status == 'finish'" class="game-actions">
<n-button size="small" ghost @click.stop="toResults(game.id!)">Результаты</n-button>
<n-button size="small" ghost @click.stop="toResults(game.ID!)">Результаты</n-button>
</div>
</div>
</div>
+2 -2
View File
@@ -20,7 +20,7 @@ async function loadReviews() {
}
async function moderate(review: GameReview, status: string) {
const res = await client.ModerateGameReview({ id: review.id, status })
const res = await client.ModerateGameReview({ ID: review.ID, status })
if (res.error != '') {
message.error(res.error!)
return
@@ -40,7 +40,7 @@ loadReviews()
</div>
<n-card v-if="reviews.length == 0">Очередь отзывов пуста.</n-card>
<n-card v-for="review in reviews" :key="review.id" class="review-card">
<n-card v-for="review in reviews" :key="review.ID" class="review-card">
<n-flex justify="space-between" align="center">
<div>
<div class="review-game">{{ review.gameName }}</div>
+4 -4
View File
@@ -15,7 +15,7 @@ const scenarioId = route.params.id
const reviews = ref<GameReview[]>([])
const scenario = ref<Scenario>({
id: undefined,
ID: undefined,
name: undefined,
story: undefined,
author: undefined,
@@ -28,7 +28,7 @@ const scenario = ref<Scenario>({
})
async function getScenario(id: number) {
const res = await client.GetScenario({ id: id })
const res = await client.GetScenario({ ID: id })
if (res.error != '') {
message.error(res.error!)
return
@@ -38,7 +38,7 @@ async function getScenario(id: number) {
getScenario(Number(scenarioId))
async function getReviews(id: number) {
const res = await client.GetScenarioReviews({ scenarioId: id })
const res = await client.GetScenarioReviews({ scenarioID: id })
if (res.error != '') {
message.error(res.error!)
return
@@ -79,7 +79,7 @@ getReviews(Number(scenarioId))
</div>
<section v-if="reviews.length" class="reviews-section">
<h2 class="reviews-title">Отзывы команд</h2>
<article v-for="review in reviews" :key="review.id" class="review-card">
<article v-for="review in reviews" :key="review.ID" class="review-card">
<div class="review-heading">
<strong>{{ review.teamName }}</strong>
<n-rate :value="review.rating" readonly size="small" />
+32 -32
View File
@@ -50,7 +50,7 @@ const message = useMessage()
const fileList = ref<UploadFileInfo[]>([])
const scenario = ref<Scenario>({
id: undefined,
ID: undefined,
name: undefined,
story: undefined,
author: undefined,
@@ -91,7 +91,7 @@ async function updateConclusion(remove = false) {
if (!file) return
const uploaded = await uploadFile(
file,
'scenarios_' + scenario.value.id + '_conclusion_' + file.name,
'scenarios_' + scenario.value.ID + '_conclusion_' + file.name,
)
if (!uploaded.filename) return
if (uploaded.fileType !== 'video') {
@@ -101,7 +101,7 @@ async function updateConclusion(remove = false) {
video = uploaded.filename
}
const saved = remove ? { text: '', video: '' } : { text: conclusion.value.text, video }
const res = await client.UpdateScenarioConclusion({ id: scenario.value.id, conclusion: saved })
const res = await client.UpdateScenarioConclusion({ ID: scenario.value.ID, conclusion: saved })
if (res.error) {
message.error(res.error!)
return
@@ -147,7 +147,7 @@ const editorQuestions = computed<EditableQuestion[]>(() => {
})
async function getScenario(id: number) {
const res = await client.GetFullScenario({ id: id })
const res = await client.GetFullScenario({ ID: id })
if (res.error != '') {
message.error(res.error!)
return
@@ -170,7 +170,7 @@ async function getScenario(id: number) {
getScenario(Number(scenarioId))
async function deleteScenario(id: number) {
const res = await client.DeleteScenario({ id: id })
const res = await client.DeleteScenario({ ID: id })
if (res.error != '') {
message.error(res.error!)
return
@@ -179,7 +179,7 @@ async function deleteScenario(id: number) {
}
async function publicScenario(id: number) {
const res = await client.PublicScenario({ id: id })
const res = await client.PublicScenario({ ID: id })
if (res.error != '') {
message.error(res.error!)
return
@@ -197,7 +197,7 @@ async function addGame(name: string, id: number) {
location: '',
format: 'online',
startAt: now,
scenarioId: id,
scenarioID: id,
})
if (resAddGame.error != '') {
message.error(resAddGame.error!)
@@ -206,17 +206,17 @@ async function addGame(name: string, id: number) {
const resAddTeam = await client.AddTeam({
name: 'Тестовая команда',
captainEmail: '',
gameId: resAddGame.id!,
gameID: resAddGame.ID!,
})
if (resAddTeam.error != '') {
message.error(resAddTeam.error!)
return
}
router.push('/team-story/' + resAddTeam.id! + '?password=' + resAddTeam.password!)
router.push('/team-story/' + resAddTeam.ID! + '?password=' + resAddTeam.password!)
}
async function draftScenario(id: number) {
const res = await client.DraftScenario({ id: id })
const res = await client.DraftScenario({ ID: id })
if (res.error != '') {
message.error(res.error!)
return
@@ -229,7 +229,7 @@ async function draftScenario(id: number) {
async function downloadArchive() {
isDownloadingArchive.value = true
try {
const { blob, filename } = await archiveClient.downloadScenarioArchive(scenario.value.id!)
const { blob, filename } = await archiveClient.downloadScenarioArchive(scenario.value.ID!)
const url = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
@@ -285,7 +285,7 @@ async function updateScenario() {
if (file == null) {
return
}
const uploaded = await uploadFile(file, 'scenarios_' + scenario.value.id + '_' + file.name)
const uploaded = await uploadFile(file, 'scenarios_' + scenario.value.ID + '_' + file.name)
if (uploaded.filename === '') {
return
}
@@ -293,7 +293,7 @@ async function updateScenario() {
}
const res = await client.UpdateScenario({
id: scenario.value.id,
ID: scenario.value.ID,
name: scenario.value.name,
description: scenario.value.description,
image: resUploadFilename,
@@ -329,7 +329,7 @@ const mode = ref('mini-add')
async function addPlace() {
const res = await client.AddScenarioPlace({
id: scenario.value.id,
ID: scenario.value.ID,
place: {
code: code.value,
name: name.value,
@@ -367,7 +367,7 @@ async function addNotFoundDoors(scenario: Scenario, place: EditablePlace) {
})
if (place == undefined) {
const res = await client.AddScenarioPlace({
id: scenario.id,
ID: scenario.ID,
place: {
code: door.code,
name: door.name,
@@ -401,7 +401,7 @@ async function updatePlace(place: EditablePlace) {
}
const uploaded = await uploadFile(
file,
'scenarios_' + scenario.value.id + '_place_' + place.code + '_' + file.name,
'scenarios_' + scenario.value.ID + '_place_' + place.code + '_' + file.name,
)
if (uploaded.filename === '') {
return
@@ -421,7 +421,7 @@ async function updatePlace(place: EditablePlace) {
}
const uploaded = await uploadFile(
file,
'scenarios_' + scenario.value.id + '_place_' + place.code + '_app_' + file.name,
'scenarios_' + scenario.value.ID + '_place_' + place.code + '_app_' + file.name,
)
if (uploaded.filename === '') {
return
@@ -432,7 +432,7 @@ async function updatePlace(place: EditablePlace) {
await addNotFoundDoors(scenario.value, place)
const res = await client.UpdateScenarioPlace({
id: scenario.value.id,
ID: scenario.value.ID,
code: place.oldCode,
place: place,
})
@@ -447,7 +447,7 @@ async function updatePlace(place: EditablePlace) {
async function deletePlace(place: EditablePlace) {
const res = await client.DeleteScenarioPlace({
id: scenario.value.id,
ID: scenario.value.ID,
code: place.oldCode,
})
if (res.error != '') {
@@ -464,7 +464,7 @@ const questionMode = ref('mini-add')
async function addQuestion() {
const res = await client.AddScenarioQuestion({
id: scenario.value.id,
ID: scenario.value.ID,
question: {
code: newQuestionCode.value,
text: newQuestionText.value,
@@ -492,7 +492,7 @@ async function cancelAddQuestion() {
async function updateQuestion(question: EditableQuestion) {
const res = await client.UpdateScenarioQuestion({
id: scenario.value.id,
ID: scenario.value.ID,
code: question.oldCode,
question: {
code: question.code,
@@ -517,7 +517,7 @@ async function cancelUpdateQuestion(question: EditableQuestion) {
async function deleteQuestion(question: EditableQuestion) {
const res = await client.DeleteScenarioQuestion({
id: scenario.value.id,
ID: scenario.value.ID,
code: question.oldCode,
})
if (res.error != '') {
@@ -544,7 +544,7 @@ async function updateIntro() {
if (file == null) {
return
}
audio = (await uploadFile(file, 'scenarios_' + scenario.value.id + '_intro_' + file.name))
audio = (await uploadFile(file, 'scenarios_' + scenario.value.ID + '_intro_' + file.name))
.filename
if (audio === '') {
return
@@ -554,7 +554,7 @@ async function updateIntro() {
}
const res = await client.UpdateScenarioIntro({
id: scenario.value.id,
ID: scenario.value.ID,
introduction: {
text: intro.value.text,
audio: audio,
@@ -576,7 +576,7 @@ async function updateBackground(remove = false) {
if (!file) return
const uploaded = await uploadFile(
file,
'scenarios_' + scenario.value.id + '_background_' + file.name,
'scenarios_' + scenario.value.ID + '_background_' + file.name,
)
if (!uploaded.filename) return
if (uploaded.fileType !== 'image') {
@@ -585,7 +585,7 @@ async function updateBackground(remove = false) {
}
background = uploaded.filename
}
const res = await client.UpdateScenarioBackground({ id: scenario.value.id, background })
const res = await client.UpdateScenarioBackground({ ID: scenario.value.ID, background })
if (res.error) {
message.error(res.error)
return
@@ -638,7 +638,7 @@ function getRandomComplimentForNastya() {
</n-alert>
<n-alert
v-if="authStore.user?.id == 2"
v-if="authStore.user?.ID == 2"
:title="getRandomComplimentForNastya()"
type="info"
style="margin-bottom: 20px"
@@ -863,7 +863,7 @@ function getRandomComplimentForNastya() {
</p>
<n-button
:loading="isDownloadingArchive"
:disabled="!scenario.id"
:disabled="!scenario.ID"
ghost
@click="downloadArchive()"
>
@@ -872,7 +872,7 @@ function getRandomComplimentForNastya() {
<hr class="settings-hr" />
<p>Создать тестовую игру</p>
<n-button @click="addGame(scenario.name || '', scenario.id!)" ghost>
<n-button @click="addGame(scenario.name || '', scenario.ID!)" ghost>
Создать игру
</n-button>
@@ -906,7 +906,7 @@ function getRandomComplimentForNastya() {
/>
<n-button
v-if="scenario.status != 'public'"
@click="publicScenario(scenario.id!)"
@click="publicScenario(scenario.ID!)"
ghost
:disabled="statusScenarioName != scenario.name"
>
@@ -914,7 +914,7 @@ function getRandomComplimentForNastya() {
</n-button>
<n-button
v-if="scenario.status != 'draft'"
@click="draftScenario(scenario.id!)"
@click="draftScenario(scenario.ID!)"
ghost
:disabled="statusScenarioName != scenario.name"
>
@@ -933,7 +933,7 @@ function getRandomComplimentForNastya() {
placeholder='Дело №0 "Следствие ведут овечки"'
/>
<n-button
@click="deleteScenario(scenario.id!)"
@click="deleteScenario(scenario.ID!)"
type="error"
ghost
:disabled="deletedScenarioName != scenario.name"
+4 -4
View File
@@ -50,7 +50,7 @@ async function addScenario(name: string) {
message.error(res.error!)
return
}
await toScenarioEditor(res.id!)
await toScenarioEditor(res.ID!)
}
async function toScenarioEditor(id: number) {
@@ -76,7 +76,7 @@ async function importScenario() {
}
message.success('Сценарий импортирован из архива')
resetImport()
await toScenarioEditor(res.id!)
await toScenarioEditor(res.ID!)
} catch (err) {
message.error(err instanceof Error ? err.message : 'Не удалось импортировать архив')
} finally {
@@ -111,8 +111,8 @@ getScenarios()
<div
class="scenario-block"
v-for="scenario in scenarios"
@click="toScenarioEditor(scenario.id!)"
v-bind:key="scenario.id"
@click="toScenarioEditor(scenario.ID!)"
v-bind:key="scenario.ID"
>
<div
class="scenario-image-block scenario-image"
+14 -14
View File
@@ -39,7 +39,7 @@ let appliedCommandVersion = 0
let pollTimer: number | null = null
let timerTick: number | null = null
const bindingFlow = computed(() => Boolean(route.query.screenId && route.query.accessToken))
const bindingFlow = computed(() => Boolean(route.query.screenID && route.query.accessToken))
const qrValue = computed(() => {
if (!screenId.value || !accessToken.value) return ''
const url = new URL('/screen', window.location.origin)
@@ -49,8 +49,8 @@ const qrValue = computed(() => {
})
const gameOptions = computed(() =>
games.value.map((game) => ({
label: `${formatGameDateTime(game.startAt).split(',')[0] || 'дата не указана'} — ${game.name || `Игра ${game.id}`}`,
value: game.id!,
label: `${formatGameDateTime(game.startAt).split(',')[0] || 'дата не указана'} — ${game.name || `Игра ${game.ID}`}`,
value: game.ID!,
})),
)
const screenMode = computed(() => state.value?.mode || 'SCREEN_MODE_COVER')
@@ -71,7 +71,7 @@ const screenBackground = computed(() => {
})
function saveSession() {
sessionStorage.setItem(sessionKey, JSON.stringify({ screenId: screenId.value, accessToken: accessToken.value }))
sessionStorage.setItem(sessionKey, JSON.stringify({ screenID: screenId.value, accessToken: accessToken.value }))
}
function syncTimer(value: ScreenState | undefined) {
@@ -100,10 +100,10 @@ function readSession() {
async function createSession() {
const res = await client.CreateScreenSession({})
if (res.error || !res.screenId || !res.accessToken) {
if (res.error || !res.screenID || !res.accessToken) {
throw new Error(res.error || 'Не удалось создать сессию экрана')
}
screenId.value = res.screenId
screenId.value = res.screenID
accessToken.value = res.accessToken
saveSession()
}
@@ -111,11 +111,11 @@ async function createSession() {
async function loadState() {
if (!screenId.value || !accessToken.value) return
try {
const res = await client.GetScreenState({ screenId: screenId.value, accessToken: accessToken.value })
const res = await client.GetScreenState({ screenID: screenId.value, accessToken: accessToken.value })
if (res.error) throw new Error(res.error)
state.value = res.state
syncTimer(state.value)
if (state.value?.gameId && state.value.mode === 'SCREEN_MODE_RESULTS') await loadResults()
if (state.value?.gameID && state.value.mode === 'SCREEN_MODE_RESULTS') await loadResults()
} catch (err) {
message.error(err instanceof Error ? err.message : 'Не удалось получить состояние экрана')
}
@@ -123,7 +123,7 @@ async function loadState() {
async function loadResults() {
if (!screenId.value || !accessToken.value) return
const res = await client.GetScreenResults({ screenId: screenId.value, accessToken: accessToken.value })
const res = await client.GetScreenResults({ screenID: screenId.value, accessToken: accessToken.value })
if (res.error == '') {
resultQuestions.value = res.questions || []
resultTeams.value = res.teams || []
@@ -180,13 +180,13 @@ watch(state, async (value) => {
})
async function bind() {
if (!selectedGameId.value || !route.query.screenId || !route.query.accessToken) return
if (!selectedGameId.value || !route.query.screenID || !route.query.accessToken) return
binding.value = true
try {
const res = await client.BindScreen({
screenId: String(route.query.screenId),
screenID: String(route.query.screenID),
accessToken: String(route.query.accessToken),
gameId: selectedGameId.value,
gameID: selectedGameId.value,
})
if (res.error) throw new Error(res.error)
bindSuccess.value = true
@@ -254,7 +254,7 @@ onUnmounted(() => {
<div v-else class="screen-page">
<div v-if="loading" class="screen-center">Подготовка экрана…</div>
<template v-else>
<div v-if="!state?.gameId" class="screen-center">
<div v-if="!state?.gameID" class="screen-center">
<n-card class="qr-card" title="Подключение экрана">
<div v-if="qrValue" class="screen-qr">
<n-qr-code :value="qrValue" :size="260" :padding="0" />
@@ -283,7 +283,7 @@ onUnmounted(() => {
<table>
<thead><tr><th>Место</th><th>Команда</th><th v-for="question in resultQuestions" :key="question.code">{{ question.code }}</th><th>Сумма</th><th>Ходы</th></tr></thead>
<tbody>
<tr v-for="result in resultTeams" :key="result.team?.id">
<tr v-for="result in resultTeams" :key="result.team?.ID">
<td>{{ result.place }}</td>
<td>{{ result.team?.name }}</td>
<td v-for="question in resultQuestions" :key="question.code">
+1 -1
View File
@@ -100,7 +100,7 @@ onUnmounted(() => {
</tr>
</thead>
<tbody>
<tr v-for="result in teams" :key="result.team?.id">
<tr v-for="result in teams" :key="result.team?.ID">
<td>{{ result.place }}</td>
<td>{{ result.team?.name }}</td>
<td v-for="question in questions" :key="question.code">
+8 -8
View File
@@ -39,7 +39,7 @@ const story = ref<AdvancedStory>({
})
const game = ref<Game | undefined>({
id: undefined,
ID: undefined,
name: undefined,
description: undefined,
startAt: undefined,
@@ -71,7 +71,7 @@ async function getStory() {
const oldStory = story.value
const res = await client.GetTeamStory({
id: Number(teamId),
ID: Number(teamId),
password: password as string,
})
if (res.error != '') {
@@ -122,7 +122,7 @@ getAnswers()
async function addAction(newCode: string) {
const res = await client.AddTeamAction({
id: Number(teamId),
ID: Number(teamId),
password: password as string,
code: newCode,
})
@@ -154,7 +154,7 @@ const answers = ref<Record<string, string>>({})
async function getAnswers() {
const res = await client.GetTeamAnswers({
id: Number(teamId),
ID: Number(teamId),
password: password as string,
})
if (res.error != '') {
@@ -170,7 +170,7 @@ async function getAnswers() {
async function submitAnswers() {
const res = await client.SubmitTeamAnswers({
id: Number(teamId),
ID: Number(teamId),
password: password as string,
answers: (story.value.questions || []).map((question) => ({
questionCode: question.code,
@@ -231,8 +231,8 @@ async function submitReview() {
}
reviewLoading.value = true
const res = await client.CreateGameReview({
gameId: Number(game.value?.id),
teamId: Number(teamId),
gameID: Number(game.value?.ID),
teamID: Number(teamId),
password: password as string,
rating: reviewRating.value,
text: reviewText.value.trim(),
@@ -249,7 +249,7 @@ async function submitReview() {
async function deleteLast() {
const res = await client.DeleteLastTeamAction({
id: Number(teamId),
ID: Number(teamId),
})
if (res.error != '') {
message.error(res.error!)
+9 -9
View File
@@ -35,7 +35,7 @@ async function changePassword() {
}
savingPassword.value = true
try {
await client.ChangeUserPassword({ id: passwordUser.value.id!, newPassword: newPassword.value })
await client.ChangeUserPassword({ ID: passwordUser.value.ID!, newPassword: newPassword.value })
closePasswordForm()
message.success('Пароль изменён')
} catch (err) {
@@ -56,7 +56,7 @@ async function getUsers() {
getUsers()
async function addRole(userId: number, role: string) {
const res = await client.AddUserRole({ id: userId, role: role })
const res = await client.AddUserRole({ ID: userId, role: role })
if (res.error != '') {
message.error(res.error!)
return
@@ -65,7 +65,7 @@ async function addRole(userId: number, role: string) {
}
async function deleteRole(userId: number, role: string) {
const res = await client.DeleteUserRole({ id: userId, role: role })
const res = await client.DeleteUserRole({ ID: userId, role: role })
if (res.error != '') {
message.error(res.error!)
return
@@ -77,7 +77,7 @@ async function deleteRole(userId: number, role: string) {
<template>
<div class="center-block-custom">
<div class="width700">
<div v-for="user in users" v-bind:key="user.id" class="user-block">
<div v-for="user in users" v-bind:key="user.ID" class="user-block">
<div class="user-field">Позывной: {{ user.username }}</div>
<div class="user-field">Почта: {{ user.email }}</div>
<div class="user-field">
@@ -90,20 +90,20 @@ async function deleteRole(userId: number, role: string) {
</div>
<n-flex justify="end" class="roles-buttons-block">
<n-button
v-if="auth.hasRole('admin') && auth.user && user.id !== auth.user.id"
v-if="auth.hasRole('admin') && auth.user && user.ID !== auth.user.ID"
@click="passwordUser = user"
>Изменить пароль</n-button>
<n-button @click="addRole(user.id!, 'author')" v-if="!user.roles?.includes('author')"
<n-button @click="addRole(user.ID!, 'author')" v-if="!user.roles?.includes('author')"
>Сделать автором</n-button
>
<n-button @click="deleteRole(user.id!, 'author')" v-else>Забрать роль автора</n-button>
<n-button @click="deleteRole(user.ID!, 'author')" v-else>Забрать роль автора</n-button>
<n-button
@click="addRole(user.id!, 'organizer')"
@click="addRole(user.ID!, 'organizer')"
v-if="!user.roles?.includes('organizer')"
>Сделать организатором</n-button
>
<n-button @click="deleteRole(user.id!, 'organizer')" v-else
<n-button @click="deleteRole(user.ID!, 'organizer')" v-else
>Забрать роль организатора</n-button
>
</n-flex>