From e87d78c295398167ee9cd84ac781cde5a75e5c0b Mon Sep 17 00:00:00 2001 From: Kavehhn174 Date: Sun, 16 Aug 2026 08:42:26 +0330 Subject: [PATCH] feat: add admin UI for reviewing pending student registrations. Let staff list, inspect, approve, or reject enrollment and class-request submissions before final enrollment. --- src/api/pendingStudentApi.js | 8 + src/components/common/StatusTag.vue | 16 ++ src/components/layout/AppSidebar.vue | 3 +- src/constants/permissions.js | 14 +- src/router/routes.js | 14 ++ .../PendingStudentDetailView.vue | 193 ++++++++++++++++++ .../PendingStudentListView.vue | 159 +++++++++++++++ 7 files changed, 405 insertions(+), 2 deletions(-) create mode 100644 src/api/pendingStudentApi.js create mode 100644 src/views/pendingStudents/PendingStudentDetailView.vue create mode 100644 src/views/pendingStudents/PendingStudentListView.vue diff --git a/src/api/pendingStudentApi.js b/src/api/pendingStudentApi.js new file mode 100644 index 0000000..6b4a420 --- /dev/null +++ b/src/api/pendingStudentApi.js @@ -0,0 +1,8 @@ +import axiosInstance from './axiosInstance'; + +export const pendingStudentApi = { + getAll: (params) => axiosInstance.get('/pending-students/admin/get-all', { params }), + getOne: (id) => axiosInstance.get(`/pending-students/admin/get-one/${id}`), + approve: (id, data = {}) => axiosInstance.post(`/pending-students/admin/${id}/approve`, data), + reject: (id, data = {}) => axiosInstance.post(`/pending-students/admin/${id}/reject`, data) +}; diff --git a/src/components/common/StatusTag.vue b/src/components/common/StatusTag.vue index 2a6ebb4..bc54dfa 100644 --- a/src/components/common/StatusTag.vue +++ b/src/components/common/StatusTag.vue @@ -49,6 +49,14 @@ const PAYMENT_LABELS = { overdue: 'معوق' }; +const PENDING_STUDENT_LABELS = { + pending_payment: 'در انتظار پرداخت', + pending_review: 'در انتظار بررسی', + approved: 'تأییدشده', + rejected: 'ردشده', + cancelled: 'لغوشده' +}; + const severity = computed(() => { const val = String(props.status).toLowerCase(); @@ -79,6 +87,13 @@ const severity = computed(() => { if (val === 'failed' || val === 'ناموفق') return 'danger'; } + if (props.type === 'pendingStudent') { + if (val === 'pending_review') return 'warning'; + if (val === 'pending_payment') return 'info'; + if (val === 'approved') return 'success'; + if (val === 'rejected' || val === 'cancelled') return 'danger'; + } + if (val === 'true' || val === 'active' || val === 'فعال') return 'success'; if (val === 'false' || val === 'inactive' || val === 'غیرفعال') return 'danger'; @@ -93,6 +108,7 @@ const label = computed(() => { if (props.type === 'contact') return CONTACT_LABELS[val] || raw; if (props.type === 'notification') return NOTIFICATION_LABELS[val] || raw; if (props.type === 'payment') return PAYMENT_LABELS[val] || raw; + if (props.type === 'pendingStudent') return PENDING_STUDENT_LABELS[val] || raw; if (val === 'true' || val === 'active') return 'فعال'; if (val === 'false' || val === 'inactive') return 'غیرفعال'; diff --git a/src/components/layout/AppSidebar.vue b/src/components/layout/AppSidebar.vue index 061488c..a331f3a 100644 --- a/src/components/layout/AppSidebar.vue +++ b/src/components/layout/AppSidebar.vue @@ -61,7 +61,8 @@ const menuGroups = computed(() => { items: [ { label: 'امور مالی و پرداخت‌ها', icon: 'pi pi-wallet', to: '/payments' }, { label: 'اطلاعیه‌ها', icon: 'pi pi-bell', to: '/notifications' }, - { label: 'درخواست‌های تماس', icon: 'pi pi-comments', to: '/contact-inquiries' } + { label: 'درخواست‌های تماس', icon: 'pi pi-comments', to: '/contact-inquiries' }, + { label: 'ثبت‌نام‌های در انتظار', icon: 'pi pi-user-plus', to: '/pending-students', permission: PERMISSIONS.PENDING_STUDENTS_READ } ] }, { diff --git a/src/constants/permissions.js b/src/constants/permissions.js index d581b0d..fc9967f 100644 --- a/src/constants/permissions.js +++ b/src/constants/permissions.js @@ -74,7 +74,10 @@ export const PERMISSIONS = { LOGS_SEARCH: 'logs:search', CONTACT_INQUIRIES_READ: 'contact_inquiries:read', - CONTACT_INQUIRIES_UPDATE: 'contact_inquiries:update' + CONTACT_INQUIRIES_UPDATE: 'contact_inquiries:update', + + PENDING_STUDENTS_READ: 'pending_students:read', + PENDING_STUDENTS_UPDATE: 'pending_students:update' }; export const PERMISSION_GROUPS = [ @@ -229,6 +232,15 @@ export const PERMISSION_GROUPS = [ { key: PERMISSIONS.CONTACT_INQUIRIES_READ, label: 'مشاهده درخواست‌ها' }, { key: PERMISSIONS.CONTACT_INQUIRIES_UPDATE, label: 'ویرایش / پیگیری درخواست‌ها' } ] + }, + { + key: 'pending_students', + label: 'ثبت‌نام‌های در انتظار', + icon: 'pi pi-user-plus', + permissions: [ + { key: PERMISSIONS.PENDING_STUDENTS_READ, label: 'مشاهده ثبت‌نام‌های در انتظار' }, + { key: PERMISSIONS.PENDING_STUDENTS_UPDATE, label: 'تأیید / رد ثبت‌نام' } + ] } ]; diff --git a/src/router/routes.js b/src/router/routes.js index 750856b..b2ad4f3 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -198,6 +198,20 @@ export const routes = [ component: () => import('@/views/contactInquiries/ContactInquiryDetailView.vue') }, + // Pending student registrations + { + path: 'pending-students', + name: 'PendingStudentList', + component: () => import('@/views/pendingStudents/PendingStudentListView.vue'), + meta: { permission: 'pending_students:read' } + }, + { + path: 'pending-students/view/:id', + name: 'PendingStudentDetail', + component: () => import('@/views/pendingStudents/PendingStudentDetailView.vue'), + meta: { permission: 'pending_students:read' } + }, + { path: 'logs', name: 'LogList', diff --git a/src/views/pendingStudents/PendingStudentDetailView.vue b/src/views/pendingStudents/PendingStudentDetailView.vue new file mode 100644 index 0000000..ead41a4 --- /dev/null +++ b/src/views/pendingStudents/PendingStudentDetailView.vue @@ -0,0 +1,193 @@ + +