• HTML
  • JavaScript
  • PHP

Как на сайте создать калькулятор услуг?

Здравствуйте! Скажите, а как можно реализовать калькулятор услуг на сайте с капчей и отправкой информации на email? Выбор услуг нужно отмечать просто установкой галочки.

Возможно, уже имеются готовые скрипты?

Комментарии: 7

Booba
Booba
style.css
#chekboxes {
  padding-top: 9px;
}

label {
  display: block;
}

label ~ label {
  padding-left: 5px;
}

.label {
  vertical-align: top;
  padding: 0, 3px, 0, 0;
}

.checkbox {
  display: none;
}

.checkbox-custom {
  display: inline-block;
  position: relative;
  width: 10px;
  height: 10px;
  border: 2px solid #ccc;
  border-radius: 3px;
}

.label {
  font-family: GOTHAPROREG;
  font-size: 14px;
  color: #333;
  white-space: pre-wrap;
}

.checkbox:checked + .checkbox-custom::before {
  content: "";
  display: block;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 2;
  left: 0;
  margin: auto;
  background: url(2832.png) no-repeat !important;
  border-radius: 2px;
  width: 14px;
  height: 24px;
}

.checkbox:disabled + .checkbox-custom {
  display: inline-block;
  position: relative;
  width: 20px;
  height: 20px;
  border: 2px solid #ccc;
  background: gray;
  border-radius: 3px;
}
Александр Мальцев
Александр Мальцев
Например, элементы checkbox:
<div class="checkbox">
  <label>
    <input type="checkbox" value="200"> Нажми на меня
  </label>
</div>
<div class="checkbox">
  <label>
    <input type="checkbox" value="300"> Нажми на меня
  </label>
</div>
<!-- Элемент, в которой будем выводить результат -->
<p id="result"></p>

Ну и сам скрипт, кооторый будет считать:
<script>
$(function(){
  $('input[type="checkbox"]').click(function(){
    var result = 0;
    $('input[type="checkbox"]:checked').each(function(){
      result += parseInt($(this).val());
    });
    $('#result').text(result);
  });
});
</script>
Также можно дать идентификаторы элементам и используя вышеприведённый код добавить их в массив.
После этого необходимо добавить результат в объект в formData (для отправки его на сервер):
formData.append('result', $('#result').text());

После этого можно получить данные на сервере ($_POST['result']) и отправить их на почту.
Booba
Booba
Спасибо. Заработало. Цену(окончательную) отправляет, а вот добиться отправки позиций отмеченных так и не смог, если направите в нужном направлении буду благодарен.
Александр Мальцев
Александр Мальцев
Отправлять лучше наверно не только позиции, но их цену. Наиболее просто это сделать в формате JSON.
HTML-код:
<div class="checkbox">
  <label>
    <input id="id1" type="checkbox" value="200"> Услуга 1
  </label>
</div>
<div class="checkbox">
  <label>
    <input id="id2" type="checkbox" value="300"> Услуга 2
  </label>
