/
var
/
www
/
qr4y.com
/
server
/
delivery
/
api
/
controllers
/
qr
/
/var/www/qr4y.com/server/delivery/api/controllers/qr
mkdir
upload
Name
Size
Mode
Actions
css/
-
0755
rm
script/
-
0755
rm
main.js
771
0644
edit
dl
rm
menu.js
10260
0644
edit
dl
rm
Edit:
/var/www/qr4y.com/server/delivery/api/controllers/qr/menu.js
(10260B)
const { NotFound } = require('../../responseModels/errors') const { isNumber } = require('../../utils/validator.util') const { isSet, isEmpty } = require('../../utils/validator.util') const config = require('../../../config/app.json') const path = require('path'); const { readFileSync } = require('fs'); module.exports = function ({ db, logger }) { return async (req, res, next) => { logger.child({ path: req.path, request: req.query }).info() let t1 = performance.now() try { const { id } = req.params if (!isSet(id) || isEmpty(id)) throw new BadRequest({ code: 1027, lang: req.user?.languageCode }) // return res.sendFile('/wwwroot/tools/websocket/index.html', { root: APP_ROOT }) // const time = performance.now() - t1 // return res.status(200).json({ id, time }) var companyName = ''; var companyDesc = ''; var companyImage = ''; const branchId = id.slice(0, -2); // id без последних двух символов -o -b -c res.redirect('https://qr4y.com/app#/branch?id=' + branchId); return; const branch = await db.branch.findOne({ where: { id: branchId }, }) if (!branch) { return res.status(404).send('Company not found'); } const company = await db.company.findOne({ where: { id: branch.companyId }, include: [{ model: db.companyImage, as: 'companyImages' }] }) const productGroups = await db.productGroup.findAll({ where: { companyId: company.id }, include: [ { model: db.product, as: 'products', include: [ { model: db.productImage, as: 'productImages' } ] }, ] }) // Функция для выбора нужного языка из строки с тегами function getLocalizedString(str, lang = 'ru') { if (!str) return ''; const regex = new RegExp(`<${lang}>([^<]*)`); const match = str.match(regex); if (match && match[1]) return match[1].trim(); // fallback на русский if (lang !== 'ru') { const ruMatch = str.match(/<ru>([^<]*)/); if (ruMatch && ruMatch[1]) return ruMatch[1].trim(); } // если ничего не найдено, вернуть исходную строку без тегов return str.replace(/<[^>]+>/g, '').trim(); } if (company) { // Получаем язык пользователя, по умолчанию 'ru' const lang = req.user?.languageCode || 'ru'; companyName = getLocalizedString(company?.name, lang); companyDesc = getLocalizedString(company?.description, lang); companyImage = company?.companyImages[0]?.image ?? ''; // Горизонтальное меню групп const groupMenu = ` <nav class="group-menu" id="groupMenu"> ${productGroups.map((group, idx) => `<a href="#group-${idx}" class="group-menu-link" id="group-link-${idx}">${getLocalizedString(group.name, lang)}</a>` ).join('')} </nav> `; context = ` ${groupMenu} <div class="menu-groups"> `; productGroups.forEach((productGroup, idx) => { context += ` <section class="group-section" id="group-${idx}"> <h2 class="group-title">${getLocalizedString(productGroup.name, lang)}</h2> <div class="products-grid"> ${productGroup.products .filter(product => { // Фильтрация: только товары с ценой не '0' let price = 0; if (product.price_json) { const price_arr = JSON.parse(product.price_json); if (price_arr && price_arr['pc']?.length > 0) { price = price_arr['pc'][0]['v'][0]['p'][0]['p'] ?? '0'; } else { price = '0'; } } else { price = product.price; } return price && price !== '0'; }) .map((product, productIdx) => { let price = 0; let name = '-'; if (product.price_json) { const price_arr = JSON.parse(product.price_json); if (price_arr && price_arr['pc']?.length > 0) { price = price_arr['pc'][0]['v'][0]['p'][0]['p'] ?? '0'; name = price_arr['pc'][0]['v'][0]['n']; } else { price = '0'; } } else { price = product.price; name = product.name; } const img = product.productImages[0]?.imageSmall ? `${config.images.url}${product.productImages[0].imageSmall}` : `data:image/svg+xml;utf8,<svg width="200" height="180" viewBox="0 0 200 180" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="200" height="180" rx="16" fill="%23f0f0f0"/><g><circle cx="100" cy="90" r="40" fill="%23e0e0e0"/><rect x="60" y="120" width="80" height="20" rx="8" fill="%23d0d0d0"/></g><g><rect x="80" y="60" width="40" height="40" rx="8" fill="%23bdbdbd"/><rect x="90" y="70" width="20" height="20" rx="4" fill="%23fff"/></g></svg>`; const imgFull = product.productImages[0]?.image ? `${config.images.url}${product.productImages[0].imageSmall}` : `data:image/svg+xml;utf8,<svg width="200" height="180" viewBox="0 0 200 180" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="200" height="180" rx="16" fill="%23f0f0f0"/><g><circle cx="100" cy="90" r="40" fill="%23e0e0e0"/><rect x="60" y="120" width="80" height="20" rx="8" fill="%23d0d0d0"/></g><g><rect x="80" y="60" width="40" height="40" rx="8" fill="%23bdbdbd"/><rect x="90" y="70" width="20" height="20" rx="4" fill="%23fff"/></g></svg>`; const productData = encodeURIComponent(JSON.stringify({ name: getLocalizedString(name, lang), description: getLocalizedString(product.description, lang), price: price, currency: company.currency, img: img, imgFull: imgFull, })); return ` <div class="product-card" data-product="${productData}"> <img src='${img}' alt="${getLocalizedString(name, lang)}" class="product-img"> <div class="product-info"> <h3 class="product-name">${getLocalizedString(name, lang)}</h3> <p class="product-price">${price} ${company.currency}</p> </div> </div> `; }).join('')} </div> </section> `; }); context += `</div>`; } else { context = `<div class="not-found">Компания не найдена</div>`; } // Добавляем стили // const css = readFileSync(`./css/menu.css`, 'utf8'); const css = readFileSync(path.join(__dirname, './css/menu.css'), 'utf8'); const script = readFileSync(path.join(__dirname, './script/menu.js'), 'utf8'); body = ` <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>QR4Y Menu - ${companyName}</title> <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap" rel="stylesheet"> <style> ${css} </style> <script> ${script} </script> </head> <body> <div id="productDetails" class="product-details"></div> <div id="mainView"> <div class="menu-header" style="background: url('${config.images.url}${companyImage}') center/cover no-repeat;"></div> <div class="menu-title"> <img src="${config.images.url}${company?.image}" alt="Logo ${companyName}" class="logo"> <div> <h1 class="menu-header-h1">${companyName}</h1> <h2 class="menu-header-h2">${companyDesc}</h2> </div> </div> ${context} </div> </body> </html> ` res.setHeader('Content-Type', 'text/html'); res.setHeader('Content-Length', Buffer.byteLength(body)); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Pragma', 'no-cache'); res.setHeader('Expires', '0'); res.send(body); } catch (err) { next(err) } } }
Save
cmd:
run