diff --git a/mirzaev/ebala/system/controllers/account.php b/mirzaev/ebala/system/controllers/account.php index d8fadb9..54f0c28 100755 --- a/mirzaev/ebala/system/controllers/account.php +++ b/mirzaev/ebala/system/controllers/account.php @@ -268,4 +268,106 @@ final class account extends core // Возврат (провал) return null; } + + /** + * Пометить заблокированным + * + * @param array $parameters Параметры запроса + */ + public function ban(array $parameters = []): ?string + { + if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) { + // Авторизован аккаунт администратора или оператора + + // Инициализация данных аккаунта + $account = model::read('d._key == "' . $parameters['id'] . '"'); + + if (!empty($account)) { + // Найден аккаунт + + // Блокирование + $account->active = false; + $account->banned = true; + + if (_core::update($account)) { + // Записаны данные аккаунта + + // Запись заголовков ответа + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Инициализация буфера вывода + ob_start(); + + // Генерация ответа + echo json_encode([ + 'banned' => true, + 'errors' => self::parse_only_text($this->errors) + ]); + + // Запись заголовков ответа + header('Content-Length: ' . ob_get_length()); + + // Отправка и деинициализация буфера вывода + ob_end_flush(); + flush(); + } else throw new exception('Не удалось записать изменения в базу данных'); + } else throw new exception('Не удалось найти аккаунт'); + } + + // Возврат (провал) + return null; + } + + /** + * Снять пометку заблокированного (разблокировать) + * + * @param array $parameters Параметры запроса + */ + public function unban(array $parameters = []): ?string + { + if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) { + // Авторизован аккаунт администратора или оператора + + // Инициализация данных аккаунта + $account = model::read('d._key == "' . $parameters['id'] . '"'); + + if (!empty($account)) { + // Найден аккаунт + + // Блокирование + $account->active = true; + $account->banned = false; + + if (_core::update($account)) { + // Записаны данные аккаунта + + // Запись заголовков ответа + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Инициализация буфера вывода + ob_start(); + + // Генерация ответа + echo json_encode([ + 'unbanned' => true, + 'errors' => self::parse_only_text($this->errors) + ]); + + // Запись заголовков ответа + header('Content-Length: ' . ob_get_length()); + + // Отправка и деинициализация буфера вывода + ob_end_flush(); + flush(); + } else throw new exception('Не удалось записать изменения в базу данных'); + } else throw new exception('Не удалось найти аккаунт'); + } + + // Возврат (провал) + return null; + } } diff --git a/mirzaev/ebala/system/controllers/core.php b/mirzaev/ebala/system/controllers/core.php index a813d89..7619563 100755 --- a/mirzaev/ebala/system/controllers/core.php +++ b/mirzaev/ebala/system/controllers/core.php @@ -14,6 +14,9 @@ use mirzaev\ebala\views\templater, // Фреймворк PHP use mirzaev\minimal\controller; +// Встроенные библиотеки +use exception; + /** * Ядро контроллеров * diff --git a/mirzaev/ebala/system/controllers/task.php b/mirzaev/ebala/system/controllers/task.php index c2fcb31..be0569d 100755 --- a/mirzaev/ebala/system/controllers/task.php +++ b/mirzaev/ebala/system/controllers/task.php @@ -31,6 +31,11 @@ final class task extends core { use errors; + /** + * Типы работ + */ + final public const WORKS = ['Кассир', 'Выкладчик', 'Гастроном', 'Бригадир', 'Грузчик', 'Мобильный грузчик', 'Мобильный универсал']; + /** * Создать * @@ -477,7 +482,7 @@ final class task extends core ]; if ($account->type === 'worker') { - // Оператор или администратор + // Сотрудник foreach ($link->task['chats']['worker'] ?? [] as $message) { // Перебор сообщений из чата: СОТРУДНИК <-> ОПЕРАТОР @@ -486,7 +491,7 @@ final class task extends core if (!array_key_exists((string) $account->getKey(), $message['readed'] ?? [])) ++$generated['chat']['unreaded']; } } else if ($account->type === 'market') { - // Оператор или администратор + // Магазин foreach ($link->task['chats']['market'] ?? [] as $message) { // Перебор сообщений из чата: МАГАЗИН <-> ОПЕРАТОР @@ -1767,21 +1772,111 @@ final class task extends core public function works(array $parameters = []): void { try { - if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator' || $this->account->type === 'market')) { - // Авторизован аккаунт администратора, оператора или магазина + if (!empty($parameters['task'])) { + // Запрошены данные работ по заявке - // Инициализация данных - $this->view->task = model::read('d._key == "' . $parameters['task'] . '"'); + if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator' || $this->account->type === 'market' || $this->account->type === 'worker')) { + // Авторизован аккаунт администратора, оператора или магазина - if ($this->view->task instanceof _document) { - // Найдена заявка + // Инициализация данных + $this->view->task = model::read('d._key == "' . $parameters['task'] . '"'); + + if ($this->view->task instanceof _document) { + // Найдена заявка + + // Заявка не принадлежит запросившему магазину? + if ($this->account->type === 'market' and $this->view->task->market !== account::market($this->account->getId())?->id) + throw new exception('Вы не авторизованы для просмотра типа работы этой заявки'); + + // Заявка не принадлежит запросившему сотруднику? + if ($this->account->type === 'worker' and $this->view->task->worker !== account::worker($this->account->getId())?->id) + throw new exception('Вы не авторизованы для просмотра типа работы этой заявки'); + + // Инициализация списка работ + $this->view->works = static::WORKS; + + // Проверка на существование записанной в задаче работы в списке существующих работ и запись об этом в глобальную переменную шаблонизатора + foreach ($this->view->works as $work) if ($this->view->task->work === $work) $this->view->exist = true; + + // Запись заголовков ответа + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Инициализация буфера вывода + ob_start(); + + // Генерация ответа + echo json_encode( + [ + 'works' => $this->view->render(DIRECTORY_SEPARATOR . 'lists' . DIRECTORY_SEPARATOR . 'works.html'), + 'errors' => self::parse_only_text($this->errors) + ] + ); + + // Запись заголовков ответа + header('Content-Length: ' . ob_get_length()); + + // Отправка и деинициализация буфера вывода + ob_end_flush(); + flush(); + } else throw new exception('Не найдена заявка'); + } else throw new exception('Вы не авторизованы'); + } else if (!empty($parameters['worker'])) { + // Запрошены данные работ по сотруднику + + if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator' || $this->account->type === 'worker')) { + // Авторизован аккаунт администратора, оператора или магазина + + // Инициализация данных + $this->view->worker = worker::read('d.id == "' . $parameters['worker'] . '"'); + + if ($this->view->worker instanceof _document) { + // Найден сотрудник + + // Сотрудник не принадлежит запросившему аккаунту? + if ($this->account->type === 'worker' and $this->view->worker->id !== account::worker($this->account->getId())?->id) + throw new exception('Вы не авторизованы для просмотра типа работы этого сотрудника'); + + // Инициализация списка работ + $this->view->works = static::WORKS; + + // Проверка на существование записанной в задаче работы в списке существующих работ и запись об этом в глобальную переменную шаблонизатора + foreach ($this->view->works as $work) if ($this->view->worker->work === $work) $this->view->exist = true; + + // Запись заголовков ответа + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Инициализация буфера вывода + ob_start(); + + // Генерация ответа + echo json_encode( + [ + 'works' => $this->view->render(DIRECTORY_SEPARATOR . 'lists' . DIRECTORY_SEPARATOR . 'works.html'), + 'errors' => self::parse_only_text($this->errors) + ] + ); + + // Запись заголовков ответа + header('Content-Length: ' . ob_get_length()); + + // Отправка и деинициализация буфера вывода + ob_end_flush(); + flush(); + } else throw new exception('Не найден сотрудник'); + } else throw new exception('Вы не авторизованы'); + } else { + // Запрошен список работ + + if ($this->account->status()) { + // Авторизован аккаунт // Инициализация списка работ $this->view->works = ['Кассир', 'Выкладчик', 'Гастроном', 'Бригадир', 'Грузчик', 'Мобильный грузчик', 'Мобильный универсал']; - // Проверка на существование записанной в задаче работы в списке существующих работ и запись об этом в глобальную переменную шаблонизатора - foreach ($this->view->works as $work) if ($this->view->task->work === $work) $this->view->exist = true; - // Запись заголовков ответа header('Content-Type: application/json'); header('Content-Encoding: none'); @@ -1804,8 +1899,8 @@ final class task extends core // Отправка и деинициализация буфера вывода ob_end_flush(); flush(); - } else throw new exception('Не найдена заявка'); - } else throw new exception('Вы не авторизованы'); + } else throw new exception('Вы не авторизованы'); + } } catch (exception $e) { // Запись в реестр ошибок $this->errors[] = [ diff --git a/mirzaev/ebala/system/controllers/worker.php b/mirzaev/ebala/system/controllers/worker.php index 8a295a1..eae2718 100755 --- a/mirzaev/ebala/system/controllers/worker.php +++ b/mirzaev/ebala/system/controllers/worker.php @@ -29,6 +29,11 @@ final class worker extends core { use errors; + /** + * Типы работ + */ + final public const WORKS = ['Кассир', 'Выкладчик', 'Гастроном', 'Бригадир', 'Грузчик', 'Мобильный грузчик', 'Мобильный универсал']; + /** * Главная страница * @@ -261,6 +266,7 @@ final class worker extends core if (!empty($parameters['requisites']) && $parameters['worker_requisites'][-1] === '.') $parameters['worker_requisites'] .= '.'; if (!empty($parameters['worker_birth'])) $parameters['worker_birth'] = DateTime::createFromFormat('Y-m-d', $parameters['worker_birth'])->getTimestamp(); if (!empty($parameters['worker_issued'])) $parameters['worker_issued'] = DateTime::createFromFormat('Y-m-d', $parameters['worker_issued'])->getTimestamp(); + if (!empty($parameters['work'])) $parameters['work'] = in_array($parameters['work'], static::WORKS) ? $parameters['work'] : static::WORKS[0]; if (!empty($parameters['worker_hiring'])) $parameters['worker_hiring'] = DateTime::createFromFormat('Y-m-d', $parameters['worker_hiring'])->getTimestamp(); // Создание аккаунта @@ -353,6 +359,7 @@ final class worker extends core 'city' => $parameters['worker_city'], 'district' => $parameters['worker_district'], 'address' => $parameters['worker_address'], + 'work' => $parameters['worker_work'], 'hiring' => $parameters['worker_hiring'], 'rating' => 3 ], @@ -389,7 +396,7 @@ final class worker extends core // Авторизован аккаунт администратора или оператора // Инициализация данных сотрудника - $worker = model::read('d.id == "' . $parameters['id'] . '"', return: '{ name: d.name, number: d.number, mail: d.mail, birth: d.birth, passport: d.passport, issued: d.issued, department: d.department, requisites: d.requisites, payment: d.payment, tax: d.tax, city: d.city, district: d.district, address: d.address, hiring: d.hiring}')->getAll(); + $worker = model::read('d.id == "' . $parameters['id'] . '"', return: '{ name: d.name, number: d.number, mail: d.mail, birth: d.birth, passport: d.passport, issued: d.issued, department: d.department, requisites: d.requisites, payment: d.payment, tax: d.tax, city: d.city, district: d.district, address: d.address, worl: d.work, hiring: d.hiring}')->getAll(); if (!empty($worker)) { // Найдены данные сотрудника @@ -437,6 +444,7 @@ final class worker extends core // Универсализация if (!empty($parameters['birth'])) $parameters['birth'] = DateTime::createFromFormat('Y-m-d', $parameters['birth'])->getTimestamp(); if (!empty($parameters['issued'])) $parameters['issued'] = DateTime::createFromFormat('Y-m-d', $parameters['issued'])->getTimestamp(); + if (!empty($parameters['work'])) $parameters['work'] = in_array($parameters['work'], static::WORKS) ? $parameters['work'] : static::WORKS[0]; if (!empty($parameters['hiring'])) $parameters['hiring'] = DateTime::createFromFormat('Y-m-d', $parameters['hiring'])->getTimestamp(); // Инициализация параметров (перезапись переданными значениями) @@ -458,6 +466,7 @@ final class worker extends core if ($parameters['city'] !== $worker->city) $worker->city = $parameters['city']; if ($parameters['district'] !== $worker->district) $worker->district = $parameters['district']; if ($parameters['address'] !== $worker->address) $worker->address = $parameters['address']; + if ($parameters['work'] !== $worker->work) $worker->work = $parameters['work']; if ($parameters['hiring'] !== $worker->hiring) $worker->hiring = $parameters['hiring']; if (_core::update($worker)) { @@ -513,6 +522,114 @@ final class worker extends core return null; } + /** + * Пометить уволенным + * + * @param array $parameters Параметры запроса + */ + public function fire(array $parameters = []): ?string + { + if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) { + // Авторизован аккаунт администратора или оператора + + // Инициализация данных сотрудника + $worker = model::read('d.id == "' . $parameters['id'] . '"'); + + if (!empty($worker)) { + // Найден сотрудник + + // Увольнение + $worker->active = false; + $worker->fired = true; + + if (_core::update($worker)) { + // Записаны данные сотрудника + + // Запись заголовков ответа + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Инициализация буфера вывода + ob_start(); + + // Инициализация буфера ответа + $return = [ + 'fired' => true, + 'errors' => self::parse_only_text($this->errors) + ]; + + // Генерация ответа + echo json_encode($return); + + // Запись заголовков ответа + header('Content-Length: ' . ob_get_length()); + + // Отправка и деинициализация буфера вывода + ob_end_flush(); + flush(); + } else throw new exception('Не удалось записать изменения в базу данных'); + } else throw new exception('Не удалось найти аккаунт'); + } + + // Возврат (провал) + return null; + } + + /** + * Снять пометку уволенного (нанять) + * + * @param array $parameters Параметры запроса + */ + public function hire(array $parameters = []): ?string + { + if ($this->account->status() && ($this->account->type === 'administrator' || $this->account->type === 'operator')) { + // Авторизован аккаунт администратора или оператора + + // Инициализация данных сотрудника + $worker = model::read('d.id == "' . $parameters['id'] . '"'); + + if (!empty($worker)) { + // Найден сотрудник + + // Увольнение + $worker->active = true; + $worker->fired = false; + + if (_core::update($worker)) { + // Записаны данные сотрудника + + // Запись заголовков ответа + header('Content-Type: application/json'); + header('Content-Encoding: none'); + header('X-Accel-Buffering: no'); + + // Инициализация буфера вывода + ob_start(); + + // Инициализация буфера ответа + $return = [ + 'hired' => true, + 'errors' => self::parse_only_text($this->errors) + ]; + + // Генерация ответа + echo json_encode($return); + + // Запись заголовков ответа + header('Content-Length: ' . ob_get_length()); + + // Отправка и деинициализация буфера вывода + ob_end_flush(); + flush(); + } else throw new exception('Не удалось записать изменения в базу данных'); + } else throw new exception('Не удалось найти аккаунт'); + } + + // Возврат (провал) + return null; + } + /** * Прочитать данные сотрудников для * diff --git a/mirzaev/ebala/system/models/account.php b/mirzaev/ebala/system/models/account.php index 0205aa4..9338aac 100755 --- a/mirzaev/ebala/system/models/account.php +++ b/mirzaev/ebala/system/models/account.php @@ -42,7 +42,7 @@ final class account extends core * Конструктор * * @param ?session $session Инстанция сессии - * @param ?string $authenticate Аутентифицировать аккаунт? Если да, то какой категории? ([worker|operator|market] из $_SERVER['INTERFACE']) + * @param ?string $authenticate Аутентифицировать аккаунт? Если да, то какой категории? ([worker|market|operator|administrator] из $_SERVER['INTERFACE']) * @param array &$errors Реестр ошибок * * @return static Инстанция аккаунта @@ -62,12 +62,19 @@ final class account extends core // Связь сессии с аккаунтом session::connect($session->getId(), $this->document->getId(), $errors); + // Блокировка доступа + if ($account?->active !== true) throw new exception('Свяжитесь с оператором'); + else if ($account?->banned === true) throw new exception('Свяжитесь с оператором'); + else if ($account->type === 'worker') + if (($worker = account::worker($account->getId()))?->active !== true) throw new exception('Свяжитесь с оператором'); + else if ($worker?->fired === true) throw new exception('Свяжитесь с оператором'); + return $this; } else { // Не найден связанный с сессией аккаунт if ( match ($authenticate) { - 'worker', 'operator', 'market', 'administrator' => true, + 'worker', 'market', 'operator', 'administrator' => true, default => false } ) { @@ -94,11 +101,16 @@ final class account extends core // Удаление использованных данных из буфера сессии $session->write(['entry' => ['number' => null, 'password' => null]]); + // Блокировка доступа + if ($account?->active !== true) throw new exception('Свяжитесь с оператором'); + else if ($account?->banned === true) throw new exception('Свяжитесь с оператором'); + else if ($account->type === 'worker') + if (($worker = account::worker($account->getId()))?->active !== true) throw new exception('Свяжитесь с оператором'); + else if ($worker?->fired === true) throw new exception('Свяжитесь с оператором'); + // Выход (успех) return $this; } else throw new exception('Неправильный пароль'); - - throw new exception('Неизвестная ошибка на этапе проверки пароля'); } else throw new exception('Не найден аккаунт'); } else throw new exception('Не найден пароль в буфере сессии'); } else if (!empty($session->buffer['operator']['entry']['_key'])) { @@ -125,8 +137,6 @@ final class account extends core // Выход (успех) return $this; } else throw new exception('Неправильный пароль'); - - throw new exception('Неизвестная ошибка на этапе проверки пароля'); } } else throw new exception('Не найден пароль в буфере сессии'); } else if (!empty($session->buffer['market']['entry']['id'])) { @@ -153,8 +163,6 @@ final class account extends core // Выход (успех) return $this; } else throw new exception('Неправильный пароль'); - - throw new exception('Неизвестная ошибка на этапе проверки пароля'); } } else throw new exception('Не найден пароль в буфере сессии'); } else if (!empty($session->buffer['administrator']['entry'])) { @@ -181,8 +189,6 @@ final class account extends core // Выход (успех) return $this; } else throw new exception('Неправильный пароль'); - - throw new exception('Неизвестная ошибка на этапе проверки пароля'); } } else throw new exception('Не найден пароль в буфере сессии'); } else throw new exception('Не найдены данные первичной идентификации в буфере сессии'); @@ -227,7 +233,7 @@ final class account extends core LIMIT 1 RETURN e ) - FILTER d._id == e[0]._to && d.active == true + FILTER d._id == e[0]._to SORT d.created DESC, d._key DESC LIMIT 1 RETURN d @@ -285,7 +291,7 @@ final class account extends core LIMIT 1 RETURN e ) - FILTER d._id == e[0]._to && d.active == true + FILTER d._id == e[0]._to SORT d.created DESC, d.id DESC LIMIT 1 RETURN d diff --git a/mirzaev/ebala/system/public/css/list.css b/mirzaev/ebala/system/public/css/list.css index 828c80a..3fc0161 100755 --- a/mirzaev/ebala/system/public/css/list.css +++ b/mirzaev/ebala/system/public/css/list.css @@ -17,34 +17,34 @@ section.panel.list.medium { width: 80%; } -section.panel.list > :is(form, search).row.menu { +section.panel.list> :is(form, search).row.menu { margin-bottom: 10px; transition: 0s; } -section.panel.list > :is(form, search).row.menu > label { +section.panel.list> :is(form, search).row.menu>label { height: max-content; min-height: 30px; display: flex; } -section.panel.list > :is(form, search).row.menu > label:not(.solid) { +section.panel.list> :is(form, search).row.menu>label:not(.solid) { gap: 15px; } -section.panel.list > :is(form, search).row.menu.wide > label { +section.panel.list> :is(form, search).row.menu.wide>label { height: 36px; } -section.panel.list > :is(form, search).row.menu.separated { +section.panel.list> :is(form, search).row.menu.separated { margin-bottom: 20px; } -div#popup > section.list > div.row.endless { +div#popup>section.list>div.row.endless { height: auto; } -section.panel.list > :is(form, search).row.menu > label > button { +section.panel.list> :is(form, search).row.menu>label>button { position: relative; display: flex; justify-content: center; @@ -52,14 +52,11 @@ section.panel.list > :is(form, search).row.menu > label > button { height: 30px; } -section.panel.list > :is(form, search).row.menu > label > button.separated { +section.panel.list> :is(form, search).row.menu>label>button.separated { margin-left: 7px; } -section.panel.list - > :is(form, search).row.menu - > label - > button.separated:before { +section.panel.list> :is(form, search).row.menu>label>button.separated:before { content: ""; left: -12px; position: absolute; @@ -68,54 +65,47 @@ section.panel.list border-left: 2px solid var(--earth-above); } -section.panel.list > :is(form, search).row.menu.stretched > label > button, -section.panel.list - > :is(form, search).row.menu.stretched - > label - > input[type="search"] { +section.panel.list> :is(form, search).row.menu.stretched>label>button, +section.panel.list> :is(form, search).row.menu.stretched>label>input[type="search"] { flex-grow: 1; } -section.panel.list > :is(form, search).row.menu.stretched > label > button { +section.panel.list> :is(form, search).row.menu.stretched>label>button { max-width: 250px; } -section.panel.list > :is(form, search).row.menu > label > input { +section.panel.list> :is(form, search).row.menu>label>input { padding: 0 10px; } -section.panel.list > :is(form, search).row.menu > label > input:not(.merged) { +section.panel.list> :is(form, search).row.menu>label>input:not(.merged) { border-radius: 3px; } -section.panel.list > :is(form, search).row.menu > label > input[type="date"] { +section.panel.list> :is(form, search).row.menu>label>input[type="date"] { width: 115px; flex-shrink: 0; } -section.panel.list - > :is(form, search).row.menu - > label - > input[type="search"] - + button { +section.panel.list> :is(form, search).row.menu>label>input[type="search"]+button { height: 100%; padding: 0 30px; flex-grow: 0; } -section.panel.list > div#title { +section.panel.list>div#title { margin-top: 20px; height: 50px; background-color: var(--background-below-6); } -section.panel.list > div#title > span { +section.panel.list>div#title>span { font-weight: unset; font-size: unset; color: unset; } -section.panel.list > div.row { +section.panel.list>div.row { --gap: 12px; --background: var(--cloud); position: relative; @@ -128,11 +118,11 @@ section.panel.list > div.row { border-radius: 0px; } -section.panel.list > div.row:not(:nth-of-type(1)) { +section.panel.list>div.row:not(:nth-of-type(1)) { background-color: var(--background); } -section.panel.list > div.row:not(:nth-of-type(1)) > span { +section.panel.list>div.row:not(:nth-of-type(1))>span { height: 100%; line-height: 2.2; padding: 0; @@ -142,7 +132,7 @@ section.panel.list > div.row:not(:nth-of-type(1)) > span { -moz-box-shadow: var(--box-shadow); } -section.panel.list > div.row:not(:nth-of-type(1)):is(:hover, :focus) { +section.panel.list>div.row:not(:nth-of-type(1)):is(:hover, :focus) { --padding-left: 24px; --padding-right: 24px; left: -12px; @@ -151,23 +141,23 @@ section.panel.list > div.row:not(:nth-of-type(1)):is(:hover, :focus) { transition: 0s; } -section.panel.list > div.row:first-of-type { +section.panel.list>div.row:first-of-type { border-radius: 3px 3px 0 0; } -section.panel.list > div.row:last-of-type { +section.panel.list>div.row:last-of-type { border-radius: 0 0 3px 3px; } -section.panel.list > div.row:is(:hover, :focus) * { +section.panel.list>div.row:is(:hover, :focus) * { transition: unset; } -section.panel.list > div.row:not(:nth-of-type(1)):nth-child(2n + 1) { +section.panel.list>div.row:not(:nth-of-type(1)):nth-child(2n + 1) { --background: var(--cloud-above); } -section.panel.list > div.row[data-selected="true"]:before { +section.panel.list>div.row[data-selected="true"]:before { left: -25px; top: 0.08rem; position: absolute; @@ -186,7 +176,7 @@ section.panel.list > div.row[data-selected="true"]:before { color: var(--interface-brown); } -section.panel.list > div.row[data-selected="true"]:after { +section.panel.list>div.row[data-selected="true"]:after { right: -25px; bottom: 0.08rem; rotate: 180deg; @@ -206,85 +196,14 @@ section.panel.list > div.row[data-selected="true"]:after { color: var(--interface-brown); } -section.panel.list > div.row:not(:nth-of-type(1)).confirmed { - --background: var(--grass); -} - -section.panel.list - > div.row:not(:nth-of-type(1)):nth-child(2n + 1).confirmed { - --background: var(--grass-above); -} - -section.panel.list > div.row:not(:nth-of-type(1)).published { - --background: var(--river); -} - -section.panel.list - > div.row:not(:nth-of-type(1)):nth-child(2n + 1).published { - --background: var(--river-above); -} - -section.panel.list > div.row:not(:nth-of-type(1)).confirmed.published:not(.problematic) { - --background: var(--sea); -} - -section.panel.list - > div.row:not(:nth-of-type(1)).confirmed.published:not(.problematic):nth-child(2n + 1) { - --background: var(--sea-above); -} - -section.panel.list > div.row:not(:nth-of-type(1)).problematic { - --background: var(--clay); -} - -section.panel.list - > div.row:not(:nth-of-type(1)):nth-child(2n + 1).problematic { - --background: var(--clay-above); -} - -section.panel.list > div.row:not(:nth-of-type(1)).coming { - --background: var(--magma); -} - -section.panel.list - > div.row:not(:nth-of-type(1)):nth-child(2n + 1).coming { - --background: var(--magma-above); -} - -section.panel.list > div.row:not(:nth-of-type(1)).completed:not(.problematic) { - --background: var(--sand); -} - -section.panel.list - > div.row:not(:nth-of-type(1)):nth-child(2n + 1).completed:not(.problematic) { - --background: var(--sand-above); -} - -section.panel.list > div.row:not(:nth-of-type(1)).passed { - filter: brightness(0.8); -} - -section.panel.list > div.row:not(:nth-of-type(1)).hided * { - filter: blur(1px); - opacity: 0.3; -} - -section.panel.list > div.row:not(:nth-of-type(1)).hided:is(:hover, :focus) * { - filter: unset; - opacity: unset; -} - -section.panel.list > div.row.reinitialized { +section.panel.list>div.row.reinitialized { animation-duration: 3s; animation-name: row-reinitialized; animation-timing-function: ease-in; } -section.panel.list - > div.row:not( - :nth-of-type(1), - [data-selected="true"] - ).reinitializable:before { +section.panel.list>div.row:not(:nth-of-type(1), + [data-selected="true"]).reinitializable:before { content: attr(data-counter); position: absolute; left: -95px; @@ -297,16 +216,13 @@ section.panel.list color: var(--earth-text); } -section.panel.list - > div.row:not(:nth-of-type(1), [data-selected="true"]).reinitializable:is( - :hover, - :focus - ):before { +section.panel.list>div.row:not(:nth-of-type(1), [data-selected="true"]).reinitializable:is(:hover, + :focus):before { content: attr(id); color: var(--earth-text-important-below); } -section.panel.list > div.row > span { +section.panel.list>div.row>span { position: relative; margin: auto 0; padding: 8px 0; @@ -314,52 +230,52 @@ section.panel.list > div.row > span { transition: 0s; } -section.panel.list > div.row:is(:hover, :focus) > span { +section.panel.list>div.row:is(:hover, :focus)>span { transition: 0s; } -section.panel.list > div.row > span:not(:first-child) { +section.panel.list>div.row>span:not(:first-child) { --padding-left: calc(var(--gap) / 2); } -section.panel.list > div.row > span:not(:last-child) { +section.panel.list>div.row>span:not(:last-child) { --padding-right: calc(var(--gap) / 2); } -section.panel.list > div.row > span:first-child { +section.panel.list>div.row>span:first-child { border-radius: 3px 0 0 3px; } -section.panel.list > div.row > span:last-child { +section.panel.list>div.row>span:last-child { border-radius: 0 3px 3px 0; } -section.panel.list > div.row:not(:hover, :focus) > span:first-child { +section.panel.list>div.row:not(:hover, :focus)>span:first-child { --padding-left: var(--gap, 12px); } -section.panel.list > div.row:not(:hover, :focus) > span:last-child { +section.panel.list>div.row:not(:hover, :focus)>span:last-child { --padding-right: var(--gap, 12px); } -section.panel.list > div.row:nth-of-type(1) > span { +section.panel.list>div.row:nth-of-type(1)>span { text-align: center; } -section.panel.list > div.row:nth-of-type(1) > span > i { +section.panel.list>div.row:nth-of-type(1)>span>i { position: relative; margin: auto; } -section.panel.list > div.row > span[onclick] { +section.panel.list>div.row>span[onclick] { cursor: pointer; } -section.panel.list > div.row > span.field { +section.panel.list>div.row>span.field { cursor: text; } -section.panel.list > div.row:not(:nth-of-type(1)) > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row:not(:nth-of-type(1))>span:is(.important, .interactive:is(:hover, :focus)) { --margin: calc(var(--gap) / 2); --border-left: calc(var(--padding-left, var(--margin, 0px)) * -1); --border-right: var(--padding-right, var(--margin, 0px)); @@ -367,54 +283,196 @@ section.panel.list > div.row:not(:nth-of-type(1)) > span:is(.important, .interac --box-shadow: var(--border-left, 0) 0 0 0 var(--box-shadow-color, var(--background)), var(--border-right, 0) 0 0 0 var(--box-shadow-color, var(--background)); } -section.panel.list > div.row:not(:nth-of-type(1)):nth-child(2n + 1) > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).confirmed { + --background: var(--grass); +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)):nth-child(2n + 1).confirmed { + --background: var(--grass-above); +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).published { + --background: var(--river); +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)):nth-child(2n + 1).published { + --background: var(--river-above); +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).confirmed.published:not(.problematic) { + --background: var(--sea); +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).confirmed.published:not(.problematic):nth-child(2n + 1) { + --background: var(--sea-above); +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).problematic { + --background: var(--clay); +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)):nth-child(2n + 1).problematic { + --background: var(--clay-above); +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).coming { + --background: var(--magma); +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)):nth-child(2n + 1).coming { + --background: var(--magma-above); +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).completed:not(.problematic) { + --background: var(--sand); +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)):nth-child(2n + 1).completed:not(.problematic) { + --background: var(--sand-above); +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).passed { + filter: brightness(0.8); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)).banned { + --background: var(--clay); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)).banned a { + --color: var(--clay-text); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)).banned a:is(:hover, :focus) { + --color: var(--clay-text-above); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)).banned a:active { + --color: var(--clay-text-below); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)):nth-child(2n + 1).banned { + --background: var(--clay-above); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)):nth-child(2n + 1).banned a { + --color: var(--clay-text); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)):nth-child(2n + 1).banned a:is(:hover, :focus) { + --color: var(--clay-text-above); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)):nth-child(2n + 1).banned a:active { + --color: var(--clay-text-below); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)).fired { + --background: var(--magma); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)).fired a:is(:hover, :focus) { + --color: var(--magma-text-above); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)).fired a:active { + --color: var(--magma-text-below); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)).fired a { + --color: var(--magma-text); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)):nth-child(2n + 1).fired { + --background: var(--magma-above); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)):nth-child(2n + 1).fired a { + --color: var(--magma-text); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)):nth-child(2n + 1).fired a:is(:hover, :focus) { + --color: var(--magma-text-above); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)):nth-child(2n + 1).fired a:active { + --color: var(--magma-text-below); +} + +section.panel.list>div.row:not(:nth-of-type(1)).hided * { + filter: blur(1px); + opacity: 0.3; +} + +section.panel.list>div.row:not(:nth-of-type(1)).hided:is(:hover, :focus) * { + filter: unset; + opacity: unset; +} + +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)):nth-child(2n + 1)>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--cloud-rainy-above); } -section.panel.list > div.row:not(:nth-of-type(1)).published > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).published>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--river-deep); } -section.panel.list > div.row:not(:nth-of-type(1)):nth-child(2n + 1).published > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)):nth-child(2n + 1).published>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--river-deep-above); } -section.panel.list > div.row:not(:nth-of-type(1)).confirmed > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).confirmed>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--grass-dense); } -section.panel.list > div.row:not(:nth-of-type(1)):nth-child(2n + 1).confirmed > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)):nth-child(2n + 1).confirmed>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--grass-dense-above); } -section.panel.list > div.row:not(:nth-of-type(1)).confirmed.published:not(.problematic) > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).confirmed.published:not(.problematic)>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--sea-deep); } -section.panel.list > div.row:not(:nth-of-type(1)):nth-child(2n + 1).confirmed.published:not(.problematic) > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)):nth-child(2n + 1).confirmed.published:not(.problematic)>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--sea-deep-above); } -section.panel.list > div.row:not(:nth-of-type(1)).problematic > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).problematic>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--clay-important); } -section.panel.list > div.row:not(:nth-of-type(1)):nth-child(2n + 1).problematic > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)):nth-child(2n + 1).problematic>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--clay-important-above); } -section.panel.list > div.row:not(:nth-of-type(1)).coming > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).coming>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--magma-important); } -section.panel.list > div.row:not(:nth-of-type(1)):nth-child(2n + 1).coming > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)):nth-child(2n + 1).coming>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--magma-important-above); } -section.panel.list > div.row:not(:nth-of-type(1)).completed:not(.problematic) > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)).completed:not(.problematic)>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--sand-important); } -section.panel.list > div.row:not(:nth-of-type(1)):nth-child(2n + 1).completed:not(.problematic) > span:is(.important, .interactive:is(:hover, :focus)) { +section.panel.list>div.row[data-row="task"]:not(:nth-of-type(1)):nth-child(2n + 1).completed:not(.problematic)>span:is(.important, .interactive:is(:hover, :focus)) { --background: var(--sand-important-above); } + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)).banned>span:is(.important, .interactive:is(:hover, :focus)) { + --background: var(--clay-important); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)):nth-child(2n + 1).banned>span:is(.important, .interactive:is(:hover, :focus)) { + --background: var(--clay-important-above); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)).fired>span:is(.important, .interactive:is(:hover, :focus)) { + --background: var(--magma-important); +} + +section.panel.list>div.row[data-row="worker"]:not(:nth-of-type(1)):nth-child(2n + 1).fired>span:is(.important, .interactive:is(:hover, :focus)) { + --background: var(--magma-important-above); +} diff --git a/mirzaev/ebala/system/public/css/main.css b/mirzaev/ebala/system/public/css/main.css index 14faedf..f7e9a71 100755 --- a/mirzaev/ebala/system/public/css/main.css +++ b/mirzaev/ebala/system/public/css/main.css @@ -259,15 +259,16 @@ button:is(.transparent, .transparent:is(:hover, :focus), .transparent:active) { } a { - color: var(--link); + --color: var(--link); + color: var(--color); } a:is(:hover, :focus) { - color: var(--link-hover); + --color: var(--link-hover); } a:active { - color: var(--link-active); + --color: var(--link-active); transition: unset; } diff --git a/mirzaev/ebala/system/public/css/pages/workers.css b/mirzaev/ebala/system/public/css/pages/workers.css index 004b430..9bee916 100755 --- a/mirzaev/ebala/system/public/css/pages/workers.css +++ b/mirzaev/ebala/system/public/css/pages/workers.css @@ -15,7 +15,7 @@ section#workers.panel.list [data-column="worker"], [data-column="name"], [data-column="number"], - [data-column="mail"], + [data-column="work"], [data-column="passport"], [data-column="address"], [data-column="tax"], diff --git a/mirzaev/ebala/system/public/css/popup.css b/mirzaev/ebala/system/public/css/popup.css index a2c99c2..f7c444d 100644 --- a/mirzaev/ebala/system/public/css/popup.css +++ b/mirzaev/ebala/system/public/css/popup.css @@ -38,7 +38,6 @@ div#popup>section.stretched { flex-grow: unset; } - div#popup>section.calculated { width: calc(var(--calculated-width) - var(--padding-horizontal, 0px) * 2); } @@ -53,6 +52,11 @@ div#popup>section.list { border-radius: 3px; } +div#popup>section.list.extensive { + max-width: unset; + max-height: unset; +} + div#popup>section.list>h3 { margin-top: 4px; margin-bottom: 22px; diff --git a/mirzaev/ebala/system/public/css/themes/harmony/earth.css b/mirzaev/ebala/system/public/css/themes/harmony/earth.css index 5f45585..bb48b41 100644 --- a/mirzaev/ebala/system/public/css/themes/harmony/earth.css +++ b/mirzaev/ebala/system/public/css/themes/harmony/earth.css @@ -83,10 +83,9 @@ --sand-important: #d7c06c; --sand-important-below: #dfc79a; - --magma-text-above: ; - --magma-text: ; - --magma-text-below: ; - --magma-text-below-1: ; + --magma-text-above: #111; + --magma-text: #5e1a1a; + --magma-text-below: #826d1c; --magma-above: #ffd325; --magma: #e6bf26; --magma-below: ; diff --git a/mirzaev/ebala/system/public/index.php b/mirzaev/ebala/system/public/index.php index 986b4f9..625e479 100755 --- a/mirzaev/ebala/system/public/index.php +++ b/mirzaev/ebala/system/public/index.php @@ -40,6 +40,7 @@ $router->write('/worker/$worker/read', 'task', 'worker', 'POST'); $router->write('/worker/$id/fields', 'worker', 'fields', 'POST'); $router->write('/worker/$id/update', 'worker', 'update', 'POST'); $router->write('/worker/$id/fire', 'worker', 'fire', 'POST'); +$router->write('/worker/$id/hire', 'worker', 'hire', 'POST'); $router->write('/workers', 'worker', 'index', 'GET'); $router->write('/workers', 'worker', 'index', 'POST'); $router->write('/workers/read', 'worker', 'read', 'POST'); @@ -68,6 +69,8 @@ $router->write('/$id', 'account', 'index', 'POST'); $router->write('/$id/fields', 'account', 'fields', 'POST'); $router->write('/$id/update', 'account', 'update', 'POST'); $router->write('/$id/delete', 'account', 'delete', 'POST'); +$router->write('/$id/ban', 'account', 'ban', 'POST'); +$router->write('/$id/unban', 'account', 'unban', 'POST'); $router->write('/session/worker', 'session', 'worker', 'POST'); $router->write('/session/write', 'session', 'write', 'POST'); $router->write('/session/read', 'session', 'read', 'POST'); @@ -79,6 +82,7 @@ $router->write('/session/invite', 'session', 'invite', 'POST'); $router->write('/tasks/create', 'task', 'create', 'POST'); $router->write('/tasks/read', 'task', 'read', 'POST'); $router->write('/works/list', 'work', 'datalist', 'POST'); +$router->write('/tasks/works', 'task', 'works', 'POST'); $router->write('/task/$task/read', 'task', 'task', 'POST'); $router->write('/task/$task/value', 'task', 'value', 'POST'); $router->write('/task/$task/confirm', 'task', 'confirm', 'POST'); @@ -88,7 +92,6 @@ $router->write('/task/$task/hide', 'task', 'hide', 'POST'); $router->write('/task/$task/remove', 'task', 'remove', 'POST'); $router->write('/task/$task/work', 'task', 'work', 'POST'); $router->write('/task/$task/date', 'task', 'date', 'POST'); -$router->write('/task/$task/works', 'task', 'works', 'POST'); $router->write('/task/$task/description', 'task', 'description', 'POST'); $router->write('/task/$task/commentary', 'task', 'commentary', 'POST'); $router->write('/task/$task/worker/update', 'task', 'update', 'POST'); diff --git a/mirzaev/ebala/system/public/js/administrators.js b/mirzaev/ebala/system/public/js/administrators.js index 339850f..2c8f467 100644 --- a/mirzaev/ebala/system/public/js/administrators.js +++ b/mirzaev/ebala/system/public/js/administrators.js @@ -338,7 +338,7 @@ if (typeof window.administrators !== "function") { // Инициализация оболочки всплывающего окна const popup = document.createElement("section"); - popup.classList.add("list", "small"); + popup.classList.add("list", "extensive", "small"); // Инициализация заголовка всплывающего окна const title = document.createElement("h3"); @@ -1056,7 +1056,7 @@ if (typeof window.administrators !== "function") { ); /** - * Сгенерировать окно с формой создания аккаунт + * Сгенерировать окно с формой создания аккаунта * * @param {HTMLElement} row Строка * @@ -1069,7 +1069,7 @@ if (typeof window.administrators !== "function") { // Инициализация оболочки всплывающего окна const popup = document.createElement("section"); - popup.classList.add("list", "small"); + popup.classList.add("list", "extensive", "small"); // Инициализация заголовка всплывающего окна const title = document.createElement("h3"); diff --git a/mirzaev/ebala/system/public/js/markets.js b/mirzaev/ebala/system/public/js/markets.js index 10df418..1b402eb 100644 --- a/mirzaev/ebala/system/public/js/markets.js +++ b/mirzaev/ebala/system/public/js/markets.js @@ -339,7 +339,7 @@ if (typeof window.markets !== "function") { // Инициализация всплывающего окна const popup = document.createElement("section"); - popup.classList.add("list", "medium"); + popup.classList.add("list", "extensive", "medium"); // Инициализация заголовка всплывающего окна const title = document.createElement("h3"); @@ -1774,7 +1774,7 @@ if (typeof window.markets !== "function") { // Инициализация всплывающего окна const popup = document.createElement("section"); - popup.classList.add("list", "medium"); + popup.classList.add("list", "extensive", "medium"); // Инициализация заголовка всплывающего окна const title = document.createElement("h3"); diff --git a/mirzaev/ebala/system/public/js/operators.js b/mirzaev/ebala/system/public/js/operators.js index 7579949..409e812 100644 --- a/mirzaev/ebala/system/public/js/operators.js +++ b/mirzaev/ebala/system/public/js/operators.js @@ -338,7 +338,7 @@ if (typeof window.operators !== "function") { // Инициализация оболочки всплывающего окна const popup = document.createElement("section"); - popup.classList.add("list", "small"); + popup.classList.add("list", "extensive", "small"); // Инициализация заголовка всплывающего окна const title = document.createElement("h3"); @@ -1069,7 +1069,7 @@ if (typeof window.operators !== "function") { // Инициализация оболочки всплывающего окна const popup = document.createElement("section"); - popup.classList.add("list", "small"); + popup.classList.add("list", "extensive", "small"); // Инициализация заголовка всплывающего окна const title = document.createElement("h3"); diff --git a/mirzaev/ebala/system/public/js/tasks.js b/mirzaev/ebala/system/public/js/tasks.js index d31cd3b..66e979f 100755 --- a/mirzaev/ebala/system/public/js/tasks.js +++ b/mirzaev/ebala/system/public/js/tasks.js @@ -2573,7 +2573,7 @@ if (typeof window.tasks !== "function") { // Инициализация списка выбора типа работы const work = document.createElement("select"); work.classList.add("row", "connected", "stretched"); - this.works(row).then((html) => (work.innerHTML = html)); + this.works(task).then((html) => (work.innerHTML = html)); work.setAttribute("title", "Тип работы"); // Инициализация поля ввода описания @@ -3840,41 +3840,33 @@ if (typeof window.tasks !== "function") { } /** - * Сгенерировать список работ и выбрать в нём ту, что записана в базе данных у заявки + * Список работ * - * @param {HTMLElement} row Строка + * Сгенерировать список работ и выбрать в нём ту, что записана в базе данных у заявки, если передана + * + * @param {number|null} id Идентификатор заявки * * @return {array|null} Массив HTML-элементов