</div>
JavaScript код, который необходимо добавить в script.js:
// массив позиций
var positions = [];
// перебираем все установленные позиции
$('input[type="checkbox"]:checked').each(function(){
  // добавляем их в массив
  positions.push({
    'id': $(this).attr('id'),
    'value': $(this).val()
  });
});
Также его необходимо добавить в formData для его отправки на сервер:
formData.append('positions', JSON.stringify(positions));
На сервере получаем позиции и перебираем их:
$positions = json_decode($_POST['positions'],true);
$positionsToMail = '';
foreach($positions as $position) {
  $positionsToMail .= 'id='.$position['id'].' , value='.$position['value'].'
';
}
После этого помещаем полученный результат в тело письма.
$output .= $positionsToMail;
Booba
Booba
<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <title>Форма обратной связи</title>
  <link rel="stylesheet" href="feedback/css/jquery-ui-1.8.18.custom.css">
  <link rel="stylesheet" href="feedback/css/bootstrap.min.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="container">
    <div class="row">
      <div class="col-sm-6 col-sm-offset-3 col-md-9 col-md-offset-0">
        <!-- Контейнер, содержащий форму обратной связи -->
        <div class="panel panel-info">
          <!-- Заголовок контейнера -->
          <div class="panel-heading">
            <h3 class="panel-title text-center">Форма обратной связи</h3>
          </div>
          <!-- Содержимое контейнера -->
          <div class="panel-body">

            <!-- Сообщение, отображаемое в случае успешной отправки данных -->
            <div class="alert alert-success hidden" role="alert" id="msgSubmit">
              <strong>Внимание!</strong> Ваше сообщение отправлено.
            </div>

            <!-- Форма обратной связи -->
            <form id="messageForm" enctype="multipart/form-data">
              <div class="row">

                <div id="error" class="col-sm-12" style="color: #ff0000; margin-top: 5px; margin-bottom: 5px;"></div>
                <!-- Имя и email пользователя -->
                <div class="col-sm-6">
                  <!-- Имя пользователя -->
                  <div class="form-group has-feedback">
                    <label for="name" class="control-label">Введите ваше имя:</label>
                    <input type="text" id="name" name="name" class="form-control" required="required" value="" placeholder="Например, Иван Иванович" minlength="2" maxlength="30">
                    <span class="glyphicon form-control-feedback"></span>
                  </div>
                </div>
                <div class="col-sm-6">
                  <!-- Email пользователя -->
                  <div class="form-group has-feedback">
                    <label for="email" class="control-label">Введите адрес email:</label>
                    <input type="email" id="email" name="email" class="form-control" required="required"  value="" placeholder="Например, ivan@mail.ru" maxlength="30">
                    <span class="glyphicon form-control-feedback"></span>
                  </div>
                </div>
              </div>
			  
<div id="chekboxes" class="container">
    <div class="col-sm-6 col-md-2">
      <label for="cbox1">
        <input class="checkbox" type="checkbox" id="cbox1" value="0">
        <span class="checkbox-custom"></span>
        <span class="label color">cbox1</span>
      </label>
      <label for="cbox11">
        <input class="checkbox" type="checkbox" id="cbox11" value="5000">
        <span class="checkbox-custom"></span>
        <span class="label">cbox11</span>
      </label>
      <label for="cbox12">
        <input class="checkbox" type="checkbox" id="cbox12" value="120000">
        <span class="checkbox-custom"></span>
        <span class="label">cbox12</span>
      </label>
      <label for="cbox13">
        <input class="checkbox" type="checkbox" id="cbox13" value="60000">
        <span class="checkbox-custom"></span>
        <span class="label">cbox13</span>
      </label>
    </div>
				  
			  
    <div class="col-sm-6 col-md-2">
      <label for="cbox2">
        <input class="checkbox" type="checkbox" id="cbox2" value="0">
        <span class="checkbox-custom"></span>
        <span class="label">cbox2</span>
      </label>
      <label for="cbox21">
        <input class="checkbox" type="checkbox" id="cbox21" value="20000">
        <span class="checkbox-custom"></span>
        <span class="label">cbox21</span>
      </label>
      <label for="cbox22">
        <input class="checkbox" type="checkbox" id="cbox22" value="35000">
        <span class="checkbox-custom"></span>
        <span class="label">cbox22</span>
      </label>
      <label for="cbox23">
        <input class="checkbox" type="checkbox" id="cbox23" value="30000">
        <span class="checkbox-custom"></span>
        <span class="label">cbox23</span>
      </label>
    </div>
 
    <div class="col-md-2">
      <label for="cbox3">
        <input class="checkbox" type="checkbox" id="cbox3" value="0">
        <span class="checkbox-custom"></span>
        <span class="label">cbox3</span>
      </label>
      <label for="cbox31">
        <input class="checkbox" type="checkbox" id="cbox31" value="5000">
        <span class="checkbox-custom"></span>
        <span class="label">cbox31</span>
      </label>
      <label for="cbox32">
        <input class="checkbox" type="checkbox" id="cbox32" value="15000">
        <span class="checkbox-custom"></span>
        <span class="label">cbox32</span>
      </label>
    </div>
    

    <div class="col-sm-6 col-xs-offset-1 col-md-10">
      <p>Итого от <span id="sum1">0</span>
	  <i class="fa fa-rub" aria-hidden="true"></i></p>
    </div>
  </div>
              <!-- Сообщение пользователя -->
            
              <hr style="margin-top: 3px; margin-bottom: 3px;">

              <!-- Капча к форме -->
              <!-- Изображение, содержащее код CAPTCHA-->		  
	            <img id="img-captcha" src="/feedback/captcha.php">
              <!--Элемент, запрашивающий новый код CAPTCHA-->
	            <div id="reload-captcha" class="btn btn-default"><i class="glyphicon glyphicon-refresh"></i> Обновить</div>
	            <!--Блок для ввода кода CAPTCHA-->
	            <div class="form-group has-feedback col-md-7">
                <label id="label-captcha" for="captcha" class="control-label">Пожалуйста, введите указанный на изображении код:</label>
	              <input id="text-captcha" name="captcha" type="text" class="form-control" required="required" value="" minlength="6" maxlength="6" autocomplete="off">
	              <span class="glyphicon form-control-feedback"></span>
              </div>

              <!-- Кнопка, отправляющая форму по технологии AJAX -->  
              <button name="send-message" type="submit" class="btn btn-primary pull-right">Отправить сообщение</button>
            
            </form><!-- Конец формы -->
          </div>
        </div><!-- Конец контейнера -->

      </div>
    </div>
  </div>

  <script src="feedback/js/jquery-1.12.4.min.js"></script>
  <script src="feedback/js/bootstrap.min.js"></script>
  <script src="feedback/script.js"></script>

