更新用户管理,现在能通过班导师,管理员,学生进入对应的页面进行密码修改

This commit is contained in:
2025-11-18 15:20:30 +08:00
parent 68bc4b54f5
commit 5a9d98282a
6 changed files with 156 additions and 51 deletions

Binary file not shown.

View File

@@ -730,7 +730,10 @@ def get_all_users():
users.append({ users.append({
"user_id": hit.user_id, "user_id": hit.user_id,
"username": hit.username, "username": hit.username,
"permission": int(hit.permission) "permission": int(hit.permission),
"email": getattr(hit, 'email', None),
"key": list(getattr(hit, 'key', []) or []),
"manage_key": list(getattr(hit, 'manage_key', []) or []),
}) })
return users return users
@@ -749,6 +752,9 @@ def get_user_by_id(user_id):
"user_id": hit.user_id, "user_id": hit.user_id,
"username": hit.username, "username": hit.username,
"permission": int(hit.permission), "permission": int(hit.permission),
"email": getattr(hit, 'email', None),
"key": list(getattr(hit, 'key', []) or []),
"manage_key": list(getattr(hit, 'manage_key', []) or []),
} }
return None return None
except Exception as e: except Exception as e:

View File

@@ -1,5 +1,5 @@
INDEX_NAME = "wordsearch2666661" INDEX_NAME = "wordsearch21"
USER_NAME = "users11111666789" USER_NAME = "users16"
ACHIEVEMENT_INDEX_NAME = INDEX_NAME ACHIEVEMENT_INDEX_NAME = INDEX_NAME
USER_INDEX_NAME = USER_NAME USER_INDEX_NAME = USER_NAME
GLOBAL_INDEX_NAME = "global11111111" GLOBAL_INDEX_NAME = "global11121"

View File

@@ -216,20 +216,49 @@
</div> </div>
</div> </div>
<!-- 主内容区域 -->
<div class="main-content"> <div class="main-content">
{% if is_student %}
<div class="card">
<div class="header"><h2>修改密码</h2></div>
<form id="selfPwdForm">
<input type="hidden" id="selfUserId" name="user_id" value="{{ user_id }}">
<div class="form-group">
<label for="password">新密码</label>
<input type="password" id="password" name="password" required>
</div>
<div class="form-group">
<label for="confirmPassword">确认密码</label>
<input type="password" id="confirmPassword" name="confirmPassword" required>
</div>
<button type="submit" class="btn btn-primary">保存</button>
</form>
</div>
{% else %}
{% if is_tutor %}
<div class="card">
<div class="header"><h2>修改本人密码</h2></div>
<form id="selfPwdForm">
<input type="hidden" id="selfUserId" name="user_id" value="{{ user_id }}">
<div class="form-group">
<label for="password">新密码</label>
<input type="password" id="password" name="password" required>
</div>
<div class="form-group">
<label for="confirmPassword">确认密码</label>
<input type="password" id="confirmPassword" name="confirmPassword" required>
</div>
<button type="submit" class="btn btn-primary">保存</button>
</form>
</div>
{% endif %}
<div class="card"> <div class="card">
<div class="header"> <div class="header">
<h2>用户管理</h2> <h2>用户管理</h2>
<button id="addUserBtn" class="btn btn-primary">添加用户</button> {% if is_admin %}<button id="addUserBtn" class="btn btn-primary">添加用户</button>{% endif %}
</div> </div>
<div class="notification success" id="successNotification"> <div class="notification success" id="successNotification">操作成功!</div>
操作成功! <div class="notification error" id="errorNotification">操作失败!</div>
</div>
<div class="notification error" id="errorNotification">
操作失败!
</div>
<div class="search-container"> <div class="search-container">
<input type="text" id="searchInput" placeholder="搜索用户名..."> <input type="text" id="searchInput" placeholder="搜索用户名...">
@@ -247,12 +276,11 @@
<th>操作</th> <th>操作</th>
</tr> </tr>
</thead> </thead>
<tbody id="usersTableBody"> <tbody id="usersTableBody"></tbody>
<!-- 用户数据将通过JavaScript加载 -->
</tbody>
</table> </table>
</div> </div>
</div> </div>
{% endif %}
</div> </div>
<!-- 添加/编辑用户模态框 --> <!-- 添加/编辑用户模态框 -->
@@ -511,7 +539,10 @@
} }
// 事件监听器 // 事件监听器
document.getElementById('addUserBtn').addEventListener('click', openAddModal); const addBtn = document.getElementById('addUserBtn');
if (addBtn) {
addBtn.addEventListener('click', openAddModal);
}
document.getElementById('userForm').addEventListener('submit', saveUser); document.getElementById('userForm').addEventListener('submit', saveUser);
@@ -523,15 +554,21 @@
}); });
}); });
document.getElementById('searchBtn').addEventListener('click', function() { const searchBtn = document.getElementById('searchBtn');
const searchTerm = document.getElementById('searchInput').value; if (searchBtn) {
loadUsers(searchTerm); searchBtn.addEventListener('click', function() {
}); const searchTerm = document.getElementById('searchInput').value;
loadUsers(searchTerm);
});
}
document.getElementById('resetBtn').addEventListener('click', function() { const resetBtn = document.getElementById('resetBtn');
document.getElementById('searchInput').value = ''; if (resetBtn) {
loadUsers(); resetBtn.addEventListener('click', function() {
}); document.getElementById('searchInput').value = '';
loadUsers();
});
}
// 点击模态框外部关闭模态框 // 点击模态框外部关闭模态框
window.addEventListener('click', function(event) { window.addEventListener('click', function(event) {
@@ -572,7 +609,34 @@
// 页面加载时获取用户列表 // 页面加载时获取用户列表
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
loadUsers(); const selfForm = document.getElementById('selfPwdForm');
if (selfForm) {
selfForm.addEventListener('submit', async (e) => {
e.preventDefault();
const uid = document.getElementById('selfUserId').value;
const pwd = document.getElementById('password').value;
const cpwd = document.getElementById('confirmPassword').value;
if (pwd !== cpwd) { showNotification('密码和确认密码不匹配', false); return; }
if ((pwd || '').length < 6) { showNotification('密码长度至少为6位', false); return; }
try {
const csrftoken = getCookie('csrftoken');
const resp = await fetch(`/elastic/users/${uid}/update/`, {
method: 'POST', credentials: 'same-origin',
headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrftoken || '' },
body: JSON.stringify({ password: pwd })
});
const result = await resp.json();
if (resp.ok && result.status === 'success') { showNotification('修改成功'); }
else { showNotification(result.message || '操作失败', false); }
} catch (error) {
showNotification('保存失败', false);
}
});
}
const tbody = document.getElementById('usersTableBody');
if (tbody) {
loadUsers();
}
}); });
// 为表格中的编辑和删除按钮添加事件监听器 // 为表格中的编辑和删除按钮添加事件监听器

