@@ -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...' )