mns-mini-zabor/components/calc/values.vue

280 lines
12 KiB
Vue

<script setup lang="ts">
import { Vector3 } from 'three';
import type { ralTypes } from '@/components/ral'
import { predefLamelleColors, predefPillarColors } from '~/composables/useCalc';
import { getName as getPattern, type patternIds } from '../pattern';
import { getName as getTopper, type toppersIds } from '../topper';
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 pillar_topper = use_topper()
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()
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 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;
}
const setPillarColor = (color: ralTypes) => {
pillar_color.value = color
}
const setPillarPattern = (id: patternIds) => {
pillar_pattern.value = id
}
const setPillarTopper = (id: toppersIds) => {
pillar_topper.value = id
}
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:
`Ламели`,
value: section_count.value * lamelles_count.value,
extra: 1 * lamelles_count.value
},
{
name: `Столбы`,
value: !form_state.remove_pillar ? section_count.value + ~~(!!form_state.extra_section) + 1 : ``,
extra: ``
},
]
})
</script>
<template>
<div class="form">
<div class="form-group">
<div class="form-row form-row_picker">
<label for="lamelle_color">Цвет ламелей</label>
<DropdownPicker type="color" :cb="setLamelleColor" name="lamelle_color" :color="lamelle_color"
:goto_target="new Vector3(0, lamelles_count * lamelle_height * 0.75, 0)"
:goto_cam="new Vector3(0.75, 0.75, 0.75)" />
<label for="pillar_color">Цвет столба</label>
<DropdownPicker type="color" :cb="setPillarColor" name="pillar_color" :color="pillar_color"
:goto_target="new Vector3(-fence_section * 0.5, lamelles_count * lamelle_height, 0)"
:goto_cam="new Vector3(-1, -1, 1)" />
</div>
<div class="form-row form-row_picker">
<label for="pillar_pattern">Узор столба</label>
<DropdownPicker type="pattern" :cb="setPillarPattern" name="pillar_pattern"
:pattern="getPattern(pillar_pattern)" :disabled="remove_pillar"
:goto_target="new Vector3(fence_section * 0.5, lamelles_count * lamelle_height, 0)"
:goto_cam="new Vector3(1, 2, -1)" />
<label for="pillar_topper">Колпак столба</label>
<DropdownPicker type="topper" :cb="setPillarTopper" name="pillar_topper"
:pattern="getTopper(pillar_topper)" :disabled="remove_pillar"
:goto_target="new Vector3(fence_section * -0.5, lamelles_count * lamelle_height, 0)"
:goto_cam="new Vector3(-1, 2, 1)" />
</div>
</div>
<div class="form-group">
<div class="form-row">
<div class="form-item form-item_range w-full">
<label for="length">Длина ламельного блока, мм</label>
<div>
<input id="length" type="range" v-bind="parametric.length" v-model="form_state.length"
:disabled="form_state.auto_length" :ref="form_refs.length" />
<span>{{ form_state.length.toFixed(0) }}&nbsp;мм</span>
</div>
</div>
</div>
<div class="form-row">
<div class="form-item form-item_range w-full">
<label for="height">Высота забора, мм</label>
<div>
<input id="height" type="range" v-bind="parametric.height" v-model="form_state.height"
:ref="form_refs.height" />
<span>{{ form_state.height }}&nbsp;мм</span>
</div>
</div>
</div>
<div class="form-row">
<div class="form-item form-item_total">
<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" />
</div>
</div>
<div class="form-row">
<div class="form-item form-item_checkbox">
<Icon :name="`mdi:check-box-outline${!form_state.auto_length ? '-blank' : ''}`"
@click="form_state.auto_length = !form_state.auto_length" />
<input id="auto_length" type="checkbox" hidden 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 class="form-item form-item_checkbox">
<Icon :name="`mdi:check-box-outline${!form_state.remove_pillar ? '-blank' : ''}`"
@click="form_state.remove_pillar = !form_state.remove_pillar" />
<input id="remove_pillar" type="checkbox" hidden v-model="form_state.remove_pillar" />
<label for="remove_pillar">Без столбов</label>
</div>
</div>
</div>
<div class="form-group">
<p v-if="form_state.total_length * 1000 < (parametric.length.min) || form_state.full_sections == 0"
class="text-ioprim text-sm">
Выбранный размер забора слишком мал для расчета стоимости. Пожалуйста, выберите больший
размер, чтобы продолжить.
</p>
<template v-else>
<div class="grid calc_table w-full">
<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>