Наверх

Калькулятор услуг на php и javascript - формирование word.docx документа

Опубликовано:
19166
1 2 3 4 5
(85%) / 20

Доброго времени суток начинающие программисты, в этом уроке мы будем создавать онлайн калькулятор услуг. В качестве примера мы будем брать калькулятор ремонта, который делает онлайн расчет стоимости ремонта. 

Живой демо пример

Фишка этого калькулятора в том, что в итоге все расчеты можно сохранить в word документ и формирует он все данные за считанные мили-секунды. 

 

Для чего мы создаем такой калькулятор расчетов услуг

  1. Быстрая готовая смета
  2. Сформированный документ можно уже отправлять клиенту
  3. Экономия времени пользователю, тем самым повышаем КПД

 

Какие методы используем

  1. Формирование шаблона на HTML
  2. Использование многомерного массива в input
  3. Запросы к базе данных для вывода услуг
  4. Расчет при помощи javascript
  5. Php формирование документа

 

Создаем калькулятор расчета за 6 простых шагов

 

Шаг 1. Создаем базу данных в mysql

В источниках есть дамп базы данных, в ней находится 2 таблицы. В последующих шагах мы будем к ним обращаться.

price_cat - таблица с категориями
price_item - таблица с услугами

Создаем базу данных импортируем файл calculator.sql  в созданную базу данных и подключаемся к ней.

$dblocation = "localhost";
$dbname = "calculator";
$dbuser = "root";
$dbpasswd = "";
$dbcnx = @mysql_connect($dblocation,$dbuser,$dbpasswd);
if (!$dbcnx) {
echo( mysql_error() );
exit();
}
mysql_query("SET NAMES utf8",$dbcnx);
if (!@mysql_select_db($dbname, $dbcnx)) {
echo( mysql_error() );
exit();
}

Все готово. Теперь необходимо разметить html шаблон и одновременно формировать запросы к базе.

 

Шаг 2. Разметим html + php шаблон

Подключаем библиотеки, которые нам понадобятся

<link href="css/bootstrap.css" rel="stylesheet">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="js/calculator.js"></script>
<script src="js/bootstrap.min.js"></script>

Обратите внимания: 
Я использовал bootstrap компоненты, а так же библиотеку awesome иконки, а в calculator.js мы будем писать скрипт расчетов.

 

Разметка калькулятора

<div class="container">
<form method='post' action='save_word.php' >
<h1>Калькулятор ремонта</h1>
<?php 
$res_category = mysql_query("SELECT *FROM price_cat ORDER BY sort");
if(mysql_num_rows($res_category)>0)
{
?>
<div class="panel-group" id="accordion">
<?
$category = mysql_fetch_array($res_category);
$i=1;
do
{
?>
<div class="panel panel-default category">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" class="open_category" aria-expanded="false" data-parent="#accordion" href="#price_cat<?php echo $i;?>">
<i class="fa fa-angle-down"></i> <?php echo $category["name"];?> <span class="summa_category"></span>
</a>
<input type="hidden" name="category[<?=$i;?>][name]" value="<?php echo $category["name"];?>" />
<input type="hidden" name="category[<?=$i;?>][summa]" value="" class="summa_category_input" />
</h4>
</div>
<div id="price_cat<?php echo $i;?>" class="panel-collapse collapse">
<div class="">
<?php 
$res_item = mysql_query("SELECT *FROM price_item WHERE catid = '$category[id]'");
if(mysql_num_rows($res_item)>0)
{
?>
<div class="teble-responsive">
<table class="table table-striped">
<th>Наименование работ</th>
<th style="text-align:center;">Ед. изм.</th>
<th style="text-align:center;">Стоимость</th>
<th style="text-align:center;">Кол-во</th>
<th style="text-align:center;">Сумма</th>
<?
$item = mysql_fetch_array($res_item);
$k=1;
do
{
$price = number_format($item["cost"], 0, '', ' ');
?>
<tr>
<td>
<span class=""><?php echo $item["name"];?></span>
<input type="hidden" name="category[<?=$i;?>][items][<?=$k;?>][name]" value="<?php echo $item["name"];?>" />
</td>
<td style="text-align:center;">
<span class=""><?php echo $item["shortdesc"];?></span>
<input type="hidden" name="category[<?=$i;?>][items][<?=$k;?>][ed_izm]" value="<?php echo $item["shortdesc"];?>" />
</td>
<td style="text-align:center;">
<span class=""><?php echo $price;?></span>
<input type="hidden" name="category[<?=$i;?>][items][<?=$k;?>][price]" value="<?php echo $item["cost"];?>" />
</td>
<td><input type="number" step="0.1" min="0" class="form-control calc" name="category[<?=$i;?>][items][<?=$k;?>][kolvo]" value="" style="width:70px; margin:0 auto;"></td>
<td><input type="text" readonly="readonly" class="form-control item_summa" name="category[<?=$i;?>][items][<?=$k;?>][summa]" value="" style="width:80px; margin:0 auto; text-align:center;"></td>
</tr>
<?	
$k++;
}
while($item = mysql_fetch_array($res_item));
?>
</table>
</div>
<?
}
?>
</div>
</div>
<div class="panel-body" style="border-top:1px solid #ddd;">
<div class="pull-right">
<div><strong>Итого:</strong> <big class="summa_category">0</big> руб.</div>
</div>
</div>
</div>
<?
$i++;
}
while($category = mysql_fetch_array($res_category));
?>
</div>
<?
}
?>

