191 lines
7.6 KiB
Vue
191 lines
7.6 KiB
Vue
<script setup lang="ts">
|
||
const lamelles_count = useState('lamelles_count', () => 8)
|
||
const fence_section = useState<number>('fence_section', () => 2000 * 0.001)
|
||
const pillar_color = useState('pillar_color', () => '#828282')
|
||
const lamelle_color = useState('lamelle_color', () => '#C2B078')
|
||
|
||
const parametric = {
|
||
length: {
|
||
min: 400,
|
||
max: 2400,
|
||
step: 50,
|
||
},
|
||
total_length: {
|
||
min: 0.4,
|
||
step: 0.05,
|
||
},
|
||
height: {
|
||
min: 675,
|
||
max: 2400,
|
||
step: 115,
|
||
}
|
||
}
|
||
const form_state = reactive({
|
||
length: fence_section.value * 1000,
|
||
fence_length: 100,
|
||
height: 100 + lamelles_count.value * parametric.height.step,
|
||
total_length: fence_section.value,
|
||
total_length_mm: fence_section.value * 1000,
|
||
full_sections: 1,
|
||
extra_section: 0
|
||
})
|
||
const form_errors = reactive({
|
||
length: false,
|
||
height: false,
|
||
total_length: false,
|
||
})
|
||
const form_refs = {
|
||
length: ref(),
|
||
height: ref(),
|
||
total_length: ref(),
|
||
}
|
||
const auto_section_width = ref<boolean>(false)
|
||
|
||
const changeParametres = () => {
|
||
const lamelles = Math.floor(form_state.height / parametric.height.step)
|
||
lamelles_count.value = lamelles
|
||
fence_section.value = form_state.length * 0.001
|
||
|
||
for (const key in form_state) {
|
||
if (parametric.hasOwnProperty(key) && parametric[key].max) {
|
||
if (form_state[key] > parametric[key].max) {
|
||
form_state[key] = parametric[key].max
|
||
}
|
||
}
|
||
if (parametric.hasOwnProperty(key) && parametric[key].min) {
|
||
if (form_state[key] < parametric[key].min) {
|
||
form_state[key] = parametric[key].min
|
||
}
|
||
}
|
||
}
|
||
|
||
form_state.total_length_mm = form_state.total_length * 1000
|
||
if (auto_section_width.value) {
|
||
let w = parametric.length.max
|
||
while (((form_state.total_length_mm % w) > 0) && w > (parametric.length.min + parametric.length.step * 10)) {
|
||
w -= parametric.length.step
|
||
}
|
||
form_state.length = w
|
||
}
|
||
if (form_state.total_length_mm < form_state.length) {
|
||
form_state.length = form_state.total_length_mm
|
||
}
|
||
|
||
const t_f = (form_state.total_length_mm - form_state.fence_length)
|
||
const i_f = (form_state.length - form_state.fence_length)
|
||
form_state.full_sections = Math.floor(t_f / i_f)
|
||
if (t_f % i_f) {
|
||
form_state.extra_section = Math.round(t_f % i_f)
|
||
} else {
|
||
form_state.extra_section = 0
|
||
}
|
||
|
||
form_refs.total_length.value.setCustomValidity('')
|
||
if (form_state.extra_section && form_state.extra_section < parametric.length.min) {
|
||
form_refs.total_length.value.setCustomValidity('Расчет невозможен')
|
||
}
|
||
}
|
||
|
||
const setLamelleColor = (color: string) => {
|
||
lamelle_color.value = color
|
||
}
|
||
const setPillarColor = (color: string) => {
|
||
pillar_color.value = color
|
||
}
|
||
const increment = (field: keyof typeof form_state, value: number) => {
|
||
if (form_state.hasOwnProperty(field)) {
|
||
let v = (form_state[field] + value * parametric[field].step ?? 1)
|
||
if (parametric.hasOwnProperty(field)) {
|
||
if (v > parametric[field].max) {
|
||
v = parametric[field].max
|
||
}
|
||
if (v < parametric[field].min) {
|
||
v = parametric[field].min
|
||
}
|
||
}
|
||
form_state[field] = parseFloat(v.toFixed(2))
|
||
}
|
||
}
|
||
const autoSectionWidth = () => {
|
||
auto_section_width.value = !auto_section_width.value
|
||
}
|
||
|
||
const predefLamelleColors = ['#474B4E', '#705335', '#FDF4E3', '#2F4538']
|
||
const predefPillarColors = ['#474B4E', '#6A5D4D', '#F4F4F4', '#2F4538']
|
||
|
||
watch(form_state, changeParametres, { deep: true })
|
||
watch(form_state, changeParametres, { deep: true })
|
||
|
||
const calc_text = computed(() => {
|
||
let txt = `Всего секций: ${form_state.full_sections} по ${form_state.length}мм`
|
||
if (form_state.extra_section) {
|
||
txt += `, 1 по ${form_state.extra_section}мм`
|
||
}
|
||
return txt
|
||
})
|
||
|
||
const isModalOpen = useState('modal_open', () => false)
|
||
const toggleModal = () => {
|
||
isModalOpen.value = !isModalOpen.value
|
||
}
|
||
</script>
|
||
<template>
|
||
<div class="container py-4">
|
||
<form class="form">
|
||
<div class="form-row">
|
||
<div class="form-item">
|
||
<label for="length">Длина секции, мм</label>
|
||
<Icon type="button" @click="increment('length', -1)" name="mdi:minus-circle-outline"
|
||
:class="auto_section_width ? `disabled` : ''" />
|
||
<input id="length" type="number" v-bind="parametric.length" v-model="form_state.length"
|
||
:disabled="auto_section_width" :ref="form_refs.length" />
|
||
<Icon type="button" @click="increment('length', 1)" name="mdi:plus-circle-outline"
|
||
:class="auto_section_width ? `disabled` : ''" />
|
||
<Icon name="mdi:calculator-variant" @click="autoSectionWidth" />
|
||
</div>
|
||
<div class="form-item">
|
||
<label for="height">Высота забора, мм</label>
|
||
<Icon type="button" @click="increment('height', -1)" name="mdi:minus-circle-outline" />
|
||
<input id="height" type="number" v-bind="parametric.height" v-model="form_state.height"
|
||
:ref="form_refs.height" />
|
||
<Icon type="button" @click="increment('height', 1)" name="mdi:plus-circle-outline" />
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-item">
|
||
<label for="lamelle_color">Цвет ламелей</label>
|
||
<input id="lamelle_color" type="text" v-model="lamelle_color" disabled />
|
||
<template v-for="item in predefLamelleColors">
|
||
<ColorPicker :color="item" :cb="setLamelleColor" :open="false"
|
||
:active="lamelle_color == item" />
|
||
</template>
|
||
<ColorPicker :cb="setLamelleColor" />
|
||
</div>
|
||
<div class="form-item">
|
||
<label for="pillar_color">Цвет столба</label>
|
||
<input id="pillar_color" type="text" v-model="pillar_color" disabled />
|
||
<template v-for="item in predefPillarColors">
|
||
<ColorPicker :color="item" :cb="setPillarColor" :open="false" :active="pillar_color == item" />
|
||
</template>
|
||
<ColorPicker :cb="setPillarColor" />
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-item">
|
||
<label for="total_length">Общая длина забора, м</label>
|
||
<Icon type="button" @click="increment('total_length', -1)" name="mdi:minus-circle-outline" />
|
||
<input type="number" id="total_length" v-bind="parametric.total_length"
|
||
v-model="form_state.total_length" :ref="form_refs.total_length" />
|
||
<Icon type="button" @click="increment('total_length', 1)" name="mdi:plus-circle-outline" />
|
||
</div>
|
||
<div class="form-item grow">
|
||
<label for="calculation">Приблизительный расчет забора</label>
|
||
<textarea id="calculation" disabled class="w-full">{{ calc_text }}</textarea>
|
||
</div>
|
||
</div>
|
||
<div class="form-row justify-center">
|
||
<button @click.prevent="toggleModal">Купить прямо сейчас</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</template> |