This commit is contained in:
146
components/DeliveryInfo.vue
Normal file
146
components/DeliveryInfo.vue
Normal file
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<ul class="delivery-info">
|
||||
<li v-if="showFullContent" class="delivery-info__item">
|
||||
<Icon class="delivery-info__icon" name="lucide:truck" />
|
||||
<span class="delivery-info__text">Yandex</span>
|
||||
</li>
|
||||
|
||||
<li class="delivery-info__item">
|
||||
<Icon class="delivery-info__icon" name="lucide:map-pin" />
|
||||
<span class="delivery-info__text">{{ checkoutPickupPoint?.address?.full_address }}</span>
|
||||
</li>
|
||||
|
||||
<li class="delivery-info__item">
|
||||
<Icon class="delivery-info__icon" name="lucide:shirt" size="xl" />
|
||||
<span class="delivery-info__text">{{ checkoutPickupPoint?.pickup_services?.is_fitting_allowed ? 'с примеркой' : 'без примерки' }}</span>
|
||||
</li>
|
||||
|
||||
<li class="delivery-info__item">
|
||||
<Icon class="delivery-info__icon" name="lucide:package" />
|
||||
<span class="delivery-info__text">срок хранения — 7 дней</span>
|
||||
</li>
|
||||
|
||||
<li class="delivery-info__item">
|
||||
<UAccordion
|
||||
:items="availableDays"
|
||||
:ui="{
|
||||
body: 'py-0',
|
||||
panel: 'p-0',
|
||||
wrapper: 'space-y-0',
|
||||
}"
|
||||
>
|
||||
<template #schedule="{ item }">
|
||||
<div>
|
||||
<div
|
||||
v-for="(scheduleItem, index) in item.content"
|
||||
:key="index"
|
||||
>
|
||||
<Icon class="delivery-info__icon mr-2" name="lucide:clock" />
|
||||
<span class="mr-2">{{ scheduleItem.dayName }}</span>
|
||||
<span>{{ scheduleItem.timeRange }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</UAccordion>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<UAccordion :items="details" />
|
||||
</li>
|
||||
|
||||
<UButton
|
||||
v-if="showFullContent"
|
||||
class="justify-content-center"
|
||||
label="Привезти сюда"
|
||||
size="xl"
|
||||
@click="nextStep"
|
||||
/>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { AccordionItem } from '@nuxt/ui'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useCheckout } from '~/composables/useCheckout'
|
||||
|
||||
withDefaults(defineProps<{
|
||||
showFullContent?: boolean
|
||||
}>(), {
|
||||
showFullContent: true,
|
||||
})
|
||||
|
||||
const { checkoutPickupPoint, nextStep } = useCheckout()
|
||||
|
||||
const restrictionDays = {
|
||||
1: 'пн',
|
||||
2: 'вт',
|
||||
3: 'ср',
|
||||
4: 'чт',
|
||||
5: 'пт',
|
||||
6: 'сб',
|
||||
7: 'вс',
|
||||
}
|
||||
|
||||
// Функция для форматирования времени с ведущим нулем
|
||||
const formatTime = (time: { hours: number | string, minutes: number | string }): string => {
|
||||
const hours = String(time.hours).padStart(2, '0')
|
||||
const minutes = String(time.minutes).padStart(2, '0')
|
||||
return `${hours}:${minutes}`
|
||||
}
|
||||
|
||||
// Функция для форматирования временного диапазона
|
||||
const formatTimeRange = (timeFrom: { hours: number | string, minutes: number | string }, timeTo: { hours: number | string, minutes: number | string }): string => {
|
||||
return `${formatTime(timeFrom)} - ${formatTime(timeTo)}`
|
||||
}
|
||||
|
||||
// Аккордеон с расписанием - используем слот вместо HTML строки
|
||||
const availableDays = computed(() => {
|
||||
const scheduleItems = checkoutPickupPoint?.value?.schedule?.restrictions?.map((restriction) => {
|
||||
const dayName = restrictionDays[restriction.days[0]]
|
||||
const timeRange = formatTimeRange(restriction.time_from, restriction.time_to)
|
||||
return { dayName, timeRange }
|
||||
}) || []
|
||||
|
||||
return [
|
||||
{
|
||||
label: 'График работы',
|
||||
icon: 'i-lucide:calendar',
|
||||
slot: 'schedule',
|
||||
content: scheduleItems,
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
const details = ref<AccordionItem[]>([
|
||||
{
|
||||
label: 'Подробнее',
|
||||
icon: 'i-lucide:info',
|
||||
content: checkoutPickupPoint?.value?.address?.comment || 'Дополнительная информация о пункте выдачи',
|
||||
},
|
||||
])
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.delivery-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
flex-shrink: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
&__text {
|
||||
flex: 1;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -20,11 +20,11 @@
|
||||
@true-bounds="trueBounds = $event"
|
||||
>
|
||||
<YandexMapMarker
|
||||
v-for="marker in pickupPoints"
|
||||
:key="marker.id"
|
||||
v-for="pickupPoint in pickupPoints"
|
||||
:key="pickupPoint.id"
|
||||
position="top-center left-center"
|
||||
:settings="{ coordinates: [marker.position.longitude, marker.position.latitude] }"
|
||||
@click="centerMap([marker.position.longitude, marker.position.latitude])"
|
||||
:settings="{ coordinates: [pickupPoint.position.longitude, pickupPoint.position.latitude] }"
|
||||
@click="centerMap(pickupPoint)"
|
||||
>
|
||||
<div class="marker">
|
||||
<Icon name="i-lucide-map-pin" class="marker__icon" />
|
||||
@@ -41,9 +41,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { LngLat, LngLatBounds, YMap } from '@yandex/ymaps3-types'
|
||||
import type { LngLatBounds, YMap } from '@yandex/ymaps3-types'
|
||||
import type { YMapLocationRequest } from '@yandex/ymaps3-types/imperative/YMap'
|
||||
import type { YMapClusterer } from '@yandex/ymaps3-types/packages/clusterer'
|
||||
import type { PickupPoint } from '~/server/shared/types/yandex_pvz'
|
||||
import { useGeolocation } from '@vueuse/core'
|
||||
import { computed, shallowRef } from 'vue'
|
||||
import {
|
||||
@@ -53,15 +54,11 @@ import {
|
||||
YandexMapDefaultSchemeLayer,
|
||||
YandexMapMarker,
|
||||
} from 'vue-yandex-maps'
|
||||
import { useCheckout } from '~/composables/useCheckout'
|
||||
|
||||
defineProps<{
|
||||
pickupPoints: {
|
||||
id: string
|
||||
address: string
|
||||
position: { latitude: number, longitude: number }
|
||||
}[]
|
||||
}>()
|
||||
defineProps<{ pickupPoints: PickupPoint[] }>()
|
||||
|
||||
const { setCheckoutPickupPoint, isPickupPointSelected } = useCheckout()
|
||||
const { coords } = useGeolocation()
|
||||
const clusterer = shallowRef<YMapClusterer | null>(null)
|
||||
const trueBounds = ref<LngLatBounds>([[0, 0], [0, 0]])
|
||||
@@ -73,12 +70,15 @@ const location = ref<YMapLocationRequest>({
|
||||
zoom: 2,
|
||||
})
|
||||
|
||||
function centerMap(coordinates: LngLat) {
|
||||
function centerMap(pickupPoint: PickupPoint) {
|
||||
location.value = {
|
||||
center: coordinates,
|
||||
center: [pickupPoint.position.longitude, pickupPoint.position.latitude],
|
||||
zoom: 18,
|
||||
duration: 2500,
|
||||
duration: 500,
|
||||
}
|
||||
|
||||
setCheckoutPickupPoint(pickupPoint)
|
||||
isPickupPointSelected.value = true
|
||||
}
|
||||
|
||||
watch(coords, (newCoords) => {
|
||||
|
||||
Reference in New Issue
Block a user