Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-03-03 10:16:05 +03:00
parent ecf3a8bd07
commit ce31aff645
26 changed files with 2013 additions and 965 deletions

View File

@@ -11,6 +11,14 @@
:loading="store.loading"
@click="refreshAll"
/>
<q-btn
class="q-ml-sm"
color="secondary"
icon="save"
label="Secili Degisiklikleri Kaydet"
:loading="store.saving"
@click="onBulkSubmit"
/>
</div>
<div class="filter-bar row q-col-gutter-md">
@@ -76,6 +84,27 @@
:rows-per-page-options="[0]"
hide-bottom
>
<template #header-cell-select="props">
<q-th :props="props" class="text-center" style="width: 44px">
<q-checkbox
size="sm"
:model-value="allSelectedVisible"
:indeterminate="someSelectedVisible && !allSelectedVisible"
@update:model-value="toggleSelectAllVisible"
/>
</q-th>
</template>
<template #body-cell-select="props">
<q-td :props="props" class="text-center" style="width: 44px">
<q-checkbox
size="sm"
:model-value="!!selectedMap[props.row.RowKey]"
@update:model-value="(val) => toggleRowSelection(props.row.RowKey, val)"
/>
</q-td>
</template>
<template #body-cell-actions="props">
<q-td :props="props" class="text-center">
<q-btn
@@ -98,6 +127,7 @@
v-model="props.row.NewItemCode"
dense
filled
maxlength="13"
label="Yeni Urun"
@update:model-value="val => onNewItemChange(props.row, val)"
>
@@ -143,10 +173,12 @@
emit-value
map-options
use-input
new-value-mode="add-unique"
dense
filled
label="Yeni Renk"
@update:model-value="() => onNewColorChange(props.row)"
@new-value="(val, done) => onCreateColorValue(props.row, val, done)"
/>
</q-td>
</template>
@@ -161,9 +193,11 @@
emit-value
map-options
use-input
new-value-mode="add-unique"
dense
filled
label="Yeni 2. Renk"
@new-value="(val, done) => onCreateSecondColorValue(props.row, val, done)"
/>
</q-td>
</template>
@@ -214,8 +248,10 @@ const descFilter = ref('')
const productOptions = ref([])
const productSearch = ref('')
const rowSavingId = ref('')
const selectedMap = ref({})
const columns = [
{ name: 'select', label: '', field: 'select', align: 'center', sortable: false, style: 'width:44px;', headerStyle: 'width:44px;' },
{ name: 'OldItemCode', label: 'Eski Urun Kodu', field: 'OldItemCode', align: 'left', sortable: true, style: 'min-width:120px;white-space:nowrap', headerStyle: 'min-width:120px;white-space:nowrap', headerClasses: 'col-old', classes: 'col-old' },
{ name: 'OldColor', label: 'Eski Urun Rengi', field: 'OldColor', align: 'left', sortable: true, style: 'min-width:100px;white-space:nowrap', headerStyle: 'min-width:100px;white-space:nowrap', headerClasses: 'col-old', classes: 'col-old' },
{ name: 'OldDim2', label: 'Eski 2. Renk', field: 'OldDim2', align: 'left', sortable: true, style: 'min-width:90px;white-space:nowrap', headerStyle: 'min-width:90px;white-space:nowrap', headerClasses: 'col-old', classes: 'col-old' },
@@ -274,18 +310,21 @@ const filteredRows = computed(() => {
)
})
const visibleRowKeys = computed(() => filteredRows.value.map(r => r.RowKey))
const selectedVisibleCount = computed(() => visibleRowKeys.value.filter(k => !!selectedMap.value[k]).length)
const allSelectedVisible = computed(() => visibleRowKeys.value.length > 0 && selectedVisibleCount.value === visibleRowKeys.value.length)
const someSelectedVisible = computed(() => selectedVisibleCount.value > 0)
function onSelectProduct (row, code) {
productSearch.value = ''
onNewItemChange(row, code)
}
function onNewItemChange (row, val) {
const next = String(val || '').trim()
if (next && !isValidModelCode(next)) {
$q.notify({ type: 'negative', message: 'Model kodu formati gecersiz. Ornek: S000-DMY00001' })
row.NewItemCode = ''
row.NewColor = ''
row.NewDim2 = ''
const next = String(val || '').trim().toUpperCase()
if (next.length > 13) {
$q.notify({ type: 'negative', message: 'Model kodu en fazla 13 karakter olabilir.' })
row.NewItemCode = next.slice(0, 13)
return
}
row.NewItemCode = next ? next.toUpperCase() : ''
@@ -297,6 +336,7 @@ function onNewItemChange (row, val) {
}
function onNewColorChange (row) {
row.NewColor = normalizeShortCode(row.NewColor, 3)
row.NewDim2 = ''
if (row.NewItemCode && row.NewColor) {
store.fetchSecondColors(row.NewItemCode, row.NewColor)
@@ -319,9 +359,91 @@ function getSecondColorOptions (row) {
return store.secondColorOptionsByKey[key] || []
}
function isValidModelCode (value) {
const text = String(value || '').trim().toUpperCase()
return /^[A-Z][0-9]{3}-[A-Z]{3}[0-9]{5}$/.test(text)
function toggleRowSelection (rowKey, checked) {
const next = { ...selectedMap.value }
if (checked) next[rowKey] = true
else delete next[rowKey]
selectedMap.value = next
}
function toggleSelectAllVisible (checked) {
const next = { ...selectedMap.value }
for (const key of visibleRowKeys.value) {
if (checked) next[key] = true
else delete next[key]
}
selectedMap.value = next
}
function onCreateColorValue (row, val, done) {
const code = normalizeShortCode(val, 3)
if (!code) {
done(null)
return
}
row.NewColor = code
onNewColorChange(row)
done(code, 'add-unique')
}
function onCreateSecondColorValue (row, val, done) {
const code = normalizeShortCode(val, 3)
if (!code) {
done(null)
return
}
row.NewDim2 = code
done(code, 'add-unique')
}
function normalizeShortCode (value, maxLen) {
return String(value || '').trim().toUpperCase().slice(0, maxLen)
}
function validateRowInput (row) {
const newItemCode = String(row.NewItemCode || '').trim().toUpperCase()
const newColor = normalizeShortCode(row.NewColor, 3)
const newDim2 = normalizeShortCode(row.NewDim2, 3)
const oldColor = String(row.OldColor || '').trim()
const oldDim2 = String(row.OldDim2 || '').trim()
if (!newItemCode) return 'Yeni model kodu zorunludur.'
if (newItemCode.length !== 13) return 'Yeni model kodu 13 karakter olmalidir.'
if (oldColor && !newColor) return 'Eski kayitta 1. renk oldugu icin yeni 1. renk zorunludur.'
if (newColor && newColor.length !== 3) return 'Yeni 1. renk kodu 3 karakter olmalidir.'
if (oldDim2 && !newDim2) return 'Eski kayitta 2. renk oldugu icin yeni 2. renk zorunludur.'
if (newDim2 && newDim2.length !== 3) return 'Yeni 2. renk kodu 3 karakter olmalidir.'
if (newDim2 && !newColor) return '2. renk girmek icin 1. renk zorunludur.'
row.NewItemCode = newItemCode
row.NewColor = newColor
row.NewDim2 = newDim2
return ''
}
function collectLinesFromRows (selectedRows) {
const lines = []
for (const row of selectedRows) {
const errMsg = validateRowInput(row)
if (errMsg) {
return { errMsg, lines: [] }
}
const baseLine = {
NewItemCode: String(row.NewItemCode || '').trim().toUpperCase(),
NewColor: normalizeShortCode(row.NewColor, 3),
NewDim2: normalizeShortCode(row.NewDim2, 3),
NewDesc: String((row.NewDesc || row.OldDesc) || '').trim()
}
for (const id of (row.OrderLineIDs || [])) {
lines.push({
OrderLineID: id,
...baseLine
})
}
}
return { errMsg: '', lines }
}
function buildGroupKey (item) {
@@ -416,23 +538,12 @@ async function refreshAll () {
}
async function onRowSubmit (row) {
const baseLine = {
NewItemCode: String(row.NewItemCode || '').trim(),
NewColor: String(row.NewColor || '').trim(),
NewDim2: String(row.NewDim2 || '').trim(),
NewDesc: String((row.NewDesc || row.OldDesc) || '').trim()
}
if (!baseLine.NewItemCode || !baseLine.NewColor) {
$q.notify({ type: 'negative', message: 'Yeni urun ve renk zorunludur.' })
const { errMsg, lines } = collectLinesFromRows([row])
if (errMsg) {
$q.notify({ type: 'negative', message: errMsg })
return
}
const lines = (row.OrderLineIDs || []).map(id => ({
OrderLineID: id,
...baseLine
}))
if (!lines.length) {
$q.notify({ type: 'negative', message: 'Satir bulunamadi.' })
return
@@ -467,6 +578,52 @@ async function onRowSubmit (row) {
rowSavingId.value = ''
}
}
async function onBulkSubmit () {
const selectedRows = rows.value.filter(r => !!selectedMap.value[r.RowKey])
if (!selectedRows.length) {
$q.notify({ type: 'warning', message: 'Lutfen en az bir satir seciniz.' })
return
}
const { errMsg, lines } = collectLinesFromRows(selectedRows)
if (errMsg) {
$q.notify({ type: 'negative', message: errMsg })
return
}
if (!lines.length) {
$q.notify({ type: 'negative', message: 'Secili satirlarda guncellenecek kayit bulunamadi.' })
return
}
try {
const validate = await store.validateUpdates(orderHeaderID.value, lines)
const missingCount = validate?.missingCount || 0
if (missingCount > 0) {
const missingList = (validate?.missing || []).map(v => (
`${v.ItemCode} / ${v.ColorCode} / ${v.ItemDim1Code} / ${v.ItemDim2Code}`
))
$q.dialog({
title: 'Eksik Varyantlar',
message: `Eksik varyant bulundu: ${missingCount}<br><br>${missingList.join('<br>')}`,
html: true,
ok: { label: 'Ekle ve Guncelle', color: 'primary' },
cancel: { label: 'Vazgec', flat: true }
}).onOk(async () => {
await store.applyUpdates(orderHeaderID.value, lines, true)
await store.fetchItems(orderHeaderID.value)
selectedMap.value = {}
})
return
}
await store.applyUpdates(orderHeaderID.value, lines, false)
await store.fetchItems(orderHeaderID.value)
selectedMap.value = {}
} catch (err) {
$q.notify({ type: 'negative', message: 'Toplu kayit islemi basarisiz.' })
}
}
</script>
<style scoped>