Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-06-02 16:14:54 +03:00
parent 5f3e975b6d
commit b4e87cfd47
25 changed files with 4918 additions and 287 deletions

View File

@@ -124,9 +124,21 @@
:rows-per-page-options="[0]"
hide-bottom
>
<template #body-cell="props">
<q-td :props="props" :class="props.col.classes">
<template v-if="props.col.name === 'open'">
<template #body="props">
<q-tr
:id="rowDomId(props.row)"
:props="props"
class="rdp-data-row"
@mouseenter="showMembersPopup(props.row)"
@mouseleave="scheduleHideMembersPopup"
>
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
:class="col.classes"
>
<template v-if="col.name === 'open'">
<div class="text-center">
<q-btn
icon="open_in_new"
@@ -141,10 +153,10 @@
</div>
</template>
<template v-else-if="isPermissionColumn(props.col.name)">
<template v-else-if="isPermissionColumn(col.name)">
<div class="text-center">
<q-checkbox
:model-value="Boolean(props.value)"
:model-value="Boolean(col.value)"
disable
dense
/>
@@ -152,12 +164,43 @@
</template>
<template v-else>
{{ props.value }}
{{ col.value }}
</template>
</q-td>
</q-tr>
</template>
</q-table>
<q-menu
v-model="membersPopupOpen"
:target="membersPopupTarget"
no-parent-event
anchor="center right"
self="center left"
:offset="[8, 0]"
class="rdp-members-popup"
@mouseenter="cancelHideMembersPopup"
@mouseleave="scheduleHideMembersPopup"
>
<div class="rdp-members-popup__header">
<div class="text-weight-bold">{{ hoveredRow?.role_title }}</div>
<div class="text-caption text-grey-7">{{ hoveredRow?.department_title }}</div>
</div>
<q-separator />
<q-list v-if="hoveredMembers.length" dense class="rdp-members-popup__list">
<q-item v-for="member in hoveredMembers" :key="member.id">
<q-item-section avatar class="rdp-member-id">{{ member.id }}</q-item-section>
<q-item-section>
<q-item-label>{{ member.full_name || member.username }}</q-item-label>
<q-item-label caption>{{ member.username }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
<div v-else class="q-pa-sm text-caption text-grey-7">
Bu grupta aktif kullanici bulunmuyor.
</div>
</q-menu>
<q-banner v-if="store.error" class="bg-red text-white q-mt-sm">
Hata: {{ store.error }}
</q-banner>
@@ -171,7 +214,7 @@
</template>
<script setup>
import { computed, onMounted, ref, watch } from 'vue'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useQuasar } from 'quasar'
import { usePermission } from 'src/composables/usePermission'
@@ -187,6 +230,10 @@ const selectedModules = ref([])
const selectedActionsByModule = ref({})
const activeModuleCode = ref('')
const allowEmptySelection = ref(false)
const membersPopupOpen = ref(false)
const membersPopupTarget = ref(false)
const hoveredRow = ref(null)
let membersPopupHideTimer = null
const actionLabelMap = {
update: 'Güncelleme',
@@ -428,6 +475,37 @@ const tableRows = computed(() =>
}))
)
const hoveredMembers = computed(() => hoveredRow.value?.members || [])
function rowDomId (row) {
const roleID = String(row?.role_id || '0').replace(/[^a-zA-Z0-9_-]/g, '-')
const departmentCode = String(row?.department_code || '').replace(/[^a-zA-Z0-9_-]/g, '-')
return `rdp-row-${roleID}-${departmentCode}`
}
function cancelHideMembersPopup () {
if (!membersPopupHideTimer) return
clearTimeout(membersPopupHideTimer)
membersPopupHideTimer = null
}
function showMembersPopup (row) {
cancelHideMembersPopup()
hoveredRow.value = row
membersPopupTarget.value = `#${rowDomId(row)}`
membersPopupOpen.value = true
}
function scheduleHideMembersPopup () {
cancelHideMembersPopup()
membersPopupHideTimer = setTimeout(() => {
membersPopupOpen.value = false
hoveredRow.value = null
membersPopupTarget.value = false
membersPopupHideTimer = null
}, 180)
}
function isPermissionColumn (name) {
return String(name || '').startsWith('perm_')
}
@@ -472,6 +550,10 @@ onMounted(async () => {
syncSelections()
}
})
onBeforeUnmount(() => {
cancelHideMembersPopup()
})
</script>
<style scoped>
@@ -571,6 +653,30 @@ onMounted(async () => {
padding: 3px 6px;
}
.rdp-data-row {
cursor: default;
}
.rdp-members-popup {
min-width: 280px;
max-width: 380px;
}
.rdp-members-popup__header {
padding: 10px 12px 8px;
}
.rdp-members-popup__list {
max-height: 360px;
overflow: auto;
}
.rdp-member-id {
min-width: 48px;
color: #1976d2;
font-weight: 700;
}
.rdp-table :deep(.q-checkbox__inner) {
pointer-events: none;
}