Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-05-12 11:54:12 +03:00
parent a4f7d5b071
commit f9a035d11d
6 changed files with 122 additions and 181 deletions

View File

@@ -173,6 +173,7 @@ import { usePermissionStore } from 'stores/permissionStore'
import { useI18n } from 'src/composables/useI18n'
import { UI_LANGUAGE_OPTIONS } from 'src/i18n/languages'
import { useLocaleStore } from 'src/stores/localeStore'
import { activityLogsMenuItem, getAuthUserId } from 'src/modules/activityLogs'
/* ================= STORES ================= */
@@ -365,18 +366,6 @@ const menuItems = [
permission: 'system:update'
},
{
label: 'Loglar',
to: '/app/activity-logs',
permission: 'system:read'
},
{
label: 'Test Mail',
to: '/app/test-mail',
permission: 'system:update'
},
{
label: 'Piyasa Mail Eşleştirme',
to: '/app/market-mail-mapping',
@@ -385,6 +374,27 @@ const menuItems = [
]
},
{
label: 'SüperAdmin',
icon: 'admin_panel_settings',
onlyUserIds: activityLogsMenuItem.onlyUserIds,
children: [
{
label: 'Log İzleme',
to: activityLogsMenuItem.to,
permission: activityLogsMenuItem.permission,
onlyUserIds: activityLogsMenuItem.onlyUserIds
},
{
label: 'Test Mail',
to: '/app/test-mail',
permission: 'system:update',
onlyUserIds: activityLogsMenuItem.onlyUserIds
}
]
},
{
label: 'Dil Çeviri',
icon: 'translate',
@@ -416,6 +426,16 @@ const menuItems = [
/* ================= FILTERED MENU ================= */
function isAllowedForUser (item) {
const only = item?.onlyUserIds
if (!Array.isArray(only) || only.length === 0) return true
const id = getAuthUserId(auth.user)
if (id == null) return false
return only.includes(id)
}
const filteredMenu = computed(() => {
if (!perm.loaded) return []
@@ -424,9 +444,10 @@ const filteredMenu = computed(() => {
.map(item => {
if (item.children) {
if (!isAllowedForUser(item)) return null
const children = item.children.filter(c =>
perm.hasApiPermission(c.permission)
isAllowedForUser(c) && perm.hasApiPermission(c.permission)
)
if (!children.length) return null
@@ -437,6 +458,10 @@ const filteredMenu = computed(() => {
}
}
if (!isAllowedForUser(item)) {
return null
}
if (!perm.hasApiPermission(item.permission)) {
return null
}

View File

@@ -1,5 +1,5 @@
<template>
<q-page v-if="canReadUser" class="act-page with-bg">
<q-page v-if="isAllowed" class="act-page with-bg">
<!-- =======================================================
🔍 FILTER BAR
@@ -218,14 +218,14 @@
<script setup>
import { ref,onMounted, watch } from 'vue'
import { ref, computed, onMounted, watch } from 'vue'
import { date } from 'quasar'
import { useActivityLogStore } from 'src/stores/activityLogStore'
import { useAuthStore } from 'stores/authStore.js'
import { usePermission } from 'src/composables/usePermission'
import { isActivityLogsAllowedUser } from 'src/modules/activityLogs'
const { canRead, canUpdate } = usePermission()
const canReadUser = canRead('user')
const { canUpdate } = usePermission()
const canUpdateUser = canUpdate('user')
const diffDialog = ref(false)
@@ -236,6 +236,7 @@ const selectedDiff = ref({
})
const store = useActivityLogStore()
const auth = useAuthStore()
const isAllowed = computed(() => isActivityLogsAllowedUser(auth.user))
const categoryOptions = [
{ label: 'Auth', value: 'auth' },

View File

@@ -1,27 +1,30 @@
<template>
<q-page v-if="canReadOrder" class="pcmm-page q-pa-md">
<div class="pcmm-header row items-center q-col-gutter-md">
<div class="col">
<div class="text-h6">Maliyet Parca Eslestirme</div>
<div class="text-caption text-grey-7">
V3 Urun Ilk Grubu (42. ozellik) + Urun Ana/Alt Grup + URETIM Parca Bolum + Hammadde Turleri eslestirmesi (URETIM mk_ tablolarinda tutulur)
<div class="pcmm-top">
<div class="pcmm-header row items-center q-col-gutter-md">
<div class="col">
<div class="text-h6">Maliyet Parca Eslestirme</div>
<div class="text-caption text-grey-7">
V3 Urun Ilk Grubu (42. ozellik) + Urun Ana/Alt Grup + URETIM Parca Bolum + Hammadde Turleri eslestirmesi (URETIM mk_ tablolarinda tutulur)
</div>
</div>
<div class="col-auto">
<q-btn
color="primary"
icon="refresh"
label="Yenile"
:loading="loading"
@click="refreshAll"
/>
</div>
</div>
<div class="col-auto">
<q-btn
color="primary"
icon="refresh"
label="Yenile"
:loading="loading"
@click="refreshAll"
/>
</div>
<q-separator class="q-my-md" />
</div>
<q-separator class="q-my-md" />
<q-table
<div class="pcmm-table-wrap">
<q-table
class="ol-table pcmm-table"
flat
bordered
@@ -34,6 +37,7 @@
no-data-label="Kayit bulunamadi"
:rows-per-page-options="[0]"
hide-bottom
sticky-header
>
<template #header-cell="props">
<q-th :props="props">
@@ -279,7 +283,8 @@
</q-select>
</q-td>
</template>
</q-table>
</q-table>
</div>
</q-page>
<q-page v-else class="q-pa-md flex flex-center">
@@ -862,6 +867,11 @@ onMounted(async () => {
<style scoped>
.pcmm-page {
background: #fafafa;
/* Prevent page scroll; table body will scroll inside .pcmm-table-wrap */
height: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
}
.pcmm-header {
@@ -869,6 +879,16 @@ onMounted(async () => {
margin: 0 auto;
}
.pcmm-top {
flex: 0 0 auto;
}
.pcmm-table-wrap {
flex: 1 1 auto;
min-height: 0; /* important for flex overflow scrolling */
overflow: auto;
}
.pcmm-form {
max-width: 1200px;
margin: 0 auto;
@@ -905,6 +925,14 @@ onMounted(async () => {
line-height: 1.15;
}
/* Keep q-table top controls visible while scrolling (like sticky headers). */
.pcmm-table :deep(.q-table__top) {
position: sticky;
top: 0;
z-index: 3;
background: #fafafa;
}
.pcmm-header-cell {
display: flex;
align-items: flex-start;

View File

@@ -5,6 +5,7 @@ import routes from 'src/router/routes.js'
import { useAuthStore } from 'stores/authStore'
import { usePermissionStore } from 'stores/permissionStore'
import { getAuthUserId } from 'src/modules/activityLogs'
export default route(function () {
@@ -54,6 +55,16 @@ export default route(function () {
return next('/first-password-change')
}
/* ================= USER ID RESTRICTIONS ================= */
const onlyUserIds = to.meta?.onlyUserIds
if (Array.isArray(onlyUserIds) && onlyUserIds.length > 0) {
const id = getAuthUserId(auth.user)
if (id == null || !onlyUserIds.includes(id)) {
return next('/unauthorized')
}
}
/* ================= ADMIN ================= */

View File

@@ -1,3 +1,5 @@
import { activityLogsRoute } from 'src/modules/activityLogs'
// src/router/routes.js
const routes = [
@@ -53,6 +55,21 @@ const routes = [
]
},
/* ==========================================================
🚫 UNAUTHORIZED
========================================================== */
{
path: '/unauthorized',
component: () => import('layouts/EmptyLayout.vue'),
children: [
{
path: '',
name: 'unauthorized',
component: () => import('pages/Unauthorized.vue')
}
]
},
/* ==========================================================
🏠 MAIN APP
@@ -110,6 +127,10 @@ const routes = [
meta: { permission: 'system:update' }
},
/* ================= ACTIVITY LOGS ================= */
activityLogsRoute,
/* ================= FINANCE ================= */
@@ -203,23 +224,13 @@ const routes = [
},
/* ================= LOGS ================= */
{
path: 'activity-logs',
name: 'activity-logs',
component: () => import('pages/ActivityLogs.vue'),
meta: { permission: 'system:read' }
},
/* ================= TEST MAIL ================= */
{
path: 'test-mail',
name: 'test-mail',
component: () => import('pages/TestMail.vue'),
meta: { permission: 'system:update' }
meta: { permission: 'system:update', onlyUserIds: [5] }
},
{