Fix product performance grouped JSON build

This commit is contained in:
M_Kececi
2026-07-05 20:31:27 +03:00
parent b2113a8d49
commit fbdde54eee
10 changed files with 1383 additions and 144 deletions
-2
View File
@@ -1289,8 +1289,6 @@ function normalizeUploadsPath (storagePath) {
function resolveProductImageUrl (item) {
if (!item || typeof item !== 'object') return ''
const imageId = Number(item.id || item.ID || 0)
if (Number.isFinite(imageId) && imageId > 0) return `/api/product-images/${imageId}/content`
const thumbUrl = toText(item.thumb_url || item.thumbUrl)
if (thumbUrl) return thumbUrl
const fullUrl = toText(item.full_url || item.fullUrl)
+232 -53
View File
@@ -60,6 +60,7 @@
</div>
</div>
</q-btn-dropdown>
<q-btn dense outline color="positive" icon="grid_on" label="Excel" :loading="excelExportLoading" :disable="pageBusy || excelExportLoading" @click="exportProductPerformanceExcel" />
<q-btn dense outline color="secondary" icon="refresh" label="Yenile" :loading="loading" :disable="pageBusy" @click="reload" />
</div>
</div>
@@ -1520,7 +1521,7 @@
<script setup>
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
import { Notify } from 'quasar'
import api from 'src/services/api'
import api, { extractApiErrorDetail } from 'src/services/api'
import { useProductPerformanceStore } from 'src/stores/productPerformanceStore'
const performanceStore = useProductPerformanceStore()
@@ -1544,6 +1545,7 @@ function formatPercent (value) {
}
const loading = ref(false)
const excelExportLoading = ref(false)
const rows = ref([])
const detailMainGroupOptionRows = ref([])
const generalRows = ref([])
@@ -1658,6 +1660,18 @@ const backendGroupedFilterFields = new Set([
'customer_name',
'performance_bucket'
])
const productPerformanceExcelExportFilterFields = new Set([
'kategori',
'askili_yan',
'urun_ilk_grubu',
'urun_ana_grubu',
'urun_alt_grubu',
'product_code',
'color_yaka',
'color_code',
'yaka_kodu',
'performance_bucket'
])
const performanceTabs = [
{ name: 'products', icon: 'dashboard', label: 'Genel Özet KPI' },
{ name: 'product_detail', icon: 'category', label: 'Detay KPI' },
@@ -2312,6 +2326,105 @@ const customerPeriodScoreColumns = [
{ name: 'customer_score_total', label: 'Genel Müşteri Skor', field: row => formatNumber(row.customer_score_total, 2), align: 'right', sortable: true }
]
const metricLabelOverrides = {
stock_qty: 'Toplam Stok',
sales_qty: 'Toplam Adet',
sales_qty_90d: '90G Toplam Adet',
sales_qty_180d: '180G Toplam Adet',
sales_qty_365d: '360G Toplam Adet',
sales_qty_total: 'Genel Toplam Adet',
sales_usd: 'Toplam Ciro USD',
sales_usd_90d: '90G Toplam Ciro USD',
sales_usd_180d: '180G Toplam Ciro USD',
sales_usd_365d: '360G Toplam Ciro USD',
sales_usd_total: 'Genel Toplam Ciro USD',
avg_price_usd: 'Ağ. Ort. Fiyat USD',
avg_price_usd_90d: '90G Ağ. Ort. Fiyat USD',
avg_price_usd_180d: '180G Ağ. Ort. Fiyat USD',
avg_price_usd_365d: '360G Ağ. Ort. Fiyat USD',
avg_price_usd_total: 'Genel Ağ. Ort. Fiyat USD',
base_price_usd: 'Ort. Taban Maliyet USD',
cost_price_usd: 'Ort. Çıplak Maliyet USD',
base_price_usd_90d: '90G Ort. Taban Maliyet USD',
cost_price_usd_90d: '90G Ort. Çıplak Maliyet USD',
base_price_usd_180d: '180G Ort. Taban Maliyet USD',
cost_price_usd_180d: '180G Ort. Çıplak Maliyet USD',
base_price_usd_365d: '360G Ort. Taban Maliyet USD',
cost_price_usd_365d: '360G Ort. Çıplak Maliyet USD',
base_price_usd_total: 'Genel Ort. Taban Maliyet USD',
cost_price_usd_total: 'Genel Ort. Çıplak Maliyet USD',
unit_profit_base_90d: '90G Ağ. Ort. Birim Taban K/Z USD',
unit_profit_cost_90d: '90G Ağ. Ort. Birim Çıplak K/Z USD',
unit_profit_base_180d: '180G Ağ. Ort. Birim Taban K/Z USD',
unit_profit_cost_180d: '180G Ağ. Ort. Birim Çıplak K/Z USD',
unit_profit_base_total: 'Genel Ağ. Ort. Birim Taban K/Z USD',
unit_profit_cost_total: 'Genel Ağ. Ort. Birim Çıplak K/Z USD',
gross_profit_usd_90d: '90G Toplam K/Z USD',
gross_profit_usd_180d: '180G Toplam K/Z USD',
gross_profit_usd_total: 'Genel Toplam K/Z USD',
gross_profit_base_usd_90d: '90G Taban Toplam K/Z USD',
gross_profit_cost_usd_90d: '90G Çıplak Toplam K/Z USD',
gross_profit_base_usd_180d: '180G Taban Toplam K/Z USD',
gross_profit_cost_usd_180d: '180G Çıplak Toplam K/Z USD',
gross_profit_base_usd_365d: '360G Taban Toplam K/Z USD',
gross_profit_cost_usd_365d: '360G Çıplak Toplam K/Z USD',
gross_profit_base_usd_total: 'Genel Taban Toplam K/Z USD',
gross_profit_cost_usd_total: 'Genel Çıplak Toplam K/Z USD',
gross_margin_base_90d: '90G Ağ. Ort. Taban Marj',
gross_margin_cost_90d: '90G Ağ. Ort. Çıplak Marj',
gross_margin_base_180d: '180G Ağ. Ort. Taban Marj',
gross_margin_cost_180d: '180G Ağ. Ort. Çıplak Marj',
gross_margin_base_365d: '360G Ağ. Ort. Taban Marj',
gross_margin_cost_365d: '360G Ağ. Ort. Çıplak Marj',
gross_margin_base_total: 'Genel Ağ. Ort. Taban Marj',
gross_margin_cost_total: 'Genel Ağ. Ort. Çıplak Marj',
performance_score: 'Ağ. Ort. Skor',
performance_score_90d: '90G Ağ. Ort. Ürün Skor',
performance_score_180d: '180G Ağ. Ort. Ürün Skor',
performance_score_365d: '360G Ağ. Ort. Ürün Skor',
performance_score_total: 'Genel Ağ. Ort. Ürün Skor',
customer_score_90d: '90G Ağ. Ort. Müşteri Skor',
customer_score_180d: '180G Ağ. Ort. Müşteri Skor',
customer_score_365d: '360G Ağ. Ort. Müşteri Skor',
customer_score_total: 'Genel Ağ. Ort. Müşteri Skor',
market_count_90d: '90G Tekil Piyasa',
customer_count_90d: '90G Tekil Müşteri',
market_count_total: 'Genel Tekil Piyasa',
customer_count_total: 'Genel Tekil Müşteri',
sales_index_90d: '90G Ağ. Ort. Endeks',
sales_index_total: 'Genel Ağ. Ort. Endeks',
stock_days_90d: '90G Ağ. Ort. Stok Gün',
stock_days_180d: '180G Ağ. Ort. Stok Gün',
stock_days_365d: '360G Ağ. Ort. Stok Gün',
stock_days_total: 'Genel Ağ. Ort. Stok Gün',
avg_daily_sales_total: 'Genel Günlük Ort. Adet'
}
function applyMetricLabelOverrides (...columnGroups) {
for (const group of columnGroups) {
for (const col of group || []) {
if (metricLabelOverrides[col?.name]) col.label = metricLabelOverrides[col.name]
}
}
}
applyMetricLabelOverrides(
detailSalesColumns,
columns,
generalColumns,
orderAnalysisColumns,
orderGroupColumns,
orderProductCustomerColumns,
orderMarketDetailColumns,
idleColumns,
marketColumns,
countryColumns,
customerColumns,
salesBreakdownColumns,
productPeriodScoreColumns,
customerPeriodScoreColumns
)
function ensureColumns (targetColumns, columnsToEnsure) {
const existing = new Set(targetColumns.map(col => col.name))
for (const col of columnsToEnsure) {
@@ -2922,7 +3035,7 @@ function backendGroupedFilterOptionParams (tabKey) {
mode: tabKey,
groupLevels: (tabGroupLevels[tabKey] || groupLevels).map(level => level.key),
fields,
limit: 5000
limit: 50000
}
if (tabKey === 'product_detail') params.urunAnaGrubu = selectedDetailMainGroup.value
return params
@@ -3283,7 +3396,9 @@ function makeGroupRow (key, level, groupDef, value, groupRows) {
sales_index_total: averageRows(groupRows, 'sales_index_total'),
performance_bucket: dominantValue(groupRows, 'performance_bucket'),
...aggregate,
performance_score: groupPerformanceScore(aggregate, groupDef.key),
performance_score: Object.prototype.hasOwnProperty.call(aggregate, 'performance_score')
? aggregate.performance_score
: groupPerformanceScore(aggregate, groupDef.key),
recommendation: dominantValue(groupRows, 'recommendation') || `${formatNumber(groupRows.length, 0)} satır`
}
}
@@ -3372,15 +3487,15 @@ function applyDerivedGroupMetrics (out, sourceRows, groupField = '') {
if (sourceRows.some(row => row.performance_bucket)) {
out.performance_bucket = dominantValue(sourceRows, 'performance_bucket')
}
out.customer_score_90d = customerSalesPeriodScore(periodMetricSource(out, '90d'))
out.customer_score_180d = customerSalesPeriodScore(periodMetricSource(out, '180d'))
out.customer_score_365d = customerSalesPeriodScore(periodMetricSource(out, '365d'))
out.customer_score_total = customerSalesPeriodScore(periodMetricSource(out, 'total'))
out.performance_score_90d = productSalesPeriodScore(productPeriodMetricSource(out, '90d'))
out.performance_score_180d = productSalesPeriodScore(productPeriodMetricSource(out, '180d'))
out.performance_score_365d = productSalesPeriodScore(productPeriodMetricSource(out, '365d'))
out.performance_score_total = productSalesPeriodScore(productPeriodMetricSource(out, 'total'))
out.performance_score = groupPerformanceScore(out, groupField)
if (!Object.prototype.hasOwnProperty.call(out, 'customer_score_90d')) out.customer_score_90d = customerSalesPeriodScore(periodMetricSource(out, '90d'))
if (!Object.prototype.hasOwnProperty.call(out, 'customer_score_180d')) out.customer_score_180d = customerSalesPeriodScore(periodMetricSource(out, '180d'))
if (!Object.prototype.hasOwnProperty.call(out, 'customer_score_365d')) out.customer_score_365d = customerSalesPeriodScore(periodMetricSource(out, '365d'))
if (!Object.prototype.hasOwnProperty.call(out, 'customer_score_total')) out.customer_score_total = customerSalesPeriodScore(periodMetricSource(out, 'total'))
if (!Object.prototype.hasOwnProperty.call(out, 'performance_score_90d')) out.performance_score_90d = productSalesPeriodScore(productPeriodMetricSource(out, '90d'))
if (!Object.prototype.hasOwnProperty.call(out, 'performance_score_180d')) out.performance_score_180d = productSalesPeriodScore(productPeriodMetricSource(out, '180d'))
if (!Object.prototype.hasOwnProperty.call(out, 'performance_score_365d')) out.performance_score_365d = productSalesPeriodScore(productPeriodMetricSource(out, '365d'))
if (!Object.prototype.hasOwnProperty.call(out, 'performance_score_total')) out.performance_score_total = productSalesPeriodScore(productPeriodMetricSource(out, 'total'))
if (!Object.prototype.hasOwnProperty.call(out, 'performance_score')) out.performance_score = groupPerformanceScore(out, groupField)
}
function groupPerformanceScore (row, groupField = '') {
@@ -3672,18 +3787,12 @@ function weightedAverageProductCost (sourceRows, valueField) {
if (!key || variants.has(key)) continue
variants.set(key, row)
}
const stockSource = variants.size > 0 ? Array.from(variants.values()) : sourceRows
const stockRows = stockSource
.map(row => ({
value: Number(row[valueField] || 0),
qty: Number(row.stock_qty || 0)
}))
.filter(row => Number.isFinite(row.value) && Number.isFinite(row.qty) && row.value > 0 && row.qty > 0)
const stockQty = stockRows.reduce((sum, row) => sum + row.qty, 0)
if (stockQty > 0) {
return stockRows.reduce((sum, row) => sum + row.value * row.qty, 0) / stockQty
}
return 0
const averageSource = variants.size > 0 ? Array.from(variants.values()) : sourceRows
const values = averageSource
.map(row => Number(row[valueField] || 0))
.filter(value => Number.isFinite(value) && value > 0)
if (!values.length) return 0
return values.reduce((sum, value) => sum + value, 0) / values.length
}
function marginFromSalesCost (salesUSD, qty, unitCost) {
@@ -3878,27 +3987,50 @@ function formatGroupCell (row, colOrName) {
}
function withProductMargins (row) {
const salesQtyTotal = Number(row?.sales_qty_total || 0)
const salesUSDTotal = Number(row?.sales_usd_total || 0)
const basePrice = Number(row?.base_price_usd || 0)
const costPrice = Number(row?.cost_price_usd || 0)
const grossProfitBaseTotal = salesQtyTotal > 0 ? salesUSDTotal - (salesQtyTotal * basePrice) : 0
const grossProfitCostTotal = salesQtyTotal > 0 ? salesUSDTotal - (salesQtyTotal * costPrice) : 0
return {
...row,
avg_price_usd_365d: Number(row?.sales_qty_365d || 0) > 0 ? Number(row?.sales_usd_365d || 0) / Number(row?.sales_qty_365d || 0) : 0,
avg_price_usd_total: salesQtyTotal > 0 ? salesUSDTotal / salesQtyTotal : Number(row?.avg_price_usd_total || 0),
stock_turnover_90d: existingOrStockTurnover(row?.stock_turnover_90d, row?.sales_qty_90d, row?.stock_qty),
stock_turnover_180d: existingOrStockTurnover(row?.stock_turnover_180d, row?.sales_qty_180d, row?.stock_qty),
stock_turnover_365d: existingOrStockTurnover(row?.stock_turnover_365d, row?.sales_qty_365d, row?.stock_qty),
stock_turnover_total: existingOrStockTurnover(row?.stock_turnover_total, row?.sales_qty_total, row?.stock_qty),
gross_profit_base_usd_total: grossProfitBaseTotal,
gross_profit_cost_usd_total: grossProfitCostTotal,
gross_profit_usd_total: Number(row?.gross_profit_usd_total ?? grossProfitCostTotal),
gross_margin_base_90d: marginFromSalesCost(row?.sales_usd_90d, row?.sales_qty_90d, row?.base_price_usd),
gross_margin_cost_90d: marginFromSalesCost(row?.sales_usd_90d, row?.sales_qty_90d, row?.cost_price_usd),
gross_margin_base_180d: marginFromSalesCost(row?.sales_usd_180d, row?.sales_qty_180d, row?.base_price_usd),
gross_margin_cost_180d: marginFromSalesCost(row?.sales_usd_180d, row?.sales_qty_180d, row?.cost_price_usd),
gross_margin_base_365d: marginFromSalesCost(row?.sales_usd_365d, row?.sales_qty_365d, row?.base_price_usd),
gross_margin_cost_365d: marginFromSalesCost(row?.sales_usd_365d, row?.sales_qty_365d, row?.cost_price_usd)
gross_margin_cost_365d: marginFromSalesCost(row?.sales_usd_365d, row?.sales_qty_365d, row?.cost_price_usd),
gross_margin_base_total: marginFromSalesCost(salesUSDTotal, salesQtyTotal, basePrice),
gross_margin_cost_total: marginFromSalesCost(salesUSDTotal, salesQtyTotal, costPrice)
}
}
function withGeneralMargins (row) {
const salesQtyTotal = Number(row?.sales_qty_total || 0)
const salesUSDTotal = Number(row?.sales_usd_total || 0)
const basePrice = Number(row?.base_price_usd || 0)
const costPrice = Number(row?.cost_price_usd || 0)
const grossProfitBaseTotal = salesQtyTotal > 0 ? salesUSDTotal - (salesQtyTotal * basePrice) : 0
const grossProfitCostTotal = salesQtyTotal > 0 ? salesUSDTotal - (salesQtyTotal * costPrice) : 0
return {
...row,
avg_price_usd_total: salesQtyTotal > 0 ? salesUSDTotal / salesQtyTotal : Number(row?.avg_price_usd_total || 0),
stock_turnover_total: existingOrStockTurnover(row?.stock_turnover_total, row?.sales_qty_total, row?.stock_qty),
gross_margin_base_total: marginFromSalesCost(row?.sales_usd_total, row?.sales_qty_total, row?.base_price_usd),
gross_margin_cost_total: marginFromSalesCost(row?.sales_usd_total, row?.sales_qty_total, row?.cost_price_usd)
gross_profit_base_usd_total: grossProfitBaseTotal,
gross_profit_cost_usd_total: grossProfitCostTotal,
gross_profit_usd_total: Number(row?.gross_profit_usd_total ?? grossProfitCostTotal),
gross_margin_base_total: marginFromSalesCost(salesUSDTotal, salesQtyTotal, basePrice),
gross_margin_cost_total: marginFromSalesCost(salesUSDTotal, salesQtyTotal, costPrice)
}
}
@@ -4276,19 +4408,19 @@ function normalizeRow (row) {
const color = String(row?.color_code || '').trim()
const yaka = String(row?.yaka_kodu || '').trim()
const market = String(row?.market_key || '').trim()
return withPeriodScores(withProductMargins({
return withPeriodScores(withGeneralMargins(withProductMargins({
...row,
row_key: `${product}|${color}|${yaka}|${market}`
}))
})))
}
function withPeriodScores (row) {
const next = { ...row }
next.performance_score_90d = Number(next.performance_score_90d || productSalesPeriodScore(productPeriodMetricSource(next, '90d')))
next.performance_score_180d = Number(next.performance_score_180d || productSalesPeriodScore(productPeriodMetricSource(next, '180d')))
next.performance_score_365d = Number(next.performance_score_365d || productSalesPeriodScore(productPeriodMetricSource(next, '365d')))
next.performance_score_total = Number(next.performance_score_total || productSalesPeriodScore(productPeriodMetricSource(next, 'total')))
if (!Number(next.performance_score || 0)) next.performance_score = next.performance_score_90d
if (!Object.prototype.hasOwnProperty.call(next, 'performance_score_90d')) next.performance_score_90d = productSalesPeriodScore(productPeriodMetricSource(next, '90d'))
if (!Object.prototype.hasOwnProperty.call(next, 'performance_score_180d')) next.performance_score_180d = productSalesPeriodScore(productPeriodMetricSource(next, '180d'))
if (!Object.prototype.hasOwnProperty.call(next, 'performance_score_365d')) next.performance_score_365d = productSalesPeriodScore(productPeriodMetricSource(next, '365d'))
if (!Object.prototype.hasOwnProperty.call(next, 'performance_score_total')) next.performance_score_total = productSalesPeriodScore(productPeriodMetricSource(next, 'total'))
if (!Object.prototype.hasOwnProperty.call(next, 'performance_score')) next.performance_score = next.performance_score_90d
return next
}
@@ -4422,16 +4554,6 @@ function displayMarketName (value) {
return parts.length ? parts[parts.length - 1] : ''
}
function normalizeUploadsPath (storagePath) {
const raw = String(storagePath || '').trim()
if (!raw) return ''
const normalized = raw.replace(/\\/g, '/')
const idx = normalized.toLowerCase().indexOf('/uploads/')
if (idx >= 0) return normalized.slice(idx)
if (normalized.toLowerCase().startsWith('uploads/')) return `/${normalized}`
return ''
}
function resolveProductImageUrl (item) {
return resolveProductImageUrls(item)[0] || ''
}
@@ -4450,18 +4572,9 @@ function resolveProductImageUrls (item) {
const fullURL = String(item.full_url || item.fullUrl || '').trim()
addURL(fullURL)
const uploadsPath = normalizeUploadsPath(item.storage_path || item.storage || '')
addURL(uploadsPath)
const fileName = String(item.file_name || item.FileName || '').trim()
if (fileName) addURL(`/uploads/image/${fileName}`)
const contentURL = String(item.content_url || item.ContentURL || '').trim()
if (contentURL.startsWith('/api/')) addURL(contentURL)
else if (contentURL.startsWith('/')) addURL(`/api${contentURL}`)
const imageId = Number(item.id || item.ID || 0)
if (Number.isFinite(imageId) && imageId > 0) addURL(`/api/product-images/${imageId}/content`)
return urls
}
@@ -4897,6 +5010,72 @@ async function timedProductPerformanceGet (label, url, config = {}) {
}
}
function productPerformanceExcelExportTableKey () {
if (isProductKpiTab.value) return activeProductTableKey.value
if (backendGroupedSupportedTab(activeTab.value)) return activeTab.value
return 'products'
}
function buildProductPerformanceExcelExportFilters () {
const tableKey = productPerformanceExcelExportTableKey()
const out = {}
for (const col of columnsForTableKey(tableKey) || []) {
const name = String(col?.name || '').trim()
if (!productPerformanceExcelExportFilterFields.has(name)) continue
const selected = selectedColumnFilters(tableKey, name)
if (selected.length) out[name] = selected
}
if (activeTab.value === 'product_detail') {
const mainGroup = String(selectedDetailMainGroup.value || '').trim()
if (mainGroup && !out.urun_ana_grubu?.includes(mainGroup)) {
out.urun_ana_grubu = [...(out.urun_ana_grubu || []), mainGroup]
}
}
return out
}
function productPerformanceExcelFilename (headers = {}) {
const disposition = String(headers?.['content-disposition'] || headers?.['Content-Disposition'] || '').trim()
const utfMatch = disposition.match(/filename\*=UTF-8''([^;]+)/i)
if (utfMatch?.[1]) return decodeURIComponent(utfMatch[1].replaceAll('"', '').trim())
const match = disposition.match(/filename="?([^";]+)"?/i)
return match?.[1]?.trim() || `product_performance_color_yaka_${new Date().toISOString().slice(0, 10)}.xlsx`
}
function downloadProductPerformanceExcelBlob (blob, filename) {
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = filename
document.body.appendChild(a)
a.click()
a.remove()
URL.revokeObjectURL(url)
}
async function exportProductPerformanceExcel () {
if (excelExportLoading.value) return
excelExportLoading.value = true
try {
const tableKey = productPerformanceExcelExportTableKey()
const pagination = tablePagination[tableKey] || tablePagination.products || {}
const response = await api.post('/pricing/product-performance/export-excel', {
filters: buildProductPerformanceExcelExportFilters(),
sort_by: pagination.sortBy || '',
descending: pagination.descending !== false
}, {
responseType: 'blob',
timeout: 180000
})
downloadProductPerformanceExcelBlob(response.data, productPerformanceExcelFilename(response.headers || {}))
} catch (err) {
const detail = await extractApiErrorDetail(err)
Notify.create({ type: 'negative', message: detail || 'Excel çıktısı alınamadı' })
} finally {
excelExportLoading.value = false
}
}
async function reload () {
loading.value = true
startLoadingTimer('Rapor verileri hazırlanıyor...')
+7 -12
View File
@@ -637,14 +637,9 @@ function resolveProductImageUrl(item) {
}
let contentUrl = ''
const imageId = Number(item.id || item.ID || 0)
if (Number.isFinite(imageId) && imageId > 0) {
contentUrl = `/api/product-images/${imageId}/content`
} else {
const contentURL = String(item.content_url || item.ContentURL || '').trim()
if (contentURL.startsWith('/api/')) contentUrl = contentURL
else if (contentURL.startsWith('/')) contentUrl = `/api${contentURL}`
}
const contentURL = String(item.content_url || item.ContentURL || '').trim()
if (contentURL.startsWith('/api/')) contentUrl = contentURL
else if (contentURL.startsWith('/')) contentUrl = `/api${contentURL}`
const uploadsPath = normalizeUploadsPath(item.storage_path || item.storage || '')
let publicUrl = ''
@@ -707,6 +702,9 @@ function clearGalleryQueryIndex() {
async function resolveProductImageUrlForCarousel(item) {
const resolved = resolveProductImageUrl(item)
const directUrl = String(resolved.fullUrl || resolved.thumbUrl || resolved.publicUrl || '').trim()
if (directUrl) return directUrl
const contentUrl = String(resolved.contentUrl || '').trim()
if (contentUrl) {
try {
@@ -721,10 +719,7 @@ async function resolveProductImageUrlForCarousel(item) {
// fall through to public url
}
}
const fullUrl = String(resolved.fullUrl || '').trim()
if (fullUrl) return fullUrl
const publicUrl = String(resolved.publicUrl || '').trim()
return String(publicUrl || fullUrl || contentUrl || '').trim()
return contentUrl
}
function getProductImageUrl(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
+7 -12
View File
@@ -618,14 +618,9 @@ function resolveProductImageUrl(item) {
}
let contentUrl = ''
const imageId = Number(item.id || item.ID || 0)
if (Number.isFinite(imageId) && imageId > 0) {
contentUrl = `/api/product-images/${imageId}/content`
} else {
const contentURL = String(item.content_url || item.ContentURL || '').trim()
if (contentURL.startsWith('/api/')) contentUrl = contentURL
else if (contentURL.startsWith('/')) contentUrl = `/api${contentURL}`
}
const contentURL = String(item.content_url || item.ContentURL || '').trim()
if (contentURL.startsWith('/api/')) contentUrl = contentURL
else if (contentURL.startsWith('/')) contentUrl = `/api${contentURL}`
const uploadsPath = normalizeUploadsPath(item.storage_path || item.storage || '')
let publicUrl = ''
@@ -686,6 +681,9 @@ function clearGalleryQueryIndex() {
async function resolveProductImageUrlForCarousel(item) {
const resolved = resolveProductImageUrl(item)
const directUrl = String(resolved.fullUrl || resolved.thumbUrl || resolved.publicUrl || '').trim()
if (directUrl) return directUrl
const contentUrl = String(resolved.contentUrl || '').trim()
if (contentUrl) {
try {
@@ -700,10 +698,7 @@ async function resolveProductImageUrlForCarousel(item) {
// fall through to public url
}
}
const fullUrl = String(resolved.fullUrl || '').trim()
if (fullUrl) return fullUrl
const publicUrl = String(resolved.publicUrl || '').trim()
return String(publicUrl || fullUrl || contentUrl || '').trim()
return contentUrl
}
function getProductImageUrl(code, color, secondColor = '', dim1Id = '', dim3Id = '') {
+1 -20
View File
@@ -4,16 +4,6 @@ import api from 'src/services/api'
const GROUPED_TTL_MS = 2 * 60 * 1000
const IMAGE_TTL_MS = 15 * 60 * 1000
function normalizeUploadsPath (storagePath) {
const raw = String(storagePath || '').trim()
if (!raw) return ''
const normalized = raw.replace(/\\/g, '/')
const idx = normalized.toLowerCase().indexOf('/uploads/')
if (idx >= 0) return normalized.slice(idx)
if (normalized.toLowerCase().startsWith('uploads/')) return `/${normalized}`
return ''
}
function resolveProductImageUrl (item) {
return resolveProductImageUrls(item)[0] || ''
}
@@ -32,18 +22,9 @@ function resolveProductImageUrls (item) {
const fullURL = String(item.full_url || item.fullUrl || '').trim()
addURL(fullURL)
const uploadsPath = normalizeUploadsPath(item.storage_path || item.storage || '')
addURL(uploadsPath)
const fileName = String(item.file_name || item.FileName || '').trim()
if (fileName) addURL(`/uploads/image/${fileName}`)
const contentURL = String(item.content_url || item.ContentURL || '').trim()
if (contentURL.startsWith('/api/')) addURL(contentURL)
else if (contentURL.startsWith('/')) addURL(`/api${contentURL}`)
const imageId = Number(item.id || item.ID || 0)
if (Number.isFinite(imageId) && imageId > 0) addURL(`/api/product-images/${imageId}/content`)
return urls
}
@@ -206,7 +187,7 @@ export const useProductPerformanceStore = defineStore('product-performance-store
urun_ana_grubu: params.urunAnaGrubu || params.urun_ana_grubu || '',
group_levels: Array.isArray(params.groupLevels) ? params.groupLevels : String(params.groupLevels || '').split(',').filter(Boolean),
fields: Array.isArray(params.fields) ? params.fields : String(params.fields || '').split(',').filter(Boolean),
limit: params.limit || 5000
limit: params.limit || 50000
}, { timeout: 60000 }).then(resp => {
const data = resp?.data && typeof resp.data === 'object' ? resp.data : {}
this.groupedFilterOptionsByKey = { ...this.groupedFilterOptionsByKey, [key]: data }