feat: Implement initial frontend for admin and instructor roles, including dashboards, course management, authentication, and core services.

This commit is contained in:
Missez 2026-02-06 14:58:41 +07:00
parent 832a8f5067
commit 127b63de49
16 changed files with 1505 additions and 102 deletions

View file

@ -214,6 +214,46 @@ export interface UpdateCategoryRequest {
};
}
// Audit Logs Interfaces
export interface AuditLog {
id: number;
user_id: number;
action: string;
entity_type: string;
entity_id: number;
old_value: string | null;
new_value: string | null;
ip_address: string | null;
user_agent: string | null;
metadata: string | null;
created_at: string;
user: {
email: string;
username: string;
id: number;
} | null;
}
export interface AuditLogsListResponse {
data: AuditLog[];
pagination: {
totalPages: number;
total: number;
limit: number;
page: number;
};
}
export interface AuditLogStats {
totalLogs: number;
todayLogs: number;
actionSummary: {
action: string;
count: number;
}[];
recentActivity: AuditLog[];
}
// Helper function to get auth token from cookie
const getAuthToken = (): string => {
const tokenCookie = useCookie('token');
@ -391,6 +431,92 @@ export const adminService = {
}
});
return response;
},
// ============ Audit Logs ============
async getAuditLogs(
page: number = 1,
limit: number = 20,
filters: {
userId?: number;
action?: string;
entityType?: string;
entityId?: number;
startDate?: string;
endDate?: string;
} = {}
): Promise<AuditLogsListResponse> {
const config = useRuntimeConfig();
const token = getAuthToken();
let query: any = { page, limit };
if (filters.userId) query.userId = filters.userId;
if (filters.action) query.action = filters.action;
if (filters.entityType) query.entityType = filters.entityType;
if (filters.entityId) query.entityId = filters.entityId;
if (filters.startDate) query.startDate = filters.startDate;
if (filters.endDate) query.endDate = filters.endDate;
const response = await $fetch<AuditLogsListResponse>('/api/admin/audit-logs', {
baseURL: config.public.apiBaseUrl as string,
headers: { Authorization: `Bearer ${token}` },
query
});
return response;
},
async getAuditLogById(id: number): Promise<AuditLog> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<AuditLog>(`/api/admin/audit-logs/${id}`, {
baseURL: config.public.apiBaseUrl as string,
headers: { Authorization: `Bearer ${token}` }
});
return response;
},
async getAuditLogStats(): Promise<AuditLogStats> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<AuditLogStats>('/api/admin/audit-logs/stats/summary', {
baseURL: config.public.apiBaseUrl as string,
headers: { Authorization: `Bearer ${token}` }
});
return response;
},
async getAuditLogsByEntity(entityType: string, entityId: number): Promise<AuditLog[]> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<AuditLog[]>(`/api/admin/audit-logs/entity/${entityType}/${entityId}`, {
baseURL: config.public.apiBaseUrl as string,
headers: { Authorization: `Bearer ${token}` }
});
return response;
},
async getAuditLogsByUser(userId: number, limit: number = 20): Promise<AuditLog[]> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<AuditLog[]>(`/api/admin/audit-logs/user/${userId}/activity`, {
baseURL: config.public.apiBaseUrl as string,
headers: { Authorization: `Bearer ${token}` },
query: { limit }
});
return response;
},
async cleanupAuditLogs(days: number = 90): Promise<ApiResponse<void>> {
const config = useRuntimeConfig();
const token = getAuthToken();
const response = await $fetch<ApiResponse<void>>('/api/admin/audit-logs/cleanup', {
method: 'DELETE',
baseURL: config.public.apiBaseUrl as string,
headers: { Authorization: `Bearer ${token}` },
query: { days }
});
return response;
}
};

View file

@ -253,7 +253,7 @@ export const instructorService = {
async submitCourseForApproval(courseId: number): Promise<ApiResponse<void>> {
return await authRequest<ApiResponse<void>>(
`/api/instructors/courses/${courseId}/submit`,
`/api/instructors/courses/send-review/${courseId}`,
{ method: 'POST' }
);
},