diff --git a/README.md b/README.md index b682cfd..2e1a82f 100755 --- a/README.md +++ b/README.md @@ -2,4 +2,6 @@ Site-registry of tasks for outsourced employees From this project i earned **700 000** Russian rubles
-*As long as commits appear in the repository, this means that i continue paid development* +*As long as commits appear in the repository, this means that i continue paid development*
+
+I am selling this site to **capitalist scum** for a lot of money, but you, friend, can use my code **for free** ✌️ diff --git a/mirzaev/ebala/system/controllers/task.php b/mirzaev/ebala/system/controllers/task.php index 580ad44..30f14f2 100755 --- a/mirzaev/ebala/system/controllers/task.php +++ b/mirzaev/ebala/system/controllers/task.php @@ -34,7 +34,7 @@ final class task extends core /** * Создать * - * @param array $parameters Параметры запроса + * @param array $parameters Параметры запроса (json в php://input) * * @return void В буфер вывода JSON-документ с запрашиваемыми параметрами */ @@ -47,33 +47,50 @@ final class task extends core // Инициализация буфера ошибок $this->errors['tasks'] ??= []; - // Создание строк - for ($i = 0, $parameters['cashiers'] = (int) $parameters['cashiers']; $i < $parameters['cashiers']; ++$i) model::create(work: 'Кассир', market: $this->account->type === 'market' ? account::market($this->account->getId())?->id : null, start: $parameters['start'], end: $parameters['end'], date: $parameters['date'], errors: $this->errors['tasks']); - for ($i = 0, $parameters['displayers'] = (int) $parameters['displayers']; $i < $parameters['displayers']; ++$i) model::create(work: 'Выкладчик', market: $this->account->type === 'market' ? account::market($this->account->getId())?->id : null, start: $parameters['start'], end: $parameters['end'], date: $parameters['date'], errors: $this->errors['tasks']); - for ($i = 0, $parameters['loaders'] = (int) $parameters['loaders']; $i < $parameters['loaders']; ++$i) model::create(work: 'Грузчик', market: $this->account->type === 'market' ? account::market($this->account->getId())?->id : null, start: $parameters['start'], end: $parameters['end'], date: $parameters['date'], errors: $this->errors['tasks']); - for ($i = 0, $parameters['gastronomes'] = (int) $parameters['gastronomes']; $i < $parameters['gastronomes']; ++$i) model::create(work: 'Гастроном', market: $this->account->type === 'market' ? account::market($this->account->getId())?->id : null, start: $parameters['start'], end: $parameters['end'], date: $parameters['date'], errors: $this->errors['tasks']); + if (!empty($json = json_decode(file_get_contents('php://input'), true, 4))) { - // Запись заголовков ответа - header('Content-Type: application/json'); - header('Content-Encoding: none'); - header('X-Accel-Buffering: no'); - // Инициализация буфера вывода - ob_start(); + foreach ($json as $work => $tasks) { + // Перебор категорий (колонок) - // Генерация ответа - echo json_encode( - [ - 'errors' => self::parse_only_text($this->errors) - ] - ); + foreach ($tasks as $task) { + // Перебор заявок - // Запись заголовков ответа - header('Content-Length: ' . ob_get_length()); + // Создание заявки + model::create( + work: model::label($work), + market: $this->account->type === 'market' ? account::market($this->account->getId())?->id : null, + start: $task['start'], + end: $task['end'], + date: $task['date'], + commentary: $task['commentary'], + errors: $this->errors['tasks'] + ); + } + } - // Отправка и деинициализация буфера вывода - ob_end_flush(); - flush(); + // Запись заголовков ответа + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Инициализация буфера вывода + ob_start(); + + // Генерация ответа + echo json_encode( + [ + 'errors' => self::parse_only_text($this->errors) + ] + ); + + // Запись заголовков ответа + header('Content-Length: ' . ob_get_length()); + + // Отправка и деинициализация буфера вывода + ob_end_flush(); + flush(); + } else throw new exception('Не удалось инициализировать JSON-документ с данными заявок'); } else throw new exception('Вы не авторизованы'); } catch (exception $e) { // Запись в реестр ошибок @@ -1758,7 +1775,7 @@ final class task extends core // Найдена заявка // Инициализация списка работ - $this->view->works = ['Кассир', 'Выкладчик', 'Грузчик', 'Гастроном']; + $this->view->works = ['Кассир', 'Выкладчик', 'Гастроном', 'Бригадир', 'Грузчик', 'Мобильный грузчик', 'Мобильный универсал']; // Проверка на существование записанной в задаче работы в списке существующих работ и запись об этом в глобальную переменную шаблонизатора foreach ($this->view->works as $work) if ($this->view->task->work === $work) $this->view->exist = true; diff --git a/mirzaev/ebala/system/models/account.php b/mirzaev/ebala/system/models/account.php index 12d7518..ef6fb55 100755 --- a/mirzaev/ebala/system/models/account.php +++ b/mirzaev/ebala/system/models/account.php @@ -135,7 +135,7 @@ final class account extends core if (!empty($session->buffer['market']['entry']['password'])) { // Найден пароль в буфере сессии - if (($account = market::account(market::read('d.id == "' . $session->buffer['market']['entry']['id'] . '"', amount: 1)?->getId())) instanceof _document) { + if (($account = market::account(market::read('d.id == "' . $session->buffer['market']['entry']['id'] . '"', amount: 1)?->getId()) ?? null) instanceof _document) { // Найден аккаунт (игнорируются ошибки) if (sodium_crypto_pwhash_str_verify($account->password, $session->buffer['market']['entry']['password'])) { diff --git a/mirzaev/ebala/system/models/task.php b/mirzaev/ebala/system/models/task.php index 9265bfe..870cb1d 100755 --- a/mirzaev/ebala/system/models/task.php +++ b/mirzaev/ebala/system/models/task.php @@ -40,7 +40,7 @@ final class task extends core /** * Create task in ArangoDB * - * @param ?string $date + * @param string|int|null $date * @param ?string $worker * @param ?string $work * @param ?string $start @@ -51,12 +51,13 @@ final class task extends core * @param bool $hided * @param bool $problematic * @param bool $completed + * @param ?string $commentary * @param array $errors * * @return ?string Identificator of instance of ArangoDB */ public static function create( - ?string $date = null, + string|int|null $date = null, ?string $worker = null, ?string $work = null, ?string $start = null, @@ -67,6 +68,7 @@ final class task extends core bool $hided = false, bool $problematic = false, bool $completed = false, + ?string $commentary = null, array &$errors = [] ): ?string { try { @@ -90,6 +92,7 @@ final class task extends core 'hided' => $hided, 'problematic' => $problematic, 'completed' => $completed, + 'commentary' => $commentary, ]); } else throw new exception('Не удалось инициализировать коллекции'); } catch (exception $e) { @@ -180,4 +183,25 @@ final class task extends core // Exit (fail) return []; } + + /** + * Generate work type label in Russian + * + * @param string $work Type of work + * + * @return string + */ + public static function label(string $work): string + { + return match (mb_strtolower($work)) { + 'cashiers', 'cashier', 'кассиры', 'кассир' => 'Кассир', + 'displayers', 'displayer', 'выкладчики', 'выкладчик' => 'Выкладчик', + 'gastronomes', 'gastronome', 'гастрономы', 'гастроном' => 'Гастроном', + 'brigadiers', 'brigadier', 'бригадиры', 'бригадир' => 'Бригадир', + 'loaders', 'loader', 'грузчики', 'грузчик' => 'Грузчик', + 'loaders_mobile', 'loader_mobile', 'мобильные грузчики', 'мобильный грузчик' => 'Мобильный грузчик', + 'universals_mobile', 'universal_mobile', 'мобильные универсалы', 'мобильный универсал' => 'Мобильный универсал', + default => $work + }; + } } diff --git a/mirzaev/ebala/system/public/css/main.css b/mirzaev/ebala/system/public/css/main.css index 3eb91fc..14faedf 100755 --- a/mirzaev/ebala/system/public/css/main.css +++ b/mirzaev/ebala/system/public/css/main.css @@ -302,12 +302,14 @@ label * { } textarea { + --padding-x: 12px; + --padding-y: 8px; width: 100%; min-width: calc(100% - 24px); min-height: 120px; max-width: calc(100% - 24px); max-height: 300px; - padding: 8px 12px; + padding: var(--padding-y, 8px) var(--padding-x, 12px); font-size: smaller; overflow: hidden; border-radius: 3px; diff --git a/mirzaev/ebala/system/public/css/popup.css b/mirzaev/ebala/system/public/css/popup.css index f11fad7..a2c99c2 100644 --- a/mirzaev/ebala/system/public/css/popup.css +++ b/mirzaev/ebala/system/public/css/popup.css @@ -44,9 +44,12 @@ div#popup>section.calculated { } div#popup>section.list { + max-width: max(70vw, 1300px); + max-height: max(62vh, 600px); display: flex; flex-direction: column; padding: 30px; + overflow-y: scroll; border-radius: 3px; } @@ -65,17 +68,30 @@ div#popup>section.list h4 { } div#popup>section.list>section.main { + --gap: 15px; display: flex; - gap: 15px; + flex-flow: row wrap; + justify-content: space-between; + gap: var(--gap, 15px); } div#popup>section.list>section.main>div.column { - flex-grow: 1; display: flex; + flex-grow: 1; flex-direction: column; gap: 8px; } +div#popup>section.list>section.main.flow>div.column:not(:only-child) { + width: 300px; +} + +div#popup>section.list>section.main>div.column:not(:only-child)[data-column="buttons"]:last-of-type { + margin-left: auto; + justify-content: end; +} + + div#popup>section.list>section.main>div.column:only-child { width: 100%; } @@ -140,7 +156,21 @@ div#popup>section.list>section.main>div.column> :is(div, select).row.buttons { div#popup>section.list>section.main>div.column> :is(div, select).row:not(.buttons, .stretchable, .endless), div#popup>section.list>section.main>div.column> :is(div, select).row:not(.buttons, .stretchable, .endless)>button { - height: 29px; + --height: 29px; + height: var(--height, 29px); +} + +div#popup>section.list>section.main>div.column> :is(div, select).row:not(.buttons .endless).stretchable, +div#popup>section.list>section.main>div.column> :is(div, select).row:not(.buttons, .endless).stretchable>button { + --height: 29px; + height: max(var(--height, 29px), fit-content); +} + +div#popup>section.list>section.main>div.column> :is(div, select).row:not(.buttons .endless).stretchable>textarea { + /* min-height: calc(var(--height, 29px) - var(--padding-y, 8ox) * 2); */ + min-height: 1rem; + max-height: 3rem; + height: 1rem; } div#popup>section.list>section.main>div.column>:is(div, section).row:not(.merged)+:is(div, section).row.merged { diff --git a/mirzaev/ebala/system/public/js/tasks.js b/mirzaev/ebala/system/public/js/tasks.js index 22ab48e..1e3e03f 100755 --- a/mirzaev/ebala/system/public/js/tasks.js +++ b/mirzaev/ebala/system/public/js/tasks.js @@ -1,5676 +1,6811 @@ "use strict"; if (typeof window.tasks !== "function") { - // Not initialized - - // Initialize of the class in global namespace - window.tasks = class tasks { - /** - * Заблокировать функцию закрытия всплывающего окна? - */ - static freeze = false; - - /** - * Тело всплывающего окна (массив) - */ - static body = {}; - - /** - * Инициализирован класс? - */ - static initialized = false; - - /** - * Создать заявку - * - * @param {HTMLElement} cashiers Количество кассиров - * @param {HTMLElement} displayers Количество выкладчиков - * @param {HTMLElement} loaders Количество грузчиков - * @param {HTMLElement} gastronomes Количество гастрономов - * @param {HTMLElement} start Начало работы (00:00) - * @param {HTMLElement} end Конец работы (00:00) - * @param {HTMLElement} date Дата работы (d.m.Y) - * @param {HTMLElement} button Кнопка заявки