Files
fzjg_local/fzjgact/huodong/templates/contact_list.html
xiaji b6704519ec feat(ui): 优化多个页面的UI设计和交互体验
重构公共电子屏、分支机构信息、设备间图片和活动统计页面的UI设计
- 添加渐变背景、阴影和悬停效果提升视觉体验
- 使用图标增强信息展示和交互提示
- 改进表格和卡片布局提高可读性
- 统一各页面的设计风格和交互模式
- 添加CSS组件类支持新的UI效果
2026-01-28 12:30:14 +08:00

438 lines
25 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block content %}
<!-- 页面标题 -->
<div class="w-full max-w-6xl mx-auto p-6">
<div class="relative flex items-center justify-center py-8">
<div class="absolute left-0 right-0 h-1 bg-gradient-to-r from-transparent via-teal-500 to-transparent"></div>
<div class="relative z-10 bg-gradient-to-r from-teal-600 to-cyan-700 text-white px-8 py-3 rounded-full shadow-lg">
<h1 class="text-xl font-bold flex items-center gap-3">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
联系人信息
</h1>
</div>
</div>
</div>
<div class="w-full max-w-6xl mx-auto p-6">
<!-- 筛选表单 -->
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-teal-100 mb-6">
<div class="px-6 py-4 bg-gradient-to-r from-teal-600 via-teal-700 to-cyan-700">
<h2 class="text-lg font-bold text-white flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
</svg>
筛选条件
</h2>
</div>
<div class="p-6">
<form method="GET" id="filterForm">
<div class="flex flex-wrap gap-4">
<!-- 分支机构筛选(带搜索的多选下拉框) -->
<div class="flex flex-col w-full md:w-1/2">
<label class="text-sm font-medium text-gray-700 mb-2 flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-teal-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
分支机构(可多选)
</label>
<div class="relative" id="branchSelectContainer">
<!-- 选择框主体 -->
<div class="relative">
<input
type="text"
id="branchSearchInput"
class="w-full pl-4 pr-10 py-2.5 border border-gray-200 rounded-lg focus:ring-2 focus:ring-teal-300 focus:border-teal-500 outline-none text-sm bg-gray-50 hover:bg-white transition-colors"
placeholder="点击选择分支机构(可多选)..."
readonly
onclick="toggleBranchDropdown()"
>
<span class="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 transition-transform duration-200" id="branchArrowIcon">
<i class="fa fa-chevron-down"></i>
</span>
<!-- 选中的机构显示 -->
<div id="selectedBranches" class="absolute z-5 mt-1 w-full bg-white rounded-lg shadow-md hidden max-h-32 overflow-y-auto">
<div class="p-2">
<div class="flex flex-wrap gap-1" id="branchTags"></div>
</div>
</div>
</div>
<!-- 下拉内容 -->
<div id="branchDropdownContent" class="absolute z-10 mt-1 w-full bg-white rounded-lg shadow-lg overflow-hidden hidden border border-gray-100">
<!-- 搜索输入框 -->
<div class="p-2 border-b border-gray-100">
<input
type="text"
id="branchFilterInput"
class="w-full px-3 py-2 border border-gray-200 rounded-lg focus:ring-1 focus:ring-teal-300 focus:border-teal-500 outline-none text-sm"
placeholder="搜索分支机构..."
oninput="filterBranchOptions()"
autofocus
>
</div>
<!-- 选项列表 -->
<div id="branchOptionsList" class="max-h-60 overflow-y-auto">
<ul>
{% for branch in branches %}
<li class="branch-option px-4 py-2.5 hover:bg-teal-50 cursor-pointer text-sm transition-colors flex items-center"
data-id="{{ branch.id }}"
data-name="{{ branch.name }}">
<input type="checkbox" class="mr-2 branch-checkbox rounded text-teal-600 focus:ring-teal-500" value="{{ branch.id }}">
{{ branch.name }}
</li>
{% endfor %}
</ul>
</div>
<!-- 操作按钮 -->
<div class="p-2 border-t border-gray-100 flex gap-2">
<button type="button" class="flex-1 px-3 py-1 text-xs bg-teal-500 text-white rounded hover:bg-teal-600 transition-colors" onclick="selectAllBranches()">全选</button>
<button type="button" class="flex-1 px-3 py-1 text-xs bg-red-500 text-white rounded hover:bg-red-600 transition-colors" onclick="clearAllBranches()">清空</button>
</div>
<!-- 独立的清空全部选择按钮 -->
<div class="p-2 border-t border-gray-100">
<button type="button" class="w-full px-3 py-2 text-sm bg-orange-500 text-white rounded-lg hover:bg-orange-600 font-medium transition-colors" onclick="clearAllBranches()" title="清空所有机构选择">
<i class="fa fa-refresh mr-1"></i>清空全部选择
</button>
</div>
<!-- 无结果提示 -->
<div id="branchNoResult" class="px-4 py-4 text-center text-gray-500 text-sm hidden">
没有找到匹配的分支机构
</div>
</div>
</div>
</div>
<!-- 联系人类别筛选 -->
<div class="flex flex-col w-full md:w-1/3">
<label class="text-sm font-medium text-gray-700 mb-2 flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-teal-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
</svg>
联系人类别
</label>
<input type="text" name="category" class="mt-1 p-2.5 border border-gray-200 rounded-lg focus:ring-2 focus:ring-teal-300 focus:border-teal-500 outline-none text-sm bg-gray-50 hover:bg-white transition-colors" placeholder="输入类别名称筛选" value="{{ selected_category|default:'' }}">
</div>
<!-- 联系人姓名筛选 -->
<div class="flex flex-col w-full md:w-1/3">
<label class="text-sm font-medium text-gray-700 mb-2 flex items-center gap-1">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-teal-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
联系人姓名
</label>
<input type="text" name="contact_name" class="mt-1 p-2.5 border border-gray-200 rounded-lg focus:ring-2 focus:ring-teal-300 focus:border-teal-500 outline-none text-sm bg-gray-50 hover:bg-white transition-colors" placeholder="输入联系人姓名筛选" value="{{ selected_contact_name|default:'' }}">
</div>
<div class="flex items-end gap-2">
<button type="submit" class="px-5 py-2.5 bg-gradient-to-r from-teal-600 to-teal-700 hover:from-teal-700 hover:to-teal-800 text-white rounded-lg shadow-md hover:shadow-lg transition-all duration-200 font-medium">
<i class="fa fa-search mr-1"></i>筛选
</button>
<button type="button" class="px-5 py-2.5 bg-gradient-to-r from-red-500 to-red-600 hover:from-red-600 hover:to-red-700 text-white rounded-lg shadow-md hover:shadow-lg transition-all duration-200 font-medium" onclick="clearFilters()">
<i class="fa fa-times mr-1"></i>清空筛选
</button>
</div>
</div>
<!-- 隐藏的分支机构ID输入框用于表单提交 -->
<input type="hidden" name="branches" id="selectedBranchesInput">
</form>
</div>
</div>
<!-- 联系人列表 -->
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-teal-100">
<div class="overflow-x-auto">
<table class="w-full border-collapse">
<thead>
<tr class="bg-gradient-to-r from-teal-50 to-cyan-50 border-b-2 border-teal-200">
<th class="px-6 py-4 text-left text-sm font-bold text-gray-700 uppercase tracking-wider">
<div class="flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-teal-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
分支机构
</div>
</th>
<th class="px-6 py-4 text-left text-sm font-bold text-gray-700 uppercase tracking-wider">
<div class="flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-teal-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
</svg>
分类
</div>
</th>
<th class="px-6 py-4 text-left text-sm font-bold text-gray-700 uppercase tracking-wider">
<div class="flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-teal-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
姓名
</div>
</th>
<th class="px-6 py-4 text-left text-sm font-bold text-gray-700 uppercase tracking-wider">
<div class="flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-teal-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
电话
</div>
</th>
<th class="px-6 py-4 text-left text-sm font-bold text-gray-700 uppercase tracking-wider">
<div class="flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-teal-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
邮箱
</div>
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
{% for contact in contacts %}
<tr class="{% cycle 'bg-white' 'bg-slate-50/50' %} hover:bg-teal-50/50 transition-colors duration-200">
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 font-medium">{{ contact.branch.name }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ contact.category|default:"-" }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">{{ contact.name|default:"-" }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ contact.phone|default:"-" }}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ contact.email|default:"-" }}</td>
</tr>
{% empty %}
<tr>
<td colspan="5" class="px-6 py-8 text-center text-gray-500">
<div class="flex flex-col items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>没有找到匹配的联系人</span>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- 导出按钮 -->
<div class="mt-6 flex justify-end">
<a href="{% url 'export-contacts-pdf' %}{% if request.GET.urlencode %}?{{ request.GET.urlencode }}{% endif %}" class="inline-flex items-center px-5 py-2.5 bg-gradient-to-r from-purple-600 to-purple-700 hover:from-purple-700 hover:to-purple-800 text-white font-medium rounded-lg shadow-md hover:shadow-lg transition-all duration-200">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
导出为PDF
</a>
</div>
</div>
<!-- 分隔线 -->
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-teal-400 to-transparent"></div>
<script>
// 选中的分支机构
let selectedBranches = new Set();
// 初始化页面
document.addEventListener('DOMContentLoaded', function() {
// 初始化选中的机构
initializeSelectedBranches();
// 绑定复选框事件
bindCheckboxEvents();
});
// 初始化选中的机构(从表单参数中读取)
function initializeSelectedBranches() {
const urlParams = new URLSearchParams(window.location.search);
const branchesParam = urlParams.get('branches');
if (branchesParam) {
const branchIds = branchesParam.split(',');
branchIds.forEach(id => {
selectedBranches.add(id);
const checkbox = document.querySelector(`input[value="${id}"]`);
if (checkbox) {
checkbox.checked = true;
}
});
}
updateBranchSelectionUI();
}
// 绑定复选框事件
function bindCheckboxEvents() {
document.querySelectorAll('.branch-checkbox').forEach(checkbox => {
checkbox.addEventListener('change', function() {
const branchId = this.value;
const branchName = this.closest('.branch-option').dataset.name;
if (this.checked) {
selectedBranches.add(branchId);
} else {
selectedBranches.delete(branchId);
}
updateBranchSelectionUI();
});
});
}
// 更新机构选择UI
function updateBranchSelectionUI() {
const selectedBranchesInput = document.getElementById('selectedBranchesInput');
const branchSearchInput = document.getElementById('branchSearchInput');
const selectedBranchesDiv = document.getElementById('selectedBranches');
const branchTags = document.getElementById('branchTags');
// 更新隐藏输入框
if (selectedBranches.size > 0) {
selectedBranchesInput.value = Array.from(selectedBranches).join(',');
branchSearchInput.placeholder = `已选择 ${selectedBranches.size} 个机构`;
} else {
selectedBranchesInput.value = '';
branchSearchInput.placeholder = '点击选择分支机构(可多选)...';
}
// 更新显示的标签
branchTags.innerHTML = '';
selectedBranches.forEach(branchId => {
const branchName = document.querySelector(`input[value="${branchId}"]`).closest('.branch-option').dataset.name;
const tag = document.createElement('span');
tag.className = 'inline-flex items-center px-2 py-1 rounded-full text-xs bg-blue-100 text-blue-800';
tag.innerHTML = `
${branchName}
<button type="button" class="ml-1 text-blue-600 hover:text-blue-800" onclick="removeBranch('${branchId}')">
<i class="fa fa-times"></i>
</button>
`;
branchTags.appendChild(tag);
});
// 控制选中机构显示区域
if (selectedBranches.size > 0) {
selectedBranchesDiv.classList.remove('hidden');
} else {
selectedBranchesDiv.classList.add('hidden');
}
}
// 移除机构
function removeBranch(branchId) {
selectedBranches.delete(branchId);
const checkbox = document.querySelector(`input[value="${branchId}"]`);
if (checkbox) {
checkbox.checked = false;
}
updateBranchSelectionUI();
}
// 全选分支机构
function selectAllBranches() {
selectedBranches.clear();
document.querySelectorAll('.branch-checkbox').forEach(checkbox => {
checkbox.checked = true;
selectedBranches.add(checkbox.value);
});
updateBranchSelectionUI();
}
// 清空所有分支机构选择
function clearAllBranches() {
selectedBranches.clear();
document.querySelectorAll('.branch-checkbox').forEach(checkbox => {
checkbox.checked = false;
});
updateBranchSelectionUI();
}
// 清空所有筛选
function clearFilters() {
// 清空所有表单字段
document.getElementById('filterForm').reset();
// 清空机构选择
clearAllBranches();
// 提交清空后的表单
window.location.href = window.location.pathname;
}
// 控制分支机构下拉框显示/隐藏
function toggleBranchDropdown() {
const dropdown = document.getElementById('branchDropdownContent');
const arrow = document.getElementById('branchArrowIcon');
if (dropdown.classList.contains('hidden')) {
dropdown.classList.remove('hidden');
arrow.classList.add('rotate-180');
document.getElementById('branchFilterInput').focus();
document.addEventListener('click', handleBranchOutsideClick);
} else {
closeBranchDropdown();
}
}
// 关闭分支机构下拉框
function closeBranchDropdown() {
const dropdown = document.getElementById('branchDropdownContent');
const arrow = document.getElementById('branchArrowIcon');
dropdown.classList.add('hidden');
arrow.classList.remove('rotate-180');
document.removeEventListener('click', handleBranchOutsideClick);
}
// 点击外部关闭下拉框
function handleBranchOutsideClick(event) {
const container = document.getElementById('branchSelectContainer');
if (!container.contains(event.target)) {
closeBranchDropdown();
}
}
// 筛选分支机构选项
function filterBranchOptions() {
const searchText = document.getElementById('branchFilterInput').value.toLowerCase();
const options = document.querySelectorAll('.branch-option');
const noResult = document.getElementById('branchNoResult');
let hasMatch = false;
options.forEach(option => {
const name = option.dataset.name.toLowerCase();
if (name.includes(searchText)) {
option.style.display = 'block';
hasMatch = true;
} else {
option.style.display = 'none';
}
});
// 显示或隐藏无结果提示
if (searchText && !hasMatch) {
noResult.classList.remove('hidden');
} else {
noResult.classList.add('hidden');
}
}
// 选择分支机构选项(保留原有功能以兼容单选操作)
document.querySelectorAll('.branch-option').forEach(option => {
option.addEventListener('click', function(e) {
// 如果点击的是复选框,不重复处理
if (e.target.type === 'checkbox') {
return;
}
const checkbox = this.querySelector('.branch-checkbox');
checkbox.checked = !checkbox.checked;
// 触发复选框的change事件
checkbox.dispatchEvent(new Event('change'));
});
});
</script>
{% endblock %}