From 00cf2ebd9a4a427bd6420f3f33a600c1d7f0704e Mon Sep 17 00:00:00 2001 From: kalugin66 Date: Tue, 4 Aug 2026 13:22:46 +0500 Subject: [PATCH] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=BA=D1=80=D0=B0?= =?UTF-8?q?=D0=B9=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/siteData/index.js | 114 ++++++++--------- modules/ssrRenderer.js | 250 ++++++++++++++++++++++++++++++++++++++ public/index.html | 57 ++++++++- server.js | 31 ++++- 4 files changed, 385 insertions(+), 67 deletions(-) create mode 100644 modules/ssrRenderer.js diff --git a/modules/siteData/index.js b/modules/siteData/index.js index 174031b..0514df1 100644 --- a/modules/siteData/index.js +++ b/modules/siteData/index.js @@ -12,63 +12,65 @@ function loadEquipmentGallery(data) { }); } +function loadSiteData() { + const data = {}; + + function loadTable(table, key) { + return new Promise((resolve) => { + db.all(`SELECT * FROM ${table} ORDER BY sort_order`, (err, rows) => { + if (err) { data[key] = []; resolve(); return; } + if (table === 'equipment' || table === 'partners') { + rows = rows.filter(r => r.is_active == 1); + } + if (table === 'services' || table === 'work_schemes') { + rows = rows.filter(r => r.is_active == 1); + } + data[key] = rows; + resolve(); + }); + }); + } + + function loadSettings(table, key, transformFn) { + return new Promise((resolve) => { + db.all(`SELECT * FROM ${table} ORDER BY id`, (err, rows) => { + if (err) { data[key] = {}; resolve(); return; } + if (transformFn) { + data[key] = transformFn(rows); + } else { + const obj = {}; + rows.forEach(r => { obj[r.key] = r.value; }); + data[key] = obj; + } + resolve(); + }); + }); + } + + return Promise.all([ + loadSettings('hero_settings', 'hero'), + loadTable('hero_stats', 'hero_stats'), + loadSettings('about_settings', 'about'), + loadTable('about_features', 'about_features'), + loadTable('services', 'services'), + loadTable('work_schemes', 'work_schemes'), + loadTable('process_steps', 'process_steps'), + loadTable('equipment', 'equipment'), + loadEquipmentGallery(data), + loadTable('geo_regions', 'geo_regions'), + loadSettings('geo_settings', 'geo'), + loadTable('licenses', 'licenses'), + loadTable('license_gallery', 'license_gallery'), + loadTable('public_activities', 'public_activities'), + loadTable('activity_gallery', 'activity_gallery'), + loadTable('partners', 'partners'), + loadSettings('settings', 'settings') + ]).then(() => data); +} + function setupRoutes(app) { app.get('/api/site-data', (req, res) => { - const data = {}; - - function loadTable(table, key) { - return new Promise((resolve) => { - db.all(`SELECT * FROM ${table} ORDER BY sort_order`, (err, rows) => { - if (err) { data[key] = []; resolve(); return; } - if (table === 'equipment' || table === 'partners') { - rows = rows.filter(r => r.is_active == 1); - } - if (table === 'services' || table === 'work_schemes') { - rows = rows.filter(r => r.is_active == 1); - } - data[key] = rows; - resolve(); - }); - }); - } - - function loadSettings(table, key, transformFn) { - return new Promise((resolve) => { - db.all(`SELECT * FROM ${table} ORDER BY id`, (err, rows) => { - if (err) { data[key] = {}; resolve(); return; } - if (transformFn) { - data[key] = transformFn(rows); - } else { - const obj = {}; - rows.forEach(r => { obj[r.key] = r.value; }); - data[key] = obj; - } - resolve(); - }); - }); - } - - Promise.all([ - loadSettings('hero_settings', 'hero'), - loadTable('hero_stats', 'hero_stats'), - loadSettings('about_settings', 'about'), - loadTable('about_features', 'about_features'), - loadTable('services', 'services'), - loadTable('work_schemes', 'work_schemes'), - loadTable('process_steps', 'process_steps'), - loadTable('equipment', 'equipment'), - loadEquipmentGallery(data), - loadTable('geo_regions', 'geo_regions'), - loadSettings('geo_settings', 'geo'), - loadTable('licenses', 'licenses'), - loadTable('license_gallery', 'license_gallery'), - loadTable('public_activities', 'public_activities'), - loadTable('activity_gallery', 'activity_gallery'), - loadTable('partners', 'partners'), - loadSettings('settings', 'settings') - ]).then(() => { - res.json(data); - }); + loadSiteData().then(data => res.json(data)); }); app.post('/api/leads', (req, res) => { @@ -83,4 +85,4 @@ function setupRoutes(app) { }); } -module.exports = { init, setupRoutes }; +module.exports = { init, setupRoutes, loadSiteData }; diff --git a/modules/ssrRenderer.js b/modules/ssrRenderer.js new file mode 100644 index 0000000..3a5359f --- /dev/null +++ b/modules/ssrRenderer.js @@ -0,0 +1,250 @@ +const yearsSince2011 = new Date().getFullYear() - 2011; + +function esc(s) { return String(s||'').replace(/&/g,'&').replace(/"/g,'"').replace(//g,'>'); } + +function imgSrc(path) { + if (!path) return './img/hero-bg.webp'; + if (path.startsWith('./')) return path; + if (path.startsWith('http')) return path; + if (/^(equipment|partner|license|activity|hero)_images\//.test(path)) return '/data/' + path; + return './img/' + path; +} + +function renderHero(data) { + var h = data.hero || {}; + var stats = data.hero_stats || []; + var phone800 = h.phone_800 || '8 (800) 555-29-31'; + var phoneEkb = h.phone_ekb || '8 (343) 237-25-66'; + var email = h.email || 'sts_zakaz@mail.ru'; + var address = h.address || 'г. Екатеринбург, ул. Московская, 11, оф. 702'; + + var contactsHtml = ''; + if (phone800 && phoneEkb) { + contactsHtml += '
' + phone800 + '
' + phoneEkb + '
'; + } + contactsHtml += '
' + email + '
'; + contactsHtml += '
' + address + '
'; + + var statsHtml = ''; + stats.forEach(function(s) { + var val = s.is_dynamic == 1 ? yearsSince2011 : s.value; + statsHtml += '
' + val + '
' + s.label + '
'; + }); + + var badgeHtml = h.badge_text ? '
' + h.badge_text + '
' : ''; + var h1text = (h.h1_text || 'демонтаж нефтегазопроводов по России, утилизация отходов').replace('{years}', yearsSince2011); + + return badgeHtml + + '

' + h1text + '

' + + '

' + (h.subtitle || '').replace('{years}', yearsSince2011) + '

' + + '
' + contactsHtml + '
' + + '
' + + '' + (h.button1_text || 'Оставить заявку') + '' + + '' + (h.button2_text || 'Наши услуги') + '' + + '
' + + '
' + statsHtml + '
'; +} + +function renderAbout(data) { + var a = data.about || {}; + var features = data.about_features || []; + var featsHtml = features.map(function(f) { + return '
' + (f.svg_icon || '') + '
' + f.title + '' + (f.description || '') + '
'; + }).join(''); + + return '

О компании

' + (a.section_subtitle || '') + '

' + + '
' + + '
' + + '

' + (a.main_heading || '') + '

' + + (a.paragraph_1 ? '

' + a.paragraph_1 + '

' : '') + + (a.paragraph_2 ? '

' + a.paragraph_2 + '

' : '') + + (a.paragraph_3 ? '

' + a.paragraph_3 + '

' : '') + + '
' + featsHtml + '
'; +} + +function renderServices(data) { + var services = data.services || []; + var st = data.settings || {}; + var cardsHtml = services.map(function(s) { + var items = []; + try { items = JSON.parse(s.items || '[]'); } catch(e) {} + return '
' + + '
' + (s.svg_icon || '') + '
' + + '

' + s.title + '

' + (s.description || '') + '

' + + (items.length ? '' : '') + + '
'; + }).join(''); + return '

Наши услуги

' + (st.section_services_subtitle || '') + '

' + + '
' + cardsHtml + '
'; +} + +function renderSchemes(data) { + var schemes = data.work_schemes || []; + var st = data.settings || {}; + var cardsHtml = schemes.map(function(s) { + var items = []; + try { items = JSON.parse(s.items || '[]'); } catch(e) {} + return '
' + + '
' + (s.svg_icon || '') + '
' + + '

' + s.title + '

' + (s.description || '') + '

' + + (items.length ? '' : '') + + '
'; + }).join(''); + return '

Гибкие схемы работы

' + (st.section_schemes_subtitle || '') + '

' + + '
' + cardsHtml + '
'; +} + +function renderProcess(data) { + var steps = data.process_steps || []; + var st = data.settings || {}; + var stepsHtml = steps.map(function(s) { + return '
' + (s.step_number || s.sort_order + 1) + '

' + s.title + '

' + (s.description || '') + '

'; + }).join(''); + return '

Этапы работы

' + (st.section_process_subtitle || '') + '

' + + '
' + stepsHtml + '
'; +} + +function renderEquipment(data) { + var eq = data.equipment || []; + var gallery = data.equipment_gallery || []; + var st = data.settings || {}; + + function getImages(e) { + var imgs = []; + if (gallery.length) { + gallery.filter(function(g) { return g.equipment_id === e.id; }).forEach(function(g) { + if (g.image_path) imgs.push(g.image_path); + }); + } + if (imgs.length === 0 && e.image_path) imgs.push(e.image_path); + return imgs; + } + + var cardsHtml = eq.map(function(e) { + var specs = []; + try { specs = JSON.parse(e.specs || '[]'); } catch(e2) {} + var imgs = getImages(e); + var imgHtml = imgs.length > 0 + ? '' + esc(e.name) + '' + : '
Нет фото
'; + + return '
' + + imgHtml + + '
' + esc(e.brand || '') + '
' + + '

' + esc(e.name) + '

' + + (e.qty ? '
' + esc(e.qty) + '
' : '') + + (specs.length ? '
' + specs.map(function(sp) { return '
' + esc(sp.label) + '' + esc(sp.value) + '
'; }).join('') + '
' : '') + + '
'; + }).join(''); + + return '

Наша спецтехника

' + esc(st.section_equipment_subtitle || '') + '

' + + '
' + cardsHtml + '
'; +} + +function renderGeography(data) { + var geo = data.geo || {}; + var regions = data.geo_regions || []; + var st = data.settings || {}; + var regionsHtml = regions.map(function(r) { + return '
' + (r.name || '') + '
'; + }).join(''); + return '

География присутствия

' + (geo.section_subtitle || st.section_services_subtitle || '') + '

' + + '
' + regionsHtml + '
' + + (geo.difficult_title ? '

' + geo.difficult_title + '

' + (geo.difficult_desc || '') + '

' : '') + + '
'; +} + +function renderLicenses(data) { + var licenses = data.licenses || []; + var gallery = data.license_gallery || []; + var st = data.settings || {}; + var cardsHtml = licenses.map(function(l) { + return '
' + (l.svg_icon || '') + '

' + l.title + '

' + (l.description || '') + '

'; + }).join(''); + var galleryHtml = gallery.map(function(g) { + return ''; + }).join(''); + return '

Лицензии и разрешения

' + (st.section_licenses_subtitle || '') + '

' + + '
' + cardsHtml + '
' + + (gallery.length ? '' : ''); +} + +function renderActivity(data) { + var acts = data.public_activities || []; + var gallery = data.activity_gallery || []; + var st = data.settings || {}; + var cardsHtml = acts.map(function(a) { + return '
' + (a.svg_icon || '') + '

' + a.title + '

' + (a.description || '') + '

'; + }).join(''); + var galleryHtml = gallery.length ? '' : ''; + return '

Общественная деятельность

' + (st.section_activity_subtitle || '') + '

' + + '
' + cardsHtml + '
' + galleryHtml; +} + +function renderPartners(data) { + var partners = data.partners || []; + var st = data.settings || {}; + var duplicated = partners.concat(partners); + var trackHtml = duplicated.map(function(p) { + return '' + esc(p.name || '') + ''; + }).join(''); + return '

Наши партнёры

' + (st.section_partners_subtitle || '') + '

' + + '
' + trackHtml + '
'; +} + +function renderContacts(data) { + var s = data.settings || {}; + var h = data.hero || {}; + var phone800 = h.phone_800 || s.contact_phone_800 || '8 (800) 555-29-31'; + var phoneEkb = h.phone_ekb || s.contact_phone_ekb || '8 (343) 237-25-66'; + var email = h.email || s.contact_email || 'sts_zakaz@mail.ru'; + var address = h.address || s.contact_address || 'г. Екатеринбург, ул. Московская, 11, оф. 702'; + var workHours = (s.contact_work_hours || 'Пн–Пт: 9:00 – 18:00|Сб: 10:00 – 15:00').replace(/\|/g, '
'); + var mapImg = s.contact_map_image || './img/secret.webp'; + + return '

Свяжитесь с нами

' + (s.section_contacts_subtitle || '') + '

' + + '
' + + '
' + + '' + + '' + + '

Адрес

' + address + '

' + + '

Режим работы

' + workHours + '

' + + '
' + + '
' + + '

' + (s.form_title || 'Оставить заявку') + '

' + + '

' + (s.form_subtitle || 'Заполните форму и мы свяжемся с вами') + '

' + + '
' + + '
' + + '
' + + '
' + + '' + + '' + + '
' + + '

Заявка отправлена!

Мы свяжемся с вами в ближайшее время

' + + '
'; +} + +function renderAll(data) { + return { + heroContent: renderHero(data), + aboutContainer: renderAbout(data), + servicesContainer: renderServices(data), + schemesContainer: renderSchemes(data), + processContainer: renderProcess(data), + equipmentContainer: renderEquipment(data), + geographyContainer: renderGeography(data), + licensesContainer: renderLicenses(data), + activityContainer: renderActivity(data), + contactsContainer: renderContacts(data), + partnersContainer: renderPartners(data) + }; +} + +module.exports = { renderAll }; diff --git a/public/index.html b/public/index.html index d23be0b..1abf8ae 100644 --- a/public/index.html +++ b/public/index.html @@ -3,13 +3,55 @@ -СТС-Авто — Демонтаж нефтегазопроводов по России, утилизация отходов - +Демонтаж нефтегазопроводов, утилизация отходов, рекультивация земель — СТС-Авто + + + + + + + + + + + + + + - - + + + +