View File

@@ -222,16 +222,27 @@ def add_user(request):
@require_http_methods(["GET"]) @require_http_methods(["GET"])
def get_users(request): def get_users(request):
if request.session.get("user_id") is None: uid = request.session.get("user_id")
if uid is None:
return JsonResponse({"status": "error", "message": "未登录"}, status=401) return JsonResponse({"status": "error", "message": "未登录"}, status=401)
if int(request.session.get("permission", 1)) != 0:
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
try: try:
is_admin = int(request.session.get("permission", 1)) == 0
requester = get_user_by_id(uid) or {}
mgr_keys = set(requester.get("manage_key") or [])
q = (request.GET.get("search") or "").strip() q = (request.GET.get("search") or "").strip()
users = get_all_users() users = get_all_users()
if is_admin:
filtered = users
elif mgr_keys:
def match_manage(user):
ukeys = set(user.get("key") or [])
return bool(ukeys & mgr_keys)
filtered = [u for u in users if match_manage(u)]
else:
filtered = [u for u in users if str(u.get("user_id")) == str(uid)]
if q: if q:
users = [u for u in users if q in str(u.get("username", ""))] filtered = [u for u in filtered if q in str(u.get("username", ""))]
return JsonResponse({"status": "success", "data": users}) return JsonResponse({"status": "success", "data": filtered})
except Exception as e: except Exception as e:
return JsonResponse({"status": "error", "message": str(e)}, status=500) return JsonResponse({"status": "error", "message": str(e)}, status=500)
@@ -239,10 +250,9 @@ def get_users(request):
@require_http_methods(["POST"]) @require_http_methods(["POST"])
@csrf_protect @csrf_protect
def update_user_by_id_view(request, user_id): def update_user_by_id_view(request, user_id):
if request.session.get("user_id") is None: uid = request.session.get("user_id")
if uid is None:
return JsonResponse({"status": "error", "message": "未登录"}, status=401) return JsonResponse({"status": "error", "message": "未登录"}, status=401)
if int(request.session.get("permission", 1)) != 0:
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
try: try:
payload = json.loads(request.body.decode("utf-8")) payload = json.loads(request.body.decode("utf-8"))
except Exception: except Exception:
@@ -250,21 +260,41 @@ def update_user_by_id_view(request, user_id):
new_username = (payload.get("username") or "").strip() new_username = (payload.get("username") or "").strip()
new_permission = payload.get("permission") new_permission = payload.get("permission")
new_password = (payload.get("password") or "").strip() new_password = (payload.get("password") or "").strip()
if new_username:
other = get_user_by_username(new_username)
if other and int(other.get("user_id", -1)) != int(user_id):
return JsonResponse({"status": "error", "message": "用户名已存在"}, status=409)
if new_password and len(new_password) < 6: if new_password and len(new_password) < 6:
return JsonResponse({"status": "error", "message": "密码长度至少为6位"}, status=400) return JsonResponse({"status": "error", "message": "密码长度至少为6位"}, status=400)
ok = es_update_user_by_id(
user_id, is_admin = int(request.session.get("permission", 1)) == 0
username=new_username if new_username else None, requester = get_user_by_id(uid) or {}
permission=int(new_permission) if new_permission is not None else None, target = get_user_by_id(user_id) or {}
password=new_password if new_password else None, requester_mgr = set(requester.get("manage_key") or [])
) target_keys = set(target.get("key") or [])
if not ok:
return JsonResponse({"status": "error", "message": "用户更新失败"}, status=500) if is_admin:
return JsonResponse({"status": "success", "message": "用户更新成功"}) if new_username:
other = get_user_by_username(new_username)
if other and int(other.get("user_id", -1)) != int(user_id):
return JsonResponse({"status": "error", "message": "用户名已存在"}, status=409)
ok = es_update_user_by_id(
user_id,
username=new_username if new_username else None,
permission=int(new_permission) if new_permission is not None else None,
password=new_password if new_password else None,
)
return JsonResponse({"status": "success"}) if ok else JsonResponse({"status": "error", "message": "用户更新失败"}, status=500)
if str(uid) == str(user_id):
if not new_password:
return JsonResponse({"status": "error", "message": "仅允许修改密码"}, status=400)
ok = es_update_user_by_id(user_id, password=new_password)
return JsonResponse({"status": "success"}) if ok else JsonResponse({"status": "error", "message": "用户更新失败"}, status=500)
if requester_mgr and (target_keys & requester_mgr):
if not new_password or new_username or new_permission is not None:
return JsonResponse({"status": "error", "message": "导师仅允许修改密码"}, status=403)
ok = es_update_user_by_id(user_id, password=new_password)
return JsonResponse({"status": "success"}) if ok else JsonResponse({"status": "error", "message": "用户更新失败"}, status=500)
return JsonResponse({"status": "error", "message": "无权限"}, status=403)
@require_http_methods(["POST"]) @require_http_methods(["POST"])
@csrf_protect @csrf_protect
@@ -598,11 +628,16 @@ def user_manage(request):
if session_user_id is None: if session_user_id is None:
from django.shortcuts import redirect from django.shortcuts import redirect
return redirect("/accounts/login/") return redirect("/accounts/login/")
if int(request.session.get("permission", 1)) != 0: is_admin = int(request.session.get("permission", 1)) == 0
from django.shortcuts import redirect me = get_user_by_id(session_user_id) or {}
return redirect("/main/home/") has_manage = bool(me.get("manage_key"))
user_id_qs = request.GET.get("user_id") user_id_qs = request.GET.get("user_id")
context = {"user_id": user_id_qs or session_user_id} context = {
"user_id": user_id_qs or session_user_id,
"is_admin": is_admin,
"is_tutor": (not is_admin) and has_manage,
"is_student": (not is_admin) and (not has_manage),
}
return render(request, "elastic/users.html", context) return render(request, "elastic/users.html", context)
@require_http_methods(["GET"]) @require_http_methods(["GET"])

