2023-07-26 16:55:19 +08:00
|
|
|
<script setup lang="ts">
|
|
|
|
import { onBeforeMount, ref, watch } from 'vue';
|
|
|
|
import Map from './components/Map.vue'
|
|
|
|
import Mark from './components/mapChild/Mark.vue'
|
|
|
|
import useMarks, { markType } from './hook/useMarks.ts'
|
|
|
|
import ThemeSwitch from './components/ThemeSwitch.vue'
|
|
|
|
import MarkMenu from './components/left/MarkMenu.vue'
|
2023-08-01 09:47:25 +08:00
|
|
|
import CtrlMenu from './components/left/CtrlMenu.vue'
|
2023-07-26 16:55:19 +08:00
|
|
|
import { mdiLanConnect } from '@quasar/extras/mdi-v7'
|
|
|
|
import { useWindowSize } from '@vueuse/core';
|
2023-08-01 09:47:25 +08:00
|
|
|
import { Config } from './hook/useConfig';
|
2023-07-26 16:55:19 +08:00
|
|
|
|
|
|
|
|
|
|
|
const map = ref<InstanceType<typeof Map>>(); // 获取地图的实例 纂取实例方法
|
|
|
|
const marks = useMarks([{ latlng: [39.92647400, 116.40328300], title: '北京故宫', opacity: 1 }])
|
|
|
|
const tab = ref('mark')
|
|
|
|
const sideStyle = ref('20em,logo');
|
|
|
|
const { width } = useWindowSize()
|
2023-08-01 09:47:25 +08:00
|
|
|
const mapConfig = ref()
|
2023-07-26 16:55:19 +08:00
|
|
|
|
|
|
|
onBeforeMount(() => {
|
|
|
|
sideStyle.value = width.value > 600 ? '20em,logo' : '0em,bar'
|
|
|
|
})
|
|
|
|
|
|
|
|
function changeSide(data: string) {
|
|
|
|
const _data = data.split(',')
|
|
|
|
document.body.style.setProperty('--side', _data[0])
|
|
|
|
document.body.style.setProperty('--logoOrBar', _data[1])
|
|
|
|
}
|
|
|
|
watch(sideStyle, changeSide)
|
|
|
|
|
|
|
|
function pushMark(params: any, type: markType) {
|
|
|
|
const { latlng } = params;
|
|
|
|
marks.value.push({ latlng: [latlng.lat, latlng.lng], title: '新标点', opacity: 1, type })
|
|
|
|
}
|
|
|
|
|
|
|
|
function removeMark(index: number) {
|
|
|
|
marks.value.splice(index, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
function flytoMark(index: number) {
|
2023-08-01 09:47:25 +08:00
|
|
|
mapConfig.value.center = marks.value[index].latlng
|
2023-07-26 16:55:19 +08:00
|
|
|
}
|
|
|
|
|
2023-08-01 09:47:25 +08:00
|
|
|
function ctrlMap(e: Config) {
|
|
|
|
mapConfig.value = e
|
2023-07-26 16:55:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
<h5 class="logo">离线地图</h5>
|
2023-08-01 09:47:25 +08:00
|
|
|
<Map ref="map" v-slot="{ contextmenu }" v-model="mapConfig">
|
2023-07-26 16:55:19 +08:00
|
|
|
<q-menu touch-position context-menu>
|
|
|
|
<q-list dense style="min-width: 100px">
|
|
|
|
<q-item clickable v-close-popup>
|
|
|
|
<q-item-section @click="pushMark(contextmenu, 'localtion')">添加标点</q-item-section>
|
|
|
|
</q-item>
|
|
|
|
<q-item clickable v-close-popup>
|
|
|
|
<q-item-section @click="pushMark(contextmenu, 'equipment')">添加设备</q-item-section>
|
|
|
|
</q-item>
|
|
|
|
</q-list>
|
|
|
|
</q-menu>
|
|
|
|
<Mark v-for="(mark, i) in marks" :key="i" :latlng="mark.latlng" :title="mark.title" :opacity="mark.opacity"
|
|
|
|
:ref="`mark-${i}`">
|
|
|
|
<template v-if="mark.type === 'equipment'">
|
|
|
|
<q-icon :name="mdiLanConnect" size="md"></q-icon>
|
|
|
|
</template>
|
|
|
|
</Mark>
|
|
|
|
</Map>
|
|
|
|
<div class="bar">
|
|
|
|
|
|
|
|
<ThemeSwitch></ThemeSwitch>
|
|
|
|
</div>
|
|
|
|
<div class="left ">
|
|
|
|
<q-toggle class="leftctl" v-model="sideStyle" true-value="20em,logo" false-value="0em,bar" />
|
|
|
|
<q-tabs v-model="tab" dense active-color="primary" indicator-color="primary" align="justify" narrow-indicator>
|
|
|
|
<q-tab name="mark" label="标点" />
|
|
|
|
<q-tab name="ctrl" label="控制" />
|
|
|
|
</q-tabs>
|
|
|
|
<q-tab-panels v-model="tab" animated keep-alive>
|
|
|
|
<q-tab-panel name="mark">
|
|
|
|
<MarkMenu :marks="marks" @flyTo="flytoMark" @remove="removeMark"></MarkMenu>
|
|
|
|
</q-tab-panel>
|
|
|
|
<q-tab-panel name="ctrl">
|
|
|
|
<CtrlMenu @change="ctrlMap"></CtrlMenu>
|
|
|
|
</q-tab-panel>
|
|
|
|
</q-tab-panels>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
.logo {
|
|
|
|
margin: unset;
|
|
|
|
grid-area: var(--logoOrBar, logo);
|
|
|
|
will-change: filter;
|
|
|
|
transition: filter 300ms;
|
|
|
|
align-self: center;
|
|
|
|
text-align: center;
|
|
|
|
}
|
|
|
|
|
|
|
|
.logo:hover {
|
|
|
|
filter: drop-shadow(0 0 2em #646cffaa);
|
|
|
|
}
|
|
|
|
|
|
|
|
.logo.vue:hover {
|
|
|
|
filter: drop-shadow(0 0 2em #42b883aa);
|
|
|
|
}
|
|
|
|
|
|
|
|
.left {
|
|
|
|
grid-area: left;
|
|
|
|
overflow: auto;
|
|
|
|
user-select: none;
|
|
|
|
|
|
|
|
.leftctl {
|
|
|
|
position: absolute;
|
|
|
|
top: 0px;
|
|
|
|
left: 10px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.bar {
|
|
|
|
grid-area: bar;
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: flex-end;
|
|
|
|
margin-right: 20px;
|
|
|
|
}
|
|
|
|
</style>
|