generated from VLADIMIR/template_frontend
182 lines
4.4 KiB
Vue
182 lines
4.4 KiB
Vue
<script setup lang="ts">
|
|
import { getAuthClient } from '@/api/auth_client';
|
|
import type { Game, Place, Story } from '@/api/generated/crabs/evening_detective_server';
|
|
import HeaderMenu from '@/components/HeaderMenu.vue'
|
|
import { NCard, NFlex, NInput, NModal, NSpace, NText, NUpload, NUploadDragger, NAlert, NTag, NButton } from 'naive-ui'
|
|
import { useMessage } from 'naive-ui';
|
|
import { nextTick, onMounted, ref } from 'vue';
|
|
import { useRoute } from 'vue-router';
|
|
import PlaceBlock from '@/components/PlaceBlock.vue'
|
|
import GameInputForm from '@/components/GameInputForm.vue'
|
|
import { useSimplePolling } from '@/composables/useSimplePolling';
|
|
import { useAuthStore } from '@/stores/auth';
|
|
|
|
const authStore = useAuthStore()
|
|
const client = getAuthClient()
|
|
const message = useMessage()
|
|
const route = useRoute()
|
|
const teamId = route.params.id
|
|
const password = route.query.password
|
|
|
|
const newPlacesCount = ref(0)
|
|
|
|
const scrollContainer = ref<HTMLDivElement | null>();
|
|
|
|
const story = ref<AdvancedStory>({
|
|
places: []
|
|
})
|
|
|
|
const game = ref<Game | undefined>({
|
|
id: undefined,
|
|
name: undefined,
|
|
description: undefined,
|
|
startAt: undefined,
|
|
status: undefined,
|
|
scenario: undefined,
|
|
teams: undefined
|
|
})
|
|
|
|
const code = ref('')
|
|
|
|
const isAtBottom = () => {
|
|
const container = scrollContainer.value;
|
|
if (!container) return false;
|
|
|
|
return container.scrollHeight - container.scrollTop - container.clientHeight < 1;
|
|
};
|
|
|
|
async function getStory() {
|
|
const oldStory = story.value
|
|
|
|
const res = await client.GetTeamStory({
|
|
id: Number(teamId),
|
|
password: password as string
|
|
})
|
|
if (res.error != '') {
|
|
message.error(res.error!)
|
|
return
|
|
}
|
|
|
|
game.value = res.game
|
|
|
|
const wasAtBottom = isAtBottom();
|
|
|
|
if (wasAtBottom) {
|
|
newPlacesCount.value = 0
|
|
}
|
|
|
|
const oldCount = story.value.places.length
|
|
|
|
story.value = {
|
|
places: res.story!.places?.map((item, i) => {
|
|
console.log(oldStory?.places[i]?.mode)
|
|
return {
|
|
place: item,
|
|
mode: oldStory?.places[i]?.mode || 'show'
|
|
}
|
|
}) || []
|
|
}
|
|
|
|
const newCount = story.value.places.length
|
|
|
|
if (newCount > oldCount && oldCount != 0) {
|
|
newPlacesCount.value += newCount - oldCount
|
|
}
|
|
|
|
await nextTick();
|
|
if (wasAtBottom && oldCount != 0) {
|
|
const container = scrollContainer.value;
|
|
if (!container) return false;
|
|
container.scrollTop = container.scrollHeight;
|
|
}
|
|
}
|
|
getStory()
|
|
|
|
async function addAction(newCode: string) {
|
|
const res = await client.AddTeamAction({
|
|
id: Number(teamId),
|
|
password: password as string,
|
|
code: newCode
|
|
})
|
|
if (res.error != '') {
|
|
message.error(res.error!)
|
|
return
|
|
}
|
|
await getStory()
|
|
code.value = ''
|
|
|
|
await nextTick();
|
|
newPlacesCount.value = 0
|
|
}
|
|
|
|
type AdvancedStory = {
|
|
places: AdvancedPlace[];
|
|
}
|
|
|
|
type AdvancedPlace = {
|
|
place: Place;
|
|
mode: string;
|
|
}
|
|
|
|
async function deleteLast() {
|
|
const res = await client.DeleteLastTeamAction({
|
|
id: Number(teamId),
|
|
})
|
|
if (res.error != '') {
|
|
message.error(res.error!)
|
|
return
|
|
}
|
|
await getStory()
|
|
code.value = ''
|
|
}
|
|
|
|
useSimplePolling(() => {
|
|
getStory()
|
|
}, 2000);
|
|
|
|
</script>
|
|
|
|
<template>
|
|
<div class="center-block-custom bottom-margin smooth-scroll" ref="scrollContainer">
|
|
<div class="width700">
|
|
<GameInputForm :addAction="addAction" :allPlacesCount="story.places.length"
|
|
:newPlacesCount="newPlacesCount"></GameInputForm>
|
|
|
|
<PlaceBlock :place="advancedPlace.place" v-model:mode="advancedPlace.mode"
|
|
v-for="advancedPlace in story.places" v-bind:key="advancedPlace.place.code" :addAction="addAction">
|
|
</PlaceBlock>
|
|
|
|
<div v-if="authStore.hasRole('author')" class="edit-panel">
|
|
<n-flex justify="end">
|
|
<n-button @click="deleteLast">Удалить последний ход</n-button>
|
|
</n-flex>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<HeaderMenu active="games" />
|
|
</template>
|
|
|
|
<style scoped>
|
|
.bottom-margin {
|
|
height: calc(100dvh - 70px - 76px);
|
|
}
|
|
|
|
.smooth-scroll {
|
|
scroll-behavior: smooth;
|
|
}
|
|
|
|
.edit-panel {
|
|
margin: 30px 0;
|
|
padding: 20px;
|
|
background-color: #222;
|
|
border-radius: 10px;
|
|
}
|
|
|
|
@media (width >=1024px) {
|
|
.bottom-margin {
|
|
height: calc(100dvh - 70px - 76px);
|
|
}
|
|
}
|
|
</style>
|