Merge pull request 'bx-935-calc' (#1) from bx-935-calc into main
Reviewed-on: ksenia_mikhailova/mns-mini-zabor#1
This commit is contained in:
commit
e4a6c95b08
|
@ -39,7 +39,7 @@ const loadAll = async () => {
|
||||||
// pointLight.value.intensity = 0
|
// pointLight.value.intensity = 0
|
||||||
pointLight.value.shadow.camera.near = 50
|
pointLight.value.shadow.camera.near = 50
|
||||||
pointLight.value.shadow.bias = -0.002
|
pointLight.value.shadow.bias = -0.002
|
||||||
|
|
||||||
const k = 5
|
const k = 5
|
||||||
pointLight.value.position.x = pointLight.value.position.x * k
|
pointLight.value.position.x = pointLight.value.position.x * k
|
||||||
pointLight.value.position.y = pointLight.value.position.y * k
|
pointLight.value.position.y = pointLight.value.position.y * k
|
||||||
|
@ -104,10 +104,9 @@ watch([section_count, extra_section], () => {
|
||||||
<ModelParametric />
|
<ModelParametric />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</TresGroup>
|
</TresGroup>
|
||||||
|
|
||||||
<TresMesh receive-shadow :position-y="-3.65" name="ground">
|
<TresMesh receive-shadow :position-y="-3.65" name="ground">
|
||||||
<TresCircleGeometry :args="[50, 32]" :rotate-x="-Math.PI * 0.5" />
|
<TresCircleGeometry :args="[50, 32]" :rotate-x="-Math.PI * 0.5" />
|
||||||
<TresShadowMaterial :opacity="0.2"/>
|
<TresShadowMaterial :opacity="0.2" />
|
||||||
</TresMesh>
|
</TresMesh>
|
||||||
|
|
||||||
<template v-if="pointLight">
|
<template v-if="pointLight">
|
||||||
|
|
|
@ -4,6 +4,7 @@ import type { ralTypes } from '@/components/ral'
|
||||||
|
|
||||||
import { predefLamelleColors, predefPillarColors } from '~/composables/useCalc';
|
import { predefLamelleColors, predefPillarColors } from '~/composables/useCalc';
|
||||||
|
|
||||||
|
const lamelle_height = use_lamelle_height()
|
||||||
const lamelles_count = use_lamelles_count()
|
const lamelles_count = use_lamelles_count()
|
||||||
const fence_section = use_fence_section()
|
const fence_section = use_fence_section()
|
||||||
const remove_pillar = use_remove_pillar()
|
const remove_pillar = use_remove_pillar()
|
||||||
|
@ -17,7 +18,7 @@ const min_length = use_min_length()
|
||||||
const parametric = reactive({
|
const parametric = reactive({
|
||||||
length: {
|
length: {
|
||||||
min: min_length.value,
|
min: min_length.value,
|
||||||
max: 2400,
|
max: 2470,
|
||||||
step: 1,
|
step: 1,
|
||||||
},
|
},
|
||||||
total_length: {
|
total_length: {
|
||||||
|
@ -26,14 +27,14 @@ const parametric = reactive({
|
||||||
step: 0.5,
|
step: 0.5,
|
||||||
},
|
},
|
||||||
height: {
|
height: {
|
||||||
min: 675,
|
min: 20 + lamelle_height.value * 1000 * 5,
|
||||||
max: 2400,
|
max: 20 + lamelle_height.value * 1000 * 20,
|
||||||
step: 115,
|
step: lamelle_height.value * 1000,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const form_state = reactive({
|
const form_state = reactive({
|
||||||
length: fence_section.value * 1000,
|
length: fence_section.value * 1000,
|
||||||
fence_length: 100,
|
fence_length: 104,
|
||||||
height: 100 + lamelles_count.value * parametric.height.step,
|
height: 100 + lamelles_count.value * parametric.height.step,
|
||||||
total_length: total_length.value,
|
total_length: total_length.value,
|
||||||
total_length_mm: fence_section.value * 1000,
|
total_length_mm: fence_section.value * 1000,
|
||||||
|
@ -69,34 +70,45 @@ const changeParametres = () => {
|
||||||
if (form_state.total_length_mm < form_state.length) {
|
if (form_state.total_length_mm < form_state.length) {
|
||||||
form_state.length = form_state.total_length_mm
|
form_state.length = form_state.total_length_mm
|
||||||
}
|
}
|
||||||
|
|
||||||
form_state.total_length_mm = form_state.total_length * 1000
|
form_state.total_length_mm = form_state.total_length * 1000
|
||||||
const total_without_pillar = form_state.total_length_mm - form_state.fence_length
|
|
||||||
|
|
||||||
if (form_state.auto_length) {
|
let { fence_length, total_length_mm, auto_length, length, full_sections } = form_state
|
||||||
|
length = parseFloat(length.toString())
|
||||||
|
|
||||||
|
if (auto_length) {
|
||||||
let w = parametric.length.min
|
let w = parametric.length.min
|
||||||
const max_sections = Math.ceil(total_without_pillar / parametric.length.min)
|
const max_sections = Math.floor((total_length_mm - fence_length) / (parametric.length.min + fence_length))
|
||||||
const min_sections = Math.ceil(total_without_pillar / parametric.length.max)
|
const min_sections = Math.ceil((total_length_mm - fence_length) / (parametric.length.max + fence_length))
|
||||||
|
|
||||||
for (let index = min_sections; index <= max_sections; index++) {
|
for (let index = min_sections; index <= max_sections; index++) {
|
||||||
w = (total_without_pillar / index) + form_state.fence_length
|
full_sections = index
|
||||||
if (w >= parametric.length.min && w <= parametric.length.max) {
|
w = (total_length_mm - fence_length * (index - 1)) / index
|
||||||
|
if (
|
||||||
|
w >= parametric.length.min
|
||||||
|
&& w <= parametric.length.max
|
||||||
|
&& w * index <= total_length_mm
|
||||||
|
) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
form_state.length = w
|
length = w
|
||||||
|
} else {
|
||||||
|
full_sections = Math.floor((total_length_mm - fence_length) / (length + fence_length))
|
||||||
|
if (full_sections == 0) {
|
||||||
|
length = total_length_mm - fence_length - fence_length
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const section_without_pillar = form_state.length - form_state.fence_length
|
if (((full_sections * length) + (full_sections * fence_length) + fence_length) <= total_length_mm) {
|
||||||
|
form_state.extra_section = Math.floor((total_length_mm - fence_length) % length)
|
||||||
form_state.full_sections = Math.floor(total_without_pillar / section_without_pillar)
|
|
||||||
|
|
||||||
if (section_without_pillar * form_state.full_sections !== form_state.full_sections) {
|
|
||||||
form_state.extra_section = Math.floor(total_without_pillar % section_without_pillar)
|
|
||||||
} else {
|
} else {
|
||||||
form_state.extra_section = 0
|
form_state.extra_section = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
form_state.full_sections = full_sections
|
||||||
|
form_state.length = length
|
||||||
|
form_state.fence_length = fence_length
|
||||||
|
|
||||||
total_length.value = form_state.total_length
|
total_length.value = form_state.total_length
|
||||||
lamelles_count.value = lamelles
|
lamelles_count.value = lamelles
|
||||||
fence_section.value = form_state.length * 0.001
|
fence_section.value = form_state.length * 0.001
|
||||||
|
@ -125,77 +137,71 @@ const plurals = {
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="container relative py-4">
|
<div class="container relative py-4">
|
||||||
<ClientOnly fallback-tag="div">
|
<form class="form">
|
||||||
<template #fallback>
|
<div class="col-span-12 lg:col-span-6">
|
||||||
<div class="fallback">
|
<div class="form-row">
|
||||||
Загрузка 3D модели
|
<div class="form-item w-full">
|
||||||
</div>
|
<label for="length">Длина ламельного блока, мм</label>
|
||||||
</template>
|
<input disabled :value="`${form_state.length} мм`" class="w-28" />
|
||||||
<form class="form">
|
<input id="length" type="range" class="w-full" v-bind="parametric.length"
|
||||||
<div class="col-span-12 lg:col-span-6">
|
v-model="form_state.length" :disabled="form_state.auto_length" :ref="form_refs.length" />
|
||||||
<div class="form-row">
|
</div>
|
||||||
<div class="form-item w-full">
|
<div class="form-item w-full">
|
||||||
<label for="length">Длина секции, мм</label>
|
<label for="height">Высота забора, мм</label>
|
||||||
<input disabled :value="`${form_state.length} мм`" class="w-28" />
|
<input disabled :value="`${form_state.height} мм`" class="w-28" />
|
||||||
<input id="length" type="range" class="w-full" v-bind="parametric.length"
|
<input id="height" type="range" class="w-full" v-bind="parametric.height"
|
||||||
v-model="form_state.length" :disabled="form_state.auto_length"
|
v-model="form_state.height" :ref="form_refs.height" />
|
||||||
:ref="form_refs.length" />
|
</div>
|
||||||
</div>
|
<div class="form-item">
|
||||||
<div class="form-item w-full">
|
<label for="total_length">Общая длина забора, м</label>
|
||||||
<label for="height">Высота забора, мм</label>
|
<input type="number" id="total_length" v-bind="parametric.total_length"
|
||||||
<input disabled :value="`${form_state.height} мм`" class="w-28" />
|
v-model="form_state.total_length" :ref="form_refs.total_length" />
|
||||||
<input id="height" type="range" class="w-full" v-bind="parametric.height"
|
</div>
|
||||||
v-model="form_state.height" :ref="form_refs.height" />
|
<div class="form-item form-item_checkbox">
|
||||||
</div>
|
<input id="auto_length" type="checkbox" v-model="form_state.auto_length" />
|
||||||
<div class="form-item">
|
<label for="auto_length">Автоматический подбор секции</label>
|
||||||
<label for="total_length">Общая длина забора, м</label>
|
</div>
|
||||||
<input type="number" id="total_length" v-bind="parametric.total_length"
|
<div class="form-item form-item_checkbox">
|
||||||
v-model="form_state.total_length" :ref="form_refs.total_length" />
|
<input id="remove_pillar" type="checkbox" v-model="form_state.remove_pillar" />
|
||||||
</div>
|
<label for="remove_pillar">Без столбов</label>
|
||||||
<div class="form-item form-item_checkbox">
|
|
||||||
<input id="auto_length" type="checkbox" v-model="form_state.auto_length" />
|
|
||||||
<label for="auto_length">Автоматический подбор секции</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-item form-item_checkbox">
|
|
||||||
<input id="remove_pillar" type="checkbox" v-model="form_state.remove_pillar" />
|
|
||||||
<label for="remove_pillar">Без столбов</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-12 lg:col-span-6">
|
</div>
|
||||||
<div class="form-row">
|
<div class="col-span-12 lg:col-span-6">
|
||||||
<div class="form-item">
|
<div class="form-row">
|
||||||
<label for="lamelle_color">Цвет ламелей</label>
|
<div class="form-item">
|
||||||
<input id="lamelle_color" type="text" :value="getColorNameFromRal(lamelle_color)"
|
<label for="lamelle_color">Цвет ламелей</label>
|
||||||
class="w-60" disabled />
|
<input id="lamelle_color" type="text" :value="getColorNameFromRal(lamelle_color)" class="w-60"
|
||||||
<ColorPicker :cb="setLamelleColor" />
|
disabled />
|
||||||
</div>
|
<ColorPicker :cb="setLamelleColor" />
|
||||||
<div class="form-item">
|
</div>
|
||||||
<template v-for="item in predefLamelleColors">
|
<div class="form-item">
|
||||||
<ColorPicker :color="item" :cb="setLamelleColor" :open="false"
|
<template v-for="item in predefLamelleColors">
|
||||||
:active="lamelle_color == item" />
|
<ColorPicker :color="item" :cb="setLamelleColor" :open="false"
|
||||||
</template>
|
:active="lamelle_color == item" />
|
||||||
</div>
|
</template>
|
||||||
<div class="form-item">
|
</div>
|
||||||
<label for="pillar_color">Цвет столба</label>
|
<div class="form-item">
|
||||||
<input id="pillar_color" type="text" :value="getColorNameFromRal(pillar_color)" class="w-60"
|
<label for="pillar_color">Цвет столба</label>
|
||||||
disabled />
|
<input id="pillar_color" type="text" :value="getColorNameFromRal(pillar_color)" class="w-60"
|
||||||
<ColorPicker :cb="setPillarColor" />
|
disabled />
|
||||||
</div>
|
<ColorPicker :cb="setPillarColor" />
|
||||||
<div class="form-item">
|
</div>
|
||||||
<template v-for="item in predefPillarColors">
|
<div class="form-item">
|
||||||
<ColorPicker :color="item" :cb="setPillarColor" :open="false"
|
<template v-for="item in predefPillarColors">
|
||||||
:active="pillar_color == item" />
|
<ColorPicker :color="item" :cb="setPillarColor" :open="false"
|
||||||
</template>
|
:active="pillar_color == item" />
|
||||||
</div>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-12 lg:col-span-8 prose min-w-full">
|
</div>
|
||||||
|
<div class="col-span-12 lg:col-span-8 prose min-w-full">
|
||||||
|
<template v-if="(form_state.total_length * 1000) >= parametric.length.min">
|
||||||
<p>
|
<p>
|
||||||
Забор общей длиной {{ form_state.total_length }}{{ '\xa0' }}м,
|
Забор общей длиной {{ form_state.total_length }}{{ '\xa0' }}м,
|
||||||
{{ section_count }}
|
{{ section_count }}
|
||||||
<Plural :n="section_count" :forms="plurals.section" /> по
|
<Plural :n="section_count" :forms="plurals.section" /> по
|
||||||
{{ `${parseInt(form_state.length).toFixed(2)}\xa0мм` }}{{
|
{{ `${parseFloat(form_state.length.toString()).toFixed(2)}\xa0мм` }}{{
|
||||||
form_state.extra_section ? ` и 1 дополнительная секция
|
form_state.extra_section ? ` и 1 дополнительная секция
|
||||||
длиной ${form_state.extra_section.toFixed(2)}\xa0мм` : '' }}.
|
длиной ${form_state.extra_section.toFixed(2)}\xa0мм` : '' }}.
|
||||||
</p>
|
</p>
|
||||||
|
@ -206,7 +212,7 @@ const plurals = {
|
||||||
</template>
|
</template>
|
||||||
{{ section_count * lamelles_count }}
|
{{ section_count * lamelles_count }}
|
||||||
<Plural :n="section_count * lamelles_count" :forms="plurals.lamelle" />
|
<Plural :n="section_count * lamelles_count" :forms="plurals.lamelle" />
|
||||||
{{ `длиной ${parseInt(form_state.length).toFixed(2)}\xa0мм` }}<template
|
{{ `длиной ${parseFloat(form_state.length.toString()).toFixed(2)}\xa0мм` }}<template
|
||||||
v-if="form_state.extra_section">
|
v-if="form_state.extra_section">
|
||||||
{{ ` и ${~~(!!form_state.extra_section.toFixed(2)) * lamelles_count}` }}
|
{{ ` и ${~~(!!form_state.extra_section.toFixed(2)) * lamelles_count}` }}
|
||||||
<Plural :n="~~(!!form_state.extra_section) * lamelles_count" :forms="plurals.lamelle" />
|
<Plural :n="~~(!!form_state.extra_section) * lamelles_count" :forms="plurals.lamelle" />
|
||||||
|
@ -214,21 +220,21 @@ const plurals = {
|
||||||
</template>.
|
</template>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Все элементы окрашиваются порошковым методом: <br />
|
Окрашивается по технологии порошковой окраски: <br />
|
||||||
ламели: {{ getColorNameFromRal(lamelle_color)?.toLowerCase() }};
|
ламели: {{ getColorNameFromRal(lamelle_color)?.toLowerCase() }};
|
||||||
столбы: {{ getColorNameFromRal(pillar_color)?.toLowerCase() }}.
|
столбы: {{ getColorNameFromRal(pillar_color)?.toLowerCase() }}.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</template>
|
||||||
<div class="prose col-span-4">
|
</div>
|
||||||
<p v-if="form_state.extra_section" class="text-ioprim">
|
<div class="prose col-span-4">
|
||||||
Внимание! Дополнительная секция приводит к увеличению стоимости.
|
<p v-if="form_state.extra_section" class="text-ioprim">
|
||||||
Рекомендуем вам изменить длину забора или длину секции!
|
Внимание! Дополнительная секция приводит к увеличению стоимости.
|
||||||
</p>
|
Рекомендуем вам изменить длину забора или длину секции!
|
||||||
</div>
|
</p>
|
||||||
<div class="form-row justify-center">
|
</div>
|
||||||
<button @click.prevent="toggleModal">Купить прямо сейчас</button>
|
<div class="form-row justify-center">
|
||||||
</div>
|
<button @click.prevent="toggleModal">Рассчитать прямо сейчас</button>
|
||||||
</form>
|
</div>
|
||||||
</ClientOnly>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
|
@ -31,7 +31,7 @@ onUnmounted(() => {
|
||||||
<div>
|
<div>
|
||||||
<div class="color_picker" ref="picker">
|
<div class="color_picker" ref="picker">
|
||||||
<div class="color_picker-selected" @click="open ? toggleOpen(!isOpenPicker) : onClick(props.color)"
|
<div class="color_picker-selected" @click="open ? toggleOpen(!isOpenPicker) : onClick(props.color)"
|
||||||
:style="[{ backgroundColor: getColorHexFromRal(props.color) ?? '' }]"
|
:style="[props.color && { backgroundColor: getColorHexFromRal(props.color) ?? '' }]"
|
||||||
:class="[{ 'color_picker-selected__active': active }]"></div>
|
:class="[{ 'color_picker-selected__active': active }]"></div>
|
||||||
<div class="color_picker-changer flex flex-wrap" v-if="isOpenPicker">
|
<div class="color_picker-changer flex flex-wrap" v-if="isOpenPicker">
|
||||||
<template v-for="col in ralClassicPallette">
|
<template v-for="col in ralClassicPallette">
|
||||||
|
|
|
@ -4,7 +4,7 @@ const apiBase = config.public.apiBase
|
||||||
import k_logo from '@/assets/icons/logo.svg'
|
import k_logo from '@/assets/icons/logo.svg'
|
||||||
|
|
||||||
const { data: footerData } = await useFetch<ApiFooterType[]>(`${apiBase}/footer/?ordering=small_text`)
|
const { data: footerData } = await useFetch<ApiFooterType[]>(`${apiBase}/footer/?ordering=small_text`)
|
||||||
const { data: social_networkData } = await useFetch<ApiSocial_networkType[]>(`${apiBase}/social_network/`)
|
const { data: social_networkData } = await useFetch<ApiSocial_networkType[]>(`${apiBase}/social_network/`)
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="footer" id="contacts">
|
<div class="footer" id="contacts">
|
||||||
|
|
|
@ -4,10 +4,11 @@ import type { ralTypes } from '@/components/ral'
|
||||||
|
|
||||||
const config = useRuntimeConfig()
|
const config = useRuntimeConfig()
|
||||||
const apiBase = config.public.apiBase
|
const apiBase = config.public.apiBase
|
||||||
const { data: calculatorData } = await useFetch(`${apiBase}/calculator/5/`)
|
const { data: calculatorData } = await useFetch<ApiCalcType>(`${apiBase}/calculator/5/`)
|
||||||
|
|
||||||
const isModalOpen = useState('modal_open', () => false)
|
const isModalOpen = useState('modal_open', () => false)
|
||||||
|
|
||||||
|
const lamelle_height = useState<number>('lamelle_height')
|
||||||
const lamelles_count = useState<number>('lamelles_count')
|
const lamelles_count = useState<number>('lamelles_count')
|
||||||
const fence_section = useState<number>('fence_section')
|
const fence_section = useState<number>('fence_section')
|
||||||
const pillar_color = useState<ralTypes>('pillar_color')
|
const pillar_color = useState<ralTypes>('pillar_color')
|
||||||
|
@ -18,6 +19,7 @@ const total_length = useState('total_length')
|
||||||
const remove_pillar = useState<boolean>('remove_pillar')
|
const remove_pillar = useState<boolean>('remove_pillar')
|
||||||
|
|
||||||
const toggleModal = () => {
|
const toggleModal = () => {
|
||||||
|
modal_data.email = undefined
|
||||||
modal_data.phone = undefined
|
modal_data.phone = undefined
|
||||||
modal_data.name = undefined
|
modal_data.name = undefined
|
||||||
modal_state.show_form = false
|
modal_state.show_form = false
|
||||||
|
@ -26,8 +28,10 @@ const toggleModal = () => {
|
||||||
type modalDataType = {
|
type modalDataType = {
|
||||||
phone?: string
|
phone?: string
|
||||||
name?: string
|
name?: string
|
||||||
|
email?: string
|
||||||
}
|
}
|
||||||
const modal_data = reactive<modalDataType>({
|
const modal_data = reactive<modalDataType>({
|
||||||
|
email: undefined,
|
||||||
phone: undefined,
|
phone: undefined,
|
||||||
name: undefined
|
name: undefined
|
||||||
})
|
})
|
||||||
|
@ -48,19 +52,16 @@ const validateInput = (evt: KeyboardEvent) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const validate = () => {
|
const validate = () => {
|
||||||
const phone_regexp = /^\+?[\d\s-()]{0,14}\d{11}$/
|
const phone_regexp = /^\+?[\d\s-()]{0,14}\d{11}$/
|
||||||
const email_regex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/
|
const email_regex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/
|
||||||
|
|
||||||
if (!modal_data.phone) {
|
modal_form.disabled = true
|
||||||
modal_form.disabled = true
|
if (
|
||||||
return
|
(modal_data.phone && phone_regexp.test(modal_data.phone))
|
||||||
}
|
|| (modal_data.email && email_regex.test(modal_data.email))
|
||||||
if (modal_data.phone.length < 3) {
|
) {
|
||||||
modal_form.disabled = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (phone_regexp.test(modal_data.phone) || email_regex.test(modal_data.phone)) {
|
|
||||||
modal_form.disabled = false
|
modal_form.disabled = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -74,6 +75,7 @@ const submit = (e: any) => {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name: modal_data.name || `ref from site ${new Date}`,
|
name: modal_data.name || `ref from site ${new Date}`,
|
||||||
phone: modal_data.phone,
|
phone: modal_data.phone,
|
||||||
|
email: modal_data.email,
|
||||||
fence_info: [
|
fence_info: [
|
||||||
...Object.values(total_txt.value).map(el => el.join('\n')),
|
...Object.values(total_txt.value).map(el => el.join('\n')),
|
||||||
total_colors.value.join('\n')
|
total_colors.value.join('\n')
|
||||||
|
@ -82,7 +84,7 @@ const submit = (e: any) => {
|
||||||
})
|
})
|
||||||
modal_data.phone = undefined
|
modal_data.phone = undefined
|
||||||
modal_data.name = undefined
|
modal_data.name = undefined
|
||||||
isModalOpen.value = false
|
toggleModal()
|
||||||
}
|
}
|
||||||
const roubleSign = new Intl.NumberFormat('ru-RU', {
|
const roubleSign = new Intl.NumberFormat('ru-RU', {
|
||||||
style: 'currency',
|
style: 'currency',
|
||||||
|
@ -95,43 +97,39 @@ const total_colors = computed(() => {
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
const total_txt = computed(() => {
|
const total_txt = computed(() => {
|
||||||
let { mortgage, pillar, lamella, rivets, bar, guide } = calculatorData.value
|
if (!calculatorData.value) return
|
||||||
mortgage = parseFloat(mortgage)
|
const pillar = parseFloat(calculatorData.value.pillar)
|
||||||
pillar = parseFloat(pillar)
|
const pillar_base = parseFloat(calculatorData.value.pillar_base)
|
||||||
lamella = parseFloat(lamella)
|
const lamelles_block = parseFloat(calculatorData.value.lamelles_block)
|
||||||
rivets = parseFloat(rivets)
|
const { discount } = calculatorData.value
|
||||||
bar = parseFloat(bar)
|
|
||||||
guide = parseFloat(guide)
|
|
||||||
const sections = section_count.value as number
|
const sections = section_count.value as number
|
||||||
const extra_m = extra_section.value as number * 0.001
|
const extra_m = extra_section.value as number * 0.001
|
||||||
const length_m = fence_section.value as number
|
const length_m = fence_section.value as number
|
||||||
const lam_count = lamelles_count.value as number
|
const lam_count = lamelles_count.value as number
|
||||||
|
|
||||||
const prices = {
|
let discountValue = 1
|
||||||
pillar: mortgage + pillar,
|
discount.forEach(element => {
|
||||||
lamella: rivets * 2 + lamella * length_m,
|
if (sections >= element.min_quantity) {
|
||||||
lamella_extra: rivets * 2 + lamella * extra_m,
|
if (element.max_quantitt && sections >= element.max_quantitt) return
|
||||||
guide: guide * lam_count * 0.115,
|
discountValue -= element.percent * 0.01
|
||||||
top: bar * length_m,
|
}
|
||||||
top_extra: bar * extra_m
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
const prices = {
|
||||||
|
pillar: discountValue * ((pillar * lam_count * lamelle_height.value) + pillar_base),
|
||||||
|
lam_quad_regular: discountValue * lamelles_block * lam_count * lamelle_height.value * length_m,
|
||||||
|
lam_quad_extra: discountValue * lamelles_block * lam_count * lamelle_height.value * extra_m,
|
||||||
|
}
|
||||||
|
// console.log(prices)
|
||||||
const extra = {
|
const extra = {
|
||||||
pillar: !remove_pillar.value && {
|
pillar: !remove_pillar.value && {
|
||||||
txt: `Дополнительная секция, столб, 1 шт`,
|
txt: `Дополнительная секция, столб, 1 шт`,
|
||||||
value: prices.pillar * 1
|
value: prices.pillar * 1
|
||||||
},
|
},
|
||||||
lamella: {
|
lamella: {
|
||||||
txt: `Дополнительная секция, ламели, ${lam_count} шт`,
|
txt: `Блок ламелей с направляющей, 1 шт`,
|
||||||
value: prices.lamella_extra * lam_count
|
value: prices.lam_quad_extra * 1
|
||||||
},
|
|
||||||
guide: {
|
|
||||||
txt: `Направляющие, 2 шт`,
|
|
||||||
value: prices.guide * 2
|
|
||||||
},
|
|
||||||
top: {
|
|
||||||
txt: `Верхняя планка`,
|
|
||||||
value: prices.top * 1
|
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -141,18 +139,10 @@ const total_txt = computed(() => {
|
||||||
value: prices.pillar * (1 + sections)
|
value: prices.pillar * (1 + sections)
|
||||||
},
|
},
|
||||||
lamella: {
|
lamella: {
|
||||||
txt: `Ламели, ${(lam_count * sections)} шт`,
|
txt: `Блок ламелей с направляющей, ${sections} шт`,
|
||||||
value: prices.lamella * (lam_count * sections)
|
value: prices.lam_quad_regular * sections
|
||||||
},
|
},
|
||||||
guide: {
|
};
|
||||||
txt: `Направляющие, ${(2 * sections)} шт`,
|
|
||||||
value: prices.guide * (2 * sections)
|
|
||||||
},
|
|
||||||
top: {
|
|
||||||
txt: `Верхняя планка ${(1 + sections)} шт`,
|
|
||||||
value: prices.top * sections
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const total = [extra, regular].map(item => Object.values(item).map(el => el ? el.value : 0)).flat().reduce((a, b) => a + b, 0)
|
const total = [extra, regular].map(item => Object.values(item).map(el => el ? el.value : 0)).flat().reduce((a, b) => a + b, 0)
|
||||||
|
|
||||||
|
@ -176,11 +166,13 @@ const total_txt = computed(() => {
|
||||||
<div class="modal">
|
<div class="modal">
|
||||||
<template v-if="modal_state.show_form">
|
<template v-if="modal_state.show_form">
|
||||||
<h2>Оставьте контакты для связи </h2>
|
<h2>Оставьте контакты для связи </h2>
|
||||||
<form @submit.prevent="submit">
|
<form @submit.prevent="submit" ref="form">
|
||||||
<input type="text" placeholder="Ваше имя" v-model="modal_data.name" @keyup="validate" />
|
<input type="text" placeholder="Ваше имя" v-model="modal_data.name" @keyup="validate" />
|
||||||
<input type="phone" placeholder="Номер телефона или e-mail" v-model="modal_data.phone"
|
<input type="phone" placeholder="Ваш номер телефона" v-model="modal_data.phone"
|
||||||
@keypress="validateInput" @keyup="validate" />
|
@keypress="validateInput" @keyup="validate" />
|
||||||
{{ total_txt.total[0] }}
|
<input type="e-mail" placeholder="Ваш e-mail" v-model="modal_data.email" @keypress="validateInput"
|
||||||
|
@keyup="validate" />
|
||||||
|
{{ total_txt && total_txt.total[0] }}
|
||||||
<div class="flex gap-4">
|
<div class="flex gap-4">
|
||||||
<button class="not-prose" :disabled="modal_form.disabled" type="submit">Отправить</button>
|
<button class="not-prose" :disabled="modal_form.disabled" type="submit">Отправить</button>
|
||||||
<button class="not-prose" type="reset" @click="toggleModal">Отмена</button>
|
<button class="not-prose" type="reset" @click="toggleModal">Отмена</button>
|
||||||
|
@ -203,9 +195,8 @@ const total_txt = computed(() => {
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-4">
|
<div class="flex gap-4 justify-center">
|
||||||
<button class="not-prose" @click="openForm">Данные верны</button>
|
<button class="not-prose" @click="openForm">Отправить расчет на e-mail</button>
|
||||||
<button class="not-prose neutral" @click="toggleModal">Закрыть окно</button>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { BufferGeometry, Color, Matrix4, Vector3 } from 'three';
|
import { BufferGeometry, Matrix4, Vector3 } from 'three';
|
||||||
|
|
||||||
const props = defineProps(['index', 'models'])
|
const props = defineProps(['index', 'models'])
|
||||||
|
|
||||||
|
const lamelle_height = use_lamelle_height()
|
||||||
const lamelles_count = use_lamelles_count()
|
const lamelles_count = use_lamelles_count()
|
||||||
const fence_section = use_fence_section()
|
const fence_section = use_fence_section()
|
||||||
const section_count = use_section_count()
|
const section_count = use_section_count()
|
||||||
|
@ -10,9 +11,9 @@ const extra_section = use_extra_section()
|
||||||
const remove_pillar = use_remove_pillar()
|
const remove_pillar = use_remove_pillar()
|
||||||
const max_size = use_max_size()
|
const max_size = use_max_size()
|
||||||
|
|
||||||
const lSize = 0.115
|
const lSize = lamelle_height.value
|
||||||
const bSize = 0.0235
|
const bSize = 0.0235
|
||||||
const pillar_size = 80 * 0.001
|
const pillar_size = 104 * 0.001
|
||||||
|
|
||||||
const pillar_one_pos = ref(fence_section.value * -0.5 - 0.015)
|
const pillar_one_pos = ref(fence_section.value * -0.5 - 0.015)
|
||||||
const pillar_two_pos = ref(fence_section.value * 0.5 + pillar_size + bSize - 0.01)
|
const pillar_two_pos = ref(fence_section.value * 0.5 + pillar_size + bSize - 0.01)
|
||||||
|
|
|
@ -66,9 +66,9 @@ pmremGenerator.compileEquirectangularShader();
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const loader = new GainMapLoader(renderer.value)
|
const loader = new GainMapLoader(renderer.value)
|
||||||
const result = await loader.loadAsync([
|
const result = await loader.loadAsync([
|
||||||
'/hdrmaps/kloppenheim_06_4k.webp',
|
'hdrmaps/alps_field_4k.webp',
|
||||||
'/hdrmaps/kloppenheim_06_4k-gainmap.webp',
|
'hdrmaps/alps_field_4k-gainmap.webp',
|
||||||
'/hdrmaps/kloppenheim_06_4k.json',
|
'hdrmaps/alps_field_4k.json',
|
||||||
])
|
])
|
||||||
const exrCubeRenderTarget = pmremGenerator.fromEquirectangular(result.renderTarget.texture);
|
const exrCubeRenderTarget = pmremGenerator.fromEquirectangular(result.renderTarget.texture);
|
||||||
const exrBackground = exrCubeRenderTarget.texture;
|
const exrBackground = exrCubeRenderTarget.texture;
|
||||||
|
|
|
@ -5,6 +5,7 @@ export const predefLamelleColors = ['3009', '9003', '6027', '5024', '9001', '101
|
||||||
|
|
||||||
const n = 2
|
const n = 2
|
||||||
const min = 1300
|
const min = 1300
|
||||||
|
export const use_lamelle_height = () => useState<number>('lamelle_height', () => 0.115)
|
||||||
export const use_lamelles_count = () => useState('lamelles_count', () => 14)
|
export const use_lamelles_count = () => useState('lamelles_count', () => 14)
|
||||||
export const use_fence_section = () => useState<number>('fence_section', () => min * 0.001)
|
export const use_fence_section = () => useState<number>('fence_section', () => min * 0.001)
|
||||||
export const use_remove_pillar = () => useState<boolean>('remove_pillar', () => false)
|
export const use_remove_pillar = () => useState<boolean>('remove_pillar', () => false)
|
||||||
|
@ -13,6 +14,6 @@ export const use_lamelle_color = () => useState<ralTypes>('lamelle_color', () =>
|
||||||
export const use_section_count = () => useState('section_count', () => n)
|
export const use_section_count = () => useState('section_count', () => n)
|
||||||
export const use_extra_section = () => useState('extra_section', () => 0)
|
export const use_extra_section = () => useState('extra_section', () => 0)
|
||||||
export const use_total_length = () => useState('total_length', () => ((min * n) - 100) * 0.001)
|
export const use_total_length = () => useState('total_length', () => ((min * n) - 100) * 0.001)
|
||||||
export const use_min_length = () => useState('min_length', () => 1000)
|
export const use_min_length = () => useState('min_length', () => 700)
|
||||||
export const use_max_size = () => useState<number>('max_size', () => 13)
|
export const use_max_size = () => useState<number>('max_size', () => 13)
|
||||||
export const use_explosion_state = () => useState<boolean>('explosion_state', () => false)
|
export const use_explosion_state = () => useState<boolean>('explosion_state', () => false)
|
|
@ -23,7 +23,7 @@ const { data: calculatorData } = await useFetch(`${apiBase}/calculator/5/`)
|
||||||
|
|
||||||
const about = (pagesData.value as ApiPagesType[]).find(el => el.slug == 'about')
|
const about = (pagesData.value as ApiPagesType[]).find(el => el.slug == 'about')
|
||||||
const reviews = (pagesData.value as ApiPagesType[]).find(el => el.slug == 'clients')
|
const reviews = (pagesData.value as ApiPagesType[]).find(el => el.slug == 'clients')
|
||||||
const delivery = (pagesData.value as ApiPagesType[]).find(el => el.slug == 'delivery')
|
const delivery = (pagesData.value as ApiPagesType[]).find(el => el.slug == 'how_to')
|
||||||
const advantages = (pagesData.value as ApiPagesType[]).find(el => el.slug == 'advantages')
|
const advantages = (pagesData.value as ApiPagesType[]).find(el => el.slug == 'advantages')
|
||||||
|
|
||||||
const roubleSign = new Intl.NumberFormat('ru-RU', {
|
const roubleSign = new Intl.NumberFormat('ru-RU', {
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"gainMapMax": [
|
"gainMapMax": [
|
||||||
6.139551352398794,
|
15.999075124875333,
|
||||||
6.139551352398794,
|
15.999075124875333,
|
||||||
6.139551352398794
|
15.999075124875333
|
||||||
],
|
],
|
||||||
"gainMapMin": [
|
"gainMapMin": [
|
||||||
0,
|
0,
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
1,
|
1,
|
||||||
1
|
1
|
||||||
],
|
],
|
||||||
"hdrCapacityMax": 6.139551352398794,
|
"hdrCapacityMax": 15.999075124875333,
|
||||||
"hdrCapacityMin": 0,
|
"hdrCapacityMin": 0,
|
||||||
"offsetHdr": [
|
"offsetHdr": [
|
||||||
0.015625,
|
0.015625,
|
Binary file not shown.
After Width: | Height: | Size: 1.9 MiB |
Binary file not shown.
Before Width: | Height: | Size: 2.6 MiB |
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 7.8 MiB |
|
@ -48,4 +48,18 @@ type ApiAdvantageType = {
|
||||||
id: number
|
id: number
|
||||||
title: string
|
title: string
|
||||||
content: string
|
content: string
|
||||||
|
}
|
||||||
|
type DiscountType = {
|
||||||
|
id: number
|
||||||
|
min_quantity: number
|
||||||
|
max_quantitt?: number
|
||||||
|
percent: number
|
||||||
|
}
|
||||||
|
type ApiCalcType = {
|
||||||
|
id: number
|
||||||
|
title: string
|
||||||
|
pillar: string
|
||||||
|
pillar_base: string
|
||||||
|
lamelles_block: string
|
||||||
|
discount: DiscountType[]
|
||||||
}
|
}
|
Loading…
Reference in New Issue