product performance grouped kpi improvements
This commit is contained in:
@@ -2910,7 +2910,7 @@ FROM (
|
|||||||
COALESCE((ARRAY_AGG(NULLIF(urun_ana_grubu,'') ORDER BY performance_score DESC NULLS LAST))[1], '') AS urun_ana_grubu,
|
COALESCE((ARRAY_AGG(NULLIF(urun_ana_grubu,'') ORDER BY performance_score DESC NULLS LAST))[1], '') AS urun_ana_grubu,
|
||||||
COALESCE((ARRAY_AGG(NULLIF(urun_alt_grubu,'') ORDER BY performance_score DESC NULLS LAST))[1], '') AS urun_alt_grubu,
|
COALESCE((ARRAY_AGG(NULLIF(urun_alt_grubu,'') ORDER BY performance_score DESC NULLS LAST))[1], '') AS urun_alt_grubu,
|
||||||
COALESCE((ARRAY_AGG(NULLIF(market_key,'') ORDER BY performance_score DESC NULLS LAST))[1], '') AS market_key,
|
COALESCE((ARRAY_AGG(NULLIF(market_key,'') ORDER BY performance_score DESC NULLS LAST))[1], '') AS market_key,
|
||||||
COALESCE(SUM(stock_qty),0) AS stock_qty,
|
COALESCE(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) AS stock_qty,
|
||||||
COALESCE(SUM(sales_qty_90d),0) AS sales_qty_90d,
|
COALESCE(SUM(sales_qty_90d),0) AS sales_qty_90d,
|
||||||
COALESCE(SUM(sales_qty_180d),0) AS sales_qty_180d,
|
COALESCE(SUM(sales_qty_180d),0) AS sales_qty_180d,
|
||||||
COALESCE(SUM(sales_qty_365d),0) AS sales_qty_365d,
|
COALESCE(SUM(sales_qty_365d),0) AS sales_qty_365d,
|
||||||
@@ -2919,9 +2919,9 @@ FROM (
|
|||||||
COALESCE(SUM(sales_usd_365d),0) AS sales_usd_365d,
|
COALESCE(SUM(sales_usd_365d),0) AS sales_usd_365d,
|
||||||
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(sales_usd_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE 0 END AS avg_price_usd_90d,
|
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(sales_usd_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE 0 END AS avg_price_usd_90d,
|
||||||
CASE WHEN SUM(sales_qty_180d) > 0 THEN SUM(sales_usd_180d) / NULLIF(SUM(sales_qty_180d),0) ELSE 0 END AS avg_price_usd_180d,
|
CASE WHEN SUM(sales_qty_180d) > 0 THEN SUM(sales_usd_180d) / NULLIF(SUM(sales_qty_180d),0) ELSE 0 END AS avg_price_usd_180d,
|
||||||
CASE WHEN SUM(stock_qty) > 0 THEN SUM(cost_price_usd * stock_qty) / NULLIF(SUM(stock_qty),0) ELSE AVG(cost_price_usd) END AS cost_price_usd,
|
CASE WHEN SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END) > 0 THEN SUM(CASE WHEN stock_variant_rank = 1 THEN cost_price_usd * stock_qty ELSE 0 END) / NULLIF(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) ELSE AVG(cost_price_usd) END AS cost_price_usd,
|
||||||
CASE WHEN SUM(stock_qty) > 0 THEN SUM(base_price_usd * stock_qty) / NULLIF(SUM(stock_qty),0) ELSE AVG(base_price_usd) END AS base_price_usd,
|
CASE WHEN SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END) > 0 THEN SUM(CASE WHEN stock_variant_rank = 1 THEN base_price_usd * stock_qty ELSE 0 END) / NULLIF(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) ELSE AVG(base_price_usd) END AS base_price_usd,
|
||||||
CASE WHEN SUM(stock_qty) > 0 THEN SUM(base_price_try * stock_qty) / NULLIF(SUM(stock_qty),0) ELSE AVG(base_price_try) END AS base_price_try,
|
CASE WHEN SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END) > 0 THEN SUM(CASE WHEN stock_variant_rank = 1 THEN base_price_try * stock_qty ELSE 0 END) / NULLIF(SUM(CASE WHEN stock_variant_rank = 1 THEN stock_qty ELSE 0 END),0) ELSE AVG(base_price_try) END AS base_price_try,
|
||||||
COALESCE(SUM(gross_profit_usd_90d),0) AS gross_profit_usd_90d,
|
COALESCE(SUM(gross_profit_usd_90d),0) AS gross_profit_usd_90d,
|
||||||
COALESCE(SUM(gross_profit_usd_180d),0) AS gross_profit_usd_180d,
|
COALESCE(SUM(gross_profit_usd_180d),0) AS gross_profit_usd_180d,
|
||||||
CASE WHEN SUM(sales_usd_90d) > 0 THEN SUM(gross_profit_usd_90d) / NULLIF(SUM(sales_usd_90d),0) ELSE 0 END AS gross_margin_90d,
|
CASE WHEN SUM(sales_usd_90d) > 0 THEN SUM(gross_profit_usd_90d) / NULLIF(SUM(sales_usd_90d),0) ELSE 0 END AS gross_margin_90d,
|
||||||
@@ -2937,13 +2937,21 @@ FROM (
|
|||||||
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(margin_index_90d * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE AVG(margin_index_90d) END AS margin_index_90d,
|
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(margin_index_90d * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE AVG(margin_index_90d) END AS margin_index_90d,
|
||||||
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(performance_score * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE AVG(performance_score) END AS performance_score,
|
CASE WHEN SUM(sales_qty_90d) > 0 THEN SUM(performance_score * sales_qty_90d) / NULLIF(SUM(sales_qty_90d),0) ELSE AVG(performance_score) END AS performance_score,
|
||||||
MODE() WITHIN GROUP (ORDER BY performance_bucket) AS performance_bucket,
|
MODE() WITHIN GROUP (ORDER BY performance_bucket) AS performance_bucket,
|
||||||
COALESCE(SUM(idle_cost_usd),0) AS idle_cost_usd
|
COALESCE(SUM(CASE WHEN stock_variant_rank = 1 THEN idle_cost_usd ELSE 0 END),0) AS idle_cost_usd
|
||||||
FROM Source
|
FROM (
|
||||||
|
SELECT
|
||||||
|
Source.*,
|
||||||
|
ROW_NUMBER() OVER (
|
||||||
|
PARTITION BY COALESCE(NULLIF(%s,''), '-'), product_code, color_code, yaka_kodu
|
||||||
|
ORDER BY performance_score DESC NULLS LAST
|
||||||
|
) AS stock_variant_rank
|
||||||
|
FROM Source
|
||||||
%s
|
%s
|
||||||
|
) s
|
||||||
GROUP BY COALESCE(NULLIF(%s,''), '-')
|
GROUP BY COALESCE(NULLIF(%s,''), '-')
|
||||||
) g
|
) g
|
||||||
ORDER BY group_value
|
ORDER BY group_value
|
||||||
`, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, groupExpr, whereSQL, groupExpr)
|
`, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, len(args)+1, groupExpr, groupExpr, whereSQL, groupExpr)
|
||||||
args = append(args, field)
|
args = append(args, field)
|
||||||
return queryProductPerformanceJSONRows(ctx, pg, query, args...)
|
return queryProductPerformanceJSONRows(ctx, pg, query, args...)
|
||||||
}
|
}
|
||||||
@@ -3192,6 +3200,14 @@ func aggregateProductPerformanceRows(rows []map[string]any, groupField string) m
|
|||||||
if key == "row_key" || key == "key" {
|
if key == "row_key" || key == "key" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if key == "stock_qty" {
|
||||||
|
out[key] = distinctProductPerformanceVariantStockQty(rows)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if key == "idle_cost_usd" {
|
||||||
|
out[key] = distinctProductPerformanceVariantStockCost(rows)
|
||||||
|
continue
|
||||||
|
}
|
||||||
if shouldSumProductPerformanceField(key) {
|
if shouldSumProductPerformanceField(key) {
|
||||||
out[key] = floatFromAny(out[key]) + floatFromAny(value)
|
out[key] = floatFromAny(out[key]) + floatFromAny(value)
|
||||||
} else if _, ok := out[key]; !ok && !shouldAverageProductPerformanceField(key) {
|
} else if _, ok := out[key]; !ok && !shouldAverageProductPerformanceField(key) {
|
||||||
@@ -3211,6 +3227,75 @@ func aggregateProductPerformanceRows(rows []map[string]any, groupField string) m
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func distinctProductPerformanceVariantStockQty(rows []map[string]any) float64 {
|
||||||
|
seen := map[string]bool{}
|
||||||
|
total := 0.0
|
||||||
|
hasKey := false
|
||||||
|
for _, row := range rows {
|
||||||
|
key := productPerformanceMapVariantKey(row)
|
||||||
|
if key == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
hasKey = true
|
||||||
|
if seen[key] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[key] = true
|
||||||
|
total += floatFromMap(row, "stock_qty")
|
||||||
|
}
|
||||||
|
if hasKey {
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
for _, row := range rows {
|
||||||
|
total += floatFromMap(row, "stock_qty")
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
func distinctProductPerformanceVariantStockCost(rows []map[string]any) float64 {
|
||||||
|
seen := map[string]bool{}
|
||||||
|
total := 0.0
|
||||||
|
hasKey := false
|
||||||
|
for _, row := range rows {
|
||||||
|
key := productPerformanceMapVariantKey(row)
|
||||||
|
if key == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
hasKey = true
|
||||||
|
if seen[key] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[key] = true
|
||||||
|
total += floatFromMap(row, "stock_qty") * floatFromMap(row, "cost_price_usd")
|
||||||
|
}
|
||||||
|
if hasKey {
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
for _, row := range rows {
|
||||||
|
total += floatFromMap(row, "idle_cost_usd")
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
func productPerformanceMapVariantKey(row map[string]any) string {
|
||||||
|
productCode := stringFromMap(row, "product_code")
|
||||||
|
if productCode == "" {
|
||||||
|
productCode = stringFromMap(row, "image_product_code")
|
||||||
|
}
|
||||||
|
colorCode := stringFromMap(row, "color_code")
|
||||||
|
if colorCode == "" {
|
||||||
|
colorCode = stringFromMap(row, "image_color_code")
|
||||||
|
}
|
||||||
|
yakaKodu := stringFromMap(row, "yaka_kodu")
|
||||||
|
if yakaKodu == "" {
|
||||||
|
yakaKodu = stringFromMap(row, "image_yaka_kodu")
|
||||||
|
}
|
||||||
|
if productCode == "" && colorCode == "" && yakaKodu == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return productPerformanceVariantKey(productCode, colorCode, yakaKodu)
|
||||||
|
}
|
||||||
|
|
||||||
func deriveProductPerformanceGroupMetrics(out map[string]any, groupField string) {
|
func deriveProductPerformanceGroupMetrics(out map[string]any, groupField string) {
|
||||||
for _, suffix := range []string{"90d", "180d", "365d", "total"} {
|
for _, suffix := range []string{"90d", "180d", "365d", "total"} {
|
||||||
sales := floatFromMap(out, "sales_usd_"+suffix)
|
sales := floatFromMap(out, "sales_usd_"+suffix)
|
||||||
@@ -3243,6 +3328,9 @@ func deriveProductPerformanceGroupMetrics(out map[string]any, groupField string)
|
|||||||
if orderQty > 0 {
|
if orderQty > 0 {
|
||||||
out["avg_order_price_usd"] = orderUSD / orderQty
|
out["avg_order_price_usd"] = orderUSD / orderQty
|
||||||
}
|
}
|
||||||
|
if _, ok := out["net_stock_after_order"]; ok || orderQty > 0 {
|
||||||
|
out["net_stock_after_order"] = floatFromMap(out, "stock_qty") - orderQty
|
||||||
|
}
|
||||||
out["customer_score_90d"] = productPerformanceCustomerSalesPeriodScore(rowPeriodMetricMap(out, "90d"))
|
out["customer_score_90d"] = productPerformanceCustomerSalesPeriodScore(rowPeriodMetricMap(out, "90d"))
|
||||||
out["customer_score_180d"] = productPerformanceCustomerSalesPeriodScore(rowPeriodMetricMap(out, "180d"))
|
out["customer_score_180d"] = productPerformanceCustomerSalesPeriodScore(rowPeriodMetricMap(out, "180d"))
|
||||||
out["customer_score_365d"] = productPerformanceCustomerSalesPeriodScore(rowPeriodMetricMap(out, "365d"))
|
out["customer_score_365d"] = productPerformanceCustomerSalesPeriodScore(rowPeriodMetricMap(out, "365d"))
|
||||||
|
|||||||
@@ -176,6 +176,7 @@
|
|||||||
v-if="getCachedProductImageUrl(props.row)"
|
v-if="getCachedProductImageUrl(props.row)"
|
||||||
:src="getCachedProductImageUrl(props.row)"
|
:src="getCachedProductImageUrl(props.row)"
|
||||||
class="product-thumb"
|
class="product-thumb"
|
||||||
|
@error="markProductImageFailed(props.row)"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -286,6 +287,7 @@
|
|||||||
v-if="getCachedProductImageUrl(props.row)"
|
v-if="getCachedProductImageUrl(props.row)"
|
||||||
:src="getCachedProductImageUrl(props.row)"
|
:src="getCachedProductImageUrl(props.row)"
|
||||||
class="product-thumb"
|
class="product-thumb"
|
||||||
|
@error="markProductImageFailed(props.row)"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -327,6 +329,7 @@
|
|||||||
v-if="getCachedProductImageUrl(props.row)"
|
v-if="getCachedProductImageUrl(props.row)"
|
||||||
:src="getCachedProductImageUrl(props.row)"
|
:src="getCachedProductImageUrl(props.row)"
|
||||||
class="product-thumb"
|
class="product-thumb"
|
||||||
|
@error="markProductImageFailed(props.row)"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -363,6 +366,7 @@
|
|||||||
v-if="getCachedProductImageUrl(props.row)"
|
v-if="getCachedProductImageUrl(props.row)"
|
||||||
:src="getCachedProductImageUrl(props.row)"
|
:src="getCachedProductImageUrl(props.row)"
|
||||||
class="product-thumb"
|
class="product-thumb"
|
||||||
|
@error="markProductImageFailed(props.row)"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -616,6 +620,7 @@
|
|||||||
v-if="getCachedProductImageUrl(props.row)"
|
v-if="getCachedProductImageUrl(props.row)"
|
||||||
:src="getCachedProductImageUrl(props.row)"
|
:src="getCachedProductImageUrl(props.row)"
|
||||||
class="product-thumb"
|
class="product-thumb"
|
||||||
|
@error="markProductImageFailed(props.row)"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -652,6 +657,7 @@
|
|||||||
v-if="getCachedProductImageUrl(props.row)"
|
v-if="getCachedProductImageUrl(props.row)"
|
||||||
:src="getCachedProductImageUrl(props.row)"
|
:src="getCachedProductImageUrl(props.row)"
|
||||||
class="product-thumb"
|
class="product-thumb"
|
||||||
|
@error="markProductImageFailed(props.row)"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -761,6 +767,7 @@
|
|||||||
v-if="getCachedProductImageUrl(props.row)"
|
v-if="getCachedProductImageUrl(props.row)"
|
||||||
:src="getCachedProductImageUrl(props.row)"
|
:src="getCachedProductImageUrl(props.row)"
|
||||||
class="product-thumb"
|
class="product-thumb"
|
||||||
|
@error="markProductImageFailed(props.row)"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -798,6 +805,7 @@
|
|||||||
v-if="getCachedProductImageUrl(props.row)"
|
v-if="getCachedProductImageUrl(props.row)"
|
||||||
:src="getCachedProductImageUrl(props.row)"
|
:src="getCachedProductImageUrl(props.row)"
|
||||||
class="product-thumb"
|
class="product-thumb"
|
||||||
|
@error="markProductImageFailed(props.row)"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -834,6 +842,7 @@
|
|||||||
v-if="getCachedProductImageUrl(props.row)"
|
v-if="getCachedProductImageUrl(props.row)"
|
||||||
:src="getCachedProductImageUrl(props.row)"
|
:src="getCachedProductImageUrl(props.row)"
|
||||||
class="product-thumb"
|
class="product-thumb"
|
||||||
|
@error="markProductImageFailed(props.row)"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
decoding="async"
|
decoding="async"
|
||||||
alt=""
|
alt=""
|
||||||
@@ -2477,6 +2486,14 @@ function aggregateGroupFields (sourceRows, groupField = '') {
|
|||||||
|
|
||||||
for (const field of fields) {
|
for (const field of fields) {
|
||||||
if (field === 'row_key' || field === 'key') continue
|
if (field === 'row_key' || field === 'key') continue
|
||||||
|
if (field === 'stock_qty') {
|
||||||
|
out[field] = distinctVariantStockQty(sourceRows)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (field === 'idle_cost_usd') {
|
||||||
|
out[field] = distinctVariantStockCost(sourceRows)
|
||||||
|
continue
|
||||||
|
}
|
||||||
if (shouldSumField(field)) {
|
if (shouldSumField(field)) {
|
||||||
out[field] = sumRows(sourceRows, field)
|
out[field] = sumRows(sourceRows, field)
|
||||||
} else if (shouldAverageField(field)) {
|
} else if (shouldAverageField(field)) {
|
||||||
@@ -2532,6 +2549,9 @@ function applyDerivedGroupMetrics (out, sourceRows, groupField = '') {
|
|||||||
|
|
||||||
const orderQty = Number(out.order_qty || 0)
|
const orderQty = Number(out.order_qty || 0)
|
||||||
if (orderQty > 0) out.avg_order_price_usd = Number(out.order_usd || 0) / orderQty
|
if (orderQty > 0) out.avg_order_price_usd = Number(out.order_usd || 0) / orderQty
|
||||||
|
if (out.net_stock_after_order !== undefined || orderQty > 0) {
|
||||||
|
out.net_stock_after_order = Number(out.stock_qty || 0) - orderQty
|
||||||
|
}
|
||||||
|
|
||||||
if (sourceRows.some(row => row.performance_bucket)) {
|
if (sourceRows.some(row => row.performance_bucket)) {
|
||||||
out.performance_bucket = dominantValue(sourceRows, 'performance_bucket')
|
out.performance_bucket = dominantValue(sourceRows, 'performance_bucket')
|
||||||
@@ -2618,6 +2638,47 @@ function sumRows (sourceRows, field) {
|
|||||||
return sourceRows.reduce((sum, row) => sum + Number(row[field] || 0), 0)
|
return sourceRows.reduce((sum, row) => sum + Number(row[field] || 0), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function productVariantStockKey (row) {
|
||||||
|
const productCode = String(row?.product_code || row?.image_product_code || '').trim()
|
||||||
|
const colorCode = String(row?.color_code || row?.image_color_code || '').trim()
|
||||||
|
const yakaKodu = String(row?.yaka_kodu || row?.image_yaka_kodu || '').trim()
|
||||||
|
if (!productCode && !colorCode && !yakaKodu) return ''
|
||||||
|
return `${productCode}|${colorCode}|${yakaKodu}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function distinctVariantStockQty (sourceRows) {
|
||||||
|
const seen = new Set()
|
||||||
|
let total = 0
|
||||||
|
let keyed = false
|
||||||
|
for (const row of sourceRows) {
|
||||||
|
const key = productVariantStockKey(row)
|
||||||
|
const stockQty = Number(row?.stock_qty || 0)
|
||||||
|
if (!key) continue
|
||||||
|
keyed = true
|
||||||
|
if (seen.has(key)) continue
|
||||||
|
seen.add(key)
|
||||||
|
total += stockQty
|
||||||
|
}
|
||||||
|
return keyed ? total : sumRows(sourceRows, 'stock_qty')
|
||||||
|
}
|
||||||
|
|
||||||
|
function distinctVariantStockCost (sourceRows) {
|
||||||
|
const seen = new Set()
|
||||||
|
let total = 0
|
||||||
|
let keyed = false
|
||||||
|
for (const row of sourceRows) {
|
||||||
|
const key = productVariantStockKey(row)
|
||||||
|
if (!key) continue
|
||||||
|
keyed = true
|
||||||
|
if (seen.has(key)) continue
|
||||||
|
seen.add(key)
|
||||||
|
const stockQty = Number(row?.stock_qty || 0)
|
||||||
|
const costPrice = Number(row?.cost_price_usd || 0)
|
||||||
|
total += stockQty * costPrice
|
||||||
|
}
|
||||||
|
return keyed ? total : sumRows(sourceRows, 'idle_cost_usd')
|
||||||
|
}
|
||||||
|
|
||||||
function distinctCount (sourceRows, field) {
|
function distinctCount (sourceRows, field) {
|
||||||
const values = new Set()
|
const values = new Set()
|
||||||
for (const row of sourceRows) {
|
for (const row of sourceRows) {
|
||||||
@@ -3234,6 +3295,14 @@ function getCachedProductImageUrl (row) {
|
|||||||
return imageUrlByKey.value[key] || performanceStore.imageUrl(key) || ''
|
return imageUrlByKey.value[key] || performanceStore.imageUrl(key) || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function markProductImageFailed (row) {
|
||||||
|
const key = productImageKey(row)
|
||||||
|
if (!key) return
|
||||||
|
performanceStore.setImageCache(key, [])
|
||||||
|
imageListByKey.value = { ...imageListByKey.value, [key]: [] }
|
||||||
|
imageUrlByKey.value = { ...imageUrlByKey.value, [key]: '' }
|
||||||
|
}
|
||||||
|
|
||||||
async function primeProductImages (sourceRows) {
|
async function primeProductImages (sourceRows) {
|
||||||
imagePrimeActiveRequests += 1
|
imagePrimeActiveRequests += 1
|
||||||
imagePrimeLoading.value = true
|
imagePrimeLoading.value = true
|
||||||
@@ -4166,48 +4235,56 @@ onMounted(reload)
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-row td {
|
.performance-table :deep(.q-table tbody tr.group-row td) {
|
||||||
background: color-mix(in srgb, var(--q-primary) 8%, #ffffff);
|
background: #edf3fb;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: color-mix(in srgb, var(--q-primary) 55%, #1f2937);
|
color: #1f2937;
|
||||||
border-color: color-mix(in srgb, var(--q-primary) 18%, #d5dce5);
|
border-color: #c4d2e2;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-row-level-0 td {
|
.performance-table :deep(.q-table tbody tr.group-row.group-row-level-0 td) {
|
||||||
background: color-mix(in srgb, var(--q-primary) 82%, #1f2937);
|
background: #2f5f8f;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-color: color-mix(in srgb, var(--q-primary) 75%, #111827);
|
border-color: #244b72;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-row-level-1 td {
|
.performance-table :deep(.q-table tbody tr.group-row.group-row-level-1 td) {
|
||||||
background: color-mix(in srgb, var(--q-primary) 68%, #ffffff);
|
background: #4f7fad;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-color: color-mix(in srgb, var(--q-primary) 58%, #d5dce5);
|
border-color: #426d96;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-row-level-2 td {
|
.performance-table :deep(.q-table tbody tr.group-row.group-row-level-2 td) {
|
||||||
background: color-mix(in srgb, var(--q-primary) 36%, #ffffff);
|
background: #d8e6f4;
|
||||||
color: color-mix(in srgb, var(--q-primary) 65%, #111827);
|
color: #1f2937;
|
||||||
border-color: color-mix(in srgb, var(--q-primary) 34%, #d5dce5);
|
border-color: #b8cce0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-row-level-3 td {
|
.performance-table :deep(.q-table tbody tr.group-row.group-row-level-3 td) {
|
||||||
background: color-mix(in srgb, var(--q-primary) 22%, #ffffff);
|
background: #e6eef7;
|
||||||
color: color-mix(in srgb, var(--q-primary) 58%, #1f2937);
|
color: #1f2937;
|
||||||
border-color: color-mix(in srgb, var(--q-primary) 24%, #d5dce5);
|
border-color: #c4d2e2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-row-level-4 td {
|
.performance-table :deep(.q-table tbody tr.group-row.group-row-level-4 td) {
|
||||||
background: color-mix(in srgb, var(--q-primary) 14%, #ffffff);
|
background: #eef4fa;
|
||||||
color: color-mix(in srgb, var(--q-primary) 52%, #1f2937);
|
color: #1f2937;
|
||||||
border-color: color-mix(in srgb, var(--q-primary) 18%, #d5dce5);
|
border-color: #cbd8e6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-row-level-5 td {
|
.performance-table :deep(.q-table tbody tr.group-row.group-row-level-5 td) {
|
||||||
background: color-mix(in srgb, var(--q-primary) 8%, #ffffff);
|
background: #f4f8fc;
|
||||||
color: color-mix(in srgb, var(--q-primary) 48%, #1f2937);
|
color: #1f2937;
|
||||||
border-color: color-mix(in srgb, var(--q-primary) 14%, #d5dce5);
|
border-color: #d5dce5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.performance-table :deep(.q-table tbody tr.group-row td span),
|
||||||
|
.performance-table :deep(.q-table tbody tr.group-row .group-title),
|
||||||
|
.performance-table :deep(.q-table tbody tr.group-row .q-btn),
|
||||||
|
.performance-table :deep(.q-table tbody tr.group-row .q-icon) {
|
||||||
|
color: inherit;
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-cell-label {
|
.group-cell-label {
|
||||||
|
|||||||
Reference in New Issue
Block a user