diff --git a/ui/src/pages/ProductStockByAttributes.vue b/ui/src/pages/ProductStockByAttributes.vue index 25f9acd..d8b6273 100644 --- a/ui/src/pages/ProductStockByAttributes.vue +++ b/ui/src/pages/ProductStockByAttributes.vue @@ -758,14 +758,24 @@ async function ensureProductImage(code, color, secondColor = '', dim1Id = '', di } } } - const list = sortImagesForDisplay(productImageListByCode.value[listKey] || []) - const first = list[0] || null + const rawList = Array.isArray(productImageListByCode.value[listKey]) ? productImageListByCode.value[listKey] : [] + const primaryItem = rawList[0] || null + const secondaryItem = rawList.length > 1 ? rawList[rawList.length - 1] : null - const resolved = resolveProductImageUrl(first) - const preferredCardUrl = first ? await resolveProductImageUrlForCarousel(first) : '' + const primaryResolved = resolveProductImageUrl(primaryItem) + let preferredCardUrl = primaryItem ? await resolveProductImageUrlForCarousel(primaryItem) : '' + if (!preferredCardUrl && secondaryItem) { + preferredCardUrl = await resolveProductImageUrlForCarousel(secondaryItem) + } + const secondaryResolved = resolveProductImageUrl(secondaryItem) - productImageCache.value[key] = String(preferredCardUrl || resolved.fullUrl || resolved.publicUrl || resolved.thumbUrl || resolved.contentUrl || '').trim() - productImageFallbackByKey.value[key] = resolved.fullUrl || resolved.publicUrl || resolved.contentUrl || '' + productImageCache.value[key] = String( + preferredCardUrl || + primaryResolved.fullUrl || primaryResolved.publicUrl || primaryResolved.thumbUrl || primaryResolved.contentUrl || + secondaryResolved.fullUrl || secondaryResolved.publicUrl || secondaryResolved.thumbUrl || secondaryResolved.contentUrl || + '' + ).trim() + productImageFallbackByKey.value[key] = primaryResolved.fullUrl || primaryResolved.publicUrl || primaryResolved.contentUrl || secondaryResolved.fullUrl || secondaryResolved.publicUrl || secondaryResolved.contentUrl || '' } catch (err) { console.warn('[ProductStockByAttributes] product image fetch failed', { code, color, err }) productImageCache.value[key] = '' @@ -1789,6 +1799,15 @@ onUnmounted(() => { --pc-media-h: min(70vh, 900px); --pc-media-w: min(74vw, 1220px); background: #f9f8f5; + height: 100vh; + display: flex; + flex-direction: column; +} + +:deep(.product-card-dialog > .q-card__section:last-child) { + flex: 1 1 auto; + min-height: 0; + overflow: hidden; } .product-card-stock { @@ -1824,6 +1843,7 @@ onUnmounted(() => { gap: 14px; align-items: stretch; justify-content: start; + height: 100%; } .product-card-images { @@ -1843,6 +1863,23 @@ onUnmounted(() => { border: 1px solid #e4dac7; } +:deep(.product-card-carousel .q-carousel__navigation) { + bottom: 10px; +} + +:deep(.product-card-carousel .q-carousel__navigation .q-btn) { + color: var(--q-secondary, #26a69a); + opacity: 0.7; + transform: scale(1); + transition: transform 0.14s ease, opacity 0.14s ease, color 0.14s ease; +} + +:deep(.product-card-carousel .q-carousel__navigation .q-btn--active) { + color: var(--q-primary, #1976d2); + opacity: 1; + transform: scale(1.22); +} + .dialog-image { width: 100%; height: 100%; @@ -1896,13 +1933,15 @@ onUnmounted(() => { } :deep(.image-fullscreen-carousel .q-carousel__navigation .q-btn) { - color: rgba(38, 166, 154, 0.42); + color: var(--q-secondary, #26a69a); + opacity: 0.72; transform: scale(1); transition: transform 0.14s ease, color 0.14s ease; } :deep(.image-fullscreen-carousel .q-carousel__navigation .q-btn--active) { color: var(--q-primary, #1976d2); + opacity: 1; transform: scale(1.28); text-shadow: 0 0 0.5px currentColor; filter: drop-shadow(0 0 2px rgba(38, 166, 154, 0.45)); diff --git a/ui/src/pages/ProductStockQuery.vue b/ui/src/pages/ProductStockQuery.vue index 197c8a7..c9388d1 100644 --- a/ui/src/pages/ProductStockQuery.vue +++ b/ui/src/pages/ProductStockQuery.vue @@ -743,13 +743,23 @@ async function ensureProductImage(code, color, secondColor = '', dim1Id = '', di } } - const list = sortImagesForDisplay(productImageListByCode.value[listKey] || []) - const first = list[0] || null + const rawList = Array.isArray(productImageListByCode.value[listKey]) ? productImageListByCode.value[listKey] : [] + const primaryItem = rawList[0] || null + const secondaryItem = rawList.length > 1 ? rawList[rawList.length - 1] : null - const resolved = resolveProductImageUrl(first) - const preferredCardUrl = first ? await resolveProductImageUrlForCarousel(first) : '' - productImageCache.value[key] = String(preferredCardUrl || resolved.fullUrl || resolved.publicUrl || resolved.thumbUrl || resolved.contentUrl || '').trim() - productImageFallbackByKey.value[key] = resolved.fullUrl || resolved.publicUrl || resolved.contentUrl || '' + const primaryResolved = resolveProductImageUrl(primaryItem) + let preferredCardUrl = primaryItem ? await resolveProductImageUrlForCarousel(primaryItem) : '' + if (!preferredCardUrl && secondaryItem) { + preferredCardUrl = await resolveProductImageUrlForCarousel(secondaryItem) + } + const secondaryResolved = resolveProductImageUrl(secondaryItem) + productImageCache.value[key] = String( + preferredCardUrl || + primaryResolved.fullUrl || primaryResolved.publicUrl || primaryResolved.thumbUrl || primaryResolved.contentUrl || + secondaryResolved.fullUrl || secondaryResolved.publicUrl || secondaryResolved.thumbUrl || secondaryResolved.contentUrl || + '' + ).trim() + productImageFallbackByKey.value[key] = primaryResolved.fullUrl || primaryResolved.publicUrl || primaryResolved.contentUrl || secondaryResolved.fullUrl || secondaryResolved.publicUrl || secondaryResolved.contentUrl || '' } catch (err) { console.warn('[ProductStockQuery] product image fetch failed', { code, color, err }) productImageCache.value[key] = '' @@ -1645,6 +1655,15 @@ onMounted(() => { --pc-media-h: min(70vh, 900px); --pc-media-w: min(74vw, 1220px); background: #f9f8f5; + height: 100vh; + display: flex; + flex-direction: column; +} + +:deep(.product-card-dialog > .q-card__section:last-child) { + flex: 1 1 auto; + min-height: 0; + overflow: hidden; } .product-card-stock { @@ -1680,6 +1699,7 @@ onMounted(() => { gap: 14px; align-items: stretch; justify-content: start; + height: 100%; } .product-card-images { @@ -1699,6 +1719,23 @@ onMounted(() => { border: 1px solid #e4dac7; } +:deep(.product-card-carousel .q-carousel__navigation) { + bottom: 10px; +} + +:deep(.product-card-carousel .q-carousel__navigation .q-btn) { + color: var(--q-secondary, #26a69a); + opacity: 0.7; + transform: scale(1); + transition: transform 0.14s ease, opacity 0.14s ease, color 0.14s ease; +} + +:deep(.product-card-carousel .q-carousel__navigation .q-btn--active) { + color: var(--q-primary, #1976d2); + opacity: 1; + transform: scale(1.22); +} + .dialog-image { width: 100%; height: 100%; @@ -1752,13 +1789,15 @@ onMounted(() => { } :deep(.image-fullscreen-carousel .q-carousel__navigation .q-btn) { - color: rgba(38, 166, 154, 0.42); + color: var(--q-secondary, #26a69a); + opacity: 0.72; transform: scale(1); transition: transform 0.14s ease, color 0.14s ease; } :deep(.image-fullscreen-carousel .q-carousel__navigation .q-btn--active) { color: var(--q-primary, #1976d2); + opacity: 1; transform: scale(1.28); text-shadow: 0 0 0.5px currentColor; filter: drop-shadow(0 0 2px rgba(38, 166, 154, 0.45));