</body>
</html>

"use strict"
var initChekbox = function(id, parent, children, target, expression, disableWhenActive) {
  var o = {
    "el": document.getElementById(id),
    "parent": parent || false,
    "children": [],
    "target": document.getElementById(target),
    "active": false,
    "disable": false,
    "disableWhenActive": disableWhenActive || false,
    "expression": expression || "sum",
    "hasChildren": (children.length > 0) ? true : false,
    "calcRes": function(expression, sum, value) {
      var sum = sum.replace(/\s*/g, '') * 1, // форматируем удаляя лишние пробелы и преобразуем в число
        value = value * 1,
        result = 0;
      switch (expression) {
        case "sum":
          result = sum + value;
          break;
        case "sub":
          result = sum - value;
          break;
        case "reset":
          result = 0;
          break;
        case "set":
          result = value;
          break;
      }
      result = result.toString().replace(/(\d{1,3}(?=(\d{3})+(?:\.\d|\b)))/g, "\$1 "); // форматирование(отделение тысяч пробелом)
      return result
    },
    "activation": function() {
      if (!this["active"]) {
        this["active"] = true;
        this.el.checked = true
      };
      this.target.textContent = this.calcRes(this.expression, this.target.textContent, this.el.getAttribute("value"));
      if (this.hasChildren) {
        this.children.forEach(function(item) {
          if (!item.active) {
            item.activation()
          };
        })
      }
    },
    "deactivation": function() {
      if (this["active"]) {
        this["active"] = false;
        this.el.checked = false
        this.target.textContent = this.calcRes("sub", this.target.textContent, this.el.getAttribute("value"));
      };
      if (this.parent) {
        this.parent["active"] = false;
        this.parent.el.checked = false
      };
      if (this.hasChildren) {
        this.children.forEach(function(item) {
          item.deactivation()
        })
      };
    },
    "disabling": function() {
      if (!this.disable) {
        this.disable = true;
        this.el.disabled = true;
        this.deactivation();
      } else {
        this.disable = false;
        this.el.disabled = false;
      }
    }
  };
  o["children"] = (o.hasChildren) ? children.map(function(item) {
    return initChekbox(item, o, [], o["target"].id)
  }) : false;
  return o
};
// получение свойств объекта
var getPropertyObject = function(o, exclude) {
  var i = [],
    exclude = exclude | "";
  for (var prop in o) {
    if (o.hasOwnProperty(prop)) {
      i.push(o[prop])
    };
  }
  return i
}

// выбор чекбокса (первый клик)
var activateCheck = function(checkbox) {
  if (cboxes.hasOwnProperty(checkbox)) {
    if (cboxes[checkbox].disableWhenActive) {
      cboxes[checkbox].disableWhenActive.forEach(function(item) {
        if (item != cboxes[checkbox]) {
          item.disabling()
        }
      })
    }
    cboxes[checkbox].activation();
  };
};
// снятие выбора (второй клик)
var deactivateCheck = function(checkbox) {
  if (cboxes.hasOwnProperty(checkbox)) {
    cboxes[checkbox].deactivation();
    if (cboxes[checkbox].disableWhenActive) {
      cboxes[checkbox].disableWhenActive.forEach(function(item) {
        if (item != cboxes[checkbox]) {
          item.disabling()
        }
      })
    }
  };
};
// проверка на выбор
var isCheckActivated = function(checkbox) {
  return (cboxes.hasOwnProperty(checkbox)) ? cboxes[checkbox].active : document.getElementById(checkbox).getAttribute("checked");
};