<div class="panel-body well well-sm">
<div class="row">
<div class="col-xs-12 col-md-6 "><button class="btn btn-primary btn-sm" name="save_word">Сохранить в WORD документ</button></div>
<div class="col-xs-12 col-md-6">
<div class=" pull-right" style="font-size:20px;">
<strong>Итого:</strong> <span class="total">0</span> руб.
<input type="hidden" name="total" class="total_input" value="" />
</div>
</div>
</div>
</div>
</form>
</div>

Как видим ничего сложного нет, очень простые запросы к базе, очень простой html код. Единственное на что хотел обратить внимание, это на то что мы используем многомерный массив input. В файле обработчике мы будет работать с ними и научимся извлекать нужные данные из них.

Теперь самое интересное. Напишем скрипт для расчета стоимости услуг на javascript.

 

Шаг 3. Пишем скрипт на javascript онлайн расчета

Некоторые строки я пояснил прямо в коде. 

$(function(){
	// смена стрелочки у категории
	$(".open_category").click(function(){
		var status = $(this).attr("aria-expanded")
		if(status=="false")
		{
			$(this).find("i").attr("class","fa fa-angle-up");
		}
		else
		{
			$(this).find("i").attr("class","fa fa-angle-down");
		}
	})
	
	
	// событие при наборе кол-ва в калькуляторе
	$(".calc").on("change keyup", function(){
		var value = $(this).val();
		var price = $(this).parent().prev().find("input").val();
		price = price.replace(/\s/g, ''); // удаляем пробелы
		var item_summa = value*price;
		item_summa = item_summa.Crop(2); // 2 знаka после запятой
		$(this).parent().next().find("input").val(item_summa);
		
		
		var summa_category = 0; // сюда будем загонять сумму в каждоый категории
		var total_summa = 0; // сюда будем загонять итоговую сумму
		var item_summa_category = $(this).parent().next().find("input");
		$(item_summa_category).each(function(){ // пробегаемся по всем суммам и суммируем
			var k = parseFloat($(this).val());
			if(!k || k==0){k=0;}
			summa_category += k;
		})
		
		// записываем расчеты по категориям
		$(this).parents(".category").find(".summa_category").text(summa_category); 
		$(this).parents(".category").find(".summa_category_input").val(summa_category);
		
		$("big.summa_category").each(function(){ // пробегаемся по всем суммам в категориях и суммируем
			var t = parseFloat($(this).text());
			if(!t || t==0){t=0;}
			total_summa += t; // считаем общую стоимость
			
		})
		
		// выводим итоговую сумму
		$(".total").text(total_summa);
		$(".total_input").val(total_summa);
		
	})
	
})

