Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -86,6 +86,63 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="lookupsLoaded && roleId && deptCode"
|
||||
class="group-members-toolbar"
|
||||
>
|
||||
<div class="group-members-toolbar__members">
|
||||
<div class="text-caption text-weight-bold">
|
||||
Grup Kullanicilari ({{ members.length }})
|
||||
</div>
|
||||
<div v-if="membersLoading" class="q-ml-sm">
|
||||
<q-spinner color="primary" size="18px" />
|
||||
</div>
|
||||
<div v-else-if="members.length" class="group-members-toolbar__chips">
|
||||
<q-chip
|
||||
v-for="member in members"
|
||||
:key="member.id"
|
||||
dense
|
||||
square
|
||||
color="blue-1"
|
||||
text-color="primary"
|
||||
>
|
||||
{{ member.id }} - {{ member.full_name || member.username }}
|
||||
<q-tooltip>{{ member.username }}</q-tooltip>
|
||||
</q-chip>
|
||||
</div>
|
||||
<div v-else class="text-caption text-grey-7 q-ml-sm">
|
||||
Bu grupta aktif kullanici bulunmuyor.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="group-members-toolbar__add">
|
||||
<q-select
|
||||
v-model="memberUserId"
|
||||
:options="filteredUserOptions"
|
||||
option-value="id"
|
||||
option-label="title"
|
||||
emit-value
|
||||
map-options
|
||||
dense
|
||||
outlined
|
||||
clearable
|
||||
use-input
|
||||
input-debounce="150"
|
||||
label="Kullanici ekle"
|
||||
class="group-members-toolbar__select"
|
||||
@filter="filterUsers"
|
||||
/>
|
||||
<q-btn
|
||||
color="primary"
|
||||
icon="person_add"
|
||||
label="Ekle"
|
||||
:disable="!memberUserId || addingMember"
|
||||
:loading="addingMember"
|
||||
@click="addMember"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -184,7 +241,7 @@
|
||||
|
||||
<script setup>
|
||||
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import { computed, ref, onMounted, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { Notify } from 'quasar'
|
||||
import api from 'src/services/api'
|
||||
@@ -201,13 +258,19 @@ const router = useRouter()
|
||||
|
||||
const roles = ref([])
|
||||
const departments = ref([])
|
||||
const users = ref([])
|
||||
const filteredUserOptions = ref([])
|
||||
const members = ref([])
|
||||
|
||||
const roleId = ref(null)
|
||||
const deptCode = ref(null)
|
||||
const memberUserId = ref(null)
|
||||
|
||||
const rows = ref([])
|
||||
|
||||
const loading = ref(false)
|
||||
const membersLoading = ref(false)
|
||||
const addingMember = ref(false)
|
||||
const dirty = ref(false)
|
||||
const lookupsLoaded = ref(false)
|
||||
|
||||
@@ -274,15 +337,18 @@ function applyRouteSelection () {
|
||||
|
||||
async function loadLookups () {
|
||||
|
||||
const [r, d, m] = await Promise.all([
|
||||
const [r, d, m, u] = await Promise.all([
|
||||
api.get('/lookups/roles-perm'),
|
||||
api.get('/lookups/departments-perm'),
|
||||
api.get('/lookups/modules')
|
||||
api.get('/lookups/modules'),
|
||||
api.get('/lookups/users-perm')
|
||||
])
|
||||
|
||||
roles.value = r.data || []
|
||||
departments.value = d.data || []
|
||||
modules.value = m.data || []
|
||||
users.value = u.data || []
|
||||
filteredUserOptions.value = [...users.value]
|
||||
|
||||
lookupsLoaded.value = true
|
||||
}
|
||||
@@ -312,7 +378,10 @@ function initMatrix () {
|
||||
|
||||
async function loadMatrix () {
|
||||
|
||||
if (!roleId.value || !deptCode.value) return
|
||||
if (!roleId.value || !deptCode.value) {
|
||||
members.value = []
|
||||
return
|
||||
}
|
||||
if (matrixLoading) return
|
||||
|
||||
matrixLoading = true
|
||||
@@ -326,9 +395,10 @@ async function loadMatrix () {
|
||||
|
||||
initMatrix()
|
||||
|
||||
const res = await api.get(
|
||||
`/roles/${roleId.value}/departments/${deptCode.value}/permissions`
|
||||
)
|
||||
const [res] = await Promise.all([
|
||||
api.get(`/roles/${roleId.value}/departments/${deptCode.value}/permissions`),
|
||||
loadMembers()
|
||||
])
|
||||
|
||||
const list = Array.isArray(res.data) ? res.data : []
|
||||
|
||||
@@ -384,6 +454,70 @@ async function loadMatrix () {
|
||||
}
|
||||
}
|
||||
|
||||
const availableUserOptions = computed(() => {
|
||||
const memberIDs = new Set(members.value.map(member => Number(member.id)))
|
||||
return users.value.filter(user => !memberIDs.has(Number(user.id)))
|
||||
})
|
||||
|
||||
function filterUsers (value, update) {
|
||||
update(() => {
|
||||
const needle = String(value || '').trim().toLocaleLowerCase('tr')
|
||||
filteredUserOptions.value = needle
|
||||
? availableUserOptions.value.filter(user => String(user.title || '').toLocaleLowerCase('tr').includes(needle))
|
||||
: [...availableUserOptions.value]
|
||||
})
|
||||
}
|
||||
|
||||
async function loadMembers () {
|
||||
if (!roleId.value || !deptCode.value) {
|
||||
members.value = []
|
||||
return
|
||||
}
|
||||
membersLoading.value = true
|
||||
try {
|
||||
const res = await api.get(
|
||||
`/roles/${roleId.value}/departments/${encodeURIComponent(deptCode.value)}/members`
|
||||
)
|
||||
members.value = Array.isArray(res.data) ? res.data : []
|
||||
filteredUserOptions.value = [...availableUserOptions.value]
|
||||
} catch (err) {
|
||||
console.error('GROUP MEMBERS LOAD ERROR:', err)
|
||||
members.value = []
|
||||
Notify.create({
|
||||
type: 'negative',
|
||||
message: 'Grup kullanicilari yuklenemedi'
|
||||
})
|
||||
} finally {
|
||||
membersLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function addMember () {
|
||||
if (!roleId.value || !deptCode.value || !memberUserId.value) return
|
||||
addingMember.value = true
|
||||
try {
|
||||
const res = await api.post(
|
||||
`/roles/${roleId.value}/departments/${encodeURIComponent(deptCode.value)}/members`,
|
||||
{ user_id: Number(memberUserId.value) }
|
||||
)
|
||||
members.value = Array.isArray(res.data) ? res.data : []
|
||||
memberUserId.value = null
|
||||
filteredUserOptions.value = [...availableUserOptions.value]
|
||||
Notify.create({
|
||||
type: 'positive',
|
||||
message: 'Kullanici gruba eklendi'
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('GROUP MEMBER ADD ERROR:', err)
|
||||
Notify.create({
|
||||
type: 'negative',
|
||||
message: 'Kullanici gruba eklenemedi'
|
||||
})
|
||||
} finally {
|
||||
addingMember.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ================= SAVE ================= */
|
||||
|
||||
@@ -482,3 +616,53 @@ watch(
|
||||
)
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.group-members-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 8px 12px;
|
||||
background: #fff;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.group-members-toolbar__members {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.group-members-toolbar__chips {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
overflow-x: auto;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.group-members-toolbar__add {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.group-members-toolbar__select {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.group-members-toolbar {
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.group-members-toolbar__select {
|
||||
width: min(100%, 420px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user