This commit is contained in:
2026-09-10 03:53:10 +07:00
parent 625f7d87fd
commit 4a2a73057c
47 changed files with 288 additions and 49 deletions
+113
View File
@@ -12,6 +12,7 @@ import { getBinaryClient } from '@/api/binary_client'
import type {
Application,
Game,
MapItem,
Question,
ScreenState,
Team,
@@ -54,6 +55,8 @@ const game = ref<Game>({
teams: undefined,
})
const screens = ref<ScreenState[]>([])
const mapItems = ref<MapItem[]>([])
let dragState: { item: MapItem; x: number; y: number } | undefined
async function getGame(id: number) {
const res = await client.GetGame({ id: id })
@@ -100,6 +103,41 @@ async function getGameScreens() {
}
getGameScreens()
async function getGameMap() {
const res = await client.GetGameMap({ gameId: Number(gameId) })
if (res.error == '') mapItems.value = res.items || []
}
getGameMap()
async function saveMapItem(item: MapItem, hidden = item.hidden) {
await client.UpdateGameMapItem({ gameId: Number(gameId), kind: item.kind, itemId: item.itemId, x: item.x, y: item.y, hidden })
}
function startMapDrag(item: MapItem, event: PointerEvent) {
dragState = { item, x: event.clientX, y: event.clientY }
;(event.currentTarget as HTMLElement).setPointerCapture(event.pointerId)
}
function moveMapDrag(event: PointerEvent) {
if (!dragState) return
dragState.item.x = (dragState.item.x || 0) + Math.round(event.clientX - dragState.x)
dragState.item.y = (dragState.item.y || 0) + Math.round(event.clientY - dragState.y)
dragState.x = event.clientX
dragState.y = event.clientY
}
async function endMapDrag() {
if (!dragState) return
const item = dragState.item
dragState = undefined
await saveMapItem(item)
}
async function toggleMapItem(item: MapItem) {
item.hidden = !item.hidden
await saveMapItem(item)
}
async function setSoundScreen(screen: ScreenState) {
const res = await client.SetScreenSound({ screenId: screen.id, soundEnabled: true })
if (res.error != '') {
@@ -280,6 +318,7 @@ async function openQR(url: string, text: string) {
useSimplePolling(() => {
getGame(Number(gameId))
getGameScreens()
getGameMap()
}, 2000)
async function resetGame() {
@@ -523,6 +562,26 @@ useSimplePolling(() => {
</div>
</div>
<div class="map-block">
<p class="screens-title">Карта помещения</p>
<div class="map-field" @pointermove="moveMapDrag" @pointerup="endMapDrag" @pointercancel="endMapDrag">
<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}px`, top: `${item.y}px` }"
@pointerdown="startMapDrag(item, $event)">
<span>{{ item.label }}</span>
<small v-if="item.kind === 'screen'">{{ item.status }}{{ item.soundEnabled ? ' · звук' : '' }}</small>
<button type="button" @pointerdown.stop @click.stop="toggleMapItem(item)">×</button>
</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)">
Добавить {{ item.label }}
</n-button>
</n-space>
</div>
<div class="team-block team-block-hover" @click="showAddTeamModal = true">
<p class="place-image-plus">+</p>
</div>
@@ -901,4 +960,58 @@ useSimplePolling(() => {
color: #f2a2a2;
font-size: 13px;
}
.map-block {
background-color: #222;
border-radius: 10px;
margin: 12px 0;
padding: 16px;
}
.map-field {
background-color: #151515;
border: 1px dashed rgb(255 255 255 / 20%);
height: 420px;
overflow: hidden;
position: relative;
touch-action: none;
}
.map-item {
border-radius: 6px;
cursor: grab;
min-width: 90px;
padding: 8px 24px 8px 10px;
position: absolute;
user-select: none;
}
.map-item:active {
cursor: grabbing;
}
.map-screen {
background-color: #355b75;
}
.map-team {
background-color: #48633a;
}
.map-item small {
display: block;
opacity: .75;
}
.map-item button {
background: transparent;
border: 0;
color: inherit;
cursor: pointer;
font-size: 16px;
position: absolute;
right: 5px;
top: 5px;
}
.map-hidden-items { margin-top: 10px; }
</style>