ilk
This commit is contained in:
408
ui/src/pages/OrderList.vue
Normal file
408
ui/src/pages/OrderList.vue
Normal 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 aç</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>
|
||||
|
||||
<!-- 📝 Açı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>
|
||||
|
||||
<!-- 🔗 Aç -->
|
||||
<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 Aç</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>
|
||||
|
||||
Reference in New Issue
Block a user