demo-int-table/admin_front/pages/plan/index.vue

251 lines
9.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import type { FileUploadUploadEvent } from '~/node_modules/primevue/fileupload/FileUpload.d.ts'
import { Grid } from 'pathfinding'
const config = useRuntimeConfig()
const point_array = useState('point_array', () => [[]])
const chunk_size = useState('chunk_size', () => 8)
const threshold = useState('threshold', () => 20)
const grid_redraw = useState<boolean>('grid_redraw', () => false)
const active_point = useState<{ x: number, y: number } | undefined>('active_point', () => undefined)
const target_points = useState<{ x: number, y: number, type: string }[]>('target_points', () => [])
const loading = ref<boolean>(false)
const grid = ref<Grid>()
const startPoint = ref<number[]>()
const endPoint = ref<number[]>()
const startToEndPath = ref()
const selectFile = ref()
const loadingFile = ref(false)
const files = ref([])
const cw = 1920
const ch = 800
const title = ref()
const dataToState = async (data: any) => {
point_array.value = data.np_field
title.value = data.title
if (data.d_size) chunk_size.value = data.d_size
if (data.d_border) threshold.value = data.d_border
try {
const res = await fetch(`${config.public.apiBase}/api/floorplan/${data.id}/points`)
if (res.status !== 200) {
throw new Error()
}
const points = await res.json()
target_points.value = points.points
target_array.value = points.points
} catch (error) {
console.log(error)
target_points.value = []
target_array.value = []
}
}
const onUpload = async (event: FileUploadUploadEvent) => {
try {
const data = JSON.parse(event.xhr.response)
await dataToState(data.response)
} catch (error) {
console.log(error)
}
}
const selectFileEvent = async () => {
loadingFile.value = true
try {
const res = await fetch(`${config.public.apiBase}/api/floorplan/${selectFile.value}`)
if (res.status !== 200) {
throw new Error()
}
const data = await res.json()
await dataToState(data)
} catch (error) {
console.log(error)
}
loadingFile.value = false
}
const loadFiles = async () => {
try {
loadingFile.value = true
const res = await fetch(`${config.public.apiBase}/api/floorplan/`)
if (res.status !== 200) {
throw new Error()
}
const data = await res.json()
files.value = data
} catch (error) {
console.log(error)
}
loadingFile.value = false
}
const openBlocks = ref<string[]>([])
const isBlockOpen = (name: string) => {
return openBlocks.value.includes(name)
}
const toggleBlock = (name: string) => {
if (isBlockOpen(name)) {
openBlocks.value.splice(openBlocks.value.indexOf(name), 1)
} else {
openBlocks.value.push(name)
}
}
const fileBtnClick = async () => {
if (isBlockOpen('upload_file')) {
await loadFiles()
}
toggleBlock('upload_file')
}
const updateValues = async () => {
const res = await fetch(`${config.public.apiBase}/api/floorplan/${selectFile.value}`, {
method: 'PATCH',
headers: {
'Accept': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
title: title.value,
d_size: chunk_size.value,
d_border: threshold.value,
})
})
const data = await res.json()
}
const target_array = ref<{ type: string, title: string, points?: { x: number, y: number } }[]>([])
const target_type = ref('')
const addTargetType = (name: string) => {
target_type.value = name
}
const savePoints = async () => {
const res = await fetch(`${config.public.apiBase}/api/floorplan/${selectFile.value}/points`, {
method: 'POST',
headers: {
'Accept': 'application/json',
"Content-Type": "application/json",
},
body: JSON.stringify({
points: target_array.value
})
})
const data = await res.json()
}
onMounted(async () => {
await loadFiles()
})
watch(grid_redraw, () => {
setTimeout(() => {
loading.value = grid_redraw.value
}, 100)
})
watch(active_point, () => {
if (!active_point.value) return
const t_index = target_array.value.findIndex(el => el.type == target_type.value)
if (t_index !== -1) target_array.value.splice(t_index, 1)
const t = ({ type: target_type.value, title: target_type.value, points: active_point.value })
const t_state_index = target_points.value.findIndex(el => el.type == target_type.value)
if (t_state_index !== -1) target_points.value.splice(t_state_index, 1)
const t_state = ({ type: target_type.value, x: active_point.value.x, y: active_point.value.y })
target_array.value.push(t)
target_points.value.push(t_state)
target_type.value = ''
})
</script>
<template>
<div class="flex flex-col gap-4">
<Panel header="Выбор пресета">
<div class="flex align-center gap-2">
<Dropdown v-model="selectFile" placeholder="Выберите файл" :options="files" optionLabel="title"
optionValue="id" :loading="loadingFile" :disabled="!files.length || loadingFile"
@change="selectFileEvent" />
<Button @click="fileBtnClick()" :disabled="loadingFile">
<span style="display: contents;" v-if="isBlockOpen('upload_file')">
Выбрать план из загруженных
</span>
<span style="display: contents;" v-else>
Загрузить новый план
</span>
</Button>
</div>
</Panel>
<Panel header="Загрузка файла" v-if="isBlockOpen('upload_file')">
<FileUpload mode="basic" name="demo" :url="`${config.public.apiBase}/api/floorplan/`" accept="image/*"
:maxFileSize="10000000" @upload="onUpload" :auto="true" chooseLabel="Выберите файл"
:disabled="loading" />
</Panel>
<Panel header="Данные для координатной сетки">
<p>Рекомендуем использовать сетку с наиболее крупными ячейками</p>
<Divider />
<div class="flex align-middle items-end gap-2">
<div class="flex flex-col">
<label for="title">Название</label>
<InputText id="title" type="text" v-model="title" />
</div>
<div class="flex flex-col">
<label for="chunk">Значение дискретизации</label>
<InputNumber id="chunk_size" showButtons :min="0" :max="50" v-model="chunk_size"
:disabled="loading" />
</div>
<div class="flex flex-col">
<label for="threshold">Пороговое значение</label>
<InputNumber id="threshold" showButtons :min="0" :max="chunk_size * chunk_size" :disabled="loading"
v-model="threshold" />
</div>
<Button @click="updateValues">Сохранить данные</Button>
</div>
</Panel>
<Panel header="Данные о помещениях">
<div class="flex gap-2">
<div class="flex flex-col gap-2">
<Button @click="addTargetType('start')" :icon="target_type == 'start' ? 'pi pi-bullseye' : ''"
:label="`${!target_array.filter(el => el.type == 'start').length ?
`Добавить` : 'Изменить'} точку старта`"></Button>
<Button
@click="addTargetType('cabinet' + (target_array.filter(el => el.type.indexOf('cabinet') !== -1).length + 1))"
:icon="target_type.indexOf('cabinet') !== -1 ? 'pi pi-bullseye' : ''"
label="Добавить точку входа в кабинет"></Button>
</div>
<div class="flex flex-col">
<span v-if="active_point">
active point {{ active_point }}
</span>
<ul>
<li v-for="item in target_array">
{{ item.title }}
{{ item.type }}
{{ item.points }}
</li>
</ul>
<Button v-if="target_array.length > 0" @click="savePoints">
Сохранить данные
</Button>
</div>
</div>
</Panel>
<Panel :header="loading ? `Идет отрисовка` : `Обработанный план здания`">
<div style=" max-width: 100%; overflow: auto; position: relative;">
<FloorplanCanvas :cw="cw" :ch="ch" />
<FloorplanSvg :cw="cw" :ch="ch" />
</div>
</Panel>
</div>
</template>