// функция знаки после запятой
Number.prototype.Crop = function (x){
	var s = this+'', a = s.split('.');
	a[1]=a[1]||'';      
	return parseFloat(a[0]+'.'+a[1].substring(0,x));
}

Отлично теперь, если вы сделали все правильно, то у наш созданный калькулятор уже должен считать.

 

Шаг 4. Пишем скрипт формирования содержимого в word.docx документ.

В исходниках есть файл sample.rtf, его вы должны разместить у Вас на сервере. Он послужит нам шаблоном для создания документа формата .docx на php. Он так же содержит метки, куда мы будем присваивать переменные, созданные в файле save_word.php. Этот файл и есть обработчик формирования word документа.

Файл save_word.php

header('Content-Type: text/html; charset= utf-8');
$categories = isset($_POST['category']) ? $_POST['category'] : array(); // Записываем в многомерный массив все инпуты, которые мы разметели с помощью цикла в php

//В Переменную word мы будем присваивать все что мы расчитали.
$word = "<div style=\"font-family: Helvetica, Arial, sans-serif;\"><table cellpadding=\"0\" border=\"1\" cellspacing=\"0\" style=\"width:100%; border-color: #ddd;\">";

// пробегаемся по категориям
foreach($categories as $category) {
	if($category["summa"]!=0) //Проверяем, если есть расчеты в категории, то считаем.
	{	
		// Обратите внимания, в переменнюу word мы присваем с точкой в начале ".=", это значит что мы добавляем содержимое к тому что было ранее. То есть иными словами Лево+Право=ЛевоПраво
		$word .= "<tr><th colspan=\"5\"><div style=\"font-family: Helvetica, Arial, sans-serif; padding:15px; text-align:left; background: #ececec; font-size: 16px;\">$category[name] ($category[summa] руб.)</th></div></tr>";
		$word .= "
		<tr style=\"font-size:13px;\">
				<td><div style=\"padding:5px; font-family: Helvetica, Arial, sans-serif;\"><strong>Наименование работ</strong></div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif; padding:5px; text-align:center\"><strong>Ед. изм.</strong></div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center\"><strong>Стоимость</strong></div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center\"><strong>Кол-во</strong></div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center\"><strong>Сумма</strong></div></td>
				</tr>
		";
		foreach($category["items"] as $items) //Пробегаемся по всем услугам
		{
			if($items["summa"]!=0) // По аналогии. ну тут понятно думаю.
			{
				$word .="<tr style=\"font-size:12px;\">
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px;\">$items[name]</div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center;\">$items[ed_izm]</div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center;\">$items[price]</div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center;\">$items[kolvo]</div></td>
				<td><div style=\"font-family: Helvetica, Arial, sans-serif;padding:5px; text-align:center;\">$items[summa]</div></td>
				</tr>";
			}
		}
	}
}
$word .="</table>";

$word .="<div style=\"padding:15px; margin-top:30px; font-size:18px; \"><strong>Итого:</strong> ".$_POST['total']." руб.</div></div>";


$d=Date('d.m.Y');
$name_doc = "Ваш прайс-лист ($d)";
//Сгенерировать заголовки, которые упростят браузеру выбор требуемого приложения для визуализации 
header('Content-type: application/msword');
header('Content-disposition: inline; filename='.$name_doc.'.doc'); 

// Открыть файл шаблона 
$filename = 'sample.rtf'; 
$fp = fopen($filename,'r'); 

//прочитать шаблон в перменную 
$output = fread($fp, filesize($filename)); 
fclose($fp); 

//Заменить заполнители в шаблоне требуемыми переменными 
$output = str_replace('<<NAME>>',$word,$output); 
//Отправить сгенерированный документ в браузер 
html_entity_decode(iconv("utf-8", "windows-1251", $output), ENT_QUOTES, "windows-1251");

echo $output

 

В некоторых моментах мне было лень присваивать классы, прописывать к ним стили, а потом подключать новую CSS. По этому я писал стили прямо в коде в тегах, конечно же плохой пример, не делайте так, но из-за 2-3 строк, тоже время терять не хочется.

Все готово, можете тестировать и визуализировать выводимый word формат.

 

