Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -321,6 +321,137 @@
|
||||
</div>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
v-else-if="col.name === 'variantCodes'"
|
||||
flat
|
||||
dense
|
||||
round
|
||||
size="8px"
|
||||
icon="filter_alt"
|
||||
:color="selectedVariantCodes.length > 0 ? 'primary' : 'grey-7'"
|
||||
:disable="pageBusy"
|
||||
class="header-filter-btn"
|
||||
@click.stop
|
||||
>
|
||||
<q-badge v-if="selectedVariantCodes.length > 0" color="primary" floating rounded>
|
||||
{{ selectedVariantCodes.length }}
|
||||
</q-badge>
|
||||
<q-menu anchor="bottom right" self="top right" :offset="[0, 4]">
|
||||
<div class="excel-filter-menu">
|
||||
<q-input
|
||||
v-model="variantFilterSearch"
|
||||
dense
|
||||
outlined
|
||||
clearable
|
||||
class="excel-filter-select"
|
||||
placeholder="Varyant ara"
|
||||
/>
|
||||
<div class="excel-filter-actions row items-center justify-between q-pt-xs">
|
||||
<q-btn flat dense size="sm" label="Tumunu Sec" :disable="pageBusy || filteredVariantOptions.length === 0" @click="selectAllVariantOptions" />
|
||||
<q-btn flat dense size="sm" label="Temizle" :disable="pageBusy || selectedVariantCodes.length === 0" @click="clearVariantOptions" />
|
||||
</div>
|
||||
<q-virtual-scroll
|
||||
v-if="filteredVariantOptions.length > 0"
|
||||
class="excel-filter-options"
|
||||
:items="filteredVariantOptions"
|
||||
:virtual-scroll-item-size="32"
|
||||
separator
|
||||
>
|
||||
<template #default="{ item: option }">
|
||||
<q-item
|
||||
:key="`variant-${option.value}`"
|
||||
dense
|
||||
clickable
|
||||
:disable="pageBusy"
|
||||
class="excel-filter-option"
|
||||
@click="toggleVariantValue(option.value)"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-checkbox
|
||||
dense
|
||||
size="sm"
|
||||
:model-value="selectedVariantCodeSet.has(option.value)"
|
||||
:disable="pageBusy"
|
||||
@update:model-value="() => toggleVariantValue(option.value)"
|
||||
@click.stop
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ option.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
</q-virtual-scroll>
|
||||
<div v-else class="excel-filter-empty">Sonuc yok</div>
|
||||
</div>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
v-else-if="isLocalFilterableColumn(col.name)"
|
||||
flat
|
||||
dense
|
||||
round
|
||||
size="8px"
|
||||
icon="filter_alt"
|
||||
:color="getColumnFilterValues(col.name).length > 0 ? 'primary' : 'grey-7'"
|
||||
:disable="pageBusy"
|
||||
class="header-filter-btn"
|
||||
@click.stop
|
||||
>
|
||||
<q-badge v-if="getColumnFilterValues(col.name).length > 0" color="primary" floating rounded>
|
||||
{{ getColumnFilterValues(col.name).length }}
|
||||
</q-badge>
|
||||
<q-menu anchor="bottom right" self="top right" :offset="[0, 4]">
|
||||
<div class="excel-filter-menu">
|
||||
<q-input
|
||||
:model-value="columnFilterSearch[col.name] || ''"
|
||||
dense
|
||||
outlined
|
||||
clearable
|
||||
class="excel-filter-select"
|
||||
placeholder="Filtre ara"
|
||||
@update:model-value="(val) => setColumnFilterSearch(col.name, val)"
|
||||
/>
|
||||
<div class="excel-filter-actions row items-center justify-between q-pt-xs">
|
||||
<q-btn flat dense size="sm" label="Tumunu Sec" :disable="pageBusy || getFilteredColumnOptions(col).length === 0" @click="selectAllColumnOptions(col)" />
|
||||
<q-btn flat dense size="sm" label="Temizle" :disable="pageBusy || getColumnFilterValues(col.name).length === 0" @click="clearColumnOptions(col.name)" />
|
||||
</div>
|
||||
<q-virtual-scroll
|
||||
v-if="getFilteredColumnOptions(col).length > 0"
|
||||
class="excel-filter-options"
|
||||
:items="getFilteredColumnOptions(col)"
|
||||
:virtual-scroll-item-size="32"
|
||||
separator
|
||||
>
|
||||
<template #default="{ item: option }">
|
||||
<q-item
|
||||
:key="`${col.name}-${option.value}`"
|
||||
dense
|
||||
clickable
|
||||
:disable="pageBusy"
|
||||
class="excel-filter-option"
|
||||
@click="toggleColumnFilterValue(col.name, option.value)"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-checkbox
|
||||
dense
|
||||
size="sm"
|
||||
:model-value="getColumnFilterSet(col.name).has(option.value)"
|
||||
:disable="pageBusy"
|
||||
@update:model-value="() => toggleColumnFilterValue(col.name, option.value)"
|
||||
@click.stop
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ option.label || '-' }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
</q-virtual-scroll>
|
||||
<div v-else class="excel-filter-empty">Sonuc yok</div>
|
||||
</div>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
<span v-else class="header-filter-ghost"></span>
|
||||
</div>
|
||||
</q-th>
|
||||
@@ -503,7 +634,11 @@ const topUrunIlkGrubu = ref(null)
|
||||
const topUrunAnaGrubu = ref(null)
|
||||
const selectedProductCodes = ref([])
|
||||
const selectedCampaignLabels = ref([])
|
||||
const selectedVariantCodes = ref([])
|
||||
const campaignFilterSearch = ref('')
|
||||
const variantFilterSearch = ref('')
|
||||
const columnFilters = ref({})
|
||||
const columnFilterSearch = ref({})
|
||||
const selectedPriceOptions = ref(['usd5', 'try5'])
|
||||
const leftDetailsExpanded = ref(true)
|
||||
|
||||
@@ -537,6 +672,7 @@ const fullscreenImages = computed(() => productCardImages.value || [])
|
||||
const selectedPriceSet = computed(() => new Set(selectedPriceOptions.value || []))
|
||||
const selectedProductCodeSet = computed(() => new Set(selectedProductCodes.value || []))
|
||||
const selectedCampaignLabelSet = computed(() => new Set(selectedCampaignLabels.value || []))
|
||||
const selectedVariantCodeSet = computed(() => new Set(selectedVariantCodes.value || []))
|
||||
const pageBusy = computed(() => loading.value || renderPending.value)
|
||||
const canFetch = computed(() => Boolean(topUrunIlkGrubu.value || topUrunAnaGrubu.value || selectedProductCodes.value.length > 0))
|
||||
const showGuidanceOverlay = computed(() => !loading.value && rows.value.length === 0 && error.value === GUIDANCE_MSG)
|
||||
@@ -559,6 +695,21 @@ const filteredCampaignOptions = computed(() => {
|
||||
const list = campaignOptions.value
|
||||
return q ? list.filter((x) => x.label.toLocaleLowerCase('tr').includes(q)) : list
|
||||
})
|
||||
const variantOptions = computed(() => {
|
||||
const uniq = new Set()
|
||||
for (const row of rows.value || []) {
|
||||
const val = toText(row?.variantCodes)
|
||||
if (val) uniq.add(val)
|
||||
}
|
||||
return Array.from(uniq)
|
||||
.sort((a, b) => variantCodeCollator.compare(a, b))
|
||||
.map((value) => ({ label: value, value }))
|
||||
})
|
||||
const filteredVariantOptions = computed(() => {
|
||||
const q = toText(variantFilterSearch.value).toLocaleLowerCase('tr')
|
||||
const list = variantOptions.value
|
||||
return q ? list.filter((x) => x.label.toLocaleLowerCase('tr').includes(q)) : list
|
||||
})
|
||||
|
||||
function toText (value) {
|
||||
return String(value ?? '').trim()
|
||||
@@ -763,6 +914,79 @@ function clearCampaignOptions () {
|
||||
selectedCampaignLabels.value = []
|
||||
}
|
||||
|
||||
function toggleVariantValue (value) {
|
||||
const v = toText(value)
|
||||
if (!v) return
|
||||
const set = new Set(selectedVariantCodes.value || [])
|
||||
if (set.has(v)) set.delete(v)
|
||||
else set.add(v)
|
||||
selectedVariantCodes.value = Array.from(set).sort((a, b) => variantCodeCollator.compare(a, b))
|
||||
}
|
||||
|
||||
function selectAllVariantOptions () {
|
||||
const set = new Set(selectedVariantCodes.value || [])
|
||||
for (const option of filteredVariantOptions.value) {
|
||||
const v = toText(option.value)
|
||||
if (v) set.add(v)
|
||||
}
|
||||
selectedVariantCodes.value = Array.from(set).sort((a, b) => variantCodeCollator.compare(a, b))
|
||||
}
|
||||
|
||||
function clearVariantOptions () {
|
||||
selectedVariantCodes.value = []
|
||||
}
|
||||
|
||||
function isLocalFilterableColumn (name) {
|
||||
if (!name || ['image', 'productCode', 'variantCodes', 'campaignLabel'].includes(name)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
function getColumnFilterValues (name) {
|
||||
const list = columnFilters.value?.[name]
|
||||
return Array.isArray(list) ? list : []
|
||||
}
|
||||
|
||||
function getColumnFilterSet (name) {
|
||||
return new Set(getColumnFilterValues(name))
|
||||
}
|
||||
|
||||
function setColumnFilterSearch (name, value) {
|
||||
columnFilterSearch.value = { ...columnFilterSearch.value, [name]: toText(value) }
|
||||
}
|
||||
|
||||
function getColumnOptions (col) {
|
||||
const uniq = new Set()
|
||||
for (const row of rows.value || []) {
|
||||
uniq.add(exportCell(row, col))
|
||||
}
|
||||
return Array.from(uniq)
|
||||
.sort((a, b) => String(a).localeCompare(String(b), 'tr', { numeric: true, sensitivity: 'base' }))
|
||||
.map((value) => ({ label: value || '-', value }))
|
||||
}
|
||||
|
||||
function getFilteredColumnOptions (col) {
|
||||
const q = toText(columnFilterSearch.value?.[col.name]).toLocaleLowerCase('tr')
|
||||
const list = getColumnOptions(col)
|
||||
return q ? list.filter((x) => String(x.label || '').toLocaleLowerCase('tr').includes(q)) : list
|
||||
}
|
||||
|
||||
function toggleColumnFilterValue (name, value) {
|
||||
const set = new Set(getColumnFilterValues(name))
|
||||
if (set.has(value)) set.delete(value)
|
||||
else set.add(value)
|
||||
columnFilters.value = { ...columnFilters.value, [name]: Array.from(set) }
|
||||
}
|
||||
|
||||
function selectAllColumnOptions (col) {
|
||||
const set = new Set(getColumnFilterValues(col.name))
|
||||
for (const option of getFilteredColumnOptions(col)) set.add(option.value)
|
||||
columnFilters.value = { ...columnFilters.value, [col.name]: Array.from(set) }
|
||||
}
|
||||
|
||||
function clearColumnOptions (name) {
|
||||
columnFilters.value = { ...columnFilters.value, [name]: [] }
|
||||
}
|
||||
|
||||
function onTopUrunIlkGrubuChange () {
|
||||
topUrunAnaGrubu.value = null
|
||||
void fetchServerFilterOptions('urunAnaGrubu', '')
|
||||
@@ -947,6 +1171,10 @@ function resetSelections () {
|
||||
topUrunIlkGrubu.value = null
|
||||
topUrunAnaGrubu.value = null
|
||||
selectedProductCodes.value = []
|
||||
selectedCampaignLabels.value = []
|
||||
selectedVariantCodes.value = []
|
||||
columnFilters.value = {}
|
||||
columnFilterSearch.value = {}
|
||||
rows.value = []
|
||||
error.value = GUIDANCE_MSG
|
||||
currentPage.value = 1
|
||||
@@ -1031,8 +1259,25 @@ const visibleColumns = computed(() => allColumns.filter((c) => {
|
||||
|
||||
const filteredRows = computed(() => {
|
||||
const campaignSet = selectedCampaignLabelSet.value
|
||||
if (campaignSet.size === 0) return rows.value || []
|
||||
return (rows.value || []).filter((row) => campaignSet.has(toText(row?.campaignLabel)))
|
||||
const variantSet = selectedVariantCodeSet.value
|
||||
const localFilters = columnFilters.value || {}
|
||||
let list = rows.value || []
|
||||
if (campaignSet.size > 0) {
|
||||
list = list.filter((row) => campaignSet.has(toText(row?.campaignLabel)))
|
||||
}
|
||||
if (variantSet.size > 0) {
|
||||
list = list.filter((row) => variantSet.has(toText(row?.variantCodes)))
|
||||
}
|
||||
const active = Object.entries(localFilters).filter(([, values]) => Array.isArray(values) && values.length > 0)
|
||||
if (active.length > 0) {
|
||||
const byName = new Map(allColumns.map((c) => [c.name, c]))
|
||||
list = list.filter((row) => active.every(([name, values]) => {
|
||||
const col = byName.get(name)
|
||||
if (!col) return true
|
||||
return new Set(values).has(exportCell(row, col))
|
||||
}))
|
||||
}
|
||||
return list
|
||||
})
|
||||
const tableMinWidth = computed(() => visibleColumns.value.reduce((sum, c) => sum + extractWidth(c.style), 0))
|
||||
const tableStyle = computed(() => ({
|
||||
|
||||
@@ -884,6 +884,7 @@ const currentPage = ref(1)
|
||||
let reloadTimer = null
|
||||
const variantRows = ref([])
|
||||
const variantRowsCache = new Map()
|
||||
const variantCodeCollator = new Intl.Collator('tr', { numeric: true, sensitivity: 'base' })
|
||||
const VARIANT_ROWS_CACHE_LIMIT = 16
|
||||
|
||||
const GUIDANCE_MSG = "Calismak icin once Urun Ilk Grubu veya Urun Ana Grubu Secin ve GRUPLARI GETIR'e Basin."
|
||||
@@ -2678,7 +2679,7 @@ async function buildVariantRowsForProductPage (baseProductRows = []) {
|
||||
})
|
||||
continue
|
||||
}
|
||||
vs.sort((a, b) => String(a?.variant_code || '').localeCompare(String(b?.variant_code || ''), 'tr'))
|
||||
vs.sort((a, b) => variantCodeCollator.compare(String(a?.variant_code || ''), String(b?.variant_code || '')))
|
||||
for (const v of vs) {
|
||||
const d1 = Number(v?.dim1 || 0)
|
||||
const d3 = v?.dim3 == null ? null : Number(v?.dim3 || 0)
|
||||
|
||||
Reference in New Issue
Block a user