Проработка панели модератора

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2021-06-01 09:03:33 +10:00
parent 4f8a99d8e2
commit fab290eacd
8 changed files with 464 additions and 34 deletions

View File

@ -77,8 +77,11 @@ $config = [
'controller' => 'main'
],
'product/<catn:[^/]+>' => 'product/index',
'<section:(product|cart)>/<catn:[^/]+>/<action:(write|edit|delete)>/<target:(title|catn|dscr|dmns|wght|image|cover|comm)>' => '<section>/<action>-<target>',
'orders' => 'order/index'
'<section:(product|cart)>/<catn:[^/]+>/<action:(read|write|edit|delete)>/<target:(title|catn|dscr|dmns|wght|image|cover|comm)>' => '<section>/<action>-<target>',
'orders' => 'order/index',
'orders/<_key:[^/]+>/<action:(accept)>' => 'order/<action>',
'orders/supply/<_key:[^/]+>/<action:(read|write|edit|delete)>' => 'order/supply-<action>',
'orders/supply/<_key:[^/]+>/<action:(read|write|edit|delete)>/<target:(stts)>' => 'order/supply-<action>-<target>'
],
],

View File

@ -11,9 +11,16 @@ use yii\web\Response;
use yii\web\Cookie;
use app\models\Order;
use app\models\Account;
use app\models\Product;
use app\models\OrderEdgeSupply;
use app\models\AccountEdgeOrder;
use app\models\connection\Dellin;
use app\models\Notification;
use app\models\SupplyEdgeProduct;
use Codeception\PHPUnit\ResultPrinter\HTML;
use Exception;
class OrderController extends Controller
@ -27,7 +34,7 @@ class OrderController extends Controller
[
'allow' => true,
'roles' => ['@'],
'actions' => ['index', 'write', 'delete', 'amount-update', 'pay']
'actions' => ['index', 'accept', 'read', 'write', 'delete', 'amount-update', 'pay', 'supply-read', 'supply-write-stts']
],
[
'allow' => false,
@ -78,6 +85,7 @@ class OrderController extends Controller
if (yii::$app->request->isPost) {
// POST-запрос
// Настройка
yii::$app->response->format = Response::FORMAT_JSON;
return [
@ -91,6 +99,47 @@ class OrderController extends Controller
return $this->render('/orders/index', compact('orders', 'moderator_orders'));
}
/**
* Подтверждение заказа
*
* @param int $_key Ключ записи в коллекции order
*
* @return string|array|null
*/
public function actionAccept(int $_key): string|array|null
{
// Инициализация
$buffer = [];
$account_edge_order = AccountEdgeOrder::searchByOrder(Order::collectionName() . '/' . $_key, limit: 1)[0];
// Запись в буфер записи в базу данных
$account_edge_order->type = 'accepted';
// Отправка изменений в базу данных
if ($account_edge_order->save()) {
// Удалось сохранить изменения
// Инициализация
$orders = Order::search(type: 'all', limit: 10, page: 1, select: '{account_edge_order, order}');
$moderator_orders = self::genOrdersForModeration();
// Запись в буфер вывода
$buffer['main'] = $this->renderPartial('/orders/index', compact('orders', 'moderator_orders'));
} else {
// Не удалось сохранить изменения
yii::$app->response->statusCode = 500;
}
// Запись обязательных параметров
$buffer['_csrf'] = yii::$app->request->getCsrfToken();
// Настройка ответа
yii::$app->response->format = Response::FORMAT_JSON;
return $buffer;
}
/**
* Запись
*/
@ -355,7 +404,8 @@ class OrderController extends Controller
*
* @return array ['order' => array, 'order_edge_account' => array, 'supplies' => array]
*/
protected static function genOrdersForModeration(int $page = 1): array {
protected static function genOrdersForModeration(int $page = 1): array
{
$orders = Order::search(account: '@all', type: 'requested', limit: 10, page: 1, select: '{account_edge_order, order}');
foreach ($orders as &$order) {
@ -366,4 +416,101 @@ class OrderController extends Controller
return $orders;
}
/**
* Чтение инстанции поставки в заказе (order_edge_supply)
*
* @param int $_key Ключ записи в коллекции order_edge_supply
*
* @return string|array|null
*/
public function actionSupplyRead(int $_key): string|array|null
{
// Инициализация
$buffer = [];
if ($order_edge_supply = OrderEdgeSupply::searchById($_id = OrderEdgeSupply::collectionName() . '/' . $_key)) {
// Удалось найти инстанцию поставки
// Инициализация ребра: ПОСТАВКА -> ТОВАР
$supply_edge_product = SupplyEdgeProduct::searchBySupplyId($order_edge_supply->_to);
// // Поиск ребра до аккаунта
// $account = Account::searchBySupplyId($order_edge_supply->_to);
// // Поиск привязанного товара
// $product = Product::searchBySupplyId($order_edge_supply->_to);
// try {
// // Инициализация доставки
// $delivery = Dellin::calcDeliveryAdvanced(
// explode('_', $account['opts']['delivery_from_terminal'])[1],
// explode('_', yii::$app->user->identity->opts['delivery_to_terminal'])[1],
// (int) ($product['wght'] ?? 0),
// (int) ($product['dmns']['x'] ?? 0),
// (int) ($product['dmns']['y'] ?? 0),
// (int) ($product['dmns']['z'] ?? 0)
// );
// } catch (Exception $e) {
// // var_dump(json_decode($e->getMessage(), true)['errors']); die;
// }
// Запись параметров
$buffer['cost'] = $order_edge_supply->cost ?? $order_edge_supply->cost = $supply_edge_product[0]['onec']['Цены']['Цена']['ЦенаЗаЕдиницу'];
$buffer['time'] = $order_edge_supply->time ?? 0;
// $buffer['time'] = $order_edge_supply->time ?? $delivery ?? 0;
$buffer['comm'] = $order_edge_supply->comm ?? $order_edge_supply->comm = 'Комментарий к заказу';
$buffer['stts'] = $order_edge_supply->stts ?? $order_edge_supply->stts = 0;
$order_edge_supply->save();
}
// Запись обязательных параметров
$buffer['_csrf'] = yii::$app->request->getCsrfToken();
// Настройка ответа
yii::$app->response->format = Response::FORMAT_JSON;
return $buffer;
}
/**
* Чтение инстанции поставки в заказе (order_edge_supply)
*
* @param int $_key Ключ записи в коллекции order_edge_supply
*
* @return string|array|null
*/
public function actionSupplyWriteStts(int $_key): string|array|null
{
// Инициализация
$stts = yii::$app->request->post('stts') ?? yii::$app->request->get('stts');
$buffer = [];
if ($order_edge_supply = OrderEdgeSupply::searchById($_id = OrderEdgeSupply::collectionName() . '/' . $_key)) {
// Удалось найти инстанцию поставки
// Запись в буфер вывода и буфер записи в базу данных
$buffer['stts'] = $order_edge_supply->stts = $stts;
// Отправка в базу данных
if ($order_edge_supply->save()) {
// Удалось сохранить изменения
} else {
// Не удалось сохранить изменения
yii::$app->response->statusCode = 500;
}
}
// Запись обязательных параметров
$buffer['_csrf'] = yii::$app->request->getCsrfToken();
// Настройка ответа
yii::$app->response->format = Response::FORMAT_JSON;
return $buffer;
}
}

View File

@ -10,4 +10,17 @@ class AccountEdgeOrder extends Edge
{
return 'account_edge_order';
}
/**
* Поиск по идентификатору заказа
*
* @param string $order_id Идентификатор записи заказа в базе данных
* @param int $limit Ограничение
*
* @return array|null
*/
public static function searchByOrder(string $order_id, int $limit = 1): ?array
{
return self::find()->where(['_to' => $order_id])->limit($limit)->all();
}
}

View File

@ -23,7 +23,10 @@ class OrderEdgeSupply extends Edge
return array_merge(
parent::attributes(),
[
'comm'
'comm',
'cost',
'time',
'stts'
]
);
}
@ -36,7 +39,10 @@ class OrderEdgeSupply extends Edge
return array_merge(
parent::attributeLabels(),
[
'comm' => 'Комментарий к заказу'
'comm' => 'Комментарий',
'cost' => 'Цена',
'time' => 'Время',
'stts' => 'Статус'
]
);
}
@ -50,12 +56,26 @@ class OrderEdgeSupply extends Edge
parent::rules(),
[
[
[
'comm'
],
'comm',
'string',
'length' => [0, 300],
'message' => '{attribute} должен быть строкой от 0 до 300 символов'
],
[
'stts',
'string',
'length' => [0, 15],
'message' => '{attribute} должен быть строкой от 0 до 15 символов'
],
[
'cost',
'integer',
'message' => '{attribute} должна быть числом'
],
[
'time',
'integer',
'message' => '{attribute} должно быть числом'
]
]
);

