Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -579,7 +579,7 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router
|
|||||||
bindV3(r, pgDB,
|
bindV3(r, pgDB,
|
||||||
"/api/product-images/{id}/content", "GET",
|
"/api/product-images/{id}/content", "GET",
|
||||||
"order", "view",
|
"order", "view",
|
||||||
wrapV3(http.HandlerFunc(routes.GetProductImageContentHandler(pgDB))),
|
http.HandlerFunc(routes.GetProductImageContentHandler(pgDB)),
|
||||||
)
|
)
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|||||||
@@ -161,6 +161,10 @@ func GetProductImagesHandler(pg *sql.DB) http.HandlerFunc {
|
|||||||
if dim1 == "" {
|
if dim1 == "" {
|
||||||
dim1 = strings.TrimSpace(r.URL.Query().Get("color"))
|
dim1 = strings.TrimSpace(r.URL.Query().Get("color"))
|
||||||
}
|
}
|
||||||
|
dim1ID := strings.TrimSpace(r.URL.Query().Get("dim1_id"))
|
||||||
|
if dim1ID == "" {
|
||||||
|
dim1ID = strings.TrimSpace(r.URL.Query().Get("itemdim1"))
|
||||||
|
}
|
||||||
dim3 := strings.TrimSpace(r.URL.Query().Get("dim3"))
|
dim3 := strings.TrimSpace(r.URL.Query().Get("dim3"))
|
||||||
if dim3 == "" {
|
if dim3 == "" {
|
||||||
dim3 = strings.TrimSpace(r.URL.Query().Get("yaka"))
|
dim3 = strings.TrimSpace(r.URL.Query().Get("yaka"))
|
||||||
@@ -168,6 +172,10 @@ func GetProductImagesHandler(pg *sql.DB) http.HandlerFunc {
|
|||||||
if dim3 == "" {
|
if dim3 == "" {
|
||||||
dim3 = strings.TrimSpace(r.URL.Query().Get("renk2"))
|
dim3 = strings.TrimSpace(r.URL.Query().Get("renk2"))
|
||||||
}
|
}
|
||||||
|
dim3ID := strings.TrimSpace(r.URL.Query().Get("dim3_id"))
|
||||||
|
if dim3ID == "" {
|
||||||
|
dim3ID = strings.TrimSpace(r.URL.Query().Get("itemdim3"))
|
||||||
|
}
|
||||||
|
|
||||||
if code == "" {
|
if code == "" {
|
||||||
|
|
||||||
@@ -224,7 +232,9 @@ ORDER BY
|
|||||||
"req_id", reqID,
|
"req_id", reqID,
|
||||||
"code", code,
|
"code", code,
|
||||||
"dim1", dim1,
|
"dim1", dim1,
|
||||||
|
"dim1_id", dim1ID,
|
||||||
"dim3", dim3,
|
"dim3", dim3,
|
||||||
|
"dim3_id", dim3ID,
|
||||||
"err", err.Error(),
|
"err", err.Error(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -240,7 +250,9 @@ ORDER BY
|
|||||||
matchedByName := make([]ProductImageItem, 0, 16)
|
matchedByName := make([]ProductImageItem, 0, 16)
|
||||||
matchedByNameDim1Only := make([]ProductImageItem, 0, 16)
|
matchedByNameDim1Only := make([]ProductImageItem, 0, 16)
|
||||||
dim1Upper := strings.ToUpper(strings.TrimSpace(dim1))
|
dim1Upper := strings.ToUpper(strings.TrimSpace(dim1))
|
||||||
|
dim1IDUpper := strings.ToUpper(strings.TrimSpace(dim1ID))
|
||||||
dim3Upper := strings.ToUpper(strings.TrimSpace(dim3))
|
dim3Upper := strings.ToUpper(strings.TrimSpace(dim3))
|
||||||
|
dim3IDUpper := strings.ToUpper(strings.TrimSpace(dim3ID))
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
|
|
||||||
@@ -264,12 +276,16 @@ ORDER BY
|
|||||||
rowDim1ByID[it.ID] = strings.TrimSpace(rowDim1)
|
rowDim1ByID[it.ID] = strings.TrimSpace(rowDim1)
|
||||||
|
|
||||||
dimMatched := true
|
dimMatched := true
|
||||||
if dim1Upper != "" {
|
if dim1IDUpper != "" {
|
||||||
|
dimMatched = dimMatched && (rowDim1 == dim1IDUpper)
|
||||||
|
} else if dim1Upper != "" {
|
||||||
// Bazı eski kayıtlarda dimval1 gerçek renk kodu yerine numeric id tutulmuş olabilir.
|
// Bazı eski kayıtlarda dimval1 gerçek renk kodu yerine numeric id tutulmuş olabilir.
|
||||||
// Bu yüzden dimval karşılaştırması yardımcı; asıl fallback file_name token eşleşmesidir.
|
// Bu yüzden dimval karşılaştırması yardımcı; asıl fallback file_name token eşleşmesidir.
|
||||||
dimMatched = dimMatched && (rowDim1 == dim1Upper)
|
dimMatched = dimMatched && (rowDim1 == dim1Upper)
|
||||||
}
|
}
|
||||||
if dim3Upper != "" {
|
if dim3IDUpper != "" {
|
||||||
|
dimMatched = dimMatched && (rowDim3 == dim3IDUpper || rowDim2 == dim3IDUpper)
|
||||||
|
} else if dim3Upper != "" {
|
||||||
dimMatched = dimMatched && (rowDim3 == dim3Upper || rowDim2 == dim3Upper)
|
dimMatched = dimMatched && (rowDim3 == dim3Upper || rowDim2 == dim3Upper)
|
||||||
}
|
}
|
||||||
if dimMatched {
|
if dimMatched {
|
||||||
@@ -284,14 +300,14 @@ ORDER BY
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if dim1Upper != "" || dim3Upper != "" {
|
if dim1Upper != "" || dim1IDUpper != "" || dim3Upper != "" || dim3IDUpper != "" {
|
||||||
if dim3Upper != "" {
|
if dim3Upper != "" || dim3IDUpper != "" {
|
||||||
// dim3 verildiginde kesin varyant listesi oncelikli.
|
// dim3 verildiginde kesin varyant listesi oncelikli.
|
||||||
if len(matchedByName) > 0 {
|
if dim3Upper != "" && len(matchedByName) > 0 {
|
||||||
items = matchedByName
|
items = matchedByName
|
||||||
} else if len(matchedByDim) > 0 {
|
} else if len(matchedByDim) > 0 {
|
||||||
items = matchedByDim
|
items = matchedByDim
|
||||||
} else if len(matchedByNameDim1Only) > 0 {
|
} else if dim3Upper != "" && len(matchedByNameDim1Only) > 0 {
|
||||||
// dim3 pattern'i olmayan legacy tek-renk isimlerde dim1-only fallback.
|
// dim3 pattern'i olmayan legacy tek-renk isimlerde dim1-only fallback.
|
||||||
hasDim3Pattern := false
|
hasDim3Pattern := false
|
||||||
for _, it := range matchedByNameDim1Only {
|
for _, it := range matchedByNameDim1Only {
|
||||||
@@ -320,6 +336,9 @@ ORDER BY
|
|||||||
} else {
|
} else {
|
||||||
items = []ProductImageItem{}
|
items = []ProductImageItem{}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if dim1IDUpper != "" && len(matchedByDim) > 0 {
|
||||||
|
items = matchedByDim
|
||||||
} else {
|
} else {
|
||||||
targetDimval1 := make(map[string]struct{}, 4)
|
targetDimval1 := make(map[string]struct{}, 4)
|
||||||
for _, it := range matchedByName {
|
for _, it := range matchedByName {
|
||||||
@@ -354,12 +373,15 @@ ORDER BY
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
slog.Info("product_images.list.ok",
|
slog.Info("product_images.list.ok",
|
||||||
"req_id", reqID,
|
"req_id", reqID,
|
||||||
"code", code,
|
"code", code,
|
||||||
"dim1", dim1,
|
"dim1", dim1,
|
||||||
|
"dim1_id", dim1ID,
|
||||||
"dim3", dim3,
|
"dim3", dim3,
|
||||||
|
"dim3_id", dim3ID,
|
||||||
"count", len(items),
|
"count", len(items),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -184,12 +184,12 @@
|
|||||||
<q-card flat bordered class="product-image-card cursor-pointer" @click.stop="openProductCard(grp1, grp2)">
|
<q-card flat bordered class="product-image-card cursor-pointer" @click.stop="openProductCard(grp1, grp2)">
|
||||||
<q-card-section class="q-pa-xs product-image-wrap">
|
<q-card-section class="q-pa-xs product-image-wrap">
|
||||||
<q-img
|
<q-img
|
||||||
v-if="getProductImageUrl(grp1.productCode, grp2.colorCode, grp2.secondColor)"
|
v-if="getProductImageUrl(grp1.productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor, grp2.photoDim1ID || '', grp2.photoDim3ID || '')"
|
||||||
:src="getProductImageUrl(grp1.productCode, grp2.colorCode, grp2.secondColor)"
|
:src="getProductImageUrl(grp1.productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor, grp2.photoDim1ID || '', grp2.photoDim3ID || '')"
|
||||||
fit="contain"
|
fit="contain"
|
||||||
class="product-image"
|
class="product-image"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
@error="onProductImageError(grp1.productCode, grp2.colorCode, grp2.secondColor)"
|
@error="onProductImageError(grp1.productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor, grp2.photoDim1ID || '', grp2.photoDim3ID || '')"
|
||||||
/>
|
/>
|
||||||
<div v-else class="product-image-placeholder">
|
<div v-else class="product-image-placeholder">
|
||||||
<q-icon name="image_not_supported" size="22px" color="grey-6" />
|
<q-icon name="image_not_supported" size="22px" color="grey-6" />
|
||||||
@@ -465,8 +465,8 @@ function sortByTotalQtyDesc(a, b) {
|
|||||||
return String(a?.key || '').localeCompare(String(b?.key || ''), 'tr', { sensitivity: 'base' })
|
return String(a?.key || '').localeCompare(String(b?.key || ''), 'tr', { sensitivity: 'base' })
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildImageKey(code, color, secondColor = '') {
|
function buildImageKey(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
|
||||||
return `${String(code || '').trim().toUpperCase()}::${String(color || '').trim().toUpperCase()}::${String(secondColor || '').trim().toUpperCase()}`
|
return `${String(code || '').trim().toUpperCase()}::${String(color || '').trim().toUpperCase()}::${String(secondColor || '').trim().toUpperCase()}::${String(dim1Id || '').trim().toUpperCase()}::${String(dim3Id || '').trim().toUpperCase()}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeImageDim3(value) {
|
function normalizeImageDim3(value) {
|
||||||
@@ -485,6 +485,34 @@ function resolvePhotoDim3(item, secondColorDisplay = '') {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolvePhotoDim1ID(item) {
|
||||||
|
const candidates = [
|
||||||
|
item?.ItemDim1Code,
|
||||||
|
item?.itemDim1Code,
|
||||||
|
item?.ITEMDIM1CODE,
|
||||||
|
item?.RenkID,
|
||||||
|
item?.Renk_Id
|
||||||
|
]
|
||||||
|
for (const value of candidates) {
|
||||||
|
const s = String(value || '').trim()
|
||||||
|
if (/^\d+$/.test(s)) return s
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolvePhotoDim3ID(item) {
|
||||||
|
const candidates = [
|
||||||
|
item?.ItemDim3Code,
|
||||||
|
item?.itemDim3Code,
|
||||||
|
item?.ITEMDIM3CODE
|
||||||
|
]
|
||||||
|
for (const value of candidates) {
|
||||||
|
const s = String(value || '').trim()
|
||||||
|
if (/^\d+$/.test(s)) return s
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
function buildDim3Candidates(secondColor) {
|
function buildDim3Candidates(secondColor) {
|
||||||
const secondTrim = normalizeImageDim3(secondColor)
|
const secondTrim = normalizeImageDim3(secondColor)
|
||||||
if (!secondTrim) return ['']
|
if (!secondTrim) return ['']
|
||||||
@@ -493,10 +521,12 @@ function buildDim3Candidates(secondColor) {
|
|||||||
return Array.from(set)
|
return Array.from(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchProductImageList(codeTrim, colorTrim, secondTrim) {
|
async function fetchProductImageList(codeTrim, colorTrim, secondTrim, dim1IdTrim = '', dim3IdTrim = '') {
|
||||||
const dim3Candidates = buildDim3Candidates(secondTrim)
|
const dim3Candidates = buildDim3Candidates(secondTrim)
|
||||||
for (const dim3Candidate of dim3Candidates) {
|
for (const dim3Candidate of dim3Candidates) {
|
||||||
const params = { code: codeTrim, dim1: colorTrim }
|
const params = { code: codeTrim, dim1: colorTrim }
|
||||||
|
if (String(dim1IdTrim || '').trim()) params.dim1_id = String(dim1IdTrim || '').trim()
|
||||||
|
if (String(dim3IdTrim || '').trim()) params.dim3_id = String(dim3IdTrim || '').trim()
|
||||||
if (dim3Candidate) params.dim3 = dim3Candidate
|
if (dim3Candidate) params.dim3 = dim3Candidate
|
||||||
const res = await api.get('/product-images', { params })
|
const res = await api.get('/product-images', { params })
|
||||||
const list = Array.isArray(res?.data) ? res.data : []
|
const list = Array.isArray(res?.data) ? res.data : []
|
||||||
@@ -550,6 +580,8 @@ function resolveProductImageUrl(item) {
|
|||||||
|
|
||||||
async function resolveProductImageUrlForCarousel(item) {
|
async function resolveProductImageUrlForCarousel(item) {
|
||||||
const resolved = resolveProductImageUrl(item)
|
const resolved = resolveProductImageUrl(item)
|
||||||
|
const publicUrl = String(resolved.publicUrl || '').trim()
|
||||||
|
if (publicUrl) return publicUrl
|
||||||
const contentUrl = String(resolved.contentUrl || '').trim()
|
const contentUrl = String(resolved.contentUrl || '').trim()
|
||||||
if (contentUrl) {
|
if (contentUrl) {
|
||||||
try {
|
try {
|
||||||
@@ -564,50 +596,31 @@ async function resolveProductImageUrlForCarousel(item) {
|
|||||||
// fall through to public url
|
// fall through to public url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return String(resolved.publicUrl || contentUrl || '').trim()
|
return String(contentUrl || '').trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProductImageUrl(code, color, secondColor = '') {
|
function getProductImageUrl(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
|
||||||
const key = buildImageKey(code, color, secondColor)
|
const key = buildImageKey(code, color, secondColor, dim1Id, dim3Id)
|
||||||
const existing = productImageCache.value[key]
|
const existing = productImageCache.value[key]
|
||||||
if (existing !== undefined) return existing || ''
|
if (existing !== undefined) return existing || ''
|
||||||
|
|
||||||
void ensureProductImage(code, color, secondColor)
|
void ensureProductImage(code, color, secondColor, dim1Id, dim3Id)
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onProductImageError(code, color, secondColor = '') {
|
async function onProductImageError(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
|
||||||
const key = buildImageKey(code, color, secondColor)
|
const key = buildImageKey(code, color, secondColor, dim1Id, dim3Id)
|
||||||
const fallback = String(productImageFallbackByKey.value[key] || '')
|
|
||||||
if (fallback && !productImageContentLoading.value[key]) {
|
|
||||||
productImageContentLoading.value[key] = true
|
|
||||||
try {
|
|
||||||
const blobRes = await api.get(fallback, {
|
|
||||||
baseURL: '',
|
|
||||||
responseType: 'blob'
|
|
||||||
})
|
|
||||||
const blob = blobRes?.data
|
|
||||||
if (blob instanceof Blob) {
|
|
||||||
const objectUrl = URL.createObjectURL(blob)
|
|
||||||
productImageBlobUrls.value.push(objectUrl)
|
|
||||||
productImageCache.value[key] = objectUrl
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// no-op
|
|
||||||
} finally {
|
|
||||||
delete productImageContentLoading.value[key]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
productImageCache.value[key] = ''
|
productImageCache.value[key] = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ensureProductImage(code, color, secondColor = '') {
|
async function ensureProductImage(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
|
||||||
const key = buildImageKey(code, color, secondColor)
|
const key = buildImageKey(code, color, secondColor, dim1Id, dim3Id)
|
||||||
const codeTrim = String(code || '').trim().toUpperCase()
|
const codeTrim = String(code || '').trim().toUpperCase()
|
||||||
const colorTrim = String(color || '').trim().toUpperCase()
|
const colorTrim = String(color || '').trim().toUpperCase()
|
||||||
const secondTrim = String(secondColor || '').trim().toUpperCase()
|
const secondTrim = String(secondColor || '').trim().toUpperCase()
|
||||||
const listKey = buildImageKey(codeTrim, colorTrim, secondTrim)
|
const dim1IDTrim = String(dim1Id || '').trim().toUpperCase()
|
||||||
|
const dim3IDTrim = String(dim3Id || '').trim().toUpperCase()
|
||||||
|
const listKey = buildImageKey(codeTrim, colorTrim, secondTrim, dim1IDTrim, dim3IDTrim)
|
||||||
if (!codeTrim) {
|
if (!codeTrim) {
|
||||||
productImageCache.value[key] = ''
|
productImageCache.value[key] = ''
|
||||||
return ''
|
return ''
|
||||||
@@ -629,7 +642,7 @@ async function ensureProductImage(code, color, secondColor = '') {
|
|||||||
await new Promise((resolve) => imageListWaitQueue.push(resolve))
|
await new Promise((resolve) => imageListWaitQueue.push(resolve))
|
||||||
}
|
}
|
||||||
imageListActiveRequests++
|
imageListActiveRequests++
|
||||||
productImageListByCode.value[listKey] = await fetchProductImageList(codeTrim, colorTrim, secondTrim)
|
productImageListByCode.value[listKey] = await fetchProductImageList(codeTrim, colorTrim, secondTrim, dim1IDTrim, dim3IDTrim)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
productImageListByCode.value[listKey] = []
|
productImageListByCode.value[listKey] = []
|
||||||
const status = Number(err?.response?.status || 0)
|
const status = Number(err?.response?.status || 0)
|
||||||
@@ -656,8 +669,8 @@ async function ensureProductImage(code, color, secondColor = '') {
|
|||||||
|
|
||||||
const resolved = resolveProductImageUrl(first)
|
const resolved = resolveProductImageUrl(first)
|
||||||
|
|
||||||
productImageCache.value[key] = resolved.contentUrl || resolved.publicUrl || ''
|
productImageCache.value[key] = resolved.publicUrl || resolved.contentUrl || ''
|
||||||
productImageFallbackByKey.value[key] = resolved.contentUrl || ''
|
productImageFallbackByKey.value[key] = resolved.publicUrl ? '' : (resolved.contentUrl || '')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('[ProductStockByAttributes] product image fetch failed', { code, color, err })
|
console.warn('[ProductStockByAttributes] product image fetch failed', { code, color, err })
|
||||||
productImageCache.value[key] = ''
|
productImageCache.value[key] = ''
|
||||||
@@ -779,6 +792,8 @@ const level1Groups = computed(() => {
|
|||||||
const colorDesc = String(item.Renk_Aciklamasi || '').trim()
|
const colorDesc = String(item.Renk_Aciklamasi || '').trim()
|
||||||
const secondColor = String(item.Yaka || '').trim()
|
const secondColor = String(item.Yaka || '').trim()
|
||||||
const photoDim3 = resolvePhotoDim3(item, secondColor)
|
const photoDim3 = resolvePhotoDim3(item, secondColor)
|
||||||
|
const photoDim1ID = resolvePhotoDim1ID(item)
|
||||||
|
const photoDim3ID = resolvePhotoDim3ID(item)
|
||||||
const depoKodu = String(item.Depo_Kodu || '').trim()
|
const depoKodu = String(item.Depo_Kodu || '').trim()
|
||||||
const depoAdi = String(item.Depo_Adi || '').trim()
|
const depoAdi = String(item.Depo_Adi || '').trim()
|
||||||
const urunAnaGrubu = String(item.URUN_ANA_GRUBU || '').trim()
|
const urunAnaGrubu = String(item.URUN_ANA_GRUBU || '').trim()
|
||||||
@@ -808,7 +823,7 @@ const level1Groups = computed(() => {
|
|||||||
}
|
}
|
||||||
l1.totalQty += qty
|
l1.totalQty += qty
|
||||||
|
|
||||||
const l2Key = `${colorCode}|${secondColor}|${photoDim3}`
|
const l2Key = `${colorCode}|${secondColor}|${photoDim3}|${photoDim1ID}|${photoDim3ID}`
|
||||||
if (!l1.childrenMap.has(l2Key)) {
|
if (!l1.childrenMap.has(l2Key)) {
|
||||||
l1.childrenMap.set(l2Key, {
|
l1.childrenMap.set(l2Key, {
|
||||||
key: `L2|${productCode}|${l2Key}`,
|
key: `L2|${productCode}|${l2Key}`,
|
||||||
@@ -816,6 +831,8 @@ const level1Groups = computed(() => {
|
|||||||
colorDesc,
|
colorDesc,
|
||||||
secondColor,
|
secondColor,
|
||||||
photoDim3,
|
photoDim3,
|
||||||
|
photoDim1ID,
|
||||||
|
photoDim3ID,
|
||||||
urunAnaGrubu,
|
urunAnaGrubu,
|
||||||
urunAltGrubu,
|
urunAltGrubu,
|
||||||
urunIcerigi,
|
urunIcerigi,
|
||||||
@@ -1074,7 +1091,7 @@ async function fetchStockByAttributes() {
|
|||||||
function onLevel2Click(productCode, grp2) {
|
function onLevel2Click(productCode, grp2) {
|
||||||
toggleOpen(grp2.key)
|
toggleOpen(grp2.key)
|
||||||
if (isOpen(grp2.key)) {
|
if (isOpen(grp2.key)) {
|
||||||
void ensureProductImage(productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor)
|
void ensureProductImage(productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor, grp2.photoDim1ID || '', grp2.photoDim3ID || '')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1083,28 +1100,36 @@ async function openProductCard(grp1, grp2) {
|
|||||||
const colorCode = String(grp2?.colorCode || '').trim()
|
const colorCode = String(grp2?.colorCode || '').trim()
|
||||||
const secondColor = String(grp2?.secondColor || '').trim()
|
const secondColor = String(grp2?.secondColor || '').trim()
|
||||||
const photoDim3 = String(grp2?.photoDim3 || secondColor).trim()
|
const photoDim3 = String(grp2?.photoDim3 || secondColor).trim()
|
||||||
const listKey = buildImageKey(productCode, colorCode, photoDim3)
|
const photoDim1ID = String(grp2?.photoDim1ID || '').trim()
|
||||||
|
const photoDim3ID = String(grp2?.photoDim3ID || '').trim()
|
||||||
|
const listKey = buildImageKey(productCode, colorCode, photoDim3, photoDim1ID, photoDim3ID)
|
||||||
const codeTrim = String(productCode || '').trim().toUpperCase()
|
const codeTrim = String(productCode || '').trim().toUpperCase()
|
||||||
const colorTrim = String(colorCode || '').trim().toUpperCase()
|
const colorTrim = String(colorCode || '').trim().toUpperCase()
|
||||||
const secondTrim = String(photoDim3 || '').trim().toUpperCase()
|
const secondTrim = String(photoDim3 || '').trim().toUpperCase()
|
||||||
|
const dim1IDTrim = String(photoDim1ID || '').trim().toUpperCase()
|
||||||
|
const dim3IDTrim = String(photoDim3ID || '').trim().toUpperCase()
|
||||||
|
|
||||||
await ensureProductImage(productCode, colorCode, photoDim3)
|
await ensureProductImage(productCode, colorCode, photoDim3, photoDim1ID, photoDim3ID)
|
||||||
let list = Array.isArray(productImageListByCode.value[listKey]) ? productImageListByCode.value[listKey] : []
|
let list = Array.isArray(productImageListByCode.value[listKey]) ? productImageListByCode.value[listKey] : []
|
||||||
console.info('[ProductStockByAttributes][openProductCard] request', {
|
console.info('[ProductStockByAttributes][openProductCard] request', {
|
||||||
productCode,
|
productCode,
|
||||||
colorCode,
|
colorCode,
|
||||||
secondColor,
|
secondColor,
|
||||||
|
dim1ID: dim1IDTrim,
|
||||||
|
dim3ID: dim3IDTrim,
|
||||||
listKey,
|
listKey,
|
||||||
cachedListCount: list.length
|
cachedListCount: list.length
|
||||||
})
|
})
|
||||||
if (!list.length && codeTrim) {
|
if (!list.length && codeTrim) {
|
||||||
try {
|
try {
|
||||||
list = await fetchProductImageList(codeTrim, colorTrim, secondTrim)
|
list = await fetchProductImageList(codeTrim, colorTrim, secondTrim, dim1IDTrim, dim3IDTrim)
|
||||||
productImageListByCode.value[listKey] = list
|
productImageListByCode.value[listKey] = list
|
||||||
console.info('[ProductStockByAttributes][openProductCard] refetch', {
|
console.info('[ProductStockByAttributes][openProductCard] refetch', {
|
||||||
productCode: codeTrim,
|
productCode: codeTrim,
|
||||||
dim1: colorTrim,
|
dim1: colorTrim,
|
||||||
|
dim1ID: dim1IDTrim,
|
||||||
dim3: secondTrim,
|
dim3: secondTrim,
|
||||||
|
dim3ID: dim3IDTrim,
|
||||||
fetchedCount: list.length,
|
fetchedCount: list.length,
|
||||||
fileNames: list.map((x) => String(x?.file_name || x?.FileName || '').trim()).filter(Boolean)
|
fileNames: list.map((x) => String(x?.file_name || x?.FileName || '').trim()).filter(Boolean)
|
||||||
})
|
})
|
||||||
@@ -1132,7 +1157,7 @@ async function openProductCard(grp1, grp2) {
|
|||||||
const uniqueImages = Array.from(new Set(images))
|
const uniqueImages = Array.from(new Set(images))
|
||||||
|
|
||||||
if (!uniqueImages.length) {
|
if (!uniqueImages.length) {
|
||||||
const single = getProductImageUrl(productCode, colorCode, photoDim3)
|
const single = getProductImageUrl(productCode, colorCode, photoDim3, photoDim1ID, photoDim3ID)
|
||||||
if (single) uniqueImages.push(single)
|
if (single) uniqueImages.push(single)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -182,12 +182,12 @@
|
|||||||
<q-card flat bordered class="product-image-card cursor-pointer" @click.stop="openProductCard(grp1, grp2)">
|
<q-card flat bordered class="product-image-card cursor-pointer" @click.stop="openProductCard(grp1, grp2)">
|
||||||
<q-card-section class="q-pa-xs product-image-wrap">
|
<q-card-section class="q-pa-xs product-image-wrap">
|
||||||
<q-img
|
<q-img
|
||||||
v-if="getProductImageUrl(grp1.productCode, grp2.colorCode, grp2.secondColor)"
|
v-if="getProductImageUrl(grp1.productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor, grp2.photoDim1ID || '', grp2.photoDim3ID || '')"
|
||||||
:src="getProductImageUrl(grp1.productCode, grp2.colorCode, grp2.secondColor)"
|
:src="getProductImageUrl(grp1.productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor, grp2.photoDim1ID || '', grp2.photoDim3ID || '')"
|
||||||
fit="contain"
|
fit="contain"
|
||||||
class="product-image"
|
class="product-image"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
@error="onProductImageError(grp1.productCode, grp2.colorCode, grp2.secondColor)"
|
@error="onProductImageError(grp1.productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor, grp2.photoDim1ID || '', grp2.photoDim3ID || '')"
|
||||||
/>
|
/>
|
||||||
<div v-else class="product-image-placeholder">
|
<div v-else class="product-image-placeholder">
|
||||||
<q-icon name="image_not_supported" size="22px" color="grey-6" />
|
<q-icon name="image_not_supported" size="22px" color="grey-6" />
|
||||||
@@ -458,8 +458,8 @@ function sortByColorCodeAsc(a, b) {
|
|||||||
return compareCodeLike(a?.secondColor, b?.secondColor)
|
return compareCodeLike(a?.secondColor, b?.secondColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildImageKey(code, color, secondColor = '') {
|
function buildImageKey(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
|
||||||
return `${String(code || '').trim().toUpperCase()}::${String(color || '').trim().toUpperCase()}::${String(secondColor || '').trim().toUpperCase()}`
|
return `${String(code || '').trim().toUpperCase()}::${String(color || '').trim().toUpperCase()}::${String(secondColor || '').trim().toUpperCase()}::${String(dim1Id || '').trim().toUpperCase()}::${String(dim3Id || '').trim().toUpperCase()}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeImageDim3(value) {
|
function normalizeImageDim3(value) {
|
||||||
@@ -478,6 +478,34 @@ function resolvePhotoDim3(item, secondColorDisplay = '') {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolvePhotoDim1ID(item) {
|
||||||
|
const candidates = [
|
||||||
|
item?.ItemDim1Code,
|
||||||
|
item?.itemDim1Code,
|
||||||
|
item?.ITEMDIM1CODE,
|
||||||
|
item?.RenkID,
|
||||||
|
item?.Renk_Id
|
||||||
|
]
|
||||||
|
for (const value of candidates) {
|
||||||
|
const s = String(value || '').trim()
|
||||||
|
if (/^\d+$/.test(s)) return s
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolvePhotoDim3ID(item) {
|
||||||
|
const candidates = [
|
||||||
|
item?.ItemDim3Code,
|
||||||
|
item?.itemDim3Code,
|
||||||
|
item?.ITEMDIM3CODE
|
||||||
|
]
|
||||||
|
for (const value of candidates) {
|
||||||
|
const s = String(value || '').trim()
|
||||||
|
if (/^\d+$/.test(s)) return s
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
function buildDim3Candidates(secondColor) {
|
function buildDim3Candidates(secondColor) {
|
||||||
const secondTrim = normalizeImageDim3(secondColor)
|
const secondTrim = normalizeImageDim3(secondColor)
|
||||||
if (!secondTrim) return ['']
|
if (!secondTrim) return ['']
|
||||||
@@ -486,10 +514,12 @@ function buildDim3Candidates(secondColor) {
|
|||||||
return Array.from(set)
|
return Array.from(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchProductImageList(codeTrim, colorTrim, secondTrim) {
|
async function fetchProductImageList(codeTrim, colorTrim, secondTrim, dim1IdTrim = '', dim3IdTrim = '') {
|
||||||
const dim3Candidates = buildDim3Candidates(secondTrim)
|
const dim3Candidates = buildDim3Candidates(secondTrim)
|
||||||
for (const dim3Candidate of dim3Candidates) {
|
for (const dim3Candidate of dim3Candidates) {
|
||||||
const params = { code: codeTrim, dim1: colorTrim }
|
const params = { code: codeTrim, dim1: colorTrim }
|
||||||
|
if (String(dim1IdTrim || '').trim()) params.dim1_id = String(dim1IdTrim || '').trim()
|
||||||
|
if (String(dim3IdTrim || '').trim()) params.dim3_id = String(dim3IdTrim || '').trim()
|
||||||
if (dim3Candidate) params.dim3 = dim3Candidate
|
if (dim3Candidate) params.dim3 = dim3Candidate
|
||||||
const res = await api.get('/product-images', { params })
|
const res = await api.get('/product-images', { params })
|
||||||
const list = Array.isArray(res?.data) ? res.data : []
|
const list = Array.isArray(res?.data) ? res.data : []
|
||||||
@@ -537,6 +567,8 @@ function resolveProductImageUrl(item) {
|
|||||||
|
|
||||||
async function resolveProductImageUrlForCarousel(item) {
|
async function resolveProductImageUrlForCarousel(item) {
|
||||||
const resolved = resolveProductImageUrl(item)
|
const resolved = resolveProductImageUrl(item)
|
||||||
|
const publicUrl = String(resolved.publicUrl || '').trim()
|
||||||
|
if (publicUrl) return publicUrl
|
||||||
const contentUrl = String(resolved.contentUrl || '').trim()
|
const contentUrl = String(resolved.contentUrl || '').trim()
|
||||||
if (contentUrl) {
|
if (contentUrl) {
|
||||||
try {
|
try {
|
||||||
@@ -551,46 +583,30 @@ async function resolveProductImageUrlForCarousel(item) {
|
|||||||
// fall through to public url
|
// fall through to public url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return String(resolved.publicUrl || contentUrl || '').trim()
|
return String(contentUrl || '').trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProductImageUrl(code, color, secondColor = '') {
|
function getProductImageUrl(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
|
||||||
const key = buildImageKey(code, color, secondColor)
|
const key = buildImageKey(code, color, secondColor, dim1Id, dim3Id)
|
||||||
const existing = productImageCache.value[key]
|
const existing = productImageCache.value[key]
|
||||||
if (existing !== undefined) return existing || ''
|
if (existing !== undefined) return existing || ''
|
||||||
void ensureProductImage(code, color, secondColor)
|
void ensureProductImage(code, color, secondColor, dim1Id, dim3Id)
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onProductImageError(code, color, secondColor = '') {
|
async function onProductImageError(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
|
||||||
const key = buildImageKey(code, color, secondColor)
|
const key = buildImageKey(code, color, secondColor, dim1Id, dim3Id)
|
||||||
const fallback = String(productImageFallbackByKey.value[key] || '')
|
|
||||||
if (fallback && !productImageContentLoading.value[key]) {
|
|
||||||
productImageContentLoading.value[key] = true
|
|
||||||
try {
|
|
||||||
const blobRes = await api.get(fallback, { baseURL: '', responseType: 'blob' })
|
|
||||||
const blob = blobRes?.data
|
|
||||||
if (blob instanceof Blob) {
|
|
||||||
const objectUrl = URL.createObjectURL(blob)
|
|
||||||
productImageBlobUrls.value.push(objectUrl)
|
|
||||||
productImageCache.value[key] = objectUrl
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// no-op
|
|
||||||
} finally {
|
|
||||||
delete productImageContentLoading.value[key]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
productImageCache.value[key] = ''
|
productImageCache.value[key] = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ensureProductImage(code, color, secondColor = '') {
|
async function ensureProductImage(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
|
||||||
const key = buildImageKey(code, color, secondColor)
|
const key = buildImageKey(code, color, secondColor, dim1Id, dim3Id)
|
||||||
const codeTrim = String(code || '').trim().toUpperCase()
|
const codeTrim = String(code || '').trim().toUpperCase()
|
||||||
const colorTrim = String(color || '').trim().toUpperCase()
|
const colorTrim = String(color || '').trim().toUpperCase()
|
||||||
const secondTrim = String(secondColor || '').trim().toUpperCase()
|
const secondTrim = String(secondColor || '').trim().toUpperCase()
|
||||||
const listKey = buildImageKey(codeTrim, colorTrim, secondTrim)
|
const dim1IDTrim = String(dim1Id || '').trim().toUpperCase()
|
||||||
|
const dim3IDTrim = String(dim3Id || '').trim().toUpperCase()
|
||||||
|
const listKey = buildImageKey(codeTrim, colorTrim, secondTrim, dim1IDTrim, dim3IDTrim)
|
||||||
if (!codeTrim) {
|
if (!codeTrim) {
|
||||||
productImageCache.value[key] = ''
|
productImageCache.value[key] = ''
|
||||||
return ''
|
return ''
|
||||||
@@ -612,7 +628,7 @@ async function ensureProductImage(code, color, secondColor = '') {
|
|||||||
await new Promise((resolve) => imageListWaitQueue.push(resolve))
|
await new Promise((resolve) => imageListWaitQueue.push(resolve))
|
||||||
}
|
}
|
||||||
imageListActiveRequests++
|
imageListActiveRequests++
|
||||||
productImageListByCode.value[listKey] = await fetchProductImageList(codeTrim, colorTrim, secondTrim)
|
productImageListByCode.value[listKey] = await fetchProductImageList(codeTrim, colorTrim, secondTrim, dim1IDTrim, dim3IDTrim)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
productImageListByCode.value[listKey] = []
|
productImageListByCode.value[listKey] = []
|
||||||
const status = Number(err?.response?.status || 0)
|
const status = Number(err?.response?.status || 0)
|
||||||
@@ -637,8 +653,8 @@ async function ensureProductImage(code, color, secondColor = '') {
|
|||||||
const first = list[0] || null
|
const first = list[0] || null
|
||||||
|
|
||||||
const resolved = resolveProductImageUrl(first)
|
const resolved = resolveProductImageUrl(first)
|
||||||
productImageCache.value[key] = resolved.contentUrl || resolved.publicUrl || ''
|
productImageCache.value[key] = resolved.publicUrl || resolved.contentUrl || ''
|
||||||
productImageFallbackByKey.value[key] = resolved.contentUrl || ''
|
productImageFallbackByKey.value[key] = resolved.publicUrl ? '' : (resolved.contentUrl || '')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('[ProductStockQuery] product image fetch failed', { code, color, err })
|
console.warn('[ProductStockQuery] product image fetch failed', { code, color, err })
|
||||||
productImageCache.value[key] = ''
|
productImageCache.value[key] = ''
|
||||||
@@ -760,6 +776,8 @@ const level1Groups = computed(() => {
|
|||||||
const colorDesc = String(item.Renk_Aciklamasi || '').trim()
|
const colorDesc = String(item.Renk_Aciklamasi || '').trim()
|
||||||
const secondColor = String(item.Yaka || '').trim()
|
const secondColor = String(item.Yaka || '').trim()
|
||||||
const photoDim3 = resolvePhotoDim3(item, secondColor)
|
const photoDim3 = resolvePhotoDim3(item, secondColor)
|
||||||
|
const photoDim1ID = resolvePhotoDim1ID(item)
|
||||||
|
const photoDim3ID = resolvePhotoDim3ID(item)
|
||||||
const depoKodu = String(item.Depo_Kodu || '').trim()
|
const depoKodu = String(item.Depo_Kodu || '').trim()
|
||||||
const depoAdi = String(item.Depo_Adi || '').trim()
|
const depoAdi = String(item.Depo_Adi || '').trim()
|
||||||
const kategori = String(item.YETISKIN_GARSON || '').trim()
|
const kategori = String(item.YETISKIN_GARSON || '').trim()
|
||||||
@@ -790,7 +808,7 @@ const level1Groups = computed(() => {
|
|||||||
}
|
}
|
||||||
l1.totalQty += qty
|
l1.totalQty += qty
|
||||||
|
|
||||||
const l2Key = `${colorCode}|${secondColor}|${photoDim3}`
|
const l2Key = `${colorCode}|${secondColor}|${photoDim3}|${photoDim1ID}|${photoDim3ID}`
|
||||||
if (!l1.childrenMap.has(l2Key)) {
|
if (!l1.childrenMap.has(l2Key)) {
|
||||||
l1.childrenMap.set(l2Key, {
|
l1.childrenMap.set(l2Key, {
|
||||||
key: `L2|${productCode}|${l2Key}`,
|
key: `L2|${productCode}|${l2Key}`,
|
||||||
@@ -798,6 +816,8 @@ const level1Groups = computed(() => {
|
|||||||
colorDesc,
|
colorDesc,
|
||||||
secondColor,
|
secondColor,
|
||||||
photoDim3,
|
photoDim3,
|
||||||
|
photoDim1ID,
|
||||||
|
photoDim3ID,
|
||||||
kategori,
|
kategori,
|
||||||
urunAnaGrubu,
|
urunAnaGrubu,
|
||||||
urunAltGrubu,
|
urunAltGrubu,
|
||||||
@@ -946,7 +966,7 @@ async function fetchStockByCode() {
|
|||||||
function onLevel2Click(productCode, grp2) {
|
function onLevel2Click(productCode, grp2) {
|
||||||
toggleOpen(grp2.key)
|
toggleOpen(grp2.key)
|
||||||
if (isOpen(grp2.key)) {
|
if (isOpen(grp2.key)) {
|
||||||
void ensureProductImage(productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor)
|
void ensureProductImage(productCode, grp2.colorCode, grp2.photoDim3 || grp2.secondColor, grp2.photoDim1ID || '', grp2.photoDim3ID || '')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -955,28 +975,36 @@ async function openProductCard(grp1, grp2) {
|
|||||||
const colorCode = String(grp2?.colorCode || '').trim()
|
const colorCode = String(grp2?.colorCode || '').trim()
|
||||||
const secondColor = String(grp2?.secondColor || '').trim()
|
const secondColor = String(grp2?.secondColor || '').trim()
|
||||||
const photoDim3 = String(grp2?.photoDim3 || secondColor).trim()
|
const photoDim3 = String(grp2?.photoDim3 || secondColor).trim()
|
||||||
const listKey = buildImageKey(productCode, colorCode, photoDim3)
|
const photoDim1ID = String(grp2?.photoDim1ID || '').trim()
|
||||||
|
const photoDim3ID = String(grp2?.photoDim3ID || '').trim()
|
||||||
|
const listKey = buildImageKey(productCode, colorCode, photoDim3, photoDim1ID, photoDim3ID)
|
||||||
const codeTrim = String(productCode || '').trim().toUpperCase()
|
const codeTrim = String(productCode || '').trim().toUpperCase()
|
||||||
const colorTrim = String(colorCode || '').trim().toUpperCase()
|
const colorTrim = String(colorCode || '').trim().toUpperCase()
|
||||||
const secondTrim = String(photoDim3 || '').trim().toUpperCase()
|
const secondTrim = String(photoDim3 || '').trim().toUpperCase()
|
||||||
|
const dim1IDTrim = String(photoDim1ID || '').trim().toUpperCase()
|
||||||
|
const dim3IDTrim = String(photoDim3ID || '').trim().toUpperCase()
|
||||||
|
|
||||||
await ensureProductImage(productCode, colorCode, photoDim3)
|
await ensureProductImage(productCode, colorCode, photoDim3, photoDim1ID, photoDim3ID)
|
||||||
let list = Array.isArray(productImageListByCode.value[listKey]) ? productImageListByCode.value[listKey] : []
|
let list = Array.isArray(productImageListByCode.value[listKey]) ? productImageListByCode.value[listKey] : []
|
||||||
console.info('[ProductStockQuery][openProductCard] request', {
|
console.info('[ProductStockQuery][openProductCard] request', {
|
||||||
productCode,
|
productCode,
|
||||||
colorCode,
|
colorCode,
|
||||||
secondColor,
|
secondColor,
|
||||||
|
dim1ID: dim1IDTrim,
|
||||||
|
dim3ID: dim3IDTrim,
|
||||||
listKey,
|
listKey,
|
||||||
cachedListCount: list.length
|
cachedListCount: list.length
|
||||||
})
|
})
|
||||||
if (!list.length && codeTrim) {
|
if (!list.length && codeTrim) {
|
||||||
try {
|
try {
|
||||||
list = await fetchProductImageList(codeTrim, colorTrim, secondTrim)
|
list = await fetchProductImageList(codeTrim, colorTrim, secondTrim, dim1IDTrim, dim3IDTrim)
|
||||||
productImageListByCode.value[listKey] = list
|
productImageListByCode.value[listKey] = list
|
||||||
console.info('[ProductStockQuery][openProductCard] refetch', {
|
console.info('[ProductStockQuery][openProductCard] refetch', {
|
||||||
productCode: codeTrim,
|
productCode: codeTrim,
|
||||||
dim1: colorTrim,
|
dim1: colorTrim,
|
||||||
|
dim1ID: dim1IDTrim,
|
||||||
dim3: secondTrim,
|
dim3: secondTrim,
|
||||||
|
dim3ID: dim3IDTrim,
|
||||||
fetchedCount: list.length,
|
fetchedCount: list.length,
|
||||||
fileNames: list.map((x) => String(x?.file_name || x?.FileName || '').trim()).filter(Boolean)
|
fileNames: list.map((x) => String(x?.file_name || x?.FileName || '').trim()).filter(Boolean)
|
||||||
})
|
})
|
||||||
@@ -1004,7 +1032,7 @@ async function openProductCard(grp1, grp2) {
|
|||||||
const uniqueImages = Array.from(new Set(images))
|
const uniqueImages = Array.from(new Set(images))
|
||||||
|
|
||||||
if (!uniqueImages.length) {
|
if (!uniqueImages.length) {
|
||||||
const single = getProductImageUrl(productCode, colorCode, photoDim3)
|
const single = getProductImageUrl(productCode, colorCode, photoDim3, photoDim1ID, photoDim3ID)
|
||||||
if (single) uniqueImages.push(single)
|
if (single) uniqueImages.push(single)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user