Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Калькулятор услуг (https://javascript.ru/forum/misc/78797-kalkulyator-uslug.html)

joyandjoy 06.11.2019 09:12

Калькулятор услуг
 
Здравствуйте!
Нужна помощь с калькулятором.

Задача у меня такая:
Пытаюсь собрать калькулятор, не могу придумать алгоритм.

Цена зависит от таких факторов - размер, тип, упаковка, рамка. Все это уже предусмотренно, и конкретные размеры, тип, пользователю предоставляется только выбор.

1. Начинает пользователь с главного, размер, пусть будет три размера 10*10, 20*20 и 30*30.
2. После выбирает тип, пусть будет тип 1, тип 2 и тип3
Цена зависит от размера т.е. если размер 10*10 и тип1 или тип2 или тип3, то цена 100, если размер 20*20 и тип1 или тип2 или тип3 - цена 200, если размер 30*30 и тип1 или тип 2, или тип3 цена 300.
3. Выбирает рамку, она зависит от размера, если размер 10*10 цена 100, если размер 20*20 цена 200, если 30 на 30 цена 300. Если рамка не нужна, то нечего не складывается.
4. Выбор упаковки, аналогично с рамкой, зависит от размера, 10*10 цена 100, если размер 20*20 цена 200, если 30 на 30 цена 300. Если упаковка не нужна, то нечего не складывается.

Т.е. есть 4 пункта, все 4 надо выбрать (кроме последних двух, они не обязательны, но если выбираются, то нужно добавлять к основной сумме).

Есть такая форма
<form method="POST" action="send.php" id="order">
        <label>Размер: </label>
        <select name="size">
            <option></option>
        </select><br />
        <label>Тип: </label>
        <select name="type">
            <option></option>
        </select><br />
        <label>рамка: </label>
        <select name="ramka">
            <option></option>
        </select><br />
        <label>упаковка: </label>
        <select name="upakovka">
            <option></option>
        </select><br />		
        <label id="price">Цена: </label><br />
        <input type="submit" value="Заказать">
    </form>

Проверка на заполненность и вычисление цены в зависимости от размера и типа.
$("#order").validate({
            rules: {
                size: {
                    required: true
                },
                type: {
                    required: true
                }
				ramka: {
                    required: true
                },
                upakovka: {
                    required: true
                }
				
            },
            messages: {
                size: {
                    required: "Не выбран размер."
                },
                type: {
                    required: "Не выбран тип."
                }
				ramka: {
                    required: "Не выбрана рамка."
                },
                upakovka: {
                    required: "Не выбрана упаковка."
                }	
		
            }
        });
        var sizes = [{ id: 1, value: "А6" }, { id: 2, value: "А5" }, { id: 3, value: "А4" }];
        var types = [{ id: 1, value: "Тип 1" }, { id: 2, value: "Тип 2" }, { id: 3, value: "Тип 3" },];
  
  
        var prices = [
            { id: 1, sizeId: 3 && 2 && 1, typeId: 1, value: 0 }, { id: 2, sizeId: 1, typeId: 2, value: 150 }, { id: 3, sizeId: 1, typeId: 3, value: 200 },
{ id: 4, sizeId: 2, typeId: 2, value: 250 }, { id: 5, sizeId: 2, typeId: 3, value: 300 },
 { id: 6, sizeId: 3, typeId: 2, value: 350 }, { id: 7, sizeId: 3, typeId: 3, value: 400 },
        ];
        var sizeEl = $("#order")[0]["size"],
            typeEl = $("#order")[0]["type"];
        for (var i = 0; i < sizes.length; i++)
            sizeEl.add(new Option(sizes[i].value, sizes[i].id));
        for (var i = 0; i < types.length; i++)
            typeEl.add(new Option(types[i].value, types[i].id));
 
        sizeEl.onchange = calculatePrice;
        typeEl.onchange = calculatePrice;
 
        function calculatePrice() {
            var e = prices.find(function (e) { return e.sizeId == sizeEl.value && e.typeId == typeEl.value; });
            $("#price").text("Цена: " + (e ? e.value : ""));
        }

Запутался как дальше реализовать сложение следующих двух пунктов. Понимаю что аналогично с размером, но как правильно - не могу понять.

laimas 06.11.2019 09:33

Начинает пользователь с главного, размер, пусть будет три размера 10*10, 20*20 и 30*30.
<select name="size">....

Логично.

После выбирает тип, пусть будет тип 1, тип 2 и тип3.
<select name="type">...


Логично.

Выбирает рамку, она зависит от размера
<select name="ramka">...


Не понятно. Размера чего, основного или своего? Если первое, то причем тут список? А упаковка, это черная, белая, красная или просто выбрать/нет ее?

joyandjoy 06.11.2019 10:22

Цитата:

Сообщение от laimas (Сообщение 514963)
Начинает пользователь с главного, размер, пусть будет три размера 10*10, 20*20 и 30*30.
<select name="size">....

Логично.

После выбирает тип, пусть будет тип 1, тип 2 и тип3.
<select name="type">...


Логично.

Выбирает рамку, она зависит от размера
<select name="ramka">...


Не понятно. Размера чего, основного или своего? Если первое, то причем тут список? А упаковка, это черная, белая, красная или просто выбрать/нет ее?

Вроде постарался подробно изложить, нашли изъяны :)

