From 81d1af61be98aed4317ee0cbb42a842fda1a5a8f Mon Sep 17 00:00:00 2001 From: M_Kececi Date: Thu, 18 Jun 2026 23:57:25 +0300 Subject: [PATCH] Merge remote-tracking branch 'origin/master' --- ui/src/pages/OrderPriceList.vue | 120 ++++++++++++++++++++++---------- 1 file changed, 85 insertions(+), 35 deletions(-) diff --git a/ui/src/pages/OrderPriceList.vue b/ui/src/pages/OrderPriceList.vue index b1c7022..5699016 100644 --- a/ui/src/pages/OrderPriceList.vue +++ b/ui/src/pages/OrderPriceList.vue @@ -363,8 +363,7 @@ :class="[props.col.classes, { 'sticky-col': isStickyCol(props.col.name), 'sticky-boundary': isStickyBoundary(props.col.name) }]" :style="getBodyCellStyle(props.col)" > - - - + @@ -505,7 +504,7 @@ const topUrunAnaGrubu = ref(null) const selectedProductCodes = ref([]) const selectedCampaignLabels = ref([]) const campaignFilterSearch = ref('') -const selectedPriceOptions = ref(priceOptions.map((x) => x.value)) +const selectedPriceOptions = ref(['usd5', 'try5']) const leftDetailsExpanded = ref(true) const rows = ref([]) @@ -815,7 +814,7 @@ async function reloadData ({ page = 1 } = {}) { } rows.value = buildRows(products, variants) error.value = '' - void loadImagesForRows(rows.value.slice(0, 120)) + void loadImagesForRows(rows.value) await nextTick() } catch (err) { rows.value = [] @@ -836,10 +835,18 @@ async function loadImagesForRows (list) { seen.add(key) targets.push({ row, key }) } - await Promise.all(targets.map(async ({ row, key }) => { + const concurrency = 12 + let cursor = 0 + let loaded = 0 + const workers = Array.from({ length: Math.min(concurrency, targets.length) }, async () => { + for (;;) { + const target = targets[cursor] + cursor += 1 + if (!target) return + const { row, key } = target if (imageCache.has(key)) { row.imageUrl = imageCache.get(key) - return + continue } try { const res = await api.get('/product-images', { @@ -858,7 +865,11 @@ async function loadImagesForRows (list) { } catch { imageCache.set(key, '') } - })) + loaded += 1 + if (loaded % 12 === 0) rows.value = [...rows.value] + } + }) + await Promise.all(workers) rows.value = [...rows.value] } @@ -978,26 +989,29 @@ function col (name, label, field, width, extra = {}) { const allColumns = [ col('image', '', 'imageUrl', 108, { align: 'center', classes: 'image-col sticky-col' }), col('brandGroupSelection', 'MARKA GRUBU', 'brandGroupSelection', 86, { classes: 'ps-col sticky-col' }), - col('marka', 'MARKA', 'marka', 62, { sortable: true, classes: 'ps-col sticky-col' }), + col('marka', 'MARKA', 'marka', 72, { sortable: true, classes: 'ps-col sticky-col' }), col('productCode', 'URUN KODU', 'productCode', 112, { sortable: true, classes: 'ps-col product-code-col sticky-col' }), - col('variantCodes', 'VARYANT', 'variantCodes', 112, { classes: 'ps-col variant-col sticky-col' }), - col('variantStocks', 'STOK', 'stockQty', 62, { align: 'right', sortable: true, classes: 'ps-col variant-stock-col sticky-col' }), + col('variantCodes', 'VARYANT', 'variantCodes', 128, { classes: 'ps-col variant-col sticky-col' }), + col('variantStocks', 'STOK', 'stockQty', 72, { align: 'right', sortable: true, classes: 'ps-col variant-stock-col sticky-col' }), col('campaignLabel', 'KAMPANYA', 'campaignLabel', 150, { classes: 'ps-col campaign-col sticky-col' }), - col('campaignRate', 'IND %', 'campaignRate', 58, { align: 'right', classes: 'ps-col campaign-rate-col sticky-col' }), - col('askiliYan', 'ASKILI YAN', 'askiliYan', 58, { sortable: true, classes: 'ps-col' }), - col('kategori', 'KATEGORI', 'kategori', 58, { sortable: true, classes: 'ps-col' }), - col('urunIlkGrubu', 'URUN ILK GRUBU', 'urunIlkGrubu', 70, { sortable: true, classes: 'ps-col' }), - col('urunAnaGrubu', 'URUN ANA GRUBU', 'urunAnaGrubu', 74, { sortable: true, classes: 'ps-col' }), - col('urunAltGrubu', 'URUN ALT GRUBU', 'urunAltGrubu', 74, { sortable: true, classes: 'ps-col' }), - col('icerik', 'ICERIK', 'icerik', 66, { sortable: true, classes: 'ps-col' }), - col('karisim', 'KARISIM', 'karisim', 66, { sortable: true, classes: 'ps-col' }), + col('campaignRate', 'IND %', 'campaignRate', 64, { align: 'right', classes: 'ps-col campaign-rate-col sticky-col' }), + col('askiliYan', 'ASKILI YAN', 'askiliYan', 72, { sortable: true, classes: 'ps-col' }), + col('kategori', 'KATEGORI', 'kategori', 82, { sortable: true, classes: 'ps-col' }), + col('urunIlkGrubu', 'URUN ILK GRUBU', 'urunIlkGrubu', 88, { sortable: true, classes: 'ps-col' }), + col('urunAnaGrubu', 'URUN ANA GRUBU', 'urunAnaGrubu', 96, { sortable: true, classes: 'ps-col' }), + col('urunAltGrubu', 'URUN ALT GRUBU', 'urunAltGrubu', 96, { sortable: true, classes: 'ps-col' }), + col('icerik', 'ICERIK', 'icerik', 112, { sortable: true, classes: 'ps-col' }), + col('karisim', 'KARISIM', 'karisim', 96, { sortable: true, classes: 'ps-col' }), ...campaignPairs.flatMap((p) => [ col(p.base, p.base.toUpperCase().replace(/([A-Z]+)(\d)/, '$1 $2'), p.base, 78, { align: 'right', classes: `${p.base.slice(0, 3)}-col` }), col(p.derived, `${p.base.toUpperCase().replace(/([A-Z]+)(\d)/, '$1 $2')} KMP`, p.derived, 88, { align: 'right', classes: `${p.base.slice(0, 3)}-col campaign-price-col` }) ]) ] -const hideableLeftDetailColumnNames = new Set([ +const compactHiddenColumnNames = new Set([ + 'variantStocks', + 'campaignLabel', + 'campaignRate', 'askiliYan', 'kategori', 'urunIlkGrubu', @@ -1010,7 +1024,7 @@ const hideableLeftDetailColumnNames = new Set([ const visibleColumns = computed(() => allColumns.filter((c) => { if (/^(usd|eur|try)[1-6]$/.test(c.name)) return selectedPriceSet.value.has(c.name) if (/^(usd|eur|try)[1-6]Campaign$/.test(c.name)) return selectedPriceSet.value.has(c.name.replace(/Campaign$/, '')) - if (!leftDetailsExpanded.value && hideableLeftDetailColumnNames.has(c.name)) return false + if (!leftDetailsExpanded.value && compactHiddenColumnNames.has(c.name)) return false return true })) @@ -1027,9 +1041,30 @@ const tableStyle = computed(() => ({ })) const stickyColumnNames = computed(() => { const visible = new Set(visibleColumns.value.map((x) => x.name)) - return ['image', 'brandGroupSelection', 'marka', 'productCode', 'variantCodes', 'variantStocks', 'campaignLabel', 'campaignRate'].filter((x) => visible.has(x)) + const expanded = [ + 'image', + 'brandGroupSelection', + 'marka', + 'productCode', + 'variantCodes', + 'variantStocks', + 'campaignLabel', + 'campaignRate', + 'askiliYan', + 'kategori', + 'urunIlkGrubu', + 'urunAnaGrubu', + 'urunAltGrubu', + 'icerik', + 'karisim' + ] + const compact = ['image', 'brandGroupSelection', 'marka', 'productCode', 'variantCodes'] + return (leftDetailsExpanded.value ? expanded : compact).filter((x) => visible.has(x)) +}) +const stickyBoundaryColumnName = computed(() => { + const list = stickyColumnNames.value + return list.length ? list[list.length - 1] : '' }) -const stickyBoundaryColumnName = 'campaignRate' const stickyColumnNameSet = computed(() => new Set(stickyColumnNames.value)) const stickyLeftMap = computed(() => { const map = {} @@ -1043,8 +1078,9 @@ const stickyLeftMap = computed(() => { return map }) const stickyScrollComp = computed(() => { - const boundaryCol = allColumns.find((x) => x.name === stickyBoundaryColumnName) - return ((stickyLeftMap.value[stickyBoundaryColumnName] || 0) + extractWidth(boundaryCol?.style)) * 1.2 + const boundaryName = stickyBoundaryColumnName.value + const boundaryCol = allColumns.find((x) => x.name === boundaryName) + return ((stickyLeftMap.value[boundaryName] || 0) + extractWidth(boundaryCol?.style)) * 1.2 }) function isStickyCol (name) { @@ -1052,7 +1088,7 @@ function isStickyCol (name) { } function isStickyBoundary (name) { - return name === stickyBoundaryColumnName + return name === stickyBoundaryColumnName.value } function getHeaderCellStyle (col) { @@ -1081,12 +1117,11 @@ function exportCell (row, col) { } function exportVisibleExcel () { - const cols = visibleColumns.value + const cols = visibleColumns.value.filter((c) => c.name !== 'image') const body = filteredRows.value.map((row) => `${cols.map((c) => { - if (c.name === 'image' && row.imageUrl) return `` return `${escapeHtml(exportCell(row, c))}` }).join('')}`).join('') - const html = `${cols.map((c) => ``).join('')}${body}
${escapeHtml(c.label || 'Gorsel')}
` + const html = `${cols.map((c) => ``).join('')}${body}
${escapeHtml(c.label)}
` const blob = new Blob([html], { type: 'application/vnd.ms-excel;charset=utf-8' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') @@ -1184,7 +1219,7 @@ onMounted(() => { display: flex; flex-direction: column; --pricing-row-height: 108px; - --pricing-header-height: 72px; + --pricing-header-height: 88px; --pricing-table-height: calc(100vh - 156px); } @@ -1315,6 +1350,13 @@ onMounted(() => { border-bottom: 1px solid rgba(0, 0, 0, 0.08) !important; } +.pricing-table :deep(td) { + overflow: hidden !important; + text-overflow: ellipsis; + white-space: nowrap; + vertical-align: middle !important; +} + .pricing-table :deep(th), .pricing-table :deep(.q-table thead tr), .pricing-table :deep(.q-table thead tr.header-row-fixed), @@ -1328,9 +1370,10 @@ onMounted(() => { .pricing-table :deep(th) { padding-top: 0; padding-bottom: 0; - white-space: nowrap; - word-break: normal; - text-overflow: ellipsis; + white-space: normal; + word-break: break-word; + overflow-wrap: anywhere; + overflow: hidden; text-align: center; font-size: 10px; font-weight: 800; @@ -1411,15 +1454,22 @@ onMounted(() => { width: 100%; overflow: hidden; text-align: center; - text-overflow: ellipsis; white-space: normal; + word-break: break-word; + overflow-wrap: anywhere; font-weight: 800; - line-height: 1.15; + line-height: 1.12; display: -webkit-box; - -webkit-line-clamp: 2; + -webkit-line-clamp: 4; -webkit-box-orient: vertical; } +.campaign-badge { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; +} + .header-filter-btn { width: 20px; height: 20px;