View File

@ -69,6 +69,11 @@ class SupplyEdgeProduct extends Edge implements OfferInterface
return self::findOne([self::getIdFieldName1c() => $ocid]);
}
public static function searchBySupplyId(string $_id, int $limit = 1): array
{
return self::find()->where(['_from' => $_id])->limit($limit)->all();
}
/**
* Название поля в котором хранится ID из 1C
*/

View File

@ -40,13 +40,8 @@ if (
</div>
<?php if (!empty($moderator_orders)) : ?>
<?php
// Инициализация счетчика заказов
$order_number = 1;
?>
<?php foreach ($moderator_orders as $order) : ?>
<div class="page_order_panel mb-3 py-3 px-4 rounded">
<div id="<?= $order['order']['_key'] ?>_panel" class="page_order_panel mb-3 py-3 px-4 rounded">
<h5 class="row mt-1 mb-3">
<?php
// Инициализация времени отправки заказа
@ -78,8 +73,8 @@ if (
</p>
</h5>
<div class="dropdown-divider mb-3"></div>
<div id="orders_panel_supplies_<?= $order_number ?>" class="row px-2 unselectable">
<div class="col-3">
<div class="row px-2">
<div id="orders_panel_supplies_<?= $order['order']['_key'] ?>" class="col-3 unselectable">
<?php if (!empty($order['supplies'])) : ?>
<?php
// Инициализация счетчика поставок для отрисовки горизонтального разделителя
@ -118,9 +113,13 @@ if (
?>
<?php foreach ($supply['order_edge_supply'] as $part) : ?>
<a id="<?= $part['_id'] ?>" class="row p-2 px-0 rounded row_supply" type="button" onclick="return orders_supply_edit(this, <?= $order_number ?>);">
<a id="<?= $part['_key'] ?>_supply" class="row p-2 px-0 rounded row_supply" type="button" onclick="return orders_supply_edit('<?= $part['_key'] ?>', <?= $order['order']['_key'] ?>);">
<img class="col-auto px-0 h-100 img-fluid rounded" src="<?= $covr ?>" />
<p class="col text-dark"><?= $supply['product']['catn'] ?></p>
<p id="<?= $part['_key'] ?>_supply_stts_indicator" class="col d-flex text-dark"><?= $supply['product']['catn'] ?>
<?php if(isset($part['stts']) && $part['stts'] == 1) :?>
<span id="<?= $part['_key'] ?>_supply_stts_indicator_icon" class="ml-auto my-auto fas fa-check"></span>
<?php endif ?>
</p>
</a>
<?php endforeach ?>
@ -134,10 +133,10 @@ if (
</div>
<?php endif ?>
</div>
<div id="orders_panel_edit_<?= $order_number ?>" class="col-6 d-flex">
<div id="orders_panel_edit_<?= $order['order']['_key'] ?>" class="px-3 col-6 d-flex flex-column">
<p class="my-auto">Выберите поставку</p>
</div>
<div id="orders_panel_info_<?= $order_number ?>" class="col-3 d-flex flex-column">
<div id="orders_panel_info_<?= $order['order']['_key'] ?>" class="col-3 d-flex flex-column">
<?php
// Конвертация статуса заказа
@ -149,15 +148,17 @@ if (
?>
<p class="row mt-0 mb-3 px-2"><b>Статус:</b> <span class="ml-auto"><?= $status ?></span></p>
<small class="row mt-auto mb-3 px-2">Здесь будет информация об общей цене и о максимальном сроке доставки которые будут меняться по мере настройки и подтверждения наличия поставок</small>
<a class="row mb-0 text-center text-white btn button_blue button_clean" type="button" onclick="return false;">Подтвердить</a>
<a id="<?= $order['order']['_key'] ?>_button" class="row mt-auto mb-0 text-center text-white btn button_blue button_clean disabled" type="button" onclick="return order_accept('<?= $order['order']['_key'] ?>');">Подтвердить</a>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
order_init('<?= $order['order']['_key'] ?>');
}, false);
</script>
</div>
<?php
// Обновление счетчика заказов
++$order_number;
?>
<?php endforeach ?>
<?php else : ?>
<div class="page_order_panel py-3 px-4 rounded">

View File

@ -269,7 +269,6 @@ function cart_list_comment_save(catn, element) {
// Запись аттрибута (предзагрузка)
element.setAttribute('onclick', 'return cart_list_comment_edit(\'' + catn + '\', this);');
$.ajax({
url: '/cart/' + catn + '/edit/comm',
type: 'post',

View File

@ -1,13 +1,60 @@
function orders_supply_edit(target, order_number) {
function order_init(order_key) {
// Инициализация панели
let panel = document.getElementById(order_key + '_panel');
// Инициализация кнопки
let button = document.getElementById(order_key + '_button');
let supplies_are_confirmed = true;
for (let i = 0; i <= panel.children[2].children[0].children.length - 1; i++) {
// Инициализация
let target = panel.children[2].children[0].children[i];
console.log(i);
if ((target === undefined || target.children[1] === undefined || target.children[1].children[0] === undefined) && !target.classList.contains('dropdown-divider')) {
supplies_are_confirmed = false;
}
}
if (supplies_are_confirmed) {
button.classList.remove('disabled');
}
return false;
}
function order_accept(order_key) {
$.ajax({
url: 'orders/' + order_key + '/accept',
type: 'post',
dataType: 'json',
data: {
'_csrf': yii.getCsrfToken()
},
success: orders_response_success,
error: orders_response_error
});
return false;
}
function orders_supply_edit(supply_key, order_key) {
// Инициализация
let supply = document.getElementById(supply_key + '_supply');
// Поиск панели для вывода информации
let panel = document.getElementById('orders_panel_edit_' + order_number);
let panel = document.getElementById('orders_panel_edit_' + order_key);
// Поиск всех кнопок с поставками
let rows = document.getElementsByClassName('row_supply');
// Деактивация остальных кнопок
for (let i = 0; i < rows.length; i++) {
if (rows[i].parentElement.parentElement.getAttribute('id') === 'orders_panel_supplies_' + order_number) {
if (rows[i].parentElement.getAttribute('id') === 'orders_panel_supplies_' + order_key) {
// Если это кнопка конкретно с этого заказа
rows[i].classList.remove('row_supply_active');
@ -15,9 +62,204 @@ function orders_supply_edit(target, order_number) {
}
// Активация выбранной кнопки
target.classList.add('row_supply_active');
supply.classList.add('row_supply_active');
panel.innerHTML = target.getAttribute('id');
// Запись индикатора загрузки
panel.innerHTML = '<p class="my-auto">Загрузка</p>';
return false
$.ajax({
url: 'orders/supply/' + supply_key + '/read',
type: 'post',
dataType: 'json',
data: {
'_csrf': yii.getCsrfToken()
},
success: function (data, status) {
// Удаление индикатора загрузки
panel.innerHTML = '';
// Цена
if (document.getElementById(supply.getAttribute('id') + '_cost') === null) {
// Инициализация контейнера
let container = document.createElement('div');
container.setAttribute('id', supply.getAttribute('id') + '_cost');
container.setAttribute('class', 'row mb-3 px-3');
// Инициализация названия
let name = document.createElement('p');
name.setAttribute('id', supply.getAttribute('id') + '_cost_name');
name.setAttribute('class', 'col-2 text-center');
name.innerText = 'Цена';
// Инициализация поля
let input = document.createElement('input');
input.setAttribute('id', supply.getAttribute('id') + '_cost_input');
input.setAttribute('class', 'col-10 form-control');
input.setAttribute('type', 'number');
if (data.cost !== undefined) {
input.setAttribute('value', data.cost);
} else {
input.setAttribute('value', 0);
}
input.setAttribute('aria-invalid', 'false');
// Запись в документ
panel.appendChild(container);
container.appendChild(name);
container.appendChild(input);
};
// Время доставки
if (document.getElementById(supply.getAttribute('id') + '_time') === null) {
// Инициализация контейнера
let container = document.createElement('div');
container.setAttribute('id', supply.getAttribute('id') + '_time');
container.setAttribute('class', 'row mb-3 px-3');
// Инициализация названия
let name = document.createElement('p');
name.setAttribute('id', supply.getAttribute('id') + '_time_name');
name.setAttribute('class', 'col-2 text-center');
name.innerText = 'Время';
// Инициализация поля
let input = document.createElement('input');
input.setAttribute('id', supply.getAttribute('id') + '_time_input');
input.setAttribute('class', 'col-10 form-control');
input.setAttribute('type', 'number');
if (data.time !== undefined) {
input.setAttribute('value', data.time);
} else {
input.setAttribute('value', 0);
}
input.setAttribute('aria-invalid', 'false');
// Запись в документ
panel.appendChild(container);
container.appendChild(name);
container.appendChild(input);
};
// Комментарий
if (document.getElementById(supply.getAttribute('id') + '_comm') === null) {
// Инициализация контейнера
let container = document.createElement('div');
container.setAttribute('id', supply.getAttribute('id') + '_comm');
container.setAttribute('class', 'row mb-3 px-3');
// Инициализация поля
let textarea = document.createElement('textarea');
textarea.setAttribute('id', supply.getAttribute('id') + '_comm_input');
textarea.setAttribute('class', 'col-12 form-control');
textarea.setAttribute('cols', '50');
textarea.setAttribute('rows', '3');
if (data.comm === undefined) {
textarea.innerText = 'Комментарий к заказу';
} else {
textarea.innerText = data.comm;
}
// Запись в документ
panel.appendChild(container);
container.appendChild(textarea);
};
// Статус подтверждения
if (document.getElementById(supply.getAttribute('id') + '_stts') === null) {
// Инициализация контейнера
let container = document.createElement('div');
container.setAttribute('id', supply.getAttribute('id') + '_stts');
container.setAttribute('class', 'row px-3');
// Инициализация индикатора
let span = document.createElement('span');
span.setAttribute('id', supply.getAttribute('id') + '_stts_indicator_icon');
span.setAttribute('class', 'ml-auto my-auto fas fa-check');
// Инициализация кнопки
let button = document.createElement('a');
button.setAttribute('id', supply.getAttribute('id') + '_stts_button');
button.setAttribute('type', 'button');
button.setAttribute('role', 'button');
button.setAttribute('onclick', 'return orders_supply_comm_write(this, \'' + supply_key + '\', \'' + order_key + '\');');
if (data.stts === undefined || data.stts == 0) {
button.setAttribute('class', 'col-12 btn button_blue button_clean');
button.innerText = 'Подтвердить';
} else {
button.setAttribute('class', 'col-12 btn button_blue button_clean disabled');
button.innerText = 'Подтверждено';
// Инициализация
let title = document.getElementById(supply.getAttribute('id') + '_stts_indicator');
console.log(title.children[0]);
if (title.children[0] === undefined) {
// Индикатор не найден
// Запись индикатора
title.appendChild(span);
}
}
// Запись в документ
panel.appendChild(container);
container.appendChild(button);
// Реинициализация
order_init(order_key);
};
orders_response_success(data, status);
},
error: orders_response_error
});
return false;
}
function orders_supply_comm_write(button, supply_key, order_key) {
// Инициализация
let supply = document.getElementById(supply_key + '_supply');
$.ajax({
url: 'orders/supply/' + supply_key + '/write/stts',
type: 'post',
dataType: 'json',
data: {
'_csrf': yii.getCsrfToken(),
'stts': 1
},
success: function (data, status) {
// Инициализация индикатора
let span = document.createElement('span');
span.setAttribute('id', supply.getAttribute('id') + '_stts_indicator_icon');
span.setAttribute('class', 'ml-auto my-auto fas fa-check');
if (data.stts === undefined || data.stts == 0) {
button.setAttribute('class', 'col-12 btn button_blue button_clean');
button.innerText = 'Подтвердить';
} else {
button.setAttribute('class', 'col-12 btn button_blue button_clean disabled');
button.innerText = 'Подтверждено';
// Инициализация
let title = document.getElementById(supply.getAttribute('id') + '_stts_indicator');
if (title.children[0] === undefined) {
// Индикатор не найден
// Запись индикатора
title.appendChild(span);
}
// Реинициализация
order_init(order_key);
}
orders_response_success(data, status);
},
error: orders_response_error
});
return false;
}