Есть изделие, оно основное, и все относится к изделию, размер изделия, упаковка и рамка для изделия, рамка и упаковка зависит от размера самого изделия, больше изделие нужно больше упаковки, и больше рамка, а значит выше себестоимость.

Рамка пусть будет рамка1, рамка 2, рамка3.
Упаковка пусть будет упаковка1, упаковка2, упаковка3.

Т.е. выбирает пользователь размер, например 10*10 и например тип2, получает цену, к ней нужно добавить цену рамки и упаковки, если они нужны (на выбор пользователя), а их цены зависят от размеров изделия (10*10 и т.д.). По итогу пользователь получает конечную сумму изделия, с учетом выбранного размера, а также включенную в стоимость рамку и упаковку если это нужно.

laimas 06.11.2019 11:00

Я о том, что в описанном не понять как же все завязано на размере. Было бы понятно, например, если бы:

1) Есть базовая цена Р печати за площадь рваную 1 дм (10х10). Выбор площади, это умножение базовой цены на выбранную площадь.

2) Есть базовые цены за рамку из: дерева, пластика, железа. В зависимости от площади печати (размера исходника) базовая цена каждого типа рамки увеличивается на N%: 10х10 = Р * 1, 20х20 = Р * 1.2, 30х30 = Р * 1.3. Подобным образом и цены других позиций зависят от размера.

3) Упаковка, либо выбрать ее и добавить к цене фиксированное значение и это флажок, либо это разный материал упаковки с разной ценой или также надбавка за размер только тогда это список.

Либо вариант для всех один - выбор любого в позициях, это увеличение единственной базовой цены на N%.

У вас же фиксированные цены для каждой позиции в каждом списке, но при этом запутанный объект их описывающий.

joyandjoy 06.11.2019 11:35

Давайте попробую по другому объяснить.

1. Вот базовые цены:

2. Рамки

3. Упаковка


Пользователь выбирает размер и тип обязательно (получает цену из пункта 1), затем (необязательно), выбирает рамку (цена рамки складывается с базовой ценой), после (необязательно), выбирает упаковку (цена упаковки складывается с предыдущей ценой).

Т.е. основной пункт это размеры, размеры фиксированные, тип, упаковка, рамка - у каждого пункта своя цена и зависит от этого самого размера, и складывается между собой.

laimas 06.11.2019 11:58

Если так, то зачем же кухня с объектом, поместите цены в опции списков, а по изменению в них выбирайте значения списков (либо из data атрибута выбранной опции) и складывайте. Что может быть проще?

joyandjoy 06.11.2019 12:00

Цитата:

Сообщение от laimas (Сообщение 514969)
Если так, то зачем же кухня с объектом, поместите цены в опции списков, а по изменению в них выбирайте значения списков (либо из data атрибута выбранной опции) и складывайте. Что может быть проще?

Не понимаю что имеете в виду, можно пример?

laimas 06.11.2019 12:09

Ну кроме указанного в таблице есть ведь список, главный, где нужно выбрать размер, так?

joyandjoy 06.11.2019 12:49

Цитата:

