This commit is contained in:
2026-02-11 17:46:22 +03:00
commit eacfacb13b
266 changed files with 51337 additions and 0 deletions

408
ui/src/pages/OrderList.vue Normal file
View File

@@ -0,0 +1,408 @@
<template>
<q-page class="ol-page">
<!-- 🔍 Sticky Filter -->
<div class="ol-filter-bar">
<!-- 🔹 TEK SATIR FLEX -->
<div class="ol-filter-row">
<!-- 🔍 Arama -->
<q-input
class="ol-filter-input ol-search"
dense
filled
v-model="store.filters.search"
label="Arama (Sipariş No / Cari / Açıklama)"
debounce="300"
clearable
>
<template #append>
<q-icon name="search" />
</template>
</q-input>
<!-- 🧾 Cari Kodu -->
<q-input
class="ol-filter-input"
dense
filled
v-model="store.filters.CurrAccCode"
label="Cari Kodu"
clearable
/>
<!-- 📅 Sipariş Tarihi -->
<q-input
class="ol-filter-input"
dense
filled
v-model="store.filters.OrderDate"
label="Sipariş Tarihi"
type="date"
/>
<!-- 🔘 Butonlar -->
<div class="ol-filter-actions">
<q-btn
label="Temizle"
icon="clear"
color="grey-7"
flat
:disable="store.loading"
@click="clearFilters"
>
<q-tooltip>
Tüm filtreleri temizle
</q-tooltip>
</q-btn>
<q-btn
label="Yenile"
color="primary"
icon="refresh"
:loading="store.loading"
@click="store.fetchOrders"
/>
<q-btn
label="Excel'e Aktar"
icon="download"
color="primary"
outline
:disable="store.loading || store.filteredOrders.length === 0"
@click="exportExcel"
/>
</div>
<!-- 💰 Toplam -->
<div class="ol-filter-total">
Toplam Görünen Sipariş Tutarı (USD):
<strong>
{{ store.totalVisibleUSD.toLocaleString('tr-TR', { minimumFractionDigits: 2 }) }}
USD
</strong>
</div>
</div>
</div>
<!-- 📋 ORDER LIST TABLE -->
<q-table
title="Mevcut Siparişler"
class="ol-table"
flat
bordered
dense
separator="cell"
row-key="OrderHeaderID"
:rows="store.filteredOrders"
:columns="columns"
:loading="store.loading"
no-data-label="Sipariş bulunamadı"
:rows-per-page-options="[0]"
hide-bottom
>
<!-- 📄 PDF + DURUM -->
<template #body-cell-IsCreditableConfirmed="props">
<q-td :props="props" class="text-center q-gutter-sm">
<q-btn
icon="picture_as_pdf"
color="red"
flat
round
dense
@click="printPDF(props.row)"
>
<q-tooltip>Siparişi PDF olarak </q-tooltip>
</q-btn>
<q-icon
:name="props.row.IsCreditableConfirmed ? 'check_circle' : 'cancel'"
:color="props.row.IsCreditableConfirmed ? 'green' : 'red'"
size="20px"
>
<q-tooltip>
{{ props.row.IsCreditableConfirmed ? 'Onaylı' : 'Onaysız' }}
</q-tooltip>
</q-icon>
</q-td>
</template>
<!-- 📅 Tarih -->
<template #body-cell-OrderDate="props">
<q-td :props="props" class="text-center">
{{ formatDate(props.row.OrderDate) }}
</q-td>
</template>
<template #body-cell-CreditableConfirmedDate="props">
<q-td :props="props" class="text-center">
{{ formatDate(props.row.CreditableConfirmedDate) }}
</q-td>
</template>
<!-- 🧾 Cari Adı 2 Satır -->
<template #body-cell-CurrAccDescription="props">
<q-td :props="props" class="ol-col-cari ol-col-multiline">
{{ props.value }}
<q-tooltip v-if="props.value">
{{ props.value }}
</q-tooltip>
</q-td>
</template>
<!-- 📝 ıklama 5 Satır -->
<template #body-cell-Description="props">
<q-td :props="props" class="ol-col-desc ol-col-multiline">
{{ props.value }}
<q-tooltip v-if="props.value">
{{ props.value }}
</q-tooltip>
</q-td>
</template>
<!-- 🔗 -->
<template #body-cell-select="props">
<q-td :props="props" class="text-center">
<q-btn
icon="open_in_new"
color="primary"
flat
round
dense
@click="selectOrder(props.row)"
>
<q-tooltip>Siparişi </q-tooltip>
</q-btn>
</q-td>
</template>
</q-table>
<!-- HATA -->
<q-banner v-if="store.error" class="bg-red text-white q-mt-sm">
{{ store.error }}
</q-banner>
</q-page>
</template>
<script setup>
import { onMounted, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useQuasar } from 'quasar'
import { useOrderListStore } from 'src/stores/OrdernewListStore'
import { useAuthStore } from 'src/stores/authStore'
import { usePermission } from 'src/composables/usePermission'
const { canRead, canWrite, canUpdate } = usePermission()
const canReadOrder = canRead('order')
const canWriteOrder = canWrite('order')
const canUpdateOrder = canUpdate('order')
/* =========================
INIT
========================= */
const router = useRouter()
const $q = useQuasar()
// ⚠️ ÖNCE store tanımlanır
const store = useOrderListStore()
/* =========================
SEARCH DEBOUNCE
========================= */
let searchTimer = null
watch(
() => store.filters.search,
() => {
clearTimeout(searchTimer)
searchTimer = setTimeout(() => {
store.fetchOrders()
}, 400)
}
)
/* =========================
HELPERS
========================= */
function exportExcel () {
const auth = useAuthStore()
if (!auth?.token) {
$q.notify({
type: 'negative',
message: 'Oturum bulunamadı',
position: 'top-right'
})
return
}
const params = new URLSearchParams({
search: store.filters.search || '',
CurrAccCode: store.filters.CurrAccCode || '',
OrderDate: store.filters.OrderDate || ''
})
const url = `http://localhost:8080/api/orders/export?${params.toString()}`
fetch(url, {
headers: {
Authorization: `Bearer ${auth.token}`
}
})
.then(res => res.blob())
.then(blob => {
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = 'siparis_listesi.xlsx'
link.click()
})
}
function formatDate (s) {
if (!s) return ''
const [y, m, d] = s.split('-')
return `${d}.${m}.${y}`
}
/* =========================
TABLE COLUMNS
========================= */
const columns = [
{ name: 'select', label: '', field: 'select', align: 'center', sortable: false },
{ name: 'OrderNumber', label: 'Sipariş No', field: 'OrderNumber', align: 'left', sortable: true },
{ name: 'OrderDate', label: 'Tarih', field: 'OrderDate', align: 'center', sortable: true },
{ name: 'CurrAccCode', label: 'Cari Kod', field: 'CurrAccCode', align: 'left', sortable: true },
{
name: 'CurrAccDescription',
label: 'Cari Adı',
field: 'CurrAccDescription',
align: 'left',
sortable: true,
classes: 'ol-col-cari',
headerClasses: 'ol-col-cari',
style: 'max-width:200px'
},
{ name: 'MusteriTemsilcisi', label: 'Temsilci', field: 'MusteriTemsilcisi', align: 'left', sortable: true },
{ name: 'Piyasa', label: 'Piyasa', field: 'Piyasa', align: 'left', sortable: true },
{ name: 'CreditableConfirmedDate', label: 'Onay', field: 'CreditableConfirmedDate', align: 'center', sortable: true },
{ name: 'DocCurrencyCode', label: 'PB', field: 'DocCurrencyCode', align: 'center', sortable: true },
{
name: 'TotalAmount',
label: 'Tutar',
field: 'TotalAmount',
align: 'right',
sortable: true,
format: (val, row) =>
Number(val || 0).toLocaleString('tr-TR', { minimumFractionDigits: 2 }) +
' ' + row.DocCurrencyCode
},
{
name: 'TotalAmountUSD',
label: 'Tutar (USD)',
field: 'TotalAmountUSD',
align: 'right',
sortable: true,
format: val =>
Number(val || 0).toLocaleString('tr-TR', { minimumFractionDigits: 2 }) + ' USD'
},
{ name: 'IsCreditableConfirmed', label: 'Durum', field: 'IsCreditableConfirmed', align: 'center', sortable: true },
{
name: 'Description',
label: 'Açıklama',
field: 'Description',
align: 'left',
sortable: false,
classes: 'ol-col-desc',
headerClasses: 'ol-col-desc',
style: 'max-width:220px'
},
{ name: 'pdf', label: 'PDF', field: 'pdf', align: 'center', sortable: false }
]
/* =========================
ACTIONS
========================= */
function selectOrder (row) {
if (!row?.OrderHeaderID) {
$q.notify({ type: 'warning', message: 'OrderHeaderID bulunamadı' })
return
}
router.push({
name: 'order-edit',
params: { orderHeaderID: row.OrderHeaderID },
query: { mode: 'edit' }
})
}
async function printPDF (row) {
if (!row?.OrderHeaderID) return
const token = useAuthStore().token
const url = `http://localhost:8080/api/order/pdf/${row.OrderHeaderID}`
try {
const res = await fetch(url, {
headers: { Authorization: `Bearer ${token}` }
})
if (!res.ok) throw new Error()
const blob = await res.blob()
window.open(URL.createObjectURL(blob), '_blank')
} catch {
$q.notify({ type: 'negative', message: 'PDF yüklenemedi' })
}
}
function clearFilters () {
store.filters.search = ''
store.filters.CurrAccCode = ''
store.filters.OrderDate = ''
store.fetchOrders()
$q.notify({
type: 'info',
message: 'Filtreler temizlendi',
position: 'top-right'
})
}
/* =========================
INIT LOAD
========================= */
onMounted(() => {
store.fetchOrders()
})
</script>