View File

@@ -42,8 +42,8 @@
<a href="{% url 'main:home' %}" onclick="return handleNavClick(this, '/');">主页</a> <a href="{% url 'main:home' %}" onclick="return handleNavClick(this, '/');">主页</a>
<a href="{% url 'elastic:upload_page' %}" onclick="return handleNavClick(this, '/elastic/upload/');">图片上传与识别</a> <a href="{% url 'elastic:upload_page' %}" onclick="return handleNavClick(this, '/elastic/upload/');">图片上传与识别</a>
<a href="{% url 'elastic:manage_page' %}" onclick="return handleNavClick(this, '/elastic/manage/');">数据管理</a> <a href="{% url 'elastic:manage_page' %}" onclick="return handleNavClick(this, '/elastic/manage/');">数据管理</a>
{% if is_admin %}
<a href="{% url 'elastic:user_manage' %}" onclick="return handleNavClick(this, '/elastic/user_manage/');">用户管理</a> <a href="{% url 'elastic:user_manage' %}" onclick="return handleNavClick(this, '/elastic/user_manage/');">用户管理</a>
{% if is_admin %}
<a href="{% url 'elastic:registration_code_manage_page' %}" onclick="return handleNavClick(this, '/elastic/registration-codes/manage/');">注册码管理</a> <a href="{% url 'elastic:registration_code_manage_page' %}" onclick="return handleNavClick(this, '/elastic/registration-codes/manage/');">注册码管理</a>
{% endif %} {% endif %}
<a id="logoutBtn">退出登录</a> <a id="logoutBtn">退出登录</a>