dev #84
|
@ -180,9 +180,10 @@ a[href^="#"] {
|
|||
&_calc {
|
||||
@apply py-0 relative;
|
||||
|
||||
> .container:first-child {
|
||||
@apply relative h-[50vh] min-h-[600px] justify-between;
|
||||
> * {
|
||||
>.container:first-child {
|
||||
@apply relative min-h-[650px] justify-between;
|
||||
|
||||
>* {
|
||||
@apply z-10
|
||||
}
|
||||
}
|
||||
|
@ -280,13 +281,32 @@ label {
|
|||
}
|
||||
|
||||
input {
|
||||
@apply bg-neutral-200 border border-gray-300 text-gray-900 rounded focus:ring-blue-500 focus:border-blue-500 text-lg p-2.5 disabled:cursor-not-allowed disabled:text-black;
|
||||
@apply bg-white border border-gray-300 text-gray-900 text-lg p-2.5 rounded focus:ring-blue-500 focus:border-blue-500 focus-visible:border-blue-500 disabled:cursor-not-allowed disabled:text-black disabled:bg-neutral-300;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
@apply w-4 h-4;
|
||||
}
|
||||
|
||||
input[type=range] {
|
||||
@apply bg-neutral-300 appearance-none h-1;
|
||||
|
||||
// [&::-webkit-slider-runnable-track]:h-1
|
||||
// [&::-moz-range-track]:h-1
|
||||
// [&::-webkit-slider-thumb]:bg-[#61C4FF] [&::-webkit-slider-thumb]:w-8
|
||||
// [&::-moz-range-thumb]:bg-[#61C4FF]
|
||||
// ;
|
||||
&::-moz-range-track,
|
||||
&::-webkit-slider-runnable-track {
|
||||
@apply h-1 bg-red-500;
|
||||
}
|
||||
|
||||
&::-moz-range-thumb,
|
||||
&::-webkit-slider-thumb {
|
||||
@apply bg-[#61C4FF] shadow-red-700;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
@apply block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 max-w-full min-h-10 max-h-40;
|
||||
}
|
||||
|
@ -323,11 +343,17 @@ button {
|
|||
}
|
||||
|
||||
&_checkbox {
|
||||
@apply w-full xl:w-auto flex-row xl:flex-initial flex-nowrap gap-4
|
||||
@apply w-full xl:w-auto flex-row xl:flex-initial flex-nowrap gap-4;
|
||||
}
|
||||
&_color {
|
||||
@apply w-full;
|
||||
.color_picker {
|
||||
@apply ml-4;
|
||||
}
|
||||
}
|
||||
|
||||
input[type=range] {
|
||||
@apply min-w-[calc(100%-8rem)] xl:min-w-min;
|
||||
@apply min-w-[calc(100%-8rem)] xl:min-w-min py-0 -translate-y-1/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -344,7 +370,7 @@ button {
|
|||
}
|
||||
|
||||
&-changer {
|
||||
@apply absolute w-80 z-10 p-4 border rounded bg-white flex gap-0 right-0 lg:right-auto;
|
||||
@apply absolute w-80 z-20 p-4 border rounded bg-white flex gap-0 right-0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,7 +403,7 @@ button {
|
|||
}
|
||||
|
||||
.calc_table {
|
||||
@apply flex flex-col gap-2 mb-4;
|
||||
@apply flex flex-col gap-2 self-end;
|
||||
|
||||
>.grid {
|
||||
@apply gap-2 items-center;
|
||||
|
|
|
@ -5,8 +5,8 @@ import { degToRad } from 'three/src/math/MathUtils.js';
|
|||
|
||||
const section_count = use_section_count()
|
||||
const extra_section = use_extra_section()
|
||||
const lamelles_count = use_lamelles_count()
|
||||
const lamelle_height = use_lamelle_height()
|
||||
const fence_section = use_fence_section()
|
||||
|
||||
const defDistance = 3
|
||||
const controlsState = reactive({
|
||||
distance: section_count.value,
|
||||
|
@ -26,8 +26,8 @@ const cameraStat = reactive({
|
|||
|
||||
const camera = ref("camera")
|
||||
|
||||
watch([section_count, extra_section], () => {
|
||||
let v = (section_count.value + ~~(!!extra_section.value));
|
||||
watch(fence_section, ()=>{
|
||||
let v = fence_section.value * 2;
|
||||
if (v <= defDistance) v = defDistance
|
||||
controlsState.minDistance = v;
|
||||
controlsState.maxDistance = v;
|
||||
|
|
|
@ -155,23 +155,33 @@ const goal = (target: string, params: object) => {
|
|||
<div class="form-row">
|
||||
<div class="form-item w-full">
|
||||
<label for="length">Длина ламельного блока, мм</label>
|
||||
<input disabled :value.input="`${form_state.length.toFixed(0)} мм`" class="w-28" />
|
||||
<input :value.input="`${form_state.length.toFixed(0)} мм`" :disabled="form_state.auto_length"
|
||||
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 class="form-item w-full">
|
||||
<label for="height">Высота забора, мм</label>
|
||||
<input disabled :value="`${form_state.height} мм`" class="w-28" />
|
||||
<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 class="form-item">
|
||||
<label for="total_length">Общая длина забора, м</label>
|
||||
<input type="number" id="total_length" v-bind="parametric.total_length" min=0
|
||||
v-model="form_state.total_length" :ref="form_refs.total_length" />
|
||||
<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>
|
||||
<p v-if="form_state.extra_section" class="text-ioprim">
|
||||
Внимание! Дополнительная секция приводит к увеличению стоимости.
|
||||
Рекомендуем вам изменить длину забора или длину секции!
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-item form-item_checkbox">
|
||||
<input id="auto_length" type="checkbox" v-model="form_state.auto_length" />
|
||||
<label for="auto_length">Автоматический подбор секции</label>
|
||||
|
@ -183,68 +193,48 @@ const goal = (target: string, params: object) => {
|
|||
</div>
|
||||
</div>
|
||||
<div class="col-span-3 col-start-10">
|
||||
<div class="form-item">
|
||||
<label for="lamelle_color">Цвет ламелей</label>
|
||||
<input id="lamelle_color" type="text" :value="getColorNameFromRal(lamelle_color)" class="w-60"
|
||||
disabled />
|
||||
<ColorPicker :cb="setLamelleColor" />
|
||||
</div>
|
||||
<div class="form-item">
|
||||
<label for="pillar_color">Цвет столба</label>
|
||||
<input id="pillar_color" type="text" :value="getColorNameFromRal(pillar_color)" class="w-60" disabled />
|
||||
<ColorPicker :cb="setPillarColor" />
|
||||
<div class="form-row">
|
||||
<div class="form-item form-item_color">
|
||||
<label for="lamelle_color">Цвет ламелей</label>
|
||||
<input id="lamelle_color" type="text" :value="getColorNameFromRal(lamelle_color)" class="w-60"
|
||||
disabled />
|
||||
<ColorPicker :cb="setLamelleColor" />
|
||||
</div>
|
||||
<div class="form-item form-item_color">
|
||||
<label for="pillar_color">Цвет столба</label>
|
||||
<input id="pillar_color" type="text" :value="getColorNameFromRal(pillar_color)" class="w-60"
|
||||
disabled />
|
||||
<ColorPicker :cb="setPillarColor" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="(form_state.total_length * 1000) >= parametric.length.min">
|
||||
<div class="col-span-12">
|
||||
<div class="col-span-12 xl:col-span-8 xl:col-start-3 grid calc_table">
|
||||
<div class="grid grid-cols-6">
|
||||
<div class="col-span-4 calc_table-maincell">Секции</div>
|
||||
<div class="col-span-2 calc_table-maincell">{{ section_count }}</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
<div class="col-span-12 xl:col-span-6 xl:col-start-4 grid calc_table">
|
||||
<div class="grid grid-cols-4">
|
||||
<div class="col-span-3 calc_table-maincell">Секции</div>
|
||||
<div class="col-span-1 calc_table-maincell">{{ section_count }}</div>
|
||||
<div class="col-span-3">
|
||||
Ламели, RAL {{ lamelle_color }}, {{ getColorNameFromRal(lamelle_color)?.toLowerCase() }}
|
||||
</div>
|
||||
<div class="col-span-1">{{ section_count * lamelles_count }}</div>
|
||||
<template v-if="!form_state.remove_pillar">
|
||||
<div class="col-span-3">Столбы, RAL {{ pillar_color }}, {{
|
||||
getColorNameFromRal(pillar_color)?.toLowerCase() }}</div>
|
||||
<div class="col-span-1">
|
||||
{{ section_count + ~~(!!form_state.extra_section) + 1 }}
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="form_state.extra_section">
|
||||
<div class="col-span-3 calc_table-maincell">Дополнительная секция</div>
|
||||
<div class="col-span-1 calc_table-maincell">1</div>
|
||||
<div class="col-span-3">
|
||||
Ламели, RAL {{ lamelle_color }}, {{ getColorNameFromRal(lamelle_color)?.toLowerCase() }}
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-1">{{ section_count * lamelles_count }}</div>
|
||||
<div class="col-span-3 sm:col-span-1">
|
||||
{{ `${parseFloat(form_state.length.toString()).toFixed(2)}\xa0мм` }}</div>
|
||||
<template v-if="!form_state.remove_pillar">
|
||||
<div class="col-span-6 sm:col-span-4">Столбы, RAL {{ pillar_color }}, {{
|
||||
getColorNameFromRal(pillar_color)?.toLowerCase() }}</div>
|
||||
<div class="col-span-3 sm:col-span-1">
|
||||
{{ section_count + ~~(!!form_state.extra_section) + 1 }}
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-1">
|
||||
{{ `${parseFloat(form_state.fence_length.toString()).toFixed(2)}\xa0мм` }}
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="form_state.extra_section">
|
||||
<div class="col-span-4 calc_table-maincell">Дополнительная секция</div>
|
||||
<div class="col-span-2 calc_table-maincell">1</div>
|
||||
<div class="col-span-6 sm:col-span-4">
|
||||
Ламели, RAL {{ lamelle_color }}, {{ getColorNameFromRal(lamelle_color)?.toLowerCase() }}
|
||||
</div>
|
||||
<div class="col-span-3 sm:col-span-1">
|
||||
{{ 1 * lamelles_count }}</div>
|
||||
<div class="col-span-3 sm:col-span-1">{{
|
||||
`${parseFloat(form_state.extra_section.toString()).toFixed(2)}\xa0мм` }}</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-12 text-center mb-4">
|
||||
<button @click.prevent="toggleModal">Рассчитать</button>
|
||||
</div>
|
||||
<div class="col-span-12">
|
||||
<div class="form-item xl:w-2/4 text-sm xl:text-base">
|
||||
<p v-if="form_state.total_length_mm < parametric.length.min" class="text-ioprim">
|
||||
Выбранный размер забора слишком мал для расчета стоимости. Пожалуйста, выберите больший
|
||||
размер, чтобы продолжить.
|
||||
</p>
|
||||
<p v-if="form_state.extra_section" class="text-ioprim">
|
||||
Внимание! Дополнительная секция приводит к увеличению стоимости.
|
||||
Рекомендуем вам изменить длину забора или длину секции!
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-span-1">
|
||||
{{ 1 * lamelles_count }}</div>
|
||||
</template>
|
||||
</div>
|
||||
<button @click.prevent="toggleModal">Рассчитать</button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
@ -28,18 +28,16 @@ onUnmounted(() => {
|
|||
})
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div class="color_picker" ref="picker">
|
||||
<div class="color_picker-selected" @click="open ? toggleOpen(!isOpenPicker) : onClick(props.color)"
|
||||
:style="[props.color && { backgroundColor: getColorHexFromRal(props.color) ?? '' }]"
|
||||
:class="[{ 'color_picker-selected__active': active }]"></div>
|
||||
<div class="color_picker-changer flex flex-wrap" v-if="isOpenPicker">
|
||||
<template v-for="col in ralClassicPallette">
|
||||
<div class="color size-5" :class="[{ 'outline outline-primary': props.color == col.hex }]"
|
||||
:style="[{ backgroundColor: col.hex }]" @click="onClick(col.code)">
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="color_picker" ref="picker">
|
||||
<div class="color_picker-selected" @click="open ? toggleOpen(!isOpenPicker) : onClick(props.color)"
|
||||
:style="[props.color && { backgroundColor: getColorHexFromRal(props.color) ?? '' }]"
|
||||
:class="[{ 'color_picker-selected__active': active }]"></div>
|
||||
<div class="color_picker-changer flex flex-wrap" v-if="isOpenPicker">
|
||||
<template v-for="col in ralClassicPallette">
|
||||
<div class="color size-5" :class="[{ 'outline outline-primary': props.color == col.hex }]"
|
||||
:style="[{ backgroundColor: col.hex }]" @click="onClick(col.code)">
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -29,22 +29,6 @@ const lamelle_height = use_lamelle_height()
|
|||
const total = ref((section_count.value + ~~(!!extra_section.value)))
|
||||
const position = ref(new Vector3())
|
||||
|
||||
const clickable_positions = reactive({
|
||||
'top': [position.value.x, (lamelle_count.value + 1) * lamelle_height.value, 0],
|
||||
'lam': [position.value.x, position.value.y * 0.5, 0]
|
||||
})
|
||||
const clickable_pointers = ref<any[]>([])
|
||||
const clickable_refs = ref<any>([])
|
||||
|
||||
Object.entries(clickable_positions).map(el => {
|
||||
const p = props.models.pointer.clone()
|
||||
p.position.set(...el[1])
|
||||
p.updateMatrixWorld()
|
||||
p.name = `clickable_${props.number}_${el[0]}`
|
||||
clickable_pointers.value.push(p)
|
||||
clickable_refs.value.push(ref(p.name))
|
||||
})
|
||||
|
||||
const count_pos = () => {
|
||||
total.value = (section_count.value + ~~(!!extra_section.value))
|
||||
|
||||
|
@ -81,22 +65,7 @@ const count_pos = () => {
|
|||
break;
|
||||
}
|
||||
line?.updateMatrixWorld()
|
||||
|
||||
clickable_positions.top = [position.value.x, (lamelle_count.value + 1) * lamelle_height.value, 0];
|
||||
clickable_positions.lam = [position.value.x, position.value.y * 0.5, 0];
|
||||
}
|
||||
watch(clickable_positions, () => {
|
||||
clickable_refs.value.map((el: Ref<Object3D[]>) => {
|
||||
const name = el.value[0].name.replace(`clickable_${props.number}_`, '')
|
||||
if (name in clickable_positions) {
|
||||
const p = clickable_positions[name as keyof typeof clickable_positions];
|
||||
console.log(props.number, p, el.value[0].name)
|
||||
el.value[0].position.set(p[0], p[1], p[2])
|
||||
el.value[0].children[0].position.set(p[0], p[1], p[2])
|
||||
el.value[0].updateMatrixWorld()
|
||||
}
|
||||
})
|
||||
}, { deep: true })
|
||||
|
||||
onMounted(() => {
|
||||
count_pos()
|
||||
|
@ -105,24 +74,6 @@ watch(() => [props.count, fence_section.value, section_count.value, extra_sectio
|
|||
count_pos,
|
||||
{ flush: 'post' }
|
||||
)
|
||||
|
||||
const { onBeforeRender } = useLoop()
|
||||
onBeforeRender(() => {
|
||||
clickable_refs.value.map((el: any) => {
|
||||
if (el.value[0] && el.value[0].children) {
|
||||
el.value[0].children[0].lookAt(camera.value?.position);
|
||||
el.value[0].children[0].rotateX(degToRad(90));
|
||||
el.value[0].children[0].rotateZ(degToRad(15));
|
||||
|
||||
const dis_to_cam = camera.value?.position.distanceTo(el.value[0].position);
|
||||
if (dis_to_cam) {
|
||||
const scaling = (0.66 * dis_to_cam) / 100
|
||||
el.value[0].children[0].scale.set(scaling, scaling, scaling);
|
||||
el.value[0].updateMatrixWorld()
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<TresGroup :name="`line_${props.number}`" :rotate-y="rotate()" :position-x="position.x" :position-y="position.y"
|
||||
|
@ -137,10 +88,5 @@ onBeforeRender(() => {
|
|||
</template>
|
||||
</template>
|
||||
</TresGroup>
|
||||
<TresGroup name="pointer">
|
||||
<template v-for="(p, i) in clickable_pointers">
|
||||
<TresObject3D v-bind="p.clone()" :ref="clickable_refs[i]" :visible="false" />
|
||||
</template>
|
||||
</TresGroup>
|
||||
</TresGroup>
|
||||
</template>
|
Loading…
Reference in New Issue