Files
bssapp/ui/src/pages/UserList.vue

296 lines
6.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<q-page
v-if="canReadUser"
class="ol-page with-bg"
>
<!-- 🔍 Sticky Filter -->
<div class="ol-filter-bar">
<div class="ol-filter-row">
<q-input
class="ol-filter-input ol-search"
dense
filled
clearable
v-model="store.filters.search"
label="Arama (Kullanıcı / Rol / Piyasa)"
debounce="300"
@update:model-value="store.fetchUsers"
>
<template #append>
<q-icon name="search" />
</template>
</q-input>
<q-toggle
v-model="store.filters.onlyActive"
label="Sadece Aktifler"
/>
<div class="ol-filter-actions">
<q-btn
v-if="canReadUser"
label="Yenile"
icon="refresh"
color="primary"
:loading="store.loading"
:disable="!canReadUser"
@click="store.fetchUsers"
/>
<q-btn
v-if="canWriteUser"
label="Yeni Kullanıcı"
icon="person_add"
color="primary"
outline
@click="goCreate"
/>
</div>
</div>
</div>
<!-- 📋 USER LIST TABLE -->
<q-table
title="Mevcut Kullanıcılar"
class="ol-table"
flat
bordered
dense
separator="cell"
row-key="id"
:rows="store.filteredUsers"
:columns="columns"
:loading="store.loading"
no-data-label="Kullanıcı bulunamadı"
:rows-per-page-options="[0]"
hide-bottom
>
<!-- 🔗 OPEN -->
<template #body-cell-open="props">
<q-td class="text-center">
<q-btn
v-if="canReadUser"
icon="open_in_new"
color="primary"
flat
round
dense
@click="openDetail(props.row.id)"
/>
</q-td>
</template>
<!-- DURUM -->
<template #body-cell-is_active="props">
<q-td class="text-center">
<q-icon
:name="props.row.is_active ? 'check_circle' : 'cancel'"
:color="props.row.is_active ? 'green' : 'red'"
size="18px"
/>
</q-td>
</template>
<!-- 👤 ROLLER -->
<template #body-cell-role_names="props">
<q-td>
<q-chip
v-for="r in splitNames(props.row.role_names)"
:key="r"
dense
color="primary"
text-color="white"
class="q-mr-xs"
>
{{ r }}
</q-chip>
</q-td>
</template>
<!-- 🏢 DEPARTMAN -->
<template #body-cell-department_names="props">
<q-td>
<q-chip
v-for="d in splitNames(props.row.department_names)"
:key="d"
dense
color="grey-7"
text-color="white"
class="q-mr-xs"
>
{{ d }}
</q-chip>
</q-td>
</template>
<!-- 🌍 PİYASALAR -->
<template #body-cell-piyasa_names="props">
<q-td class="ol-col-piyasa">
<div class="piyasa-wrap">
<q-chip
v-for="p in splitPiyasalar(props.row.piyasa_names)"
:key="p"
dense
outline
color="indigo"
class="piyasa-chip"
:title="p"
>
{{ p }}
</q-chip>
</div>
</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>
<q-page
v-else
class="q-pa-md flex flex-center"
>
<div class="text-negative text-subtitle1">
Bu module erisim yetkiniz yok.
</div>
</q-page>
</template>
<script setup>
import { onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useUserListStore } from 'src/stores/UserListStore'
import { usePermission } from 'src/composables/usePermission'
const { canRead, canWrite, canUpdate } = usePermission()
const canReadUser = canRead('user')
const canWriteUser = canWrite('user')
const canUpdateUser = canUpdate('user')
const router = useRouter()
const store = useUserListStore()
/* ==========================================================
📌 QTable Columns
========================================================== */
const columns = [
{ name: 'open', label: '', align: 'center' },
{
name: 'id',
label: 'No',
field: row => row.id,
sortable: true
},
{
name: 'code',
label: 'Kullanıcı',
field: row => row.code || '',
sortable: true,
sort: (a, b) => a.localeCompare(b, 'tr', { sensitivity: 'base' })
},
{
name: 'nebim_username',
label: 'Nebim',
field: row => row.nebim_username || '',
sortable: true,
sort: (a, b) => a.localeCompare(b, 'tr')
},
{
name: 'user_group_code',
label: 'Grup',
field: row => row.user_group_code || '',
sortable: true,
sort: (a, b) => a.localeCompare(b, 'tr')
},
{
name: 'is_active',
label: 'Durum',
field: row => row.is_active,
align: 'center',
sortable: true,
sort: (a, b) => Number(b) - Number(a)
},
{
name: 'role_names',
label: 'Roller',
field: row => row.role_names || '',
sortable: true,
sort: (a, b) => a.localeCompare(b, 'tr')
},
{
name: 'department_names',
label: 'Departmanlar',
field: row => row.department_names || '',
sortable: true,
sort: (a, b) => a.localeCompare(b, 'tr')
},
{
name: 'piyasa_names',
label: 'Piyasalar',
field: row => row.piyasa_names || '',
sortable: true,
sort: (a, b) => a.localeCompare(b, 'tr')
}
]
/* ==========================================================
HELPERS
========================================================== */
function splitNames(val) {
if (!val) return []
return val.split(',').map(v => v.trim())
}
function openDetail(id) {
const routeName = canUpdateUser.value ? 'user-edit' : 'user-view'
router.push({
name: routeName,
params: { id: String(id) }
})
}
function goCreate() {
if (!canWriteUser.value) return
router.push({ name: 'user-new' })
}
function splitPiyasalar (val) {
if (!val) return []
return val
.split(',')
.map(v => v.trim())
.filter(Boolean)
.slice(0, 24) // ✅ 6 satır × 4 kolon
}
onMounted(() => {
if (canReadUser.value) {
store.fetchUsers()
}
})
</script>