Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -1,24 +1,177 @@
|
||||
<template>
|
||||
<q-page class="q-pa-md">
|
||||
<div class="text-h6 text-weight-bold">Üretime Verilen Ürünler</div>
|
||||
<div class="text-caption text-grey-7 q-mt-xs">
|
||||
OrderHeaderID: {{ orderHeaderID || '-' }}
|
||||
<div class="row items-center justify-between">
|
||||
<div>
|
||||
<div class="text-h6 text-weight-bold">Uretime Verilen Urunleri Guncelle</div>
|
||||
<div class="text-caption text-grey-7 q-mt-xs">
|
||||
OrderHeaderID: {{ orderHeaderID || '-' }}
|
||||
</div>
|
||||
</div>
|
||||
<q-btn
|
||||
color="primary"
|
||||
icon="refresh"
|
||||
label="Yenile"
|
||||
:loading="store.loading"
|
||||
@click="refreshAll"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="filter-bar row q-col-gutter-md q-mt-md">
|
||||
<div class="col-5">
|
||||
<q-input
|
||||
:model-value="cariLabel"
|
||||
label="Cari Secimi"
|
||||
filled
|
||||
dense
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<q-input
|
||||
:model-value="header?.OrderNumber || ''"
|
||||
label="Siparis No"
|
||||
filled
|
||||
dense
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<q-input
|
||||
:model-value="formatDate(header?.OrderDate)"
|
||||
label="Olusturulma Tarihi"
|
||||
filled
|
||||
dense
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<q-input
|
||||
:model-value="formatDate(header?.AverageDueDate)"
|
||||
label="Tahmini Termin Tarihi"
|
||||
filled
|
||||
dense
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-table
|
||||
<q-table
|
||||
class="q-mt-md"
|
||||
flat
|
||||
bordered
|
||||
dense
|
||||
separator="cell"
|
||||
row-key="OrderLineID"
|
||||
:rows="store.items"
|
||||
:rows="rows"
|
||||
:columns="columns"
|
||||
:loading="store.loading"
|
||||
no-data-label="Üretime verilecek ürün bulunamadı"
|
||||
no-data-label="Uretime verilecek urun bulunamadi"
|
||||
:rows-per-page-options="[0]"
|
||||
hide-bottom
|
||||
/>
|
||||
>
|
||||
<template #body-cell-actions="props">
|
||||
<q-td :props="props" class="text-center">
|
||||
<q-btn
|
||||
color="primary"
|
||||
icon="save"
|
||||
flat
|
||||
round
|
||||
dense
|
||||
:loading="rowSavingId === props.row.OrderLineID"
|
||||
@click="onRowSubmit(props.row)"
|
||||
>
|
||||
<q-tooltip>Satiri Guncelle</q-tooltip>
|
||||
</q-btn>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template #body-cell-NewItemCode="props">
|
||||
<q-td :props="props">
|
||||
<q-input
|
||||
v-model="props.row.NewItemCode"
|
||||
dense
|
||||
filled
|
||||
label="Yeni Urun"
|
||||
@update:model-value="val => onNewItemChange(props.row, val)"
|
||||
>
|
||||
<template #append>
|
||||
<q-icon name="arrow_drop_down" class="cursor-pointer" />
|
||||
</template>
|
||||
<q-menu
|
||||
anchor="bottom left"
|
||||
self="top left"
|
||||
fit
|
||||
>
|
||||
<div class="q-pa-sm" style="min-width:260px">
|
||||
<q-input
|
||||
v-model="productSearch"
|
||||
dense
|
||||
filled
|
||||
debounce="200"
|
||||
placeholder="Urun ara..."
|
||||
/>
|
||||
<q-list class="q-mt-xs" bordered separator>
|
||||
<q-item
|
||||
v-for="opt in filteredProducts"
|
||||
:key="opt.ProductCode"
|
||||
clickable
|
||||
@click="onSelectProduct(props.row, opt.ProductCode)"
|
||||
>
|
||||
<q-item-section>{{ opt.ProductCode }}</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</div>
|
||||
</q-menu>
|
||||
</q-input>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template #body-cell-NewColor="props">
|
||||
<q-td :props="props">
|
||||
<q-select
|
||||
v-model="props.row.NewColor"
|
||||
:options="getColorOptions(props.row)"
|
||||
option-label="colorLabel"
|
||||
option-value="color_code"
|
||||
emit-value
|
||||
map-options
|
||||
use-input
|
||||
dense
|
||||
filled
|
||||
label="Yeni Renk"
|
||||
@update:model-value="() => onNewColorChange(props.row)"
|
||||
/>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template #body-cell-NewDim2="props">
|
||||
<q-td :props="props">
|
||||
<q-select
|
||||
v-model="props.row.NewDim2"
|
||||
:options="getSecondColorOptions(props.row)"
|
||||
option-label="item_dim2_code"
|
||||
option-value="item_dim2_code"
|
||||
emit-value
|
||||
map-options
|
||||
use-input
|
||||
dense
|
||||
filled
|
||||
label="Yeni 2. Renk"
|
||||
/>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template #body-cell-NewDesc="props">
|
||||
<q-td :props="props">
|
||||
<q-input
|
||||
v-model="props.row.NewDesc"
|
||||
dense
|
||||
filled
|
||||
label="Yeni Aciklama"
|
||||
/>
|
||||
</q-td>
|
||||
</template>
|
||||
</q-table>
|
||||
|
||||
<q-banner v-if="store.error" class="bg-red text-white q-mt-sm">
|
||||
Hata: {{ store.error }}
|
||||
@@ -27,31 +180,193 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useQuasar } from 'quasar'
|
||||
import { useOrderProductionItemStore } from 'src/stores/OrderProductionItemStore'
|
||||
|
||||
const route = useRoute()
|
||||
const $q = useQuasar()
|
||||
const store = useOrderProductionItemStore()
|
||||
|
||||
const orderHeaderID = computed(() => String(route.params.orderHeaderID || '').trim())
|
||||
const header = computed(() => store.header || {})
|
||||
const cariLabel = computed(() => {
|
||||
const code = header.value?.CurrAccCode || ''
|
||||
const name = header.value?.CurrAccDescription || ''
|
||||
if (!code && !name) return ''
|
||||
if (!name) return code
|
||||
return `${code} - ${name}`
|
||||
})
|
||||
|
||||
const rows = ref([])
|
||||
const productOptions = ref([])
|
||||
const productSearch = ref('')
|
||||
const rowSavingId = ref('')
|
||||
|
||||
const columns = [
|
||||
{ name: 'OldItemCode', label: 'Eski Ürün Kodu', field: 'OldItemCode', align: 'left', sortable: true, style: 'min-width:140px;white-space:nowrap', headerStyle: 'min-width:140px;white-space:nowrap' },
|
||||
{ name: 'OldColor', label: 'Eski Ürün Rengi', field: 'OldColor', align: 'left', sortable: true, style: 'min-width:120px;white-space:nowrap', headerStyle: 'min-width:120px;white-space:nowrap' },
|
||||
{ name: 'OldItemCode', label: 'Eski Urun Kodu', field: 'OldItemCode', align: 'left', sortable: true, style: 'min-width:140px;white-space:nowrap', headerStyle: 'min-width:140px;white-space:nowrap' },
|
||||
{ name: 'OldColor', label: 'Eski Urun Rengi', field: 'OldColor', align: 'left', sortable: true, style: 'min-width:120px;white-space:nowrap', headerStyle: 'min-width:120px;white-space:nowrap' },
|
||||
{ name: 'OldDim2', label: 'Eski 2. Renk', field: 'OldDim2', align: 'left', sortable: true, style: 'min-width:110px;white-space:nowrap', headerStyle: 'min-width:110px;white-space:nowrap' },
|
||||
{ name: 'OldDesc', label: 'Eski Açıklama', field: 'OldDesc', align: 'left', sortable: false, style: 'min-width:180px;white-space:nowrap', headerStyle: 'min-width:180px;white-space:nowrap' },
|
||||
{ name: 'NewItemCode', label: 'Yeni Ürün Kodu', field: 'NewItemCode', align: 'left', sortable: true, style: 'min-width:140px;white-space:nowrap', headerStyle: 'min-width:140px;white-space:nowrap' },
|
||||
{ name: 'NewColor', label: 'Yeni Ürün Rengi', field: 'NewColor', align: 'left', sortable: true, style: 'min-width:120px;white-space:nowrap', headerStyle: 'min-width:120px;white-space:nowrap' },
|
||||
{ name: 'NewDim2', label: 'Yeni 2. Renk', field: 'NewDim2', align: 'left', sortable: true, style: 'min-width:110px;white-space:nowrap', headerStyle: 'min-width:110px;white-space:nowrap' },
|
||||
{ name: 'NewDesc', label: 'Yeni Açıklama', field: 'NewDesc', align: 'left', sortable: false, style: 'min-width:180px;white-space:nowrap', headerStyle: 'min-width:180px;white-space:nowrap' }
|
||||
{ name: 'OldDesc', label: 'Eski Aciklama', field: 'OldDesc', align: 'left', sortable: false, style: 'min-width:180px;white-space:nowrap', headerStyle: 'min-width:180px;white-space:nowrap' },
|
||||
{ name: 'NewItemCode', label: 'Yeni Urun Kodu', field: 'NewItemCode', align: 'left', sortable: false, style: 'min-width:190px;', headerStyle: 'min-width:190px;' },
|
||||
{ name: 'NewColor', label: 'Yeni Urun Rengi', field: 'NewColor', align: 'left', sortable: false, style: 'min-width:160px;', headerStyle: 'min-width:160px;' },
|
||||
{ name: 'NewDim2', label: 'Yeni 2. Renk', field: 'NewDim2', align: 'left', sortable: false, style: 'min-width:160px;', headerStyle: 'min-width:160px;' },
|
||||
{ name: 'NewDesc', label: 'Yeni Aciklama', field: 'NewDesc', align: 'left', sortable: false, style: 'min-width:220px;', headerStyle: 'min-width:220px;' },
|
||||
{ name: 'actions', label: '', field: 'actions', align: 'center', sortable: false, style: 'width:60px;', headerStyle: 'width:60px;' }
|
||||
]
|
||||
|
||||
onMounted(() => {
|
||||
store.fetchItems(orderHeaderID.value)
|
||||
onMounted(async () => {
|
||||
await refreshAll()
|
||||
})
|
||||
|
||||
watch(orderHeaderID, (id) => {
|
||||
store.fetchItems(id)
|
||||
watch(orderHeaderID, async (id) => {
|
||||
await refreshAll()
|
||||
})
|
||||
|
||||
watch(
|
||||
() => store.items,
|
||||
(items) => {
|
||||
rows.value = (items || []).map(item => ({
|
||||
...item,
|
||||
NewItemCode: '',
|
||||
NewColor: '',
|
||||
NewDim2: '',
|
||||
NewDesc: ''
|
||||
}))
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
() => store.products,
|
||||
(products) => {
|
||||
productOptions.value = products || []
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
function formatDate (val) {
|
||||
if (!val) return ''
|
||||
const text = String(val)
|
||||
return text.length >= 10 ? text.slice(0, 10) : text
|
||||
}
|
||||
|
||||
const filteredProducts = computed(() => {
|
||||
const needle = String(productSearch.value || '').toLowerCase()
|
||||
if (!needle) return productOptions.value.slice(0, 50)
|
||||
return productOptions.value.filter(p =>
|
||||
String(p?.ProductCode || '').toLowerCase().includes(needle)
|
||||
).slice(0, 50)
|
||||
})
|
||||
|
||||
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 = ''
|
||||
return
|
||||
}
|
||||
row.NewItemCode = next ? next.toUpperCase() : ''
|
||||
row.NewColor = ''
|
||||
row.NewDim2 = ''
|
||||
if (row.NewItemCode) {
|
||||
store.fetchColors(row.NewItemCode)
|
||||
}
|
||||
}
|
||||
|
||||
function onNewColorChange (row) {
|
||||
row.NewDim2 = ''
|
||||
if (row.NewItemCode && row.NewColor) {
|
||||
store.fetchSecondColors(row.NewItemCode, row.NewColor)
|
||||
}
|
||||
}
|
||||
|
||||
function getColorOptions (row) {
|
||||
const code = row?.NewItemCode || ''
|
||||
const list = store.colorOptionsByCode[code] || []
|
||||
return list.map(c => ({
|
||||
...c,
|
||||
colorLabel: `${c.color_code} - ${c.color_description || ''}`.trim()
|
||||
}))
|
||||
}
|
||||
|
||||
function getSecondColorOptions (row) {
|
||||
const code = row?.NewItemCode || ''
|
||||
const color = row?.NewColor || ''
|
||||
const key = `${code}::${color}`
|
||||
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 buildPayloadLines () {
|
||||
return rows.value.map(r => ({
|
||||
OrderLineID: r.OrderLineID,
|
||||
NewItemCode: String(r.NewItemCode || '').trim(),
|
||||
NewColor: String(r.NewColor || '').trim(),
|
||||
NewDim2: String(r.NewDim2 || '').trim(),
|
||||
NewDesc: String(r.NewDesc || '').trim()
|
||||
}))
|
||||
}
|
||||
|
||||
async function refreshAll () {
|
||||
await store.fetchHeader(orderHeaderID.value)
|
||||
await store.fetchItems(orderHeaderID.value)
|
||||
await store.fetchProducts()
|
||||
}
|
||||
|
||||
async function onRowSubmit (row) {
|
||||
const line = {
|
||||
OrderLineID: row.OrderLineID,
|
||||
NewItemCode: String(row.NewItemCode || '').trim(),
|
||||
NewColor: String(row.NewColor || '').trim(),
|
||||
NewDim2: String(row.NewDim2 || '').trim(),
|
||||
NewDesc: String(row.NewDesc || '').trim()
|
||||
}
|
||||
|
||||
if (!line.NewItemCode || !line.NewColor) {
|
||||
$q.notify({ type: 'negative', message: 'Yeni urun ve renk zorunludur.' })
|
||||
return
|
||||
}
|
||||
|
||||
rowSavingId.value = row.OrderLineID
|
||||
try {
|
||||
const validate = await store.validateUpdates(orderHeaderID.value, [line])
|
||||
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, [line], true)
|
||||
await store.fetchItems(orderHeaderID.value)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
await store.applyUpdates(orderHeaderID.value, [line], false)
|
||||
await store.fetchItems(orderHeaderID.value)
|
||||
} catch (err) {
|
||||
$q.notify({ type: 'negative', message: 'Islem basarisiz.' })
|
||||
} finally {
|
||||
rowSavingId.value = ''
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user