<?php
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
CModule::IncludeModule("iblock");
// Подключение к базе данных
global $DB;
// Обработка AJAX запросов
if ($_POST['action'] == 'get_sections_count') {
$iblocks = $_POST['iblocks'];
$level = intval($_POST['level']);
$totalSections = 0;
foreach ($iblocks as $iblockId) {
$filter = array(
'IBLOCK_ID' => $iblockId,
'DEPTH_LEVEL' => $level,
'ACTIVE' => 'Y'
);
$sections = CIBlockSection::GetList(array(), $filter, false, array('ID'));
while ($section = $sections->Fetch()) {
$totalSections++;
}
}
echo json_encode(array('total' => $totalSections));
die();
}
if ($_POST['action'] == 'check_properties') {
$iblocks = $_POST['iblocks'];
$result = array();
foreach ($iblocks as $iblockId) {
$iblock = CIBlock::GetByID($iblockId)->Fetch();
// Проверяем существование таблицы и полей напрямую в БД
$tableName = 'b_uts_iblock_' . $iblockId . '_section';
// Проверяем существование таблицы
$tableExists = false;
$hasUpProperty = false;
$hasDownProperty = false;
$checkTableQuery = "SHOW TABLES LIKE '" . $tableName . "'";
$tableResult = $DB->Query($checkTableQuery);
if ($tableResult->Fetch()) {
$tableExists = true;
// Проверяем существование полей
$checkColumnsQuery = "SHOW COLUMNS FROM `" . $tableName . "`";
$columnsResult = $DB->Query($checkColumnsQuery);
while ($column = $columnsResult->Fetch()) {
if ($column['Field'] == 'UF_UP_IMAGES_BLOCK') {
$hasUpProperty = true;
}
if ($column['Field'] == 'UF_DOWN_IMAGES_BLOCK') {
$hasDownProperty = true;
}
}
}
$result[] = array(
'id' => $iblockId,
'name' => $iblock['NAME'],
'table_exists' => $tableExists,
'table_name' => $tableName,
'has_up_property' => $hasUpProperty,
'has_down_property' => $hasDownProperty
);
}
echo json_encode($result);
die();
}
if ($_POST['action'] == 'process_sections') {
$iblocks = $_POST['iblocks'];
$level = intval($_POST['level']);
$step = intval($_POST['step']);
$offset = intval($_POST['offset']);
$upProperties = $_POST['up_properties'];
$downProperties = $_POST['down_properties'];
$overwriteUp = $_POST['overwrite_up'] == '1';
$overwriteDown = $_POST['overwrite_down'] == '1';
$processed = 0;
$currentSection = '';
$currentIblock = '';
$currentOffset = intval($_POST['offset']);
$globalOffset = 0;
foreach ($iblocks as $iblockId) {
$iblock = CIBlock::GetByID($iblockId)->Fetch();
$currentIblock = $iblock['NAME'] . " (ID: $iblockId)";
$tableName = 'b_uts_iblock_' . $iblockId . '_section';
// Проверяем существование таблицы
$checkTableQuery = "SHOW TABLES LIKE '" . $tableName . "'";
$tableResult = $DB->Query($checkTableQuery);
if (!$tableResult->Fetch()) {
continue; // Пропускаем если таблицы нет
}
$filter = array(
'IBLOCK_ID' => $iblockId,
'DEPTH_LEVEL' => $level,
'ACTIVE' => 'Y'
);
$sections = CIBlockSection::GetList(array('ID' => 'ASC'), $filter, false, array('ID', 'NAME'));
$sectionCount = 0;
while ($section = $sections->Fetch()) {
if ($globalOffset < $currentOffset) {
$globalOffset++;
continue;
}
if ($processed >= $step) {
break 2;
}
$sectionId = $section['ID'];
$currentSection = $section['NAME'] . " (ID: {$sectionId})";
// Получаем данные из таблицы пользовательских свойств
$selectQuery = "SELECT * FROM `" . $tableName . "` WHERE VALUE_ID = " . intval($sectionId);
$sectResult = $DB->Query($selectQuery);
$sectData = $sectResult->Fetch();
if (!$sectData) {
// Если записи нет, создаем её
$insertQuery = "INSERT INTO `" . $tableName . "` (VALUE_ID) VALUES (" . intval($sectionId) . ")";
$DB->Query($insertQuery);
$sectData = array('VALUE_ID' => $sectionId);
}
$updateFields = array();
// Обработка UF_UP_IMAGES_BLOCK
if (!empty($upProperties) && ($overwriteUp || empty($sectData['UF_UP_IMAGES_BLOCK']))) {
$upContent = '';
foreach ($upProperties as $prop) {
if (!empty($sectData[$prop])) {
$upContent .= $sectData[$prop];
}
}
if (!empty($upContent) || $overwriteUp) {
$updateFields['UF_UP_IMAGES_BLOCK'] = "'" . $DB->ForSql($upContent) . "'";
}
}
// Обработка UF_DOWN_IMAGES_BLOCK
if (!empty($downProperties) && ($overwriteDown || empty($sectData['UF_DOWN_IMAGES_BLOCK']))) {
$downContent = '';
foreach ($downProperties as $prop) {
if (!empty($sectData[$prop])) {
$downContent .= $sectData[$prop];
}
}
if (!empty($downContent) || $overwriteDown) {
$updateFields['UF_DOWN_IMAGES_BLOCK'] = "'" . $DB->ForSql($downContent) . "'";
}
}
// Обновляем данные в БД
if (!empty($updateFields)) {
$updateParts = array();
foreach ($updateFields as $field => $value) {
$updateParts[] = "`" . $field . "` = " . $value;
}
$updateQuery = "UPDATE `" . $tableName . "` SET " . implode(', ', $updateParts) . " WHERE VALUE_ID = " . intval($sectionId);
$DB->Query($updateQuery);
}
$processed++;
$globalOffset++;
}
if ($processed >= $step) {
break;
}
}
echo json_encode(array(
'processed' => $processed,
'current_section' => $currentSection,
'current_iblock' => $currentIblock,
'new_offset' => $currentOffset + $processed
));
die();
}
// Получение списка инфоблоков
$iblocks = array();
$res = CIBlock::GetList(array('SORT' => 'ASC', 'NAME' => 'ASC'), array('ACTIVE' => 'Y'));
while ($iblock = $res->Fetch()) {
$iblocks[] = $iblock;
}
// Свойства BLOCKCODE
$blockCodeProperties = array(
'UF_IMAGE1_BLOCKCODE' => 'IMAGE1_BLOCKCODE',
'UF_IMAGE2_BLOCKCODE' => 'IMAGE2_BLOCKCODE',
'UF_IMAGE3_BLOCKCODE' => 'IMAGE3_BLOCKCODE',
'UF_IMAGE4_BLOCKCODE' => 'IMAGE4_BLOCKCODE',
'UF_IMAGE5_BLOCKCODE' => 'IMAGE5_BLOCKCODE',
'UF_IMAGE6_BLOCKCODE' => 'IMAGE6_BLOCKCODE',
'UF_IMAGE7_BLOCKCODE' => 'IMAGE7_BLOCKCODE'
);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Формирование блоков картинок для разделов</title>
<style>
body {
font-family: arial, sans-serif;
margin: 20px;
background-color: #f9f9f9;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1 {
color: #1a73e8;
margin-bottom: 30px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="text"], input[type="number"], select {
width: 100%;
padding: 8px 12px;
border: 1px solid #dadce0;
border-radius: 4px;
font-size: 14px;
box-sizing: border-box;
}
input[type="text"]:focus, input[type="number"]:focus, select:focus {
outline: none;
border-color: #1a73e8;
box-shadow: 0 0 0 2px rgba(26,115,232,0.2);
}
.multi-select {
width: 100%;
height: 150px;
padding: 8px;
border: 1px solid #dadce0;
border-radius: 4px;
font-size: 14px;
box-sizing: border-box;
resize: vertical;
}
.multi-select:focus {
outline: none;
border-color: #1a73e8;
box-shadow: 0 0 0 2px rgba(26,115,232,0.2);
}
.multi-select option {
padding: 5px;
}
.checkbox-group {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 5px;
}
.checkbox-item {
display: flex;
align-items: center;
gap: 5px;
}
.section-block {
border: 1px solid #e0e0e0;
border-radius: 4px;
padding: 15px;
margin: 15px 0;
background-color: #fafafa;
}
.section-title {
font-weight: bold;
color: #333;
margin-bottom: 15px;
}
.btn {
background-color: #1a73e8;
color: white;
border: none;
padding: 10px 24px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
margin-right: 10px;
}
.btn:hover {
background-color: #1557b0;
}
.btn:disabled {
background-color: #ccc;
cursor: not-allowed;
}
.btn-secondary {
background-color: #5f6368;
}
.btn-secondary:hover {
background-color: #3c4043;
}
.progress-container {
display: none;
margin-top: 20px;
padding: 20px;
border: 1px solid #e0e0e0;
border-radius: 4px;
background-color: #f8f9fa;
}
.progress-bar {
width: 100%;
height: 20px;
background-color: #e0e0e0;
border-radius: 10px;
overflow: hidden;
margin: 10px 0;
}
.progress-fill {
height: 100%;
background-color: #1a73e8;
transition: width 0.3s;
width: 0%;
}
.status-info {
margin: 10px 0;
font-size: 14px;
}
.hidden {
display: none;
}
.search-box {
margin-bottom: 10px;
}
.help-text {
font-size: 12px;
color: #666;
margin-top: 5px;
}
.error-message {
color: #d93025;
font-size: 12px;
margin-top: 5px;
display: none;
}
.warning-message {
color: #f57c00;
font-size: 12px;
margin-top: 5px;
display: none;
}
.property-status {
margin: 5px 0;
padding: 8px;
border-radius: 4px;
font-size: 12px;
}
.property-ok {
background-color: #e8f5e8;
color: #137333;
border: 1px solid #d4edda;
}
.property-missing {
background-color: #fce8e6;
color: #d93025;
border: 1px solid #f5c6cb;
}
.property-warning {
background-color: #fff3cd;
color: #856404;
border: 1px solid #ffeaa7;
}
.table-info {
font-family: monospace;
font-size: 11px;
color: #666;
}
</style>
</head>
<body>
<div class="container">
<h1>Формирование блоков картинок для разделов</h1>
<form id="mainForm">
<!-- Выбор инфоблоков -->
<div class="form-group">
<label for="iblocks">Выберите инфоблоки:</label>
<input type="text" id="iblockSearch" placeholder="Поиск по инфоблокам..." class="search-box">
<select id="iblocks" name="iblocks" class="multi-select" multiple>
<?php foreach ($iblocks as $iblock): ?>
<option value="<?php echo $iblock['ID']; ?>" data-name="<?php echo strtolower($iblock['NAME']); ?>">
<?php echo htmlspecialchars($iblock['NAME']); ?> (ID: <?php echo $iblock['ID']; ?>)
</option>
<?php endforeach; ?>
</select>
<div class="help-text">Используйте Ctrl+Click для множественного выбора</div>
<div id="iblockError" class="error-message">Выберите хотя бы один инфоблок</div>
<div id="propertyStatus"></div>
</div>
<!-- Уровень вложенности -->
<div class="form-group">
<label for="level">Уровень вложенности разделов:</label>
<input type="number" id="level" name="level" value="3" min="1">
</div>
<!-- Блок UP_IMAGES_BLOCK -->
<div class="section-block">
<div class="section-title">Заполнение свойства раздела UF_UP_IMAGES_BLOCK</div>
<div class="form-group">
<div class="checkbox-item">
<input type="checkbox" id="overwrite_up" name="overwrite_up">
<label for="overwrite_up">Перезаписывать значения свойства, если заполнены</label>
</div>
</div>
<div class="form-group">
<label for="up_properties">Выберите свойства BLOCKCODE:</label>
<select id="up_properties" name="up_properties" class="multi-select" multiple>
<?php foreach ($blockCodeProperties as $code => $name): ?>
<option value="<?php echo $code; ?>"><?php echo $name; ?></option>
<?php endforeach; ?>
</select>
<div class="help-text">Используйте Ctrl+Click для множественного выбора</div>
</div>
</div>
<!-- Блок DOWN_IMAGES_BLOCK -->
<div class="section-block">
<div class="section-title">Заполнение свойства раздела UF_DOWN_IMAGES_BLOCK</div>
<div class="form-group">
<div class="checkbox-item">
<input type="checkbox" id="overwrite_down" name="overwrite_down">
<label for="overwrite_down">Перезаписывать значения свойства, если заполнены</label>
</div>
</div>
<div class="form-group">
<label for="down_properties">Выберите свойства BLOCKCODE:</label>
<select id="down_properties" name="down_properties" class="multi-select" multiple>
<?php foreach ($blockCodeProperties as $code => $name): ?>
<option value="<?php echo $code; ?>"><?php echo $name; ?></option>
<?php endforeach; ?>
</select>
<div class="help-text">Используйте Ctrl+Click для множественного выбора</div>
<div id="propertiesError" class="error-message">Выберите хотя бы одно свойство для обработки</div>
</div>
</div>
<!-- Общие параметры -->
<div class="form-group">
<label for="step">Обрабатывать X разделов за шаг:</label>
<input type="number" id="step" name="step" value="10" min="1">
</div>
<button type="button" class="btn" onclick="startProcessing()">Запустить обработку</button>
</form>
<!-- Прогресс обработки -->
<div id="progressContainer" class="progress-container">
<div class="status-info">
<div><strong>Текущий инфоблок:</strong> <span id="currentIblock">-</span></div>
<div><strong>Текущий раздел:</strong> <span id="currentSection">-</span></div>
<div><strong>Прогресс:</strong> <span id="progressText">0 / 0</span></div>
</div>
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<div>
<button type="button" class="btn btn-secondary" id="pauseBtn" onclick="pauseProcessing()">Приостановить</button>
<button type="button" class="btn" id="resumeBtn" onclick="resumeProcessing()" style="display: none;">Продолжить</button>
<button type="button" class="btn btn-secondary" onclick="stopProcessing()">Остановить</button>
</div>
</div>
</div>
<script>
// Поиск по инфоблокам
document.getElementById('iblockSearch').addEventListener('input', function() {
const searchTerm = this.value.toLowerCase();
const options = document.querySelectorAll('#iblocks option');
options.forEach(function(option) {
const name = option.dataset.name;
if (name.includes(searchTerm)) {
option.style.display = 'block';
} else {
option.style.display = 'none';
}
});
});
// Проверка свойств при изменении выбора инфоблоков
document.getElementById('iblocks').addEventListener('change', function() {
const selectedIblocks = Array.from(this.selectedOptions).map(option => option.value);
hideErrors();
if (selectedIblocks.length > 0) {
checkProperties(selectedIblocks);
} else {
document.getElementById('propertyStatus').innerHTML = '';
}
});
function checkProperties(iblocks) {
fetch(window.location.href, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'action=check_properties&' +
'iblocks[]=' + iblocks.join('&iblocks[]=')
})
.then(response => response.json())
.then(data => {
let statusHtml = '<div style="margin-top: 15px;"><strong>Статус свойств и таблиц БД:</strong></div>';
data.forEach(function(iblock) {
let statusClass = 'property-ok';
let status = '';
if (!iblock.table_exists) {
statusClass = 'property-missing';
status = '✗ Таблица отсутствует';
} else if (!iblock.has_up_property && !iblock.has_down_property) {
statusClass = 'property-missing';
status = '✗ Свойства отсутствуют';
} else if (!iblock.has_up_property || !iblock.has_down_property) {
statusClass = 'property-warning';
status = '⚠ Не все свойства найдены';
} else {
status = '✓ Все свойства найдены';
}
statusHtml += '<div class="property-status ' + statusClass + '">';
statusHtml += '<div><strong>' + iblock.name + ' (ID: ' + iblock.id + ')</strong></div>';
statusHtml += '<div>Таблица: <span class="table-info">' + iblock.table_name + '</span></div>';
statusHtml += '<div>UP_IMAGES_BLOCK: ' + (iblock.has_up_property ? '✓' : '✗') + '</div>';
statusHtml += '<div>DOWN_IMAGES_BLOCK: ' + (iblock.has_down_property ? '✓' : '✗') + '</div>';
statusHtml += '<div><strong>' + status + '</strong></div>';
statusHtml += '</div>';
});
document.getElementById('propertyStatus').innerHTML = statusHtml;
})
.catch(error => {
console.error('Error:', error);
document.getElementById('propertyStatus').innerHTML = '<div class="property-status property-missing">Ошибка при проверке свойств</div>';
});
}
function hideErrors() {
document.getElementById('iblockError').style.display = 'none';
document.getElementById('propertiesError').style.display = 'none';
}
let isProcessing = false;
let isPaused = false;
let totalSections = 0;
let processedSections = 0;
let currentOffset = 0;
function startProcessing() {
hideErrors();
// Получаем данные формы
const selectedIblocks = Array.from(document.getElementById('iblocks').selectedOptions).map(option => option.value);
const upProperties = Array.from(document.getElementById('up_properties').selectedOptions).map(option => option.value);
const downProperties = Array.from(document.getElementById('down_properties').selectedOptions).map(option => option.value);
// Валидация
let hasErrors = false;
if (selectedIblocks.length === 0) {
document.getElementById('iblockError').style.display = 'block';
hasErrors = true;
}
if (upProperties.length === 0 && downProperties.length === 0) {
document.getElementById('propertiesError').style.display = 'block';
hasErrors = true;
}
if (hasErrors) {
return;
}
isProcessing = true;
isPaused = false;
processedSections = 0;
currentOffset = 0;
document.getElementById('progressContainer').style.display = 'block';
document.querySelector('.btn').disabled = true;
// Получаем общее количество разделов
getSectionsCount(selectedIblocks, document.getElementById('level').value);
}
function getSectionsCount(iblocks, level) {
fetch(window.location.href, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'action=get_sections_count&' +
'iblocks[]=' + iblocks.join('&iblocks[]=') +
'&level=' + level
})
.then(response => response.json())
.then(data => {
totalSections = data.total;
updateProgress();
processSections();
})
.catch(error => {
console.error('Error:', error);
alert('Ошибка при получении количества разделов');
stopProcessing();
});
}
function processSections() {
if (!isProcessing || isPaused) {
return;
}
const form = document.getElementById('mainForm');
const formData = new FormData(form);
formData.append('action', 'process_sections');
formData.append('offset', currentOffset);
// Добавляем выбранные инфоблоки
const selectedIblocks = Array.from(document.getElementById('iblocks').selectedOptions).map(option => option.value);
selectedIblocks.forEach(iblock => formData.append('iblocks[]', iblock));
// Добавляем выбранные свойства
const upProperties = Array.from(document.getElementById('up_properties').selectedOptions).map(option => option.value);
const downProperties = Array.from(document.getElementById('down_properties').selectedOptions).map(option => option.value);
upProperties.forEach(prop => formData.append('up_properties[]', prop));
downProperties.forEach(prop => formData.append('down_properties[]', prop));
fetch(window.location.href, {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
processedSections += data.processed;
currentOffset = data.new_offset;
document.getElementById('currentIblock').textContent = data.current_iblock || '-';
document.getElementById('currentSection').textContent = data.current_section || '-';
updateProgress();
if (processedSections < totalSections && data.processed > 0) {
setTimeout(processSections, 100); // Небольшая пауза между запросами
} else {
completeProcessing();
}
})
.catch(error => {
console.error('Error:', error);
alert('Ошибка при обработке разделов');
stopProcessing();
});
}
function updateProgress() {
const percentage = totalSections > 0 ? Math.round((processedSections / totalSections) * 100) : 0;
document.getElementById('progressFill').style.width = percentage + '%';
document.getElementById('progressText').textContent = processedSections + ' / ' + totalSections;
}
function pauseProcessing() {
isPaused = true;
document.getElementById('pauseBtn').style.display = 'none';
document.getElementById('resumeBtn').style.display = 'inline-block';
}
function resumeProcessing() {
isPaused = false;
document.getElementById('pauseBtn').style.display = 'inline-block';
document.getElementById('resumeBtn').style.display = 'none';
processSections();
}
function stopProcessing() {
isProcessing = false;
isPaused = false;
document.querySelector('.btn').disabled = false;
document.getElementById('progressContainer').style.display = 'none';
document.getElementById('pauseBtn').style.display = 'inline-block';
document.getElementById('resumeBtn').style.display = 'none';
}
function completeProcessing() {
isProcessing = false;
document.querySelector('.btn').disabled = false;
document.getElementById('pauseBtn').style.display = 'none';
document.getElementById('resumeBtn').style.display = 'none';
alert('Обработка завершена! Обработано разделов: ' + processedSections);
}
</script>
</body>
</html>