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
+323 -283
View File
@@ -4,56 +4,25 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>车主信息查询系统 - 查询</title>
<!-- 引入Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- 引入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 href="{{ url_for('static', filename='css/custom.css') }}" rel="stylesheet">
<!-- 引入Layui JS -->
<script src="{{ url_for('static', filename='layui.js') }}"></script>
<!-- 配置Tailwind CSS -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
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']
}
}
}
}
layui.use(['layer', 'form', 'table'], function(){
var layer = layui.layer;
var form = layui.form;
var table = layui.table;
});
</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 {
from {
opacity: 0;
@@ -66,148 +35,111 @@
}
</style>
</head>
<body class="bg-secondary min-h-screen font-sans">
<body>
<!-- 引入统一的顶部导航栏 -->
{% include 'header.html' %}
<!-- 主要内容区域 -->
<main class="container mx-auto px-4 pt-24 pb-12">
<!-- 消息提示区域 -->
{% if error %}
<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">
<i class="fa fa-exclamation-circle mt-1 mr-3"></i>
<span>{{ error }}</span>
</div>
{% endif %}
{% if success %}
<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-check-circle mt-1 mr-3"></i>
<span>{{ success }}</span>
</div>
{% endif %}
<!-- 最近查询记录 -->
{% if recent_queries %}
<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">
<i class="fa fa-history text-primary mr-2"></i> 最近查询记录
</h2>
<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-plus mr-1"></i> 增加
</button>
</div>
</h2>
<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>
<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">登录IP</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
{% for query in recent_queries %}
<tr class="table-hover cursor-pointer transition-all duration-200 hover:bg-primary-light/40" data-history-id="{{ query.id }}">
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ loop.index }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ query.query_date }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ query.plate_number }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ query.phone }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full
{% if query.results_count == -1 %}
bg-warning/10 text-warning
{% elif query.results_count > 0 %}
bg-success/10 text-success
{% else %}
bg-error/10 text-error
{% endif %}">
{% if query.results_count == -1 %}
待查询
{% else %}
{{ query.results_count }} 条记录
{% endif %}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ query.department }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ query.query_ip }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
</main>
<!-- 增加查询模态框 -->
<div id="addQueryModal" 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-md w-full">
<div class="flex justify-between items-center p-6 border-b">
<h3 class="text-xl font-semibold text-gray-800">增加查询记录</h3>
<button id="closeAddModal" class="text-gray-500 hover:text-gray-700 transition-colors">
<i class="fa fa-times text-xl"></i>
</button>
</div>
<div class="p-6">
<form id="addQueryForm">
<div class="mb-4">
<label for="add_plate_number" class="block text-sm font-medium text-gray-700 mb-1">车牌号</label>
<input type="text" id="add_plate_number" name="plate_number"
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 class="content-container">
<div class="content-wrapper">
<div class="card">
<div class="card-body">
<!-- 表单已清除 -->
<!-- 消息提示区域 -->
{% if error %}
<div class="error-message">
<i class="fa fa-exclamation-circle"></i> {{ error }}
</div>
{% endif %}
{% if success %}
<div class="success-message">
<i class="fa fa-check-circle"></i> {{ success }}
</div>
{% endif %}
<!-- 最近查询记录 -->
{% if recent_queries %}
<div class="card">
<div class="card-header">
<i class="fa fa-history"></i> 最近查询记录
<button id="addQueryBtn" class="layui-btn layui-btn-normal" style="
float: right;
padding: 6px 16px;
border-radius: 6px;
background-color: #009688;
border-color: #009688;
font-size: 14px;
font-weight: 500;
color: white;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: center;
gap: 5px;
">
<i class="fa fa-plus-circle"></i> 新增查询记录
</button>
</div>
<div class="card-body">
<table class="layui-table">
<thead>
<tr>
<th>序号</th>
<th>查询日期</th>
<th>车牌号</th>
<th>手机号</th>
<th>状态</th>
<th>登录部门</th>
<th>登录IP</th>
</tr>
</thead>
<tbody>
{% for query in recent_queries %}
<tr class="table-hover" data-history-id="{{ query.id }}">
<td>{{ loop.index }}</td>
<td>{{ query.query_date }}</td>
<td>{{ query.plate_number }}</td>
<td>{{ query.phone }}</td>
<td>
<span class="layui-badge
{% if query.results_count == -1 %}
layui-bg-orange
{% elif query.results_count > 0 %}
layui-bg-green
{% else %}
layui-bg-red
{% endif %}">
{% if query.results_count == -1 %}
待查询
{% else %}
{{ query.results_count }} 条记录
{% endif %}
</span>
</td>
<td>{{ query.department }}</td>
<td>{{ query.query_ip }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
</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 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 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 class="grid grid-cols-1 md:grid-cols-2 gap-6" id="carOwnerCards">
@@ -249,56 +181,222 @@
// 增加查询按钮点击事件
addQueryBtn.addEventListener('click', function() {
// 兼容classList API
if (addQueryModal.classList) {
addQueryModal.classList.remove('hidden');
} else {
addQueryModal.className = addQueryModal.className.replace('hidden', '');
}
addQueryForm.reset();
});
// 关闭增加查询模态框
closeAddModal.addEventListener('click', function() {
// 兼容classList API
if (addQueryModal.classList) {
addQueryModal.classList.add('hidden');
} else {
addQueryModal.className += ' hidden';
}
});
// 取消增加查询
cancelAddBtn.addEventListener('click', function() {
// 兼容classList API
if (addQueryModal.classList) {
addQueryModal.classList.add('hidden');
} else {
addQueryModal.className += ' hidden';
}
});
// 点击增加查询模态框背景关闭
addQueryModal.addEventListener('click', function(e) {
if (e.target === addQueryModal) {
// 兼容classList API
if (addQueryModal.classList) {
addQueryModal.classList.add('hidden');
} else {
addQueryModal.className += ' hidden';
// 使用layui创建增加查询记录弹窗,并美化设计
layer.open({
type: 1,
title: '<i class="fa fa-plus-circle"></i> 增加查询记录',
area: ['520px', '380px'],
offset: '10%',
shade: 0.3,
shadeClose: false,
anim: 2,
content: `
<div class="form-container" style="padding: 24px;">
<!-- 表单主体 -->
<form class="layui-form">
<!-- 车牌号输入框 -->
<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>
<div class="input-wrapper" style="position: relative;">
<input type="text" id="layui_add_plate_number"
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="请输入车牌号(如:京A123456"
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>
<!-- 手机号输入框 -->
<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) {
@@ -312,66 +410,8 @@
}
});
// 处理增加查询表单提交
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';
}
});
});
// 表单提交逻辑已整合到layui弹窗中,不需要单独的表单提交事件
// 加载查询历史详情
function loadHistoryDetail(historyId) {