This commit is contained in:
parent
9f2a6e5dd2
commit
c38b6ba6a9
47
composables/useCheckout.ts
Normal file
47
composables/useCheckout.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { createSharedComposable } from '@vueuse/core'
|
||||
|
||||
export const useCheckout = createSharedComposable(() => {
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
const checkoutSteps = [
|
||||
{
|
||||
step: 1,
|
||||
title: 'delivery',
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
title: 'contacts',
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
title: 'summary',
|
||||
},
|
||||
]
|
||||
|
||||
const currentCheckoutStep = ref(checkoutSteps.find(value => value.title === route.path.split('/').pop()))
|
||||
|
||||
function previewStep() {
|
||||
const findIndex = checkoutSteps.findIndex(value => value.step === currentCheckoutStep?.value.step)
|
||||
if (findIndex !== 0) {
|
||||
currentCheckoutStep.value = checkoutSteps[findIndex - 1]
|
||||
router.push(`/checkout/${currentCheckoutStep?.value.title}`)
|
||||
}
|
||||
}
|
||||
|
||||
function nextStep() {
|
||||
const findIndex = checkoutSteps.findIndex(value => value.step === currentCheckoutStep?.value.step)
|
||||
if (findIndex + 1 !== checkoutSteps.length) {
|
||||
currentCheckoutStep.value = checkoutSteps[findIndex + 1]
|
||||
router.push(`/checkout/${currentCheckoutStep?.value.title}`)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
checkoutSteps,
|
||||
currentCheckoutStep,
|
||||
|
||||
previewStep,
|
||||
nextStep,
|
||||
}
|
||||
})
|
||||
@ -8,5 +8,10 @@
|
||||
"materials": {
|
||||
"cotton": "хлопок",
|
||||
"cotton-polyester": "хлопок-полиэстер"
|
||||
},
|
||||
"checkoutSteps": {
|
||||
"delivery": "Выберите адрес получения заказа",
|
||||
"contacts": "Введите данные получателя",
|
||||
"summary": "Подтвердите заказ"
|
||||
}
|
||||
}
|
||||
69
layouts/checkout.vue
Normal file
69
layouts/checkout.vue
Normal file
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div class="layout">
|
||||
<header class="header">
|
||||
<div class="header__container">
|
||||
<Icon class="cursor-pointer w-6 h-6" name="lucide:arrow-left" @click="previewStep" />
|
||||
|
||||
<h3>
|
||||
Шаг {{ currentCheckoutStep?.step }} из {{ checkoutSteps?.length }}
|
||||
•
|
||||
{{ t(`checkoutSteps.${currentCheckoutStep?.title}`) }}
|
||||
</h3>
|
||||
|
||||
<Icon class="cursor-pointer w-6 h-6" name="lucide:arrow-right" @click="nextStep" />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="main">
|
||||
<UContainer class="container">
|
||||
<slot />
|
||||
</UContainer>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useCheckout } from '../composables/useCheckout'
|
||||
|
||||
const { previewStep, nextStep, currentCheckoutStep, checkoutSteps } = useCheckout()
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.container {
|
||||
--ui-container: 100%;
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
height: 54px;
|
||||
|
||||
&__container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
text-align: center;
|
||||
padding: 0 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
margin-top: 54px;
|
||||
}
|
||||
</style>
|
||||
@ -24,6 +24,7 @@
|
||||
"axios": "^1.12.2",
|
||||
"dayjs": "^1.11.13",
|
||||
"decimal.js": "^10.5.0",
|
||||
"maska": "^3.2.0",
|
||||
"nuxt": "^3.17.6",
|
||||
"swiper": "^12.0.2",
|
||||
"typescript": "^5.6.3",
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
<div>{{ `Товары: ${cart?.line_items?.length}` }}</div>
|
||||
<div>{{ `Сумма: ${cart?.line_items?.length}` }}</div>
|
||||
|
||||
<UButton class="w-100 d-flex" @click="createOrder">
|
||||
<UButton class="w-100 d-flex" @click="router.push(`/checkout/delivery`)">
|
||||
Перейти к оформлению
|
||||
</UButton>
|
||||
</div>
|
||||
@ -23,24 +23,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { IBspb } from '~/server/shared/types/bspb'
|
||||
import { usePostOrdersCreate } from '~/api/mutations/wp/usePostOrdersCreate'
|
||||
import { useCart } from '~/composables'
|
||||
|
||||
const router = useRouter()
|
||||
const { cart } = useCart()
|
||||
const { mutateAsync } = usePostOrdersCreate()
|
||||
|
||||
const createOrder = async () => {
|
||||
router.push(`/order/delivery`)
|
||||
|
||||
await mutateAsync({ line_items: cart.value.line_items })
|
||||
|
||||
const { data } = await useFetch<IBspb>('/api/bspb')
|
||||
|
||||
const redirectUrl = `${data?.value?.order?.hppUrl}?orderId=${data?.value?.order?.id}&password=${data.value?.order?.password}`
|
||||
window.open(redirectUrl, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
109
pages/checkout/contacts.vue
Normal file
109
pages/checkout/contacts.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div class="contacts">
|
||||
<UInput
|
||||
v-model="name"
|
||||
size="xl"
|
||||
placeholder=" "
|
||||
:ui="{ base: 'peer' }"
|
||||
class="relative"
|
||||
>
|
||||
<label
|
||||
class="pointer-events-none absolute left-3 text-base transition-all peer-focus:-top-3 peer-focus:text-highlighted peer-focus:text-sm peer-focus:font-medium" :class="[
|
||||
name
|
||||
? '-top-3 text-sm text-highlighted font-medium'
|
||||
: 'top-3 text-dimmed peer-placeholder-shown:top-2 peer-placeholder-shown:text-base peer-placeholder-shown:text-dimmed',
|
||||
]"
|
||||
>
|
||||
<span class="inline-flex bg-default px-1">Имя</span>
|
||||
</label>
|
||||
</UInput>
|
||||
|
||||
<UInput
|
||||
v-model="surname"
|
||||
size="xl"
|
||||
placeholder=" "
|
||||
:ui="{ base: 'peer' }"
|
||||
class="relative"
|
||||
>
|
||||
<label
|
||||
class="pointer-events-none absolute left-3 text-base transition-all peer-focus:-top-3 peer-focus:text-highlighted peer-focus:text-sm peer-focus:font-medium" :class="[
|
||||
surname
|
||||
? '-top-3 text-sm text-highlighted font-medium'
|
||||
: 'top-3 text-dimmed peer-placeholder-shown:top-2 peer-placeholder-shown:text-base peer-placeholder-shown:text-dimmed',
|
||||
]"
|
||||
>
|
||||
<span class="inline-flex bg-default px-1">Фамилия</span>
|
||||
</label>
|
||||
</UInput>
|
||||
|
||||
<UInput
|
||||
v-model="phone"
|
||||
v-maska="'+7 (###) ###-##-##'"
|
||||
size="xl"
|
||||
placeholder=" "
|
||||
:ui="{ base: 'peer' }"
|
||||
class="relative"
|
||||
>
|
||||
<label
|
||||
class="pointer-events-none absolute left-3 text-base transition-all peer-focus:-top-3 peer-focus:text-highlighted peer-focus:text-sm peer-focus:font-medium" :class="[
|
||||
phone
|
||||
? '-top-3 text-sm text-highlighted font-medium'
|
||||
: 'top-3 text-dimmed peer-placeholder-shown:top-2 peer-placeholder-shown:text-base peer-placeholder-shown:text-dimmed',
|
||||
]"
|
||||
>
|
||||
<span class="inline-flex bg-default px-1">телефон</span>
|
||||
</label>
|
||||
</UInput>
|
||||
|
||||
<UInput
|
||||
v-model="email"
|
||||
size="xl"
|
||||
placeholder=" "
|
||||
:ui="{ base: 'peer' }"
|
||||
class="relative"
|
||||
trailing-icon="i-lucide-at-sign"
|
||||
>
|
||||
<label
|
||||
class="pointer-events-none absolute left-3 text-base transition-all peer-focus:-top-3 peer-focus:text-highlighted peer-focus:text-sm peer-focus:font-medium" :class="[
|
||||
email
|
||||
? '-top-3 text-sm text-highlighted font-medium'
|
||||
: 'top-3 text-dimmed peer-placeholder-shown:top-2 peer-placeholder-shown:text-base peer-placeholder-shown:text-dimmed',
|
||||
]"
|
||||
>
|
||||
<span class="inline-flex bg-default px-1">email</span>
|
||||
</label>
|
||||
</UInput>
|
||||
|
||||
<UButton
|
||||
size="xl"
|
||||
label="продолжить"
|
||||
class="justify-center text-center"
|
||||
@click="nextStep"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useCheckout } from '../../composables/useCheckout'
|
||||
|
||||
const name = ref('')
|
||||
const surname = ref('')
|
||||
const phone = ref('')
|
||||
const email = ref('')
|
||||
|
||||
const { nextStep } = useCheckout()
|
||||
|
||||
definePageMeta({
|
||||
layout: 'checkout',
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.contacts {
|
||||
margin-inline: auto;
|
||||
max-width: 400px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
</style>
|
||||
@ -11,7 +11,6 @@
|
||||
{{ `${point?.address?.street} ${point?.address?.house}` }}
|
||||
<Icon class="pickup-point-item__action" name="lucide:chevron-right" />
|
||||
</div>
|
||||
<pre />
|
||||
</div>
|
||||
<PvzMap ref="mapRef" :pickup-points="data?.points" />
|
||||
</div>
|
||||
@ -32,6 +31,10 @@ const onPickupClick = (point: any) => {
|
||||
mapRef.value?.centerMap(lat, lon)
|
||||
}
|
||||
}
|
||||
|
||||
definePageMeta({
|
||||
layout: 'checkout',
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
30
pages/checkout/summary.vue
Normal file
30
pages/checkout/summary.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<UButton label="СОздать ОредЕр" @click="createOrder" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { IBspb } from '~/server/shared/types/bspb'
|
||||
import { usePostOrdersCreate } from '~/api/mutations/wp/usePostOrdersCreate'
|
||||
import { useCart } from '~/composables'
|
||||
|
||||
const router = useRouter()
|
||||
const { cart } = useCart()
|
||||
const { mutateAsync } = usePostOrdersCreate()
|
||||
|
||||
const createOrder = async () => {
|
||||
await mutateAsync({ line_items: cart.value.line_items })
|
||||
|
||||
const { data } = await useFetch<IBspb>('/api/bspb')
|
||||
|
||||
const redirectUrl = `${data?.value?.order?.hppUrl}?orderId=${data?.value?.order?.id}&password=${data.value?.order?.password}`
|
||||
window.open(redirectUrl, '_blank')
|
||||
}
|
||||
|
||||
definePageMeta({
|
||||
layout: 'checkout',
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@ -1,8 +0,0 @@
|
||||
<template>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
@ -1,10 +0,0 @@
|
||||
<template>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
5
plugins/maska.ts
Normal file
5
plugins/maska.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { vMaska } from 'maska/vue'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
nuxtApp.vueApp.directive('maska', vMaska)
|
||||
})
|
||||
@ -2,17 +2,13 @@ import axios from 'axios'
|
||||
import { defineEventHandler } from 'h3'
|
||||
|
||||
export default defineEventHandler(async () => {
|
||||
const token = 'y2_AgAAAAD04omrAAAPeAAAAAACRpC94Qk6Z5rUTgOcTgYFECJllXYKFx8'
|
||||
const businessId = '216467845'
|
||||
const token = 'ACMA:jSy96waKHy8jbq5NqjlGy77WarNYKOYO8aEgjExw:b9ff0949'
|
||||
|
||||
try {
|
||||
const response = await axios.post(
|
||||
'https://b2b.taxi.tst.yandex.net/api/b2b/platform/pickup-points/list',
|
||||
{
|
||||
filters: {
|
||||
region_ids: [213],
|
||||
},
|
||||
limit: 5,
|
||||
},
|
||||
`https://api.partner.market.yandex.ru/v2/businesses/${businessId}/logistics-points`,
|
||||
{},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user