product performance grouped kpi improvements

This commit is contained in:
M_Kececi
2026-07-03 02:12:55 +03:00
parent 75e5136ab7
commit 5d5a38647d
+276 -108
View File
@@ -17,14 +17,14 @@
<div class="page-busy-label">Yükleniyor...</div>
</div>
</teleport>
<div class="row items-center justify-between q-col-gutter-sm q-mb-sm">
<div class="performance-top-bar row items-center justify-between q-col-gutter-xs q-mb-xs">
<div class="col-12 col-md">
<div class="text-h6">Ürün Performans ve Karlılık Analizi</div>
<div class="text-caption text-grey-7">
<div class="performance-page-title">Ürün Performans ve Karlılık Analizi</div>
<div class="performance-page-subtitle text-grey-7">
Ürün, renk, yaka, piyasa ve müşteri segmenti bazında satış, stok dönüşü ve karlılık KPI'ları.
</div>
</div>
<div class="col-12 col-md-auto row items-center q-gutter-sm">
<div class="performance-top-actions col-12 col-md-auto row items-center q-gutter-xs">
<q-option-group
v-model="selectedPeriods"
:options="periodOptions"
@@ -32,7 +32,7 @@
inline
dense
:disable="pageBusy"
class="period-selector bg-white q-px-sm q-py-xs"
class="period-selector bg-white q-px-xs q-py-none"
/>
<q-btn-dropdown
dense
@@ -57,11 +57,11 @@
</div>
</div>
</q-btn-dropdown>
<q-btn outline color="secondary" icon="refresh" label="Yenile" :loading="loading" :disable="pageBusy" @click="reload" />
<q-btn dense outline color="secondary" icon="refresh" label="Yenile" :loading="loading" :disable="pageBusy" @click="reload" />
</div>
</div>
<div class="row q-col-gutter-sm q-mb-sm">
<div class="performance-summary-row row q-col-gutter-xs q-mb-xs">
<div v-for="card in summaryCards" :key="card.key" class="col-6 col-md-2">
<q-card flat bordered class="metric-card">
<q-card-section>
@@ -72,7 +72,7 @@
</div>
</div>
<div class="performance-tab-grid q-mb-sm">
<div class="performance-tab-grid q-mb-xs">
<button
v-for="tab in performanceTabs"
:key="tab.name"
@@ -2750,6 +2750,23 @@ function groupShowsImage (row) {
return Number(row?.level ?? 0) < autoExpandThroughLevel.value
}
const groupDimensionFields = new Set([
'product_code',
'color_code',
'yaka_kodu',
'item_description',
'kategori',
'askili_yan',
'urun_ilk_grubu',
'urun_ana_grubu',
'urun_alt_grubu',
'market_key',
'country',
'customer_segment',
'customer_code',
'customer_name'
])
function groupCellClass (colOrName) {
const name = colOrName?.name || colOrName
if (name === 'image') return 'product-image-cell'
@@ -2763,6 +2780,7 @@ function formatGroupCell (row, colOrName) {
const name = colOrName?.name || colOrName
if (name === 'image') return ''
if (name === 'recommendation') return row.recommendation || ''
if (groupDimensionFields.has(name) && name !== row?.group_field) return ''
return formatTableCell(row, colOrName)
}
@@ -3591,15 +3609,73 @@ onMounted(reload)
font-weight: 700;
}
.performance-top-bar {
min-height: 34px;
}
.performance-page-title {
font-size: 14px;
font-weight: 700;
line-height: 1.12;
}
.performance-page-subtitle {
font-size: 10px;
line-height: 1.15;
margin-top: 1px;
}
.performance-top-actions {
min-height: 30px;
}
.performance-top-actions :deep(.q-btn) {
min-height: 26px;
padding: 2px 8px;
font-size: 11px;
line-height: 1.1;
}
.performance-top-actions :deep(.q-btn .q-icon) {
font-size: 16px;
}
.period-selector {
min-height: 26px;
border: 1px solid #d5dce5;
border-radius: 6px;
display: flex;
align-items: center;
}
.period-selector :deep(.q-option-group) {
gap: 4px;
}
.period-selector :deep(.q-checkbox) {
min-height: 22px;
}
.period-selector :deep(.q-checkbox__inner) {
font-size: 26px;
width: 26px;
height: 26px;
}
.period-selector :deep(.q-checkbox__label) {
font-size: 11px;
line-height: 1.1;
}
.performance-tab-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
gap: 6px;
gap: 4px;
}
.performance-tab-button {
min-height: 38px;
padding: 6px 8px;
min-height: 24px;
padding: 3px 6px;
display: inline-flex;
align-items: center;
justify-content: center;
@@ -3608,7 +3684,7 @@ onMounted(reload)
border-radius: 6px;
background: #fff;
color: #4b5563;
font-size: 11px;
font-size: 10px;
font-weight: 700;
line-height: 1.15;
text-align: center;
@@ -3632,27 +3708,37 @@ onMounted(reload)
}
.metric-card {
min-height: 78px;
min-height: 38px;
}
.metric-card :deep(.q-card__section) {
padding: 5px 7px;
}
.metric-card :deep(.text-caption) {
font-size: 10px;
line-height: 1.1;
}
.metric-value {
font-size: 20px;
font-size: 14px;
font-weight: 700;
line-height: 1.25;
margin-top: 4px;
line-height: 1.08;
margin-top: 1px;
}
.detail-level-menu {
width: 260px;
padding: 10px;
width: 230px;
padding: 7px;
}
.performance-table {
max-height: calc(100vh - 260px);
max-height: calc(100vh - 160px);
font-size: 11px;
}
.performance-table :deep(.q-table__middle) {
max-height: calc(100vh - 320px);
max-height: calc(100vh - 220px);
}
.performance-table :deep(.q-table) {
@@ -3666,18 +3752,19 @@ onMounted(reload)
border-bottom: 1px solid #d5dce5;
vertical-align: middle;
white-space: normal;
padding: 4px 5px;
}
.performance-table :deep(.q-table tbody tr),
.performance-table :deep(.q-table tbody td) {
height: auto;
min-height: 48px;
min-height: 38px;
}
.performance-table :deep(.q-table tbody td) {
max-width: 320px;
padding-top: 6px;
padding-bottom: 6px;
padding-top: 4px;
padding-bottom: 4px;
overflow-wrap: anywhere;
}
@@ -3689,13 +3776,52 @@ onMounted(reload)
line-height: 1.25;
}
.performance-table :deep(.q-table th.text-right),
.performance-table :deep(.q-table td.text-right) {
min-width: 98px;
width: 98px;
max-width: none;
white-space: nowrap;
overflow-wrap: normal;
word-break: normal;
}
.performance-table :deep(.q-table td.text-right span:not(.q-badge):not(.q-icon)) {
display: inline-block;
-webkit-line-clamp: unset;
-webkit-box-orient: initial;
max-width: none;
white-space: nowrap;
overflow: visible;
line-height: 1.25;
}
.performance-table :deep(.q-table th.text-right .header-label) {
white-space: normal;
overflow-wrap: anywhere;
}
.performance-table :deep(.q-table th:not(.text-right)),
.performance-table :deep(.q-table td:not(.text-right)) {
white-space: normal;
overflow-wrap: anywhere;
}
.performance-table :deep(.q-table tbody td .q-field),
.performance-table :deep(.q-table tbody td input),
.performance-table :deep(.q-table tbody td textarea) {
min-width: 96px;
min-width: 72px;
max-width: 100%;
}
.performance-table :deep(.q-table tbody td .q-field__control),
.performance-table :deep(.q-table tbody td .q-field__native),
.performance-table :deep(.q-table tbody td .q-field__input) {
min-height: 26px;
font-size: 11px;
line-height: 1.2;
}
.performance-table :deep(.q-table th:first-child),
.performance-table :deep(.q-table td:first-child) {
border-left: 1px solid #d5dce5;
@@ -3710,7 +3836,7 @@ onMounted(reload)
}
.product-breakdown-table :deep(.q-table) {
min-width: 3200px;
min-width: 2500px;
table-layout: fixed;
}
@@ -3732,102 +3858,135 @@ onMounted(reload)
.product-breakdown-table :deep(.q-table th:nth-child(1)),
.product-breakdown-table :deep(.q-table td:nth-child(1)) {
left: 0;
width: 92px;
min-width: 92px;
max-width: 92px;
width: 72px;
min-width: 72px;
max-width: 72px;
}
.product-breakdown-table :deep(.q-table th:nth-child(2)),
.product-breakdown-table :deep(.q-table td:nth-child(2)) {
left: 92px;
width: 120px;
min-width: 120px;
max-width: 120px;
}
.product-breakdown-table :deep(.q-table th:nth-child(3)),
.product-breakdown-table :deep(.q-table td:nth-child(3)) {
left: 212px;
width: 64px;
min-width: 64px;
max-width: 64px;
}
.product-breakdown-table :deep(.q-table th:nth-child(4)),
.product-breakdown-table :deep(.q-table td:nth-child(4)) {
left: 276px;
width: 64px;
min-width: 64px;
max-width: 64px;
}
.product-breakdown-table :deep(.q-table th:nth-child(5)),
.product-breakdown-table :deep(.q-table td:nth-child(5)) {
left: 340px;
width: 200px;
min-width: 200px;
max-width: 200px;
}
.product-breakdown-table :deep(.q-table th:nth-child(6)),
.product-breakdown-table :deep(.q-table td:nth-child(6)) {
left: 540px;
width: 110px;
min-width: 110px;
max-width: 110px;
}
.product-breakdown-table :deep(.q-table th:nth-child(7)),
.product-breakdown-table :deep(.q-table td:nth-child(7)) {
left: 650px;
left: 72px;
width: 100px;
min-width: 100px;
max-width: 100px;
}
.product-breakdown-table :deep(.q-table th:nth-child(3)),
.product-breakdown-table :deep(.q-table td:nth-child(3)) {
left: 172px;
width: 54px;
min-width: 54px;
max-width: 54px;
}
.product-breakdown-table :deep(.q-table th:nth-child(4)),
.product-breakdown-table :deep(.q-table td:nth-child(4)) {
left: 226px;
width: 54px;
min-width: 54px;
max-width: 54px;
}
.product-breakdown-table :deep(.q-table th:nth-child(5)),
.product-breakdown-table :deep(.q-table td:nth-child(5)) {
left: 280px;
width: 160px;
min-width: 160px;
max-width: 160px;
}
.product-breakdown-table :deep(.q-table th:nth-child(6)),
.product-breakdown-table :deep(.q-table td:nth-child(6)) {
left: 440px;
width: 92px;
min-width: 92px;
max-width: 92px;
}
.product-breakdown-table :deep(.q-table th:nth-child(7)),
.product-breakdown-table :deep(.q-table td:nth-child(7)) {
left: 532px;
width: 86px;
min-width: 86px;
max-width: 86px;
}
.product-breakdown-table :deep(.q-table th:nth-child(8)),
.product-breakdown-table :deep(.q-table td:nth-child(8)) {
left: 750px;
width: 130px;
min-width: 130px;
max-width: 130px;
left: 618px;
width: 110px;
min-width: 110px;
max-width: 110px;
}
.product-breakdown-table :deep(.q-table th:nth-child(9)),
.product-breakdown-table :deep(.q-table td:nth-child(9)) {
left: 880px;
width: 130px;
min-width: 130px;
max-width: 130px;
left: 728px;
width: 110px;
min-width: 110px;
max-width: 110px;
}
.product-breakdown-table :deep(.q-table th:nth-child(10)),
.product-breakdown-table :deep(.q-table td:nth-child(10)) {
left: 1010px;
width: 130px;
min-width: 130px;
max-width: 130px;
left: 838px;
width: 110px;
min-width: 110px;
max-width: 110px;
}
.product-breakdown-table :deep(.q-table th:nth-child(11)),
.product-breakdown-table :deep(.q-table td:nth-child(11)) {
left: 1140px;
width: 190px;
min-width: 190px;
max-width: 190px;
left: 948px;
width: 160px;
min-width: 160px;
max-width: 160px;
box-shadow: 8px 0 10px -10px rgba(17, 24, 39, 0.45);
}
.sticky-dim-table :deep(.q-table) {
min-width: 2200px;
min-width: 1700px;
table-layout: fixed;
}
.sticky-dim-table :deep(.q-table th),
.sticky-dim-table :deep(.q-table td) {
min-width: 130px;
width: 130px;
max-width: 180px;
min-width: 104px;
width: 104px;
max-width: 150px;
}
.sticky-dim-table :deep(.q-table th.text-right),
.sticky-dim-table :deep(.q-table td.text-right),
.product-breakdown-table :deep(.q-table th.text-right),
.product-breakdown-table :deep(.q-table td.text-right) {
min-width: 98px;
width: 98px;
max-width: none;
white-space: nowrap;
}
.product-breakdown-table :deep(.q-table th:nth-child(n+12):not(.text-right)),
.product-breakdown-table :deep(.q-table td:nth-child(n+12):not(.text-right)),
.sticky-dim-table.sticky-dim-3 :deep(.q-table th:nth-child(n+4):not(.text-right)),
.sticky-dim-table.sticky-dim-3 :deep(.q-table td:nth-child(n+4):not(.text-right)),
.sticky-dim-table.sticky-dim-5 :deep(.q-table th:nth-child(n+6):not(.text-right)),
.sticky-dim-table.sticky-dim-5 :deep(.q-table td:nth-child(n+6):not(.text-right)),
.sticky-dim-table.sticky-dim-6 :deep(.q-table th:nth-child(n+7):not(.text-right)),
.sticky-dim-table.sticky-dim-6 :deep(.q-table td:nth-child(n+7):not(.text-right)),
.sticky-dim-table.sticky-dim-7 :deep(.q-table th:nth-child(n+8):not(.text-right)),
.sticky-dim-table.sticky-dim-7 :deep(.q-table td:nth-child(n+8):not(.text-right)),
.sticky-dim-table.sticky-dim-8 :deep(.q-table th:nth-child(n+9):not(.text-right)),
.sticky-dim-table.sticky-dim-8 :deep(.q-table td:nth-child(n+9):not(.text-right)),
.sticky-dim-table.sticky-dim-9 :deep(.q-table th:nth-child(n+10):not(.text-right)),
.sticky-dim-table.sticky-dim-9 :deep(.q-table td:nth-child(n+10):not(.text-right)),
.sticky-dim-table.sticky-dim-10 :deep(.q-table th:nth-child(n+11):not(.text-right)),
.sticky-dim-table.sticky-dim-10 :deep(.q-table td:nth-child(n+11):not(.text-right)),
.sticky-dim-table.sticky-dim-11 :deep(.q-table th:nth-child(n+12):not(.text-right)),
.sticky-dim-table.sticky-dim-11 :deep(.q-table td:nth-child(n+12):not(.text-right)) {
min-width: 140px;
width: 140px;
max-width: 210px;
}
.sticky-dim-table :deep(.q-table th:nth-child(1)),
@@ -3840,52 +3999,52 @@ onMounted(reload)
.sticky-dim-table :deep(.q-table th:nth-child(2)),
.sticky-dim-table :deep(.q-table td:nth-child(2)) {
left: 130px;
left: 104px;
}
.sticky-dim-table :deep(.q-table th:nth-child(3)),
.sticky-dim-table :deep(.q-table td:nth-child(3)) {
left: 260px;
left: 208px;
}
.sticky-dim-table :deep(.q-table th:nth-child(4)),
.sticky-dim-table :deep(.q-table td:nth-child(4)) {
left: 390px;
left: 312px;
}
.sticky-dim-table :deep(.q-table th:nth-child(5)),
.sticky-dim-table :deep(.q-table td:nth-child(5)) {
left: 520px;
left: 416px;
}
.sticky-dim-table :deep(.q-table th:nth-child(6)),
.sticky-dim-table :deep(.q-table td:nth-child(6)) {
left: 650px;
left: 520px;
}
.sticky-dim-table :deep(.q-table th:nth-child(7)),
.sticky-dim-table :deep(.q-table td:nth-child(7)) {
left: 780px;
left: 624px;
}
.sticky-dim-table :deep(.q-table th:nth-child(8)),
.sticky-dim-table :deep(.q-table td:nth-child(8)) {
left: 910px;
left: 728px;
}
.sticky-dim-table :deep(.q-table th:nth-child(9)),
.sticky-dim-table :deep(.q-table td:nth-child(9)) {
left: 1040px;
left: 832px;
}
.sticky-dim-table :deep(.q-table th:nth-child(10)),
.sticky-dim-table :deep(.q-table td:nth-child(10)) {
left: 1170px;
left: 936px;
}
.sticky-dim-table :deep(.q-table th:nth-child(11)),
.sticky-dim-table :deep(.q-table td:nth-child(11)) {
left: 1300px;
left: 1040px;
}
.sticky-dim-table.sticky-dim-3 :deep(.q-table th:nth-child(-n+3)),
@@ -3896,6 +4055,8 @@ onMounted(reload)
.sticky-dim-table.sticky-dim-6 :deep(.q-table td:nth-child(-n+6)),
.sticky-dim-table.sticky-dim-7 :deep(.q-table th:nth-child(-n+7)),
.sticky-dim-table.sticky-dim-7 :deep(.q-table td:nth-child(-n+7)),
.sticky-dim-table.sticky-dim-8 :deep(.q-table th:nth-child(-n+8)),
.sticky-dim-table.sticky-dim-8 :deep(.q-table td:nth-child(-n+8)),
.sticky-dim-table.sticky-dim-9 :deep(.q-table th:nth-child(-n+9)),
.sticky-dim-table.sticky-dim-9 :deep(.q-table td:nth-child(-n+9)),
.sticky-dim-table.sticky-dim-10 :deep(.q-table th:nth-child(-n+10)),
@@ -3910,6 +4071,7 @@ onMounted(reload)
.sticky-dim-table.sticky-dim-5 :deep(.q-table th:nth-child(-n+5)),
.sticky-dim-table.sticky-dim-6 :deep(.q-table th:nth-child(-n+6)),
.sticky-dim-table.sticky-dim-7 :deep(.q-table th:nth-child(-n+7)),
.sticky-dim-table.sticky-dim-8 :deep(.q-table th:nth-child(-n+8)),
.sticky-dim-table.sticky-dim-9 :deep(.q-table th:nth-child(-n+9)),
.sticky-dim-table.sticky-dim-10 :deep(.q-table th:nth-child(-n+10)),
.sticky-dim-table.sticky-dim-11 :deep(.q-table th:nth-child(-n+11)) {
@@ -3929,6 +4091,8 @@ onMounted(reload)
.sticky-dim-table.sticky-dim-6 :deep(.q-table td:nth-child(6)),
.sticky-dim-table.sticky-dim-7 :deep(.q-table th:nth-child(7)),
.sticky-dim-table.sticky-dim-7 :deep(.q-table td:nth-child(7)),
.sticky-dim-table.sticky-dim-8 :deep(.q-table th:nth-child(8)),
.sticky-dim-table.sticky-dim-8 :deep(.q-table td:nth-child(8)),
.sticky-dim-table.sticky-dim-9 :deep(.q-table th:nth-child(9)),
.sticky-dim-table.sticky-dim-9 :deep(.q-table td:nth-child(9)),
.sticky-dim-table.sticky-dim-10 :deep(.q-table th:nth-child(10)),
@@ -3947,14 +4111,18 @@ onMounted(reload)
grid-template-columns: minmax(0, 1fr) 24px;
align-items: center;
gap: 4px;
min-width: 80px;
min-width: 104px;
}
.header-with-filter > span {
line-height: 1.15;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
line-height: 1.18;
white-space: normal;
overflow: hidden;
text-overflow: ellipsis;
overflow-wrap: anywhere;
text-overflow: clip;
}
.header-filter-btn {
@@ -4054,13 +4222,13 @@ onMounted(reload)
}
.product-image-cell {
width: 80px;
min-width: 80px;
width: 64px;
min-width: 64px;
}
.product-thumb-button {
width: 68px;
height: 92px;
width: 54px;
height: 72px;
border: 1px solid #d9dde3;
border-radius: 6px;
background: #fff;
@@ -4073,8 +4241,8 @@ onMounted(reload)
.product-thumb,
.product-thumb-placeholder {
width: 58px;
height: 82px;
width: 46px;
height: 64px;
}
.product-thumb {