Отлично! Давайте всё исправим. Вот финальный код:
## 1. ИСПРАВЛЯЕМ ОТОБРАЖЕНИЕ КОНСТРУКЦИИ (все диаметры, штриховка, крупный шрифт):
```javascript
function drawWellConstruction(data, scale = 40) {
const graphicsScrollContainer = document.getElementById('graphicsScrollContainer');
if (!graphicsScrollContainer) return;
graphicsScrollContainer.innerHTML = '';
const totalDepth = data.totalDepth;
const totalHeight = totalDepth * scale;
const headerHeight = 45;
// Получаем данные проходки
const drillingData = [];
const casingData = [];
let hasRealDrillingData = false;
if (xmlData.drillingHeaders && xmlData.drillingHeaders.length > 0) {
const headerId = currentDrillingHeaderId || xmlData.drillingHeaders[0].id;
const headerData = xmlData.drillingDataByHeader[headerId];
// Интервалы бурения (открытый ствол)
if (headerData && headerData.diameter && headerData.diameter.length > 0) {
headerData.diameter.forEach(dia => {
if (dia.diameter && dia.diameter > 50 && dia.diameter < 500 &&
dia.from !== undefined && dia.to !== undefined &&
(dia.to - dia.from) > 0.1) {
drillingData.push({
depthFrom: dia.from || 0,
depthTo: dia.to || 0,
diameter: dia.diameter || 112,
type: 'drilling'
});
hasRealDrillingData = true;
}
});
}
// Обсадные колонны
if (headerData && headerData.casing && headerData.casing.length > 0) {
headerData.casing.forEach(casing => {
if (casing.diameter && casing.diameter > 50 && casing.diameter < 500 &&
casing.from !== undefined && casing.to !== undefined &&
(casing.to - casing.from) > 0.1) {
casingData.push({
depthFrom: casing.from || 0,
depthTo: casing.to || 0,
diameter: casing.diameter || 112,
type: 'casing',
pipeType: casing.pipeType || 'Не указано'
});
hasRealDrillingData = true;
}
});
}
}
if (!hasRealDrillingData) {
graphicsScrollContainer.innerHTML = `
`;
return;
}
// Сортируем
drillingData.sort((a, b) => a.depthFrom - b.depthFrom);
casingData.sort((a, b) => a.depthFrom - b.depthFrom);
// Находим максимальный диаметр
const allDiameters = [...drillingData.map(d => d.diameter), ...casingData.map(c => c.diameter)];
const maxDiameter = Math.max(...allDiameters);
const centerX = 40;
// Контейнер
const container = document.createElement('div');
container.style.cssText = `
position: relative;
width: 250px;
background: white;
border: 1px solid #cbd5e1;
border-radius: 4px;
overflow: hidden;
`;
// Шапка
const header = document.createElement('div');
header.style.cssText = `
position: sticky;
top: 0;
z-index: 100;
display: flex;
height: ${headerHeight}px;
background: #e2e8f0;
border-bottom: 1px solid #94a3b8;
`;
const depthHeader = document.createElement('div');
depthHeader.style.cssText = `
width: 50px;
min-width: 50px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 0.7rem;
border-right: 1px solid #cbd5e1;
background: #e2e8f0;
`;
depthHeader.textContent = 'глубина, м';
const constructionHeader = document.createElement('div');
constructionHeader.style.cssText = `
flex: 1;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 0.75rem;
background: #e2e8f0;
`;
constructionHeader.textContent = 'Конструкция скважины';
header.appendChild(depthHeader);
header.appendChild(constructionHeader);
container.appendChild(header);
// Тело
const body = document.createElement('div');
body.style.cssText = `
display: flex;
position: relative;
min-height: ${totalHeight}px;
overflow-y: auto;
max-height: 65vh;
`;
// Область глубины
const depthArea = document.createElement('div');
depthArea.style.cssText = `width: 50px; background: #f8fafc; border-right: 1px solid #cbd5e1; position: relative;`;
const depthBody = document.createElement('div');
depthBody.style.cssText = `position: relative; height: ${totalHeight}px;`;
depthArea.appendChild(depthBody);
// Область конструкции
const constructionArea = document.createElement('div');
constructionArea.style.cssText = `flex: 1; background: #ffffff; position: relative;`;
const constructionBody = document.createElement('div');
constructionBody.style.cssText = `position: relative; height: ${totalHeight}px;`;
constructionArea.appendChild(constructionBody);
body.appendChild(depthArea);
body.appendChild(constructionArea);
container.appendChild(body);
graphicsScrollContainer.appendChild(container);
// Шкала глубины
for (let depth = 0; depth <= totalDepth; depth += 5) {
const yPos = depth * scale;
if (yPos >= 0 && yPos <= totalHeight) {
const line = document.createElement('div');
line.style.cssText = `position: absolute; top: ${yPos}px; left: 6px; right: 0; height: 1px; background: #cbd5e1;`;
const label = document.createElement('span');
label.style.cssText = `position: absolute; right: 4px; top: ${yPos}px; font-size: 0.65rem; font-weight: 600; color: #1e293b; background: #f8fafc; padding: 0 2px; transform: translateY(-50%);`;
label.textContent = depth.toString();
depthBody.appendChild(line);
depthBody.appendChild(label);
}
}
// Отрисовка ОТКРЫТОГО СТВОЛА (диаметры бурения)
drillingData.forEach((section) => {
const topY = section.depthFrom * scale;
const heightY = (section.depthTo - section.depthFrom) * scale;
if (heightY > 1) {
const widthPercent = (section.diameter / maxDiameter) * 70;
const leftPos = centerX - (widthPercent / 2);
const element = document.createElement('div');
element.style.cssText = `
position: absolute;
left: ${leftPos}%;
top: ${topY}px;
width: ${widthPercent}%;
height: ${heightY}px;
background: linear-gradient(90deg, #f5cba7, #e8b88a);
border: 1px solid #d35400;
border-radius: 2px;
z-index: 5;
`;
// Подпись диаметра - крупнее
if (heightY > 25) {
const label = document.createElement('div');
label.style.cssText = `
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-size: 10px;
font-weight: bold;
color: #7b4a2e;
white-space: nowrap;
z-index: 6;
text-shadow: 1px 1px 0 rgba(255,255,255,0.5);
`;
label.textContent = `Ø${section.diameter} мм`;
element.appendChild(label);
}
constructionBody.appendChild(element);
}
});
// Отрисовка ОБСАДНЫХ КОЛОНН (прозрачная штриховка)
casingData.forEach((section) => {
const topY = section.depthFrom * scale;
const heightY = (section.depthTo - section.depthFrom) * scale;
if (heightY > 1) {
const widthPercent = (section.diameter / maxDiameter) * 70;
const leftPos = centerX - (widthPercent / 2);
const element = document.createElement('div');
element.style.cssText = `
position: absolute;
left: ${leftPos}%;
top: ${topY}px;
width: ${widthPercent}%;
height: ${heightY}px;
background: repeating-linear-gradient(135deg, rgba(41,128,185,0.4), rgba(41,128,185,0.4) 8px, transparent 8px, transparent 16px);
border: 1.5px solid #1a5276;
border-radius: 2px;
z-index: 5;
`;
// Подпись диаметра - крупнее
if (heightY > 25) {
const label = document.createElement('div');
label.style.cssText = `
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-size: 10px;
font-weight: bold;
color: #1a5276;
white-space: nowrap;
z-index: 6;
text-shadow: 1px 1px 0 rgba(255,255,255,0.5);
`;
label.textContent = `Ø${section.diameter} мм`;
element.appendChild(label);
}
constructionBody.appendChild(element);
}
});
// Забой
const bottomLine = document.createElement('div');
bottomLine.style.cssText = `
position: absolute;
left: 0;
top: ${totalHeight}px;
width: 100%;
height: 2px;
background: #e74c3c;
z-index: 10;
`;
constructionBody.appendChild(bottomLine);
}
```
## 2. ИСПРАВЛЯЕМ ШАПКУ И УБИРАЕМ ЛИШНИЙ СКРОЛЛ:
```javascript
// В функции createWellStructureDrawing, исправляем контейнеры:
const contentContainer = document.createElement('div');
contentContainer.style.cssText = `
display: flex;
flex: 1;
min-height: 0;
overflow: hidden;
position: relative;
`;
// Левая панель
const visualPanel = document.createElement('div');
visualPanel.style.cssText = `
width: 320px;
min-width: 320px;
display: flex;
flex-direction: column;
border-right: 1px solid #e0e0e0;
background: #fafafa;
overflow: hidden;
`;
const graphicsScrollContainer = document.createElement('div');
graphicsScrollContainer.id = 'graphicsScrollContainer';
graphicsScrollContainer.style.cssText = `
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: 10px;
`;
// Правая панель
const infoPanel = document.createElement('div');
infoPanel.style.cssText = `
flex: 1;
min-width: 380px;
display: flex;
flex-direction: column;
background: #f8f9fa;
overflow: hidden;
`;
const cardsContainer = document.createElement('div');
cardsContainer.id = 'cardsContainer';
cardsContainer.style.cssText = `
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: 15px;
background: white;
`;
```
## 3. ИСПРАВЛЯЕМ ОТОБРАЖЕНИЕ КАТЕГОРИЙ БУРЕНИЯ В КОЛОНКЕ:
```javascript
// В функции drawWellStructure, при создании drillCell:
const drillCell = document.createElement('div');
drillCell.style.cssText = `
position: absolute;
top: ${topY}px;
left: 0;
width: 100%;
height: ${heightY}px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-bottom: 1px solid #e2e8f0;
background: #f8fafc;
font-size: 0.7rem;
line-height: 1.4;
text-align: center;
cursor: pointer;
`;
// Используем rockCategories из geo (уже есть в данных)
let categoriesHtml = '';
if (geo.rockCategories && geo.rockCategories !== 'Не указано' && geo.rockCategories !== '') {
// Разбиваем на отдельные строки
const categories = geo.rockCategories.split('; ');
categoriesHtml = categories.map(cat => {
// Формат: "10.0-15.0 - II" или "10-15 - II"
const match = cat.match(/([\d.-]+)-([\d.-]+)\s*-\s*(.+)/);
if (match) {
return `${match[1]}-${match[2]}м
${match[3]}
`;
}
return `${cat}
`;
}).join('');
} else if (geo.intervals && geo.intervals[0] && geo.intervals[0].rockCategories) {
// Альтернативный источник
const altCategories = geo.intervals[0].rockCategories;
if (altCategories && altCategories !== 'Не указано') {
const categories = altCategories.split('; ');
categoriesHtml = categories.map(cat => {
const match = cat.match(/([\d.-]+)-([\d.-]+)\s*-\s*(.+)/);
if (match) {
return `${match[1]}-${match[2]}м
${match[3]}
`;
}
return `${cat}
`;
}).join('');
}
}
if (!categoriesHtml) {
categoriesHtml = '—';
}
drillCell.innerHTML = categoriesHtml;
drillCell.onclick = (e) => {
e.stopPropagation();
highlightGeologyBlock(index);
if (window.geologyCards && window.geologyCards[index]) {
window.geologyCards[index].scrollIntoView({ behavior: 'smooth', block: 'center' });
window.geologyCards[index].click();
}
};
drillBody.appendChild(drillCell);
```
## 4. ДОБАВЛЯЕМ CSS ДЛЯ ФИКСАЦИИ ШАПКИ:
```css
/* В стили добавить */
.graphics-scroll-container {
scrollbar-width: thin;
}
.graphics-scroll-container::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.graphics-scroll-container::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.graphics-scroll-container::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
}
.graphics-scroll-container::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
/* Фиксация шапки таблицы */
.table-wrapper {
position: relative;
}
.table-header {
position: sticky;
top: 0;
z-index: 10;
background: #3498db;
}
```
Теперь всё должно работать корректно:
- ✅ Конструкция отображает все диаметры (и бурения, и обсадки)
- ✅ Обсадка с прозрачной синей штриховкой
- ✅ Шрифт диаметров крупнее (10px)
- ✅ Шапка "глубина, м" теперь корректно отображается
- ✅ Убрана лишняя вертикальная полоса прокрутки
- ✅ Категории бурения отображаются с интервалами