Сообщение от laimas (Сообщение 514971)
Ну кроме указанного в таблице есть ведь список, главный, где нужно выбрать размер, так?

Только таблицы. Посмотрите html форму.
1. Выбор размера (10*10, 20*20, 30*30).
2. Тип - цена зависит от пункта 1. Цены только из таблицы с типами.
3. Рамка - цена зависит от пункта 1. Цены только из таблицы с рамками.
4. Упаковка - цена зависит от пункта 1. Цены только из таблицы с упаковками.

Алгоритм пользователя:
Выбор размера - 10*10
Выбор типа - тип 2
Цена = 150
Выбор рамки (необязательно) - Рамка2
Цена = 150 + 150
Цена = 300
Выбор упаковки (необязательно) - Зеленая
Цена 300 + 200
Цена: 500


laimas 06.11.2019 13:00

Я на JQ, чтобы короче:

<form method="POST" action="send.php" id="order">
        <label>Размер: </label>
        <select name="size" required>
            <option value="" disabled selected>Выбрать</option>
            <option value="1">10x10</option>
            <option value="2">20x20</option>
            <option value="3">30x30</option>
        </select><br />
        <label>Тип: </label>
        <select name="type" required>
            <option value="" disabled selected>Выбрать</option>
            <option data-price="[100,200,300]" value="1">Тип 1</option>
            <option data-price="[150,250,350]" value="2">Тип 2</option>
            <option data-price="[200,300,400]" value="3">Тип 3</option>
        </select><br />
        <label>рамка: </label>
        <select name="frame">
            <option value="">Выбрать</option>
            <option data-price="[100,200,300]" value="1">Рамка 1</option>
            <option data-price="[150,250,350]" value="2">Рамка 2</option>
            <option data-price="[200,300,400]" value="3">Рамка 3</option>
        </select><br />
        <label>упаковка: </label>
        <select name="packing">
            <option value="">Выбрать</option>
            <option data-price="[100,200,300]" value="1">Красная</option>
            <option data-price="[150,250,350]" value="2">Синяя</option>
            <option data-price="[200,300,400]" value="3">Зеленая</option>
        </select><br />
	
        Итого: <output name="total"></output><br />
        <input type="submit" value="Заказать">
    </form>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$('#order').on('change', 'select', function(e) {
    var f = e.delegateTarget, p = $('select', f), size = p.eq(0).children(':selected').index()-1, v = 0;
    
    if(!p.filter(function() {
        return this.required && !this.value    
    }).length) {
        $.each(p.slice(1), function() {
            v += this.value ? $(this).children(':selected').data('price')[size] : 0
        });
        f.total.value = v;
    }
});
</script>


Правильно считает?

joyandjoy 06.11.2019 13:17

Нет :-? Размер 30*30, тип3, выходит 400, рамка 2, должно получится 750, калькулятор считает 700.

laimas 06.11.2019 13:22

Цитата:

Сообщение от joyandjoy
должно получится 750

С чего вдруг?

Размер 30*30 - это индекс 2. Далее по вашим ценам:
Для типа 3 это значение из массива: [300,350,400][2] = 400.
Для рамки 2 это значение из массива: [200,250,300][2] = 300.
400 + 300 = 700

laimas 06.11.2019 13:31

А, да, надо было цены из таблицы вставлять в массивы не построчно, а брать из столбцов. Ну это не проблема, сейчас исправим.

joyandjoy 06.11.2019 13:33

Берм размер 20*20, тип 3, цена 300, рамку 2, цена 550, а калькулятор выводит 500.

joyandjoy 06.11.2019 13:33

А ок :)

laimas 06.11.2019 13:35

Исправлено, теперь верно?

joyandjoy 06.11.2019 13:41

Вроде как да :) Спасибо. Еще такой момент остался, если пользователь не выбрал рамку или упаковку, как отобразить текущую цену?

laimas 06.11.2019 13:48

Цитата:

Сообщение от joyandjoy
Еще такой момент остался, если пользователь не выбрал рамку или упаковку, как отобразить текущую цену?

А как он может не выбрать рамку, если у вас этот список обязателен для выбора? Упаковка понятно, она не обязательна, поэтому в расчете и проверяется значение списка, и по результату берется либо значение из массива, либо 0. В противном случае, при обязательном выборе всех списков, такая проверка не нужна.

