core v1
This commit is contained in:
@@ -28,6 +28,7 @@ export interface StudentItem {
|
||||
location?: string;
|
||||
systemId?: number;
|
||||
systemName?: string;
|
||||
avatar?: string;
|
||||
}
|
||||
|
||||
export interface StatsResponse {
|
||||
@@ -54,6 +55,55 @@ export interface SyncStatus {
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
export interface ClassScheduleItem {
|
||||
id?: number;
|
||||
classRkId?: number;
|
||||
dayOfWeek: number;
|
||||
period: number;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
courseId: number;
|
||||
courseName: string;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
export interface ClassCourseItem {
|
||||
id: number;
|
||||
name: string;
|
||||
courseCode?: string;
|
||||
}
|
||||
|
||||
export interface AttendanceRow {
|
||||
studentRkId: number;
|
||||
studentCode: string;
|
||||
fullName: string;
|
||||
email: string;
|
||||
status: number;
|
||||
statusLabel: string;
|
||||
onlineMinutes: number;
|
||||
statusEditedByTeacher: boolean;
|
||||
}
|
||||
|
||||
export const ATTENDANCE_STATUS_OPTIONS = [
|
||||
{ value: 0, label: 'Nghỉ không phép' },
|
||||
{ value: 1, label: 'Nghỉ có phép' },
|
||||
{ value: 2, label: 'Nghỉ nửa buổi' },
|
||||
{ value: 3, label: 'Đi học muộn' },
|
||||
{ value: 4, label: 'Đi học đầy đủ' },
|
||||
];
|
||||
|
||||
export interface StudentSessionLogItem {
|
||||
id: number;
|
||||
studentRkId: number;
|
||||
studentCode: string;
|
||||
fullName: string;
|
||||
email: string;
|
||||
onlineSeconds: number;
|
||||
offlineSeconds: number;
|
||||
wifiSsids: string;
|
||||
lastActiveAt?: string;
|
||||
}
|
||||
|
||||
export const api = {
|
||||
getStats: async (): Promise<StatsResponse> => {
|
||||
const res = await fetch(`${API_BASE}/stats`);
|
||||
@@ -87,7 +137,10 @@ export const api = {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ isStudying }),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to update class studying status');
|
||||
if (!res.ok) {
|
||||
const errData = await res.json().catch(() => ({}));
|
||||
throw new Error(errData.error || 'Failed to update class studying status');
|
||||
}
|
||||
return res.json();
|
||||
},
|
||||
|
||||
@@ -143,3 +196,199 @@ export const api = {
|
||||
return res.json();
|
||||
},
|
||||
};
|
||||
|
||||
// Export individual learning functions to simplify imports in components
|
||||
export const apiFetchActiveSchedules = async (): Promise<{ data: any[] }> => {
|
||||
const res = await fetch(`${API_BASE}/classes/schedules`);
|
||||
if (!res.ok) throw new Error('Failed to fetch active schedules');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiFetchClassSchedule = async (rkId: number): Promise<{ data: ClassScheduleItem[] }> => {
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/schedule`);
|
||||
if (!res.ok) throw new Error('Failed to fetch class schedule');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiSaveClassSchedule = async (rkId: number, schedules: ClassScheduleItem[]): Promise<any> => {
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/schedule`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ schedules }),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to save class schedule');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiDeleteClassSchedule = async (rkId: number): Promise<any> => {
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/schedule`, { method: 'DELETE' });
|
||||
if (!res.ok) throw new Error('Failed to delete class schedule');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiFetchAllowedApps = async (rkId: number): Promise<{ classRkId: number; keywords: string }> => {
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/allowed-apps`);
|
||||
if (!res.ok) throw new Error('Failed to fetch allowed apps keywords');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiSaveAllowedApps = async (rkId: number, keywords: string): Promise<any> => {
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/allowed-apps`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ keywords }),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to save allowed apps keywords');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export interface AppPoolItem {
|
||||
id: number;
|
||||
processName: string;
|
||||
windowTitle: string;
|
||||
keyword: string;
|
||||
hitCount: number;
|
||||
lastSeenAt: string;
|
||||
lastStudentRkId?: number;
|
||||
lastClassRkId?: number;
|
||||
}
|
||||
|
||||
export const apiFetchAppPool = async (q = '', limit = 50): Promise<{ data: AppPoolItem[]; q?: string; limit?: number }> => {
|
||||
const params = new URLSearchParams();
|
||||
if (q.trim()) params.set('q', q.trim());
|
||||
params.set('limit', String(limit));
|
||||
const query = params.toString() ? `?${params.toString()}` : '';
|
||||
const res = await fetch(`${API_BASE}/app-pool${query}`);
|
||||
if (!res.ok) throw new Error('Failed to fetch app pool');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export interface WifiPoolItem {
|
||||
id: number;
|
||||
ssid: string;
|
||||
bssid: string;
|
||||
hitCount: number;
|
||||
lastSeenAt: string;
|
||||
lastStudentRkId?: number;
|
||||
}
|
||||
|
||||
export interface AcceptedWifiItem {
|
||||
id: number;
|
||||
ssid: string;
|
||||
bssid: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export type WifiAcceptItem = { ssid: string; bssid: string };
|
||||
|
||||
export const apiFetchWifiPool = async (q = '', limit = 50): Promise<{ data: WifiPoolItem[] }> => {
|
||||
const params = new URLSearchParams();
|
||||
if (q.trim()) params.set('q', q.trim());
|
||||
params.set('limit', String(limit));
|
||||
const query = params.toString() ? `?${params.toString()}` : '';
|
||||
const res = await fetch(`${API_BASE}/wifi-pool${query}`);
|
||||
if (!res.ok) throw new Error('Failed to fetch wifi pool');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiFetchAcceptedWifis = async (): Promise<{ data: AcceptedWifiItem[] }> => {
|
||||
const res = await fetch(`${API_BASE}/network/accepted-wifis`);
|
||||
if (!res.ok) throw new Error('Failed to fetch accepted wifis');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiSaveAcceptedWifis = async (items: WifiAcceptItem[]): Promise<any> => {
|
||||
const res = await fetch(`${API_BASE}/network/accepted-wifis`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ items }),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to save accepted wifis');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiFetchClassStudents = api.getClassStudents;
|
||||
export const apiFetchClasses = api.getClasses;
|
||||
|
||||
export const apiFetchClassSessionLogs = async (
|
||||
rkId: number,
|
||||
date?: string,
|
||||
period?: number
|
||||
): Promise<{ data: StudentSessionLogItem[]; period?: number; date?: string }> => {
|
||||
const params = new URLSearchParams();
|
||||
if (date) params.set('date', date);
|
||||
if (period) params.set('period', String(period));
|
||||
const query = params.toString() ? `?${params.toString()}` : '';
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/session-logs${query}`);
|
||||
if (!res.ok) throw new Error('Failed to fetch class session logs');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiFetchOnlineStudents = async (rkId: number): Promise<{ onlineStudentIds: number[] }> => {
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/online-students`);
|
||||
if (!res.ok) throw new Error('Failed to fetch online students list');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiFetchClassCourses = async (rkId: number): Promise<{
|
||||
data: ClassCourseItem[];
|
||||
source?: string;
|
||||
cached?: boolean;
|
||||
warning?: string;
|
||||
hint?: string;
|
||||
}> => {
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/courses`);
|
||||
const body = await res.json().catch(() => ({}));
|
||||
if (!res.ok) {
|
||||
throw new Error(body.error || body.hint || 'Không tải được danh sách môn học từ QLĐT');
|
||||
}
|
||||
return body;
|
||||
};
|
||||
|
||||
export const apiApplyScheduleTemplate = async (rkId: number): Promise<{ created: number; skipped: number }> => {
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/schedule/apply-template`, { method: 'POST' });
|
||||
if (!res.ok) throw new Error('Failed to apply schedule template');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiFetchAttendanceShifts = async (rkId: number, date?: string) => {
|
||||
const q = date ? `?date=${date}` : '';
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/attendance/shifts${q}`);
|
||||
if (!res.ok) throw new Error('Failed to fetch attendance shifts');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiFetchAttendance = async (rkId: number, date: string, period: number) => {
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/attendance?date=${date}&period=${period}`);
|
||||
if (!res.ok) throw new Error('Failed to fetch attendance');
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiUpdateAttendanceStatus = async (
|
||||
rkId: number,
|
||||
payload: { date: string; period: number; studentRkId: number; status: number }
|
||||
) => {
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/attendance/status`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({}));
|
||||
throw new Error(err.error || 'Failed to update attendance status');
|
||||
}
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const apiPushAttendanceQLDT = async (rkId: number, date: string, period: number) => {
|
||||
const res = await fetch(`${API_BASE}/classes/${rkId}/attendance/push-qldt`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ date, period }),
|
||||
});
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({}));
|
||||
throw new Error(err.error || 'Failed to push attendance to QLĐT');
|
||||
}
|
||||
return res.json();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user