Files
SharedClassManager/frontend/assets/js/common.js
2026-04-10 14:18:07 +08:00

245 lines
6.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 班级操行分管理系统 - 公共JS
*
* 开发者: Canglan
* 联系方式: admin@sea-studio.top
* 版权归属: Sea Network Technology Studio
* 许可证: MIT License
*
* 版权所有 © Sea Network Technology Studio
*/
// API 使用相对路径,由 Nginx 反向代理 /api/ 到后端
const API_BASE_URL = '';
const JWT_STORAGE_KEY = 'class_system_token';
const USER_STORAGE_KEY = 'class_system_user';
// 获取Token
function getToken() {
return localStorage.getItem(JWT_STORAGE_KEY);
}
// 获取用户信息
function getUserInfo() {
const userStr = localStorage.getItem(USER_STORAGE_KEY);
if (!userStr) return null;
try {
return JSON.parse(userStr);
} catch {
return null;
}
}
// 保存用户信息
function setUserInfo(user) {
localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(user));
}
// 清除登录信息
function clearAuth() {
localStorage.removeItem(JWT_STORAGE_KEY);
localStorage.removeItem(USER_STORAGE_KEY);
}
// 检查登录状态
function checkAuth() {
const token = getToken();
if (!token) {
window.location.href = '/index.php';
return false;
}
return true;
}
// API请求封装
async function apiRequest(url, options = {}) {
const token = getToken();
const headers = {
'Content-Type': 'application/json',
...options.headers
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
// 确保 url 以 /api/ 开头
const fullUrl = url.startsWith('/api/') ? url : `/api${url}`;
const config = {
...options,
headers
};
try {
const response = await fetch(fullUrl, config);
const data = await response.json();
if (response.status === 401) {
clearAuth();
window.location.href = '/index.php';
return null;
}
return data;
} catch (error) {
console.error('API请求错误:', error);
showToast('网络错误,请稍后重试', 'error');
return null;
}
}
// GET请求
async function apiGet(url, params = {}) {
const queryString = new URLSearchParams(params).toString();
const fullUrl = queryString ? `${url}?${queryString}` : url;
return apiRequest(fullUrl, { method: 'GET' });
}
// POST请求
async function apiPost(url, data = {}) {
return apiRequest(url, {
method: 'POST',
body: JSON.stringify(data)
});
}
// PUT请求
async function apiPut(url, data = {}) {
return apiRequest(url, {
method: 'PUT',
body: JSON.stringify(data)
});
}
// DELETE请求
async function apiDelete(url) {
return apiRequest(url, { method: 'DELETE' });
}
// 显示提示消息
function showToast(message, type = 'success') {
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => {
toast.remove();
}, 3000);
}
// 格式化日期
function formatDate(dateStr) {
if (!dateStr) return '-';
const date = new Date(dateStr);
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
}
// 格式化日期时间
function formatDateTime(dateStr) {
if (!dateStr) return '-';
const date = new Date(dateStr);
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
}
// 获取状态标签HTML
function getStatusBadge(status, type = 'homework') {
const statusMap = {
homework: {
'submitted': '已提交',
'not_submitted': '未提交',
'late': '迟交'
},
attendance: {
'present': '出勤',
'absent': '缺勤',
'late': '迟到',
'leave': '请假'
}
};
const texts = statusMap[type] || statusMap.homework;
const text = texts[status] || status;
let className = 'status-badge ';
switch (status) {
case 'submitted':
case 'present':
className += 'status-submitted';
break;
case 'not_submitted':
case 'absent':
className += 'status-not_submitted';
break;
case 'late':
className += 'status-late';
break;
case 'leave':
className += 'status-leave';
break;
default:
className += 'status-not_submitted';
}
return `<span class="${className}">${text}</span>`;
}
// 退出登录
async function logout() {
await apiPost('/api/auth/logout');
clearAuth();
window.location.href = '/index.php';
}
// 加载用户信息
function loadUserInfo() {
const user = getUserInfo();
const userNameSpan = document.getElementById('userName');
if (userNameSpan && user) {
userNameSpan.textContent = user.real_name || user.username;
}
}
// 检查是否需要修改密码
function checkNeedChangePassword() {
const user = getUserInfo();
if (user && user.need_change_password) {
const newPassword = prompt('首次登录请设置新密码6-20位需包含字母和数字');
if (newPassword) {
changePassword(newPassword);
}
}
}
// 修改密码
async function changePassword(newPassword) {
const res = await apiPost('/api/auth/change-password', {
old_password: newPassword,
new_password: newPassword
});
if (res && res.success) {
showToast('密码修改成功,请重新登录');
setTimeout(() => logout(), 1500);
} else {
showToast(res?.message || '密码修改失败', 'error');
checkNeedChangePassword();
}
}
// HTML转义
function escapeHtml(str) {
if (!str) return '';
return str.replace(/[&<>]/g, function(m) {
if (m === '&') return '&amp;';
if (m === '<') return '&lt;';
if (m === '>') return '&gt;';
return m;
});
}
// 页面加载时初始化
document.addEventListener('DOMContentLoaded', () => {
loadUserInfo();
const logoutBtn = document.getElementById('logoutBtn');
if (logoutBtn) {
logoutBtn.addEventListener('click', logout);
}
if (window.location.pathname.includes('/student/') || window.location.pathname.includes('/parent/')) {
checkNeedChangePassword();
}
});