Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-06-22 22:25:55 +03:00
parent a839cae840
commit 4e36e2b057
14 changed files with 2946 additions and 372 deletions
+195
View File
@@ -0,0 +1,195 @@
<template>
<q-page class="q-pa-md">
<div class="row items-center justify-between q-mb-md">
<div>
<div class="text-h6">Urun Seri Tanimlamalari</div>
<div class="text-caption text-grey-7">Seri kodu ve beden seri basliklari burada yonetilir.</div>
</div>
<div class="row q-gutter-sm">
<q-btn color="secondary" outline icon="refresh" label="Yenile" :loading="loading" @click="reload" />
<q-btn color="primary" icon="add" label="Yeni Seri" :disable="!canUpdate" @click="newRow" />
</div>
</div>
<q-table
flat
bordered
row-key="id"
:rows="rows"
:columns="columns"
:loading="loading"
:pagination="{ rowsPerPage: 0 }"
hide-bottom
class="bg-white"
>
<template #body-cell-is_active="props">
<q-td :props="props">
<q-toggle v-model="props.row.is_active" dense :disable="!canUpdate || saving" @update:model-value="() => markDirty(props.row)" />
</q-td>
</template>
<template #body-cell-actions="props">
<q-td :props="props" class="text-right">
<q-btn dense flat round icon="edit" color="primary" :disable="!canUpdate" @click="editRow(props.row)" />
<q-btn dense flat round icon="delete" color="negative" :disable="!canUpdate" @click="removeRow(props.row)" />
</q-td>
</template>
</q-table>
<q-dialog v-model="dialogOpen" persistent>
<q-card style="min-width: 520px">
<q-card-section class="row items-center justify-between">
<div class="text-subtitle1">{{ editing.id ? 'Seri Duzenle' : 'Yeni Seri' }}</div>
<q-btn flat round dense icon="close" v-close-popup />
</q-card-section>
<q-separator />
<q-card-section class="q-gutter-md">
<q-input v-model="editing.code" dense outlined label="Seri Kodu" autofocus />
<q-input v-model="editing.title" dense outlined label="Seri Basligi" />
<q-input v-model="editing.parent_filter" dense outlined label="Parent Filter" />
<q-input v-model.number="editing.sort_order" dense outlined type="number" label="Sira" />
<q-input v-model="editing.notes" dense outlined type="textarea" label="Not" />
<q-toggle v-model="editing.is_active" label="Aktif" />
</q-card-section>
<q-card-actions align="right">
<q-btn flat label="Vazgec" v-close-popup />
<q-btn color="primary" icon="save" label="Kaydet" :loading="saving" @click="saveDialog" />
</q-card-actions>
</q-card>
</q-dialog>
</q-page>
</template>
<script setup>
import { computed, onMounted, ref } from 'vue'
import { Dialog, Notify } from 'quasar'
import api from 'src/services/api'
import { usePermissionStore } from 'stores/permissionStore'
const perm = usePermissionStore()
const canUpdate = computed(() => perm.hasApiPermission('pricing:update'))
const loading = ref(false)
const saving = ref(false)
const rows = ref([])
const dialogOpen = ref(false)
const editing = ref(emptyRow())
const columns = [
{ name: 'code', label: 'Seri Kodu', field: 'code', align: 'left', sortable: true },
{ name: 'title', label: 'Seri Basligi', field: 'title', align: 'left', sortable: true },
{ name: 'parent_filter', label: 'Parent Filter', field: 'parent_filter', align: 'left', sortable: true },
{ name: 'sort_order', label: 'Sira', field: 'sort_order', align: 'right', sortable: true },
{ name: 'is_active', label: 'Aktif', field: 'is_active', align: 'center', sortable: true },
{ name: 'actions', label: '', field: 'actions', align: 'right' }
]
function emptyRow () {
return {
id: 0,
code: '',
title: '',
is_active: true,
parent_filter: '',
sort_order: 0,
notes: ''
}
}
function normalizeRow (row) {
return {
id: Number(row.id || 0),
code: String(row.code || '').trim(),
title: String(row.title || '').trim(),
is_active: row.is_active !== false,
parent_filter: String(row.parent_filter || '').trim(),
sort_order: Number(row.sort_order || 0),
notes: String(row.notes || '').trim()
}
}
async function reload () {
loading.value = true
try {
const res = await api.get('/pricing/product-series/definitions')
rows.value = (Array.isArray(res.data) ? res.data : []).map(normalizeRow)
} catch (err) {
Notify.create({ type: 'negative', message: err?.response?.data || err?.message || 'Seri tanimlari alinamadi' })
} finally {
loading.value = false
}
}
function newRow () {
editing.value = emptyRow()
dialogOpen.value = true
}
function editRow (row) {
editing.value = { ...normalizeRow(row) }
dialogOpen.value = true
}
function markDirty (row) {
saveInline(row)
}
async function saveInline (row) {
if (!canUpdate.value || !row.id) return
saving.value = true
try {
await api.put(`/pricing/product-series/definitions/${row.id}`, normalizeRow(row))
Notify.create({ type: 'positive', message: 'Kaydedildi' })
} catch (err) {
Notify.create({ type: 'negative', message: err?.response?.data || err?.message || 'Seri tanimi kaydedilemedi' })
await reload()
} finally {
saving.value = false
}
}
async function saveDialog () {
const payload = normalizeRow(editing.value)
if (!payload.code) {
Notify.create({ type: 'warning', message: 'Seri kodu zorunludur' })
return
}
saving.value = true
try {
if (payload.id) {
await api.put(`/pricing/product-series/definitions/${payload.id}`, payload)
} else {
await api.post('/pricing/product-series/definitions', payload)
}
dialogOpen.value = false
await reload()
Notify.create({ type: 'positive', message: 'Kaydedildi' })
} catch (err) {
Notify.create({ type: 'negative', message: err?.response?.data || err?.message || 'Seri tanimi kaydedilemedi' })
} finally {
saving.value = false
}
}
function removeRow (row) {
Dialog.create({
title: 'Seri pasife alinsin mi?',
message: `${row.code} - ${row.title}`,
cancel: true,
persistent: true
}).onOk(async () => {
saving.value = true
try {
await api.delete(`/pricing/product-series/definitions/${row.id}`)
await reload()
Notify.create({ type: 'positive', message: 'Pasife alindi' })
} catch (err) {
Notify.create({ type: 'negative', message: err?.response?.data || err?.message || 'Seri tanimi silinemedi' })
} finally {
saving.value = false
}
})
}
onMounted(reload)
</script>