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": {
|
"materials": {
|
||||||
"cotton": "хлопок",
|
"cotton": "хлопок",
|
||||||
"cotton-polyester": "хлопок-полиэстер"
|
"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",
|
"axios": "^1.12.2",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"decimal.js": "^10.5.0",
|
"decimal.js": "^10.5.0",
|
||||||
|
"maska": "^3.2.0",
|
||||||
"nuxt": "^3.17.6",
|
"nuxt": "^3.17.6",
|
||||||
"swiper": "^12.0.2",
|
"swiper": "^12.0.2",
|
||||||
"typescript": "^5.6.3",
|
"typescript": "^5.6.3",
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
<div>{{ `Товары: ${cart?.line_items?.length}` }}</div>
|
<div>{{ `Товары: ${cart?.line_items?.length}` }}</div>
|
||||||
<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>
|
</UButton>
|
||||||
</div>
|
</div>
|
||||||
@ -23,24 +23,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { IBspb } from '~/server/shared/types/bspb'
|
|
||||||
import { usePostOrdersCreate } from '~/api/mutations/wp/usePostOrdersCreate'
|
|
||||||
import { useCart } from '~/composables'
|
import { useCart } from '~/composables'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { cart } = useCart()
|
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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<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}` }}
|
{{ `${point?.address?.street} ${point?.address?.house}` }}
|
||||||
<Icon class="pickup-point-item__action" name="lucide:chevron-right" />
|
<Icon class="pickup-point-item__action" name="lucide:chevron-right" />
|
||||||
</div>
|
</div>
|
||||||
<pre />
|
|
||||||
</div>
|
</div>
|
||||||
<PvzMap ref="mapRef" :pickup-points="data?.points" />
|
<PvzMap ref="mapRef" :pickup-points="data?.points" />
|
||||||
</div>
|
</div>
|
||||||
@ -32,6 +31,10 @@ const onPickupClick = (point: any) => {
|
|||||||
mapRef.value?.centerMap(lat, lon)
|
mapRef.value?.centerMap(lat, lon)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
layout: 'checkout',
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<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'
|
import { defineEventHandler } from 'h3'
|
||||||
|
|
||||||
export default defineEventHandler(async () => {
|
export default defineEventHandler(async () => {
|
||||||
const token = 'y2_AgAAAAD04omrAAAPeAAAAAACRpC94Qk6Z5rUTgOcTgYFECJllXYKFx8'
|
const businessId = '216467845'
|
||||||
|
const token = 'ACMA:jSy96waKHy8jbq5NqjlGy77WarNYKOYO8aEgjExw:b9ff0949'
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(
|
const response = await axios.post(
|
||||||
'https://b2b.taxi.tst.yandex.net/api/b2b/platform/pickup-points/list',
|
`https://api.partner.market.yandex.ru/v2/businesses/${businessId}/logistics-points`,
|
||||||
{
|
{},
|
||||||
filters: {
|
|
||||||
region_ids: [213],
|
|
||||||
},
|
|
||||||
limit: 5,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user