307 lines
5.0 KiB
Vue
307 lines
5.0 KiB
Vue
<template>
|
||
<q-page v-if="canReadSystem" padding>
|
||
|
||
<div class="text-h6 q-mb-md">
|
||
Rol + Departman Yetkilendirme
|
||
</div>
|
||
|
||
<!-- SELECTS -->
|
||
<div class="row q-col-gutter-md q-mb-md">
|
||
|
||
<div class="col-4">
|
||
<q-select
|
||
v-model="roleId"
|
||
:options="roles"
|
||
label="Rol"
|
||
dense
|
||
outlined
|
||
emit-value
|
||
map-options
|
||
@update:model-value="loadMatrix"
|
||
/>
|
||
</div>
|
||
|
||
<div class="col-4">
|
||
<q-select
|
||
v-model="deptCode"
|
||
:options="departments"
|
||
label="Departman"
|
||
dense
|
||
outlined
|
||
emit-value
|
||
map-options
|
||
@update:model-value="loadMatrix"
|
||
/>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
<!-- TABLE -->
|
||
<q-table
|
||
:rows="rows"
|
||
:columns="columns"
|
||
row-key="module"
|
||
flat
|
||
bordered
|
||
dense
|
||
:loading="loading"
|
||
>
|
||
|
||
<template v-slot:body-cell="props">
|
||
|
||
<q-td :props="props">
|
||
|
||
<!-- MODULE NAME -->
|
||
<span v-if="props.col.name === 'module'">
|
||
{{ props.row.label }}
|
||
</span>
|
||
|
||
<!-- CHECKBOX -->
|
||
<q-checkbox
|
||
v-else
|
||
v-model="props.row[props.col.name]"
|
||
dense
|
||
@update:model-value="dirty = true"
|
||
/>
|
||
|
||
</q-td>
|
||
|
||
</template>
|
||
|
||
</q-table>
|
||
|
||
|
||
<!-- SAVE -->
|
||
<div class="q-mt-md">
|
||
|
||
<q-btn
|
||
v-if="canUpdateUser"
|
||
color="primary"
|
||
icon="save"
|
||
label="Kaydet"
|
||
:disable="!dirty"
|
||
@click="save"
|
||
/>
|
||
|
||
</div>
|
||
|
||
</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 { ref, onMounted } from 'vue'
|
||
import { Notify } from 'quasar'
|
||
import api from 'src/services/api'
|
||
import { usePermission } from 'src/composables/usePermission'
|
||
|
||
const { canRead, canUpdate } = usePermission()
|
||
const canReadSystem = canRead('system')
|
||
const canUpdateUser = canUpdate('user')
|
||
|
||
|
||
/* ================= STATE ================= */
|
||
|
||
const roles = ref([])
|
||
const departments = ref([])
|
||
|
||
const roleId = ref(null)
|
||
const deptCode = ref(null)
|
||
|
||
const rows = ref([])
|
||
|
||
const loading = ref(false)
|
||
const dirty = ref(false)
|
||
|
||
|
||
/* ================= ACTION MAP ================= */
|
||
|
||
const actions = [
|
||
{ key: 'write', label: 'Ekleme' },
|
||
{ key: 'read', label: 'Görüntüleme' },
|
||
{ key: 'delete', label: 'Silme' },
|
||
{ key: 'update', label: 'Güncelleme' },
|
||
{ key: 'export', label: 'Çıktı' }
|
||
]
|
||
|
||
|
||
|
||
/* ================= MODULES ================= */
|
||
|
||
const [r, d, m] = await Promise.all([
|
||
api.get('/lookups/roles'),
|
||
api.get('/lookups/departments'),
|
||
api.get('/lookups/modules')
|
||
])
|
||
|
||
modules.value = m.data || []
|
||
|
||
|
||
/* ================= TABLE ================= */
|
||
|
||
const columns = [
|
||
|
||
{
|
||
name: 'module',
|
||
label: 'Modül',
|
||
field: 'label',
|
||
align: 'left'
|
||
},
|
||
|
||
...actions.map(a => ({
|
||
name: a.key,
|
||
label: a.label,
|
||
align: 'center'
|
||
}))
|
||
]
|
||
|
||
|
||
/* ================= LOAD LOOKUPS ================= */
|
||
|
||
async function loadLookups () {
|
||
|
||
const [r, d] = await Promise.all([
|
||
|
||
api.get('/lookups/roles'),
|
||
api.get('/lookups/departments')
|
||
|
||
])
|
||
|
||
roles.value = r.data
|
||
departments.value = d.data
|
||
}
|
||
|
||
|
||
/* ================= INIT TABLE ================= */
|
||
|
||
function initMatrix () {
|
||
|
||
rows.value = modules.map(m => {
|
||
|
||
const row = {
|
||
module: m.code,
|
||
label: m.label
|
||
}
|
||
|
||
actions.forEach(a => {
|
||
row[a.key] = false
|
||
})
|
||
|
||
return row
|
||
})
|
||
}
|
||
|
||
|
||
/* ================= LOAD ================= */
|
||
|
||
async function loadMatrix () {
|
||
|
||
if (!roleId.value || !deptCode.value) return
|
||
|
||
loading.value = true
|
||
|
||
try {
|
||
|
||
initMatrix()
|
||
|
||
const res = await api.get(
|
||
`/roles/${roleId.value}/departments/${deptCode.value}/permissions`
|
||
)
|
||
|
||
list.forEach(p => {
|
||
|
||
const code = String(p.module_code || p.module)
|
||
.toLowerCase()
|
||
.trim()
|
||
// 🔥 kritik
|
||
|
||
const row = rows.value.find(r => r.module === code)
|
||
|
||
if (row) {
|
||
row[p.action] = p.allowed
|
||
}
|
||
|
||
})
|
||
|
||
|
||
dirty.value = false
|
||
|
||
} catch {
|
||
|
||
Notify.create({
|
||
type: 'negative',
|
||
message: 'Yetkiler yüklenemedi'
|
||
})
|
||
|
||
} finally {
|
||
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
|
||
/* ================= SAVE ================= */
|
||
|
||
async function save () {
|
||
|
||
try {
|
||
|
||
loading.value = true
|
||
|
||
const payload = []
|
||
|
||
rows.value.forEach(r => {
|
||
|
||
actions.forEach(a => {
|
||
|
||
payload.push({
|
||
module: r.module,
|
||
action: a.key,
|
||
allowed: r[a.key]
|
||
})
|
||
|
||
})
|
||
})
|
||
|
||
await api.post(
|
||
`/roles/${roleId.value}/departments/${deptCode.value}/permissions`,
|
||
payload
|
||
)
|
||
|
||
Notify.create({
|
||
type: 'positive',
|
||
message: 'Kaydedildi'
|
||
})
|
||
|
||
dirty.value = false
|
||
|
||
} catch {
|
||
|
||
Notify.create({
|
||
type: 'negative',
|
||
message: 'Kayıt hatası'
|
||
})
|
||
|
||
} finally {
|
||
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
|
||
/* ================= INIT ================= */
|
||
|
||
onMounted(() => {
|
||
loadLookups()
|
||
})
|
||
|
||
</script>
|