Вывод

В этом уроке мы создали онлайн калькулятор расчета услуг, на примере калькулятора ремонта, позаимствовав идею у сайта remont-cityper.ru. Написанный нами код очень сильно отличается от кода, который использован в демо примере. ( можете убедится сами). Так же мы научились создавать word документ под средством php, использовав шаблон rtf и специальные метки. Это отличный урок по созданию счетов, бланков, прайс-листов и т.д. 

 

Пишите комментарии по этому поводу, я буду раз услышать от вас рекомендации или советы.

 



Дорогой web-мастер.
Для меня очень важна обратная связь от Вас в виде лайков или рейтинга.
Пожалуйста оцените эту публикацию или поставь лайк за старание.
Статья подготовлена для Вас сайтом kisameev.ru
Перевел: Кисамеев Дмитрий
Статью просмотрели: 19166
Понравилось:
Поделится ссылкой
Сергей Князев
Привет, помогите вот тут https://c-wd.ru/uslugi/lending/ скрипт установить
Дмитрий Кисамеев
Если есть доступы от хостинга, то скидывайте на почту dima@kisameev.ru. Сделаю
Денис Дёмин
Дмитрий, Вы проделали колосальную работу. Спасибо Вашему мануалу. Он мне очень поможет в создании калькулятора.
Можно будет к Вам обратиться, если будут вопросы?
Спасибо большое
Дмитрий Кисамеев
Спасибо, за обратную связь, обращайтесь, попробую помочь.
Денис
Дмитрий, а подскажите пожалуйста, как мне сделать так, чтобы порог изменения поля "Кол-во" был равен 1, а не как на Вашем примере (0,1)?
Спасибо большое
Денис
Разобрался с шагом в 0,1
Вопрос в другом:
http://calc.denzip.ru/remont/
В графе "Итого" в конце формы он отображает только стоимость последнего посчитаного элемента вида (работ), а на демо сайте он считает сразу все позиции и как сделать еще чекбоксы со скидкой?
Спасибо большое, за уделенное время
Дмитрий Кисамеев
в чекбоксах у Вас должны быть значения например скидка 7% - это 0.93
и эти 0.93 умножаете на итоговую сумму
Получать значение скидки (0.93) так: var discount = parseFloat($("класс_чекбокса").val())
parseFloat - перевод в число на всякий случай.

Теперь записываем в переменную
var total_summa_discount = discount * total_summa

Ну и выводить ее в нужный ДИВ
$("КЛАСС_ДИВА").text("Итого со скидкой: "+total_summa_discount)
Денис
А можно дать это в исходнике поправленном?
Спасибо
Денис
Как решить эту проблему?
"В графе "Итого" в конце формы он отображает только стоимость последнего посчитаного элемента вида (работ), а на демо сайте он считает сразу все позиции"
Дмитрий Кисамеев
Перезалил файл calculator.js в исходниках
Денис
http://prntscr.com/kvqtit
http://prntscr.com/kvqtyw
Здравствуйте, Дмитрий. Все бы хорошо, но не работает :-(
http://calc.denzip.ru/remont/
Денис
Простите пожалуйста, Дмитрий. По ходу КЭШ был.
Все отлично работает
Анна
Здравствуйте! Спасибо за вашу работу. Подскажите, с помощью какого кода можно отправить расчеты в корзину.
Дмитрий Кисамеев
Здравствуйте, готового кода нет, если в теории, то нужно в БД создавать отдельную таблицы корзины и заказа.
Александр
Благодарю, написал бы и сам. Но реально Вы сэкономили мне время. Еще раз спасибо.
Николай
Очень годная штуковина, ещё и в вк всё объяснили. спасибо вам!
Дмитрий Кисамеев
Пожалуйста, пользуйтесь )
Антон
Добрый день.
Спасибо за разработку
Не понимаю, откуда он использует при формировании вордовского документа category?
Адаптирую для своих нужд.
Алексей
Всё супер
огромное спасибо
но при переходе на php7 вылетает ошибка
можете переделать код по 7ю версию

