301 lines
12 KiB
Vue
301 lines
12 KiB
Vue
<script setup lang="ts">
|
|
import { getColorHexFromRal, getColorNameFromRal } from '@/components/ral'
|
|
import type { ralTypes } from '@/components/ral'
|
|
|
|
import { predefLamelleColors, predefPillarColors } from '~/composables/useCalc';
|
|
import { getFilename, type patternTypes } from '../pattern';
|
|
import { Vector3 } from 'three';
|
|
|
|
const lamelle_height = use_lamelle_height()
|
|
const lamelles_count = use_lamelles_count()
|
|
const fence_section = use_fence_section()
|
|
const remove_pillar = use_remove_pillar()
|
|
const pillar_color = use_pillar_color()
|
|
const pillar_pattern = use_pattern()
|
|
const lamelle_color = use_lamelle_color()
|
|
const section_count = use_section_count()
|
|
const extra_section = use_extra_section()
|
|
const total_length = use_total_length()
|
|
const min_length = use_min_length()
|
|
const goto_cam = use_goto_camera()
|
|
const goto_target = use_goto_target()
|
|
const open_calc = use_open_calc()
|
|
|
|
if (!pillar_color.value) {
|
|
const r = Math.floor(Math.random() * predefPillarColors.length)
|
|
pillar_color.value = predefPillarColors[r] as ralTypes
|
|
lamelle_color.value = predefLamelleColors[r] as ralTypes
|
|
}
|
|
|
|
const parametric = reactive({
|
|
length: {
|
|
min: min_length.value,
|
|
max: 2470,
|
|
step: 1,
|
|
},
|
|
total_length: {
|
|
min: min_length.value * 0.001,
|
|
max: undefined,
|
|
step: 0.5,
|
|
},
|
|
height: {
|
|
min: 20 + lamelle_height.value * 1000 * 5,
|
|
max: 20 + lamelle_height.value * 1000 * 20,
|
|
step: lamelle_height.value * 1000,
|
|
}
|
|
})
|
|
const form_state = reactive({
|
|
length: fence_section.value * 1000,
|
|
fence_length: 104,
|
|
height: 100 + lamelles_count.value * parametric.height.step,
|
|
total_length: total_length.value,
|
|
total_length_mm: fence_section.value * 1000,
|
|
full_sections: section_count.value,
|
|
extra_section: 0,
|
|
auto_length: true,
|
|
remove_pillar: false
|
|
})
|
|
let copy_form_state = Object.assign({}, form_state)
|
|
const form_refs = {
|
|
length: ref(),
|
|
height: ref(),
|
|
total_length: ref(),
|
|
}
|
|
|
|
const lamelle_text = ref(contrastColor(lamelle_color.value))
|
|
const pillar_text = ref(contrastColor(pillar_color.value))
|
|
|
|
const changeParametres = () => {
|
|
// console.log('form', form_state.total_length * 1000, 'copy', copy_form_state.total_length * 1000)
|
|
|
|
const lamelles = Math.floor(form_state.height / parametric.height.step)
|
|
|
|
for (const key in form_state) {
|
|
if (parametric.hasOwnProperty(key)) {
|
|
const key_p = key as keyof typeof parametric
|
|
const key_s = key as keyof typeof form_state
|
|
if (parametric[key_p].max) {
|
|
if ((form_state[key_s] as number) > parametric[key_p].max) {
|
|
(form_state[key_s] as number) = parametric[key_p].max
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
form_state.total_length_mm = form_state.total_length * 1000
|
|
|
|
let { fence_length, total_length_mm, auto_length, length, full_sections } = form_state
|
|
length = parseFloat(length.toString())
|
|
if (total_length_mm < parametric.length.min) total_length_mm = parametric.length.min
|
|
|
|
if (auto_length) {
|
|
let w = parametric.length.min
|
|
const max_sections = Math.floor((total_length_mm - fence_length) / (parametric.length.min + fence_length))
|
|
const min_sections = Math.floor((total_length_mm - fence_length) / (parametric.length.max + fence_length)) || 1
|
|
|
|
for (let index = min_sections; index <= max_sections; index++) {
|
|
full_sections = index
|
|
w = (total_length_mm - fence_length - fence_length * index) / index
|
|
if (
|
|
w >= parametric.length.min
|
|
&& w <= parametric.length.max
|
|
&& w * index <= total_length_mm
|
|
) {
|
|
break
|
|
}
|
|
}
|
|
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 calc_full_section = () => (full_sections * length) + (full_sections * fence_length) + fence_length
|
|
let total_length_calc = calc_full_section()
|
|
if (Math.round(total_length_mm - total_length_calc) > 0 && Math.round(total_length_mm - total_length_calc) <= fence_length) {
|
|
full_sections -= 1
|
|
total_length_calc = calc_full_section()
|
|
}
|
|
if (Math.round(total_length_mm - total_length_calc) > 0) {
|
|
form_state.extra_section = total_length_mm - total_length_calc - fence_length
|
|
} else {
|
|
form_state.extra_section = 0
|
|
}
|
|
|
|
form_state.full_sections = full_sections
|
|
form_state.length = typeof length == 'string' ? parseFloat(length) : length
|
|
form_state.fence_length = typeof fence_length == 'string' ? parseFloat(fence_length) : fence_length
|
|
|
|
copy_form_state = Object.assign({}, form_state)
|
|
|
|
total_length.value = form_state.total_length
|
|
lamelles_count.value = lamelles
|
|
fence_section.value = form_state.length * 0.001
|
|
section_count.value = form_state.full_sections
|
|
extra_section.value = form_state.extra_section
|
|
remove_pillar.value = form_state.remove_pillar
|
|
|
|
goal('calc_fence', form_state)
|
|
}
|
|
|
|
|
|
const setLamelleColor = (color: ralTypes) => {
|
|
lamelle_color.value = color;
|
|
lamelle_text.value = contrastColor(color) ?? '#000'
|
|
}
|
|
const setPillarColor = (color: ralTypes) => {
|
|
pillar_color.value = color
|
|
pillar_text.value = contrastColor(color) ?? '#000'
|
|
}
|
|
const setPillarPattern = (pattern: patternTypes) => {
|
|
pillar_pattern.value = pattern
|
|
}
|
|
watch(() => form_state, changeParametres, { deep: true })
|
|
|
|
const isModalOpen = useState('modal_open', () => false)
|
|
const toggleModal = () => {
|
|
isModalOpen.value = !isModalOpen.value
|
|
}
|
|
const goal = (target: string, params: object) => {
|
|
const nuxtApp = useNuxtApp()
|
|
if (nuxtApp.$metrika) {
|
|
(nuxtApp.$metrika as any).reachGoal(target, params || {})
|
|
}
|
|
}
|
|
const calc_table = computed(() => {
|
|
return [
|
|
{
|
|
name: 'Секции',
|
|
value: section_count,
|
|
extra: 1,
|
|
extra_name: 'Дополнительная секция'
|
|
},
|
|
{
|
|
name:
|
|
`Ламели, RAL ${lamelle_color.value}, ${getColorNameFromRal(lamelle_color.value)?.toLowerCase()}`,
|
|
value: section_count.value * lamelles_count.value,
|
|
extra: 1 * lamelles_count.value
|
|
},
|
|
{
|
|
name: `Столбы, RAL ${pillar_color.value}, ${getColorNameFromRal(pillar_color.value)?.toLowerCase()}`,
|
|
value: !form_state.remove_pillar ? section_count.value + ~~(!!form_state.extra_section) + 1 : `—`,
|
|
extra: `—`
|
|
},
|
|
]
|
|
})
|
|
|
|
watch(open_calc, () => {
|
|
if (Object.keys(open_calc.value).length == 0) {
|
|
goto_cam.value = new Vector3(0, 0, 0)
|
|
goto_target.value = new Vector3(0, 0, 0)
|
|
}
|
|
})
|
|
</script>
|
|
<template>
|
|
<div class="form">
|
|
<div class="form-row">
|
|
<div class="form-item w-full">
|
|
<label for="length">Длина ламельного блока, мм</label>
|
|
<input :value.input="`${form_state.length.toFixed(0)} мм`" disabled class="w-full" />
|
|
<input id="length" type="range" class="xl:w-full" v-bind="parametric.length" v-model="form_state.length"
|
|
:disabled="form_state.auto_length" :ref="form_refs.length" />
|
|
</div>
|
|
</div>
|
|
<div class="form-row">
|
|
<div class="form-item w-full">
|
|
<label for="height">Высота забора, мм</label>
|
|
<input :value="`${form_state.height} мм`" class="w-full" disabled />
|
|
<input id="height" type="range" class="xl:w-full" v-bind="parametric.height" v-model="form_state.height"
|
|
:ref="form_refs.height" />
|
|
</div>
|
|
</div>
|
|
<div class="form-row">
|
|
<div class="form-item">
|
|
<label for="total_length">Общая длина забора, м</label>
|
|
<input type="number" id="total_length" v-bind="parametric.total_length" min=0 max="600"
|
|
v-model="form_state.total_length" :ref="form_refs.total_length" class="w-full" />
|
|
</div>
|
|
<div class="form-item text-sm xl:text-base">
|
|
<p v-if="form_state.total_length_mm < parametric.length.min" class="text-ioprim">
|
|
Выбранный размер забора слишком мал для расчета стоимости. Пожалуйста, выберите больший
|
|
размер, чтобы продолжить.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="form-row">
|
|
<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>
|
|
<p v-if="!form_state.auto_length" class="text-ioprim text-sm">
|
|
Рекомендуем вам включить автоподбор длины секции
|
|
</p>
|
|
</div>
|
|
<div class="form-row">
|
|
<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 class="form-row">
|
|
<div class="form-item form-item_color">
|
|
<label for="lamelle_color">Цвет ламелей</label>
|
|
<DropdownPicker type="color" :cb="setLamelleColor" name="lamelle_color" :goto_cam="new Vector3(1, 1, 1)"
|
|
:goto_target="new Vector3(1, 1, 1)">
|
|
<input id="lamelle_color" type="text" :value="getColorNameFromRal(lamelle_color)" :style="{
|
|
backgroundColor: getColorHexFromRal(lamelle_color) ?? 'transparent',
|
|
color: lamelle_text
|
|
}" />
|
|
</DropdownPicker>
|
|
</div>
|
|
</div>
|
|
<div class="form-row">
|
|
<div class="form-item form-item_color">
|
|
<label for="pillar_color">Цвет столба</label>
|
|
<DropdownPicker type="color" :cb="setPillarColor" name="pillar_color" :goto_cam="new Vector3(2, 1, 1)"
|
|
:goto_target="new Vector3(1, 1, 1)">
|
|
<input id="pillar_color" type="text" :value="getColorNameFromRal(pillar_color)" :style="{
|
|
backgroundColor: getColorHexFromRal(pillar_color) ?? 'transparent',
|
|
color: pillar_text
|
|
}" />
|
|
</DropdownPicker>
|
|
</div>
|
|
</div>
|
|
<div class="form-row">
|
|
<div class="form-item form-item_color">
|
|
<label for="pillar_pattern">Узор столба</label>
|
|
<DropdownPicker type="pattern" :cb="setPillarPattern" name="pillar_pattern"
|
|
:goto_cam="new Vector3(-1, 0, 0)" :goto_target="new Vector3(1, 1, 1)">
|
|
<input id="pillar_pattern" type="text" :value="pillar_pattern" :style="{
|
|
backgroundImage: `url(${getFilename(pillar_pattern)})`
|
|
}" />
|
|
</DropdownPicker>
|
|
</div>
|
|
</div>
|
|
<div class="form-row">
|
|
<template v-if="(form_state.total_length * 1000) >= parametric.length.min">
|
|
<div class="col-span-12 xl:col-span-6 xl:col-start-4 grid calc_table">
|
|
<div class="grid grid-cols-4 relative">
|
|
<template v-for="item in calc_table">
|
|
<div class="col-span-3 calc_table-maincell">
|
|
{{ item.name }}
|
|
</div>
|
|
<div class="col-span-1 calc_table-maincell">{{ item.value }}</div>
|
|
</template>
|
|
</div>
|
|
<button @click.prevent="toggleModal">Рассчитать</button>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<style lang="scss" scoped>
|
|
#pillar_pattern {
|
|
&[style*='url("/'] {
|
|
background-size: contain;
|
|
background-clip: content-box;
|
|
color: transparent;
|
|
}
|
|
}
|
|
</style> |