forked from mirzaev/site-tordv-calculator
Доработки под доп. листы
This commit is contained in:
parent
4c6331b5da
commit
b1d5a6c37b
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace mirzaev\calculator\controllers;
|
||||
|
||||
use Exception;
|
||||
use mirzaev\calculator\controllers\core;
|
||||
use mirzaev\calculator\models\calculators_model as calculators;
|
||||
use mirzaev\calculator\models\settings_model as settings;
|
||||
|
@ -93,6 +94,12 @@ final class calculator_controller extends core
|
|||
*/
|
||||
public function result(array $vars = []): ?string
|
||||
{
|
||||
// Инициализация журнала ошибок
|
||||
$vars['errors'] = ['calculators' => []];
|
||||
|
||||
// Инициализация данных калькулятора
|
||||
$vars['discount'] = settings::read('discount', $vars['errors']['calculators']);
|
||||
|
||||
// Генерация представления
|
||||
return $this->view->render(DIRECTORY_SEPARATOR . 'calculators' . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . 'result.html', $vars);
|
||||
}
|
||||
|
@ -118,7 +125,7 @@ final class calculator_controller extends core
|
|||
if (empty($vars['marks'])) $vars['marks'] = ['Не найдено'];
|
||||
|
||||
// Генерация представления
|
||||
return $this->view->render(DIRECTORY_SEPARATOR . 'calculators' . DIRECTORY_SEPARATOR . 'elements' . DIRECTORY_SEPARATOR. 'metals' . DIRECTORY_SEPARATOR . 'mark.html', $vars);
|
||||
return $this->view->render(DIRECTORY_SEPARATOR . 'calculators' . DIRECTORY_SEPARATOR . 'elements' . DIRECTORY_SEPARATOR . 'metals' . DIRECTORY_SEPARATOR . 'mark.html', $vars);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,17 +174,13 @@ final class calculator_controller extends core
|
|||
}
|
||||
|
||||
/**
|
||||
* Рассчёт
|
||||
* Расчёт
|
||||
*
|
||||
* Генерирует ответ в виде ['expenses' => 0, 'income' => 0, 'profit' => 0]
|
||||
*
|
||||
* @param array $vars Параметры
|
||||
*
|
||||
* @todo
|
||||
* 1. Отправлять данные в зависимости от разрешения (обычным пользователям только expenses)
|
||||
* 2. Переписать журнал ошибок и написать вывод ошибок куда-нибудь
|
||||
* 3. Вывод ошибок в представления
|
||||
* 4. Проверка на то, что существуют поставки для характеристик вписываемых в калькулятор (в режиме прямой трансляции)
|
||||
* 5. Убрать передачу цены работы (оставить только время работы в часах и цену за работу в час)
|
||||
*/
|
||||
public function calculate(array $vars = []): ?string
|
||||
|
@ -185,11 +188,19 @@ final class calculator_controller extends core
|
|||
// Инициализация журнала ошибок
|
||||
$vars['errors'] = ['calculators' => []];
|
||||
|
||||
// Инициализация калькуляторов из тела запроса (подразумевается, что там массивы с параметрами)
|
||||
$calculators = json_decode(file_get_contents('php://input'), true);
|
||||
try {
|
||||
// Инициализация параметров из тела запроса (подразумевается, что там массивы с параметрами)
|
||||
$vars['input'] = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
$calculators = $vars['input']['calculators'];
|
||||
$discount = $vars['input']['discount'];
|
||||
$cutting = $vars['input']['cutting'];
|
||||
|
||||
// Инициализация переменных для буфера вывода
|
||||
$machines = $managers = $engineers = $operators = 0;
|
||||
$machines = $managers = $engineers = $operators = $handymans = $other = 0;
|
||||
|
||||
if (count($calculators) > 0) {
|
||||
// Найдены калькуляторы
|
||||
|
||||
foreach ($calculators as $i => $calculator) {
|
||||
// Перебор калькуляторов
|
||||
|
@ -224,8 +235,23 @@ final class calculator_controller extends core
|
|||
$parameters += $calculator;
|
||||
|
||||
// Расчёт
|
||||
[$machines, $managers, $engineers, $operators, $handymans, $other] = calculators::$type(...$parameters);
|
||||
[$machines, $managers, $engineers, $operators, $handymans, $other] = calculators::$type(...$parameters + ['cutting' => $cutting]);
|
||||
}
|
||||
} else {
|
||||
// Не найдены калькуляторы
|
||||
|
||||
throw new exception('Не найдены калькуляторы');
|
||||
}
|
||||
} catch (exception $e) {
|
||||
// Запись в журнал ошибок
|
||||
$vars['errors']['calculators'][] = [
|
||||
'text' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
'stack' => $e->getTrace()
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
return json_encode([
|
||||
'machines' => $machines,
|
||||
|
@ -233,8 +259,8 @@ final class calculator_controller extends core
|
|||
'engineers' => $engineers,
|
||||
'operators' => $operators,
|
||||
'handymans' => $handymans,
|
||||
'other' => $other,
|
||||
'errors' => $calculator['errors']
|
||||
'other' => $other + ['discount' => $discount],
|
||||
'errors' => $vars['errors']
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace mirzaev\calculator\models;
|
||||
|
||||
use exception;
|
||||
use pdo;
|
||||
|
||||
/**
|
||||
* Модель баллонов
|
||||
*
|
||||
* @package mirzaev\calculator\models
|
||||
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
|
||||
*
|
||||
* @todo
|
||||
* 1. Если длина реза баллона зависит от типа металла (учитывается) то перенести это в класс металлов
|
||||
*/
|
||||
final class baloons_model extends core
|
||||
{
|
||||
/**
|
||||
* Используемый газ
|
||||
*/
|
||||
public string $gas;
|
||||
|
||||
/**
|
||||
* Количество баллонов
|
||||
*/
|
||||
public float $amount = 0;
|
||||
|
||||
/**
|
||||
* Цена всех баллонов
|
||||
*/
|
||||
public float $cost;
|
||||
|
||||
/**
|
||||
* Вычисление используемого газа
|
||||
*
|
||||
* @param float $length Толщина металла
|
||||
* @param array &$errors Журнал ошибок
|
||||
*
|
||||
* @return string|null Название газа
|
||||
*/
|
||||
public function gas(float $length, array &$errors = []): ?string
|
||||
{
|
||||
try {
|
||||
return $this->gas = match (true) {
|
||||
$length >= 4 => 'oxygen',
|
||||
default => 'air'
|
||||
};
|
||||
} catch (exception $e) {
|
||||
// Запись в журнал ошибок
|
||||
$errors[] = [
|
||||
'text' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
'stack' => $e->getTrace()
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Вычисление количества используемых баллонов
|
||||
*
|
||||
* @param string $metal Тип металла
|
||||
* @param float $cutting Длина реза
|
||||
* @param float $length Толщина листа
|
||||
* @param string|null $gas Используемый газ
|
||||
* @param array &$errors Журнал ошибок
|
||||
*
|
||||
* @return int|null Количество баллонов
|
||||
*
|
||||
* @todo
|
||||
* 1. Добавить к баллонам уточнение чтобы считало не по листам а по объёму а лучше по длине реза
|
||||
* 2. Определение длины реза по типу металла
|
||||
*/
|
||||
public function amount(string $metal, float $cutting, float $length, ?string $gas = null, array &$errors = []): ?float
|
||||
{
|
||||
try {
|
||||
// Инициализация входных параметров
|
||||
$gas ?? $gas = &$this->gas;
|
||||
|
||||
// Инициализация запроса
|
||||
$request = static::$db->prepare("SELECT `length` FROM `baloons` WHERE `gas` = :gas LIMIT 30");
|
||||
|
||||
// Отправка запроса
|
||||
$request->execute([
|
||||
':gas' => $gas
|
||||
]);
|
||||
|
||||
// Генерация ответа
|
||||
$response = $request->fetch(pdo::FETCH_ASSOC);
|
||||
|
||||
// Проверка на полученные значения
|
||||
if (!is_array($response)) return null;
|
||||
|
||||
// Вычисление длины реза на которое хватит баллона
|
||||
$flow = $response['length'] / $length;
|
||||
|
||||
// Вычисление количества баллонов (округление к большему)
|
||||
return $this->amount = $cutting / $flow;
|
||||
} catch (exception $e) {
|
||||
// Запись в журнал ошибок
|
||||
$errors[] = [
|
||||
'text' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
'stack' => $e->getTrace()
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Вычисление стоимости баллонов
|
||||
*
|
||||
* @param string $metal Тип металла
|
||||
* @param int|null $gas Используемый газ
|
||||
* @param array &$errors Журнал ошибок
|
||||
*
|
||||
* @return float|null Стоимость баллонов
|
||||
*/
|
||||
public function cost(string $metal, ?int $amount = null, ?string $gas = null, array &$errors = []): ?float
|
||||
{
|
||||
try {
|
||||
// Инициализация входных параметров
|
||||
$amount ?? $amount = &$this->amount;
|
||||
$gas ?? $gas = &$this->gas;
|
||||
|
||||
// Инициализация запроса
|
||||
$request = static::$db->prepare("SELECT `cost` FROM `baloons` WHERE `gas` = :gas LIMIT 30");
|
||||
|
||||
// Отправка запроса
|
||||
$request->execute([
|
||||
':gas' => $gas
|
||||
]);
|
||||
|
||||
// Генерация ответа
|
||||
$response = $request->fetch(pdo::FETCH_ASSOC);
|
||||
|
||||
// Проверка на полученные значения
|
||||
if (!is_array($response)) return null;
|
||||
|
||||
// Инициализация стоимости всех баллонов
|
||||
return $this->cost = $response['cost'] * $amount;
|
||||
} catch (exception $e) {
|
||||
// Запись в журнал ошибок
|
||||
$errors[] = [
|
||||
'text' => $e->getMessage(),
|
||||
'file' => $e->getFile(),
|
||||
'line' => $e->getLine(),
|
||||
'stack' => $e->getTrace()
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ namespace mirzaev\calculator\models;
|
|||
|
||||
use mirzaev\calculator\models\settings_model as settings;
|
||||
use mirzaev\calculator\models\metals_model as metals;
|
||||
use mirzaev\calculator\models\baloons_model as baloons;
|
||||
|
||||
use exception;
|
||||
|
||||
|
@ -22,18 +23,18 @@ final class calculators_model extends core
|
|||
* Расчёт стоимости переработки за 1 тонну
|
||||
*
|
||||
* @param string $complexity Сложность
|
||||
* @param float $lenght Толщина
|
||||
* @param float $length Толщина
|
||||
* @param array &$errors Журнал ошибок
|
||||
*
|
||||
* @return float Стоимость переработки за 1 тонну (руб)
|
||||
*/
|
||||
public static function reprocessing(string $complexity, float $lenght, array &$errors = []): ?float
|
||||
public static function reprocessing(string $complexity, float $length, array &$errors = []): ?float
|
||||
{
|
||||
try {
|
||||
return (float) match (true) {
|
||||
$lenght > 0 && $lenght < 4 => settings::read('reprocessing_' . $complexity . '_1_3', $errors),
|
||||
$lenght > 3 && $lenght < 7 => settings::read('reprocessing_' . $complexity . '_4_6', $errors),
|
||||
$lenght > 6 && $lenght < 11 => settings::read('reprocessing_' . $complexity . '_7_10', $errors),
|
||||
$length > 0 && $length < 4 => settings::read('reprocessing_' . $complexity . '_1_3', $errors),
|
||||
$length > 3 && $length < 7 => settings::read('reprocessing_' . $complexity . '_4_6', $errors),
|
||||
$length > 6 && $length < 11 => settings::read('reprocessing_' . $complexity . '_7_10', $errors),
|
||||
default => settings::read('reprocessing_' . $complexity . '_10', $errors),
|
||||
}
|
||||
?? 0.0;
|
||||
|
@ -52,7 +53,7 @@ final class calculators_model extends core
|
|||
*
|
||||
* @param string $complexity Сложность детали (easy, medium, hard)
|
||||
* @param int|null $area Площадь детали
|
||||
* @param float|null $lenght Толщина детали
|
||||
* @param float|null $length Толщина детали
|
||||
* @param array &$errors Журнал ошибок
|
||||
*
|
||||
* @return float Коэффициент
|
||||
|
@ -60,7 +61,7 @@ final class calculators_model extends core
|
|||
* @todo
|
||||
* 1. Коэффициент исходя из типа газа (баллоны)
|
||||
*/
|
||||
public static function coefficient(string $complexity, ?int $area = null, ?float $lenght = null, array &$errors = []): float|false
|
||||
public static function coefficient(string $complexity, ?int $area = null, ?float $length = null, array &$errors = []): float|false
|
||||
{
|
||||
try {
|
||||
// Коэффициент полученный исходя из сложности детали
|
||||
|
@ -78,15 +79,15 @@ final class calculators_model extends core
|
|||
}
|
||||
|
||||
if (
|
||||
isset($lenght)
|
||||
&& ($lenght <= (settings::read('coefficient_lenght_less', $errors) ?? throw new exception("Не найдено: coefficient_lenght_less"))
|
||||
|| $lenght >= (settings::read('coefficient_lenght_more', $errors) ?? throw new exception("Не найдено: coefficient_lenght_more")))
|
||||
isset($length)
|
||||
&& ($length <= (settings::read('coefficient_length_less', $errors) ?? throw new exception("Не найдено: coefficient_length_less"))
|
||||
|| $length >= (settings::read('coefficient_length_more', $errors) ?? throw new exception("Не найдено: coefficient_length_more")))
|
||||
) {
|
||||
// Толщина детали не более и не менее заданных в базе данных размеров
|
||||
|
||||
// Прибавление коэффициента исходя из толщины детали
|
||||
// $coefficient += settings::read('coefficient_lenght_degree', $errors) ?? throw new exception("Не найдено: coefficient_lenght_degree");
|
||||
// $coefficient -= settings::read('coefficient_lenght_degree', $errors) ?? throw new exception("Не найдено: coefficient_lenght_degree");
|
||||
// $coefficient += settings::read('coefficient_length_degree', $errors) ?? throw new exception("Не найдено: coefficient_length_degree");
|
||||
// $coefficient -= settings::read('coefficient_length_degree', $errors) ?? throw new exception("Не найдено: coefficient_length_degree");
|
||||
}
|
||||
|
||||
return (float) $coefficient;
|
||||
|
@ -167,18 +168,18 @@ final class calculators_model extends core
|
|||
* @param bool|null $out Наш металл?
|
||||
* @param int|string|null $holes Количество отверстий
|
||||
* @param int|string|null $diameter Диаметр отверстий (мм)
|
||||
* @param string|null $discount Скидка менеджера
|
||||
* @param float|null $cutting Длина реза (мм)
|
||||
* @param array &$errors Журнал ошибок
|
||||
*
|
||||
* @return array|bool Аккаунт, если удалось аутентифицироваться
|
||||
*
|
||||
* @todo
|
||||
* 18. 1200 баллон кислород расход 1 баллон на 3 листа 4ки
|
||||
* 22. Выводится результат даже если не аутентифицирован (проблема с куки)
|
||||
* 29. Амортизация станка
|
||||
* 30. Аренда помещения
|
||||
* 31. Расходники
|
||||
* 37. Проверка на то, что загружен минимум 1 калькулятор
|
||||
* 39. Переделать массивы в объекты там, где позволяет случай
|
||||
* 40. Перенести лазерный станок в отдельную таблицу в базе данных со всеми его данными
|
||||
* 43. Удаление калькуляторов
|
||||
* @ 44. от 750 +1 лист от 3
|
||||
* @ 45. от 0.5 до 3 от 620 +1
|
||||
*/
|
||||
public static function laser(
|
||||
bool|int|string|null $company = null,
|
||||
|
@ -192,7 +193,7 @@ final class calculators_model extends core
|
|||
?bool $our = null,
|
||||
int|string|null $holes = null,
|
||||
float|string|null $diameter = null,
|
||||
float|string|null $discount = null,
|
||||
float|null $cutting = null,
|
||||
array &$errors = []
|
||||
): array {
|
||||
// Инициализация журнала ошибок
|
||||
|
@ -217,7 +218,7 @@ final class calculators_model extends core
|
|||
$our = (bool) $our ?? true;
|
||||
$holes = (int) $holes ?? throw new exception('Не передан параметр holes');
|
||||
$diameter = (float) $diameter ?? throw new exception('Не передан параметр diameter');
|
||||
$discount = (float) $discount ?? throw new exception('Не передан параметр discount');
|
||||
$cutting = (float) $cutting ?? throw new exception('Не передан параметр time');
|
||||
|
||||
if ($width <= 0 || $height <= 0 || $length <= 0) {
|
||||
// Неподходящие для выполнения значения
|
||||
|
@ -225,9 +226,11 @@ final class calculators_model extends core
|
|||
throw new exception('Передан нулевой размер одной из сторон заготовки');
|
||||
}
|
||||
|
||||
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
// $gas = 'oxygen';
|
||||
$gas = 'air';
|
||||
// Инициализация инстанции баллонов
|
||||
$baloons = new baloons;
|
||||
|
||||
// Вычисление используемого газа
|
||||
$baloons->gas($length, $errors) ?? throw new exception('Не удалось вычислить тип газа для резки');
|
||||
|
||||
// Инициализация станка для буфера вывода
|
||||
$machine = [
|
||||
|
@ -236,25 +239,24 @@ final class calculators_model extends core
|
|||
|
||||
// Инициализация буфера остальных вычислений для буфера вывода
|
||||
$other = [
|
||||
'additive' => (float) settings::read('additive', $errors) ?? throw new exception('Не найдено: additive'),
|
||||
'discount' => $discount
|
||||
'additive' => (float) settings::read('additive', $errors) ?? throw new exception('Не найдено: additive')
|
||||
];
|
||||
|
||||
// Инициализация прибавок к наценке
|
||||
$increase_300_3000 = (float) settings::read('additive_increase_300_3000', $errors) ?? throw new exception('Не найдено: additive_increase_300_3000');
|
||||
// // Инициализация прибавок к наценке
|
||||
// $increase_300_3000 = (float) settings::read('additive_increase_300_3000', $errors) ?? throw new exception('Не найдено: additive_increase_300_3000');
|
||||
|
||||
if ($amount >= 300) {
|
||||
// Количество заказанных деталей равно или более чем 300 шт.
|
||||
// if ($amount >= 300) {
|
||||
// // Количество заказанных деталей равно или более чем 300 шт.
|
||||
|
||||
for ($i = 0; $i <= $amount; ++$i) {
|
||||
// Перебор по количеству изготавливаемых деталей
|
||||
// for ($i = 0; $i <= $amount; ++$i) {
|
||||
// // Перебор по количеству изготавливаемых деталей
|
||||
|
||||
// Количество заказанных деталей равно или более чем 300 шт. и равно или менее чем 3000 шт.
|
||||
if ($amount <= 3000) $other['additive'] += $increase_300_3000;
|
||||
}
|
||||
}
|
||||
// // Количество заказанных деталей равно или более чем 300 шт. и равно или менее чем 3000 шт.
|
||||
// if ($amount <= 3000) $other['additive'] += $increase_300_3000;
|
||||
// }
|
||||
// }
|
||||
|
||||
$other['additive'] = 1.07;
|
||||
// $other['additive'] = 1.07;
|
||||
|
||||
// Площадь
|
||||
$area = $width * $height;
|
||||
|
@ -283,7 +285,7 @@ final class calculators_model extends core
|
|||
|
||||
// Инициализация характеристик металла
|
||||
$metal = [
|
||||
'cut' => metals::cut($type, $gas, $length, $errors),
|
||||
'cut' => metals::cut($type, $baloons->gas, $length, $errors),
|
||||
'weight' => metals::kg($type, $errors) * $length,
|
||||
'cost' => $list['ton'] / 1000 // Цена за килограмм
|
||||
];
|
||||
|
@ -294,6 +296,9 @@ final class calculators_model extends core
|
|||
throw new exception('Ошибка при вычислении характеристик металла');
|
||||
}
|
||||
|
||||
if ($cutting === 0.0) {
|
||||
// Не передана длина реза
|
||||
|
||||
if ($holes == 0 ?? $diameter == 0) {
|
||||
// Не переданы данные об отверстиях
|
||||
|
||||
|
@ -305,8 +310,10 @@ final class calculators_model extends core
|
|||
// Длина реза (мм)
|
||||
$cutting = (3.1416 * $diameter * $holes + $width * 2 + $height * 2) * self::coefficient($complexity, $area, $length, $errors);
|
||||
}
|
||||
}
|
||||
|
||||
$metal['cut'] = 65;
|
||||
// Запись в буфер вывода
|
||||
$other['cutting'] = $cutting;
|
||||
|
||||
// Время реза одной детали (c)
|
||||
$time = $cutting / $metal['cut'];
|
||||
|
@ -323,6 +330,9 @@ final class calculators_model extends core
|
|||
// Стоимость переработки (руб)
|
||||
$other['reprocessing'] = self::reprocessing($complexity, $length, $errors) / 1000 * $weight;
|
||||
|
||||
// Стоимость аренды помещения
|
||||
$other['rent'] = $time * $amount / 60 / 60 * (int) settings::read('rent', $errors) ?? throw new exception('Не найдено: rent');
|
||||
|
||||
// (Наш металл) Стоимость металла (руб)
|
||||
if ($our) $machine['metal'] = $weight * $metal['cost'];
|
||||
|
||||
|
@ -338,6 +348,41 @@ final class calculators_model extends core
|
|||
// Вычисление количества листов
|
||||
for ($lists = 0; ++$lists * $list['volume'] < $volume * $amount;);
|
||||
|
||||
// Условия для прибавления листа (костыль)
|
||||
if (($length > 3 && ($width >= 750 || $height >= 750))
|
||||
|| ($length >= 0.5 && $length <= 3 && ($width >= 620 || $height >= 620))
|
||||
) ++$list;
|
||||
|
||||
// Инициализация данных линзы
|
||||
$lense = [
|
||||
'cost' => (int) settings::read('laser_lense_cost', $errors) ?? throw new exception('Не найдено: laser_lense_cost'),
|
||||
'length' => (int) settings::read('laser_lense_flow', $errors) ?? throw new exception('Не найдено: laser_lense_flow')
|
||||
];
|
||||
|
||||
// Вычисление количества используемых линз
|
||||
$lenses = $cutting / $lense['length'];
|
||||
|
||||
// Запись данных о линзах в буфер вывода (стоимость)
|
||||
$machine['lenses'] = $lenses * $lense['cost'];
|
||||
|
||||
// Вычисление количества использованных баллонов
|
||||
$baloons->amount($type, $cutting * $amount, $length, errors: $errors) ?? throw new exception('Не удалось вычислить количество используемых баллонов');
|
||||
|
||||
// Вычисление стоимости баллонов
|
||||
$baloons->cost($type, errors: $errors) ?? throw new exception('Не удалось вычислить стоимость баллонов');
|
||||
|
||||
// Запись данных о баллонах в буфер вывода
|
||||
$other['baloons'] = [
|
||||
'amount' => $baloons->amount,
|
||||
'cost' => $baloons->cost
|
||||
];
|
||||
|
||||
// Запись данных о баллонах в буфер вывода
|
||||
$other['baloons'] = [
|
||||
'amount' => $baloons->amount,
|
||||
'cost' => $baloons->cost
|
||||
];
|
||||
|
||||
// Вычисление времени работы разнорабочих (ч)
|
||||
$work = $lists * $load / 60;
|
||||
|
||||
|
@ -375,7 +420,7 @@ final class calculators_model extends core
|
|||
[
|
||||
'time' => [
|
||||
'design' => $operator['time'],
|
||||
'machine' => ($time * $amount / 60 / 60) + $work
|
||||
'machine' => $time * $amount / 60 / 60 + $work
|
||||
],
|
||||
'hour' => $operator['hour']
|
||||
]
|
||||
|
@ -407,6 +452,8 @@ final class calculators_model extends core
|
|||
];
|
||||
}
|
||||
|
||||
$machine['depreciation'] = $time * $amount / 60 / 60 * (int) settings::read('laser_depreciation', $errors) ?? throw new exception('Не найдено: laser_depreciation');
|
||||
|
||||
// Инициализация станков
|
||||
$machines = [
|
||||
$machine
|
||||
|
|
|
@ -116,3 +116,56 @@
|
|||
#calculator>.calculator>div>div>input[type="range"] {
|
||||
min-width: 50%;
|
||||
}
|
||||
|
||||
#calculator>.calculator>div>div>input[type="range"] {
|
||||
min-width: 50%;
|
||||
}
|
||||
|
||||
#calculator>#result {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#calculator>#result>a {
|
||||
margin: unset;
|
||||
}
|
||||
|
||||
#calculator>#result>#errors {
|
||||
margin-bottom: unset;
|
||||
padding: 15px 25px;
|
||||
background-color: #acacac;
|
||||
}
|
||||
|
||||
#calculator>#result>#errors:empty {
|
||||
margin: unset;
|
||||
padding: unset;
|
||||
background-color: unset;
|
||||
}
|
||||
|
||||
#calculator>#result>#errors>dt {
|
||||
margin-bottom: 8px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#calculator>#result>#errors>dd {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
#calculator>#result>div[type="row"]:first-of-type {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#calculator>#result>div[type="row"]:last-of-type {
|
||||
margin-bottom: 20px;
|
||||
|
||||
}
|
||||
|
||||
#calculator>#result>div[type="row"] {
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#calculator>#result>div[type="row"]>label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
|
@ -71,17 +71,25 @@ let calculator = {
|
|||
calculate() {
|
||||
// Запрос и генерация HTML с данными о рассчете со всех калькуляторов
|
||||
|
||||
// Инициализация параметров
|
||||
let cutting = document.getElementById('cutting');
|
||||
let discount = document.getElementById('discount');
|
||||
|
||||
// Инициализация буфера запроса
|
||||
let query = {};
|
||||
let query = {
|
||||
calculators: {},
|
||||
cutting: +cutting.value ?? 0,
|
||||
discount: +discount.value ?? 0
|
||||
};
|
||||
|
||||
for (const number in this.calculators) {
|
||||
// Перебор калькуляторов
|
||||
|
||||
// Инициализация буфера запроса для нового калькулятора
|
||||
query[number] = {};
|
||||
query['calculators'][number] = {};
|
||||
|
||||
// Инициализация типа калькулятора
|
||||
query[number]['calculator'] = this.calculators[number].getAttribute('data-calculator');
|
||||
query['calculators'][number]['calculator'] = this.calculators[number].getAttribute('data-calculator');
|
||||
|
||||
for (const buyer of this.index.querySelectorAll('input[name="buyer"]')) {
|
||||
// Перебор полей с параметрами типа заказчика
|
||||
|
@ -90,7 +98,7 @@ let calculator = {
|
|||
// Найдено выбранное поле
|
||||
|
||||
// Запись в буфер запроса
|
||||
query[number]['buyer'] = buyer.value;
|
||||
query['calculators'][number]['buyer'] = buyer.value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +109,7 @@ let calculator = {
|
|||
// Найдено выбранное поле
|
||||
|
||||
// Запись в буфер запроса
|
||||
query[number]['complexity'] = complexity.value;
|
||||
query['calculators'][number]['complexity'] = complexity.value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,22 +120,19 @@ let calculator = {
|
|||
// Флажок
|
||||
|
||||
// Запись в буфер запроса
|
||||
query[number][field.getAttribute('data-calculator-parameter')] = field.checked;
|
||||
query['calculators'][number][field.getAttribute('data-calculator-parameter')] = field.checked;
|
||||
} else if (field.getAttribute('type') === 'text' || field.getAttribute('type') === 'number' || field.getAttribute('type') === 'range') {
|
||||
// Текстовое, цифровое поле или ползунок
|
||||
|
||||
// Запись в буфер запроса
|
||||
query[number][field.getAttribute('data-calculator-parameter')] = field.value;
|
||||
query['calculators'][number][field.getAttribute('data-calculator-parameter')] = field.value;
|
||||
} else {
|
||||
// Элемент с тегом <select> (подразумевается)
|
||||
|
||||
// Запись в буфер запроса
|
||||
query[number][field.getAttribute('data-calculator-parameter')] = field.value ?? field.options[field.selectedIndex].text;
|
||||
query['calculators'][number][field.getAttribute('data-calculator-parameter')] = field.value ?? field.options[field.selectedIndex].text;
|
||||
}
|
||||
}
|
||||
|
||||
// Сортировка
|
||||
query[number] = query[number];
|
||||
}
|
||||
|
||||
return fetch('/calculator/calculate', {
|
||||
|
@ -141,31 +146,67 @@ let calculator = {
|
|||
// Инициализация буфера расходов
|
||||
let expenses = 0;
|
||||
|
||||
// Инициализация буфера с данными расчёта
|
||||
let result;
|
||||
|
||||
if (this.generate.error(success.errors) > 0) {
|
||||
// Найдены ошибки
|
||||
|
||||
// Генерация текста ответа
|
||||
result = 'Ошибка';
|
||||
} else {
|
||||
// Не найдены ошибки
|
||||
|
||||
if (success.other.cutting !== undefined) {
|
||||
// Получены данные времени работы
|
||||
|
||||
// Запись полученных данных
|
||||
cutting.value = success.other.cutting;
|
||||
cutting.parentElement.children[0].innerText = 'Длина реза 1 детали (' + cutting.value + 'мм)';
|
||||
|
||||
// Разблокировка параметра
|
||||
cutting.removeAttribute('disabled');
|
||||
}
|
||||
|
||||
if (success.other.discount !== undefined) {
|
||||
// Получены данные скидки
|
||||
|
||||
// Запись полученных данных
|
||||
discount.value = success.other.discount;
|
||||
discount.parentElement.children[0].innerText = 'Скидка (' + discount.value + '%)';
|
||||
}
|
||||
|
||||
for (const [, machine] of Object.entries(success.machines)) {
|
||||
// Перебор станков
|
||||
|
||||
// Прибавление данных к буферу расходов
|
||||
// Прибавление данных станка к буферу расходов
|
||||
expenses += (machine.electricity + (machine.metal ?? 0));
|
||||
|
||||
// Прибавление амортизации к буферу вывода
|
||||
expenses += machine.reprocessing ?? 0;
|
||||
|
||||
// Прибавление линз к буферу вывода
|
||||
expenses += machine.lenses ?? 0;
|
||||
}
|
||||
|
||||
for (const [, manager] of Object.entries(success.managers)) {
|
||||
// Перебор менеджеров
|
||||
|
||||
// Прибавление данных к буферу расходов
|
||||
// Прибавление данных менеджера к буферу расходов
|
||||
expenses += manager.time * manager.hour;
|
||||
}
|
||||
|
||||
for (const [, engineer] of Object.entries(success.engineers)) {
|
||||
// Перебор менеджеров
|
||||
// Перебор инженеров
|
||||
|
||||
// Прибавление данных к буферу расходов
|
||||
// Прибавление данных инженера к буферу расходов
|
||||
expenses += engineer.time * engineer.hour;
|
||||
}
|
||||
|
||||
for (const [, operator] of Object.entries(success.operators)) {
|
||||
// Перебор операторов
|
||||
|
||||
// Прибавление данных к буферу расходов
|
||||
// Прибавление данных оператора к буферу расходов
|
||||
expenses += (operator.time.design + operator.time.machine) * operator.hour;
|
||||
}
|
||||
|
||||
|
@ -176,19 +217,29 @@ let calculator = {
|
|||
expenses += handyman.time * handyman.hour;
|
||||
}
|
||||
|
||||
// Добавление переработки
|
||||
expenses += success.other.reprocessing;
|
||||
// Прибавление аренды к буферу расходов
|
||||
expenses += success.other.rent ?? 0;
|
||||
|
||||
// Добавление наценки (коэффициент)
|
||||
expenses *= success.other.additive;
|
||||
// Прибавление переработки к буферу расходов
|
||||
expenses += success.other.reprocessing ?? 0;
|
||||
|
||||
// Добавление скидки менеджера
|
||||
expenses -= expenses * (success.other.discount / 100)
|
||||
// Прибавление баллонов к буферу расходов
|
||||
expenses += success.other.baloons.cost ?? 0;
|
||||
|
||||
// Вычисление наценки (коэффициент)
|
||||
expenses *= success.other.additive ?? 1;
|
||||
|
||||
// Вычитание скидки менеджера
|
||||
expenses -= expenses * ((discount.value ?? 100) / 100);
|
||||
|
||||
// Округление
|
||||
expenses = expenses.toFixed(2);
|
||||
|
||||
if (this.generate.result(expenses + ' рублей')) {
|
||||
// Генерация текста ответа
|
||||
result = expenses + ' рублей';
|
||||
}
|
||||
|
||||
if (this.generate.result(result)) {
|
||||
console.log(`[КАЛЬКУЛЯТОР] Сгенерирован результат: ${expenses} рублей`);
|
||||
} else {
|
||||
console.log('[КАЛЬКУЛЯТОР] [ОШИБКА] Не удалось сгенерировать результат');
|
||||
|
@ -261,54 +312,6 @@ let calculator = {
|
|||
}
|
||||
});
|
||||
},
|
||||
result(expenses) {
|
||||
// Запрос и генерация HTML с данными о результате калькуляции
|
||||
|
||||
function request() {
|
||||
return fetch('/calculator/generate/result', {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/x-www-form-urlencoded" }
|
||||
}).then((response) => {
|
||||
if (response.status === 200) {
|
||||
response.text().then(
|
||||
success => {
|
||||
calculator.index.insertAdjacentHTML('beforeend', success);
|
||||
|
||||
console.log('[КАЛЬКУЛЯТОР] Загружен элемент с данными о результате калькуляции');
|
||||
},
|
||||
error => {
|
||||
console.log('[КАЛЬКУЛЯТОР] [ОШИБКА] Не удалось загрузить элемент с данными о результате калькуляции');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (document.getElementById("result") === null) {
|
||||
// Не найден элемент с данными расчётов
|
||||
|
||||
// Генерация элемента с данными расчётов
|
||||
}
|
||||
|
||||
if (expenses !== undefined) {
|
||||
// Переданы расходы
|
||||
|
||||
// Инициализация элемента
|
||||
let element = document.getElementById('calculate');
|
||||
|
||||
if (element == null) {
|
||||
// Не найден элемент с результатом расчёта
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Запись расходов в элемент (подразумевается кнопка отправки на расчёт)
|
||||
element.innerText = expenses;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return request();
|
||||
},
|
||||
mark(element, type = '') {
|
||||
// Запрос и генерация HTML с полем выбора марки металла
|
||||
|
||||
|
@ -373,6 +376,116 @@ let calculator = {
|
|||
}
|
||||
});
|
||||
},
|
||||
result(expenses) {
|
||||
// Запрос и генерация HTML с данными о результате калькуляции
|
||||
|
||||
function request() {
|
||||
return fetch('/calculator/generate/result', {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/x-www-form-urlencoded" }
|
||||
}).then((response) => {
|
||||
if (response.status === 200) {
|
||||
response.text().then(
|
||||
success => {
|
||||
calculator.index.insertAdjacentHTML('beforeend', success);
|
||||
|
||||
console.log('[КАЛЬКУЛЯТОР] Загружен элемент с данными о результате калькуляции');
|
||||
},
|
||||
error => {
|
||||
console.log('[КАЛЬКУЛЯТОР] [ОШИБКА] Не удалось загрузить элемент с данными о результате калькуляции');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (document.getElementById("result") === null) {
|
||||
// Не найден элемент с данными расчётов
|
||||
} else {
|
||||
// Найден элемент с данными расчётов
|
||||
|
||||
if (expenses !== undefined) {
|
||||
// Переданы расходы
|
||||
|
||||
// Инициализация элемента
|
||||
let element = document.getElementById('calculate');
|
||||
|
||||
if (element == null) {
|
||||
// Не найден элемент с результатом расчёта
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Запись расходов в элемент (подразумевается кнопка отправки на расчёт)
|
||||
element.innerText = expenses;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return request();
|
||||
},
|
||||
error(errors = []) {
|
||||
// Генерация ошибки
|
||||
|
||||
// Инициализация количества обработанных ошибок
|
||||
let amount = 0;
|
||||
|
||||
if (typeof errors === 'object') {
|
||||
// Передан массив с ошибками и он является массивом
|
||||
|
||||
// Инициализация буфера для проверки вложенности массива
|
||||
let first = Object.values(errors)[0];
|
||||
|
||||
if (first !== undefined && first.text === undefined) {
|
||||
// Найден массив с ошибками (категория)
|
||||
|
||||
// Вход в рекурсию
|
||||
amount += this.error(first);
|
||||
} else {
|
||||
// Не найден массив с ошибками (подразумевается, что это и есть информация об ошибке)
|
||||
|
||||
// Инициализация элемента-оболочки
|
||||
let list = document.getElementById('errors');
|
||||
|
||||
// Перезапись данных об ошибках
|
||||
list.innerText = '';
|
||||
|
||||
// Проверка на наличие ошибок
|
||||
if (errors.length === 0) return false;
|
||||
|
||||
if (list !== null) {
|
||||
// Оболочка найдена
|
||||
|
||||
for (const [, error] of Object.entries(errors)) {
|
||||
// Перебор станков
|
||||
|
||||
// Инициализация элемента-заголовка
|
||||
let term = document.createElement('dt');
|
||||
|
||||
// Запись содержимого
|
||||
term.innerText = error.text;
|
||||
|
||||
// Инициализация элемента-описания
|
||||
let definition = document.createElement('dd');
|
||||
|
||||
// Запись содержимого
|
||||
definition.innerText = error.file + ' в строке ' + error.line;
|
||||
|
||||
// input.setAttribute('id', element.id);
|
||||
|
||||
// Запись в список
|
||||
list.insertAdjacentElement('beforeend', term);
|
||||
list.insertAdjacentElement('beforeend', definition);
|
||||
|
||||
// Добавление к счётчику обработанных ошибок
|
||||
++amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return amount;
|
||||
},
|
||||
calculators: {
|
||||
laser() {
|
||||
// Запрос и генерация HTML с калькулятором лазерной резки
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<h3>Лазерная резка</h3>
|
||||
<h3>Лазерная резка <span title="Удалить"></span></h3>
|
||||
<section class="calculator" data-calculator="laser">
|
||||
<div>
|
||||
<label>Тип</label>
|
||||
|
@ -66,27 +66,4 @@
|
|||
<input data-calculator-parameter="our" type="checkbox" title="Используется наш металл" checked>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>Скидка ({{ calculators.laser.discount.default ?? 0 }}%)</label>
|
||||
<div>
|
||||
<input data-calculator-parameter="discount" type="range" title="Скидка менеджера"
|
||||
value="{{ calculators.laser.discount.default ?? 0 }}" min="{{ calculators.laser.discount.min ?? 0 }}"
|
||||
max="{{ calculators.laser.discount.max ?? 5 }}" step="{{ calculators.laser.discount.step ?? 1 }}" oninput="this.parentElement.parentElement.children[0].innerText = 'Скидка (' + this.value + '%)';">
|
||||
|
||||
<!-- <datalist id="discount_level">
|
||||
<option value="0" label="{{ calculators.laser.discount.min ?? 0 }}%">
|
||||
<option value="10">
|
||||
<option value="20">
|
||||
<option value="30">
|
||||
<option value="40">
|
||||
<option value="50" label="{{ ((calculators.laser.discount.max ?? 5) + (calculators.laser.discount.min ?? 0)) / 2 }}%">
|
||||
<option value="60">
|
||||
<option value="70">
|
||||
<option value="80">
|
||||
<option value="90">
|
||||
<option value="100" label="{{ calculators.laser.discount.max ?? 5 }}%">
|
||||
</datalist> -->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -1,3 +1,46 @@
|
|||
<section id="result">
|
||||
<div type="row">
|
||||
<label>Длина реза 1 детали ({{ cutting.default ?? 0 }}мм)</label>
|
||||
<input id="cutting" type="range" title="Длина реза 1 детали "
|
||||
value="{{ cutting.default ?? 0 }}" min="{{ cutting.min ?? 0 }}" max="{{ cutting.max ?? 10000 }}"
|
||||
step="{{ cutting.step ?? 1 }}"
|
||||
oninput="this.parentElement.children[0].innerText = 'Длина реза 1 детали (' + this.value + 'мм)';" disabled>
|
||||
<!-- <datalist id="cutting_level">
|
||||
<option value="0" label="{{ cutting.min ?? 0 }}%">
|
||||
<option value="10">
|
||||
<option value="20">
|
||||
<option value="30">
|
||||
<option value="40">
|
||||
<option value="50" label="{{ ((cutting.max ?? 10000) + (cutting.min ?? 0)) / 2 }}%">
|
||||
<option value="60">
|
||||
<option value="70">
|
||||
<option value="80">
|
||||
<option value="90">
|
||||
<option value="100" label="{{ cutting.max ?? 100005 }}%">
|
||||
</datalist> -->
|
||||
</div>
|
||||
|
||||
<div type="row">
|
||||
<label>Скидка ({{ discount.default ?? 0 }}%)</label>
|
||||
<input id="discount" type="range" title="Скидка менеджера"
|
||||
value="{{ discount.default ?? 0 }}" min="{{ discount.min ?? 0 }}" max="{{ discount.max ?? 5 }}"
|
||||
step="{{ discount.step ?? 1 }}"
|
||||
oninput="this.parentElement.children[0].innerText = 'Скидка (' + this.value + '%)';">
|
||||
|
||||
<!-- <datalist id="discount_level">
|
||||
<option value="0" label="{{ calculators.discount.min ?? 0 }}%">
|
||||
<option value="10">
|
||||
<option value="20">
|
||||
<option value="30">
|
||||
<option value="40">
|
||||
<option value="50" label="{{ ((calculators.discount.max ?? 5) + (discount.min ?? 0)) / 2 }}%">
|
||||
<option value="60">
|
||||
<option value="70">
|
||||
<option value="80">
|
||||
<option value="90">
|
||||
<option value="100" label="{{ discount.max ?? 5 }}%">
|
||||
</datalist> -->
|
||||
</div>
|
||||
<a id="calculate" class="unselectable" type="button" onclick="return calculator.calculate();">0 рублей</a>
|
||||
<dl id="errors"></dl>
|
||||
</section>
|
||||
|
|
Loading…
Reference in New Issue