Удален файл CSS_FIX_GUIDE.md, который содержал инструкции по исправлению проблем со стилями в Docker. Обновлены зависимости в package-lock.json и package.json для улучшения совместимости с Tailwind CSS и PostCSS. Внесены изменения в конфигурацию PostCSS и удален устаревший файл tailwind.config.js. Обновлены стили в globals.css для улучшения структуры и добавлены новые переменные. Добавлен новый элемент в боковое меню для тестирования стилей.

This commit is contained in:
Bivekich
2025-07-01 22:25:01 +03:00
parent 249a07fc2b
commit 80b699ff4e
13 changed files with 801 additions and 452 deletions

View File

@ -138,6 +138,12 @@ export interface LaximoDetail {
description?: string
applicablemodels?: string
note?: string
amount?: string
range?: string
codeonimage?: string
match?: boolean
dateRange?: string
ssd?: string
attributes?: LaximoDetailAttribute[]
}
@ -1079,12 +1085,18 @@ class LaximoService {
if (vehicleId) {
command += `|VehicleId=${vehicleId}`
}
if (ssd && ssd.trim() !== '') {
// 🎯 ИСПРАВЛЕНИЕ: Для категорий каталога НЕ используем SSD
// SSD используется только для QuickGroup'ов, но не для категорий
if (categoryId) {
// Если указана категория, НЕ добавляем SSD - показываем ВСЕ узлы категории
command += `|CategoryId=${categoryId}`
console.log('🔧 Режим "От производителя": используем CategoryId БЕЗ SSD для получения всех узлов категории')
} else if (ssd && ssd.trim() !== '') {
// SSD добавляем только если НЕТ CategoryId (для QuickGroup'ов)
const escapedSsd = this.escapeSsdForXML(ssd)
command += `|ssd=${escapedSsd}`
}
if (categoryId) {
command += `|CategoryId=${categoryId}`
console.log('🔧 Режим "Общие": используем SSD для получения узлов автомобиля')
}
const hmac = this.createHMAC(command)
@ -1452,6 +1464,9 @@ class LaximoService {
const xmlText = await response.text()
console.log('📥 RAW XML ответ длиной:', xmlText.length, 'символов')
console.log('📄 ПОЛНЫЙ XML ОТВЕТ:')
console.log(xmlText)
console.log('📄 ======= КОНЕЦ XML =======')
console.log('📄 Первые 1000 символов XML:')
console.log(xmlText.substring(0, 1000))
@ -1748,19 +1763,49 @@ class LaximoService {
* Парсит ответ информации об автомобиле
*/
private parseVehicleInfoResponse(xmlText: string): LaximoVehicleInfo | null {
console.log('🔍 parseVehicleInfoResponse - начинаем парсинг...')
console.log('📄 XML длина:', xmlText.length)
console.log('📄 XML первые 500 символов:', xmlText.substring(0, 500))
const resultData = this.extractResultData(xmlText)
if (!resultData) return null
if (!resultData) {
console.log('❌ Не удалось извлечь resultData')
return null
}
console.log('📋 resultData первые 500 символов:', resultData.substring(0, 500))
const rowMatch = resultData.match(/<row([^>]*)>([\s\S]*?)<\/row>/)
if (!rowMatch) return null
if (!rowMatch) {
console.log('❌ Не найден тег <row>')
return null
}
console.log('✅ Найден тег <row>')
const attributes = rowMatch[1]
const content = rowMatch[2]
console.log('📋 Атрибуты row:', attributes)
const getAttribute = (name: string): string => {
const match = attributes.match(new RegExp(`${name}="([^"]*)"`, 'i'))
return match ? match[1] : ''
}
const vehicleid = getAttribute('vehicleid')
const name = getAttribute('name')
const ssd = getAttribute('ssd')
const brand = getAttribute('brand')
const catalog = getAttribute('catalog')
console.log('🔍 Извлеченные атрибуты:', {
vehicleid,
name,
brand,
catalog,
ssd: ssd ? `${ssd.substring(0, 50)}...` : 'отсутствует',
ssdLength: ssd?.length
})
// Парсим атрибуты автомобиля
const vehicleAttributes: LaximoVehicleAttribute[] = []
@ -2087,7 +2132,7 @@ class LaximoService {
throw new Error('SSD parameter is required for ListQuickDetail')
}
const command = `ListQuickDetail:Locale=ru_RU|Catalog=${catalogCode}|VehicleId=${vehicleId}|QuickGroupId=${quickGroupId}|ssd=${ssd}`
const command = `ListQuickDetail:Locale=ru_RU|Catalog=${catalogCode}|VehicleId=${vehicleId}|QuickGroupId=${quickGroupId}|ssd=${ssd}|Localized=true|All=1`
const hmac = this.createHMAC(command)
console.log('📝 ListQuickDetail Command:', command)
@ -2115,9 +2160,19 @@ class LaximoService {
return null
}
// Ищем секцию ListQuickDetail
const quickDetailMatch = resultData.match(/<ListQuickDetail[^>]*>([\s\S]*?)<\/ListQuickDetail>/) ||
resultData.match(/<response[^>]*>([\s\S]*?)<\/response>/)
// Декодируем HTML entities в XML для правильного парсинга
const decodedXML = resultData
.replace(/&amp;/g, '&')
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&quot;/g, '"')
.replace(/&#39;/g, "'")
// Ищем секцию ListQuickDetail в декодированном XML
const quickDetailMatch = decodedXML.match(/<ListQuickDetail[^>]*>([\s\S]*?)<\/ListQuickDetail>/) ||
decodedXML.match(/<response[^>]*>([\s\S]*?)<\/response>/)
if (!quickDetailMatch) {
console.log('❌ Не найдена секция ListQuickDetail')
@ -2174,30 +2229,116 @@ class LaximoService {
details: []
}
// В каждом узле ищем детали (Detail)
const detailPattern = /<Detail([^>]*?)(?:\s*\/>|>([\s\S]*?)<\/Detail>)/g
let detailMatch
console.log('🔍 Содержимое узла (первые 1000 символов):')
console.log(unitContent.substring(0, 1000))
console.log('🔍 Ищем детали в содержимом узла...')
// ВАЖНО: Детали могут быть как внутри Unit content, так и в атрибутах самого Unit
// Сначала ищем в содержимом узла
const detailTagCount = (unitContent.match(/<Detail/g) || []).length
console.log(`🔍 Общее количество тегов <Detail в содержимом: ${detailTagCount}`)
while ((detailMatch = detailPattern.exec(unitContent)) !== null) {
const detailAttributes = detailMatch[1]
const detailContent = detailMatch[2] || ''
// Также проверяем весь блок Unit на предмет деталей
const fullUnitBlock = unitMatch[0] // Полный блок Unit включая все его содержимое
const fullUnitDetailCount = (fullUnitBlock.match(/<Detail/g) || []).length
console.log(`🔍 Общее количество тегов <Detail в полном блоке Unit: ${fullUnitDetailCount}`)
// Будем искать детали в полном блоке Unit, а не только в unitContent
const searchContent = fullUnitBlock
console.log('🔍 Поиск деталей в полном блоке Unit (первые 500 символов):')
console.log(searchContent.substring(0, 500))
const detailMatches: Array<{attributes: string, content: string, fullMatch: string}> = []
// ИСПРАВЛЕНО: Ищем все теги Detail (самозакрывающиеся и полные) в одном регулярном выражении
const detailPattern = /<Detail([^>]*?)(?:\s*\/>|>([\s\S]*?)<\/Detail>)/g
let match
while ((match = detailPattern.exec(searchContent)) !== null) {
detailMatches.push({
attributes: match[1] || '',
content: match[2] || '',
fullMatch: match[0]
})
}
console.log(`🔍 Найдено ${detailMatches.length} элементов Detail в узле`)
let detailCount = 0
for (const detailMatch of detailMatches) {
detailCount++
const detailAttributes = detailMatch.attributes || ''
const detailContent = detailMatch.content || ''
console.log(`🔍 Raw detail match #${detailCount}:`)
console.log('Attributes:', detailAttributes.substring(0, 200))
if (detailContent) {
console.log('Content:', detailContent.substring(0, 200))
}
const detailId = this.extractAttribute(detailAttributes, 'detailid')
const detailName = this.extractAttribute(detailAttributes, 'name')
const oem = this.extractAttribute(detailAttributes, 'oem')
const brand = this.extractAttribute(detailAttributes, 'brand')
const codeonimage = this.extractAttribute(detailAttributes, 'codeonimage')
console.log('🔩 Найдена деталь:', { detailId, detailName, oem, brand })
console.log(`🔩 Найдена деталь #${detailCount}: ${detailName} (${oem})`)
const detail: LaximoDetail = {
detailid: detailId,
detailid: detailId || codeonimage || oem,
name: detailName,
oem: oem,
brand: brand,
attributes: []
}
// Парсим атрибуты детали
// Парсим атрибуты детали из тега Detail
const amount = this.extractAttribute(detailAttributes, 'amount')
const dateRange = this.extractAttribute(detailAttributes, 'date_range')
const matchAttr = this.extractAttribute(detailAttributes, 'match')
const range = this.extractAttribute(detailAttributes, 'range')
const ssdAttr = this.extractAttribute(detailAttributes, 'ssd')
// Добавляем все найденные атрибуты в деталь
if (amount) {
detail.amount = amount
detail.attributes?.push({
key: 'amount',
name: 'Количество',
value: amount
})
}
if (dateRange) {
detail.dateRange = dateRange
detail.attributes?.push({
key: 'date_range',
name: 'date_range',
value: dateRange
})
}
if (matchAttr) {
detail.match = matchAttr === 't' || matchAttr === 'true'
}
if (range) {
detail.range = range
detail.attributes?.push({
key: 'range',
name: 'Диапазон',
value: range
})
}
if (ssdAttr) {
detail.ssd = ssdAttr
}
if (codeonimage) {
detail.codeonimage = codeonimage
}
// Парсим дополнительные атрибуты из содержимого детали
const attributePattern = /<attribute([^>]*?)(?:\s*\/>)/g
let attrMatch
@ -2224,6 +2365,60 @@ class LaximoService {
unit.details!.push(detail)
}
console.log(`📊 Найдено деталей в узле "${unitName}": ${detailCount}`)
// Если детали не найдены, попробуем альтернативный подход
if (detailCount === 0) {
console.log('🔍 Детали не найдены стандартным способом, пробуем альтернативный парсинг...')
// Поиск деталей в исходном XML блоке (до декодирования)
const originalUnitBlock = unitMatch[0]
console.log('🔍 Исходный XML блок (первые 1000 символов):')
console.log(originalUnitBlock.substring(0, 1000))
// Ищем детали в исходном формате
const originalDetailPattern = /<Detail[^>]*(?:\s*\/>|>[\s\S]*?<\/Detail>)/g
let originalMatch
let altDetailCount = 0
while ((originalMatch = originalDetailPattern.exec(originalUnitBlock)) !== null) {
altDetailCount++
const detailTag = originalMatch[0]
console.log(`🔍 Альтернативный парсинг - найдена деталь #${altDetailCount}:`)
console.log(detailTag.substring(0, 300))
// Простой парсинг атрибутов из тега
const nameMatch = detailTag.match(/name="([^"]*)"/)
const oemMatch = detailTag.match(/oem="([^"]*)"/)
const codeMatch = detailTag.match(/codeonimage="([^"]*)"/)
const amountMatch = detailTag.match(/amount="([^"]*)"/)
if (nameMatch || oemMatch) {
const altDetail: LaximoDetail = {
detailid: codeMatch?.[1] || oemMatch?.[1] || `alt_${altDetailCount}`,
name: nameMatch?.[1] || 'Неизвестная деталь',
oem: oemMatch?.[1] || '',
attributes: []
}
if (amountMatch) {
altDetail.attributes?.push({
key: 'amount',
name: 'Количество',
value: amountMatch[1]
})
}
unit.details!.push(altDetail)
console.log(`🔩 Альтернативный парсинг - добавлена деталь: ${altDetail.name} (${altDetail.oem})`)
}
}
if (altDetailCount > 0) {
console.log(`✅ Альтернативный парсинг нашел ${altDetailCount} деталей`)
}
}
quickDetail.units!.push(unit)
}
}
@ -2232,7 +2427,7 @@ class LaximoService {
if (quickDetail.units!.length === 0) {
console.log('🔄 Пробуем альтернативный формат парсинга...')
// Ищем узлы напрямую
// Ищем узлы напрямую в декодированном XML
const directUnitPattern = /<row([^>]*?)(?:\s*\/>|>([\s\S]*?)<\/row>)/g
let directUnitMatch
@ -2261,6 +2456,31 @@ class LaximoService {
console.log(`✅ Обработано ${quickDetail.units!.length} узлов в группе ${quickGroupId}`)
// Подсчитываем общее количество деталей
const totalDetails = quickDetail.units!.reduce((total, unit) => total + (unit.details?.length || 0), 0)
console.log(`📊 Общее количество деталей: ${totalDetails}`)
// Выводим детальную информацию о каждом узле
quickDetail.units!.forEach((unit, index) => {
console.log(`📦 Узел #${index + 1}: ${unit.name} (${unit.details?.length || 0} деталей)`)
unit.details?.forEach((detail, detailIndex) => {
const amountAttr = detail.attributes?.find(attr => attr.key === 'amount')
const amountStr = amountAttr ? ` - ${amountAttr.value}` : ''
console.log(` 🔩 Деталь #${detailIndex + 1}: ${detail.name} (${detail.oem})${amountStr}`)
})
})
// Дополнительная диагностика
if (totalDetails === 0) {
console.log('⚠️ НЕ НАЙДЕНО НИ ОДНОЙ ДЕТАЛИ!')
console.log('🔍 Оригинальные данные (первые 1000 символов):')
console.log(resultData?.substring(0, 1000))
console.log('🔍 Декодированные данные (первые 1000 символов):')
console.log(decodedXML.substring(0, 1000))
} else {
console.log(`✅ Успешно найдено ${totalDetails} деталей`)
}
if (quickDetail.units!.length === 0) {
return null
}
@ -2479,52 +2699,58 @@ class LaximoService {
details: []
}
// В каждом узле ищем детали (Detail)
const detailPattern = /<Detail([^>]*?)(?:\s*\/>|>([\s\S]*?)<\/Detail>)/g
// В каждом узле ищем детали (Detail) - поддерживаем как самозакрывающиеся, так и полные теги
// Используем более простой подход: сначала найдем все вхождения тега Detail
console.log('🔍 Поиск деталей в полном блоке Unit (первые 500 символов):')
console.log(unitMatch[0].substring(0, 500))
// Ищем все теги Detail внутри текущего Unit
const detailPattern = /<Detail[^>]*(?:\s*\/>|>[^<]*<\/Detail>)/g
let detailMatch
let detailCount = 0
while ((detailMatch = detailPattern.exec(unitContent)) !== null) {
// Получаем содержимое Unit для поиска деталей
const unitContentForDetails = unitMatch[2] || ''
// Ищем все детали в содержимом Unit
const allDetailMatches = [...unitContentForDetails.matchAll(/<Detail([^>]*?)(?:\s*\/>)/g)]
console.log(`🔍 Найдено ${allDetailMatches.length} самозакрывающихся тегов Detail в Unit`)
for (const detailMatch of allDetailMatches) {
const detailAttributes = detailMatch[1]
const detailContent = detailMatch[2] || ''
console.log(`🔍 Raw detail match #${detailCount + 1}:`)
console.log('Attributes:', detailAttributes.substring(0, 150))
const detailId = this.extractAttribute(detailAttributes, 'detailid')
const detailName = this.extractAttribute(detailAttributes, 'name')
// Извлекаем основные атрибуты детали
const name = this.extractAttribute(detailAttributes, 'name')
const oem = this.extractAttribute(detailAttributes, 'oem')
const brand = this.extractAttribute(detailAttributes, 'brand')
const amount = this.extractAttribute(detailAttributes, 'amount')
const range = this.extractAttribute(detailAttributes, 'range')
console.log('🔩 Найдена деталь:', { detailId, detailName, oem, brand })
const codeonimage = this.extractAttribute(detailAttributes, 'codeonimage')
const match = this.extractAttribute(detailAttributes, 'match')
const dateRange = this.extractAttribute(detailAttributes, 'date_range')
const ssd = this.extractAttribute(detailAttributes, 'ssd')
const detail: LaximoOEMDetail = {
detailid: detailId,
name: detailName,
oem: oem,
brand: brand,
amount: amount,
range: range,
if (name && oem) {
const detail: LaximoDetail = {
detailid: `${unitId}_${detailCount}`,
name,
oem,
brand: '',
amount: amount || '1pcs',
range: dateRange || '',
codeonimage: codeonimage || '',
match: match === 't',
dateRange: dateRange || '',
ssd: ssd || '',
applicablemodels: '',
note: '',
attributes: []
}
// Парсим атрибуты детали
const attributePattern = /<attribute([^>]*?)(?:\s*\/>)/g
let attrMatch
while ((attrMatch = attributePattern.exec(detailContent)) !== null) {
const attrAttributes = attrMatch[1]
const key = this.extractAttribute(attrAttributes, 'key')
const name = this.extractAttribute(attrAttributes, 'name')
const value = this.extractAttribute(attrAttributes, 'value')
detail.attributes?.push({
key,
name: name || key,
value
})
console.log(`🔩 Найдена деталь #${detailCount + 1}: ${detail.name} (${detail.oem})`)
unit.details!.push(detail)
detailCount++
}
unit.details.push(detail)
}
category.units.push(unit)
@ -3026,7 +3252,7 @@ export class LaximoUnitService extends LaximoService {
console.log('📋 Параметры:', { catalogCode, vehicleId, unitId, ssd: ssd ? `${ssd.substring(0, 30)}...` : 'отсутствует' })
// Используем GetUnitInfo согласно документации Laximo
let command = `GetUnitInfo:Locale=ru_RU|Catalog=${catalogCode}|UnitId=${unitId}`
let command = `GetUnitInfo:Locale=ru_RU|Catalog=${catalogCode}|VehicleId=${vehicleId}|UnitId=${unitId}`
if (ssd && ssd.trim() !== '') {
command += `|ssd=${ssd}`
@ -3061,7 +3287,7 @@ export class LaximoUnitService extends LaximoService {
console.log('📋 Параметры:', { catalogCode, vehicleId, unitId, ssd: ssd ? `${ssd.substring(0, 30)}...` : 'отсутствует' })
// Используем ListDetailByUnit согласно документации Laximo
let command = `ListDetailByUnit:Locale=ru_RU|Catalog=${catalogCode}|UnitId=${unitId}`
let command = `ListDetailByUnit:Locale=ru_RU|Catalog=${catalogCode}|VehicleId=${vehicleId}|UnitId=${unitId}`
if (ssd && ssd.trim() !== '') {
command += `|ssd=${ssd}`
@ -3099,7 +3325,7 @@ export class LaximoUnitService extends LaximoService {
console.log('📋 Параметры:', { catalogCode, vehicleId, unitId, ssd: ssd ? `${ssd.substring(0, 30)}...` : 'отсутствует' })
// Используем ListImageMapByUnit согласно документации Laximo
let command = `ListImageMapByUnit:Catalog=${catalogCode}|UnitId=${unitId}`
let command = `ListImageMapByUnit:Catalog=${catalogCode}|VehicleId=${vehicleId}|UnitId=${unitId}`
if (ssd && ssd.trim() !== '') {
command += `|ssd=${ssd}`
@ -3107,6 +3333,9 @@ export class LaximoUnitService extends LaximoService {
command += `|ssd=`
}
// Добавляем WithLinks=true согласно документации
command += `|WithLinks=true`
const hmac = this.createHMAC(command)
console.log('📝 ListImageMapByUnit Command:', command)