Fix vendor mapping delete behavior and update docs
This commit is contained in:
@@ -11,12 +11,17 @@
|
||||
</a>
|
||||
<h1 id="page-title" class="text-2xl font-bold text-gray-900">Загрузка...</h1>
|
||||
</div>
|
||||
<button onclick="exportToCSV()" class="px-4 py-2 bg-orange-600 text-white rounded-md hover:bg-orange-700 flex items-center space-x-2">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<span>Экспорт в CSV</span>
|
||||
</button>
|
||||
<div class="flex items-center gap-2">
|
||||
<button onclick="openPriceChangesReport()" class="px-4 py-2 border border-gray-300 text-gray-700 rounded-md hover:bg-gray-50">
|
||||
Отчет по изменениям
|
||||
</button>
|
||||
<button onclick="exportToCSV()" class="px-4 py-2 bg-orange-600 text-white rounded-md hover:bg-orange-700 flex items-center space-x-2">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
<span>Экспорт в CSV</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="pricelist-info" class="bg-white rounded-lg shadow p-6">
|
||||
@@ -85,6 +90,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="price-changes-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
|
||||
<div class="bg-white rounded-lg p-6 max-w-4xl w-full mx-4 max-h-[85vh] overflow-hidden flex flex-col">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="text-xl font-bold">Отчет по изменениям цен</h2>
|
||||
<button type="button" onclick="closePriceChangesModal()" class="text-gray-500 hover:text-gray-700">Закрыть</button>
|
||||
</div>
|
||||
<div id="price-changes-summary" class="text-sm text-gray-600 mb-4"></div>
|
||||
<div id="price-changes-content" class="overflow-auto space-y-4"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const pricelistId = window.location.pathname.split('/').pop();
|
||||
let currentPage = 1;
|
||||
@@ -187,6 +203,87 @@
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function closePriceChangesModal() {
|
||||
document.getElementById('price-changes-modal').classList.add('hidden');
|
||||
document.getElementById('price-changes-modal').classList.remove('flex');
|
||||
}
|
||||
|
||||
function formatReportPrice(value) {
|
||||
if (value === null || value === undefined || Number.isNaN(Number(value))) return '-';
|
||||
return Number(value).toLocaleString('ru-RU', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||
}
|
||||
|
||||
function renderPriceChangesTable(items, showDiff = true) {
|
||||
if (!Array.isArray(items) || items.length === 0) return '<div class="text-sm text-gray-500">Нет данных</div>';
|
||||
const rows = items.map(item => {
|
||||
const t = item.change_type || '';
|
||||
const rowClass = t === 'increased' ? 'bg-red-50' : (t === 'decreased' ? 'bg-green-50' : '');
|
||||
const diffValue = Number(item.diff || 0);
|
||||
const diffClass = diffValue > 0 ? 'text-red-700' : (diffValue < 0 ? 'text-green-700' : 'text-gray-700');
|
||||
const diffText = (showDiff && item.diff != null) ? `${diffValue > 0 ? '+' : ''}${formatReportPrice(diffValue)}` : '-';
|
||||
return `
|
||||
<tr class="${rowClass}">
|
||||
<td class="px-3 py-2 font-mono text-xs">${escapeHtml(item.lot_name || '')}</td>
|
||||
<td class="px-3 py-2 text-right">${formatReportPrice(item.old_price)}</td>
|
||||
<td class="px-3 py-2 text-right">${item.new_price == null ? '-' : formatReportPrice(item.new_price)}</td>
|
||||
<td class="px-3 py-2 text-right ${diffClass}">${diffText}</td>
|
||||
</tr>
|
||||
`;
|
||||
}).join('');
|
||||
return `
|
||||
<div class="border rounded-lg overflow-hidden">
|
||||
<table class="min-w-full text-sm">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-3 py-2 text-left">Позиция</th>
|
||||
<th class="px-3 py-2 text-right">Было</th>
|
||||
<th class="px-3 py-2 text-right">Стало</th>
|
||||
<th class="px-3 py-2 text-right">Изм.</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>${rows}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
async function openPriceChangesReport() {
|
||||
try {
|
||||
const summary = document.getElementById('price-changes-summary');
|
||||
const content = document.getElementById('price-changes-content');
|
||||
summary.textContent = 'Загрузка отчета...';
|
||||
content.innerHTML = '';
|
||||
document.getElementById('price-changes-modal').classList.remove('hidden');
|
||||
document.getElementById('price-changes-modal').classList.add('flex');
|
||||
|
||||
const resp = await fetch(`/api/pricelists/${pricelistId}/price-changes`);
|
||||
if (!resp.ok) throw new Error('Не удалось загрузить отчет');
|
||||
const changes = await resp.json();
|
||||
|
||||
const changed = Array.isArray(changes.changed) ? changes.changed : [];
|
||||
const missing = Array.isArray(changes.missing) ? changes.missing : [];
|
||||
const prevVersion = changes.previous_pricelist_version || null;
|
||||
|
||||
summary.innerHTML = prevVersion
|
||||
? `Сравнение с прайслистом <span class="font-mono">${escapeHtml(prevVersion)}</span>. Изменилось: <b>${changed.length}</b>, пропало (нет котировок): <b>${missing.length}</b>.`
|
||||
: 'Предыдущий прайслист для сравнения не найден.';
|
||||
|
||||
content.innerHTML = `
|
||||
<div>
|
||||
<h3 class="font-semibold mb-2">Изменившиеся цены</h3>
|
||||
${renderPriceChangesTable(changed, true)}
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="font-semibold mb-2">Пропали котировки (цена была раньше)</h3>
|
||||
${renderPriceChangesTable(missing, false)}
|
||||
</div>
|
||||
`;
|
||||
} catch (e) {
|
||||
showToast('Ошибка: ' + e.message, 'error');
|
||||
closePriceChangesModal();
|
||||
}
|
||||
}
|
||||
|
||||
function formatPriceSettings(item) {
|
||||
// Format price settings to match admin pricing interface style
|
||||
let settings = [];
|
||||
|
||||
Reference in New Issue
Block a user