// инициализация всех чекбоксов
var cboxes = {
  "cbox1": initChekbox("cbox1", undefined, ["cbox11", "cbox12", "cbox13"], "sum1"),
  "cbox2": initChekbox("cbox2", undefined, ["cbox21", "cbox22", "cbox23"], "sum1"),
  "cbox3": initChekbox("cbox3", undefined, ["cbox31", "cbox32"], "sum1"),
};
// добавление дополнительных параметров
// children cbox1
cboxes["cbox11"] = cboxes.cbox1.children[0];
cboxes["cbox12"] = cboxes.cbox1.children[1];
cboxes["cbox13"] = cboxes.cbox1.children[2];
// children cbox2
cboxes["cbox21"] = cboxes.cbox2.children[0];
cboxes["cbox22"] = cboxes.cbox2.children[1];
cboxes["cbox23"] = cboxes.cbox2.children[2];
// children cbox3
cboxes["cbox31"] = cboxes.cbox3.children[0];
cboxes["cbox32"] = cboxes.cbox3.children[1];
// custom event checkbox

// обработчик события для чекбоксов
jQuery("#chekboxes").on('click', 'input', function(e) {
  if (!e.target.disabled) {
    var targetId = e.target.id;
    (!isCheckActivated(targetId)) ? activateCheck(targetId): deactivateCheck(targetId);
  }
})