laimas 06.11.2019 13:53

Если нужно чтобы расчет производился в любом случае, то убрать условие и так:

$('#order').on('change', 'select', function(e) {
    var f = e.delegateTarget, p = $('select', f), v = 0, size = p.eq(0).val()-1;
    $.each(p.slice(1), function() {
        v += this.value ? $(this).children(':selected').data('price')[size] : 0
    });
    f.total.value = v;
});

joyandjoy 06.11.2019 13:55

Цитата:

Сообщение от laimas (Сообщение 514981)
А как он может не выбрать рамку, если у вас этот список обязателен для выбора? Упаковка понятно, она не обязательна, поэтому в расчете и проверяется значение списка, и по результату берется либо значение из массива, либо 0. В противном случае, при обязательном выборе всех списков, такая проверка не нужна.

Цитата:

Сообщение от joyandjoy (Сообщение 514962)
есть 4 пункта, все 4 надо выбрать (кроме последних двух, они не обязательны, но если выбираются, то нужно добавлять к основной сумме).

Цитата:

Сообщение от joyandjoy (Сообщение 514972)
Выбор рамки (необязательно) - Рамка2

Выбор упаковки (необязательно) - Зеленая

Обязателен только размер и тип. Рамка и упаковка не обязательны, т.е. если человеку нужна только упаковка то складываем цену изделия базовую и упаковку, если рамка только, то базовая цена и рамка, если и то и то, то базовая цена + рамка + упаковка.

joyandjoy 06.11.2019 13:58

А ну вот. Да. Теперь все работает. Еще потестирую. Проще было чем в варианте из шапки темы)
Спасибо!

laimas 06.11.2019 13:58

Цитата:

Сообщение от joyandjoy
Обязателен только размер и тип. Рамка и упаковка не обязательны

Уберите атрибут required у списка frame и атрибуты disabled и selected у его первой опции.

С условием проверки будет считать при обязательном выборе размера и типа (код менять не требуется), а без условия всегда (код как в посте #19).

laimas 06.11.2019 14:08

Цитата:

Сообщение от joyandjoy
Проще было чем в варианте из шапки темы

Ну так кто вас заставляет так запутанно объект описывать. Можно и не в атрибутах держать цены, а описать их в js объекте. Все зависит от того как удобнее на сервере формировать страницу, он ведь ведает этими данными, он готовит все.

Но если вы оперируете списками, от которых зависит итог, значит имена первичных ключей (свойств) объекта выгоднее сделать равными именам списков, под которыми содержатся обычные индексные массивы цен. Зачем тут объекты, если проще представлять размер как индекс этих массивов?

joyandjoy 06.11.2019 18:01

Цитата:

Сообщение от laimas (Сообщение 514986)
Ну так кто вас заставляет так запутанно объект описывать. Можно и не в атрибутах держать цены, а описать их в js объекте. Все зависит от того как удобнее на сервере формировать страницу, он ведь ведает этими данными, он готовит все.

Но если вы оперируете списками, от которых зависит итог, значит имена первичных ключей (свойств) объекта выгоднее сделать равными именам списков, под которыми содержатся обычные индексные массивы цен. Зачем тут объекты, если проще представлять размер как индекс этих массивов?

Ну надо тоже понимать, уровень владения совершенно разный)

laimas 06.11.2019 18:09

Цитата:

Сообщение от joyandjoy
Ну надо тоже понимать, уровень владения совершенно разный

Да что тут понимать то ) Вот в примере так определяется индекс по которому будет выбираться значение:

size = p.eq(0).val()-1;

то есть, берется значение списка размера (выбранной опции), вычитается 1, понятно, потому как индексы начинаются с 0. Но ведь форма отправляется на сервер, а значения опций списков это только в примере чинно от 1, а в реалии это может быть какое-то уникальное значение, например 83, под которым сервер хранит такой набор.

Непорядок, и корректнее брать индекс выбранной опции (опции списка, это коллекция, следовательно в этом наборе они тоже имеют индексы) минус единица:

size = p.eq(0).children(':selected').index()-1


Часовой пояс GMT +3, время: 02:01.