用户系统

This commit is contained in:
2025-10-04 11:51:08 +08:00
parent 657365f9de
commit 5575370621
11 changed files with 4043 additions and 96 deletions

440
templates/register.html Normal file
View File

@@ -0,0 +1,440 @@
{% extends "base.html" %}
{% block title %}注册新用户{% endblock %}
{% block content %}
<div class="register-container">
<div class="register-card">
<div class="register-header">
<h1>注册新用户</h1>
<p>创建新的系统用户账户</p>
</div>
<form method="POST" class="register-form">
<div class="form-group">
<label for="username">
<i class="fas fa-user"></i>
用户名
</label>
<input type="text"
id="username"
name="username"
required
minlength="3"
maxlength="20"
placeholder="请输入用户名3-20个字符">
<small class="form-text">用户名长度为3-20个字符只能包含字母、数字和下划线</small>
</div>
<div class="form-group">
<label for="password">
<i class="fas fa-lock"></i>
密码
</label>
<input type="password"
id="password"
name="password"
required
minlength="6"
placeholder="请输入密码至少6位">
<small class="form-text">密码长度至少6位建议包含字母和数字</small>
</div>
<div class="form-group">
<label for="confirm_password">
<i class="fas fa-lock"></i>
确认密码
</label>
<input type="password"
id="confirm_password"
name="confirm_password"
required
minlength="6"
placeholder="请再次输入密码">
<small class="form-text">请再次输入相同的密码进行确认</small>
</div>
<div class="form-group">
<label for="permission">
<i class="fas fa-user-cog"></i>
权限级别
</label>
<select id="permission" name="permission" required>
<option value="">请选择权限级别</option>
<option value="1">普通用户 - 可以录入和查询数据</option>
<option value="0">管理员 - 拥有所有权限</option>
</select>
<small class="form-text">
<strong>普通用户:</strong>可以上传图片、录入数据、查询数据<br>
<strong>管理员:</strong>拥有所有权限,包括用户管理和数据管理
</small>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">
<i class="fas fa-user-plus"></i>
创建用户
</button>
<a href="{{ url_for('user_management') }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i>
返回用户管理
</a>
</div>
</form>
</div>
</div>
<style>
.register-container {
display: flex;
justify-content: center;
align-items: center;
min-height: calc(100vh - 200px);
padding: 20px;
}
.register-card {
background: white;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
padding: 40px;
width: 100%;
max-width: 500px;
}
.register-header {
text-align: center;
margin-bottom: 30px;
}
.register-header h1 {
color: #333;
margin-bottom: 10px;
font-size: 28px;
}
.register-header p {
color: #666;
font-size: 16px;
margin: 0;
}
.register-form {
width: 100%;
}
.form-group {
margin-bottom: 25px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #333;
font-size: 14px;
}
.form-group label i {
margin-right: 8px;
color: #007bff;
width: 16px;
}
.form-group input,
.form-group select {
width: 100%;
padding: 12px 16px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 14px;
transition: all 0.3s ease;
box-sizing: border-box;
}
.form-group input:focus,
.form-group select:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0,123,255,0.1);
}
.form-group input:invalid {
border-color: #dc3545;
}
.form-group input:valid {
border-color: #28a745;
}
.form-text {
display: block;
margin-top: 5px;
font-size: 12px;
color: #666;
line-height: 1.4;
}
.form-actions {
display: flex;
gap: 15px;
margin-top: 30px;
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
cursor: pointer;
text-decoration: none;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: 600;
transition: all 0.3s ease;
flex: 1;
}
.btn i {
margin-right: 8px;
}
.btn-primary {
background-color: #007bff;
color: white;
}
.btn-primary:hover {
background-color: #0056b3;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,123,255,0.3);
}
.btn-secondary {
background-color: #6c757d;
color: white;
}
.btn-secondary:hover {
background-color: #545b62;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(108,117,125,0.3);
}
/* 响应式设计 */
@media (max-width: 768px) {
.register-container {
padding: 10px;
}
.register-card {
padding: 30px 20px;
}
.form-actions {
flex-direction: column;
}
.btn {
width: 100%;
}
}
/* 密码强度指示器 */
.password-strength {
margin-top: 5px;
height: 4px;
background-color: #e0e0e0;
border-radius: 2px;
overflow: hidden;
}
.password-strength-bar {
height: 100%;
width: 0%;
transition: all 0.3s ease;
}
.strength-weak {
background-color: #dc3545;
width: 33%;
}
.strength-medium {
background-color: #ffc107;
width: 66%;
}
.strength-strong {
background-color: #28a745;
width: 100%;
}
/* 表单验证样式 */
.form-group.error input,
.form-group.error select {
border-color: #dc3545;
box-shadow: 0 0 0 3px rgba(220,53,69,0.1);
}
.form-group.success input,
.form-group.success select {
border-color: #28a745;
box-shadow: 0 0 0 3px rgba(40,167,69,0.1);
}
.error-message {
color: #dc3545;
font-size: 12px;
margin-top: 5px;
display: none;
}
.success-message {
color: #28a745;
font-size: 12px;
margin-top: 5px;
display: none;
}
</style>
<script>
// 表单验证
document.addEventListener('DOMContentLoaded', function() {
const form = document.querySelector('.register-form');
const username = document.getElementById('username');
const password = document.getElementById('password');
const confirmPassword = document.getElementById('confirm_password');
const permission = document.getElementById('permission');
// 用户名验证
username.addEventListener('input', function() {
const value = this.value;
const formGroup = this.closest('.form-group');
if (value.length < 3) {
setFieldError(formGroup, '用户名至少需要3个字符');
} else if (value.length > 20) {
setFieldError(formGroup, '用户名不能超过20个字符');
} else if (!/^[a-zA-Z0-9_]+$/.test(value)) {
setFieldError(formGroup, '用户名只能包含字母、数字和下划线');
} else {
setFieldSuccess(formGroup, '用户名格式正确');
}
});
// 密码验证
password.addEventListener('input', function() {
const value = this.value;
const formGroup = this.closest('.form-group');
if (value.length < 6) {
setFieldError(formGroup, '密码至少需要6个字符');
} else {
setFieldSuccess(formGroup, '密码长度符合要求');
}
// 检查确认密码
if (confirmPassword.value) {
validateConfirmPassword();
}
});
// 确认密码验证
confirmPassword.addEventListener('input', validateConfirmPassword);
function validateConfirmPassword() {
const formGroup = confirmPassword.closest('.form-group');
if (confirmPassword.value !== password.value) {
setFieldError(formGroup, '两次输入的密码不一致');
} else if (confirmPassword.value.length >= 6) {
setFieldSuccess(formGroup, '密码确认正确');
}
}
// 权限选择验证
permission.addEventListener('change', function() {
const formGroup = this.closest('.form-group');
if (this.value === '') {
setFieldError(formGroup, '请选择权限级别');
} else {
setFieldSuccess(formGroup, '权限级别已选择');
}
});
// 表单提交验证
form.addEventListener('submit', function(e) {
let isValid = true;
// 验证用户名
if (username.value.length < 3 || username.value.length > 20 || !/^[a-zA-Z0-9_]+$/.test(username.value)) {
isValid = false;
setFieldError(username.closest('.form-group'), '用户名格式不正确');
}
// 验证密码
if (password.value.length < 6) {
isValid = false;
setFieldError(password.closest('.form-group'), '密码长度至少6位');
}
// 验证确认密码
if (password.value !== confirmPassword.value) {
isValid = false;
setFieldError(confirmPassword.closest('.form-group'), '两次输入的密码不一致');
}
// 验证权限选择
if (permission.value === '') {
isValid = false;
setFieldError(permission.closest('.form-group'), '请选择权限级别');
}
if (!isValid) {
e.preventDefault();
}
});
function setFieldError(formGroup, message) {
formGroup.classList.remove('success');
formGroup.classList.add('error');
let errorMsg = formGroup.querySelector('.error-message');
if (!errorMsg) {
errorMsg = document.createElement('div');
errorMsg.className = 'error-message';
formGroup.appendChild(errorMsg);
}
errorMsg.textContent = message;
errorMsg.style.display = 'block';
const successMsg = formGroup.querySelector('.success-message');
if (successMsg) {
successMsg.style.display = 'none';
}
}
function setFieldSuccess(formGroup, message) {
formGroup.classList.remove('error');
formGroup.classList.add('success');
let successMsg = formGroup.querySelector('.success-message');
if (!successMsg) {
successMsg = document.createElement('div');
successMsg.className = 'success-message';
formGroup.appendChild(successMsg);
}
successMsg.textContent = message;
successMsg.style.display = 'block';
const errorMsg = formGroup.querySelector('.error-message');
if (errorMsg) {
errorMsg.style.display = 'none';
}
}
});
</script>
{% endblock %}