product performance grouped kpi improvements

This commit is contained in:
M_Kececi
2026-07-03 02:37:58 +03:00
parent e7a4c58934
commit c7ff2328fb
+241 -80
View File
@@ -343,7 +343,7 @@
<div <div
v-else-if="col.name === groupLabelColumnName(props.row)" v-else-if="col.name === groupLabelColumnName(props.row)"
class="group-cell-label" class="group-cell-label"
:style="{ paddingLeft: `${props.row.level * 18}px` }" :style="{ paddingLeft: groupIndentPx(props.row) }"
> >
<q-btn <q-btn
flat flat
@@ -496,7 +496,7 @@
<div <div
v-if="col.name === groupLabelColumnName(props.row)" v-if="col.name === groupLabelColumnName(props.row)"
class="group-cell-label" class="group-cell-label"
:style="{ paddingLeft: `${props.row.level * 18}px` }" :style="{ paddingLeft: groupIndentPx(props.row) }"
> >
<q-btn <q-btn
flat flat
@@ -634,7 +634,7 @@
<div <div
v-else-if="col.name === groupLabelColumnName(props.row)" v-else-if="col.name === groupLabelColumnName(props.row)"
class="group-cell-label" class="group-cell-label"
:style="{ paddingLeft: `${props.row.level * 18}px` }" :style="{ paddingLeft: groupIndentPx(props.row) }"
> >
<q-btn <q-btn
flat flat
@@ -819,7 +819,7 @@
<div <div
v-else-if="col.name === groupLabelColumnName(props.row)" v-else-if="col.name === groupLabelColumnName(props.row)"
class="group-cell-label" class="group-cell-label"
:style="{ paddingLeft: `${props.row.level * 18}px` }" :style="{ paddingLeft: groupIndentPx(props.row) }"
> >
<q-btn <q-btn
flat flat
@@ -1077,7 +1077,7 @@
<div <div
v-if="col.name === groupLabelColumnName(props.row)" v-if="col.name === groupLabelColumnName(props.row)"
class="group-cell-label" class="group-cell-label"
:style="{ paddingLeft: `${props.row.level * 18}px` }" :style="{ paddingLeft: groupIndentPx(props.row) }"
> >
<q-btn <q-btn
flat flat
@@ -1523,17 +1523,19 @@ let imagePrimeActiveRequests = 0
const columnFilters = reactive({}) const columnFilters = reactive({})
const columnFilterSearch = reactive({}) const columnFilterSearch = reactive({})
const expandedGroups = ref({}) const expandedGroups = ref({})
const lastManualExpandedGroupKey = ref('')
const selectedExpandLevelKeysByTab = reactive({ const selectedExpandLevelKeysByTab = reactive({
products: ['kategori', 'askili_yan', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu', 'product_code', 'item_description', 'color_code', 'yaka_kodu', 'market_key'], products: ['kategori', 'askili_yan', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu'],
sales_color_yaka_market_customer: ['color_code', 'yaka_kodu', 'askili_yan', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu', 'product_code', 'item_description', 'country', 'market_key', 'customer_segment', 'customer_code', 'customer_name'], sales_color_yaka_market_customer: ['color_code', 'yaka_kodu', 'askili_yan', 'urun_ilk_grubu'],
idle: ['askili_yan', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu', 'product_code', 'item_description', 'color_code', 'yaka_kodu'], idle: ['askili_yan', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu'],
sales_product_country_segment_market_customer: ['market_key', 'customer_code', 'customer_name', 'kategori', 'askili_yan', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu', 'product_code', 'item_description', 'color_code', 'yaka_kodu'], sales_product_country_segment_market_customer: ['market_key', 'customer_code', 'customer_name', 'kategori'],
sales_market_customer_product: ['market_key', 'customer_code', 'customer_name', 'kategori', 'askili_yan', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu', 'product_code', 'item_description', 'color_code', 'yaka_kodu'], sales_market_customer_product: ['market_key', 'customer_code', 'customer_name', 'kategori'],
sales_country_segment_market_customer_product: ['market_key', 'customer_code', 'customer_name', 'kategori', 'askili_yan', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu', 'product_code', 'item_description', 'color_code', 'yaka_kodu'], sales_country_segment_market_customer_product: ['market_key', 'customer_code', 'customer_name', 'kategori'],
order_product_customers: ['market_key', 'customer_code', 'customer_name', 'kategori', 'askili_yan', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu', 'product_code', 'item_description', 'color_code', 'yaka_kodu'], order_product_customers: ['market_key', 'customer_code', 'customer_name', 'kategori'],
order_market_details: ['market_key', 'customer_code', 'customer_name', 'kategori', 'askili_yan', 'urun_ilk_grubu', 'urun_ana_grubu', 'urun_alt_grubu', 'product_code', 'item_description', 'color_code', 'yaka_kodu'] order_market_details: ['market_key', 'customer_code', 'customer_name', 'kategori']
}) })
const productKpiFetchLimit = 50000 const productKpiFetchLimit = 50000
const maxBulkExpandKeys = 1200
const performanceTabs = [ const performanceTabs = [
{ name: 'products', icon: 'inventory_2', label: 'Ürün KPI' }, { name: 'products', icon: 'inventory_2', label: 'Ürün KPI' },
{ name: 'sales_color_yaka_market_customer', icon: 'palette', label: 'Renk > Yaka > Piyasa > Müşteri' }, { name: 'sales_color_yaka_market_customer', icon: 'palette', label: 'Renk > Yaka > Piyasa > Müşteri' },
@@ -1668,6 +1670,49 @@ const periodColumnRules = [
{ period: 'total', match: name => name.includes('_total') } { period: 'total', match: name => name.includes('_total') }
] ]
const periodOrder = {
90: 1,
180: 2,
360: 3,
total: 4
}
const metricOrderFragments = [
'customer_score',
'performance_score',
'product_count',
'market_count',
'customer_count',
'invoice_count',
'order_count',
'line_count',
'sales_qty',
'order_qty',
'sales_usd',
'order_usd',
'avg_price',
'avg_order_price',
'sales_index',
'avg_daily_sales',
'stock_days',
'stock_turnover',
'base_price',
'cost_price',
'base_cost',
'cost_amount',
'unit_profit_base',
'unit_profit_cost',
'gross_profit_usd',
'gross_profit_base',
'gross_profit_cost',
'expected_profit_base',
'expected_profit_cost',
'gross_margin_base',
'gross_margin_cost',
'expected_margin_base',
'expected_margin_cost'
]
const selectedPeriodSet = computed(() => new Set(selectedPeriods.value)) const selectedPeriodSet = computed(() => new Set(selectedPeriods.value))
function columnPeriod (name) { function columnPeriod (name) {
@@ -1679,7 +1724,44 @@ function visiblePeriodColumn (col) {
return !period || selectedPeriodSet.value.has(period) return !period || selectedPeriodSet.value.has(period)
} }
const productColumns = computed(() => columns.filter(visiblePeriodColumn)) function metricBaseName (name) {
return String(name || '')
.replace(/_90d$|_180d$|_365d$|_total$/g, '')
}
function metricOrder (name) {
const base = metricBaseName(name)
const idx = metricOrderFragments.findIndex(fragment => base.includes(fragment))
return idx >= 0 ? idx : 999
}
function isTrailingInfoColumn (name) {
return ['performance_bucket', 'recommendation', 'last_sale_date', 'first_sale_date', 'is_overdue'].includes(name)
}
function orderedMetricColumns (sourceColumns) {
return [...sourceColumns].sort((a, b) => {
const aPeriod = columnPeriod(a.name)
const bPeriod = columnPeriod(b.name)
const aTrailing = isTrailingInfoColumn(a.name)
const bTrailing = isTrailingInfoColumn(b.name)
if (aTrailing !== bTrailing) return aTrailing ? 1 : -1
if (!aPeriod && !bPeriod) return 0
if (!aPeriod) return -1
if (!bPeriod) return 1
const periodDiff = periodOrder[aPeriod] - periodOrder[bPeriod]
if (periodDiff) return periodDiff
const metricDiff = metricOrder(a.name) - metricOrder(b.name)
return metricDiff || 0
})
}
function reorderColumnsInPlace (targetColumns) {
targetColumns.splice(0, targetColumns.length, ...orderedMetricColumns(targetColumns))
return targetColumns
}
const productColumns = computed(() => orderedMetricColumns(columns.filter(visiblePeriodColumn)))
const generalColumns = [ const generalColumns = [
{ name: 'image', label: 'Foto', field: 'image', align: 'center' }, { name: 'image', label: 'Foto', field: 'image', align: 'center' },
@@ -1986,7 +2068,21 @@ const salesBreakdownColumns = [
{ name: 'recommendation', label: 'Öneri', field: 'recommendation', align: 'left' } { name: 'recommendation', label: 'Öneri', field: 'recommendation', align: 'left' }
] ]
const visibleSalesBreakdownColumns = computed(() => salesBreakdownColumns.filter(visiblePeriodColumn)) ;[
columns,
generalColumns,
orderAnalysisColumns,
orderGroupColumns,
orderProductCustomerColumns,
orderMarketDetailColumns,
idleColumns,
marketColumns,
countryColumns,
customerColumns,
salesBreakdownColumns
].forEach(reorderColumnsInPlace)
const visibleSalesBreakdownColumns = computed(() => orderedMetricColumns(salesBreakdownColumns.filter(visiblePeriodColumn)))
const summaryCards = computed(() => [ const summaryCards = computed(() => [
{ key: 'date', label: 'KPI Tarihi', value: summary.value.kpi_date || '-' }, { key: 'date', label: 'KPI Tarihi', value: summary.value.kpi_date || '-' },
@@ -2369,6 +2465,7 @@ function backendRowsForTab (tabKey, fallbackRows) {
} }
function collectGroupKeys (out, sourceRows, level, parentKeys, levels = groupLevels, maxLevel = levels.length - 1) { function collectGroupKeys (out, sourceRows, level, parentKeys, levels = groupLevels, maxLevel = levels.length - 1) {
if (out.length >= maxBulkExpandKeys) return
if (level >= levels.length) return if (level >= levels.length) return
const groupDef = levels[level] const groupDef = levels[level]
@@ -2382,6 +2479,7 @@ function collectGroupKeys (out, sourceRows, level, parentKeys, levels = groupLev
Array.from(grouped.entries()) Array.from(grouped.entries())
.sort((a, b) => a[0].localeCompare(b[0], 'tr')) .sort((a, b) => a[0].localeCompare(b[0], 'tr'))
.forEach(([value, groupRows]) => { .forEach(([value, groupRows]) => {
if (out.length >= maxBulkExpandKeys) return
const key = [...parentKeys, `${groupDef.key}:${value}`].join('|') const key = [...parentKeys, `${groupDef.key}:${value}`].join('|')
out.push(key) out.push(key)
if (level < maxLevel) { if (level < maxLevel) {
@@ -2774,6 +2872,7 @@ function isGroupExpanded (key) {
} }
function toggleGroup (key) { function toggleGroup (key) {
lastManualExpandedGroupKey.value = key
expandedGroups.value = { expandedGroups.value = {
...expandedGroups.value, ...expandedGroups.value,
[key]: !isGroupExpanded(key) [key]: !isGroupExpanded(key)
@@ -2792,14 +2891,26 @@ function toggleAllProductGroups () {
function collapseAllProductGroups () { function collapseAllProductGroups () {
expandedGroups.value = {} expandedGroups.value = {}
lastManualExpandedGroupKey.value = ''
scheduleLoadBackendGroupedRows() scheduleLoadBackendGroupedRows()
} }
function expandSelectedProductGroups () { function expandSelectedProductGroups () {
const keys = productAutoExpandKeys.value const keys = productAutoExpandKeys.value
const next = { ...expandedGroups.value } const expandableKeys = keys.slice(0, maxBulkExpandKeys)
for (const key of keys) next[key] = true const tabPrefix = `tab:${activeTab.value}|`
const next = Object.fromEntries(
Object.entries(expandedGroups.value).filter(([key]) => !key.startsWith(tabPrefix))
)
for (const key of expandableKeys) next[key] = true
expandedGroups.value = next expandedGroups.value = next
lastManualExpandedGroupKey.value = ''
if (keys.length > expandableKeys.length) {
Notify.create({
type: 'warning',
message: `${formatNumber(expandableKeys.length, 0)} grup açıldı. Daha derin detaylar için satırları kademeli açın.`
})
}
scheduleLoadBackendGroupedRows() scheduleLoadBackendGroupedRows()
} }
@@ -2807,6 +2918,10 @@ function groupLabelColumnName (row) {
return row?.group_field || 'product_code' return row?.group_field || 'product_code'
} }
function groupIndentPx (row) {
return '0px'
}
function groupShowsImage (row) { function groupShowsImage (row) {
return Number(row?.level ?? 0) < autoExpandThroughLevel.value return Number(row?.level ?? 0) < autoExpandThroughLevel.value
} }
@@ -3412,11 +3527,31 @@ function backendGroupedSupportedTab (tabKey = activeTab.value) {
function activeExpandedGroupKeys () { function activeExpandedGroupKeys () {
const tabPrefix = `tab:${activeTab.value}|` const tabPrefix = `tab:${activeTab.value}|`
const validFields = new Set(activeGroupLevels.value.map(level => level.key)) const validFields = new Set(activeGroupLevels.value.map(level => level.key))
return Object.entries(expandedGroups.value) const keys = Object.entries(expandedGroups.value)
.filter(([, value]) => value === true) .filter(([, value]) => value === true)
.map(([key]) => key) .map(([key]) => key)
.filter(key => key.startsWith(tabPrefix)) .filter(key => key.startsWith(tabPrefix))
.filter(key => key.split('|').slice(1).every(part => validFields.has(String(part).split(':')[0]))) .filter(key => key.split('|').slice(1).every(part => validFields.has(String(part).split(':')[0])))
const manualKey = lastManualExpandedGroupKey.value
const out = []
if (manualKey && keys.includes(manualKey)) out.push(manualKey)
for (const key of keys) {
if (out.length >= maxBulkExpandKeys) break
if (key !== manualKey) out.push(key)
}
return out
}
function pruneActiveExpandedGroups () {
const tabPrefix = `tab:${activeTab.value}|`
const allowed = new Set(activeExpandedGroupKeys())
const next = {}
for (const [key, value] of Object.entries(expandedGroups.value)) {
if (!value) continue
if (key.startsWith(tabPrefix) && !allowed.has(key)) continue
next[key] = value
}
expandedGroups.value = next
} }
function scheduleLoadBackendGroupedRows () { function scheduleLoadBackendGroupedRows () {
@@ -3436,6 +3571,7 @@ function switchPerformanceTab (tabName) {
async function loadBackendGroupedRows () { async function loadBackendGroupedRows () {
const tabKey = activeTab.value const tabKey = activeTab.value
if (!backendGroupedSupportedTab(tabKey)) return if (!backendGroupedSupportedTab(tabKey)) return
pruneActiveExpandedGroups()
backendGroupedLoading.value = true backendGroupedLoading.value = true
const params = { const params = {
mode: tabKey, mode: tabKey,
@@ -3824,6 +3960,12 @@ onMounted(reload)
padding: 4px 5px; padding: 4px 5px;
} }
.performance-table :deep(.q-table th) {
height: 42px;
min-height: 42px;
padding: 3px 4px;
}
.performance-table :deep(.q-table tbody tr), .performance-table :deep(.q-table tbody tr),
.performance-table :deep(.q-table tbody td) { .performance-table :deep(.q-table tbody td) {
height: auto; height: auto;
@@ -3905,7 +4047,7 @@ onMounted(reload)
} }
.product-breakdown-table :deep(.q-table) { .product-breakdown-table :deep(.q-table) {
min-width: 2500px; min-width: 3000px;
table-layout: fixed; table-layout: fixed;
} }
@@ -3935,81 +4077,81 @@ onMounted(reload)
.product-breakdown-table :deep(.q-table th:nth-child(2)), .product-breakdown-table :deep(.q-table th:nth-child(2)),
.product-breakdown-table :deep(.q-table td:nth-child(2)) { .product-breakdown-table :deep(.q-table td:nth-child(2)) {
left: 72px; left: 72px;
width: 100px; width: 140px;
min-width: 100px; min-width: 140px;
max-width: 100px; max-width: 140px;
} }
.product-breakdown-table :deep(.q-table th:nth-child(3)), .product-breakdown-table :deep(.q-table th:nth-child(3)),
.product-breakdown-table :deep(.q-table td:nth-child(3)) { .product-breakdown-table :deep(.q-table td:nth-child(3)) {
left: 172px; left: 212px;
width: 54px; width: 110px;
min-width: 54px; min-width: 110px;
max-width: 54px; max-width: 110px;
} }
.product-breakdown-table :deep(.q-table th:nth-child(4)), .product-breakdown-table :deep(.q-table th:nth-child(4)),
.product-breakdown-table :deep(.q-table td:nth-child(4)) { .product-breakdown-table :deep(.q-table td:nth-child(4)) {
left: 226px; left: 322px;
width: 54px; width: 150px;
min-width: 54px; min-width: 150px;
max-width: 54px; max-width: 150px;
} }
.product-breakdown-table :deep(.q-table th:nth-child(5)), .product-breakdown-table :deep(.q-table th:nth-child(5)),
.product-breakdown-table :deep(.q-table td:nth-child(5)) { .product-breakdown-table :deep(.q-table td:nth-child(5)) {
left: 280px; left: 472px;
width: 160px; width: 170px;
min-width: 160px; min-width: 170px;
max-width: 160px; max-width: 170px;
} }
.product-breakdown-table :deep(.q-table th:nth-child(6)), .product-breakdown-table :deep(.q-table th:nth-child(6)),
.product-breakdown-table :deep(.q-table td:nth-child(6)) { .product-breakdown-table :deep(.q-table td:nth-child(6)) {
left: 440px; left: 642px;
width: 92px; width: 150px;
min-width: 92px; min-width: 150px;
max-width: 92px; max-width: 150px;
} }
.product-breakdown-table :deep(.q-table th:nth-child(7)), .product-breakdown-table :deep(.q-table th:nth-child(7)),
.product-breakdown-table :deep(.q-table td:nth-child(7)) { .product-breakdown-table :deep(.q-table td:nth-child(7)) {
left: 532px; left: 792px;
width: 86px; width: 130px;
min-width: 86px; min-width: 130px;
max-width: 86px; max-width: 130px;
} }
.product-breakdown-table :deep(.q-table th:nth-child(8)), .product-breakdown-table :deep(.q-table th:nth-child(8)),
.product-breakdown-table :deep(.q-table td:nth-child(8)) { .product-breakdown-table :deep(.q-table td:nth-child(8)) {
left: 618px; left: 922px;
width: 110px; width: 180px;
min-width: 110px; min-width: 180px;
max-width: 110px; max-width: 180px;
} }
.product-breakdown-table :deep(.q-table th:nth-child(9)), .product-breakdown-table :deep(.q-table th:nth-child(9)),
.product-breakdown-table :deep(.q-table td:nth-child(9)) { .product-breakdown-table :deep(.q-table td:nth-child(9)) {
left: 728px; left: 1102px;
width: 110px; width: 90px;
min-width: 110px; min-width: 90px;
max-width: 110px; max-width: 90px;
} }
.product-breakdown-table :deep(.q-table th:nth-child(10)), .product-breakdown-table :deep(.q-table th:nth-child(10)),
.product-breakdown-table :deep(.q-table td:nth-child(10)) { .product-breakdown-table :deep(.q-table td:nth-child(10)) {
left: 838px; left: 1192px;
width: 110px; width: 80px;
min-width: 110px; min-width: 80px;
max-width: 110px; max-width: 80px;
} }
.product-breakdown-table :deep(.q-table th:nth-child(11)), .product-breakdown-table :deep(.q-table th:nth-child(11)),
.product-breakdown-table :deep(.q-table td:nth-child(11)) { .product-breakdown-table :deep(.q-table td:nth-child(11)) {
left: 948px; left: 1272px;
width: 160px; width: 130px;
min-width: 160px; min-width: 130px;
max-width: 160px; max-width: 130px;
box-shadow: 8px 0 10px -10px rgba(17, 24, 39, 0.45); box-shadow: 8px 0 10px -10px rgba(17, 24, 39, 0.45);
} }
@@ -4020,9 +4162,9 @@ onMounted(reload)
.sticky-dim-table :deep(.q-table th), .sticky-dim-table :deep(.q-table th),
.sticky-dim-table :deep(.q-table td) { .sticky-dim-table :deep(.q-table td) {
min-width: 104px; min-width: 118px;
width: 104px; width: 118px;
max-width: 150px; max-width: 180px;
} }
.sticky-dim-table :deep(.q-table th.text-right), .sticky-dim-table :deep(.q-table th.text-right),
@@ -4068,52 +4210,52 @@ onMounted(reload)
.sticky-dim-table :deep(.q-table th:nth-child(2)), .sticky-dim-table :deep(.q-table th:nth-child(2)),
.sticky-dim-table :deep(.q-table td:nth-child(2)) { .sticky-dim-table :deep(.q-table td:nth-child(2)) {
left: 104px; left: 118px;
} }
.sticky-dim-table :deep(.q-table th:nth-child(3)), .sticky-dim-table :deep(.q-table th:nth-child(3)),
.sticky-dim-table :deep(.q-table td:nth-child(3)) { .sticky-dim-table :deep(.q-table td:nth-child(3)) {
left: 208px; left: 236px;
} }
.sticky-dim-table :deep(.q-table th:nth-child(4)), .sticky-dim-table :deep(.q-table th:nth-child(4)),
.sticky-dim-table :deep(.q-table td:nth-child(4)) { .sticky-dim-table :deep(.q-table td:nth-child(4)) {
left: 312px; left: 354px;
} }
.sticky-dim-table :deep(.q-table th:nth-child(5)), .sticky-dim-table :deep(.q-table th:nth-child(5)),
.sticky-dim-table :deep(.q-table td:nth-child(5)) { .sticky-dim-table :deep(.q-table td:nth-child(5)) {
left: 416px; left: 472px;
} }
.sticky-dim-table :deep(.q-table th:nth-child(6)), .sticky-dim-table :deep(.q-table th:nth-child(6)),
.sticky-dim-table :deep(.q-table td:nth-child(6)) { .sticky-dim-table :deep(.q-table td:nth-child(6)) {
left: 520px; left: 590px;
} }
.sticky-dim-table :deep(.q-table th:nth-child(7)), .sticky-dim-table :deep(.q-table th:nth-child(7)),
.sticky-dim-table :deep(.q-table td:nth-child(7)) { .sticky-dim-table :deep(.q-table td:nth-child(7)) {
left: 624px; left: 708px;
} }
.sticky-dim-table :deep(.q-table th:nth-child(8)), .sticky-dim-table :deep(.q-table th:nth-child(8)),
.sticky-dim-table :deep(.q-table td:nth-child(8)) { .sticky-dim-table :deep(.q-table td:nth-child(8)) {
left: 728px; left: 826px;
} }
.sticky-dim-table :deep(.q-table th:nth-child(9)), .sticky-dim-table :deep(.q-table th:nth-child(9)),
.sticky-dim-table :deep(.q-table td:nth-child(9)) { .sticky-dim-table :deep(.q-table td:nth-child(9)) {
left: 832px; left: 944px;
} }
.sticky-dim-table :deep(.q-table th:nth-child(10)), .sticky-dim-table :deep(.q-table th:nth-child(10)),
.sticky-dim-table :deep(.q-table td:nth-child(10)) { .sticky-dim-table :deep(.q-table td:nth-child(10)) {
left: 936px; left: 1062px;
} }
.sticky-dim-table :deep(.q-table th:nth-child(11)), .sticky-dim-table :deep(.q-table th:nth-child(11)),
.sticky-dim-table :deep(.q-table td:nth-child(11)) { .sticky-dim-table :deep(.q-table td:nth-child(11)) {
left: 1040px; left: 1180px;
} }
.sticky-dim-table.sticky-dim-3 :deep(.q-table th:nth-child(-n+3)), .sticky-dim-table.sticky-dim-3 :deep(.q-table th:nth-child(-n+3)),
@@ -4177,27 +4319,31 @@ onMounted(reload)
.header-with-filter { .header-with-filter {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) 24px; grid-template-columns: minmax(0, 1fr) 18px;
align-items: center; align-items: center;
gap: 4px; gap: 2px;
min-width: 104px; min-width: 82px;
width: 100%;
} }
.header-with-filter > span { .header-with-filter > span {
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 3; -webkit-line-clamp: 3;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
line-height: 1.18; line-height: 1.12;
white-space: normal; white-space: normal;
overflow: hidden; overflow: hidden;
overflow-wrap: anywhere; overflow-wrap: anywhere;
text-overflow: clip; text-overflow: clip;
font-size: 10px;
font-weight: 700;
} }
.header-filter-btn { .header-filter-btn {
width: 24px; width: 18px;
height: 24px; height: 18px;
min-height: 24px; min-height: 18px;
padding: 0;
} }
.header-filter-ghost { .header-filter-ghost {
@@ -4290,12 +4436,27 @@ onMounted(reload)
.group-cell-label { .group-cell-label {
display: flex; display: flex;
align-items: center; align-items: center;
min-width: 180px; gap: 3px;
width: 100%;
min-width: 0;
max-width: 100%;
}
.group-cell-label :deep(.q-btn) {
flex: 0 0 20px;
width: 20px;
height: 20px;
min-height: 20px;
} }
.group-title { .group-title {
margin-left: 4px; flex: 1 1 auto;
min-width: 0;
margin-left: 0;
white-space: normal; white-space: normal;
overflow: visible;
overflow-wrap: anywhere;
line-height: 1.18;
} }
.product-image-cell { .product-image-cell {