This commit is contained in:
2025-09-22 07:33:37 +08:00
parent b34e97b93b
commit 0cae9749a8
19 changed files with 2557 additions and 1225 deletions
BIN
View File
Binary file not shown.
+487
View File
@@ -0,0 +1,487 @@
/* 自定义样式 */
body {
background-color: #f2f2f2;
font-family: "Microsoft YaHei", sans-serif;
margin: 0;
padding: 0;
padding-top: 60px; /* 为固定的顶部导航栏留出空间 */
min-height: 100vh;
display: flex;
flex-direction: column;
}
.footer {
background-color: #ffffff;
padding: 16px 0;
border-top: 1px solid #e0e0e0;
color: #666666;
font-size: 14px;
margin-top: 20px;
text-align: center;
}
/* 参数配置页面样式 */
.content-container {
flex: 1;
padding: 20px 0;
}
.content-wrapper {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.back-button-container {
margin-bottom: 24px;
display: flex;
justify-content: flex-end;
}
.back-button {
display: inline-flex;
align-items: center;
color: #009688;
text-decoration: none;
transition: color 0.3s ease;
}
.back-button:hover {
color: #007d6e;
}
.form-card {
max-width: 500px;
margin: 0 auto;
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
padding: 32px;
}
.form-header {
text-align: center;
margin-bottom: 24px;
}
.icon-container {
width: 64px;
height: 64px;
background-color: #e6f7f5;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 16px auto;
}
.form-title {
font-size: 24px;
font-weight: bold;
color: #333333;
margin: 0 0 8px 0;
}
.form-subtitle {
font-size: 14px;
color: #666666;
margin: 0;
}
/* 消息提示样式 */
.error-message,
.success-message,
.info-message {
margin-bottom: 16px;
padding: 12px 16px;
border-radius: 4px;
display: flex;
align-items: flex-start;
}
.error-message {
background-color: #fff1f0;
border: 1px solid #ffccc7;
color: #cf1322;
}
.success-message {
background-color: #f6ffed;
border: 1px solid #b7eb8f;
color: #389e0d;
}
.info-message {
background-color: #e6f7ff;
border: 1px solid #91d5ff;
color: #0958d9;
display: flex;
align-items: center;
}
/* 表单样式 */
.form-content {
space-y: 16px;
}
.form-group {
margin-bottom: 16px;
}
.form-label {
display: block;
font-size: 14px;
font-weight: 500;
color: #333333;
margin-bottom: 8px;
}
.required-mark {
color: #ff4d4f;
}
.form-input {
width: 100%;
height: 40px;
padding: 0 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 14px;
transition: all 0.3s ease;
}
/* 自定义下拉选择器样式,确保下拉箭头显示 */
.custom-select {
height: 38px !important;
padding: 0 10px !important;
padding-right: 30px !important;
border: 1px solid #e6e6e6 !important;
border-radius: 2px !important;
background-color: #fff !important;
font-size: 14px !important;
appearance: none !important;
-webkit-appearance: none !important;
-moz-appearance: none !important;
position: relative !important;
}
/* 使用绝对定位的div作为下拉箭头容器 */
.custom-select-wrapper {
position: relative !important;
display: inline-block !important;
}
/* 为部门选择器设置特定宽度 */
#filterDepartment {
width: 150px !important;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath fill='%23666' d='M5 6L0 1h10z'/%3E%3C/svg%3E") !important;
background-repeat: no-repeat !important;
background-position: right 10px center !important;
background-size: 10px 6px !important;
}
/* 为状态选择器设置特定宽度 */
#filterStatus {
width: 120px !important;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath fill='%23666' d='M5 6L0 1h10z'/%3E%3C/svg%3E") !important;
background-repeat: no-repeat !important;
background-position: right 10px center !important;
background-size: 10px 6px !important;
}
.form-input:focus {
border-color: #009688;
box-shadow: 0 0 0 2px rgba(0, 150, 136, 0.2);
outline: none;
}
.form-actions {
display: flex;
justify-content: space-between;
margin-top: 24px;
gap: 12px;
}
.btn-primary,
.btn-secondary {
flex: 1;
height: 40px;
padding: 0 16px;
border: none;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.btn-primary {
background-color: #009688;
color: #ffffff;
}
.btn-primary:hover {
background-color: #007d6e;
}
.btn-secondary {
background-color: #ffffff;
border: 1px solid #d9d9d9;
color: #666666;
}
.btn-secondary:hover {
border-color: #009688;
color: #009688;
}
/* 顶部导航栏样式 */
.header-navbar {
background-color: #ffffff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
height: 60px;
display: flex;
align-items: center;
}
.header-container {
max-width: 1200px;
margin: 0 auto;
width: 100%;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.header-logo {
display: flex;
align-items: center;
}
.header-icon {
font-size: 24px;
color: #009688;
margin-right: 10px;
}
.header-title {
font-size: 20px;
font-weight: bold;
color: #333333;
margin: 0;
}
.header-user {
display: flex;
align-items: center;
}
/* 用户下拉菜单样式 */
.user-dropdown-container {
position: relative;
}
.user-dropdown-toggle {
display: flex;
align-items: center;
cursor: pointer;
color: #666666;
transition: color 0.3s ease;
}
.user-dropdown-toggle:hover {
color: #009688;
}
.user-welcome {
color: #666666;
}
.dropdown-icon {
margin-left: 8px;
font-size: 12px;
transition: transform 0.3s ease;
}
.dropdown-icon.rotate {
transform: rotate(180deg);
}
.user-dropdown {
position: absolute;
right: 0;
top: 100%;
margin-top: 8px;
width: 192px;
background-color: #ffffff;
border-radius: 4px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
z-index: 2000;
}
.user-dropdown.show {
opacity: 1;
visibility: visible;
}
.dropdown-content {
padding: 4px 0;
}
.dropdown-item {
display: block;
padding: 8px 16px;
font-size: 14px;
color: #333333;
text-decoration: none;
transition: background-color 0.3s ease, color 0.3s ease;
}
.dropdown-item:hover {
background-color: #009688;
color: #ffffff;
}
.dropdown-icon-item {
margin-right: 8px;
}
.dropdown-divider {
height: 1px;
background-color: #e0e0e0;
margin: 4px 0;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.card {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 20px;
margin-bottom: 20px;
}
.header {
background-color: #009688;
color: #fff;
padding: 15px 0;
margin-bottom: 20px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.header h1 {
margin: 0;
font-size: 24px;
text-align: center;
}
/* 主样式中的footer定义已包含所有必要样式 */
/* 登录和注册页面样式 */
.login-container, .register-container {
max-width: 400px;
margin: 50px auto;
}
.login-title, .register-title {
text-align: center;
margin-bottom: 20px;
color: #009688;
}
/* 表单样式优化 */
.layui-form-item {
margin-bottom: 20px;
}
.layui-input {
height: 40px;
line-height: 40px;
border-radius: 4px;
}
.layui-btn {
height: 40px;
line-height: 40px;
border-radius: 4px;
}
.layui-btn-primary {
border-color: #009688;
color: #009688;
}
.layui-btn-primary:hover {
border-color: #009688;
color: #fff;
background-color: #009688;
}
/* 表格样式优化 */
.layui-table {
border-radius: 4px;
overflow: hidden;
}
.layui-table th {
background-color: #f8f8f8;
font-weight: bold;
}
/* 导航菜单样式 */
.nav-menu {
background-color: #393D49;
border-radius: 4px;
overflow: hidden;
margin-bottom: 20px;
}
.nav-menu .layui-nav-item {
line-height: 50px;
}
.nav-menu .layui-nav-item a {
color: #fff;
padding: 0 20px;
}
.nav-menu .layui-nav-item.layui-this a {
background-color: #009688;
}
/* 查询表单样式 */
.search-form {
padding: 20px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
/* 响应式调整 */
@media screen and (max-width: 768px) {
.container {
padding: 10px;
}
.login-container, .register-container {
margin: 20px auto;
}
}
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
File diff suppressed because one or more lines are too long
+178 -149
View File
@@ -4,175 +4,204 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>修改密码 - 车主信息查询系统</title> <title>修改密码 - 车主信息查询系统</title>
<!-- Tailwind CSS --> <!-- 引入Layui CSS -->
<script src="https://cdn.tailwindcss.com"></script> <link rel="stylesheet" href="{{ url_for('static', filename='css/layui.css') }}">
<!-- Font Awesome --> <!-- 引入Font Awesome -->
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
<!-- 配置Tailwind自定义颜色和字体 --> <!-- 引入自定义CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/custom.css') }}">
<!-- 引入Layui JS -->
<script src="{{ url_for('static', filename='layui.js') }}"></script>
<script> <script>
tailwind.config = { layui.use(['layer', 'form', 'element'], function(){
theme: { var layer = layui.layer;
extend: { var form = layui.form;
colors: { var element = layui.element;
primary: '#2563eb', });
secondary: '#f3f4f6',
'primary-light': '#dbeafe',
'primary-dark': '#1d4ed8',
'table-header': '#f9fafb',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script> </script>
<!-- 自定义工具类 -->
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.card-shadow {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
}
.input-focus {
@apply focus:border-primary focus:ring-2 focus:ring-primary/20 focus:outline-none;
}
.animate-fade-in {
animation: fadeIn 0.3s ease-out forwards;
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head> </head>
<body class="bg-secondary min-h-screen font-sans"> <body>
<!-- 引入统一的顶部导航栏 -->
{% include 'header.html' %} {% include 'header.html' %}
<!-- 主要内容区域 --> <!-- 主要内容区域 -->
<main class="container mx-auto px-4 pt-24 pb-12"> <div class="content-container">
<!-- 返回按钮 --> <div class="content-wrapper">
<div class="mb-6 flex justify-end"> <div class="card">
<a href="{{ url_for('query') }}" class="inline-flex items-center text-primary hover:text-primary-dark transition-colors"> <div class="card-header">
<i class="fa fa-arrow-left mr-2"></i> 返回主页面 <i class="fa fa-key"></i> 修改密码
</a> <a href="{{ url_for('query') }}" class="layui-btn layui-btn-xs layui-btn-primary" style="float: right;">
</div> <i class="fa fa-arrow-left"></i> 返回主页面
</a>
<!-- 修改密码表单 --> </div>
<div class="max-w-md mx-auto bg-white rounded-lg shadow-xl p-8 animate-fade-in"> <div class="card-body">
<div class="text-center mb-6"> <!-- 消息提示区域 -->
<div class="w-16 h-16 bg-primary-light rounded-full flex items-center justify-center mx-auto mb-4"> {% if error %}
<i class="fa fa-key text-primary text-2xl"></i> <div class="layui-bg-red message-box">
<i class="fa fa-exclamation-circle"></i> {{ error }}
</div>
{% endif %}
{% if success %}
<div class="layui-bg-green message-box">
<i class="fa fa-check-circle"></i> {{ success }}
</div>
{% endif %}
<div class="layui-text" style="text-align: center; margin-bottom: 20px;">
<div style="width: 80px; height: 80px; background-color: #f2f2f2; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 15px;">
<i class="fa fa-key" style="font-size: 40px; color: #009688;"></i>
</div>
<p style="color: #666;">请填写以下信息以修改您的密码</p>
</div>
<!-- 表单 - 使用Layui样式 -->
<form class="layui-form" id="changePasswordForm" action="/change_password_page" method="POST" style="max-width: 500px; margin: 0 auto;">
<div class="layui-form-item">
<label class="layui-form-label">旧密码</label>
<div class="layui-input-block">
<input type="password" id="old_password" name="old_password" class="layui-input" placeholder="请输入旧密码" required>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">新密码</label>
<div class="layui-input-block">
<input type="password" id="new_password" name="new_password" class="layui-input" placeholder="请输入新密码" required>
</div>
<div class="layui-form-mid layui-word-aux">密码长度至少8位,包含字母和数字</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">确认新密码</label>
<div class="layui-input-block">
<input type="password" id="confirm_password" name="confirm_password" class="layui-input" placeholder="请再次输入新密码" required>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="submit" class="layui-btn" lay-submit>
<i class="fa fa-save mr-1"></i> 确认修改
</button>
<button type="button" onclick="window.location.href='{{ url_for('query') }}'" class="layui-btn layui-btn-primary">
<i class="fa fa-times mr-1"></i> 取消
</button>
</div>
</div>
</form>
</div> </div>
<h2 class="text-2xl font-bold text-gray-800">修改密码</h2>
<p class="text-gray-500 mt-2">请填写以下信息以修改您的密码</p>
</div> </div>
<!-- 错误信息显示区域 -->
{% if error %}
<div class="mb-4 bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-md flex items-start animate-fade-in">
<i class="fa fa-exclamation-circle mt-1 mr-3"></i>
<span>{{ error }}</span>
</div>
{% endif %}
<!-- 表单 -->
<form id="changePasswordForm" method="POST" class="space-y-4">
<div class="mb-4">
<label for="old_password" class="block text-gray-700 text-sm font-medium mb-2">旧密码</label>
<div class="relative">
<input type="password" id="old_password" name="old_password" class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-colors" placeholder="请输入旧密码" required>
<button type="button" class="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-500 hover:text-gray-700 transition-colors" onclick="togglePasswordVisibility('old_password', this)">
<i class="fa fa-eye"></i>
</button>
</div>
</div>
<div class="mb-4">
<label for="new_password" class="block text-gray-700 text-sm font-medium mb-2">新密码</label>
<div class="relative">
<input type="password" id="new_password" name="new_password" class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-colors" placeholder="请输入新密码" required>
<button type="button" class="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-500 hover:text-gray-700 transition-colors" onclick="togglePasswordVisibility('new_password', this)">
<i class="fa fa-eye"></i>
</button>
</div>
<p class="text-xs text-gray-500 mt-1">密码长度至少8位,包含字母和数字</p>
</div>
<div class="mb-6">
<label for="confirm_password" class="block text-gray-700 text-sm font-medium mb-2">确认新密码</label>
<div class="relative">
<input type="password" id="confirm_password" name="confirm_password" class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-colors" placeholder="请再次输入新密码" required>
<button type="button" class="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-500 hover:text-gray-700 transition-colors" onclick="togglePasswordVisibility('confirm_password', this)">
<i class="fa fa-eye"></i>
</button>
</div>
</div>
<div class="flex space-x-3">
<button type="submit" class="flex-1 bg-primary hover:bg-primary-dark text-white py-2 px-4 rounded-md transition-colors shadow-sm hover:shadow">
确认修改
</button>
<button type="button" onclick="window.location.href='{{ url_for('query') }}'" class="flex-1 border border-gray-300 text-gray-700 hover:bg-gray-50 py-2 px-4 rounded-md transition-colors">
取消
</button>
</div>
</form>
</div> </div>
</main> </div>
<!-- 页脚 -->
{% include 'footer.html' %} {% include 'footer.html' %}
<!-- JavaScript --> <!-- JavaScript -->
<script> <script>
// 密码可见性切换 layui.use(['form', 'layer'], function() {
function togglePasswordVisibility(inputId, button) { var form = layui.form;
const input = document.getElementById(inputId); var layer = layui.layer;
const icon = button.querySelector('i');
if (input.type === 'password') {
input.type = 'text';
icon.classList.remove('fa-eye');
icon.classList.add('fa-eye-slash');
} else {
input.type = 'password';
icon.classList.remove('fa-eye-slash');
icon.classList.add('fa-eye');
}
}
// 表单提交处理
document.getElementById('changePasswordForm').addEventListener('submit', function(e) {
e.preventDefault(); // 阻止默认提交
const newPassword = document.getElementById('new_password').value; // 密码可见性切换功能
const confirmPassword = document.getElementById('confirm_password').value; function togglePasswordVisibility(inputId) {
const oldPassword = document.getElementById('old_password').value; var input = document.getElementById(inputId);
var icon = document.getElementById(inputId + '_icon');
// 前端验证
if (!oldPassword) { if (input.type === 'password') {
alert('请输入旧密码'); input.type = 'text';
return; icon.classList.remove('fa-eye');
icon.classList.add('fa-eye-slash');
} else {
input.type = 'password';
icon.classList.remove('fa-eye-slash');
icon.classList.add('fa-eye');
}
} }
if (newPassword.length < 8 || !/[a-zA-Z]/.test(newPassword) || !/[0-9]/.test(newPassword)) { // 为输入框添加密码可见性切换图标
alert('新密码长度至少8位,且必须包含字母和数字'); function addPasswordToggleIcons() {
return; var passwordInputs = document.querySelectorAll('input[type="password"]');
passwordInputs.forEach(function(input) {
var parent = input.parentElement;
var toggleBtn = document.createElement('i');
toggleBtn.id = input.id + '_icon';
toggleBtn.className = 'fa fa-eye layui-icon layui-input-icon-right password-toggle-icon';
toggleBtn.style.position = 'absolute';
toggleBtn.style.right = '10px';
toggleBtn.style.top = '50%';
toggleBtn.style.transform = 'translateY(-50%)';
toggleBtn.style.cursor = 'pointer';
toggleBtn.style.color = '#999';
// 为容器添加相对定位
parent.style.position = 'relative';
// 添加点击事件
toggleBtn.addEventListener('click', function() {
togglePasswordVisibility(input.id);
});
// 检查是否已存在图标
if (!document.getElementById(input.id + '_icon')) {
parent.appendChild(toggleBtn);
// 为输入框添加右侧内边距,防止文字被图标遮挡
input.style.paddingRight = '30px';
}
});
} }
if (newPassword !== confirmPassword) { // 表单验证
alert('两次输入的新密码不一致'); form.verify({
return; password: [
} /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/,
'密码长度至少8位,且必须包含字母和数字'
]
});
// 提交表单 // 表单提交处理
this.submit(); form.on('submit(changePasswordForm)', function(data) {
const newPassword = document.getElementById('new_password').value;
const confirmPassword = document.getElementById('confirm_password').value;
const oldPassword = document.getElementById('old_password').value;
// 前端验证
if (!oldPassword) {
layer.msg('请输入旧密码', {icon: 5});
return false;
}
if (newPassword.length < 8 || !/[a-zA-Z]/.test(newPassword) || !/[0-9]/.test(newPassword)) {
layer.msg('新密码长度至少8位,且必须包含字母和数字', {icon: 5});
return false;
}
if (newPassword !== confirmPassword) {
layer.msg('两次输入的新密码不一致', {icon: 5});
return false;
}
// 提交表单前的视觉反馈
const submitButton = document.querySelector('button[type="submit"]');
const originalText = submitButton.innerHTML;
submitButton.disabled = true;
submitButton.innerHTML = '<i class="fa fa-spinner fa-spin mr-1"></i> 提交中...';
// 延迟提交以显示加载状态
setTimeout(() => {
document.getElementById('changePasswordForm').submit();
}, 500);
return false;
});
// 页面加载完成后执行
window.onload = function() {
// 添加密码可见性切换图标
addPasswordToggleIcons();
// 重新渲染表单
form.render();
};
}); });
</script> </script>
</body> </body>
+184
View File
@@ -0,0 +1,184 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>参数配置 - 车主信息查询系统</title>
<!-- 引入Layui CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/layui.css') }}">
<!-- 引入Font Awesome -->
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
<!-- 引入自定义CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/custom.css') }}">
<!-- 引入Layui JS -->
<script src="{{ url_for('static', filename='layui.js') }}"></script>
<script>
layui.use(['layer', 'form', 'element', 'table'], function(){
var layer = layui.layer;
var form = layui.form;
var element = layui.element;
var table = layui.table;
});
</script>
</head>
<body>
<div class="layui-layout layui-layout-admin">
<!-- 引入统一的顶部导航栏 -->
{% include 'header.html' %}
<!-- 为了保持原有布局,添加一个占位div -->
<div class="layui-header" style="height: 60px; background-color: #f2f2f2;"></div>
<!-- 主要内容区域 -->
<div class="layui-body">
<div class="layui-fluid">
<div class="layui-row layui-col-space15">
<div class="layui-col-md12">
<div class="layui-card">
<div class="layui-card-header">
<i class="fa fa-cog"></i> 系统参数配置
</div>
<div class="layui-card-body">
<!-- 消息提示区域 -->
{% if error %}
<div class="layui-bg-red message-box">
<i class="fa fa-exclamation-circle"></i> {{ error }}
</div>
{% endif %}
{% if success %}
<div class="layui-bg-green message-box">
<i class="fa fa-check-circle"></i> {{ success }}
</div>
{% endif %}
<!-- 参数配置表单 -->
<form class="layui-form" method="POST">
<div class="layui-tab layui-tab-card">
<ul class="layui-tab-title">
<li class="layui-this">基本设置</li>
<li>查询设置</li>
<li>安全设置</li>
</ul>
<div class="layui-tab-content">
<!-- 基本设置 -->
<div class="layui-tab-item layui-show">
<div class="layui-form-item">
<label class="layui-form-label">系统名称</label>
<div class="layui-input-block">
<input type="text" name="system_name" value="{{ config.system_name if config else '车主信息查询系统' }}" class="layui-input" lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">系统版本</label>
<div class="layui-input-block">
<input type="text" name="system_version" value="{{ config.system_version if config else '1.0.0' }}" class="layui-input" lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">管理员邮箱</label>
<div class="layui-input-block">
<input type="email" name="admin_email" value="{{ config.admin_email if config else '' }}" class="layui-input" lay-verify="email">
</div>
</div>
</div>
<!-- 查询设置 -->
<div class="layui-tab-item">
<div class="layui-form-item">
<label class="layui-form-label">每页记录数</label>
<div class="layui-input-block">
<input type="number" name="page_size" value="{{ config.page_size if config else 10 }}" class="layui-input" lay-verify="required|number">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">查询超时(秒)</label>
<div class="layui-input-block">
<input type="number" name="query_timeout" value="{{ config.query_timeout if config else 30 }}" class="layui-input" lay-verify="required|number">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">最大查询结果</label>
<div class="layui-input-block">
<input type="number" name="max_results" value="{{ config.max_results if config else 1000 }}" class="layui-input" lay-verify="required|number">
</div>
</div>
</div>
<!-- 安全设置 -->
<div class="layui-tab-item">
<div class="layui-form-item">
<label class="layui-form-label">密码最小长度</label>
<div class="layui-input-block">
<input type="number" name="min_password_length" value="{{ config.min_password_length if config else 8 }}" class="layui-input" lay-verify="required|number">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">会话超时(分钟)</label>
<div class="layui-input-block">
<input type="number" name="session_timeout" value="{{ config.session_timeout if config else 30 }}" class="layui-input" lay-verify="required|number">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">登录失败锁定</label>
<div class="layui-input-block">
<input type="checkbox" name="enable_login_lock" value="1" title="启用" lay-skin="switch" {% if config and config.enable_login_lock %}checked{% endif %}>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">失败次数限制</label>
<div class="layui-input-block">
<input type="number" name="login_fail_limit" value="{{ config.login_fail_limit if config else 5 }}" class="layui-input" lay-verify="required|number">
</div>
</div>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="submit" class="layui-btn" lay-submit>保存配置</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 引入统一的页脚 -->
{% include 'footer.html' %}
</div>
<script>
layui.use(['form', 'element', 'layer'], function(){
var form = layui.form;
var element = layui.element;
var layer = layui.layer;
// 表单验证
form.verify({
number: function(value) {
if(!/^\d+$/.test(value)) {
return '必须为数字';
}
},
email: function(value) {
if(value && !/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/.test(value)) {
return '邮箱格式不正确';
}
}
});
// 表单提交
form.on('submit', function(data){
// 表单数据会自动提交,这里可以添加额外的验证逻辑
return true;
});
});
</script>
</body>
</html>
+2 -2
View File
@@ -1,6 +1,6 @@
<!-- 页脚 --> <!-- 页脚 -->
<footer class="bg-white py-4 border-t border-gray-200"> <footer class="footer">
<div class="container mx-auto px-4 text-center text-gray-500 text-sm"> <div class="container text-center">
<p>© {{ current_year }} 车主信息查询系统 - 版权所有</p> <p>© {{ current_year }} 车主信息查询系统 - 版权所有</p>
<p>免责声明:本系统为内部测试使用,仅供学习和研究。</p> <p>免责声明:本系统为内部测试使用,仅供学习和研究。</p>
</div> </div>
+84 -24
View File
@@ -1,42 +1,102 @@
<!-- 顶部导航栏 --> <!-- 顶部导航栏 -->
<header class="bg-white shadow-sm fixed top-0 left-0 right-0 z-10"> <header class="header-navbar">
<div class="container mx-auto px-4 py-3 flex justify-between items-center"> <div class="header-container">
<div class="flex items-center space-x-2"> <div class="header-logo">
<i class="fa fa-car text-primary text-2xl"></i> <i class="fa fa-car header-icon"></i>
<h1 class="text-xl font-bold text-gray-800">车主信息查询系统</h1> <h1 class="header-title">车主信息查询系统</h1>
</div> </div>
<div class="flex items-center space-x-4"> <div class="header-user">
<!-- 用户下拉菜单 --> <!-- 用户下拉菜单 -->
<div class="relative group"> <div class="user-dropdown-container">
<div class="flex items-center cursor-pointer hover:text-primary transition-colors"> <div class="user-dropdown-toggle">
<span class="text-gray-600">欢迎 <strong>{{ session.department }}</strong> <strong>{{ session.name }}</strong></span> <span class="user-welcome">欢迎 <strong>{{ session.department }}</strong> <strong>{{ session.name }}</strong></span>
<i class="fa fa-chevron-down ml-2 text-xs transition-transform duration-300 group-hover:rotate-180"></i> <i class="fa fa-chevron-down dropdown-icon" id="dropdown-icon"></i>
</div> </div>
<!-- 下拉菜单 --> <!-- 下拉菜单 -->
<div class="absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-300 transform origin-top-right scale-95 group-hover:scale-100 z-20"> <div class="user-dropdown" id="user-dropdown">
<div class="py-1"> <div class="dropdown-content">
<a href="{{ url_for('user.user_profile_page') }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-primary hover:text-white transition-colors"> <a href="{{ url_for('user.user_profile_page') }}" class="dropdown-item">
<i class="fa fa-user mr-2"></i> 个人信息 <i class="fa fa-user dropdown-icon-item"></i> 个人信息
</a> </a>
<a href="{{ url_for('user.change_password_page') }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-primary hover:text-white transition-colors"> <a href="{{ url_for('user.change_password_page') }}" class="dropdown-item">
<i class="fa fa-lock mr-2"></i> 修改密码 <i class="fa fa-lock dropdown-icon-item"></i> 修改密码
</a> </a>
<a href="{{ url_for('user.parameter_config_page') }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-primary hover:text-white transition-colors"> <a href="{{ url_for('user.parameter_config_page') }}" class="dropdown-item">
<i class="fa fa-cog mr-2"></i> 参数配置 <i class="fa fa-cog dropdown-icon-item"></i> 参数配置
</a> </a>
{% if session.username == 'admin' %} {% if session.username == 'admin' %}
<a href="{{ url_for('user.users_management') }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-primary hover:text-white transition-colors"> <a href="{{ url_for('user.users_management') }}" class="dropdown-item">
<i class="fa fa-users mr-2"></i> 用户管理 <i class="fa fa-users dropdown-icon-item"></i> 用户管理
</a> </a>
{% endif %} {% endif %}
<div class="border-t border-gray-200 my-1"></div> <div class="dropdown-divider"></div>
<a href="{{ url_for('user.logout') }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-primary hover:text-white transition-colors"> <a href="{{ url_for('user.logout') }}" class="dropdown-item">
<i class="fa fa-sign-out mr-2"></i> 退出 <i class="fa fa-sign-out dropdown-icon-item"></i> 退出
</a> </a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</header> </header>
<script>
document.addEventListener('DOMContentLoaded', function() {
const dropdownContainer = document.querySelector('.user-dropdown-container');
const dropdownToggle = document.querySelector('.user-dropdown-toggle');
const dropdown = document.getElementById('user-dropdown');
const dropdownIcon = document.getElementById('dropdown-icon');
let timeout;
// 点击切换下拉菜单
dropdownToggle.addEventListener('click', function(e) {
e.stopPropagation(); // 阻止冒泡,避免立即关闭
toggleDropdown();
});
// 点击页面其他地方关闭下拉菜单
document.addEventListener('click', function() {
closeDropdown();
});
// 鼠标悬停显示下拉菜单
dropdownContainer.addEventListener('mouseenter', function() {
clearTimeout(timeout);
openDropdown();
});
// 鼠标离开延迟关闭下拉菜单
dropdownContainer.addEventListener('mouseleave', function() {
timeout = setTimeout(closeDropdown, 300);
});
// 下拉菜单内鼠标进入取消关闭计时器
dropdown.addEventListener('mouseenter', function() {
clearTimeout(timeout);
});
// 下拉菜单内鼠标离开延迟关闭
dropdown.addEventListener('mouseleave', function() {
timeout = setTimeout(closeDropdown, 300);
});
function toggleDropdown() {
if (dropdown.classList.contains('show')) {
closeDropdown();
} else {
openDropdown();
}
}
function openDropdown() {
dropdown.classList.add('show');
dropdownIcon.classList.add('rotate');
}
function closeDropdown() {
dropdown.classList.remove('show');
dropdownIcon.classList.remove('rotate');
}
});
</script>
+42 -55
View File
@@ -4,78 +4,65 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>车主信息查询系统 - 登录</title> <title>车主信息查询系统 - 登录</title>
<!-- 引入Tailwind CSS --> <!-- 引入Layui CSS -->
<script src="https://cdn.tailwindcss.com"></script> <link rel="stylesheet" href="{{ url_for('static', filename='css/layui.css') }}">
<!-- 引入Font Awesome --> <!-- 引入Font Awesome -->
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
<!-- 引入自定义CSS -->
<link href="{{ url_for('static', filename='css/custom.css') }}" rel="stylesheet">
<!-- 配置Tailwind CSS --> <!-- 引入Layui JS -->
<script src="{{ url_for('static', filename='layui.js') }}"></script>
<script> <script>
tailwind.config = { layui.use(['layer', 'form'], function(){
theme: { var layer = layui.layer;
extend: { var form = layui.form;
colors: { });
primary: '#1890ff',
secondary: '#f5f7fa',
success: '#52c41a',
warning: '#faad14',
error: '#f5222d',
info: '#8c8c8c'
},
fontFamily: {
sans: ['Microsoft YaHei', 'Arial', 'sans-serif']
}
}
}
}
</script> </script>
<!-- 自定义工具类 -->
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.input-focus {
@apply focus:border-primary focus:ring-2 focus:ring-primary/20 focus:outline-none;
}
}
</style>
</head> </head>
<body class="bg-secondary min-h-screen font-sans flex justify-center items-center"> <body>
<div class="bg-white rounded-lg shadow-md p-8 w-full max-w-md"> <div class="login-container card">
<div class="text-center mb-8"> <div class="login-title">
<h1 class="text-2xl font-bold text-gray-800">车主信息查询系统</h1> <h1><i class="fa fa-car"></i> 车主信息查询系统</h1>
</div> </div>
<form method="POST"> <form class="layui-form" method="POST">
<div class="mb-6"> <div class="layui-form-item">
<label for="username" class="block text-gray-700 font-medium mb-2">用户名</label> <label class="layui-form-label"><i class="fa fa-user"></i> 用户名</label>
<input type="text" id="username" name="username" required <div class="layui-input-block">
class="w-full px-4 py-3 border border-gray-300 rounded-md input-focus"> <input type="text" id="username" name="username" required lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input">
</div>
</div> </div>
<div class="mb-6"> <div class="layui-form-item">
<label for="password" class="block text-gray-700 font-medium mb-2">密码</label> <label class="layui-form-label"><i class="fa fa-lock"></i> 密码</label>
<input type="password" id="password" name="password" required <div class="layui-input-block">
class="w-full px-4 py-3 border border-gray-300 rounded-md input-focus"> <input type="password" id="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input">
</div>
</div> </div>
{% if error %} {% if error %}
<div class="text-error text-center mb-4"> <div class="layui-form-item">
{{ error }} <div class="layui-input-block">
<div class="layui-bg-red" style="padding: 10px; border-radius: 4px;">{{ error }}</div>
</div>
</div> </div>
{% endif %} {% endif %}
{% if success %} {% if success %}
<div class="text-success text-center mb-4"> <div class="layui-form-item">
{{ success }} <div class="layui-input-block">
<div class="layui-bg-green" style="padding: 10px; border-radius: 4px;">{{ success }}</div>
</div>
</div> </div>
{% endif %} {% endif %}
<button type="submit" <div class="layui-form-item">
class="w-full py-3 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors duration-300 font-medium"> <div style="text-align: center;">
登录 <button type="submit" class="layui-btn layui-btn-normal"><i class="fa fa-sign-in"></i> 登录</button>
</button> </div>
<div class="mt-4 text-center"> </div>
<a href="/register" class="text-primary hover:text-primary/80 transition-colors">注册账号</a> <div class="layui-form-item" style="text-align: center;">
<a href="/register" class="layui-link">没有账号?点击注册</a>
</div> </div>
</form> </form>
</div> </div>
<!-- 引入统一的页脚 -->
{% include 'footer.html' %}
</body> </body>
</html> </html>
+179 -201
View File
@@ -4,176 +4,136 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>参数配置 - 车主信息查询系统</title> <title>参数配置 - 车主信息查询系统</title>
<!-- Tailwind CSS --> <!-- 引入Layui CSS -->
<script src="https://cdn.tailwindcss.com"></script> <link rel="stylesheet" href="{{ url_for('static', filename='css/layui.css') }}">
<!-- Font Awesome --> <!-- 引入Font Awesome -->
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
<!-- 配置Tailwind自定义颜色和字体 --> <!-- 引入自定义CSS -->
<script> <link rel="stylesheet" href="{{ url_for('static', filename='css/custom.css') }}">
tailwind.config = {
theme: { <!-- 引入Layui JS -->
extend: { <script src="{{ url_for('static', filename='layui.js') }}"></script>
colors: {
primary: '#2563eb',
secondary: '#f3f4f6',
'primary-light': '#dbeafe',
'primary-dark': '#1d4ed8',
'table-header': '#f9fafb',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script>
<!-- 自定义工具类 -->
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.card-shadow {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
}
.input-focus {
@apply focus:border-primary focus:ring-2 focus:ring-primary/20 focus:outline-none;
}
.animate-fade-in {
animation: fadeIn 0.3s ease-out forwards;
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head> </head>
<body class="bg-secondary min-h-screen font-sans"> <body>
{% include 'header.html' %} {% include 'header.html' %}
<!-- 主要内容区域 --> <!-- 主要内容区域 -->
<main class="container mx-auto px-4 pt-24 pb-12"> <div class="content-container">
<!-- 返回按钮 --> <div class="content-wrapper">
<div class="mb-6 flex justify-end"> <!-- 参数配置卡片 -->
<a href="{{ url_for('query') }}" class="inline-flex items-center text-primary hover:text-primary-dark transition-colors"> <div class="card">
<i class="fa fa-arrow-left mr-2"></i> 返回主页面 <div class="card-header">
</a> <i class="fa fa-cog"></i> 参数配置
<a href="{{ url_for('query') }}" class="layui-btn layui-btn-xs layui-btn-primary" style="float: right;">
<i class="fa fa-arrow-left"></i> 返回主页面
</a>
</div>
<div class="card-body">
<!-- 消息提示区域 -->
{% if error %}
<div class="layui-bg-red message-box">
<i class="fa fa-exclamation-circle"></i> {{ error }}
</div>
{% endif %}
{% if success %}
<div class="layui-bg-green message-box">
<i class="fa fa-check-circle"></i> {{ success }}
</div>
{% endif %}
<div class="layui-text" style="text-align: center; margin-bottom: 20px;">
<div style="width: 80px; height: 80px; background-color: #f2f2f2; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 15px;">
<i class="fa fa-cogs" style="font-size: 40px; color: #009688;"></i>
</div>
<p style="color: #666;">请设置和管理系统参数配置</p>
</div>
<!-- 表单区域 -->
<div class="layui-form" id="parameterForm" style="max-width: 600px; margin: 0 auto;">
<div class="message-box" id="updateTimeAlert" style="display: none; justify-content: center; margin-bottom: 15px;">
<i class="fa fa-info-circle"></i>
<span id="updateTimeContent"></span>
</div>
<div class="layui-form-item">
<label class="layui-form-label">参数1 <span class="layui-form-must">*</span></label>
<div class="layui-input-block">
<input type="text" id="param1" name="param1" required lay-verify="required" placeholder="请输入参数1的值" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">参数2</label>
<div class="layui-input-block">
<input type="text" id="param2" name="param2" placeholder="请输入参数2的值" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">参数3</label>
<div class="layui-input-block">
<input type="text" id="param3" name="param3" placeholder="请输入参数3的值" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">参数4</label>
<div class="layui-input-block">
<input type="text" id="param4" name="param4" placeholder="请输入参数4的值" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">参数5</label>
<div class="layui-input-block">
<input type="text" id="param5" name="param5" placeholder="请输入参数5的值" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-btn-primary" id="reloadButton">
<i class="fa fa-refresh mr-1"></i> 重新加载
</button>
<button class="layui-btn layui-btn-normal" id="saveButton" lay-submit lay-filter="saveConfig">
<i class="fa fa-save mr-1"></i> 保存配置
</button>
</div>
</div>
</div>
</div>
</div>
</div> </div>
</div>
<!-- 个人信息表单 -->
<div class="max-w-md mx-auto bg-white rounded-lg shadow-xl p-8 animate-fade-in">
<div class="text-center mb-6">
<div class="w-16 h-16 bg-primary-light rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fa fa-cog text-primary text-2xl"></i>
</div>
<h2 class="text-2xl font-bold text-gray-800">参数配置</h2>
<p class="text-gray-500 mt-2">请配置系统参数</p>
</div>
<!-- 消息提示区域 -->
{% if error %}
<div class="mb-4 bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-md flex items-start animate-fade-in">
<i class="fa fa-exclamation-circle mt-1 mr-3"></i>
<span>{{ error }}</span>
</div>
{% endif %}
{% if success %}
<div class="mb-4 bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded-md flex items-start animate-fade-in">
<i class="fa fa-check-circle mt-1 mr-3"></i>
<span>{{ success }}</span>
</div>
{% endif %}
<div class="mb-6 bg-blue-50 border border-blue-100 text-blue-700 px-4 py-3 rounded-md flex items-center" id="updateTimeAlert" style="display: none;">
<i class="fa fa-info-circle mr-2"></i>
<span id="updateTimeContent"></span>
</div>
<div class="space-y-4">
<div class="mb-4">
<label for="param1" class="block text-gray-700 text-sm font-medium mb-2">参数1 <span class="text-red-500">*</span></label>
<input type="text" id="param1" class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-colors" placeholder="请输入参数1的值">
</div>
<div class="mb-4">
<label for="param2" class="block text-gray-700 text-sm font-medium mb-2">参数2</label>
<input type="text" id="param2" class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-colors" placeholder="请输入参数2的值">
</div>
<div class="mb-4">
<label for="param3" class="block text-gray-700 text-sm font-medium mb-2">参数3</label>
<input type="text" id="param3" class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-colors" placeholder="请输入参数3的值">
</div>
<div class="mb-4">
<label for="param4" class="block text-gray-700 text-sm font-medium mb-2">参数4</label>
<input type="text" id="param4" class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-colors" placeholder="请输入参数4的值">
</div>
<div class="mb-6">
<label for="param5" class="block text-gray-700 text-sm font-medium mb-2">参数5</label>
<input type="text" id="param5" class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-colors" placeholder="请输入参数5的值">
</div>
<div class="flex space-x-3">
<button onclick="loadParameterConfig()" class="flex-1 border border-gray-300 text-gray-700 hover:bg-gray-50 py-2 px-4 rounded-md transition-colors flex items-center justify-center">
<i class="fa fa-refresh mr-2"></i> 重新加载
</button>
<button onclick="saveParameterConfig()" class="flex-1 bg-primary hover:bg-primary-dark text-white py-2 px-4 rounded-md transition-colors shadow-sm hover:shadow flex items-center justify-center">
<i class="fa fa-save mr-2"></i> 保存配置
</button>
</div>
</div>
</main>
<script> <script>
layui.use(['form', 'layer'], function(){
var form = layui.form;
var layer = layui.layer;
// 页面加载时获取参数配置 // 页面加载时获取参数配置
document.addEventListener('DOMContentLoaded', function() { loadParameterConfig();
// 重新加载按钮点击事件
document.getElementById('reloadButton').addEventListener('click', function() {
loadParameterConfig(); loadParameterConfig();
}); });
// 加载参数配置 // 表单提交
function loadParameterConfig() { form.on('submit(saveConfig)', function() {
fetch('/get_parameter_config') // 添加加载状态
.then(response => response.json()) var saveButton = document.getElementById('saveButton');
.then(data => { var originalText = saveButton.innerHTML;
if (data.success && data.parameters) {
const parameters = data.parameters; saveButton.disabled = true;
document.getElementById('param1').value = parameters.param1 || ''; saveButton.innerHTML = '<i class="fa fa-spinner fa-spin mr-1"></i> 保存中...';
document.getElementById('param2').value = parameters.param2 || '';
document.getElementById('param3').value = parameters.param3 || '';
document.getElementById('param4').value = parameters.param4 || '';
document.getElementById('param5').value = parameters.param5 || '';
// 显示更新时间
if (parameters.update_time) {
document.getElementById('updateTimeContent').textContent = '最后更新时间:' + parameters.update_time;
document.getElementById('updateTimeAlert').style.display = 'flex';
}
} else {
showErrorMessage('获取参数配置失败:' + (data.error || ''));
}
})
.catch(error => {
showErrorMessage('获取参数配置失败,请稍后重试');
console.error('获取参数配置失败', error);
});
}
// 保存参数配置
function saveParameterConfig() {
// 表单验证 // 表单验证
if (!document.getElementById('param1').value.trim()) { if (!document.getElementById('param1').value.trim()) {
showErrorMessage('参数1不能为空'); showErrorMessage('参数1不能为空');
return; saveButton.disabled = false;
saveButton.innerHTML = originalText;
return false;
} }
const formData = { const formData = {
@@ -193,6 +153,10 @@
}) })
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
// 恢复按钮状态
saveButton.disabled = false;
saveButton.innerHTML = originalText;
if (data.success) { if (data.success) {
showSuccessMessage('参数配置保存成功'); showSuccessMessage('参数配置保存成功');
// 重新加载参数配置 // 重新加载参数配置
@@ -202,6 +166,10 @@
} }
}) })
.catch(error => { .catch(error => {
// 恢复按钮状态
saveButton.disabled = false;
saveButton.innerHTML = originalText;
let errorMessage = '保存参数配置失败,请稍后重试'; let errorMessage = '保存参数配置失败,请稍后重试';
if (error.responseJSON && error.responseJSON.error) { if (error.responseJSON && error.responseJSON.error) {
errorMessage = error.responseJSON.error; errorMessage = error.responseJSON.error;
@@ -209,61 +177,71 @@
showErrorMessage(errorMessage); showErrorMessage(errorMessage);
console.error('保存参数配置失败', error); console.error('保存参数配置失败', error);
}); });
return false; // 阻止表单默认提交
});
// 加载参数配置
function loadParameterConfig() {
// 添加加载状态
var reloadButton = document.getElementById('reloadButton');
var originalText = reloadButton.innerHTML;
reloadButton.disabled = true;
reloadButton.innerHTML = '<i class="fa fa-spinner fa-spin mr-1"></i> 加载中...';
fetch('/get_parameter_config')
.then(response => response.json())
.then(data => {
// 恢复按钮状态
reloadButton.disabled = false;
reloadButton.innerHTML = originalText;
if (data.success && data.parameters) {
const parameters = data.parameters;
document.getElementById('param1').value = parameters.param1 || '';
document.getElementById('param2').value = parameters.param2 || '';
document.getElementById('param3').value = parameters.param3 || '';
document.getElementById('param4').value = parameters.param4 || '';
document.getElementById('param5').value = parameters.param5 || '';
// 显示更新时间
if (parameters.update_time) {
document.getElementById('updateTimeContent').textContent = '最后更新时间:' + parameters.update_time;
document.getElementById('updateTimeAlert').style.display = 'flex';
} else {
document.getElementById('updateTimeAlert').style.display = 'none';
}
} else {
showErrorMessage('获取参数配置失败:' + (data.error || ''));
}
})
.catch(error => {
// 恢复按钮状态
reloadButton.disabled = false;
reloadButton.innerHTML = originalText;
showErrorMessage('获取参数配置失败,请稍后重试');
console.error('获取参数配置失败', error);
});
} }
// 显示错误消息 // 显示错误消息
function showErrorMessage(message) { function showErrorMessage(message) {
// 创建错误消息元素 layer.msg(message, {
const errorDiv = document.createElement('div'); icon: 5,
errorDiv.className = 'mb-4 bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-md flex items-start animate-fade-in'; time: 3000
errorDiv.innerHTML = ` });
<i class="fa fa-exclamation-circle mt-1 mr-3"></i>
<span>${message}</span>
`;
// 插入到表单前
const container = document.querySelector('.space-y-4');
container.insertBefore(errorDiv, container.firstChild);
// 3秒后自动移除
setTimeout(() => {
errorDiv.style.opacity = '0';
errorDiv.style.transform = 'translateY(-10px)';
errorDiv.style.transition = 'opacity 0.3s, transform 0.3s';
setTimeout(() => {
if (errorDiv.parentNode) {
errorDiv.parentNode.removeChild(errorDiv);
}
}, 300);
}, 3000);
} }
// 显示成功消息 // 显示成功消息
function showSuccessMessage(message) { function showSuccessMessage(message) {
// 创建成功消息元素 layer.msg(message, {
const successDiv = document.createElement('div'); icon: 1,
successDiv.className = 'mb-4 bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded-md flex items-start animate-fade-in'; time: 3000
successDiv.innerHTML = ` });
<i class="fa fa-check-circle mt-1 mr-3"></i>
<span>${message}</span>
`;
// 插入到表单前
const container = document.querySelector('.space-y-4');
container.insertBefore(successDiv, container.firstChild);
// 3秒后自动移除
setTimeout(() => {
successDiv.style.opacity = '0';
successDiv.style.transform = 'translateY(-10px)';
successDiv.style.transition = 'opacity 0.3s, transform 0.3s';
setTimeout(() => {
if (successDiv.parentNode) {
successDiv.parentNode.removeChild(successDiv);
}
}, 300);
}, 3000);
} }
});
</script> </script>
{% include 'footer.html' %} {% include 'footer.html' %}
+323 -283
View File
@@ -4,56 +4,25 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>车主信息查询系统 - 查询</title> <title>车主信息查询系统 - 查询</title>
<!-- 引入Tailwind CSS --> <!-- 引入Layui CSS -->
<script src="https://cdn.tailwindcss.com"></script> <link rel="stylesheet" href="{{ url_for('static', filename='css/layui.css') }}">
<!-- 引入Font Awesome --> <!-- 引入Font Awesome -->
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
<!-- 引入自定义CSS -->
<link href="{{ url_for('static', filename='css/custom.css') }}" rel="stylesheet">
<!-- 引入Layui JS -->
<script src="{{ url_for('static', filename='layui.js') }}"></script>
<!-- 配置Tailwind CSS -->
<script> <script>
tailwind.config = { layui.use(['layer', 'form', 'table'], function(){
theme: { var layer = layui.layer;
extend: { var form = layui.form;
colors: { var table = layui.table;
primary: '#1890ff', });
secondary: '#f0f2f5',
success: '#52c41a',
warning: '#faad14',
error: '#f5222d',
info: '#8c8c8c',
'primary-light': '#e6f7ff',
'table-header': '#fafafa'
},
fontFamily: {
sans: ['Microsoft YaHei', 'Arial', 'sans-serif']
}
}
}
}
</script> </script>
<!-- 自定义工具类 -->
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.card-shadow {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
}
.input-focus {
@apply focus:border-primary focus:ring-2 focus:ring-primary/20 focus:outline-none;
}
.table-hover {
@apply hover:bg-primary-light/30 transition-colors duration-150;
}
.animate-fade-in {
animation: fadeIn 0.3s ease-out forwards;
}
}
<style>
@keyframes fadeIn { @keyframes fadeIn {
from { from {
opacity: 0; opacity: 0;
@@ -66,148 +35,111 @@
} }
</style> </style>
</head> </head>
<body class="bg-secondary min-h-screen font-sans"> <body>
<!-- 引入统一的顶部导航栏 -->
{% include 'header.html' %} {% include 'header.html' %}
<!-- 主要内容区域 --> <!-- 主要内容区域 -->
<main class="container mx-auto px-4 pt-24 pb-12"> <div class="content-container">
<!-- 消息提示区域 --> <div class="content-wrapper">
{% if error %} <div class="card">
<div class="mb-6 bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-md flex items-start animate-fade-in"> <div class="card-body">
<i class="fa fa-exclamation-circle mt-1 mr-3"></i> <!-- 表单已清除 -->
<span>{{ error }}</span>
</div> <!-- 消息提示区域 -->
{% endif %} {% if error %}
{% if success %} <div class="error-message">
<div class="mb-6 bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded-md flex items-start animate-fade-in"> <i class="fa fa-exclamation-circle"></i> {{ error }}
<i class="fa fa-check-circle mt-1 mr-3"></i> </div>
<span>{{ success }}</span> {% endif %}
</div> {% if success %}
{% endif %} <div class="success-message">
<i class="fa fa-check-circle"></i> {{ success }}
<!-- 最近查询记录 --> </div>
{% if recent_queries %} {% endif %}
<div class="bg-white rounded-lg card-shadow p-6 transform hover:translate-y-[-2px] transition-all duration-300">
<div class="flex justify-between items-center mb-4"> <!-- 最近查询记录 -->
<h2 class="text-lg font-semibold text-gray-800 flex items-center"> {% if recent_queries %}
<i class="fa fa-history text-primary mr-2"></i> 最近查询记录 <div class="card">
</h2> <div class="card-header">
<button id="addQueryBtn" class="bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-md flex items-center transition-all duration-200 shadow-sm hover:shadow"> <i class="fa fa-history"></i> 最近查询记录
<i class="fa fa-plus mr-1"></i> 增加 <button id="addQueryBtn" class="layui-btn layui-btn-normal" style="
</button> float: right;
</div> padding: 6px 16px;
</h2> border-radius: 6px;
<div class="overflow-x-auto"> background-color: #009688;
<table class="min-w-full divide-y divide-gray-200"> border-color: #009688;
<thead class="bg-table-header"> font-size: 14px;
<tr> font-weight: 500;
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">序号</th> color: white;
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">查询日期</th> transition: all 0.3s ease;
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">车牌号</th> box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">手机号</th> display: flex;
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">状态</th> align-items: center;
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">登录部门</th> justify-content: center;
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">登录IP</th> gap: 5px;
</tr> ">
</thead> <i class="fa fa-plus-circle"></i> 新增查询记录
<tbody class="bg-white divide-y divide-gray-200"> </button>
{% for query in recent_queries %} </div>
<tr class="table-hover cursor-pointer transition-all duration-200 hover:bg-primary-light/40" data-history-id="{{ query.id }}"> <div class="card-body">
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ loop.index }}</td> <table class="layui-table">
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ query.query_date }}</td> <thead>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ query.plate_number }}</td> <tr>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ query.phone }}</td> <th>序号</th>
<td class="px-6 py-4 whitespace-nowrap text-sm"> <th>查询日期</th>
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full <th>车牌号</th>
{% if query.results_count == -1 %} <th>手机号</th>
bg-warning/10 text-warning <th>状态</th>
{% elif query.results_count > 0 %} <th>登录部门</th>
bg-success/10 text-success <th>登录IP</th>
{% else %} </tr>
bg-error/10 text-error </thead>
{% endif %}"> <tbody>
{% if query.results_count == -1 %} {% for query in recent_queries %}
待查询 <tr class="table-hover" data-history-id="{{ query.id }}">
{% else %} <td>{{ loop.index }}</td>
{{ query.results_count }} 条记录 <td>{{ query.query_date }}</td>
{% endif %} <td>{{ query.plate_number }}</td>
</span> <td>{{ query.phone }}</td>
</td> <td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ query.department }}</td> <span class="layui-badge
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ query.query_ip }}</td> {% if query.results_count == -1 %}
</tr> layui-bg-orange
{% endfor %} {% elif query.results_count > 0 %}
</tbody> layui-bg-green
</table> {% else %}
</div> layui-bg-red
</div> {% endif %}">
{% endif %} {% if query.results_count == -1 %}
</main> 待查询
{% else %}
<!-- 增加查询模态框 --> {{ query.results_count }} 条记录
<div id="addQueryModal" class="fixed inset-0 bg-black/50 z-50 hidden flex items-center justify-center p-4"> {% endif %}
<div class="bg-white rounded-lg shadow-xl max-w-md w-full"> </span>
<div class="flex justify-between items-center p-6 border-b"> </td>
<h3 class="text-xl font-semibold text-gray-800">增加查询记录</h3> <td>{{ query.department }}</td>
<button id="closeAddModal" class="text-gray-500 hover:text-gray-700 transition-colors"> <td>{{ query.query_ip }}</td>
<i class="fa fa-times text-xl"></i> </tr>
</button> {% endfor %}
</div> </tbody>
<div class="p-6"> </table>
<form id="addQueryForm"> </div>
<div class="mb-4"> </div>
<label for="add_plate_number" class="block text-sm font-medium text-gray-700 mb-1">车牌号</label> {% endif %}
<input type="text" id="add_plate_number" name="plate_number" </div>
class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-all duration-200"
placeholder="请输入车牌号(如:京A123456">
</div>
<div class="mb-6">
<label for="add_phone" class="block text-sm font-medium text-gray-700 mb-1">手机号</label>
<input type="tel" id="add_phone" name="phone"
class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-all duration-200"
placeholder="请输入手机号(如:13800138001">
<p class="mt-1 text-sm text-gray-500">提示:请至少输入车牌号或手机号其中一项</p>
</div>
<div class="flex space-x-4">
<button type="submit" class="flex-1 bg-primary hover:bg-primary/90 text-white px-4 py-2 rounded-md transition-all duration-200">
保存
</button>
<button type="button" id="cancelAddBtn" class="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-md transition-all duration-200">
取消
</button>
</div>
</form>
<!-- 加载状态 -->
<div id="addQueryLoading" class="py-10 flex flex-col items-center justify-center hidden">
<i class="fa fa-spinner fa-spin text-primary text-3xl mb-4"></i>
<p class="text-gray-600">正在处理...</p>
</div>
</div> </div>
</div> </div>
</div> </div>
<!-- 用于layui增加查询弹窗的隐藏字段 -->
<input type="hidden" id="add_plate_number">
<input type="hidden" id="add_phone">
<!-- 详情模态框 --> <!-- 详情模态框 -->
<div id="detailModal" class="fixed inset-0 bg-black/50 z-50 hidden flex items-center justify-center p-4"> <div id="detailModal" class="fixed inset-0 bg-black/50 z-50 hidden flex items-center justify-center p-4">
<div class="bg-white rounded-lg shadow-xl max-w-4xl w-full max-h-[90vh] overflow-y-auto"> <div class="bg-white rounded-lg shadow-xl max-w-4xl w-full max-h-[90vh] overflow-y-auto">
<div class="flex justify-between items-center p-6 border-b">
<h3 class="text-xl font-semibold text-gray-800">查询结果详情</h3>
<button id="closeModal" class="text-gray-500 hover:text-gray-700 transition-colors">
<i class="fa fa-times text-xl"></i>
</button>
</div>
<div class="p-6" id="modalContent"> <div class="p-6" id="modalContent">
<!-- 加载状态 -->
<div id="loadingState" class="py-10 flex flex-col items-center justify-center">
<i class="fa fa-spinner fa-spin text-primary text-3xl mb-4"></i>
<p class="text-gray-600">正在加载详情...</p>
</div>
<!-- 无结果状态 -->
<div id="noResultState" class="py-10 flex flex-col items-center justify-center hidden">
<i class="fa fa-search text-gray-300 text-5xl mb-4"></i>
<p class="text-gray-600">未找到相关车辆信息</p>
</div>
<!-- 结果列表 --> <!-- 结果列表 -->
<div id="resultList" class="hidden"> <div id="resultList" class="hidden">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6" id="carOwnerCards"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6" id="carOwnerCards">
@@ -249,56 +181,222 @@
// 增加查询按钮点击事件 // 增加查询按钮点击事件
addQueryBtn.addEventListener('click', function() { addQueryBtn.addEventListener('click', function() {
// 兼容classList API // 使用layui创建增加查询记录弹窗,并美化设计
if (addQueryModal.classList) { layer.open({
addQueryModal.classList.remove('hidden'); type: 1,
} else { title: '<i class="fa fa-plus-circle"></i> 增加查询记录',
addQueryModal.className = addQueryModal.className.replace('hidden', ''); area: ['520px', '380px'],
} offset: '10%',
addQueryForm.reset(); shade: 0.3,
}); shadeClose: false,
anim: 2,
// 关闭增加查询模态框 content: `
closeAddModal.addEventListener('click', function() { <div class="form-container" style="padding: 24px;">
// 兼容classList API
if (addQueryModal.classList) {
addQueryModal.classList.add('hidden'); <!-- 表单主体 -->
} else { <form class="layui-form">
addQueryModal.className += ' hidden'; <!-- 车牌号输入框 -->
} <div class="form-group" style="margin-bottom: 20px;">
}); <label for="layui_add_plate_number" style="display: block; font-size: 14px; color: #333; margin-bottom: 8px; font-weight: 500;">
<i class="fa fa-id-card-o" style="color: #009688; margin-right: 6px;"></i>车牌号
// 取消增加查询 </label>
cancelAddBtn.addEventListener('click', function() { <div class="input-wrapper" style="position: relative;">
// 兼容classList API <input type="text" id="layui_add_plate_number"
if (addQueryModal.classList) { style="
addQueryModal.classList.add('hidden'); width: 100%;
} else { height: 42px;
addQueryModal.className += ' hidden'; padding: 0 12px;
} border: 1px solid #dcdfe6;
}); border-radius: 6px;
font-size: 14px;
// 点击增加查询模态框背景关闭 transition: all 0.3s ease;
addQueryModal.addEventListener('click', function(e) { box-sizing: border-box;
if (e.target === addQueryModal) { "
// 兼容classList API placeholder="请输入车牌号(如:京A123456"
if (addQueryModal.classList) { onfocus="this.style.borderColor='#009688'; this.style.boxShadow='0 0 0 2px rgba(0,150,136,0.2)';"
addQueryModal.classList.add('hidden'); onblur="this.style.borderColor='#dcdfe6'; this.style.boxShadow='none';">
} else { </div>
addQueryModal.className += ' hidden'; </div>
<!-- 手机号输入框 -->
<div class="form-group" style="margin-bottom: 24px;">
<label for="layui_add_phone" style="display: block; font-size: 14px; color: #333; margin-bottom: 8px; font-weight: 500;">
<i class="fa fa-mobile" style="color: #009688; margin-right: 6px;"></i>手机号
</label>
<div class="input-wrapper" style="position: relative;">
<input type="tel" id="layui_add_phone"
style="
width: 100%;
height: 42px;
padding: 0 12px;
border: 1px solid #dcdfe6;
border-radius: 6px;
font-size: 14px;
transition: all 0.3s ease;
box-sizing: border-box;
"
placeholder="请输入手机号(如:13800138001"
onfocus="this.style.borderColor='#009688'; this.style.boxShadow='0 0 0 2px rgba(0,150,136,0.2)';"
onblur="this.style.borderColor='#dcdfe6'; this.style.boxShadow='none';">
</div>
<div class="form-tip" style="margin-top: 6px;">
<i class="fa fa-info-circle" style="color: #909399; font-size: 12px;"></i>
<span style="color: #909399; font-size: 12px; margin-left: 4px;">提示:请至少输入车牌号或手机号其中一项</span>
</div>
</div>
<!-- 加载状态 -->
<div id="layui_addQueryLoading" class="loading-state" style="display: none; flex-direction: column; align-items: center; justify-content: center; padding: 30px 0;">
<div class="spinner" style="width: 40px; height: 40px; border: 3px solid #f0f0f0; border-top: 3px solid #009688; border-radius: 50%; animation: spin 1s linear infinite;"></div>
<p style="margin-top: 12px; color: #606266; font-size: 14px;">正在处理...</p>
</div>
<style>
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</form>
<style>
.btn-success {
background-color: #009688;
border-color: #009688;
color: white;
padding: 8px 20px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 150, 136, 0.2);
outline: none;
cursor: pointer;
}
.btn-success:hover {
background-color: #26a69a;
border-color: #26a69a;
box-shadow: 0 4px 8px rgba(0, 150, 136, 0.3);
}
.btn-success:active {
transform: translateY(1px);
}
.btn-secondary {
background-color: #f0f2f5;
border-color: #dcdfe6;
color: #606266;
padding: 8px 20px;
border-radius: 6px;
font-size: 14px;
transition: all 0.3s ease;
outline: none;
cursor: pointer;
}
.btn-secondary:hover {
background-color: #e6eaf0;
border-color: #c0c4cc;
}
</style>
</div>
`,
btn: ['保存', '取消'],
btnAlign: 'c',
btnClass: ['btn-success', 'btn-secondary'],
btn1: function(index, layero) {
const plateNumber = document.getElementById('layui_add_plate_number').value;
const phone = document.getElementById('layui_add_phone').value;
// 验证输入
if (!plateNumber && !phone) {
layer.msg('请至少输入车牌号或手机号其中一项', {
icon: 5,
anim: 6,
time: 2000
});
return false;
}
// 手机号格式验证
if (phone && !/^1[3-9]\d{9}$/.test(phone)) {
layer.msg('请输入正确的手机号码', {
icon: 5,
anim: 6,
time: 2000
});
return false;
}
// 车牌号格式简单验证(可根据实际需求调整)
if (plateNumber && plateNumber.length < 5) {
layer.msg('请输入正确的车牌号', {
icon: 5,
anim: 6,
time: 2000
});
return false;
}
// 显示加载状态
document.getElementById('layui_addQueryLoading').style.display = 'flex';
// 模拟提交数据
setTimeout(function() {
// 创建表单用于提交数据
var form = document.createElement('form');
form.method = 'POST';
form.action = '/query';
// 添加车牌号字段
var plateInput = document.createElement('input');
plateInput.type = 'hidden';
plateInput.name = 'plate_number';
plateInput.value = plateNumber;
form.appendChild(plateInput);
// 添加手机号字段
var phoneInput = document.createElement('input');
phoneInput.type = 'hidden';
phoneInput.name = 'phone';
phoneInput.value = phone;
form.appendChild(phoneInput);
// 添加标识字段,表示这是从"增加"按钮提交的请求
var isAddInput = document.createElement('input');
isAddInput.type = 'hidden';
isAddInput.name = 'is_add_query';
isAddInput.value = 'true';
form.appendChild(isAddInput);
// 隐藏加载状态
document.getElementById('layui_addQueryLoading').style.display = 'none';
// 关闭弹窗
layer.close(index);
// 显示成功消息
layer.msg('查询记录添加成功', {
icon: 1,
time: 2000,
end: function() {
// 提交表单,将数据发送到服务器
document.body.appendChild(form);
form.submit();
}
});
}, 800);
},
btn2: function(index, layero) {
layer.close(index);
return false;
} }
} });
}); });
// 关闭详情模态框 // 移除对已删除元素的引用
closeModal.addEventListener('click', function() {
// 兼容classList API
if (detailModal.classList) {
detailModal.classList.add('hidden');
} else {
detailModal.className += ' hidden';
}
});
// 点击详情模态框背景关闭 // 点击详情模态框背景关闭
detailModal.addEventListener('click', function(e) { detailModal.addEventListener('click', function(e) {
@@ -312,66 +410,8 @@
} }
}); });
// 处理增加查询表单提交 // 表单提交逻辑已整合到layui弹窗中,不需要单独的表单提交事件
addQueryForm.addEventListener('submit', function(e) {
e.preventDefault();
var plateNumber = document.getElementById('add_plate_number').value.trim();
var phone = document.getElementById('add_phone').value.trim();
if (!plateNumber && !phone) {
alert('请至少输入车牌号或手机号');
return;
}
// 显示加载状态
// 兼容classList API
if (addQueryForm.classList) {
addQueryForm.classList.add('hidden');
} else {
addQueryForm.className += ' hidden';
}
if (addQueryLoading.classList) {
addQueryLoading.classList.remove('hidden');
} else {
addQueryLoading.className = addQueryLoading.className.replace('hidden', '');
}
// 构建表单数据
var formData = new FormData();
formData.append('plate_number', plateNumber);
formData.append('phone', phone);
formData.append('is_add_query', 'true');
// 发送请求到查询路由
fetch('/query', {
method: 'POST',
body: formData
})
.then(function(response) {
if (!response.ok) {
throw new Error('网络错误');
}
// 重新加载页面以显示新的查询记录
window.location.reload();
})
.catch(function(error) {
console.error('Error submitting query:', error);
alert('提交失败,请重试');
// 恢复表单显示
// 兼容classList API
if (addQueryForm.classList) {
addQueryForm.classList.remove('hidden');
} else {
addQueryForm.className = addQueryForm.className.replace('hidden', '');
}
if (addQueryLoading.classList) {
addQueryLoading.classList.add('hidden');
} else {
addQueryLoading.className += ' hidden';
}
});
});
// 加载查询历史详情 // 加载查询历史详情
function loadHistoryDetail(historyId) { function loadHistoryDetail(historyId) {
+192 -90
View File
@@ -4,103 +4,205 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>车主信息查询系统 - 注册</title> <title>车主信息查询系统 - 注册</title>
<!-- 引入Tailwind CSS --> <!-- 引入Layui CSS -->
<script src="https://cdn.tailwindcss.com"></script> <link rel="stylesheet" href="{{ url_for('static', filename='css/layui.css') }}">
<!-- 引入Font Awesome --> <!-- 引入Font Awesome -->
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
<!-- 引入自定义CSS -->
<link href="{{ url_for('static', filename='css/custom.css') }}" rel="stylesheet">
<!-- 配置Tailwind CSS --> <!-- 引入Layui JS -->
<script src="{{ url_for('static', filename='layui.js') }}"></script>
</head>
<body>
<!-- 引入统一的顶部导航栏 -->
{% include 'header.html' %}
<!-- 主要内容区域 -->
<div class="content-container">
<div class="content-wrapper">
<div class="card">
<div class="card-header">
<i class="fa fa-user-plus"></i> 用户注册
</div>
<div class="card-body">
<!-- 消息提示区域 -->
{% if error %}
<div class="layui-bg-red message-box">
<i class="fa fa-exclamation-circle"></i> {{ error }}
</div>
{% endif %}
{% if success %}
<div class="layui-bg-green message-box">
<i class="fa fa-check-circle"></i> {{ success }}
</div>
{% endif %}
<div class="layui-text" style="text-align: center; margin-bottom: 20px;">
<div style="width: 80px; height: 80px; background-color: #f2f2f2; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 15px;">
<i class="fa fa-user-plus" style="font-size: 40px; color: #009688;"></i>
</div>
<p style="color: #666;">请填写以下信息完成注册</p>
</div>
<!-- 表单 -->
<form class="layui-form" id="registerForm" method="POST" style="max-width: 500px; margin: 0 auto;">
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-input-block">
<input type="text" id="username" name="username" required lay-verify="required|username" placeholder="请输入用户名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">姓名</label>
<div class="layui-input-block">
<input type="text" id="name" name="name" required lay-verify="required" placeholder="请输入真实姓名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">联系电话</label>
<div class="layui-input-block">
<input type="tel" id="phone" name="phone" required lay-verify="required|phone" placeholder="请输入联系电话" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">部门名称</label>
<div class="layui-input-block">
<input type="text" id="department" name="department" required lay-verify="required" placeholder="请输入部门名称" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码</label>
<div class="layui-input-block">
<input type="password" id="password" name="password" required lay-verify="required|password" placeholder="请设置密码" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">确认密码</label>
<div class="layui-input-block">
<input type="password" id="confirm_password" name="confirm_password" required lay-verify="required|confirmPassword" placeholder="请再次输入密码" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="submit" class="layui-btn" lay-submit lay-filter="registerForm"><i class="fa fa-check"></i> 注册</button>
<button type="reset" class="layui-btn layui-btn-primary"><i class="fa fa-refresh"></i> 重置</button>
</div>
</div>
<div class="layui-form-item" style="text-align: center;">
<a href="{{ url_for('user.login') }}" class="layui-link">已有账号?返回登录</a>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- 页脚 -->
{% include 'footer.html' %}
<script> <script>
tailwind.config = { layui.use(['form', 'layer'], function(){
theme: { var form = layui.form;
extend: { var layer = layui.layer;
colors: {
primary: '#1890ff', // 表单验证
secondary: '#f5f7fa', form.verify({
success: '#52c41a', username: function(value){
warning: '#faad14', if(value.length < 3){
error: '#f5222d', return '用户名至少3个字符';
info: '#8c8c8c' }
}, },
fontFamily: { phone: [
sans: ['Microsoft YaHei', 'Arial', 'sans-serif'] /^1\d{10}$/,
} '请输入正确的手机号'
],
password: [
/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/,
'密码长度至少8位,且必须包含字母和数字'
],
confirmPassword: function(value){
var password = document.getElementById('password').value;
if(value !== password){
return '两次输入的密码不一致';
} }
} }
});
// 表单提交
form.on('submit(registerForm)', function(data){
// 添加加载状态
var submitButton = document.querySelector('button[type="submit"]');
var originalText = submitButton.innerHTML;
submitButton.disabled = true;
submitButton.innerHTML = '<i class="fa fa-spinner fa-spin mr-1"></i> 提交中...';
// 延迟提交以显示加载状态
setTimeout(function(){
document.getElementById('registerForm').submit();
}, 500);
return false;
});
// 密码可见性切换功能
function togglePasswordVisibility(inputId) {
var input = document.getElementById(inputId);
var icon = document.getElementById(inputId + '_icon');
if (input.type === 'password') {
input.type = 'text';
icon.classList.remove('fa-eye');
icon.classList.add('fa-eye-slash');
} else {
input.type = 'password';
icon.classList.remove('fa-eye-slash');
icon.classList.add('fa-eye');
}
} }
// 为输入框添加密码可见性切换图标
function addPasswordToggleIcons() {
var passwordInputs = document.querySelectorAll('input[type="password"]');
passwordInputs.forEach(function(input) {
var parent = input.parentElement;
var toggleBtn = document.createElement('i');
toggleBtn.id = input.id + '_icon';
toggleBtn.className = 'fa fa-eye layui-icon layui-input-icon-right password-toggle-icon';
toggleBtn.style.position = 'absolute';
toggleBtn.style.right = '10px';
toggleBtn.style.top = '50%';
toggleBtn.style.transform = 'translateY(-50%)';
toggleBtn.style.cursor = 'pointer';
toggleBtn.style.color = '#999';
// 为容器添加相对定位
parent.style.position = 'relative';
// 添加点击事件
toggleBtn.addEventListener('click', function() {
togglePasswordVisibility(input.id);
});
// 检查是否已存在图标
if (!document.getElementById(input.id + '_icon')) {
parent.appendChild(toggleBtn);
// 为输入框添加右侧内边距,防止文字被图标遮挡
input.style.paddingRight = '30px';
}
});
}
// 页面加载完成后执行
window.onload = function() {
// 添加密码可见性切换图标
addPasswordToggleIcons();
// 重新渲染表单
form.render();
};
});
</script> </script>
<!-- 自定义工具类 -->
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.input-focus {
@apply focus:border-primary focus:ring-2 focus:ring-primary/20 focus:outline-none;
}
}
</style>
</head>
<body class="bg-secondary min-h-screen font-sans flex justify-center items-center">
<div class="bg-white rounded-lg shadow-md p-8 w-full max-w-md">
<div class="text-center mb-8">
<h1 class="text-2xl font-bold text-gray-800">车主信息查询系统</h1>
<p class="text-gray-600 mt-2">用户注册</p>
</div>
<form method="POST">
<div class="flex gap-4 mb-6">
<div class="flex-1">
<label for="username" class="block text-gray-700 font-medium mb-2">用户名</label>
<input type="text" id="username" name="username" required placeholder="请输入用户名"
class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus">
</div>
<div class="flex-1">
<label for="name" class="block text-gray-700 font-medium mb-2">姓名</label>
<input type="text" id="name" name="name" required placeholder="请输入真实姓名"
class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus">
</div>
</div>
<div class="flex gap-4 mb-6">
<div class="flex-1">
<label for="phone" class="block text-gray-700 font-medium mb-2">联系电话</label>
<input type="tel" id="phone" name="phone" required placeholder="请输入联系电话"
class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus">
</div>
<div class="flex-1">
<label for="department" class="block text-gray-700 font-medium mb-2">部门名称</label>
<input type="text" id="department" name="department" required placeholder="请输入部门名称"
class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus">
</div>
</div>
<div class="mb-6">
<label for="password" class="block text-gray-700 font-medium mb-2">密码</label>
<input type="password" id="password" name="password" required placeholder="请设置密码"
class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus">
</div>
<div class="mb-6">
<label for="confirm_password" class="block text-gray-700 font-medium mb-2">确认密码</label>
<input type="password" id="confirm_password" name="confirm_password" required placeholder="请再次输入密码"
class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus">
</div>
{% if error %}
<div class="text-error text-center mb-4">
{{ error }}
</div>
{% endif %}
{% if success %}
<div class="text-success text-center mb-4">
{{ success }}
</div>
{% endif %}
<button type="submit"
class="w-full py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors duration-300 font-medium">
注册
</button>
<div class="mt-4 text-center">
<a href="/" class="text-primary hover:text-primary/80 transition-colors hover:underline">已有账号?返回登录</a>
</div>
</form>
</div>
</body> </body>
</html> </html>
+103 -111
View File
@@ -4,124 +4,116 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>个人信息 - 车主信息查询系统</title> <title>个人信息 - 车主信息查询系统</title>
<!-- Tailwind CSS --> <!-- 引入Layui CSS -->
<script src="https://cdn.tailwindcss.com"></script> <link rel="stylesheet" href="{{ url_for('static', filename='css/layui.css') }}">
<!-- Font Awesome --> <!-- 引入Font Awesome -->
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
<!-- 配置Tailwind自定义颜色和字体 --> <!-- 引入自定义CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/custom.css') }}">
<!-- 引入Layui JS -->
<script src="{{ url_for('static', filename='layui.js') }}"></script>
<script> <script>
tailwind.config = { layui.use(['layer', 'form', 'element'], function(){
theme: { var layer = layui.layer;
extend: { var form = layui.form;
colors: { var element = layui.element;
primary: '#2563eb', });
secondary: '#f3f4f6',
'primary-light': '#dbeafe',
'primary-dark': '#1d4ed8',
'table-header': '#f9fafb',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script> </script>
<!-- 自定义工具类 -->
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.card-shadow {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
}
.input-focus {
@apply focus:border-primary focus:ring-2 focus:ring-primary/20 focus:outline-none;
}
.animate-fade-in {
animation: fadeIn 0.3s ease-out forwards;
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head> </head>
<body class="bg-secondary min-h-screen font-sans"> <body>
<!-- 引入统一的顶部导航栏 -->
{% include 'header.html' %} {% include 'header.html' %}
<!-- 主要内容区域 --> <!-- 主要内容区域 -->
<main class="container mx-auto px-4 pt-24 pb-12"> <div class="content-container">
<!-- 返回按钮 --> <div class="content-wrapper">
<div class="mb-6 flex justify-end"> <div class="card">
<a href="{{ url_for('query') }}" class="inline-flex items-center text-primary hover:text-primary-dark transition-colors"> <div class="card-header">
<i class="fa fa-arrow-left mr-2"></i> 返回主页面 <i class="fa fa-user"></i> 个人信息
</a> <a href="{{ url_for('query') }}" class="layui-btn layui-btn-xs layui-btn-primary" style="float: right;">
<i class="fa fa-arrow-left"></i> 返回主页面
</a>
</div>
<div class="card-body">
<!-- 消息提示区域 -->
{% if error %}
<div class="layui-bg-red message-box">
<i class="fa fa-exclamation-circle"></i> {{ error }}
</div>
{% endif %}
{% if success %}
<div class="layui-bg-green message-box">
<i class="fa fa-check-circle"></i> {{ success }}
</div>
{% endif %}
<div class="layui-text" style="text-align: center; margin-bottom: 20px;">
<div style="width: 80px; height: 80px; background-color: #f2f2f2; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 15px;">
<i class="fa fa-user" style="font-size: 40px; color: #009688;"></i>
</div>
<p style="color: #666;">请查看并更新您的个人信息</p>
</div>
<!-- 表单 -->
<form class="layui-form" id="userProfileForm" method="POST" style="max-width: 500px; margin: 0 auto;">
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-input-block">
<input type="text" id="profile_username" value="{{ user.username }}" class="layui-input" disabled>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">姓名</label>
<div class="layui-input-block">
<input type="text" id="profile_name" name="name" value="{{ user.name }}" class="layui-input" placeholder="请输入姓名" lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">联系电话</label>
<div class="layui-input-block">
<input type="tel" id="profile_phone" name="phone" value="{{ user.phone }}" class="layui-input" placeholder="请输入联系电话" lay-verify="required|phone">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">部门名称</label>
<div class="layui-input-block">
<input type="text" id="profile_department" name="department" value="{{ user.department }}" class="layui-input" placeholder="请输入部门名称" lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button type="submit" class="layui-btn" lay-submit>保存修改</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
</div>
</div> </div>
</div>
<!-- 个人信息表单 -->
<div class="max-w-md mx-auto bg-white rounded-lg shadow-xl p-8 animate-fade-in"> <!-- 页脚 -->
<div class="text-center mb-6">
<div class="w-16 h-16 bg-primary-light rounded-full flex items-center justify-center mx-auto mb-4">
<i class="fa fa-user text-primary text-2xl"></i>
</div>
<h2 class="text-2xl font-bold text-gray-800">个人信息</h2>
<p class="text-gray-500 mt-2">请查看并更新您的个人信息</p>
</div>
<!-- 消息提示区域 -->
{% if error %}
<div class="mb-4 bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-md flex items-start animate-fade-in">
<i class="fa fa-exclamation-circle mt-1 mr-3"></i>
<span>{{ error }}</span>
</div>
{% endif %}
{% if success %}
<div class="mb-4 bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded-md flex items-start animate-fade-in">
<i class="fa fa-check-circle mt-1 mr-3"></i>
<span>{{ success }}</span>
</div>
{% endif %}
<!-- 表单 -->
<form id="userProfileForm" method="POST" class="space-y-4">
<div class="mb-4">
<label for="profile_username" class="block text-gray-700 text-sm font-medium mb-2">用户名</label>
<input type="text" id="profile_username" value="{{ user.username }}" class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-colors bg-gray-50 cursor-not-allowed" disabled>
</div>
<div class="mb-4">
<label for="profile_name" class="block text-gray-700 text-sm font-medium mb-2">姓名 <span class="text-red-500">*</span></label>
<input type="text" id="profile_name" name="name" value="{{ user.name }}" class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-colors" placeholder="请输入姓名" required>
</div>
<div class="mb-4">
<label for="profile_phone" class="block text-gray-700 text-sm font-medium mb-2">联系电话 <span class="text-red-500">*</span></label>
<input type="tel" id="profile_phone" name="phone" value="{{ user.phone }}" class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-colors" placeholder="请输入联系电话" required>
</div>
<div class="mb-6">
<label for="profile_department" class="block text-gray-700 text-sm font-medium mb-2">部门名称 <span class="text-red-500">*</span></label>
<input type="text" id="profile_department" name="department" value="{{ user.department }}" class="w-full px-4 py-2 border border-gray-300 rounded-md input-focus transition-colors" placeholder="请输入部门名称" required>
</div>
<div class="flex space-x-3">
<button type="submit" class="flex-1 bg-primary hover:bg-primary-dark text-white py-2 px-4 rounded-md transition-colors shadow-sm hover:shadow">
保存修改
</button>
<button type="button" onclick="window.location.href='{{ url_for('query') }}'" class="flex-1 border border-gray-300 text-gray-700 hover:bg-gray-50 py-2 px-4 rounded-md transition-colors">
取消
</button>
</div>
</form>
</div>
</main>
{% include 'footer.html' %} {% include 'footer.html' %}
<script>
layui.use(['form', 'element'], function(){
var form = layui.form;
var element = layui.element;
// 表单验证
form.verify({
phone: [
/^1\d{10}$/,
'请输入正确的手机号'
]
});
// 表单提交
form.on('submit(userProfileForm)', function(data){
// 表单数据会自动提交,这里可以添加额外的验证逻辑
return true;
});
});
</script>
</body> </body>
</html> </html>
+372 -310
View File
@@ -4,247 +4,155 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>车主信息查询系统 - 用户管理</title> <title>车主信息查询系统 - 用户管理</title>
<!-- 引入Tailwind CSS --> <!-- 引入Layui CSS -->
<script src="https://cdn.tailwindcss.com"></script> <link rel="stylesheet" href="{{ url_for('static', filename='css/layui.css') }}">
<!-- 引入Font Awesome --> <!-- 引入Font Awesome -->
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
<!-- 引入自定义CSS -->
<link href="{{ url_for('static', filename='css/custom.css') }}" rel="stylesheet">
<!-- 配置Tailwind CSS --> <!-- 引入Layui JS -->
<script src="{{ url_for('static', filename='layui.js') }}"></script>
<!-- 初始化Layui组件 -->
<script> <script>
tailwind.config = { layui.use(['layer', 'form', 'table'], function(){
theme: { var layer = layui.layer;
extend: { var form = layui.form;
colors: { var table = layui.table;
primary: '#1890ff',
secondary: '#f0f2f5', // 渲染所有表单元素
success: '#52c41a', form.render();
warning: '#faad14', });
error: '#f5222d',
info: '#8c8c8c',
'primary-light': '#e6f7ff',
'table-header': '#fafafa'
},
fontFamily: {
sans: ['Microsoft YaHei', 'Arial', 'sans-serif']
}
}
}
}
</script> </script>
<!-- 引入通用工具函数 --> <!-- 引入通用工具函数 -->
<script src="{{ url_for('static', filename='js/utils.js') }}"></script> <script src="{{ url_for('static', filename='js/utils.js') }}"></script>
<!-- 自定义工具类 -->
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.card-shadow {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
}
.input-focus {
@apply focus:border-primary focus:ring-2 focus:ring-primary/20 focus:outline-none;
}
.table-hover {
@apply hover:bg-primary-light/30 transition-colors duration-150;
}
.animate-fade-in {
animation: fadeIn 0.3s ease-out forwards;
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>
</head> </head>
<body class="bg-secondary min-h-screen font-sans"> <body>
<!-- 引入统一的顶部导航栏 -->
{% include 'header.html' %} {% include 'header.html' %}
<!-- 主内容区 --> <!--内容区 -->
<main class="container mx-auto px-4 pt-24 pb-12"> <div class="content-container">
<!-- 返回按钮 --> <div class="content-wrapper">
<div class="mb-6 flex justify-end"> <div class="card">
<a href="{{ url_for('query') }}" class="inline-flex items-center text-primary hover:text-primary-dark transition-colors"> <div class="card-header">
<i class="fa fa-arrow-left mr-2"></i> 返回主页面 <i class="fa fa-users"></i> 用户管理
</a> <a href="{{ url_for('query') }}" class="layui-btn layui-btn-xs layui-btn-primary" style="float: right;">
</div> <i class="fa fa-arrow-left"></i> 返回主页面
</a>
<!-- 页面标题 -->
<div class="mb-6">
<h2 class="text-2xl font-bold text-gray-800">用户管理</h2>
<p class="text-gray-500 mt-1">管理系统用户、审核登录权限、修改部门信息和初始化密码</p>
</div>
<!-- 搜索框 -->
<div class="bg-white rounded-lg shadow-sm p-4 mb-6">
<div class="flex flex-col md:flex-row gap-4">
<div class="flex-1">
<div class="relative">
<input type="text" id="searchUsername" placeholder="输入用户名搜索"
class="w-full px-4 py-2 pl-10 border border-gray-300 rounded-md input-focus">
<i class="fa fa-search absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"></i>
</div>
</div> </div>
<div class="flex flex-col md:flex-row gap-2"> <div class="card-body">
<select id="filterDepartment" class="w-full md:w-auto px-4 py-2 border border-gray-300 rounded-md input-focus"> <!-- 消息提示区域 -->
<option value="">所有部门</option> <div id="messageContainer" class="mb-6 hidden">
{% for dept in departments %}
<option value="{{ dept }}">{{ dept }}</option>
{% endfor %}
</select>
<select id="filterStatus" class="w-full md:w-auto px-4 py-2 border border-gray-300 rounded-md input-focus">
<option value="">所有状态</option>
<option value="active">已启用</option>
<option value="inactive">已禁用</option>
</select>
<button onclick="searchUsers()" class="w-full md:w-auto bg-primary text-white px-4 py-2 rounded-md hover:bg-primary/90 transition-colors">
<i class="fa fa-search mr-1"></i> 搜索
</button>
</div>
</div>
</div>
<!-- 消息提示区域 -->
<div id="messageContainer" class="mb-6 hidden">
<div id="successMessage" class="bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded-md flex items-center hidden">
<i class="fa fa-check-circle mr-2"></i>
<span></span>
</div>
<div id="errorMessage" class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-md flex items-center hidden">
<i class="fa fa-exclamation-circle mr-2"></i>
<span></span>
</div>
</div>
<!-- 用户列表表格 -->
<div class="bg-white rounded-lg shadow-sm overflow-hidden">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-table-header">
<tr>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">用户名</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">姓名</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">部门</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">状态</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th>
</tr>
</thead>
<tbody id="usersTableBody" class="bg-white divide-y divide-gray-200">
<!-- 用户数据将通过JavaScript动态加载 -->
</tbody>
</table>
</div>
<!-- 分页控制 -->
<div class="px-6 py-3 flex items-center justify-between border-t border-gray-200">
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
<div>
<p class="text-sm text-gray-700">
显示 <span id="startItem">1</span><span id="endItem">10</span> 条,共 <span id="totalItems">0</span> 条记录
</p>
</div> </div>
<div>
<nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination"> <div class="layui-text" style="text-align: center; margin-bottom: 20px;">
<button id="prevPage" class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed"> <div style="width: 80px; height: 80px; background-color: #f2f2f2; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; margin-bottom: 15px;">
<span class="sr-only">上一页</span> <i class="fa fa-users" style="font-size: 40px; color: #009688;"></i>
<i class="fa fa-chevron-left"></i> </div>
<p style="color: #666;">管理系统用户、审核登录权限、修改部门信息和初始化密码</p>
</div>
<!-- 搜索框 -->
<div class="mb-6">
<div class="layui-form" style="margin-bottom: 15px;">
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-input-inline" style="width: 180px;">
<input type="text" id="searchUsername" placeholder="输入用户名搜索" class="layui-input">
</div>
<label class="layui-form-label">部门</label>
<div class="layui-input-inline" style="width: 120px;">
<select id="filterDepartment" class="layui-select" lay-search>
<option value="">所有部门</option>
{% for dept in departments %}
<option value="{{ dept }}">{{ dept }}</option>
{% endfor %}
</select>
</div>
<label class="layui-form-label">状态</label>
<div class="layui-input-inline" style="width: 100px;">
<select id="filterStatus" class="layui-select">
<option value="">所有状态</option>
<option value="active">已启用</option>
<option value="inactive">已禁用</option>
</select>
</div>
<div class="layui-input-inline">
<button id="searchButton" onclick="searchUsers()" class="layui-btn layui-btn-normal">
<i class="fa fa-search mr-1"></i> 搜索
</button>
</div>
</div>
</div>
</div>
<!-- 用户列表表格 -->
<div class="overflow-x-auto">
<table class="layui-table">
<thead>
<tr>
<th>用户名</th>
<th>姓名</th>
<th>部门</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="usersTableBody">
<!-- 用户数据将通过JavaScript动态加载 -->
</tbody>
</table>
</div>
<!-- 分页控制 -->
<div class="layui-form-item" style="text-align: center; margin-top: 20px;">
<div class="layui-input-block">
<span id="paginationInfo" class="layui-btn layui-btn-primary layui-btn-radius" style="margin-right: 20px;">
显示 <span id="startItem" style="color: #1E9FFF;">1</span><span id="endItem" style="color: #1E9FFF;">10</span> 条,共 <span id="totalItems" style="color: #1E9FFF;">0</span> 条记录
</span>
<button id="prevPage" class="layui-btn layui-btn-radius" disabled>
<i class="fa fa-chevron-left"></i> 上一页
</button> </button>
<button id="nextPage" class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed"> <button id="nextPage" class="layui-btn layui-btn-radius">
<span class="sr-only">下一页</span> 下一页 <i class="fa fa-chevron-right"></i>
<i class="fa fa-chevron-right"></i>
</button> </button>
</nav> </div>
</div> </div>
</div>
</div>
</div> </div>
</div> </div>
</main> </div>
<!-- 页脚 -->
{% include 'footer.html' %} {% include 'footer.html' %}
<!-- 修改部门信息弹窗 --> <!-- 用于存储弹窗数据的隐藏字段 -->
<div id="editDepartmentModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> <input type="hidden" id="editUserId">
<div class="bg-white rounded-lg shadow-xl w-full max-w-md mx-4 overflow-hidden transform transition-all animate-fade-in"> <input type="hidden" id="editUsername">
<div class="bg-primary text-white p-4 flex justify-between items-center"> <input type="hidden" id="resetUserId">
<h3 class="text-lg font-medium">修改部门信息</h3> <input type="hidden" id="resetUsername">
<button onclick="closeEditDepartmentModal()" class="text-white hover:text-gray-200 transition-colors">
<i class="fa fa-times"></i> <!-- 部门选项数据 -->
</button> <script id="departmentOptions" type="application/json">
</div> [{% for dept in departments %}{{ dept | tojson }}{% if not loop.last %},{% endif %}{% endfor %}]
<div class="p-6"> </script>
<input type="hidden" id="editUserId">
<input type="hidden" id="editUsername">
<div class="mb-4">
<label for="editUserName" class="block text-sm font-medium text-gray-700 mb-1">用户名</label>
<input type="text" id="editUserName" readonly class="w-full px-3 py-2 border border-gray-300 rounded-md bg-gray-50 cursor-not-allowed">
</div>
<div class="mb-4">
<label for="editUserRealName" class="block text-sm font-medium text-gray-700 mb-1">姓名</label>
<input type="text" id="editUserRealName" readonly class="w-full px-3 py-2 border border-gray-300 rounded-md bg-gray-50 cursor-not-allowed">
</div>
<div class="mb-6">
<label for="editUserDepartment" class="block text-sm font-medium text-gray-700 mb-1">部门</label>
<select id="editUserDepartment" class="w-full px-3 py-2 border border-gray-300 rounded-md input-focus">
{% for dept in departments %}
<option value="{{ dept }}">{{ dept }}</option>
{% endfor %}
</select>
</div>
<div class="flex space-x-4">
<button onclick="saveDepartmentChanges()" class="flex-1 bg-primary hover:bg-primary/90 text-white py-2 px-4 rounded-md transition-colors shadow-sm hover:shadow">
保存修改
</button>
<button onclick="closeEditDepartmentModal()" class="flex-1 border border-gray-300 text-gray-700 hover:bg-gray-50 py-2 px-4 rounded-md transition-colors">
取消
</button>
</div>
</div>
</div>
</div>
<!-- 初始化密码弹窗 -->
<div id="resetPasswordModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-lg shadow-xl w-full max-w-md mx-4 overflow-hidden transform transition-all animate-fade-in">
<div class="bg-primary text-white p-4 flex justify-between items-center">
<h3 class="text-lg font-medium">初始化密码</h3>
<button onclick="closeResetPasswordModal()" class="text-white hover:text-gray-200 transition-colors">
<i class="fa fa-times"></i>
</button>
</div>
<div class="p-6">
<input type="hidden" id="resetUserId">
<input type="hidden" id="resetUsername">
<div class="mb-6">
<p class="text-gray-700 mb-2">确定要初始化用户 <span id="resetUserNameDisplay" class="font-medium"></span> 的密码吗?</p>
<p class="text-gray-500 text-sm">初始化后,密码将重置为默认值:<code class="bg-gray-100 px-1 py-0.5 rounded">default123</code></p>
</div>
<div class="flex space-x-4">
<button onclick="confirmResetPassword()" class="flex-1 bg-primary hover:bg-primary/90 text-white py-2 px-4 rounded-md transition-colors shadow-sm hover:shadow">
确定初始化
</button>
<button onclick="closeResetPasswordModal()" class="flex-1 border border-gray-300 text-gray-700 hover:bg-gray-50 py-2 px-4 rounded-md transition-colors">
取消
</button>
</div>
</div>
</div>
</div>
<!-- 安全转义函数 -->
<script>
// HTML转义函数,防止XSS攻击
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
</script>
<!-- 用户管理相关JavaScript --> <!-- 用户管理相关JavaScript -->
<script> <script>
// 当前页码和每页显示数量 // 当前页码和每页显示数量
@@ -252,6 +160,7 @@
const pageSize = 10; const pageSize = 10;
let totalUsers = 0; let totalUsers = 0;
let usersData = []; let usersData = [];
let isLoading = false; // 添加加载状态标志
// 页面加载完成后初始化 // 页面加载完成后初始化
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
@@ -279,13 +188,32 @@
} }
}); });
// 绑定模态框点击外部关闭事件 // 使用layui弹窗,不再需要绑定模态框点击外部关闭事件
bindModalOutsideClick('editDepartmentModal');
bindModalOutsideClick('resetPasswordModal');
}); });
// 加载用户列表 // 加载用户列表
function loadUsers() { function loadUsers() {
if (isLoading) return;
isLoading = true;
// 显示加载状态
const loadingRow = document.getElementById('loadingRow');
if (loadingRow) {
loadingRow.classList.remove('hidden');
}
// 清空表格内容
const tableBody = document.getElementById('usersTableBody');
if (tableBody) {
// 只保留loadingRow元素
const children = Array.from(tableBody.children);
children.forEach(child => {
if (child.id !== 'loadingRow') {
tableBody.removeChild(child);
}
});
}
apiRequest('/api/users') apiRequest('/api/users')
.then(data => { .then(data => {
if (data.success) { if (data.success) {
@@ -299,13 +227,28 @@
.catch(error => { .catch(error => {
console.error('加载用户列表时发生错误:', error); console.error('加载用户列表时发生错误:', error);
showMessage('网络错误,请稍后重试', false); showMessage('网络错误,请稍后重试', false);
})
.finally(() => {
isLoading = false;
// 隐藏加载状态
if (loadingRow) {
loadingRow.classList.add('hidden');
}
}); });
} }
// 渲染用户表格 // 渲染用户表格
function renderUsersTable() { function renderUsersTable() {
const tableBody = document.getElementById('usersTableBody'); const tableBody = document.getElementById('usersTableBody');
tableBody.innerHTML = ''; if (!tableBody) return;
// 清空表格内容,但保留loadingRow
const children = Array.from(tableBody.children);
children.forEach(child => {
if (child.id !== 'loadingRow') {
tableBody.removeChild(child);
}
});
// 计算当前页的用户数据 // 计算当前页的用户数据
const startIndex = (currentPage - 1) * pageSize; const startIndex = (currentPage - 1) * pageSize;
@@ -313,43 +256,56 @@
const currentUsers = usersData.slice(startIndex, endIndex); const currentUsers = usersData.slice(startIndex, endIndex);
// 更新分页信息 // 更新分页信息
document.getElementById('startItem').textContent = startIndex + 1; const startItemEl = document.getElementById('startItem');
document.getElementById('endItem').textContent = endIndex; const endItemEl = document.getElementById('endItem');
document.getElementById('totalItems').textContent = totalUsers; const totalItemsEl = document.getElementById('totalItems');
if (startItemEl) startItemEl.textContent = startIndex + 1;
if (endItemEl) endItemEl.textContent = endIndex;
if (totalItemsEl) totalItemsEl.textContent = totalUsers;
// 更新分页按钮状态 // 更新分页按钮状态
document.getElementById('prevPage').disabled = currentPage === 1; const prevPageBtn = document.getElementById('prevPage');
document.getElementById('nextPage').disabled = currentPage === Math.ceil(totalUsers / pageSize); const nextPageBtn = document.getElementById('nextPage');
if (prevPageBtn) prevPageBtn.disabled = currentPage === 1;
if (nextPageBtn) nextPageBtn.disabled = currentPage === Math.ceil(totalUsers / pageSize);
// 渲染用户行 // 渲染用户行
currentUsers.forEach(user => { currentUsers.forEach((user) => {
const row = document.createElement('tr'); const row = document.createElement('tr');
row.className = 'table-hover';
// 状态样式 // 状态样式 - 使用layui风格
const statusClass = user.status === 'active' ? 'bg-success/10 text-success' : 'bg-error/10 text-error'; const statusClass = user.status === 'active' ? 'layui-bg-green' : 'layui-bg-red';
const statusText = user.status === 'active' ? '已启用' : '已禁用'; const statusText = user.status === 'active' ? '已启用' : '已禁用';
// 转义用户输入以防止XSS
const safeUsername = escapeHtml(user.username);
const safeName = escapeHtml(user.name);
const safeDepartment = escapeHtml(user.department);
row.innerHTML = ` row.innerHTML = `
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${user.username}</td> <td>${safeUsername}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${user.name}</td> <td>${safeName}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">${user.department}</td> <td>${safeDepartment}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm"> <td>
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${statusClass}"> <span class="layui-badge ${statusClass}" style="padding: 0 10px;">
<i class="fa ${user.status === 'active' ? 'fa-check-circle mr-1' : 'fa-times-circle mr-1'}"></i>
${statusText} ${statusText}
</span> </span>
</td> </td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium"> <td>
<button onclick="toggleUserStatus(${user.id}, '${user.username}', '${user.status}')" <button onclick="toggleUserStatus(${user.id}, '${safeUsername}', '${user.status}')"
class="text-primary hover:text-primary/80 mr-3"> class="layui-btn layui-btn-xs layui-btn-primary">
<i class="fa ${user.status === 'active' ? 'fa-lock mr-1' : 'fa-unlock mr-1'}"></i>
${user.status === 'active' ? '禁用' : '启用'} ${user.status === 'active' ? '禁用' : '启用'}
</button> </button>
<button onclick="showEditDepartmentModal(${user.id}, '${user.username}', '${user.name}', '${user.department}')" <button onclick="showEditDepartmentModal(${user.id}, '${safeUsername}', '${safeName}', '${safeDepartment}')"
class="text-primary hover:text-primary/80 mr-3"> class="layui-btn layui-btn-xs layui-btn-normal">
<i class="fa fa-building mr-1"></i>
修改部门 修改部门
</button> </button>
<button onclick="showResetPasswordModal(${user.id}, '${user.username}')" <button onclick="showResetPasswordModal(${user.id}, '${safeUsername}')"
class="text-primary hover:text-primary/80"> class="layui-btn layui-btn-xs layui-btn-warm">
<i class="fa fa-key mr-1"></i>
初始化密码 初始化密码
</button> </button>
</td> </td>
@@ -358,13 +314,16 @@
tableBody.appendChild(row); tableBody.appendChild(row);
}); });
// 如果没有数据,显示空状态 // 如果没有数据,显示空状态 - 使用layUI风格
if (totalUsers === 0) { if (totalUsers === 0) {
const emptyRow = document.createElement('tr'); const emptyRow = document.createElement('tr');
emptyRow.innerHTML = ` emptyRow.innerHTML = `
<td colspan="5" class="px-6 py-10 text-center text-gray-500"> <td colspan="5" style="text-align: center; padding: 40px 0; color: #999;">
<i class="fa fa-user-circle-o text-4xl mb-2 opacity-30"></i> <div class="layui-none">
<p>暂无用户数据</p> <i class="fa fa-user-circle-o text-5xl mb-4" style="opacity: 0.3;"></i>
<p class="layui-text" style="font-size: 16px;">暂无用户数据</p>
<p style="color: #ccc; margin-top: 10px;">请添加新用户或等待其他用户注册</p>
</div>
</td> </td>
`; `;
tableBody.appendChild(emptyRow); tableBody.appendChild(emptyRow);
@@ -373,6 +332,15 @@
// 搜索用户 // 搜索用户
function searchUsers() { function searchUsers() {
if (isLoading) return;
const searchButton = document.getElementById('searchButton');
const originalText = searchButton.innerHTML;
isLoading = true;
searchButton.disabled = true;
searchButton.innerHTML = '<i class="fa fa-spinner fa-spin mr-1"></i> 搜索中...';
const searchUsername = document.getElementById('searchUsername').value.toLowerCase().trim(); const searchUsername = document.getElementById('searchUsername').value.toLowerCase().trim();
const filterDepartment = document.getElementById('filterDepartment').value; const filterDepartment = document.getElementById('filterDepartment').value;
const filterStatus = document.getElementById('filterStatus').value; const filterStatus = document.getElementById('filterStatus').value;
@@ -388,7 +356,7 @@
return matchesUsername && matchesDepartment && matchesStatus; return matchesUsername && matchesDepartment && matchesStatus;
}); });
totalUsers = data.total; totalUsers = usersData.length;
currentPage = 1; // 重置到第一页 currentPage = 1; // 重置到第一页
renderUsersTable(); renderUsersTable();
} else { } else {
@@ -398,15 +366,24 @@
.catch(error => { .catch(error => {
console.error('搜索用户时发生错误:', error); console.error('搜索用户时发生错误:', error);
showMessage('网络错误,请稍后重试', false); showMessage('网络错误,请稍后重试', false);
})
.finally(() => {
isLoading = false;
searchButton.disabled = false;
searchButton.innerHTML = originalText;
}); });
} }
// 切换用户状态 // 切换用户状态
function toggleUserStatus(userId, username, currentStatus) { function toggleUserStatus(userId, username, currentStatus) {
if (isLoading) return;
const newStatus = currentStatus === 'active' ? 'inactive' : 'active'; const newStatus = currentStatus === 'active' ? 'inactive' : 'active';
const confirmMessage = `确定要${newStatus === 'active' ? '启用' : '禁用'}用户 ${username} 吗?`; const confirmMessage = `确定要${newStatus === 'active' ? '启用' : '禁用'}用户 ${username} 吗?`;
if (confirm(confirmMessage)) { if (confirm(confirmMessage)) {
isLoading = true;
apiRequest('{{ url_for('user.update_user_status') }}', 'POST', { apiRequest('{{ url_for('user.update_user_status') }}', 'POST', {
user_id: userId, user_id: userId,
status: newStatus status: newStatus
@@ -426,40 +403,102 @@
.catch(error => { .catch(error => {
console.error('更新用户状态时发生错误:', error); console.error('更新用户状态时发生错误:', error);
showMessage('网络错误,请稍后重试', false); showMessage('网络错误,请稍后重试', false);
})
.finally(() => {
isLoading = false;
}); });
} }
} }
// 显示修改部门弹窗 // 显示修改部门弹窗(使用layui
function showEditDepartmentModal(userId, username, name, department) { function showEditDepartmentModal(userId, username, name, department) {
// 存储用户数据
document.getElementById('editUserId').value = userId; document.getElementById('editUserId').value = userId;
document.getElementById('editUsername').value = username; document.getElementById('editUsername').value = username;
document.getElementById('editUserName').value = username;
document.getElementById('editUserRealName').value = name;
// 设置当前部门 // 获取部门选项
const departmentSelect = document.getElementById('editUserDepartment'); const departments = JSON.parse(document.getElementById('departmentOptions').textContent);
for (let i = 0; i < departmentSelect.options.length; i++) { let departmentOptionsHtml = '';
if (departmentSelect.options[i].value === department) { departments.forEach(dept => {
departmentSelect.selectedIndex = i; const selected = dept === department ? 'selected' : '';
break; departmentOptionsHtml += `<option value="${dept}" ${selected}>${dept}</option>`;
});
// 创建美化后的弹窗内容 - 参照初始化密码弹窗样式
const content = `
<div class="layui-text">
<!-- 表单主体 - 使用layUI风格 -->
<form class="layui-form" style="padding: 20px;">
<!-- 用户名列 -->
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-input-block" style="max-width: 300px;">
<input type="text" value="${username}" readonly class="layui-input layui-disabled">
</div>
</div>
<!-- 姓名列 -->
<div class="layui-form-item">
<label class="layui-form-label">姓名</label>
<div class="layui-input-block" style="max-width: 300px;">
<input type="text" id="layuiEditName" value="${name}" class="layui-input" lay-affix="clear">
</div>
</div>
<!-- 部门选择 -->
<div class="layui-form-item">
<label class="layui-form-label">部门</label>
<div class="layui-input-block" style="max-width: 300px;">
<input type="text" id="layuiEditDepartment" value="${department}" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux" style="color: #666; margin-top: 5px;">输入新的部门名称后点击保存</div>
</div>
</form>
</div>
`;
// 打开美化后的layui弹窗 - 参照初始化密码弹窗样式
layer.open({
type: 1,
title: '<i class="fa fa-building-o"></i> 修改部门信息',
area: ['500px', '380px'],
offset: '10%',
shade: 0.3,
shadeClose: false,
anim: 2,
content: content,
btn: ['保存修改', '取消'],
btnAlign: 'c',
btnClass: ['layui-btn layui-btn-normal', 'layui-btn layui-btn-primary'],
skin: 'layui-layer-molv',
success: function(layero, index) {
// 确保部门输入框在弹窗中可以正常交互
const inputElement = layero.find('#layuiEditDepartment')[0];
if (inputElement) {
// 移除可能阻止交互的属性
inputElement.removeAttribute('disabled');
inputElement.style.pointerEvents = 'auto';
// 聚焦到输入框
inputElement.focus();
}
},
btn1: function(index, layero) {
const newDepartment = document.getElementById('layuiEditDepartment').value;
// 获取修改后的姓名值
const newName = layero.find('input[type="text"]')[1].value;
saveDepartmentChanges(userId, username, newName, newDepartment, index);
},
btn2: function(index, layero) {
layer.close(index);
return false;
} }
} });
showModal('editDepartmentModal');
} }
// 关闭修改部门弹窗 // 保存部门和姓名修改
function closeEditDepartmentModal() { function saveDepartmentChanges(userId, username, newName, newDepartment, layerIndex) {
document.getElementById('editDepartmentModal').classList.add('hidden');
}
// 保存部门修改
function saveDepartmentChanges() {
const userId = document.getElementById('editUserId').value;
const username = document.getElementById('editUsername').value;
const newDepartment = document.getElementById('editUserDepartment').value;
fetch('{{ url_for('user.update_user_department') }}', { fetch('{{ url_for('user.update_user_department') }}', {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -467,44 +506,73 @@
}, },
body: JSON.stringify({ body: JSON.stringify({
user_id: userId, user_id: userId,
name: newName,
department: newDepartment department: newDepartment
}) })
}) })
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) {
showMessage(data.message || '部门信息更新成功', true); // 关闭弹窗
closeModal('editDepartmentModal'); layer.close(layerIndex);
loadUsers(); // 重新加载用户列表
} else { // 显示成功消息,带图标和动画效果
showMessage(data.error || '部门信息更新失败', false); layer.msg(data.message || '部门信息更新成功', {
} icon: 1,
}) anim: 0,
.catch(error => { time: 2000,
console.error('更新部门信息时发生错误:', error); end: function() {
showMessage('网络错误,请稍后重试', false); // 重新加载用户列表
loadUsers();
}
});
} else {
// 显示错误消息,带图标和动画效果
layer.msg(data.error || '部门信息更新失败', {
icon: 5,
anim: 6,
time: 2000
});
}
})
.catch(error => {
console.error('更新部门信息时发生错误:', error);
// 显示网络错误消息,带图标和动画效果
layer.msg('网络错误,请稍后重试', {
icon: 5,
anim: 6,
time: 2000
}); });
});
} }
// 显示初始化密码弹窗 // 显示初始化密码弹窗(使用layui
function showResetPasswordModal(userId, username) { function showResetPasswordModal(userId, username) {
// 存储用户数据
document.getElementById('resetUserId').value = userId; document.getElementById('resetUserId').value = userId;
document.getElementById('resetUsername').value = username; document.getElementById('resetUsername').value = username;
document.getElementById('resetUserNameDisplay').textContent = username;
document.getElementById('resetPasswordModal').classList.remove('hidden'); // 打开layui确认弹窗
} layer.confirm(
`<div class="layui-text">
// 关闭初始化密码弹窗 <p>确定要初始化用户 <span style="font-weight: 500;">${username}</span> 的密码吗?</p>
function closeResetPasswordModal() { <p style="color: #666; margin-top: 10px;">初始化后,密码将重置为默认值:<code class="layui-code">default123</code></p>
document.getElementById('resetPasswordModal').classList.add('hidden'); </div>`,
{
title: '初始化密码',
btn: ['确定初始化', '取消'],
area: ['450px', '200px'],
btn1: function(index) {
confirmResetPassword(userId, username, index);
},
skin: 'layui-layer-molv'
}
);
} }
// 确认初始化密码 // 确认初始化密码
function confirmResetPassword() { function confirmResetPassword(userId, username, layerIndex) {
const userId = document.getElementById('resetUserId').value;
const username = document.getElementById('resetUsername').value;
fetch('{{ url_for('user.reset_user_password') }}', { fetch('{{ url_for('user.reset_user_password') }}', {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -517,24 +585,18 @@
}) })
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) {
showMessage(data.message || '密码初始化成功', true); showMessage(data.message || '密码初始化成功', true);
closeModal('resetPasswordModal'); layer.close(layerIndex); // 关闭弹窗
} else { } else {
showMessage(data.error || '密码初始化失败', false); showMessage(data.error || '密码初始化失败', false);
} }
}) })
.catch(error => { .catch(error => {
console.error('初始化密码时发生错误:', error); console.error('初始化密码时发生错误:', error);
showMessage('网络错误,请稍后重试', false); showMessage('网络错误,请稍后重试', false);
}); });
} }
</script> </script>
</body> </body>
</html> </html>