generated from VLADIMIR/template_frontend
add map
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user