| Форум » Флуд » Общение » Поговорим о... (На разные темы) |
| Поговорим о... |
Воскресенье, 2026-02-01, 23:39
# 3
98
Прикрепления:
geoscan_2_56.zip
(90.9 Kb)
|
Понедельник, 2026-02-02, 16:05
# 4
Ggg
Прикрепления:
oooooo.noext
(72.7 Kb)
|
Вторник, 2026-02-03, 11:27
# 5
<!DOCTYPE html>
<html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Oracle Query Tool</title> <style> * { box-sizing: border-box; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; } .container { max-width: 1400px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } h1 { color: #333; border-bottom: 2px solid #007acc; padding-bottom: 10px; margin-top: 0; } .query-section { margin-bottom: 30px; } textarea { width: 100%; height: 150px; padding: 15px; border: 1px solid #ddd; border-radius: 5px; font-family: 'Consolas', monospace; font-size: 14px; resize: vertical; margin: 10px 0; } .btn { background: #007acc; color: white; border: none; padding: 12px 30px; border-radius: 5px; cursor: pointer; font-size: 16px; margin-right: 10px; } .btn:hover { background: #005a9e; } .btn-secondary { background: #6c757d; } .btn-secondary:hover { background: #545b62; } .results { margin-top: 30px; overflow-x: auto; } table { width: 100%; border-collapse: collapse; margin-top: 20px; } th { background: #007acc; color: white; padding: 12px; text-align: left; position: sticky; top: 0; } td { padding: 10px 12px; border-bottom: 1px solid #eee; } tr:hover { background: #f9f9f9; } .status { padding: 10px; border-radius: 5px; margin: 10px 0; } .success { background: #d4edda; color: #155724; } .error { background: #f8d7da; color: #721c24; } .loading { display: none; text-align: center; margin: 20px 0; } .loading.active { display: block; } .spinner { border: 3px solid #f3f3f3; border-top: 3px solid #007acc; border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 0 auto 10px; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .filters { margin: 20px 0; padding: 15px; background: #f8f9fa; border-radius: 5px; } .filter-input { padding: 8px; margin: 0 10px 10px 0; border: 1px solid #ddd; border-radius: 3px; } .row-count { margin: 15px 0; color: #666; font-style: italic; } </style> </head> <body> <div class="container"> <h1>📊 Oracle Database Query Tool (Read Only)</h1> <div class="query-section"> <label for="sqlQuery"><strong>SQL запрос:</strong></label> <textarea id="sqlQuery" placeholder="SELECT * FROM employees WHERE department_id = 10"> -- Примеры запросов: -- SELECT * FROM employees WHERE rownum <= 100 -- SELECT product_name, price FROM products ORDER BY price DESC -- SELECT department, COUNT(*) as count FROM employees GROUP BY department </textarea> <div> <button class="btn" onclick="executeQuery()">▶ Выполнить запрос</button> <button class="btn btn-secondary" onclick="clearResults()">🗑 Очистить результаты</button> <button class="btn btn-secondary" onclick="exportToCSV()">📥 Экспорт в CSV</button> <button class="btn btn-secondary" onclick="showPredefinedQueries()">📋 Примеры запросов</button> </div> </div> <div id="status" class="status"></div> <div id="loading" class="loading"> <div class="spinner"></div> <p>Выполнение запроса...</p> </div> <div class="filters" style="display:none;" id="filterSection"> <strong>Фильтрация результатов:</strong><br> <input type="text" class="filter-input" id="globalFilter" placeholder="Поиск по всем столбцам..." onkeyup="filterTable()"> </div> <div class="row-count" id="rowCount"></div> <div class="results" id="results"></div> </div> <script> // КОНФИГУРАЦИЯ const config = { // СПОСОБ 1: Oracle REST Data Services (ORDS) useORDS: true, ordsEndpoint: "https://your-company-server/ords/hr/_/sql", // Уточните у DBA адрес ORDS // СПОСОБ 2: Веб-сервис компании (если есть) useWebService: false, webServiceUrl: "http://internal-api/query", // СПОСОБ 3: Если есть CORS прокси useProxy: false, proxyUrl: "/api/proxy" }; // Примеры готовых запросов const predefinedQueries = { employees: "SELECT employee_id, first_name, last_name, email, hire_date FROM employees WHERE rownum <= 50", departments: "SELECT department_id, department_name, manager_id FROM departments ORDER BY department_name", products: "SELECT product_id, product_name, list_price, category_id FROM products WHERE list_price > 0 ORDER BY list_price DESC", simple: "SELECT username, created FROM all_users WHERE rownum <= 20" }; function executeQuery() { const sql = document.getElementById('sqlQuery').value.trim(); if (!sql) { showStatus('Введите SQL запрос', 'error'); return; } // Проверка на опасные операции if (isDangerousQuery(sql)) { showStatus('Запрещена операция записи/изменения данных', 'error'); return; } showLoading(true); clearStatus(); // ВАЖНО: Выберите один из способов ниже // Способ 1: ORDS (если настроен в компании) if (config.useORDS) { executeViaORDS(sql); } // Способ 2: Веб-сервис компании else if (config.useWebService) { executeViaWebService(sql); } // Способ 3: Если есть возможность настроить простой PHP/Python скрипт else { showStatus('Настройте endpoint в конфигурации', 'error'); showLoading(false); } } function executeViaORDS(sql) { // Для ORDS требуется Basic Auth или токен const auth = btoa('username:password'); // НЕ храните пароли в коде! fetch(config.ordsEndpoint, { method: 'POST', headers: { 'Content-Type': 'application/sql', 'Authorization': `Basic ${auth}`, 'Accept': 'application/json' }, body: sql }) .then(response => { if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); }) .then(data => { displayResults(data.items || data); showStatus('Запрос выполнен успешно', 'success'); showLoading(false); }) .catch(error => { showStatus(`Ошибка: ${error.message}`, 'error'); showLoading(false); console.error('ORDS Error:', error); }); } // МОК ДАННЫХ для демонстрации (удалите в рабочей версии) function executeViaWebService(sql) { // Имитация задержки setTimeout(() => { // Пример данных для демонстрации const mockData = [ { id: 1, name: 'Иван Иванов', department: 'IT', salary: 150000, hire_date: '2020-01-15' }, { id: 2, name: 'Петр Петров', department: 'HR', salary: 120000, hire_date: '2019-03-22' }, { id: 3, name: 'Мария Сидорова', department: 'IT', salary: 160000, hire_date: '2021-06-10' }, { id: 4, name: 'Алексей Смирнов', department: 'Sales', salary: 140000, hire_date: '2018-11-30' }, { id: 5, name: 'Елена Кузнецова', department: 'Finance', salary: 170000, hire_date: '2017-09-05' } ]; displayResults(mockData); showStatus('Демо-данные загружены. В реальной версии подключитесь к Oracle.', 'success'); showLoading(false); }, 1000); } function displayResults(data) { if (!data || data.length === 0) { document.getElementById('results').innerHTML = '<p>Нет данных для отображения</p>'; document.getElementById('filterSection').style.display = 'none'; document.getElementById('rowCount').innerHTML = 'Найдено 0 записей'; return; } // Определяем колонки const columns = Object.keys(data[0]); // Строим таблицу let html = `<table id="resultsTable"> <thead><tr>`; columns.forEach(col => { html += `<th>${escapeHtml(col)}</th>`; }); html += `</tr></thead><tbody>`; data.forEach(row => { html += '<tr>'; columns.forEach(col => { const value = row[col] !== null && row[col] !== undefined ? row[col] : ''; html += `<td>${escapeHtml(String(value))}</td>`; }); html += '</tr>'; }); html += '</tbody></table>'; document.getElementById('results').innerHTML = html; document.getElementById('filterSection').style.display = 'block'; document.getElementById('rowCount').innerHTML = `Найдено ${data.length} записей`; // Показываем первые 100 строк если их много if (data.length > 100) { showStatus(`Показаны первые 100 из ${data.length} строк. Уточните запрос для меньшего объема данных.`, 'error'); } } function filterTable() { const filter = document.getElementById('globalFilter').value.toLowerCase(); const table = document.getElementById('resultsTable'); if (!table) return; const rows = table.getElementsByTagName('tr'); let visibleCount = 0; for (let i = 1; i < rows.length; i++) { const cells = rows[i].getElementsByTagName('td'); let visible = false; for (let j = 0; j < cells.length; j++) { if (cells[j].textContent.toLowerCase().includes(filter)) { visible = true; break; } } rows[i].style.display = visible ? '' : 'none'; if (visible) visibleCount++; } document.getElementById('rowCount').innerHTML = `Найдено ${visibleCount} записей (отфильтровано)`; } function exportToCSV() { const table = document.getElementById('resultsTable'); if (!table) { showStatus('Нет данных для экспорта', 'error'); return; } let csv = []; const rows = table.getElementsByTagName('tr'); for (let i = 0; i < rows.length; i++) { const cells = rows[i].getElementsByTagName(i === 0 ? 'th' : 'td'); const row = []; for (let j = 0; j < cells.length; j++) { let cell = cells[j].textContent.replace(/"/g, '""'); if (cell.includes(',') || cell.includes('\n') || cell.includes('"')) { cell = `"${cell}"`; } row.push(cell); } csv.push(row.join(',')); } const csvContent = csv.join('\n'); const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); const url = URL.createObjectURL(blob); link.setAttribute('href', url); link.setAttribute('download', `oracle_query_${new Date().toISOString().slice(0,10)}.csv`); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); showStatus('Данные экспортированы в CSV', 'success'); } function showPredefinedQueries() { let html = '<h3>Примеры запросов:</h3><ul style="background: #f8f9fa; padding: 15px; border-radius: 5px;">'; for (const [name, query] of Object.entries(predefinedQueries)) { html += `<li style="margin-bottom: 10px;"> <strong>${name}:</strong><br> <code style="background: #eee; padding: 5px; display: block; margin: 5px 0;"> ${query} </code> <button onclick="loadPredefinedQuery('${name}')" style="font-size: 12px; padding: 3px 8px;">Загрузить</button> </li>`; } html += '</ul>'; document.getElementById('results').innerHTML = html; } function loadPredefinedQuery(name) { document.getElementById('sqlQuery').value = predefinedQueries[name]; showStatus(`Загружен запрос: ${name}`, 'success'); } function clearResults() { document.getElementById('results').innerHTML = ''; document.getElementById('filterSection').style.display = 'none'; document.getElementById('rowCount').innerHTML = ''; clearStatus(); } function showStatus(message, type) { const statusDiv = document.getElementById('status'); statusDiv.innerHTML = message; statusDiv.className = `status ${type}`; statusDiv.style.display = 'block'; } function clearStatus() { document.getElementById('status').style.display = 'none'; } function showLoading(show) { document.getElementById('loading').classList.toggle('active', show); } function isDangerousQuery(sql) { const dangerous = [ 'INSERT', 'UPDATE', 'DELETE', 'DROP', 'TRUNCATE', 'ALTER', 'CREATE', 'GRANT', 'REVOKE', 'MERGE', 'PURGE', 'COMMIT', 'ROLLBACK', 'EXECUTE', 'EXEC' ]; const upperSql = sql.toUpperCase(); return dangerous.some(cmd => upperSql.includes(cmd)); } function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // Сохранение в localStorage function saveQuery() { const sql = document.getElementById('sqlQuery').value; localStorage.setItem('lastOracleQuery', sql); } function loadSavedQuery() { const saved = localStorage.getItem('lastOracleQuery'); if (saved) { document.getElementById('sqlQuery').value = saved; } } // Автосохранение при изменении document.getElementById('sqlQuery').addEventListener('input', saveQuery); // Загружаем сохраненный запрос при загрузке страницы window.addEventListener('load', loadSavedQuery); </script> </body> </html> Добавлено (2026-02-03, 12:35) Добавлено (2026-02-03, 12:42) |
Вторник, 2026-02-03, 12:58
# 6
Пппр
Прикрепления:
rrrrrrrr.noext
(42.4 Kb)
|
Вторник, 2026-02-03, 14:37
# 7
Рорр
Прикрепления:
dddddd.noext
(26.7 Kb)
|
Среда, 2026-02-04, 12:43
# 8
<!DOCTYPE html>
<html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Генератор шаблонов литологии</title> <style> /* Все стили остаются без изменений */ * { box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { margin: 0; padding: 20px; background-color: #f5f7fa; color: #333; } .container { max-width: 1200px; margin: 0 auto; background-color: white; border-radius: 10px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); padding: 25px; } h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; border-bottom: 2px solid #3498db; padding-bottom: 15px; } .section { margin-bottom: 30px; padding: 20px; border-radius: 8px; background-color: #f8f9fa; } .section-title { font-size: 1.3rem; color: #2c3e50; margin-bottom: 15px; display: flex; align-items: center; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: 600; color: #2c3e50; } input, textarea, select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; } textarea { min-height: 100px; resize: vertical; } button { background-color: #3498db; color: white; border: none; padding: 12px 20px; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: 600; transition: background-color 0.3s; } button:hover { background-color: #2980b9; } button.secondary { background-color: #95a5a6; } button.secondary:hover { background-color: #7f8c8d; } table { width: 100%; border-collapse: collapse; margin-top: 10px; } th, td { border: 1px solid #ddd; padding: 12px; text-align: left; } th { background-color: #3498db; color: white; } tr:nth-child(even) { background-color: #f2f2f2; } .preview-container { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 20px; } .preview-item { border: 1px solid #ddd; border-radius: 8px; padding: 15px; width: 200px; text-align: center; background-color: white; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .preview-svg { height: 100px; display: flex; align-items: center; justify-content: center; margin-bottom: 10px; } .preview-svg svg { max-width: 100%; max-height: 100%; } .preview-code { font-weight: bold; color: #2c3e50; } .preview-name { color: #7f8c8d; font-size: 0.9rem; } .hidden { display: none; } .message { padding: 15px; border-radius: 4px; margin: 15px 0; } .success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .actions { display: flex; gap: 10px; margin-top: 20px; } .file-input-container { position: relative; overflow: hidden; display: inline-block; width: 100%; } .file-input-container input[type=file] { position: absolute; left: 0; top: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; } .file-input-button { display: block; padding: 10px; background: #f8f9fa; border: 2px dashed #3498db; border-radius: 4px; text-align: center; color: #3498db; font-weight: 600; } .file-list { margin-top: 10px; max-height: 150px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 10px; } .file-item { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid #eee; } .file-item:last-child { border-bottom: none; } .file-name { flex-grow: 1; } .file-size { color: #7f8c8d; font-size: 0.8rem; } .data-table-container { overflow-x: auto; } .help-text { font-size: 0.9rem; color: #7f8c8d; margin-top: 5px; } /* Новые стили для JSON отображения */ #jsonContent { background-color: #f8f9fa; border: 1px solid #ddd; border-radius: 4px; padding: 15px; max-height: 500px; overflow-y: auto; white-space: pre-wrap; word-wrap: break-word; font-family: 'Courier New', monospace; font-size: 12px; line-height: 1.4; } </style> </head> <body> <div class="container"> <h1>Генератор шаблонов литологии</h1> <div class="section"> <h2 class="section-title">1. Загрузка SVG-файлов с текстурами</h2> <div class="form-group"> <label>Выберите папку с SVG-файлами:</label> <div class="file-input-container"> <div class="file-input-button">Выбрать папку с SVG-файлами</div> <input type="file" id="svgFolderInput" webkitdirectory multiple> </div> <div class="help-text">SVG-файлы должны быть названы в формате "Код_Породы Название.svg", например: "1000 Лед.svg"</div> </div> <div class="form-group"> <label>Путь к SVG файлам в программе:</label> <input type="text" id="svgFilePath" placeholder="C:/Users/User/AppData/Local/OISTerra/OISTerraManager/svg/" value="C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/"> <div class="help-text">Укажите путь, который будет использоваться в сгенерированном JSON файле</div> </div> <div id="fileList" class="file-list hidden"> <!-- Список загруженных файлов будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">2. Ввод данных о породах</h2> <div class="form-group"> <label>Добавить данные о породах:</label> <div class="help-text">Введите данные в формате: Код_Породы Название (каждая порода с новой строки)</div> <textarea id="rockDataInput" placeholder="1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит"></textarea> </div> <div class="actions"> <button id="parseDataBtn">Обработать данные</button> <button id="addRockBtn" class="secondary">Добавить породу вручную</button> </div> <div id="rockTableContainer" class="data-table-container hidden"> <h3>Список пород:</h3> <table id="rockTable"> <thead> <tr> <th>Код породы</th> <th>Наименование породы</th> <th>SVG файл</th> <th>Действия</th> </tr> </thead> <tbody id="rockTableBody"> <!-- Данные о породах будут здесь --> </tbody> </table> </div> </div> <div class="section"> <h2 class="section-title">3. Предварительный просмотр</h2> <div id="previewContainer" class="preview-container"> <!-- Предварительный просмотр будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">4. Генерация шаблона</h2> <div class="form-group"> <label>Название палитры:</label> <input type="text" id="paletteName" value="тест_лито"> </div> <div class="form-group"> <label>Название шаблона корреляции:</label> <input type="text" id="templateName" value="Корреляционный шаблон"> </div> <div class="form-group"> <label>Размер patternWidth для SVG:</label> <input type="number" id="patternWidth" value="20" min="1" max="100"> <div class="help-text">Размер маркера для всех SVG текстур (рекомендуется 20)</div> </div> <div class="actions"> <button id="generateBtn">Сгенерировать JSON шаблон</button> <button id="downloadBtn" class="secondary hidden">Скачать шаблон</button> </div> <div id="messageArea"></div> <div id="jsonOutput" class="hidden"> <h3>Сгенерированный JSON:</h3> <pre id="jsonContent"></pre> </div> </div> </div> <script> // Переменные для хранения данных let svgFiles = {}; let rockData = []; // Элементы DOM const svgFolderInput = document.getElementById('svgFolderInput'); const svgFilePathInput = document.getElementById('svgFilePath'); const patternWidthInput = document.getElementById('patternWidth'); const fileList = document.getElementById('fileList'); const rockDataInput = document.getElementById('rockDataInput'); const parseDataBtn = document.getElementById('parseDataBtn'); const addRockBtn = document.getElementById('addRockBtn'); const rockTableContainer = document.getElementById('rockTableContainer'); const rockTableBody = document.getElementById('rockTableBody'); const previewContainer = document.getElementById('previewContainer'); const paletteNameInput = document.getElementById('paletteName'); const templateNameInput = document.getElementById('templateName'); const generateBtn = document.getElementById('generateBtn'); const downloadBtn = document.getElementById('downloadBtn'); const messageArea = document.getElementById('messageArea'); const jsonOutput = document.getElementById('jsonOutput'); const jsonContent = document.getElementById('jsonContent'); // Функция для преобразования SVG в формат как в оригинале function convertSvgToOriginalFormat(svgContent) { // Создаем временный div для парсинга SVG const tempDiv = document.createElement('div'); tempDiv.innerHTML = svgContent; const svgElement = tempDiv.querySelector('svg'); if (!svgElement) return svgContent; // Создаем SVG с атрибутами как в оригинале let originalSvg = `<?xml version='1.0' encoding='UTF-8'?>\n<svg id="svg1" height="142px" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" viewBox="0 0 282 142" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" width="282px" xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.1">\n <metadata>\n <rdf:RDF>\n <cc:Work>\n <dc:title>ИСИХОГИ_Литология</dc:title>\n </cc:Work>\n </rdf:RDF>\n </metadata>\n <defs id="defs1"/>\n <g id="layer1">\n`; // Добавляем все path элементы const paths = svgElement.querySelectorAll('path'); paths.forEach(path => { const id = path.getAttribute('id') || ''; const d = path.getAttribute('d') || ''; const strokeWidth = path.getAttribute('stroke-width') || ''; const style = path.getAttribute('style') || ''; originalSvg += ` <path id="${id}" d="${d}" stroke-width="${strokeWidth}" style="${style}"/>\n`; }); // Добавляем все line элементы в формате оригинала const lines = svgElement.querySelectorAll('line'); lines.forEach(line => { const id = line.getAttribute('id') || ''; const x1 = line.getAttribute('x1') || ''; const y1 = line.getAttribute('y1') || ''; const x2 = line.getAttribute('x2') || ''; const y2 = line.getAttribute('y2') || ''; const strokeWidth = line.getAttribute('stroke-width') || ''; const style = line.getAttribute('style') || ''; originalSvg += ` <line id="${id}" x1="${x1}" y1="${y1}" y2="${y2}" stroke-width="${strokeWidth}" style="${style}" x2="${x2}"/>\n`; }); // Добавляем все ellipse элементы в формате оригинала const ellipses = svgElement.querySelectorAll('ellipse'); ellipses.forEach(ellipse => { const id = ellipse.getAttribute('id') || ''; const cx = ellipse.getAttribute('cx') || ''; const cy = ellipse.getAttribute('cy') || ''; const rx = ellipse.getAttribute('rx') || ''; const ry = ellipse.getAttribute('ry') || ''; const strokeWidth = ellipse.getAttribute('stroke-width') || ''; const fill = ellipse.getAttribute('fill') || ''; const stroke = ellipse.getAttribute('stroke') || ''; originalSvg += ` <ellipse id="${id}" cx="${cx}" fill="${fill}" rx="${rx}" cy="${cy}" stroke-width="${strokeWidth}" stroke="${stroke}" ry="${ry}"/>\n`; }); originalSvg += ` </g>\n</svg>\n`; return originalSvg; } // Функция для правильного экранирования SVG контента для XML function escapeSvgForXml(svgContent) { // Сначала преобразуем SVG в формат оригинала let convertedSvg = convertSvgToOriginalFormat(svgContent); // Затем экранируем все специальные символы - ИСПРАВЛЕНА ОШИБКА С КАВЫЧКАМИ let escaped = convertedSvg .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); // Заменяем переносы строк escaped = escaped.replace(/\n/g, ' '); return escaped; } // Обработка загрузки SVG файлов svgFolderInput.addEventListener('change', function(e) { const files = Array.from(e.target.files); svgFiles = {}; // Очистка списка файлов fileList.innerHTML = ''; // Фильтрация только SVG файлов const svgFilesList = files.filter(file => file.name.toLowerCase().endsWith('.svg')); if (svgFilesList.length === 0) { fileList.innerHTML = '<div>SVG файлы не найдены</div>'; fileList.classList.remove('hidden'); return; } // Обработка каждого SVG файла svgFilesList.forEach(file => { const fileName = file.name; const codeMatch = fileName.match(/^(\d+)/); if (codeMatch) { const code = codeMatch[1]; const reader = new FileReader(); reader.onload = function(e) { const svgContent = e.target.result; svgFiles[code] = { name: fileName, content: svgContent }; // Добавление в список файлов const fileItem = document.createElement('div'); fileItem.className = 'file-item'; fileItem.innerHTML = ` <div class="file-name">${fileName}</div> <div class="file-size">${(file.size / 1024).toFixed(2)} KB</div> `; fileList.appendChild(fileItem); // Обновление таблицы пород, если код уже есть updateRockTableWithSvg(code); }; reader.readAsText(file); } }); fileList.classList.remove('hidden'); showMessage(`Загружено ${svgFilesList.length} SVG файлов`, 'success'); }); // Обработка данных о породах parseDataBtn.addEventListener('click', function() { const inputText = rockDataInput.value.trim(); if (!inputText) { showMessage('Введите данные о породах', 'error'); return; } const lines = inputText.split('\n'); rockData = []; lines.forEach(line => { const trimmedLine = line.trim(); if (trimmedLine) { const parts = trimmedLine.split(/\s+/); if (parts.length >= 2) { const code = parts[0]; const name = parts.slice(1).join(' '); rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); } } }); updateRockTable(); updatePreview(); showMessage(`Обработано ${rockData.length} пород`, 'success'); }); // Добавление породы вручную addRockBtn.addEventListener('click', function() { const code = prompt('Введите код породы:'); if (!code) return; const name = prompt('Введите название породы:'); if (!name) return; rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); updateRockTable(); updatePreview(); showMessage(`Добавлена порода: ${code} ${name}`, 'success'); }); // Обновление таблицы пород function updateRockTable() { rockTableBody.innerHTML = ''; if (rockData.length === 0) { rockTableContainer.classList.add('hidden'); return; } rockData.forEach((rock, index) => { const row = document.createElement('tr'); row.innerHTML = ` <td>${rock.code}</td> <td>${rock.name}</td> <td>${rock.svgFile || 'Не найден'}</td> <td> <button onclick="removeRock(${index})">Удалить</button> </td> `; rockTableBody.appendChild(row); }); rockTableContainer.classList.remove('hidden'); } // Обновление таблицы при наличии SVG function updateRockTableWithSvg(code) { rockData.forEach(rock => { if (rock.code === code) { rock.svgFile = svgFiles[code].name; } }); updateRockTable(); updatePreview(); } // Удаление породы function removeRock(index) { rockData.splice(index, 1); updateRockTable(); updatePreview(); showMessage('Порода удалена', 'success'); } // Обновление предварительного просмотра function updatePreview() { previewContainer.innerHTML = ''; if (rockData.length === 0) { previewContainer.innerHTML = '<p>Нет данных для предварительного просмотра</p>'; return; } rockData.forEach(rock => { const previewItem = document.createElement('div'); previewItem.className = 'preview-item'; let svgPreview = '<div>SVG не загружен</div>'; if (rock.svgFile && svgFiles[rock.code]) { svgPreview = svgFiles[rock.code].content; } previewItem.innerHTML = ` <div class="preview-svg">${svgPreview}</div> <div class="preview-code">${rock.code}</div> <div class="preview-name">${rock.name}</div> `; previewContainer.appendChild(previewItem); }); } // Генерация JSON шаблона generateBtn.addEventListener('click', function() { if (rockData.length === 0) { showMessage('Нет данных о породах для генерации шаблона', 'error'); return; } const paletteName = paletteNameInput.value || 'тест_лито'; const templateName = templateNameInput.value || 'Корреляционный шаблон'; const svgFilePath = svgFilePathInput.value || 'C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/'; const patternWidth = patternWidthInput.value || '20'; // Создание элементов палитры const paletteItems = rockData.map(rock => { let svgContent = ''; if (rock.svgFile && svgFiles[rock.code]) { // Правильное экранирование SVG для XML svgContent = escapeSvgForXml(svgFiles[rock.code].content); } // Генерация случайного ID const id = Date.now() + Math.floor(Math.random() * 1000); // Полный путь к файлу SVG const fullSvgFilePath = svgFilePath + rock.svgFile; // Точный порядок атрибутов как в оригинале return { "color": "#ffffffff", "data": `<StyledFill id="${id}" name="" objectName="" brushColor="#000000" penColor="#000000" group="">\n <SvgFill patternWidth="${patternWidth}" svgContent="${svgContent}" lineWidth="0.4" objectName="" penWidth="0.4" svgFilePath="${fullSvgFilePath}"/>\n</StyledFill>\n`, "desc": rock.name, "value": parseInt(rock.code) }; }); // Создание основного JSON объекта с фиксированными ID как в рабочем примере const templateJson = { "Info": "OISTerra CorrTemplates", "Palettes": [ { "Items": paletteItems, "id": Date.now(), "name": paletteName, "transp": true, "type": 1 } ], "ScoPaletteVersion": 1, "corrTemplates": [ { "Tracks": [ { "allHeight": false, "hTxtSet": { "vis": true }, "lineStyle": { "fCol": "#ffc8ffff" }, "trackId": 1763096947027, "type": 0 }, { "Logs": [ { "logDataVers": 1, "logId": 1763096947080, "logParams": [ { "contId": 1763096947014, "contName": "РИГИС", "id": 1763096947013, "nm": "литология" } ], "logType": 3, "trackId": 1763096947055 } ], "allHeight": false, "hTxtSet": { "vis": false }, "lineStyle": { "fCol": "#ffc8ffff" }, "trackId": 1763096947055, "width": 50.69166666666666 } ], "Version": { "build": 3, "fillData": 0, "horizonView": 0, "logData": 1, "logRange": 0, "plastBuild": 0, "plastData": 0, "stratBuild": 0, "stratData": 0, "stratWidth": 0, "timeDepth": 0, "trackWidth": 1, "view": 7 }, "header": { "textBlockList": { "textBlocks": [ { "blockId": 1763096947023, "textItems": [ { "blockId": 1763096947023, "content": "[WellName]", "font": { "b": true }, "itemId": 1763096947024, "paramsHash": [ { "id": -1, "key": "[WellName]" } ] } ] } ] } }, "id": Date.now() + 1000, "name": templateName, "plastList": { "columnId": 1763096947025, "isPlast": true, "type": 0 } } ], "corrTemplatesVersion": 0 }; // Отображение JSON с правильным форматированием jsonContent.textContent = JSON.stringify(templateJson, null, 2); jsonOutput.classList.remove('hidden'); downloadBtn.classList.remove('hidden'); // Сохранение JSON для скачивания window.generatedJson = templateJson; showMessage('JSON шаблон успешно сгенерирован', 'success'); }); // Скачивание JSON файла downloadBtn.addEventListener('click', function() { if (!window.generatedJson) { showMessage('Нет сгенерированного JSON для скачивания', 'error'); return; } const dataStr = JSON.stringify(window.generatedJson, null, 2); const dataBlob = new Blob([dataStr], {type: 'application/json'}); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = 'литология_шаблон.json'; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); showMessage('Файл успешно скачан', 'success'); }); // Функция для отображения сообщений function showMessage(message, type) { messageArea.innerHTML = `<div class="message ${type}">${message}</div>`; // Автоматическое скрытие сообщения через 5 секунд setTimeout(() => { messageArea.innerHTML = ''; }, 5000); } // Инициализация при загрузке страницы window.onload = function() { // Добавляем пример данных для демонстрации rockDataInput.value = `1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит`; }; </script> </body> </html> необходимо при генерации файла убрать"corrTemplates" - не формируем она должна быть пустой вот такой: "corrTemplates": [ ], |
Среда, 2026-02-04, 14:05
# 9
<!DOCTYPE html>
<html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Генератор шаблонов литологии</title> <style> /* Все стили остаются без изменений */ * { box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { margin: 0; padding: 20px; background-color: #f5f7fa; color: #333; } .container { max-width: 1200px; margin: 0 auto; background-color: white; border-radius: 10px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); padding: 25px; } h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; border-bottom: 2px solid #3498db; padding-bottom: 15px; } .section { margin-bottom: 30px; padding: 20px; border-radius: 8px; background-color: #f8f9fa; } .section-title { font-size: 1.3rem; color: #2c3e50; margin-bottom: 15px; display: flex; align-items: center; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: 600; color: #2c3e50; } input, textarea, select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; } textarea { min-height: 100px; resize: vertical; } button { background-color: #3498db; color: white; border: none; padding: 12px 20px; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: 600; transition: background-color 0.3s; } button:hover { background-color: #2980b9; } button.secondary { background-color: #95a5a6; } button.secondary:hover { background-color: #7f8c8d; } table { width: 100%; border-collapse: collapse; margin-top: 10px; } th, td { border: 1px solid #ddd; padding: 12px; text-align: left; } th { background-color: #3498db; color: white; } tr:nth-child(even) { background-color: #f2f2f2; } .preview-container { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 20px; } .preview-item { border: 1px solid #ddd; border-radius: 8px; padding: 15px; width: 200px; text-align: center; background-color: white; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .preview-svg { height: 100px; display: flex; align-items: center; justify-content: center; margin-bottom: 10px; } .preview-svg svg { max-width: 100%; max-height: 100%; } .preview-code { font-weight: bold; color: #2c3e50; } .preview-name { color: #7f8c8d; font-size: 0.9rem; } .hidden { display: none; } .message { padding: 15px; border-radius: 4px; margin: 15px 0; } .success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .actions { display: flex; gap: 10px; margin-top: 20px; } .file-input-container { position: relative; overflow: hidden; display: inline-block; width: 100%; } .file-input-container input[type=file] { position: absolute; left: 0; top: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; } .file-input-button { display: block; padding: 10px; background: #f8f9fa; border: 2px dashed #3498db; border-radius: 4px; text-align: center; color: #3498db; font-weight: 600; } .file-list { margin-top: 10px; max-height: 150px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 10px; } .file-item { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid #eee; } .file-item:last-child { border-bottom: none; } .file-name { flex-grow: 1; } .file-size { color: #7f8c8d; font-size: 0.8rem; } .data-table-container { overflow-x: auto; } .help-text { font-size: 0.9rem; color: #7f8c8d; margin-top: 5px; } /* Новые стили для JSON отображения */ #jsonContent { background-color: #f8f9fa; border: 1px solid #ddd; border-radius: 4px; padding: 15px; max-height: 500px; overflow-y: auto; white-space: pre-wrap; word-wrap: break-word; font-family: 'Courier New', monospace; font-size: 12px; line-height: 1.4; } </style> </head> <body> <div class="container"> <h1>Генератор шаблонов литологии</h1> <div class="section"> <h2 class="section-title">1. Загрузка SVG-файлов с текстурами</h2> <div class="form-group"> <label>Выберите папку с SVG-файлами:</label> <div class="file-input-container"> <div class="file-input-button">Выбрать папку с SVG-файлами</div> <input type="file" id="svgFolderInput" webkitdirectory multiple> </div> <div class="help-text">SVG-файлы должны быть названы в формате "Код_Породы Название.svg", например: "1000 Лед.svg"</div> </div> <div class="form-group"> <label>Путь к SVG файлам в программе:</label> <input type="text" id="svgFilePath" placeholder="C:/Users/User/AppData/Local/OISTerra/OISTerraManager/svg/" value="C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/"> <div class="help-text">Укажите путь, который будет использоваться в сгенерированном JSON файле</div> </div> <div id="fileList" class="file-list hidden"> <!-- Список загруженных файлов будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">2. Ввод данных о породах</h2> <div class="form-group"> <label>Добавить данные о породах:</label> <div class="help-text">Введите данные в формате: Код_Породы Название (каждая порода с новой строки)</div> <textarea id="rockDataInput" placeholder="1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит"></textarea> </div> <div class="actions"> <button id="parseDataBtn">Обработать данные</button> <button id="addRockBtn" class="secondary">Добавить породу вручную</button> </div> <div id="rockTableContainer" class="data-table-container hidden"> <h3>Список пород:</h3> <table id="rockTable"> <thead> <tr> <th>Код породы</th> <th>Наименование породы</th> <th>SVG файл</th> <th>Действия</th> </tr> </thead> <tbody id="rockTableBody"> <!-- Данные о породах будут здесь --> </tbody> </table> </div> </div> <div class="section"> <h2 class="section-title">3. Предварительный просмотр</h2> <div id="previewContainer" class="preview-container"> <!-- Предварительный просмотр будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">4. Генерация шаблона</h2> <div class="form-group"> <label>Название палитры:</label> <input type="text" id="paletteName" value="тест_лито"> </div> <div class="form-group"> <label>Название шаблона корреляции:</label> <input type="text" id="templateName" value="Корреляционный шаблон"> </div> <div class="form-group"> <label>Размер patternWidth для SVG:</label> <input type="number" id="patternWidth" value="20" min="1" max="100"> <div class="help-text">Размер маркера для всех SVG текстур (рекомендуется 20)</div> </div> <div class="actions"> <button id="generateBtn">Сгенерировать JSON шаблон</button> <button id="downloadBtn" class="secondary hidden">Скачать шаблон</button> </div> <div id="messageArea"></div> <div id="jsonOutput" class="hidden"> <h3>Сгенерированный JSON:</h3> <pre id="jsonContent"></pre> </div> </div> </div> <script> // Переменные для хранения данных let svgFiles = {}; let rockData = []; // Элементы DOM const svgFolderInput = document.getElementById('svgFolderInput'); const svgFilePathInput = document.getElementById('svgFilePath'); const patternWidthInput = document.getElementById('patternWidth'); const fileList = document.getElementById('fileList'); const rockDataInput = document.getElementById('rockDataInput'); const parseDataBtn = document.getElementById('parseDataBtn'); const addRockBtn = document.getElementById('addRockBtn'); const rockTableContainer = document.getElementById('rockTableContainer'); const rockTableBody = document.getElementById('rockTableBody'); const previewContainer = document.getElementById('previewContainer'); const paletteNameInput = document.getElementById('paletteName'); const templateNameInput = document.getElementById('templateName'); const generateBtn = document.getElementById('generateBtn'); const downloadBtn = document.getElementById('downloadBtn'); const messageArea = document.getElementById('messageArea'); const jsonOutput = document.getElementById('jsonOutput'); const jsonContent = document.getElementById('jsonContent'); // Функция для преобразования SVG в формат как в оригинале function convertSvgToOriginalFormat(svgContent) { // Создаем временный div для парсинга SVG const tempDiv = document.createElement('div'); tempDiv.innerHTML = svgContent; const svgElement = tempDiv.querySelector('svg'); if (!svgElement) return svgContent; // Создаем SVG с атрибутами как в оригинале let originalSvg = `<?xml version='1.0' encoding='UTF-8'?>\n<svg id="svg1" height="142px" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" viewBox="0 0 282 142" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" width="282px" xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.1">\n <metadata>\n <rdf:RDF>\n <cc:Work>\n <dc:title>ИСИХОГИ_Литология</dc:title>\n </cc:Work>\n </rdf:RDF>\n </metadata>\n <defs id="defs1"/>\n <g id="layer1">\n`; // Добавляем все path элементы const paths = svgElement.querySelectorAll('path'); paths.forEach(path => { const id = path.getAttribute('id') || ''; const d = path.getAttribute('d') || ''; const strokeWidth = path.getAttribute('stroke-width') || ''; const style = path.getAttribute('style') || ''; originalSvg += ` <path id="${id}" d="${d}" stroke-width="${strokeWidth}" style="${style}"/>\n`; }); // Добавляем все line элементы в формате оригинала const lines = svgElement.querySelectorAll('line'); lines.forEach(line => { const id = line.getAttribute('id') || ''; const x1 = line.getAttribute('x1') || ''; const y1 = line.getAttribute('y1') || ''; const x2 = line.getAttribute('x2') || ''; const y2 = line.getAttribute('y2') || ''; const strokeWidth = line.getAttribute('stroke-width') || ''; const style = line.getAttribute('style') || ''; originalSvg += ` <line id="${id}" x1="${x1}" y1="${y1}" y2="${y2}" stroke-width="${strokeWidth}" style="${style}" x2="${x2}"/>\n`; }); // Добавляем все ellipse элементы в формате оригинала const ellipses = svgElement.querySelectorAll('ellipse'); ellipses.forEach(ellipse => { const id = ellipse.getAttribute('id') || ''; const cx = ellipse.getAttribute('cx') || ''; const cy = ellipse.getAttribute('cy') || ''; const rx = ellipse.getAttribute('rx') || ''; const ry = ellipse.getAttribute('ry') || ''; const strokeWidth = ellipse.getAttribute('stroke-width') || ''; const fill = ellipse.getAttribute('fill') || ''; const stroke = ellipse.getAttribute('stroke') || ''; originalSvg += ` <ellipse id="${id}" cx="${cx}" fill="${fill}" rx="${rx}" cy="${cy}" stroke-width="${strokeWidth}" stroke="${stroke}" ry="${ry}"/>\n`; }); originalSvg += ` </g>\n</svg>\n`; return originalSvg; } // Функция для правильного экранирования SVG контента для XML function escapeSvgForXml(svgContent) { // Сначала преобразуем SVG в формат оригинала let convertedSvg = convertSvgToOriginalFormat(svgContent); // Затем экранируем все специальные символы - ИСПРАВЛЕНА ОШИБКА С КАВЫЧКАМИ let escaped = convertedSvg .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); // Заменяем переносы строк escaped = escaped.replace(/\n/g, ' '); return escaped; } // Обработка загрузки SVG файлов svgFolderInput.addEventListener('change', function(e) { const files = Array.from(e.target.files); svgFiles = {}; // Очистка списка файлов fileList.innerHTML = ''; // Фильтрация только SVG файлов const svgFilesList = files.filter(file => file.name.toLowerCase().endsWith('.svg')); if (svgFilesList.length === 0) { fileList.innerHTML = '<div>SVG файлы не найдены</div>'; fileList.classList.remove('hidden'); return; } // Обработка каждого SVG файла svgFilesList.forEach(file => { const fileName = file.name; const codeMatch = fileName.match(/^(\d+)/); if (codeMatch) { const code = codeMatch[1]; const reader = new FileReader(); reader.onload = function(e) { const svgContent = e.target.result; svgFiles[code] = { name: fileName, content: svgContent }; // Добавление в список файлов const fileItem = document.createElement('div'); fileItem.className = 'file-item'; fileItem.innerHTML = ` <div class="file-name">${fileName}</div> <div class="file-size">${(file.size / 1024).toFixed(2)} KB</div> `; fileList.appendChild(fileItem); // Обновление таблицы пород, если код уже есть updateRockTableWithSvg(code); }; reader.readAsText(file); } }); fileList.classList.remove('hidden'); showMessage(`Загружено ${svgFilesList.length} SVG файлов`, 'success'); }); // Обработка данных о породах parseDataBtn.addEventListener('click', function() { const inputText = rockDataInput.value.trim(); if (!inputText) { showMessage('Введите данные о породах', 'error'); return; } const lines = inputText.split('\n'); rockData = []; lines.forEach(line => { const trimmedLine = line.trim(); if (trimmedLine) { const parts = trimmedLine.split(/\s+/); if (parts.length >= 2) { const code = parts[0]; const name = parts.slice(1).join(' '); rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); } } }); updateRockTable(); updatePreview(); showMessage(`Обработано ${rockData.length} пород`, 'success'); }); // Добавление породы вручную addRockBtn.addEventListener('click', function() { const code = prompt('Введите код породы:'); if (!code) return; const name = prompt('Введите название породы:'); if (!name) return; rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); updateRockTable(); updatePreview(); showMessage(`Добавлена порода: ${code} ${name}`, 'success'); }); // Обновление таблицы пород function updateRockTable() { rockTableBody.innerHTML = ''; if (rockData.length === 0) { rockTableContainer.classList.add('hidden'); return; } rockData.forEach((rock, index) => { const row = document.createElement('tr'); row.innerHTML = ` <td>${rock.code}</td> <td>${rock.name}</td> <td>${rock.svgFile || 'Не найден'}</td> <td> <button onclick="removeRock(${index})">Удалить</button> </td> `; rockTableBody.appendChild(row); }); rockTableContainer.classList.remove('hidden'); } // Обновление таблицы при наличии SVG function updateRockTableWithSvg(code) { rockData.forEach(rock => { if (rock.code === code) { rock.svgFile = svgFiles[code].name; } }); updateRockTable(); updatePreview(); } // Удаление породы function removeRock(index) { rockData.splice(index, 1); updateRockTable(); updatePreview(); showMessage('Порода удалена', 'success'); } // Обновление предварительного просмотра function updatePreview() { previewContainer.innerHTML = ''; if (rockData.length === 0) { previewContainer.innerHTML = '<p>Нет данных для предварительного просмотра</p>'; return; } rockData.forEach(rock => { const previewItem = document.createElement('div'); previewItem.className = 'preview-item'; let svgPreview = '<div>SVG не загружен</div>'; if (rock.svgFile && svgFiles[rock.code]) { svgPreview = svgFiles[rock.code].content; } previewItem.innerHTML = ` <div class="preview-svg">${svgPreview}</div> <div class="preview-code">${rock.code}</div> <div class="preview-name">${rock.name}</div> `; previewContainer.appendChild(previewItem); }); } // Генерация JSON шаблона generateBtn.addEventListener('click', function() { if (rockData.length === 0) { showMessage('Нет данных о породах для генерации шаблона', 'error'); return; } const paletteName = paletteNameInput.value || 'тест_лито'; const templateName = templateNameInput.value || 'Корреляционный шаблон'; const svgFilePath = svgFilePathInput.value || 'C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/'; const patternWidth = patternWidthInput.value || '20'; // Создание элементов палитры const paletteItems = rockData.map(rock => { let svgContent = ''; if (rock.svgFile && svgFiles[rock.code]) { // Правильное экранирование SVG для XML svgContent = escapeSvgForXml(svgFiles[rock.code].content); } // Генерация случайного ID const id = Date.now() + Math.floor(Math.random() * 1000); // Полный путь к файлу SVG const fullSvgFilePath = svgFilePath + rock.svgFile; // Точный порядок атрибутов как в оригинале return { "color": "#ffffffff", "data": `<StyledFill id="${id}" name="" objectName="" brushColor="#000000" penColor="#000000" group="">\n <SvgFill patternWidth="${patternWidth}" svgContent="${svgContent}" lineWidth="0.4" objectName="" penWidth="0.4" svgFilePath="${fullSvgFilePath}"/>\n</StyledFill>\n`, "desc": rock.name, "value": parseInt(rock.code) }; }); // Создание основного JSON объекта с фиксированными ID как в рабочем примере // corrTemplates теперь пустой массив const templateJson = { "Info": "OISTerra CorrTemplates", "Palettes": [ { "Items": paletteItems, "id": Date.now(), "name": paletteName, "transp": true, "type": 1 } ], "ScoPaletteVersion": 1, "corrTemplates": [], // Пустой массив, как требуется "corrTemplatesVersion": 0 }; // Отображение JSON с правильным форматированием jsonContent.textContent = JSON.stringify(templateJson, null, 2); jsonOutput.classList.remove('hidden'); downloadBtn.classList.remove('hidden'); // Сохранение JSON для скачивания window.generatedJson = templateJson; showMessage('JSON шаблон успешно сгенерирован', 'success'); }); // Скачивание JSON файла downloadBtn.addEventListener('click', function() { if (!window.generatedJson) { showMessage('Нет сгенерированного JSON для скачивания', 'error'); return; } const dataStr = JSON.stringify(window.generatedJson, null, 2); const dataBlob = new Blob([dataStr], {type: 'application/json'}); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = 'литология_шаблон.json'; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); showMessage('Файл успешно скачан', 'success'); }); // Функция для отображения сообщений function showMessage(message, type) { messageArea.innerHTML = `<div class="message ${type}">${message}</div>`; // Автоматическое скрытие сообщения через 5 секунд setTimeout(() => { messageArea.innerHTML = ''; }, 5000); } // Инициализация при загрузке страницы window.onload = function() { // Добавляем пример данных для демонстрации rockDataInput.value = `1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит`; }; </script> </body> </html> |
Среда, 2026-02-04, 14:19
# 10
<!DOCTYPE html>
<html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Генератор шаблонов литологии</title> <style> /* Все стили остаются без изменений */ * { box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { margin: 0; padding: 20px; background-color: #f5f7fa; color: #333; } .container { max-width: 1200px; margin: 0 auto; background-color: white; border-radius: 10px; box-shadow: 0 0 20px rgba(0, 0, 0, 0.1); padding: 25px; } h1 { color: #2c3e50; text-align: center; margin-bottom: 30px; border-bottom: 2px solid #3498db; padding-bottom: 15px; } .section { margin-bottom: 30px; padding: 20px; border-radius: 8px; background-color: #f8f9fa; } .section-title { font-size: 1.3rem; color: #2c3e50; margin-bottom: 15px; display: flex; align-items: center; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: 600; color: #2c3e50; } input, textarea, select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; } textarea { min-height: 100px; resize: vertical; } button { background-color: #3498db; color: white; border: none; padding: 12px 20px; border-radius: 4px; cursor: pointer; font-size: 16px; font-weight: 600; transition: background-color 0.3s; } button:hover { background-color: #2980b9; } button.secondary { background-color: #95a5a6; } button.secondary:hover { background-color: #7f8c8d; } table { width: 100%; border-collapse: collapse; margin-top: 10px; } th, td { border: 1px solid #ddd; padding: 12px; text-align: left; } th { background-color: #3498db; color: white; } tr:nth-child(even) { background-color: #f2f2f2; } .preview-container { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 20px; } .preview-item { border: 1px solid #ddd; border-radius: 8px; padding: 15px; width: 200px; text-align: center; background-color: white; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .preview-svg { height: 100px; display: flex; align-items: center; justify-content: center; margin-bottom: 10px; } .preview-svg svg { max-width: 100%; max-height: 100%; } .preview-code { font-weight: bold; color: #2c3e50; } .preview-name { color: #7f8c8d; font-size: 0.9rem; } .hidden { display: none; } .message { padding: 15px; border-radius: 4px; margin: 15px 0; } .success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .error { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .actions { display: flex; gap: 10px; margin-top: 20px; } .file-input-container { position: relative; overflow: hidden; display: inline-block; width: 100%; } .file-input-container input[type=file] { position: absolute; left: 0; top: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; } .file-input-button { display: block; padding: 10px; background: #f8f9fa; border: 2px dashed #3498db; border-radius: 4px; text-align: center; color: #3498db; font-weight: 600; } .file-list { margin-top: 10px; max-height: 150px; overflow-y: auto; border: 1px solid #ddd; border-radius: 4px; padding: 10px; } .file-item { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid #eee; } .file-item:last-child { border-bottom: none; } .file-name { flex-grow: 1; } .file-size { color: #7f8c8d; font-size: 0.8rem; } .data-table-container { overflow-x: auto; } .help-text { font-size: 0.9rem; color: #7f8c8d; margin-top: 5px; } /* Новые стили для JSON отображения */ #jsonContent { background-color: #f8f9fa; border: 1px solid #ddd; border-radius: 4px; padding: 15px; max-height: 500px; overflow-y: auto; white-space: pre-wrap; word-wrap: break-word; font-family: 'Courier New', monospace; font-size: 12px; line-height: 1.4; } </style> </head> <body> <div class="container"> <h1>Генератор шаблонов литологии</h1> <div class="section"> <h2 class="section-title">1. Загрузка SVG-файлов с текстурами</h2> <div class="form-group"> <label>Выберите папку с SVG-файлами:</label> <div class="file-input-container"> <div class="file-input-button">Выбрать папку с SVG-файлами</div> <input type="file" id="svgFolderInput" webkitdirectory multiple> </div> <div class="help-text">SVG-файлы должны быть названы в формате "Код_Породы Название.svg", например: "1000 Лед.svg"</div> </div> <div class="form-group"> <label>Путь к SVG файлам в программе:</label> <input type="text" id="svgFilePath" placeholder="C:/Users/User/AppData/Local/OISTerra/OISTerraManager/svg/" value="C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/"> <div class="help-text">Укажите путь, который будет использоваться в сгенерированном JSON файле</div> </div> <div id="fileList" class="file-list hidden"> <!-- Список загруженных файлов будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">2. Ввод данных о породах</h2> <div class="form-group"> <label>Добавить данные о породах:</label> <div class="help-text">Введите данные в формате: Код_Породы Название (каждая порода с новой строки)</div> <textarea id="rockDataInput" placeholder="1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит"></textarea> </div> <div class="actions"> <button id="parseDataBtn">Обработать данные</button> <button id="addRockBtn" class="secondary">Добавить породу вручную</button> </div> <div id="rockTableContainer" class="data-table-container hidden"> <h3>Список пород:</h3> <table id="rockTable"> <thead> <tr> <th>Код породы</th> <th>Наименование породы</th> <th>SVG файл</th> <th>Действия</th> </tr> </thead> <tbody id="rockTableBody"> <!-- Данные о породах будут здесь --> </tbody> </table> </div> </div> <div class="section"> <h2 class="section-title">3. Предварительный просмотр</h2> <div id="previewContainer" class="preview-container"> <!-- Предварительный просмотр будет здесь --> </div> </div> <div class="section"> <h2 class="section-title">4. Генерация шаблона</h2> <div class="form-group"> <label>Название палитры:</label> <input type="text" id="paletteName" value="тест_лито"> </div> <div class="form-group"> <label>Размер patternWidth для SVG:</label> <input type="number" id="patternWidth" value="20" min="1" max="100"> <div class="help-text">Размер маркера для всех SVG текстур (рекомендуется 20)</div> </div> <div class="actions"> <button id="generateBtn">Сгенерировать JSON шаблон</button> <button id="downloadBtn" class="secondary hidden">Скачать шаблон</button> </div> <div id="messageArea"></div> <div id="jsonOutput" class="hidden"> <h3>Сгенерированный JSON:</h3> <pre id="jsonContent"></pre> </div> </div> </div> <script> // Переменные для хранения данных let svgFiles = {}; let rockData = []; // Элементы DOM const svgFolderInput = document.getElementById('svgFolderInput'); const svgFilePathInput = document.getElementById('svgFilePath'); const patternWidthInput = document.getElementById('patternWidth'); const fileList = document.getElementById('fileList'); const rockDataInput = document.getElementById('rockDataInput'); const parseDataBtn = document.getElementById('parseDataBtn'); const addRockBtn = document.getElementById('addRockBtn'); const rockTableContainer = document.getElementById('rockTableContainer'); const rockTableBody = document.getElementById('rockTableBody'); const previewContainer = document.getElementById('previewContainer'); const paletteNameInput = document.getElementById('paletteName'); const generateBtn = document.getElementById('generateBtn'); const downloadBtn = document.getElementById('downloadBtn'); const messageArea = document.getElementById('messageArea'); const jsonOutput = document.getElementById('jsonOutput'); const jsonContent = document.getElementById('jsonContent'); // Функция для преобразования SVG в формат как в оригинале function convertSvgToOriginalFormat(svgContent) { // Создаем временный div для парсинга SVG const tempDiv = document.createElement('div'); tempDiv.innerHTML = svgContent; const svgElement = tempDiv.querySelector('svg'); if (!svgElement) return svgContent; // Создаем SVG с атрибутами как в оригинале let originalSvg = `<?xml version='1.0' encoding='UTF-8'?>\n<svg id="svg1" height="142px" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" viewBox="0 0 282 142" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" width="282px" xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.1">\n <metadata>\n <rdf:RDF>\n <cc:Work>\n <dc:title>ИСИХОГИ_Литология</dc:title>\n </cc:Work>\n </rdf:RDF>\n </metadata>\n <defs id="defs1"/>\n <g id="layer1">\n`; // Добавляем все path элементы const paths = svgElement.querySelectorAll('path'); paths.forEach(path => { const id = path.getAttribute('id') || ''; const d = path.getAttribute('d') || ''; const strokeWidth = path.getAttribute('stroke-width') || ''; const style = path.getAttribute('style') || ''; originalSvg += ` <path id="${id}" d="${d}" stroke-width="${strokeWidth}" style="${style}"/>\n`; }); // Добавляем все line элементы в формате оригинала const lines = svgElement.querySelectorAll('line'); lines.forEach(line => { const id = line.getAttribute('id') || ''; const x1 = line.getAttribute('x1') || ''; const y1 = line.getAttribute('y1') || ''; const x2 = line.getAttribute('x2') || ''; const y2 = line.getAttribute('y2') || ''; const strokeWidth = line.getAttribute('stroke-width') || ''; const style = line.getAttribute('style') || ''; originalSvg += ` <line id="${id}" x1="${x1}" y1="${y1}" y2="${y2}" stroke-width="${strokeWidth}" style="${style}" x2="${x2}"/>\n`; }); // Добавляем все ellipse элементы в формате оригинала const ellipses = svgElement.querySelectorAll('ellipse'); ellipses.forEach(ellipse => { const id = ellipse.getAttribute('id') || ''; const cx = ellipse.getAttribute('cx') || ''; const cy = ellipse.getAttribute('cy') || ''; const rx = ellipse.getAttribute('rx') || ''; const ry = ellipse.getAttribute('ry') || ''; const strokeWidth = ellipse.getAttribute('stroke-width') || ''; const fill = ellipse.getAttribute('fill') || ''; const stroke = ellipse.getAttribute('stroke') || ''; originalSvg += ` <ellipse id="${id}" cx="${cx}" fill="${fill}" rx="${rx}" cy="${cy}" stroke-width="${strokeWidth}" stroke="${stroke}" ry="${ry}"/>\n`; }); originalSvg += ` </g>\n</svg>\n`; return originalSvg; } // Функция для правильного экранирования SVG контента для XML function escapeSvgForXml(svgContent) { // Сначала преобразуем SVG в формат оригинала let convertedSvg = convertSvgToOriginalFormat(svgContent); // Затем экранируем все специальные символы - ИСПРАВЛЕНА ОШИБКА С КАВЫЧКАМИ let escaped = convertedSvg .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); // Заменяем переносы строк escaped = escaped.replace(/\n/g, ' '); return escaped; } // Обработка загрузки SVG файлов svgFolderInput.addEventListener('change', function(e) { const files = Array.from(e.target.files); svgFiles = {}; // Очистка списка файлов fileList.innerHTML = ''; // Фильтрация только SVG файлов const svgFilesList = files.filter(file => file.name.toLowerCase().endsWith('.svg')); if (svgFilesList.length === 0) { fileList.innerHTML = '<div>SVG файлы не найдены</div>'; fileList.classList.remove('hidden'); return; } // Обработка каждого SVG файла svgFilesList.forEach(file => { const fileName = file.name; const codeMatch = fileName.match(/^(\d+)/); if (codeMatch) { const code = codeMatch[1]; const reader = new FileReader(); reader.onload = function(e) { const svgContent = e.target.result; svgFiles[code] = { name: fileName, content: svgContent }; // Добавление в список файлов const fileItem = document.createElement('div'); fileItem.className = 'file-item'; fileItem.innerHTML = ` <div class="file-name">${fileName}</div> <div class="file-size">${(file.size / 1024).toFixed(2)} KB</div> `; fileList.appendChild(fileItem); // Обновление таблицы пород, если код уже есть updateRockTableWithSvg(code); }; reader.readAsText(file); } }); fileList.classList.remove('hidden'); showMessage(`Загружено ${svgFilesList.length} SVG файлов`, 'success'); }); // Обработка данных о породах parseDataBtn.addEventListener('click', function() { const inputText = rockDataInput.value.trim(); if (!inputText) { showMessage('Введите данные о породах', 'error'); return; } const lines = inputText.split('\n'); rockData = []; lines.forEach(line => { const trimmedLine = line.trim(); if (trimmedLine) { const parts = trimmedLine.split(/\s+/); if (parts.length >= 2) { const code = parts[0]; const name = parts.slice(1).join(' '); rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); } } }); updateRockTable(); updatePreview(); showMessage(`Обработано ${rockData.length} пород`, 'success'); }); // Добавление породы вручную addRockBtn.addEventListener('click', function() { const code = prompt('Введите код породы:'); if (!code) return; const name = prompt('Введите название породы:'); if (!name) return; rockData.push({ code: code, name: name, svgFile: svgFiles[code] ? svgFiles[code].name : null }); updateRockTable(); updatePreview(); showMessage(`Добавлена порода: ${code} ${name}`, 'success'); }); // Обновление таблицы пород function updateRockTable() { rockTableBody.innerHTML = ''; if (rockData.length === 0) { rockTableContainer.classList.add('hidden'); return; } rockData.forEach((rock, index) => { const row = document.createElement('tr'); row.innerHTML = ` <td>${rock.code}</td> <td>${rock.name}</td> <td>${rock.svgFile || 'Не найден'}</td> <td> <button onclick="removeRock(${index})">Удалить</button> </td> `; rockTableBody.appendChild(row); }); rockTableContainer.classList.remove('hidden'); } // Обновление таблицы при наличии SVG function updateRockTableWithSvg(code) { rockData.forEach(rock => { if (rock.code === code) { rock.svgFile = svgFiles[code].name; } }); updateRockTable(); updatePreview(); } // Удаление породы function removeRock(index) { rockData.splice(index, 1); updateRockTable(); updatePreview(); showMessage('Порода удалена', 'success'); } // Обновление предварительного просмотра function updatePreview() { previewContainer.innerHTML = ''; if (rockData.length === 0) { previewContainer.innerHTML = '<p>Нет данных для предварительного просмотра</p>'; return; } rockData.forEach(rock => { const previewItem = document.createElement('div'); previewItem.className = 'preview-item'; let svgPreview = '<div>SVG не загружен</div>'; if (rock.svgFile && svgFiles[rock.code]) { svgPreview = svgFiles[rock.code].content; } previewItem.innerHTML = ` <div class="preview-svg">${svgPreview}</div> <div class="preview-code">${rock.code}</div> <div class="preview-name">${rock.name}</div> `; previewContainer.appendChild(previewItem); }); } // Генерация JSON шаблона generateBtn.addEventListener('click', function() { if (rockData.length === 0) { showMessage('Нет данных о породах для генерации шаблона', 'error'); return; } const paletteName = paletteNameInput.value || 'тест_лито'; const svgFilePath = svgFilePathInput.value || 'C:/Users/StamberskiyAA/AppData/Local/OISTerra/OISTerraManager/svg/'; const patternWidth = patternWidthInput.value || '20'; // Создание элементов палитры const paletteItems = rockData.map(rock => { let svgContent = ''; if (rock.svgFile && svgFiles[rock.code]) { // Правильное экранирование SVG для XML svgContent = escapeSvgForXml(svgFiles[rock.code].content); } // Генерация случайного ID const id = Date.now() + Math.floor(Math.random() * 1000); // Полный путь к файлу SVG const fullSvgFilePath = svgFilePath + rock.svgFile; // Точный порядок атрибутов как в оригинале return { "color": "#ffffffff", "data": `<StyledFill id="${id}" name="" objectName="" brushColor="#000000" penColor="#000000" group="">\n <SvgFill patternWidth="${patternWidth}" svgContent="${svgContent}" lineWidth="0.4" objectName="" penWidth="0.4" svgFilePath="${fullSvgFilePath}"/>\n</StyledFill>\n`, "desc": rock.name, "value": parseInt(rock.code) }; }); // Создание основного JSON объекта с фиксированными ID как в рабочем примере // corrTemplates теперь пустой массив const templateJson = { "Info": "OISTerra CorrTemplates", "Palettes": [ { "Items": paletteItems, "id": Date.now(), "name": paletteName, "transp": true, "type": 1 } ], "ScoPaletteVersion": 1, "corrTemplates": [], "corrTemplatesVersion": 0 }; // Отображение JSON с правильным форматированием jsonContent.textContent = JSON.stringify(templateJson, null, 2); jsonOutput.classList.remove('hidden'); downloadBtn.classList.remove('hidden'); // Сохранение JSON для скачивания window.generatedJson = templateJson; showMessage('JSON шаблон успешно сгенерирован', 'success'); }); // Скачивание JSON файла downloadBtn.addEventListener('click', function() { if (!window.generatedJson) { showMessage('Нет сгенерированного JSON для скачивания', 'error'); return; } const dataStr = JSON.stringify(window.generatedJson, null, 2); const dataBlob = new Blob([dataStr], {type: 'application/json'}); const url = URL.createObjectURL(dataBlob); const link = document.createElement('a'); link.href = url; link.download = 'литология_шаблон.json'; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); showMessage('Файл успешно скачан', 'success'); }); // Функция для отображения сообщений function showMessage(message, type) { messageArea.innerHTML = `<div class="message ${type}">${message}</div>`; // Автоматическое скрытие сообщения через 5 секунд setTimeout(() => { messageArea.innerHTML = ''; }, 5000); } // Инициализация при загрузке страницы window.onload = function() { // Добавляем пример данных для демонстрации rockDataInput.value = `1300 Суглинок 1700 Илы 1800 Торф 1400 Супесь 2300 Аргиллит 2400 Алевролит`; }; </script> </body> </html> |
Четверг, 2026-02-05, 10:26
# 11
SELECT
class.node_name node_name, class.node_id, spck.lcode_spck LCODE_SPECK FROM mr_dba.classifier class LEFT JOIN mr_dba.speck_spck spck ON class.lcode_speck = id_speck_spck WHERE class.node_id LIKE 'A0301%' AND length(class.node_id) >= 5 AND REGEXP_LIKE(class.node_id, '^A0301[0-9]+$') and class.node_name <> '-' |
Четверг, 2026-02-05, 10:33
# 12
SELECT
class.node_name, class.node_id, class.lcode_speck, spck.id_speck_spck, spck.lcode_spck FROM mr_dba.classifier class LEFT JOIN mr_dba.speck_spck spck ON class.lcode_speck = spck.id_speck_spck WHERE class.node_id LIKE 'A0301%' AND length(class.node_id) >= 5 AND REGEXP_LIKE(class.node_id, '^A0301[0-9]+$') AND class.node_name <> '-' ORDER BY class.node_id; |
Понедельник, 2026-02-09, 12:05
# 13
Ошибка: The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.
|
Понедельник, 2026-02-09, 13:47
# 15
тттт
Прикрепления:
6619215.txt
(116.1 Kb)
|
| |||


