| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- <template>
- <div class="map-container">
- <v-skeleton-loader v-if="pending" type="image"></v-skeleton-loader>
- <LMap
- v-show="!pending"
- style="height: 350px"
- :zoom="zoom"
- :center="position"
- :use-global-leaflet="false"
- >
- <LTileLayer
- url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
- attribution='&copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors'
- layer-type="base"
- name="OpenStreetMap"
- />
- <LMarker
- :lat-lng="position"
- :draggable="!readonly"
- @update:lat-lng="onPositionUpdate($event)"
- />
- </LMap>
- <v-btn
- v-if="searchButton && !readonly"
- prepend-icon="fas fa-location-dot"
- class="mt-3"
- @click="search()"
- >
- {{ $t('search_gps_button') }}
- </v-btn>
- <div v-if="!pending && gpsResponses.length > 0">
- <div
- v-for="(gpsResponse, key) in gpsResponses"
- :key="key"
- class="address_choices"
- @click="addressChoice(key)"
- >
- {{ gpsResponse['displayName'] }}
- <v-btn prepend-icon="fas fa-map-location" @click="addressChoice(key)"
- >Choisir</v-btn
- >
- </div>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import 'leaflet/dist/leaflet.css'
- import { LMap, LTileLayer, LMarker } from '@vue-leaflet/vue-leaflet'
- import { type ComputedRef, defineProps, type PropType } from 'vue'
- import { LatLng, type PointTuple } from 'leaflet'
- import { useAp2iRequestService } from '~/composables/data/useAp2iRequestService'
- import UrlUtils from '~/services/utils/urlUtils'
- import type { AnyJson, CollectionResponsePromise } from '~/types/data'
- import Country from '~/models/Core/Country'
- import { useEntityManager } from '~/composables/data/useEntityManager'
- const props = defineProps({
- latitude: {
- type: Number as PropType<number | null>,
- required: true,
- },
- longitude: {
- type: Number as PropType<number | null>,
- required: true,
- },
- streetAddress: {
- type: String as PropType<string | null>,
- required: false,
- default: null,
- },
- streetAddressSecond: {
- type: String as PropType<string | null>,
- required: false,
- default: null,
- },
- streetAddressThird: {
- type: String as PropType<string | null>,
- required: false,
- default: null,
- },
- postalCode: {
- type: String as PropType<string | null>,
- required: false,
- default: null,
- },
- addressCity: {
- type: String as PropType<string | null>,
- required: false,
- default: null,
- },
- addressCountryId: {
- type: Number as PropType<number | null>,
- required: false,
- default: null,
- },
- searchButton: {
- type: Boolean,
- required: false,
- default: false,
- },
- readonly: {
- type: Boolean,
- required: false,
- default: false,
- },
- })
- const FRANCE_LATITUDE = 46.603354
- const FRANCE_LONGITUDE = 1.888334
- const { apiRequestService, pending } = useAp2iRequestService()
- const { em } = useEntityManager()
- const position: ComputedRef<PointTuple> = computed(() => {
- return [
- props.latitude || FRANCE_LATITUDE,
- props.longitude || FRANCE_LONGITUDE,
- ]
- })
- const zoom = computed({
- get() {
- return props.latitude && props.latitude != FRANCE_LATITUDE ? 12 : 5
- },
- set(newValue: string) {
- zoom.value = newValue
- },
- })
- const emit = defineEmits(['update:latitude', 'update:longitude'])
- const onPositionUpdate = (event: LatLng): void => {
- emit('update:latitude', event.lat)
- emit('update:longitude', event.lng)
- }
- const gpsResponses: Ref<Array<AnyJson>> = ref([])
- const search = async () => {
- gpsResponses.value = []
- const baseUrl = UrlUtils.join('api', 'gps-coordinate-searching')
- const query: AnyJson = {
- streetAddress: props.streetAddress,
- streetAddressSecond: props.streetAddressSecond,
- streetAddressThird: props.streetAddressThird,
- cp: props.postalCode,
- city: props.addressCity,
- }
- if (props.addressCountryId) {
- const country: Country = em.find(Country, props.addressCountryId)
- query['country'] = country?.name
- }
- const url = UrlUtils.addQuery(baseUrl, query)
- const responses: CollectionResponsePromise = await apiRequestService.get(url)
- if (responses['member'].length > 0) {
- onPositionUpdate(
- new LatLng(
- responses['member'][0]['latitude'],
- responses['member'][0]['longitude'],
- ),
- )
- if (responses['member'].length > 1) {
- zoom.value = 6
- gpsResponses.value = responses['member']
- } else {
- zoom.value = 12
- }
- }
- }
- const addressChoice = (key: number): void => {
- zoom.value = 12
- onPositionUpdate(
- new LatLng(
- gpsResponses.value[key]['latitude'] as number,
- gpsResponses.value[key]['longitude'] as number,
- ),
- )
- }
- </script>
- <style scoped lang="scss">
- .address_choices {
- cursor: pointer;
- width: 60%;
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 0.75rem 1rem;
- border-radius: 0.5rem;
- margin-top: 0.5rem;
- background-color: #f9f9f9;
- transition: background-color 0.2s ease;
- &:hover {
- background-color: #eef3ff;
- }
- .v-btn {
- flex-shrink: 0;
- }
- }
- :deep(.v-skeleton-loader__image) {
- height: 350px;
- }
- :deep(.map_wrap) {
- height: 350px;
- }
- </style>
|