Спасибо
Алексей Александрович Морозов
Не соглашусь, что она прям колоссальная, как работа, но вот то что она актуальная и гениальная - это да!!!
Гость
не работает! Почему то...
Базу создал, данные базы указал.
Всё как обычно, НО
Fatal error: Uncaught Error: Call to undefined function mysql_connect() in C:OpenServerdomainskalkulyator-test.ruconnectdb.php:7 Stack trace: #0 C:OpenServerdomainskalkulyator-test.ruindex.php(1): include() #1 {main} thrown in C:OpenServerdomainskalkulyator-test.ruconnectdb.php on line 7

В чём может быть дело?
Дмитрий Кисамеев
Калькулятор тестировался под php версию 5.6
Возможно все mysql нужно переделать в mysqli

например: вместо mysql_connect попробовать написать mysqli_connect
Вместо mysql_query прописать mysqli_query
и т.п.
Гость
Можете исправить?
Дмитрий Кисамеев
нет, тут уж сами под свой сервер адаптируйтесь) экспериментируйте, пробуйте, подсказку дал )
на denwer локалке знаю что будет работать, на обычном хостинге тоже
на openserver не знаю
Гость
Да вы уж сделали бы нормальный рабочий скрипт, хотя бы посмотреть хоть что он из себя представляет, а там может и доработку индивидуальную заказал вам.
Гость
Напишите мне пожалуйста на почту.
Есть предложение по доработке скрипта за оплату.
Дмитрий Кисамеев
Пишите мне в ВК https://vk.com/kisameev
Гость
Установил на другой сервер с php5.6 и mysql 5.5 и снова ошибки.
При нажатии кнопки вывел таблицу без итоговой суммы вверху сообщения об ошибках:

Warning: Unknown: Input variables exceeded 1000. To increase the limit change max_input_vars in php.ini. in Unknown on line 0

Warning: Cannot modify header information - headers already sent in C:OpenServer_OLDdomainslocalhostkalkulyator4save_word.php on line 2

Warning: Cannot modify header information - headers already sent in C:OpenServer_OLDdomainslocalhostkalkulyator4save_word.php on line 45

Warning: Cannot modify header information - headers already sent in C:OpenServer_OLDdomainslocalhostkalkulyator4save_word.php on line 46
Гость
Может Telegram есть? Я вк не пользуюсь
Дмитрий Кисамеев
пишите в ТГ @kisameev
Дмитрий Микулин
Здравствуйте Дмитрий. Всё получилось на локальном сервере XAMPP. Шаг 4 работает и даже скачивает word.doc документ на компьютер. Выложил на beget (бесплатный), и Шаг 4 формирует содержимое в word.doc документ, выводит документ в браузер, но не даёт скачать этот word.doc документ на компьютер. Подскажите пожалуйста как это сделать.
Дмитрий Кисамеев
Здравствуйте, Данный пример размещен как раз на beget
Версия php 5.6
должно все работать как у меня
Станислав Рахимов
Здравствуйте. Разрабатываете модули для Drupal 9?
Михаил
Добрый день!

В последнее время документы для чтения и ношения при себе получили большее распространение, чем только *.rtf & *.doc
Не было мысли о разнообразии вывода? типа два-три варианта Word | Exel | PDF ?
Последний удобен для телефонов, второй легко импортируется/экспортируется (например в различные CRM)... Только с Word довольно скучновато, но за саму идею большое спасибо, как раз искал именно подобное для внедрения на сайте, чтобы имея под руками расценки потенциальные клиенты могли сами составить примерную смету, придти к пониманию предстоящих объемов работ и накладных расходов

Для вставки кода используйте комментарии от ВК или FB:

Похожие публикации

В этой статье мы научимся создавать документ PDF на PHP из HTML с помощью библиотеки dompdf
Наложение текста на картинку при помощи php не такая уж и сложная задача, главное разобраться с функцией imagettftext(), поlстраивая координаты по...
HTML5 представляет несколько новых атрибутов для реализации проверки на основе браузера. pattern Атрибут является регулярным выражением , которое определяет диапазон допустимых входов...

Нашли баг или ошибку?

Выдели текст
мышкой и нажми:
Нашел ошибку