v0.3测试
This commit is contained in:
@@ -9,19 +9,12 @@
|
|||||||
* 版权所有 © Sea Network Technology Studio
|
* 版权所有 © 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() {
|
function getToken() {
|
||||||
return localStorage.getItem(JWT_STORAGE_KEY);
|
return localStorage.getItem(window.JWT_STORAGE_KEY || 'class_system_token');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取用户信息
|
|
||||||
function getUserInfo() {
|
function getUserInfo() {
|
||||||
const userStr = localStorage.getItem(USER_STORAGE_KEY);
|
const userStr = localStorage.getItem(window.USER_STORAGE_KEY || 'class_system_user');
|
||||||
if (!userStr) return null;
|
if (!userStr) return null;
|
||||||
try {
|
try {
|
||||||
return JSON.parse(userStr);
|
return JSON.parse(userStr);
|
||||||
@@ -30,28 +23,15 @@ function getUserInfo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存用户信息
|
|
||||||
function setUserInfo(user) {
|
function setUserInfo(user) {
|
||||||
localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(user));
|
localStorage.setItem(window.USER_STORAGE_KEY || 'class_system_user', JSON.stringify(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清除登录信息
|
|
||||||
function clearAuth() {
|
function clearAuth() {
|
||||||
localStorage.removeItem(JWT_STORAGE_KEY);
|
localStorage.removeItem(window.JWT_STORAGE_KEY || 'class_system_token');
|
||||||
localStorage.removeItem(USER_STORAGE_KEY);
|
localStorage.removeItem(window.USER_STORAGE_KEY || 'class_system_user');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查登录状态
|
|
||||||
function checkAuth() {
|
|
||||||
const token = getToken();
|
|
||||||
if (!token) {
|
|
||||||
window.location.href = '/index.php';
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// API请求封装
|
|
||||||
async function apiRequest(url, options = {}) {
|
async function apiRequest(url, options = {}) {
|
||||||
const token = getToken();
|
const token = getToken();
|
||||||
const headers = {
|
const headers = {
|
||||||
@@ -62,16 +42,11 @@ async function apiRequest(url, options = {}) {
|
|||||||
headers['Authorization'] = `Bearer ${token}`;
|
headers['Authorization'] = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保 url 以 /api/ 开头
|
const baseUrl = window.API_BASE_URL;
|
||||||
const fullUrl = url.startsWith('/api/') ? url : `/api${url}`;
|
const fullUrl = `${baseUrl}${url}`;
|
||||||
|
|
||||||
const config = {
|
|
||||||
...options,
|
|
||||||
headers
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(fullUrl, config);
|
const response = await fetch(fullUrl, { ...options, headers });
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
@@ -87,60 +62,50 @@ async function apiRequest(url, options = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET请求
|
function apiGet(url, params = {}) {
|
||||||
async function apiGet(url, params = {}) {
|
|
||||||
const queryString = new URLSearchParams(params).toString();
|
const queryString = new URLSearchParams(params).toString();
|
||||||
const fullUrl = queryString ? `${url}?${queryString}` : url;
|
const fullUrl = queryString ? `${url}?${queryString}` : url;
|
||||||
return apiRequest(fullUrl, { method: 'GET' });
|
return apiRequest(fullUrl, { method: 'GET' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST请求
|
function apiPost(url, data = {}) {
|
||||||
async function apiPost(url, data = {}) {
|
|
||||||
return apiRequest(url, {
|
return apiRequest(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT请求
|
function apiPut(url, data = {}) {
|
||||||
async function apiPut(url, data = {}) {
|
|
||||||
return apiRequest(url, {
|
return apiRequest(url, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE请求
|
function apiDelete(url) {
|
||||||
async function apiDelete(url) {
|
|
||||||
return apiRequest(url, { method: 'DELETE' });
|
return apiRequest(url, { method: 'DELETE' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示提示消息
|
|
||||||
function showToast(message, type = 'success') {
|
function showToast(message, type = 'success') {
|
||||||
const toast = document.createElement('div');
|
const toast = document.createElement('div');
|
||||||
toast.className = `toast toast-${type}`;
|
toast.className = `toast toast-${type}`;
|
||||||
toast.textContent = message;
|
toast.textContent = message;
|
||||||
document.body.appendChild(toast);
|
document.body.appendChild(toast);
|
||||||
setTimeout(() => {
|
setTimeout(() => toast.remove(), 3000);
|
||||||
toast.remove();
|
|
||||||
}, 3000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 格式化日期
|
|
||||||
function formatDate(dateStr) {
|
function formatDate(dateStr) {
|
||||||
if (!dateStr) return '-';
|
if (!dateStr) return '-';
|
||||||
const date = new Date(dateStr);
|
const date = new Date(dateStr);
|
||||||
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 格式化日期时间
|
|
||||||
function formatDateTime(dateStr) {
|
function formatDateTime(dateStr) {
|
||||||
if (!dateStr) return '-';
|
if (!dateStr) return '-';
|
||||||
const date = new Date(dateStr);
|
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')}`;
|
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') {
|
function getStatusBadge(status, type = 'homework') {
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
homework: {
|
homework: {
|
||||||
@@ -179,49 +144,12 @@ function getStatusBadge(status, type = 'homework') {
|
|||||||
return `<span class="${className}">${text}</span>`;
|
return `<span class="${className}">${text}</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 退出登录
|
|
||||||
async function logout() {
|
async function logout() {
|
||||||
await apiPost('/api/auth/logout');
|
await apiPost('/api/auth/logout');
|
||||||
clearAuth();
|
clearAuth();
|
||||||
window.location.href = '/index.php';
|
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) {
|
function escapeHtml(str) {
|
||||||
if (!str) return '';
|
if (!str) return '';
|
||||||
return str.replace(/[&<>]/g, function(m) {
|
return str.replace(/[&<>]/g, function(m) {
|
||||||
@@ -232,14 +160,14 @@ function escapeHtml(str) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 页面加载时初始化
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
loadUserInfo();
|
const user = getUserInfo();
|
||||||
|
const userNameSpan = document.getElementById('userName');
|
||||||
|
if (userNameSpan && user) {
|
||||||
|
userNameSpan.textContent = user.real_name || user.username;
|
||||||
|
}
|
||||||
const logoutBtn = document.getElementById('logoutBtn');
|
const logoutBtn = document.getElementById('logoutBtn');
|
||||||
if (logoutBtn) {
|
if (logoutBtn) {
|
||||||
logoutBtn.addEventListener('click', logout);
|
logoutBtn.addEventListener('click', logout);
|
||||||
}
|
}
|
||||||
if (window.location.pathname.includes('/student/') || window.location.pathname.includes('/parent/')) {
|
|
||||||
checkNeedChangePassword();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
@@ -52,7 +52,7 @@ if (!empty($missingKeys)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 定义常量
|
// 定义常量
|
||||||
define('API_BASE_URL', '');
|
define('API_BASE_URL', $config['API_BASE_URL']);
|
||||||
define('API_TIMEOUT', (int)$config['API_TIMEOUT']);
|
define('API_TIMEOUT', (int)$config['API_TIMEOUT']);
|
||||||
define('JWT_STORAGE_KEY', $config['JWT_STORAGE_KEY']);
|
define('JWT_STORAGE_KEY', $config['JWT_STORAGE_KEY']);
|
||||||
define('USER_STORAGE_KEY', $config['USER_STORAGE_KEY']);
|
define('USER_STORAGE_KEY', $config['USER_STORAGE_KEY']);
|
||||||
|
|||||||
@@ -12,15 +12,13 @@
|
|||||||
|
|
||||||
require_once __DIR__ . '/config.php';
|
require_once __DIR__ . '/config.php';
|
||||||
|
|
||||||
// 如果已登录,跳转到对应页面
|
|
||||||
if (isset($_SESSION['user_id']) && isset($_SESSION['user_type'])) {
|
if (isset($_SESSION['user_id']) && isset($_SESSION['user_type'])) {
|
||||||
$redirect = [
|
$redirect = [
|
||||||
'student' => '/student/dashboard.php',
|
'student' => '/student/dashboard.php',
|
||||||
'parent' => '/parent/dashboard.php',
|
'parent' => '/parent/dashboard.php',
|
||||||
'admin' => '/admin/dashboard.php'
|
'admin' => '/admin/dashboard.php'
|
||||||
];
|
];
|
||||||
$target = $redirect[$_SESSION['user_type']] ?? '/index.php';
|
header("Location: " . ($redirect[$_SESSION['user_type']] ?? '/index.php'));
|
||||||
header("Location: $target");
|
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -42,7 +40,7 @@ if (isset($_SESSION['user_id']) && isset($_SESSION['user_type'])) {
|
|||||||
<form id="loginForm" class="login-form">
|
<form id="loginForm" class="login-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>用户名</label>
|
<label>用户名</label>
|
||||||
<input type="text" id="username" name="username" required autocomplete="off" placeholder="请输入用户名">
|
<input type="text" id="username" name="username" required autocomplete="off" placeholder="学号/手机号/管理员账号">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>密码</label>
|
<label>密码</label>
|
||||||
@@ -84,11 +82,8 @@ if (isset($_SESSION['user_id']) && isset($_SESSION['user_type'])) {
|
|||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
if (data.success && data.data) {
|
if (data.success && data.data) {
|
||||||
// 存储Token和用户信息
|
|
||||||
localStorage.setItem(JWT_STORAGE_KEY, data.data.token);
|
localStorage.setItem(JWT_STORAGE_KEY, data.data.token);
|
||||||
localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(data.data));
|
localStorage.setItem(USER_STORAGE_KEY, JSON.stringify(data.data));
|
||||||
|
|
||||||
// 跳转
|
|
||||||
window.location.href = data.data.redirect;
|
window.location.href = data.data.redirect;
|
||||||
} else {
|
} else {
|
||||||
showError(data.message || '登录失败');
|
showError(data.message || '登录失败');
|
||||||
|
|||||||
29
nginx.ini
29
nginx.ini
@@ -1,29 +0,0 @@
|
|||||||
# 前端站点配置
|
|
||||||
server {
|
|
||||||
listen 443 ssl http2;
|
|
||||||
server_name class.sea-studio.top;
|
|
||||||
root /www/wwwroot/ClassManager/frontend;
|
|
||||||
index index.php;
|
|
||||||
|
|
||||||
# 反向代理 /api/ 到后端
|
|
||||||
location /api/ {
|
|
||||||
proxy_pass https://classbackendapi.sea-studio.top/api/;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
proxy_pass_request_headers on;
|
|
||||||
}
|
|
||||||
|
|
||||||
# PHP 处理
|
|
||||||
location ~ \.php$ {
|
|
||||||
fastcgi_pass unix:/tmp/php-cgi-80.sock;
|
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
|
||||||
include fastcgi_params;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 静态资源缓存
|
|
||||||
location ~* \.(css|js|jpg|png|gif|ico)$ {
|
|
||||||
expires 30d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user