заказы
This commit is contained in:
+621
-7
@@ -89,7 +89,11 @@ async function checkActiveUser() {
|
||||
}
|
||||
}
|
||||
|
||||
async function openTab(event, tabId) {
|
||||
async function openTab(event, tabId, autoLoad = false) {
|
||||
const activeTab = loadFromStorage('tab');
|
||||
if (activeTab && activeTab.tabId === tabId && !autoLoad) {
|
||||
return;
|
||||
}
|
||||
// Убираем активный класс со всех вкладок и кнопок
|
||||
document.querySelectorAll('.tab-nav-btn').forEach(btn => {
|
||||
btn.classList.remove('active');
|
||||
@@ -136,6 +140,12 @@ function prepareTabs() {
|
||||
};
|
||||
}
|
||||
|
||||
tabsData['orders'] = {
|
||||
title: 'Заказы',
|
||||
icon: 'bi-basket',
|
||||
description: 'Управление заказами'
|
||||
};
|
||||
|
||||
if (accessData.view_requests) {
|
||||
tabsData['jurnal_toolkits'] = {
|
||||
title: 'Журнал перемещений',
|
||||
@@ -170,11 +180,11 @@ function prepareTabs() {
|
||||
<div id="mainTabsNavWrapper">
|
||||
<nav class="nav nav-pills gap-2" id="mainTabsNav" role="tablist">
|
||||
${Object.entries(tabsData).map(([tabId, tabData], index) => `
|
||||
<button class="nav-link tab-nav-btn d-flex flex-column align-items-center justify-content-center py-3 px-2"
|
||||
id="${tabId}-tab"
|
||||
role="tab"
|
||||
onclick="openTab(event, '${tabId}')"
|
||||
style="min-width: 120px; transition: all 0.3s ease;">
|
||||
<button class="nav-link tab-nav-btn d-flex flex-column align-items-center justify-content-center py-3 px-2 position-relative"
|
||||
id="${tabId}-tab"
|
||||
role="tab"
|
||||
onclick="openTab(event, '${tabId}')"
|
||||
style="min-width: 120px; transition: all 0.3s ease;">
|
||||
<i class="${tabData.icon} nav-icon fs-3 mb-2 text-muted" style="transition: all 0.3s ease;"></i>
|
||||
<span class="nav-title fw-medium" style="font-size: 0.9rem;">${tabData.title}</span>
|
||||
<div class="nav-indicator"></div>
|
||||
@@ -240,7 +250,7 @@ function prepareTabs() {
|
||||
const activeTabId = activeTabData.tabId;
|
||||
const tabBtn = document.getElementById(`${activeTabId}-tab`);
|
||||
if (tabBtn) {
|
||||
openTab({ currentTarget: tabBtn }, activeTabId);
|
||||
openTab({ currentTarget: tabBtn }, activeTabId, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,6 +290,9 @@ function fillTab(tabId, tabData) {
|
||||
case 'toolkits':
|
||||
renderToolkitsTab(tabId, tabData.toolkits, tabData.categories);
|
||||
break;
|
||||
case 'orders':
|
||||
renderOrdersTab(tabId, tabData);
|
||||
break;
|
||||
case 'jurnal_toolkits':
|
||||
renderJurnalToolkitsTab(tabId, tabData);
|
||||
break;
|
||||
@@ -5986,6 +5999,578 @@ function renderRequestsTab(tabId, tabData) {
|
||||
renderRequestsTable();
|
||||
}
|
||||
|
||||
function renderOrdersTab(tabId, tabData) {
|
||||
|
||||
const tabContent = document.getElementById(`${tabId}-tab-content`);
|
||||
const tabOptionalContent = document.getElementById(`${tabId}-tab-optional-content`);
|
||||
|
||||
const { orders, users, startDate, endDate, fullAccess } = tabData;
|
||||
|
||||
// Создаем мапу пользователей
|
||||
const userMap = {};
|
||||
users.forEach(user => {
|
||||
userMap[user.id] = user.username;
|
||||
});
|
||||
|
||||
// const ordersStatuses = {
|
||||
|
||||
// }
|
||||
|
||||
// Сохраненные фильтры
|
||||
const savedFilters = loadFromStorage(tabId);
|
||||
let currentFilters = {
|
||||
customer: savedFilters?.customer || 'all',
|
||||
status: savedFilters?.status || 'all',
|
||||
search: savedFilters?.search || ''
|
||||
};
|
||||
|
||||
// Хранилище измененных данных
|
||||
const changedOrders = {};
|
||||
const statusesList = []
|
||||
const statusesMap = {
|
||||
'new': 'Новый',
|
||||
'working': 'В работе',
|
||||
'complete': 'Выполнен',
|
||||
'cancelled': 'Отменен',
|
||||
}
|
||||
|
||||
// Оригинальные данные заказов (для сравнения)
|
||||
const originalOrders = {};
|
||||
orders.forEach(o => {
|
||||
originalOrders[o.id] = {
|
||||
status: o.status,
|
||||
executor_comment: o.executor_comment || ''
|
||||
};
|
||||
if (!statusesList.includes(o.status)) {
|
||||
statusesList.push(o.status)
|
||||
}
|
||||
});
|
||||
|
||||
// Рендерим дополнительный контейнер с фильтрами и кнопками
|
||||
tabOptionalContent.innerHTML = `
|
||||
<div class="row align-items-center mb-1">
|
||||
<!-- Левая часть с фильтрами -->
|
||||
<div class="col-12 col-md-6 mb-2 mb-md-0">
|
||||
<div class="row align-items-center mb-2">
|
||||
<!-- Поиск -->
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">
|
||||
<i class="bi bi-search"></i>
|
||||
</span>
|
||||
<input type="text" class="form-control"
|
||||
id="${tabId}-search-filter"
|
||||
placeholder="Поиск по таблице..."
|
||||
value="${currentFilters.search}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Кнопка сброса -->
|
||||
<div class="col-12 col-md-3">
|
||||
<button class="btn btn-outline-secondary" id="${tabId}-filter-reset-btn">
|
||||
<i class="bi bi-x-circle me-1"></i>Сброс
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Фильтр по статусу -->
|
||||
<div class="row g-2">
|
||||
<div class="col-12 col-md-5">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">
|
||||
<i class="bi bi-list-check"></i>
|
||||
</span>
|
||||
<select class="form-select" id="${tabId}-status-filter">
|
||||
<option value="all">Все статусы</option>
|
||||
${statusesList.map(status => `<option value="${status}">${statusesMap[status] || status}</option>`).join('')}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
${!fullAccess ? `
|
||||
<div class="col-12 col-md-7">
|
||||
<button class="btn btn-primary" id="${tabId}-new-order-btn">
|
||||
<i class="bi bi-plus-circle me-1"></i>Оформить заказ
|
||||
</button>
|
||||
</div>
|
||||
` : `
|
||||
<div class="col-12 col-md-7">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">
|
||||
<i class="bi bi-person"></i>
|
||||
</span>
|
||||
<select class="form-select" id="${tabId}-customer-filter">
|
||||
<option value="all">Все заказчики</option>
|
||||
${[...new Set(orders.map(o => o.customer_id))].map(customerId => `
|
||||
<option value="${customerId}">${userMap[customerId] || `Пользователь ${customerId}`}</option>
|
||||
`).join('')}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
` }
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-2">
|
||||
<button class="btn btn-outline-primary" id="${tabId}-date-update-btn">
|
||||
Обновить список заказов
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Правая часть с датами и кнопками -->
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="d-flex flex-wrap gap-2 justify-content-md-end">
|
||||
<div class="input-group date">
|
||||
<span class="input-group-text" style="width: 170px;">
|
||||
<i class="bi bi-calendar me-1"></i>Дата начала:
|
||||
</span>
|
||||
<input type="date" class="form-control" id="${tabId}-date-from">
|
||||
</div>
|
||||
<div class="input-group date">
|
||||
<span class="input-group-text" style="width: 170px;">
|
||||
<i class="bi bi-calendar me-1"></i>Дата окончания:
|
||||
</span>
|
||||
<input type="date" class="form-control" id="${tabId}-date-to">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
`;
|
||||
|
||||
// Модальное окно для нового заказа
|
||||
if (!fullAccess) {
|
||||
document.body.insertAdjacentHTML('beforeend', `
|
||||
<div class="modal fade" id="${tabId}-new-order-modal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Оформление нового заказа</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label for="${tabId}-order-description" class="form-label">Описание заказа</label>
|
||||
<textarea class="form-control" id="${tabId}-order-description"
|
||||
rows="4" placeholder="Опишите, что вам нужно..."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
|
||||
<button type="button" class="btn btn-primary" id="${tabId}-order-submit-btn">Заказать</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Инициализация фильтров
|
||||
if (fullAccess) {
|
||||
document.getElementById(`${tabId}-customer-filter`).value = currentFilters.customer;
|
||||
}
|
||||
document.getElementById(`${tabId}-status-filter`).value = currentFilters.status;
|
||||
document.getElementById(`${tabId}-search-filter`).value = currentFilters.search;
|
||||
|
||||
// Обработчики событий
|
||||
const filterResetBtn = document.getElementById(`${tabId}-filter-reset-btn`);
|
||||
filterResetBtn.addEventListener('click', () => {
|
||||
currentFilters = {
|
||||
customer: 'all',
|
||||
status: 'all',
|
||||
search: ''
|
||||
};
|
||||
if (fullAccess) {
|
||||
document.getElementById(`${tabId}-customer-filter`).value = currentFilters.customer;
|
||||
}
|
||||
document.getElementById(`${tabId}-status-filter`).value = currentFilters.status;
|
||||
document.getElementById(`${tabId}-search-filter`).value = currentFilters.search;
|
||||
saveToStorage(tabId, currentFilters);
|
||||
renderOrdersTable();
|
||||
});
|
||||
|
||||
// Дата фильтры
|
||||
const startDateInput = document.getElementById(`${tabId}-date-from`);
|
||||
const endDateInput = document.getElementById(`${tabId}-date-to`);
|
||||
startDateInput.value = startDate;
|
||||
endDateInput.value = endDate;
|
||||
|
||||
const refreshDateBtn = document.getElementById(`${tabId}-date-update-btn`);
|
||||
refreshDateBtn.addEventListener('click', async () => {
|
||||
const newStartDate = startDateInput.value;
|
||||
const newEndDate = endDateInput.value;
|
||||
if (newStartDate && newEndDate) {
|
||||
tabContent.innerHTML = `
|
||||
<div class="alert alert-info m-4" role="alert">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
Загрузка данных...
|
||||
</div>
|
||||
`;
|
||||
|
||||
const cookiesData = { userData, accessData };
|
||||
const newPeriodData = await apiRequest('/', {
|
||||
tabId: tabId,
|
||||
startDate: newStartDate,
|
||||
endDate: newEndDate,
|
||||
cookiesData
|
||||
});
|
||||
if (newPeriodData.status === 'ok') {
|
||||
renderOrdersTab(tabId, {
|
||||
...tabData,
|
||||
...newPeriodData.data,
|
||||
startDate: newStartDate,
|
||||
endDate: newEndDate,
|
||||
fullAccess
|
||||
});
|
||||
await checkNewOrders();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Кнопка нового заказа
|
||||
if (!fullAccess) {
|
||||
const newOrderBtn = document.getElementById(`${tabId}-new-order-btn`);
|
||||
newOrderBtn.addEventListener('click', () => {
|
||||
const modal = new bootstrap.Modal(document.getElementById(`${tabId}-new-order-modal`));
|
||||
modal.show();
|
||||
});
|
||||
|
||||
// Отправка нового заказа
|
||||
const orderSubmitBtn = document.getElementById(`${tabId}-order-submit-btn`);
|
||||
orderSubmitBtn.onclick = async () => {
|
||||
if (orderSubmitBtn.disabled) return;
|
||||
|
||||
orderSubmitBtn.disabled = true;
|
||||
|
||||
const description = document.getElementById(`${tabId}-order-description`).value;
|
||||
if (!description.trim()) {
|
||||
showInfo('Пожалуйста, введите описание заказа', 'warning');
|
||||
orderSubmitBtn.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await apiRequest('/orders/new', {
|
||||
userId: userData.id,
|
||||
customer_comment: description
|
||||
});
|
||||
|
||||
if (result.status === 'ok') {
|
||||
const modal = bootstrap.Modal.getInstance(
|
||||
document.getElementById(`${tabId}-new-order-modal`)
|
||||
);
|
||||
modal.hide();
|
||||
document.getElementById(`${tabId}-order-description`).value = '';
|
||||
refreshDateBtn.click();
|
||||
} else {
|
||||
showInfo(result.message || 'Ошибка при создании заказа', 'danger');
|
||||
}
|
||||
} finally {
|
||||
orderSubmitBtn.disabled = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
if (orders.length === 0) {
|
||||
tabContent.innerHTML = `
|
||||
<div class="alert alert-info m-4" role="alert">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
Нет заказов за период ${startDate} - ${endDate}
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
// Рендерим таблицу
|
||||
tabContent.innerHTML = `
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0" id="${tabId}-orders-table">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th width="150">Заказчик</th>
|
||||
<th>Описание заказа</th>
|
||||
<th width="120">Статус</th>
|
||||
<th width="150">Исполнитель</th>
|
||||
<th>Комментарий исполнителя</th>
|
||||
${fullAccess ? '<th width="30">⚙️</th>' : ''}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="${tabId}-orders-body">
|
||||
<!-- Заказы будут вставлены здесь -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="text-center p-3 border-top" id="${tabId}-no-orders" style="display: none;">
|
||||
<i class="bi bi-inbox fs-1 text-muted"></i>
|
||||
<p class="text-muted mt-2">Нет заказов по выбранным фильтрам</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Функция фильтрации
|
||||
function filterOrders() {
|
||||
let filtered = orders;
|
||||
|
||||
// Фильтр по заказчику
|
||||
if (fullAccess && currentFilters.customer !== 'all') {
|
||||
filtered = filtered.filter(o => o.customer_id == currentFilters.customer);
|
||||
}
|
||||
|
||||
// Фильтр по статусу
|
||||
if (currentFilters.status !== 'all') {
|
||||
filtered = filtered.filter(o => o.status === currentFilters.status);
|
||||
}
|
||||
|
||||
// Поиск
|
||||
if (currentFilters.search.trim()) {
|
||||
const searchTerm = currentFilters.search.toLowerCase();
|
||||
filtered = filtered.filter(o => {
|
||||
return (
|
||||
(userMap[o.customer_id] || '').toLowerCase().includes(searchTerm) ||
|
||||
o.customer_comment.toLowerCase().includes(searchTerm) ||
|
||||
(userMap[o.executor_id] || '').toLowerCase().includes(searchTerm) ||
|
||||
(o.executor_comment || '').toLowerCase().includes(searchTerm) ||
|
||||
o.status.toLowerCase().includes(searchTerm)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
// Функция рендеринга таблицы
|
||||
function renderOrdersTable() {
|
||||
const tbody = document.getElementById(`${tabId}-orders-body`);
|
||||
const noOrdersDiv = document.getElementById(`${tabId}-no-orders`);
|
||||
const filteredOrders = filterOrders();
|
||||
|
||||
if (filteredOrders.length === 0) {
|
||||
tbody.innerHTML = '';
|
||||
noOrdersDiv.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
|
||||
noOrdersDiv.style.display = 'none';
|
||||
|
||||
tbody.innerHTML = filteredOrders.map(order => {
|
||||
// Определяем класс для статуса
|
||||
const statusClass = {
|
||||
new: 'warning',
|
||||
working: 'primary',
|
||||
complete: 'success',
|
||||
cancelled: 'danger'
|
||||
}[order.status] || 'secondary';
|
||||
|
||||
// Определяем русское название статуса
|
||||
const statusText = {
|
||||
new: 'Новый',
|
||||
working: 'В работе',
|
||||
complete: 'Выполнен',
|
||||
cancelled: 'Отменен'
|
||||
}[order.status] || order.status;
|
||||
|
||||
// Рендерим статус
|
||||
let statusCell;
|
||||
if (fullAccess && (order.status === 'new' || order.status === 'working')) {
|
||||
statusCell = `
|
||||
<select class="form-select form-select-sm order-status"
|
||||
data-order-id="${order.id}"
|
||||
style="min-width: 120px;">
|
||||
<option value="new" ${order.status === 'new' ? 'selected' : ''} disabled>Новый</option>
|
||||
<option value="working" ${order.status === 'working' ? 'selected' : ''}>В работе</option>
|
||||
<option value="complete" ${order.status === 'complete' ? 'selected' : ''}>Выполнен</option>
|
||||
<option value="cancelled" ${order.status === 'cancelled' ? 'selected' : ''}>Отменен</option>
|
||||
</select>
|
||||
`;
|
||||
} else {
|
||||
statusCell = `<span class="badge bg-${statusClass}">${statusText}</span>`;
|
||||
}
|
||||
|
||||
// Рендерим комментарий исполнителя
|
||||
let commentCell;
|
||||
if (fullAccess && (order.status === 'new' || order.status === 'working')) {
|
||||
commentCell = `
|
||||
<textarea class="form-control form-control-sm executor-comment"
|
||||
data-order-id="${order.id}"
|
||||
rows="2"
|
||||
placeholder="Введите комментарий...">${order.executor_comment || ''}</textarea>
|
||||
`;
|
||||
} else {
|
||||
commentCell = `<small class="text-muted">${order.executor_comment || 'Нет комментария'}</small>`;
|
||||
}
|
||||
|
||||
return `
|
||||
<tr data-order-id="${order.id}">
|
||||
<td class="align-middle">
|
||||
${userMap[order.customer_id] || `Пользователь ${order.customer_id}`}<br>
|
||||
<small class="text-muted">${order.created_at}</small>
|
||||
</td>
|
||||
<td class="align-middle"><small>${order.customer_comment}</small></td>
|
||||
<td class="align-middle">
|
||||
${statusCell}<br>
|
||||
<small class="text-muted">${order.updated_at}</small>
|
||||
</td>
|
||||
<td class="align-middle">${order.executor_id ? (userMap[order.executor_id] || `Пользователь ${order.executor_id}`) : '-'}</td>
|
||||
<td class="align-middle">${commentCell}</td>
|
||||
${fullAccess ? `
|
||||
<td class="align-middle text-center">
|
||||
${fullAccess && (order.status === 'new' || order.status === 'working') ? `
|
||||
<button class="btn btn-sm btn-success save-row-btn"
|
||||
data-order-id="${order.id}"
|
||||
disabled>
|
||||
<i class="bi bi-save"></i>
|
||||
</button>
|
||||
` : '☑️'}
|
||||
</td>
|
||||
`: ''}
|
||||
</tr>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
function updateRowState(orderId) {
|
||||
const original = originalOrders[orderId];
|
||||
const current = changedOrders[orderId];
|
||||
|
||||
const hasChanges =
|
||||
current &&
|
||||
(
|
||||
(current.status !== undefined && current.status !== original.status) ||
|
||||
(current.executor_comment !== undefined && current.executor_comment !== original.executor_comment)
|
||||
);
|
||||
|
||||
const saveBtn = document.querySelector(
|
||||
`.save-row-btn[data-order-id="${orderId}"]`
|
||||
);
|
||||
|
||||
if (saveBtn) {
|
||||
saveBtn.disabled = !hasChanges;
|
||||
}
|
||||
}
|
||||
|
||||
// Добавляем обработчики изменений
|
||||
if (fullAccess) {
|
||||
document.querySelectorAll(`.order-status`).forEach(select => {
|
||||
select.addEventListener('change', function () {
|
||||
const orderId = this.dataset.orderId;
|
||||
|
||||
changedOrders[orderId] = {
|
||||
...changedOrders[orderId],
|
||||
status: this.value
|
||||
};
|
||||
|
||||
updateRowState(orderId);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll(`.executor-comment`).forEach(textarea => {
|
||||
textarea.addEventListener('input', function () {
|
||||
const orderId = this.dataset.orderId;
|
||||
|
||||
changedOrders[orderId] = {
|
||||
...changedOrders[orderId],
|
||||
executor_comment: this.value
|
||||
};
|
||||
|
||||
updateRowState(orderId);
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('.save-row-btn').forEach(btn => {
|
||||
btn.addEventListener('click', async function () {
|
||||
const orderId = this.dataset.orderId;
|
||||
const original = originalOrders[orderId];
|
||||
const current = changedOrders[orderId];
|
||||
|
||||
if (!current) return;
|
||||
|
||||
// Формируем diff
|
||||
const payload = { orderId, userId: userData.id };
|
||||
|
||||
if (current.status !== undefined && current.status !== original.status) {
|
||||
payload.status = current.status;
|
||||
}
|
||||
|
||||
if (
|
||||
current.executor_comment !== undefined &&
|
||||
current.executor_comment !== original.executor_comment
|
||||
) {
|
||||
payload.comment = current.executor_comment;
|
||||
}
|
||||
|
||||
if (Object.keys(payload).length === 2) return;
|
||||
|
||||
this.disabled = true;
|
||||
|
||||
const result = await apiRequest('/orders/', payload);
|
||||
|
||||
if (result.status === 'ok') {
|
||||
// Обновляем оригинал
|
||||
originalOrders[orderId] = {
|
||||
status: payload.status ?? original.status,
|
||||
executor_comment: payload.comment ?? original.executor_comment
|
||||
};
|
||||
|
||||
delete changedOrders[orderId];
|
||||
|
||||
if (payload.status && original.status === 'new') {
|
||||
await checkNewOrders();
|
||||
}
|
||||
|
||||
this.innerHTML = '<i class="bi bi-check-circle"></i>';
|
||||
setTimeout(() => {
|
||||
this.innerHTML = '<i class="bi bi-save"></i>';
|
||||
}, 1500);
|
||||
|
||||
if (originalOrders[orderId].status === 'complete' || originalOrders[orderId].status === 'cancelled') {
|
||||
const foundOrder = orders.find(order => order.id === Number(orderId));
|
||||
if (foundOrder) {
|
||||
foundOrder.executor_id = userData.id;
|
||||
foundOrder.executor_comment = originalOrders[orderId].executor_comment;
|
||||
foundOrder.status = current.status;
|
||||
}
|
||||
renderOrdersTable();
|
||||
}
|
||||
} else {
|
||||
showInfo('Ошибка сохранения', 'danger');
|
||||
this.disabled = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Обработчики фильтров
|
||||
if (fullAccess) {
|
||||
document.getElementById(`${tabId}-customer-filter`).addEventListener('change', function () {
|
||||
currentFilters.customer = this.value;
|
||||
saveToStorage(tabId, currentFilters);
|
||||
renderOrdersTable();
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById(`${tabId}-status-filter`).addEventListener('change', function () {
|
||||
currentFilters.status = this.value;
|
||||
saveToStorage(tabId, currentFilters);
|
||||
renderOrdersTable();
|
||||
});
|
||||
|
||||
document.getElementById(`${tabId}-search-filter`).addEventListener('input', function () {
|
||||
currentFilters.search = this.value;
|
||||
saveToStorage(tabId, currentFilters);
|
||||
renderOrdersTable();
|
||||
});
|
||||
|
||||
// Первоначальный рендеринг
|
||||
renderOrdersTable();
|
||||
}
|
||||
|
||||
function renderJurnalToolkitsTab(tabId, tabData) {
|
||||
const tabContent = document.getElementById(`${tabId}-tab-content`);
|
||||
const tabOptionalContent = document.getElementById(`${tabId}-tab-optional-content`);
|
||||
@@ -7446,6 +8031,34 @@ function renderUsersTab(tabId, tabData) {
|
||||
renderUsersCards();
|
||||
}
|
||||
|
||||
async function checkNewOrders() {
|
||||
const result = await apiRequest('/orders/', {}, 'GET');
|
||||
|
||||
if (result && result.orders > 0) {
|
||||
const ordersTabBtn = document.getElementById('orders-tab');
|
||||
|
||||
// Удаляем старый бейдж, если есть
|
||||
const oldBadge = ordersTabBtn.querySelector('.orders-badge');
|
||||
if (oldBadge) oldBadge.remove();
|
||||
|
||||
const newOrdersBadge = document.createElement('span');
|
||||
newOrdersBadge.className =
|
||||
'badge rounded-pill bg-danger position-absolute orders-badge';
|
||||
newOrdersBadge.textContent = result.orders;
|
||||
|
||||
// Позиция: правый верх
|
||||
newOrdersBadge.style.top = '6px';
|
||||
newOrdersBadge.style.right = '8px';
|
||||
|
||||
ordersTabBtn.appendChild(newOrdersBadge);
|
||||
}
|
||||
if (result && result.orders == 0) {
|
||||
const ordersTabBtn = document.getElementById('orders-tab');
|
||||
const oldBadge = ordersTabBtn.querySelector('.orders-badge');
|
||||
if (oldBadge) oldBadge.remove();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
await getCookieData();
|
||||
|
||||
@@ -7456,6 +8069,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
}
|
||||
|
||||
prepareTabs();
|
||||
await checkNewOrders();
|
||||
});
|
||||
|
||||
window.openTab = openTab;
|
||||
Reference in New Issue
Block a user