//после загрузки веб-страницы
$(function() {

  // при нажатии на кнопку "Обновить", выведим новый код капчи
  $('#reload-captcha').click(function() {
    $('#img-captcha').attr('src', '/feedback/captcha.php?id=' + Math.random() + '');
  });

  // при отправке формы messageForm на сервер (id="messageForm")
  $('#messageForm').submit(function(event) {
    // отменим стандартное действие браузера
    event.preventDefault();
    // заведём переменную, которая будет говорить о том валидная форма или нет
    var formValid = true;

    // перебирём все элементы управления формы (input и textarea) 
    $('#messageForm input,#messageForm textarea').each(function() {

      //если этот элемент капча, то не проверять его
      if ($(this).attr('id') == 'text-captcha') {
        return true;
      }
      //найти предков, имеющих класс .form-group (для установления success/error)
      var formGroup = $(this).parents('.form-group');
      //найти glyphicon (иконка успеха или ошибки)
      var glyphicon = formGroup.find('.form-control-feedback');
      //валидация данных с помощью HTML5 функции checkValidity
      if (this.checkValidity()) {
        //добавить к formGroup класс .has-success и удалить .has-error
        formGroup.addClass('has-success').removeClass('has-error');
        //добавить к glyphicon класс .glyphicon-ok и удалить .glyphicon-remove
        glyphicon.addClass('glyphicon-ok').removeClass('glyphicon-remove');
      } else {
        //добавить к formGroup класс .has-error и удалить .has-success
        formGroup.addClass('has-error').removeClass('has-success');
        //добавить к glyphicon класс glyphicon-remove и удалить glyphicon-ok
        glyphicon.addClass('glyphicon-remove').removeClass('glyphicon-ok');
        //если элемент не прошёл проверку, то отметить форму как не валидную 
        formValid = false;
      }
    });

    //проверяем элемент, содержащий код капчи
    //1. Получаем значение элемента input, содержащего код капчи
    var captcha = $("#text-captcha").val();
    //2. Если длина кода капчи, которой ввёл пользователь не равно 6,
    //   то сразу отмечаем капчу как невалидную (без отправки на сервер)
    if (captcha.length != 6) {
      // получаем элемент, содержащий капчу
      inputCaptcha = $("#text-captcha");
      //найти предка, имеющего класс .form-group (для установления success/error)
      formGroupCaptcha = inputCaptcha.parents('.form-group');
      //найти glyphicon (иконка успеха или ошибки)
      glyphiconCaptcha = formGroupCaptcha.find('.form-control-feedback');
      //добавить к formGroup класс .has-error и удалить .has-success
      formGroupCaptcha.addClass('has-error').removeClass('has-success');
      //добавить к glyphicon класс glyphicon-remove и удалить glyphicon-ok
      glyphiconCaptcha.addClass('glyphicon-remove').removeClass('glyphicon-ok');
    }

    // форма валидна и длина капчи равно 6 символам, то отправляем форму на сервер (AJAX)
    if ((formValid) && (captcha.length == 6)) {

      // получаем имя, которое ввёл пользователь	
      var name = $("#name").val();
      // получаем email, который ввёл пользователь
      var email = $("#email").val();
      // получаем сообщение, которое ввёл пользователь
      var message = $("#message").val();
      // получаем капчу, которую ввёл пользователь
      var captcha = $("#text-captcha").val();

      // объект, посредством которого будем кодировать форму перед отправкой её на сервер
      var formData = new FormData();
      // добавить в formData значение 'name'=значение_поля_name
      formData.append('name', name);
      // добавить в formData значение 'email'=значение_поля_email
      formData.append('email', email);
      // добавить в formData значение 'message'=значение_поля_message
      formData.append('message', message);
      // добавить в formData значение 'captcha'=значение_поля_captcha
      formData.append('captcha', captcha);

      // технология AJAX 
      $.ajax({
        //метод передачи запроса - POST
        type: "POST",
        //URL-адрес запроса 
        url: "/feedback/verify.php",
        //передаваемые данные - formData
        data: formData,
        // не устанавливать тип контента, т.к. используется FormData
        contentType: false,
        // не обрабатывать данные formData
        processData: false,
        // отключить кэширование результатов в браузере
        cache: false,
        //при успешном выполнении запроса
        success: function(data) {
          // разбираем строку JSON, полученную от сервера
          var $data = JSON.parse(data);
          // устанавливаем элементу, содержащему текст ошибки, пустую строку
          $('#error').text('');

          // если сервер вернул ответ success, то значит двнные отправлены
          if ($data.result == "success") {
            // скрываем форму обратной связи
            $('#messageForm').hide();
            // удаляем у элемента, имеющего id=msgSubmit, класс hidden
            $('#msgSubmit').removeClass('hidden');
          } else if ($data.result == "invalidCaptcha") {
            // Если сервер вернул ответ invalidcaptcha, то делаем следующее...

            //получаем элемент, содержащий капчу
            inputCaptcha = $("#text-captcha");
            //найти предка, имеющего класс .form-group (для установления success/error)
            formGroupCaptcha = inputCaptcha.parents('.form-group');
            //найти glyphicon (иконка успеха или ошибки)
            glyphiconCaptcha = formGroupCaptcha.find('.form-control-feedback');
            //добавить к formGroup класс .has-error и удалить .has-success
            formGroupCaptcha.addClass('has-error').removeClass('has-success');
            //добавить к glyphicon класс glyphicon-remove и удалить glyphicon-ok
            glyphiconCaptcha.addClass('glyphicon-remove').removeClass('glyphicon-ok');
            //вывести новый код капча
            $('#img-captcha').attr('src', '/feedback/captcha.php?id=' + Math.random() + '');
            //установить полю ввода капчи пустое значение
            $("#text-captcha").val('');
          } else {
            // Если сервер вернул ответ error, то делаем следующее...
            $('#error').text('Произошли ошибки при отправке формы на сервер.');
          }
        },
        error: function(request) {
          $('#error').text('Произошла ошибка ' + request.responseText + ' при отправке данных.');
        }
      });
    }
  });
});
verify.php не менял пока что.
Booba
Booba
Это я сделал, вот тольна примере обратной связи без файлов. Вписал туда список «товаров» — получил итого, но вот как добиться того, чтобы он выводил полученный итог и выбранные пункты пока не смог. Если не трудно помогите доработать.
Александр Мальцев
Александр Мальцев
Это можно организовать на базе формы обратной связи, которую можно взять со страницы: itchief.ru/lessons/php/pop-up-feedback-form
Только поля заменить на необходимые элементы. Ну и конечно если нужны расчёты и некоторый результат, то написать небольшой скрипт на JavaScript.