Compare commits
17 Commits
9cbc90cc37
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 635ba67876 | |||
| 776ae36ede | |||
| 56ada564e0 | |||
| 2714d78f56 | |||
| 0a35884a09 | |||
| b6704519ec | |||
| 18314c9808 | |||
| 2b1331d9f0 | |||
| 4e9b5f5bd0 | |||
| dea365977e | |||
| 51f3b9241c | |||
| b99c2303e5 | |||
| 8eba3f0160 | |||
| 7c2095a52e | |||
| f86107ea5d | |||
| 26554c7f29 | |||
| 51286ae181 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -2,10 +2,8 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
*.pyc
|
||||
# Django stuff:
|
||||
db.sqlite3
|
||||
*.sqlite3
|
||||
media/
|
||||
|
||||
# IDE related
|
||||
|
||||
189
README.md
Normal file
189
README.md
Normal file
@@ -0,0 +1,189 @@
|
||||
# 分支机构活动管理系统
|
||||
|
||||
这是一个基于Django开发的分支机构活动管理系统,用于管理公司各分支机构的活动、人员、设备和预算等信息。
|
||||
|
||||
## 功能特点
|
||||
|
||||
- **分支机构管理**:维护分支机构的基本信息、联系方式、分类和状态
|
||||
- **活动管理**:记录分支机构的新建、搬迁、装修、撤销等活动信息
|
||||
- **联系人管理**:管理各分支机构的联系人信息及分类
|
||||
- **设备间图片管理**:上传和管理分支机构设备间的图片
|
||||
- **图纸管理**:上传和管理分支机构相关图纸
|
||||
- **预算管理**:管理活动预算、设备预算和基础设施预算
|
||||
- **终端设备管理**:管理视频终端等设备信息
|
||||
- **公共屏幕管理**:管理分支机构的公共屏幕信息
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **后端框架**:Django
|
||||
- **数据库**:SQLite
|
||||
- **前端技术**:HTML、CSS、Tailwind CSS
|
||||
- **表单处理**:Django Forms
|
||||
- **模板引擎**:Django Templates
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
fzjgact/
|
||||
├── fzjgact/ # 项目配置目录
|
||||
│ ├── __init__.py
|
||||
│ ├── asgi.py
|
||||
│ ├── settings.py
|
||||
│ ├── urls.py
|
||||
│ └── wsgi.py
|
||||
├── huodong/ # 主应用目录
|
||||
│ ├── migrations/ # 数据库迁移文件
|
||||
│ ├── static/ # 静态资源
|
||||
│ ├── templates/ # 模板文件
|
||||
│ ├── templatetags/ # 自定义模板标签
|
||||
│ ├── __init__.py
|
||||
│ ├── admin.py # 后台管理配置
|
||||
│ ├── apps.py # 应用配置
|
||||
│ ├── models.py # 数据模型
|
||||
│ ├── serializers.py # 序列化器
|
||||
│ ├── tests.py # 测试文件
|
||||
│ ├── urls.py # 应用路由
|
||||
│ └── views.py # 视图函数
|
||||
├── db.sqlite3 # 数据库文件
|
||||
├── manage.py # Django管理脚本
|
||||
├── tailwind.config.js # Tailwind CSS配置
|
||||
└── requirements.txt # 依赖文件(需创建)
|
||||
```
|
||||
|
||||
## 安装和运行
|
||||
|
||||
### 1. 环境要求
|
||||
|
||||
- Python 3.7+
|
||||
- Django 3.2+
|
||||
- 其他依赖(见requirements.txt)
|
||||
|
||||
### 2. 安装步骤
|
||||
|
||||
1. **克隆项目**
|
||||
|
||||
```bash
|
||||
git clone http://124.223.26.33:3000/xiaji/fzjg_local.git
|
||||
cd 分支机构活动
|
||||
```
|
||||
|
||||
2. **创建虚拟环境**
|
||||
|
||||
```bash
|
||||
python -m venv venv
|
||||
```
|
||||
|
||||
3. **激活虚拟环境**
|
||||
|
||||
- Windows:
|
||||
```bash
|
||||
venv\Scripts\activate
|
||||
```
|
||||
- Linux/Mac:
|
||||
```bash
|
||||
source venv/bin/activate
|
||||
```
|
||||
|
||||
4. **安装依赖**
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
5. **初始化数据库**
|
||||
|
||||
```bash
|
||||
cd fzjgact
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
6. **创建超级用户**
|
||||
|
||||
```bash
|
||||
python manage.py createsuperuser
|
||||
```
|
||||
|
||||
7. **启动开发服务器**
|
||||
|
||||
```bash
|
||||
python manage.py runserver
|
||||
```
|
||||
|
||||
### 3. 访问系统
|
||||
|
||||
- 后台管理:http://localhost:8000/admin
|
||||
- 前端页面:http://localhost:8000
|
||||
|
||||
## 使用说明
|
||||
|
||||
### 后台管理
|
||||
|
||||
1. 使用超级用户登录后台管理界面
|
||||
2. 可以管理以下模块:
|
||||
- 分支机构信息
|
||||
- 联系人管理
|
||||
- 活动记录
|
||||
- 设备间图片
|
||||
- 图纸管理
|
||||
- 预算信息
|
||||
- 公共屏幕
|
||||
- 视频终端
|
||||
|
||||
### 前端功能
|
||||
|
||||
1. **分支机构列表**:查看所有分支机构信息
|
||||
2. **分支机构详情**:查看分支机构的详细信息、联系人、活动等
|
||||
3. **设备间图片**:查看分支机构设备间的图片
|
||||
4. **公共屏幕**:查看公共屏幕信息
|
||||
5. **视频终端**:查看视频终端信息
|
||||
6. **统计信息**:查看系统统计数据
|
||||
|
||||
## 自定义命令
|
||||
|
||||
- `randomize_background_color`:为分支机构随机生成背景颜色
|
||||
|
||||
## 开发说明
|
||||
|
||||
### Tailwind CSS
|
||||
|
||||
项目使用Tailwind CSS进行样式开发:
|
||||
|
||||
1. 配置文件:`tailwind.config.js`
|
||||
2. 启动Tailwind开发服务器:
|
||||
```bash
|
||||
./tailwindcss-windows-x64.exe -i ./huodong/static/huodong/input.css -o ./huodong/static/huodong/output.css --watch
|
||||
```
|
||||
|
||||
### 数据模型
|
||||
|
||||
主要数据模型包括:
|
||||
- Branch(分支机构)
|
||||
- Contact(联系人)
|
||||
- Activity(活动)
|
||||
- EquipmentImage(设备间图片)
|
||||
- Drawing(图纸)
|
||||
- Budget(预算)
|
||||
- PublicScreen(公共屏幕)
|
||||
- VideoTerminal(视频终端)
|
||||
|
||||
## 许可证
|
||||
|
||||
[MIT License](LICENSE)
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.0
|
||||
- 初始版本
|
||||
- 实现基本的分支机构和活动管理功能
|
||||
|
||||
### v1.1
|
||||
- 增加联系人管理功能
|
||||
- 增加设备间图片管理
|
||||
|
||||
### v1.2
|
||||
- 增加图纸管理功能
|
||||
- 增加预算管理功能
|
||||
|
||||
### v1.3
|
||||
- 增加公共屏幕和视频终端管理
|
||||
- 优化界面样式
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
127
fzjgact/huodong/management/commands/update_provinces.py
Normal file
127
fzjgact/huodong/management/commands/update_provinces.py
Normal file
@@ -0,0 +1,127 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from openai import OpenAI
|
||||
from huodong.models import Branch
|
||||
import time
|
||||
import re
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Update branch provinces using AI API'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
client = OpenAI(
|
||||
base_url="https://integrate.api.nvidia.com/v1",
|
||||
api_key="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"
|
||||
)
|
||||
|
||||
def get_correct_province(branch_name, current_location, retry_count=0):
|
||||
prompt = f"""请根据以下分支机构名称,返回一个正确的中国省份名称(全称,如:浙江省、北京市、上海市、广东省等)。
|
||||
|
||||
分支机构名称:{branch_name}
|
||||
|
||||
要求:
|
||||
1. 只返回省份名称,不要包含任何其他文字
|
||||
2. 省份名称必须是中国的省级行政区全称
|
||||
3. 如果无法确定,返回None
|
||||
4. 不要被名称里含有的地名所影响
|
||||
例子一:
|
||||
分支机构名称:石家庄中山西路营业部
|
||||
返回:河北省
|
||||
例子二:
|
||||
分支机构名称:北京市海淀区营业部
|
||||
返回:北京市
|
||||
例子三:
|
||||
分支机构名称:奎屯北京东路营业部
|
||||
返回:新疆维吾尔自治区
|
||||
|
||||
"""
|
||||
|
||||
|
||||
try:
|
||||
completion = client.chat.completions.create(
|
||||
model="deepseek-ai/deepseek-r1",
|
||||
messages=[{"role": "user", "content": prompt}],
|
||||
temperature=0.3,
|
||||
top_p=0.7,
|
||||
max_tokens=100,
|
||||
stream=False
|
||||
)
|
||||
|
||||
message = completion.choices[0].message
|
||||
reasoning = getattr(message, "reasoning_content", None)
|
||||
content = message.content
|
||||
|
||||
if reasoning:
|
||||
self.stdout.write(f" 推理过程: {reasoning[:200]}...")
|
||||
|
||||
if content is None:
|
||||
if reasoning:
|
||||
self.stdout.write(f" content为None,尝试从推理过程提取...")
|
||||
|
||||
patterns = [
|
||||
r'(?:正确的(?:答案)?应该是|所以|因此|答案是|结果为)[::\s]*(北京市|天津市|上海市|重庆市|河北省|山西省|辽宁省|吉林省|黑龙江省|江苏省|浙江省|安徽省|福建省|江西省|山东省|河南省|湖北省|湖南省|广东省|海南省|四川省|贵州省|云南省|陕西省|甘肃省|青海省|台湾省|内蒙古自治区|广西壮族自治区|西藏自治区|宁夏回族自治区|新疆维吾尔自治区|香港特别行政区|澳门特别行政区)',
|
||||
r'(北京市|天津市|上海市|重庆市|河北省|山西省|辽宁省|吉林省|黑龙江省|江苏省|浙江省|安徽省|福建省|江西省|山东省|河南省|湖北省|湖南省|广东省|海南省|四川省|贵州省|云南省|陕西省|甘肃省|青海省|台湾省|内蒙古自治区|广西壮族自治区|西藏自治区|宁夏回族自治区|新疆维吾尔自治区|香港特别行政区|澳门特别行政区)'
|
||||
]
|
||||
|
||||
for pattern in patterns:
|
||||
match = re.search(pattern, reasoning)
|
||||
if match:
|
||||
result = match.group(1)
|
||||
self.stdout.write(f" 从推理提取结果: {result}")
|
||||
return result
|
||||
|
||||
if retry_count < 2:
|
||||
self.stdout.write(f" content为None,重试中 ({retry_count + 1}/2)...")
|
||||
time.sleep(2)
|
||||
return get_correct_province(branch_name, current_location, retry_count + 1)
|
||||
else:
|
||||
self.stdout.write(self.style.WARNING(f" 多次重试后仍无结果,使用当前省份"))
|
||||
return current_location
|
||||
|
||||
result = content.strip()
|
||||
self.stdout.write(f" 原始结果: {result}")
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
if retry_count < 2:
|
||||
self.stdout.write(self.style.WARNING(f" API调用失败: {e},重试中 ({retry_count + 1}/2)..."))
|
||||
time.sleep(2)
|
||||
return get_correct_province(branch_name, current_location, retry_count + 1)
|
||||
else:
|
||||
self.stdout.write(self.style.ERROR(f" 多次重试后仍失败: {e},使用当前省份"))
|
||||
return current_location
|
||||
|
||||
branches = Branch.objects.all()
|
||||
total = branches.count()
|
||||
updated_count = 0
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f"开始处理 {total} 个分支机构..."))
|
||||
self.stdout.write("=" * 80)
|
||||
|
||||
for index, branch in enumerate(branches, 1):
|
||||
self.stdout.write(f"\n[{index}/{total}] 处理: {branch.name}")
|
||||
self.stdout.write(f"当前省份: {branch.location}")
|
||||
|
||||
try:
|
||||
correct_province = get_correct_province(branch.name, branch.location)
|
||||
self.stdout.write(f"建议省份: {correct_province}")
|
||||
|
||||
if correct_province != branch.location:
|
||||
old_location = branch.location
|
||||
branch.location = correct_province
|
||||
branch.save()
|
||||
self.stdout.write(self.style.SUCCESS(f"✓ 已更新: {old_location} -> {correct_province}"))
|
||||
updated_count += 1
|
||||
else:
|
||||
self.stdout.write("- 省份未变化")
|
||||
|
||||
except Exception as e:
|
||||
self.stdout.write(self.style.ERROR(f"✗ 处理失败: {e}"))
|
||||
|
||||
self.stdout.write("-" * 80)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f"\n处理完成!"))
|
||||
self.stdout.write(f"总计: {total} 个分支机构")
|
||||
self.stdout.write(f"已更新: {updated_count} 个")
|
||||
self.stdout.write(f"未变化: {total - updated_count} 个")
|
||||
@@ -33,7 +33,8 @@ class Contact(models.Model):
|
||||
('机房/设备间巡检人', '机房/设备间巡检人'),
|
||||
('信息安全联系人', '信息安全联系人'),
|
||||
('兼岗', '兼岗'),
|
||||
('安全员', '安全员')
|
||||
('安全员', '安全员'),
|
||||
('合规管理人', '合规管理人')
|
||||
# 可以添加更多类别
|
||||
]
|
||||
# 修改为支持多选的 CharField
|
||||
@@ -64,6 +65,7 @@ class Activity(models.Model):
|
||||
('搬迁', '搬迁'),
|
||||
('原址装修', '原址装修'),
|
||||
('撤销', '撤销'),
|
||||
('变更', '变更'),
|
||||
('其他技术问题', '其他技术问题')
|
||||
|
||||
), verbose_name='活动类型')
|
||||
|
||||
@@ -1,3 +1,37 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer components {
|
||||
.card-gradient {
|
||||
@apply bg-gradient-to-br from-white via-blue-50/30 to-blue-100/50;
|
||||
}
|
||||
|
||||
.card-gradient-early {
|
||||
@apply bg-gradient-to-br from-emerald-50 via-white to-teal-100/50;
|
||||
}
|
||||
|
||||
.card-gradient-latest {
|
||||
@apply bg-gradient-to-br from-amber-50 via-white to-orange-100/50;
|
||||
}
|
||||
|
||||
.table-header-gradient {
|
||||
@apply bg-gradient-to-r from-blue-600 via-blue-700 to-indigo-700;
|
||||
}
|
||||
|
||||
.hover-lift {
|
||||
@apply transition-all duration-300 hover:-translate-y-1 hover:shadow-xl;
|
||||
}
|
||||
|
||||
.timeline-dot {
|
||||
@apply absolute top-1/2 w-5 h-5 rounded-full transform -translate-y-1/2 border-4 border-white shadow-lg;
|
||||
}
|
||||
|
||||
.glass-effect {
|
||||
@apply backdrop-blur-sm bg-white/80;
|
||||
}
|
||||
|
||||
.section-divider {
|
||||
@apply h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-blue-400 to-transparent;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,101 +1,101 @@
|
||||
<!DOCTYPE html>
|
||||
{% load static %}
|
||||
{% load custom_filters %}
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="{% static 'huodong/output.css' %}">
|
||||
<title>分支机构活动管理</title>
|
||||
<script src="https://unpkg.com/alpinejs@3.14.1/dist/cdn.min.js" defer></script>
|
||||
</head>
|
||||
<body class="font-sans text-gray-900">
|
||||
|
||||
<!-- 顶部标题 -->
|
||||
<header class="bg-gray-50 dark:bg-gray-800 dark:border-gray-700 p-4 text-center text-xl font-bold">
|
||||
分支机构活动管理
|
||||
<br>
|
||||
2025年
|
||||
</header>
|
||||
|
||||
<!-- 主体内容:左右两侧栏布局 -->
|
||||
<div class="flex">
|
||||
<!-- 左侧边栏 -->
|
||||
<aside class="w-27 bg-gray-300 p-4 ">
|
||||
{% block sidebar %}
|
||||
<ul class="flex flex-col space-y-8 text-lg">
|
||||
{% if request.resolver_match.view_name != 'branch-all' %}
|
||||
<li>
|
||||
<a href="{% url 'branch-all' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
返回首页
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a href="{% url 'branchinfo' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
系统类型
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'statistics' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
活动的统计数据
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'contact-list' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
联系人信息
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'equipment-images' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
设备间图片列表
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'public-screens' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
公共电子屏列表
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'video-terminals' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
视频设备终端
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/admin/" class="bg-gradient-to-r from-gray-700 to-gray-900 hover:from-gray-800 hover:to-black text-white p-3 rounded-md font-medium shadow-lg transition-all duration-300 flex items-center justify-between border-l-4 border-amber-500" target="_blank">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3 text-amber-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3zM6 8a2 2 0 11-4 0 2 2 0 014 0zM16 18v-3a5.972 5.972 0 00-.75-2.906A3.005 3.005 0 0119 15v3h-3zM4.75 12.094A5.973 5.973 0 004 15v3H1v-3a3 3 0 013.75-2.906z" />
|
||||
</svg>
|
||||
<span>后台管理</span>
|
||||
</div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-amber-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
||||
</aside>
|
||||
|
||||
<!-- 主要内容区域 -->
|
||||
<main class="flex-1 bg-white p-4">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
|
||||
<!-- 右侧边栏 -->
|
||||
<!-- 注意:如果需要右侧边栏,请取消下方注释,并相应调整主内容区域的宽度 -->
|
||||
<!-- <aside class="w-1/3 bg-gray-300 p-4">
|
||||
Right Sidebar
|
||||
</aside> -->
|
||||
</div>
|
||||
|
||||
<!-- 页脚 -->
|
||||
<footer class="bg-gray-200 p-4 text-center mt-4">
|
||||
© 2025 My Website. All rights reserved.
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
<!DOCTYPE html>
|
||||
{% load static %}
|
||||
{% load custom_filters %}
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="{% static 'huodong/output.css' %}">
|
||||
<title>分支机构活动管理</title>
|
||||
<script src="https://unpkg.com/alpinejs@3.14.1/dist/cdn.min.js" defer></script>
|
||||
</head>
|
||||
<body class="font-sans text-gray-900">
|
||||
|
||||
<!-- 顶部标题 -->
|
||||
<header class="bg-gray-50 dark:bg-gray-800 dark:border-gray-700 p-4 text-center text-xl font-bold">
|
||||
分支机构活动管理 {{ ''|get_current_year }}年
|
||||
<br>
|
||||
<small>统计周期:{{ ''|get_statistic_period }}</small>
|
||||
</header>
|
||||
|
||||
<!-- 主体内容:左右两侧栏布局 -->
|
||||
<div class="flex">
|
||||
<!-- 左侧边栏 -->
|
||||
<aside class="w-27 bg-gray-300 p-4 ">
|
||||
{% block sidebar %}
|
||||
<ul class="flex flex-col space-y-8 text-lg">
|
||||
{% if request.resolver_match.view_name != 'branch-all' %}
|
||||
<li>
|
||||
<a href="{% url 'branch-all' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
返回首页
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<a href="{% url 'branchinfo' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
系统类型
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'statistics' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
活动的统计数据
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'contact-list' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
联系人信息
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'equipment-images' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
设备间图片列表
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'public-screens' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
公共电子屏列表
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url 'video-terminals' %}" class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
视频设备终端
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/admin/" class="bg-gradient-to-r from-gray-700 to-gray-900 hover:from-gray-800 hover:to-black text-white p-3 rounded-md font-medium shadow-lg transition-all duration-300 flex items-center justify-between border-l-4 border-amber-500" target="_blank">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-3 text-amber-400" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3zM6 8a2 2 0 11-4 0 2 2 0 014 0zM16 18v-3a5.972 5.972 0 00-.75-2.906A3.005 3.005 0 0119 15v3h-3zM4.75 12.094A5.973 5.973 0 004 15v3H1v-3a3 3 0 013.75-2.906z" />
|
||||
</svg>
|
||||
<span>后台管理</span>
|
||||
</div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-amber-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
||||
</aside>
|
||||
|
||||
<!-- 主要内容区域 -->
|
||||
<main class="flex-1 bg-white p-4">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
|
||||
<!-- 右侧边栏 -->
|
||||
<!-- 注意:如果需要右侧边栏,请取消下方注释,并相应调整主内容区域的宽度 -->
|
||||
<!-- <aside class="w-1/3 bg-gray-300 p-4">
|
||||
Right Sidebar
|
||||
</aside> -->
|
||||
</div>
|
||||
|
||||
<!-- 页脚 -->
|
||||
<footer class="bg-gray-200 p-4 text-center mt-4">
|
||||
© 2025 My Website. All rights reserved.
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,304 +2,478 @@
|
||||
{% load custom_filters %}
|
||||
|
||||
{% block content %}
|
||||
<div class="w-full max-w-4xl mx-auto p-6">
|
||||
<div class="relative">
|
||||
<!-- 时间线 -->
|
||||
<div class="absolute top-1/2 left-0 right-0 h-0.5 bg-blue-500 transform -translate-y-1/2"></div>
|
||||
<!-- 时间线区域 -->
|
||||
<div class="w-full max-w-5xl mx-auto p-6">
|
||||
<div class="relative py-8">
|
||||
<!-- 时间线背景 -->
|
||||
<div class="absolute top-1/2 left-0 right-0 h-1 bg-gradient-to-r from-emerald-400 via-blue-500 to-amber-400 rounded-full transform -translate-y-1/2 shadow-sm"></div>
|
||||
|
||||
<div class="relative z-10 flex justify-between items-center">
|
||||
<!-- 第一个卡片 -->
|
||||
<div class="w-[calc(50%-2rem)] bg-white rounded-lg shadow-lg overflow-hidden transition-all duration-300 hover:shadow-xl">
|
||||
<div class="relative z-10 flex justify-between items-center gap-6">
|
||||
<!-- 第一个卡片 - 最初活动 -->
|
||||
<div class="w-[calc(50%-2.5rem)] group">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden transition-all duration-500 hover:shadow-2xl hover:-translate-y-2 border border-emerald-100">
|
||||
<div class="h-1.5 bg-gradient-to-r from-emerald-400 to-teal-500"></div>
|
||||
<div class="p-6 flex flex-col h-full">
|
||||
<div class="flex-grow">
|
||||
<div class="text-xs font-semibold text-blue-600 mb-2">最初活动</div>
|
||||
<h3 class="text-xl font-bold mb-3 text-gray-800">{{ earliest_act.branch }}{{ earliest_act.name }}</h3>
|
||||
<p class="text-sm text-gray-600 mb-4">
|
||||
{{ earliest_act.description }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<span class="inline-flex items-center rounded-full bg-blue-100 px-3 py-1 text-xs font-medium text-blue-800 whitespace-nowrap">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="mr-1.5 h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-emerald-100 text-emerald-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
{{ earliest_act.start_time|format_chinese_full_date }}
|
||||
</span>
|
||||
<span class="text-xs font-bold text-emerald-600 uppercase tracking-wider">最初活动</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中间的箭头 -->
|
||||
<div class="bg-white rounded-full p-3 shadow-md z-20">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- 第二个卡片 -->
|
||||
<div class="w-[calc(50%-2rem)] bg-white rounded-lg shadow-lg overflow-hidden transition-all duration-300 hover:shadow-xl">
|
||||
<div class="p-6 flex flex-col h-full">
|
||||
<div class="flex-grow">
|
||||
<div class="text-xs font-semibold text-blue-600 mb-2">最后活动</div>
|
||||
<h3 class="text-xl font-bold mb-3 text-gray-800">{{ latest_act.branch }}{{ latest_act.name }}</h3>
|
||||
<p class="text-sm text-gray-600 mb-4">
|
||||
{{ latest_act.description }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<span class="inline-flex items-center rounded-full bg-blue-100 px-3 py-1 text-xs font-medium text-blue-800 whitespace-nowrap">
|
||||
<h3 class="text-lg font-bold mb-2 text-gray-800 group-hover:text-emerald-700 transition-colors">{{ earliest_act.branch }}{{ earliest_act.name }}</h3>
|
||||
<p class="text-sm text-gray-600 mb-4 line-clamp-3">
|
||||
{{ earliest_act.description }}
|
||||
</p>
|
||||
<div class="mt-auto pt-3 border-t border-emerald-100">
|
||||
<span class="inline-flex items-center text-xs font-medium text-emerald-700 bg-emerald-50 px-3 py-1.5 rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="mr-1.5 h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
{{ latest_act.start_time|format_chinese_full_date }} </span>
|
||||
{{ earliest_act.start_time|format_chinese_full_date }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 装饰元素 -->
|
||||
<div class="absolute top-1/2 left-0 w-4 h-4 bg-blue-500 rounded-full transform -translate-y-1/2 border-4 border-white"></div>
|
||||
<div class="absolute top-1/2 right-0 w-4 h-4 bg-blue-500 rounded-full transform -translate-y-1/2 border-4 border-white"></div>
|
||||
<!-- 中间的箭头 -->
|
||||
<div class="flex-shrink-0 bg-white rounded-full p-4 shadow-lg z-20 border-2 border-blue-100 hover:scale-110 transition-transform duration-300">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- 第二个卡片 - 最后活动 -->
|
||||
<div class="w-[calc(50%-2.5rem)] group">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden transition-all duration-500 hover:shadow-2xl hover:-translate-y-2 border border-amber-100">
|
||||
<div class="h-1.5 bg-gradient-to-r from-amber-400 to-orange-500"></div>
|
||||
<div class="p-6 flex flex-col h-full">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-amber-100 text-amber-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="text-xs font-bold text-amber-600 uppercase tracking-wider">最后活动</span>
|
||||
</div>
|
||||
<h3 class="text-lg font-bold mb-2 text-gray-800 group-hover:text-amber-700 transition-colors">{{ latest_act.branch }}{{ latest_act.name }}</h3>
|
||||
<p class="text-sm text-gray-600 mb-4 line-clamp-3">
|
||||
{{ latest_act.description }}
|
||||
</p>
|
||||
<div class="mt-auto pt-3 border-t border-amber-100">
|
||||
<span class="inline-flex items-center text-xs font-medium text-amber-700 bg-amber-50 px-3 py-1.5 rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="mr-1.5 h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
{{ latest_act.start_time|format_chinese_full_date }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 装饰元素 -->
|
||||
<div class="absolute top-1/2 left-0 w-6 h-6 bg-gradient-to-br from-emerald-400 to-emerald-600 rounded-full transform -translate-y-1/2 -translate-x-1/2 border-4 border-white shadow-lg"></div>
|
||||
<div class="absolute top-1/2 right-0 w-6 h-6 bg-gradient-to-br from-amber-400 to-orange-500 rounded-full transform -translate-y-1/2 translate-x-1/2 border-4 border-white shadow-lg"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<table class="items-center bg-transparent w-full border-collapse ">
|
||||
<thead>
|
||||
<tr class="bg-gray-100">
|
||||
<th class="px-6 bg-blueGray-50 text-blueGray-500 align-middle border border-solid border-blueGray-100 py-3 text-base uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left">
|
||||
分支机构名称
|
||||
<br>
|
||||
新建-搬迁-装修
|
||||
</th>
|
||||
<th class="px-6 bg-blueGray-50 text-blueGray-500 align-middle border border-solid border-blueGray-100 py-3 text-base uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-right">
|
||||
活动的总数量
|
||||
</th>
|
||||
<th class="px-6 bg-blueGray-50 text-blueGray-500 align-middle border border-solid border-blueGray-100 py-3 text-base uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-right">
|
||||
活动进行中的数量
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in branches %}
|
||||
<!-- 这里是其他行的处理逻辑 -->
|
||||
<tr class="{% if forloop.counter|divisibleby:2 %}bg-gray-100{% else %}bg-white{% endif %}">
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-left border-b border-gray-200">
|
||||
<a href="{% url 'branch-detail' item.branch.pk %}"
|
||||
class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
{{ item.branch.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-right">
|
||||
{{ item.total_count }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-right">
|
||||
{{ item.onging_count }}
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<!-- 这里是最后一行的处理逻辑 -->
|
||||
<tr>
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-left border-b border-gray-200 font-bold text-center">
|
||||
总计: {{ total_branch_count }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-right">
|
||||
{{ total_activities }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-right">
|
||||
{{ ongoing_activities_count }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<hr class="h-px my-8 bg-red-500 border-1 dark:bg-red-700">
|
||||
|
||||
|
||||
<!--插入事件-->
|
||||
<div class="p-5 border border-gray-100 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700">
|
||||
<time class="text-lg font-semibold text-gray-900 dark:text-white">事件</time>
|
||||
<ol class="mt-3 divide-y divider-gray-200 dark:divide-gray-700">
|
||||
{% for event in ongoing_events %}
|
||||
<li>
|
||||
<div href="#" class="items-center block p-3 sm:flex hover:bg-gray-100 dark:hover:bg-gray-700">
|
||||
<div class="text-gray-600 dark:text-gray-400">
|
||||
<span class="inline-flex items-center text-xs font-normal text-gray-400 dark:text-gray-400">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
||||
class="w-2.5 h-2.5 text-blue-800 dark:text-blue-300">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15.75 9V5.25A2.25 2.25 0 0 0 13.5 3h-6a2.25 2.25 0 0 0-2.25 2.25v13.5A2.25 2.25 0 0 0 7.5 21h6a2.25 2.25 0 0 0 2.25-2.25V15m3 0 3-3m0 0-3-3m3 3H9"/>
|
||||
</svg>
|
||||
开始时间 {{ event.start_time| date:"Y年m月d日" }}
|
||||
</span>
|
||||
<div class="text-base font-normal">
|
||||
<span class="font-medium text-gray-900 dark:text-white">
|
||||
{% if not event.end_time %}
|
||||
<span class="text-lg font-semibold text-red-900 dark:text-white">
|
||||
{{ event.name }}-未完成
|
||||
<!-- 统计表格 -->
|
||||
<div class="w-full max-w-5xl mx-auto p-6">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-gray-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-blue-600 via-blue-700 to-indigo-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="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||
</svg>
|
||||
分支机构活动统计
|
||||
</h2>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="bg-gradient-to-r from-slate-50 to-gray-100 border-b-2 border-blue-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-blue-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>
|
||||
分支机构名称
|
||||
<span class="text-xs font-normal text-gray-500 normal-case">(新建-搬迁-装修)</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="px-6 py-4 text-right text-sm font-bold text-gray-700 uppercase tracking-wider">
|
||||
<div class="flex items-center justify-end gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||
</svg>
|
||||
活动总数
|
||||
</div>
|
||||
</th>
|
||||
<th class="px-6 py-4 text-right text-sm font-bold text-gray-700 uppercase tracking-wider">
|
||||
<div class="flex items-center justify-end gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
进行中
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100">
|
||||
{% for item in branches %}
|
||||
<tr class="{% if forloop.counter|divisibleby:2 %}bg-slate-50/50{% else %}bg-white{% endif %} hover:bg-blue-50 transition-colors duration-200 group">
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<a href="{% url 'branch-detail' item.branch.pk %}"
|
||||
class="inline-flex items-center px-3 py-1.5 rounded-lg text-sm font-medium text-gray-700 bg-gray-100 hover:bg-blue-600 hover:text-white transition-all duration-200 group-hover:shadow-md">
|
||||
{{ item.branch.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right">
|
||||
<span class="inline-flex items-center justify-center min-w-[2rem] px-2.5 py-1 rounded-full text-sm font-semibold {% if item.total_count > 0 %}bg-blue-100 text-blue-700{% else %}bg-gray-100 text-gray-500{% endif %}">
|
||||
{{ item.total_count }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="text-lg font-semibold text-blue-900 dark:text-white">
|
||||
{{ event.name }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right">
|
||||
<span class="inline-flex items-center justify-center min-w-[2rem] px-2.5 py-1 rounded-full text-sm font-semibold {% if item.onging_count > 0 %}bg-green-100 text-green-700{% else %}bg-gray-100 text-gray-500{% endif %}">
|
||||
{{ item.onging_count }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<!-- 总计行 -->
|
||||
<tr class="bg-gradient-to-r from-blue-50 to-indigo-50 border-t-2 border-blue-200">
|
||||
<td class="px-6 py-4 whitespace-nowrap font-bold text-gray-800">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-blue-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
|
||||
</svg>
|
||||
总计 ({{ total_branch_count }} 个分支机构)
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right">
|
||||
<span class="inline-flex items-center justify-center min-w-[2.5rem] px-3 py-1.5 rounded-full text-base font-bold bg-blue-600 text-white shadow-md">
|
||||
{{ total_activities }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-right">
|
||||
<span class="inline-flex items-center justify-center min-w-[2.5rem] px-3 py-1.5 rounded-full text-base font-bold {% if ongoing_activities_count > 0 %}bg-green-500 text-white{% else %}bg-gray-400 text-white{% endif %} shadow-md">
|
||||
{{ ongoing_activities_count }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-purple-400 to-transparent"></div>
|
||||
|
||||
<!-- 事件列表 -->
|
||||
<div class="w-full max-w-5xl mx-auto p-6">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-purple-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-purple-600 via-purple-700 to-indigo-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="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
事件列表
|
||||
<span class="ml-auto text-sm font-normal bg-white/20 px-3 py-1 rounded-full">{{ ongoing_events|length }} 个事件</span>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="divide-y divide-gray-100">
|
||||
{% for event in ongoing_events %}
|
||||
<div class="p-5 hover:bg-purple-50/50 transition-colors duration-200 group">
|
||||
<div class="flex flex-col sm:flex-row sm:items-start gap-4">
|
||||
<!-- 时间轴标记 -->
|
||||
<div class="flex-shrink-0 flex flex-col items-center">
|
||||
<div class="w-10 h-10 rounded-full {% if not event.end_time %}bg-gradient-to-br from-red-400 to-red-600{% else %}bg-gradient-to-br from-purple-400 to-purple-600{% endif %} flex items-center justify-center text-white shadow-md">
|
||||
<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="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 内容 -->
|
||||
<div class="flex-grow min-w-0">
|
||||
<div class="flex flex-wrap items-center gap-2 mb-2">
|
||||
<h3 class="text-lg font-bold {% if not event.end_time %}text-red-700{% else %}text-gray-800{% endif %} group-hover:text-purple-700 transition-colors">
|
||||
{{ event.name }}{% if not event.end_time %}<span class="ml-2 text-sm font-medium text-red-500 bg-red-100 px-2 py-0.5 rounded-full">进行中</span>{% endif %}
|
||||
</h3>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 mb-3 line-clamp-2">{{ event.description }}</p>
|
||||
<div class="flex flex-wrap items-center gap-4 text-xs text-gray-500">
|
||||
<span class="inline-flex items-center gap-1 bg-blue-50 text-blue-700 px-2.5 py-1 rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
{{ event.start_time|date:"Y年m月d日" }}
|
||||
</span>
|
||||
{% if event.end_time %}
|
||||
<span class="inline-flex items-center gap-1 bg-green-50 text-green-700 px-2.5 py-1 rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
{{ event.end_time|date:"Y年m月d日" }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-sm font-normal">
|
||||
{{ event.description }}
|
||||
</div>
|
||||
<div class="text-sm font-normal">
|
||||
{% with branch_count=event.branches.count %}
|
||||
{% if branch_count == all_branch_count %}
|
||||
涉及分支机构:全辖分支机构
|
||||
{% elif branch_count == 1 %}
|
||||
涉及分支机构:{{ event.branches.first.name }}
|
||||
{% elif branch_count > 1 %}
|
||||
涉及分支机构:{{ event.branches.all.0.name }}、{{ event.branches.all.1.name }}等{{ branch_count }}个营业部
|
||||
{% else %}
|
||||
涉及分支机构:暂无
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
<span class="inline-flex items-center text-xs font-normal text-gray-400 dark:text-gray-400">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
||||
class="w-2.5 h-2.5 text-blue-800 dark:text-blue-300">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15.75 9V5.25A2.25 2.25 0 0 0 13.5 3h-6a2.25 2.25 0 0 0-2.25 2.25v13.5A2.25 2.25 0 0 0 7.5 21h6a2.25 2.25 0 0 0 2.25-2.25V15m3 0 3-3m0 0-3-3m3 3H9"/>
|
||||
</svg>
|
||||
结束时间 {{ event.end_time| date:"Y年m月d日" }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<hr class="h-px my-8 bg-red-500 border-1 dark:bg-red-700">
|
||||
|
||||
|
||||
<div class="p-5 border border-gray-100 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700">
|
||||
<time class="text-lg font-semibold text-gray-900 dark:text-white">活动中的</time>
|
||||
<ol class="mt-3 divide-y divider-gray-200 dark:divide-gray-700">
|
||||
{% for huodong in ongoing_activities %}
|
||||
<li>
|
||||
<div href="#" class="items-center block p-3 sm:flex hover:bg-gray-100 dark:hover:bg-gray-700">
|
||||
<div class="text-gray-600 dark:text-gray-400">
|
||||
<span class="inline-flex items-center text-xs font-normal text-gray-400 dark:text-gray-400">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
||||
class="w-2.5 h-2.5 text-blue-800 dark:text-blue-300">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15.75 9V5.25A2.25 2.25 0 0 0 13.5 3h-6a2.25 2.25 0 0 0-2.25 2.25v13.5A2.25 2.25 0 0 0 7.5 21h6a2.25 2.25 0 0 0 2.25-2.25V15m3 0 3-3m0 0-3-3m3 3H9"/>
|
||||
</svg>
|
||||
开始时间 {{ huodong.start_time| date:"Y年m月d日" }}
|
||||
</span>
|
||||
<div class="text-base font-normal">
|
||||
<span class="font-medium text-gray-900 dark:text-white">
|
||||
{% if not huodong.end_time %}
|
||||
<span class="text-lg font-semibold text-red-900 dark:text-white">
|
||||
<a href="{% url 'branch-detail' huodong.branch.pk %}"
|
||||
class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
{{ huodong.branch }}
|
||||
</a>
|
||||
{{ huodong.name }}-未完成
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-sm font-normal">
|
||||
{{ huodong.description }}
|
||||
</div>
|
||||
<div class="mt-3 text-sm text-gray-600">
|
||||
{% with branch_count=event.branches.count %}
|
||||
{% if branch_count == all_branch_count %}
|
||||
<span class="inline-flex items-center gap-1 text-purple-700 bg-purple-50 px-2.5 py-1 rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" 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>
|
||||
涉及:全辖分支机构
|
||||
</span>
|
||||
{% elif branch_count == 1 %}
|
||||
<span class="inline-flex items-center gap-1 text-blue-700 bg-blue-50 px-2.5 py-1 rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" 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>
|
||||
涉及:{{ event.branches.first.name }}
|
||||
</span>
|
||||
{% elif branch_count > 1 %}
|
||||
<span class="inline-flex items-center gap-1 text-blue-700 bg-blue-50 px-2.5 py-1 rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" 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>
|
||||
涉及:{{ event.branches.all.0.name }}、{{ event.branches.all.1.name }}等{{ branch_count }}个营业部
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="inline-flex items-center gap-1 text-gray-500 bg-gray-100 px-2.5 py-1 rounded-full">
|
||||
涉及:暂无
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
{% empty %}
|
||||
<div class="p-8 text-center text-gray-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-3 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
暂无事件
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="h-px my-8 bg-gray-200 border-0 dark:bg-gray-700">
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-orange-400 to-transparent"></div>
|
||||
|
||||
<!-- 活动中的列表 -->
|
||||
<div class="w-full max-w-5xl mx-auto p-6">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-orange-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-orange-500 via-orange-600 to-red-600">
|
||||
<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="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
进行中的活动
|
||||
<span class="ml-auto text-sm font-normal bg-white/20 px-3 py-1 rounded-full">{{ ongoing_activities|length }} 个活动</span>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="divide-y divide-gray-100">
|
||||
{% for huodong in ongoing_activities %}
|
||||
<div class="p-5 hover:bg-orange-50/50 transition-colors duration-200 group">
|
||||
<div class="flex flex-col sm:flex-row sm:items-start gap-4">
|
||||
<!-- 状态标记 -->
|
||||
<div class="flex-shrink-0">
|
||||
<div class="w-10 h-10 rounded-full bg-gradient-to-br from-red-400 to-red-600 flex items-center justify-center text-white shadow-md">
|
||||
<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="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 内容 -->
|
||||
<div class="flex-grow min-w-0">
|
||||
<div class="flex flex-wrap items-center gap-2 mb-2">
|
||||
<a href="{% url 'branch-detail' huodong.branch.pk %}"
|
||||
class="inline-flex items-center px-2.5 py-1 rounded-lg text-sm font-medium bg-orange-100 text-orange-700 hover:bg-orange-600 hover:text-white transition-colors">
|
||||
{{ huodong.branch }}
|
||||
</a>
|
||||
<h3 class="text-lg font-bold text-red-700 group-hover:text-red-800 transition-colors">
|
||||
{{ huodong.name }}
|
||||
</h3>
|
||||
<span class="text-xs font-medium text-white bg-red-500 px-2 py-0.5 rounded-full">未完成</span>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 mb-3 line-clamp-2">{{ huodong.description }}</p>
|
||||
<div class="flex flex-wrap items-center gap-4 text-xs text-gray-500">
|
||||
<span class="inline-flex items-center gap-1 bg-blue-50 text-blue-700 px-2.5 py-1 rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
开始时间:{{ huodong.start_time|date:"Y年m月d日" }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="p-8 text-center text-gray-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-3 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
暂无进行中的活动
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-teal-400 to-transparent"></div>
|
||||
|
||||
<!-- 今年活动分类展示 -->
|
||||
{% for scope, scope_data in grouped_activities.items %}
|
||||
<div class="p-5 border border-gray-100 rounded-lg dark:bg-gray-800 dark:border-gray-700">
|
||||
<time class="text-lg font-semibold text-gray-900 dark:text-white">今年的{{ scope }}(共{{ scope_data.branch_count }}个分支机构)</time>
|
||||
<ol class="mt-3 divide-y divider-gray-200 dark:divide-gray-700">
|
||||
{% for activity in scope_data.activities %}
|
||||
<li style= "background-color: {{ activity.branch.background_color }};" >
|
||||
<div class="items-center block p-3 sm:flex hover:bg-gray-100 dark:hover:bg-gray-700">
|
||||
<div class="text-gray-600 dark:text-gray-400">
|
||||
<span class="inline-flex items-center text-xs font-normal text-gray-400 dark:text-gray-400">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-2.5 h-2.5 text-blue-800 dark:text-blue-300">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M15.75 9V5.25A2.25 2.25 0 0 0 13.5 3h-6a2.25 2.25 0 0 0-2.25 2.25v13.5A2.25 2.25 0 0 0 7.5 21h6a2.25 2.25 0 0 0 2.25-2.25V15m3 0 3-3m0 0-3-3m3 3H9"/>
|
||||
</svg>
|
||||
开始时间 {{ activity.start_time| date:"Y年m月d日" }}
|
||||
</span>
|
||||
<div class="text-base font-normal">
|
||||
<span class="font-medium text-gray-900 dark:text-white">
|
||||
<div class="w-full max-w-5xl mx-auto p-6">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-teal-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-teal-500 via-teal-600 to-cyan-600">
|
||||
<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="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||
</svg>
|
||||
今年的{{ scope }}
|
||||
<span class="ml-auto text-sm font-normal bg-white/20 px-3 py-1 rounded-full">{{ scope_data.branch_count }} 个分支机构</span>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="divide-y divide-gray-100">
|
||||
{% for activity in scope_data.activities %}
|
||||
<div class="p-5 hover:bg-teal-50/50 transition-colors duration-200 group" style="background-color: {{ activity.branch.background_color }};">
|
||||
<div class="flex flex-col sm:flex-row sm:items-start gap-4">
|
||||
<!-- 状态标记 -->
|
||||
<div class="flex-shrink-0">
|
||||
<div class="w-10 h-10 rounded-full {% if not activity.end_time %}bg-gradient-to-br from-red-400 to-red-600{% else %}bg-gradient-to-br from-teal-400 to-teal-600{% endif %} flex items-center justify-center text-white shadow-md">
|
||||
{% if not activity.end_time %}
|
||||
<span class="text-lg font-semibold text-red-900 dark:text-white">
|
||||
<a href="{% url 'branch-detail' activity.branch.pk %}"
|
||||
class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
{{ activity.branch }}
|
||||
</a>
|
||||
{{ activity.name }}-未完成
|
||||
</span>
|
||||
<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="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
{% else %}
|
||||
<span class="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
<a href="{% url 'branch-detail' activity.branch.pk %}"
|
||||
class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
{{ activity.branch }}
|
||||
</a>
|
||||
<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="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<!-- 内容 -->
|
||||
<div class="flex-grow min-w-0">
|
||||
<div class="flex flex-wrap items-center gap-2 mb-2">
|
||||
<a href="{% url 'branch-detail' activity.branch.pk %}"
|
||||
class="inline-flex items-center px-2.5 py-1 rounded-lg text-sm font-medium bg-teal-100 text-teal-700 hover:bg-teal-600 hover:text-white transition-colors">
|
||||
{{ activity.branch }}
|
||||
</a>
|
||||
<h3 class="text-lg font-bold {% if not activity.end_time %}text-red-700{% else %}text-gray-800{% endif %} group-hover:text-teal-700 transition-colors">
|
||||
{{ activity.name }}
|
||||
</h3>
|
||||
{% if not activity.end_time %}
|
||||
<span class="text-xs font-medium text-white bg-red-500 px-2 py-0.5 rounded-full">未完成</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 mb-3 line-clamp-2">{{ activity.description }}</p>
|
||||
<div class="flex flex-wrap items-center gap-4 text-xs text-gray-500">
|
||||
<span class="inline-flex items-center gap-1 bg-blue-50 text-blue-700 px-2.5 py-1 rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
{{ activity.start_time|date:"Y年m月d日" }}
|
||||
</span>
|
||||
{% if activity.end_time %}
|
||||
<span class="inline-flex items-center gap-1 bg-green-50 text-green-700 px-2.5 py-1 rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
{{ activity.end_time|date:"Y年m月d日" }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm font-normal">
|
||||
{{ activity.description }}
|
||||
</div>
|
||||
<span class="inline-flex items-center text-xs font-normal text-gray-400 dark:text-gray-400">
|
||||
<svg class="w-2.5 h-2.5 text-blue-800 dark:text-blue-300" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
|
||||
fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M20 4a2 2 0 0 0-2-2h-2V1a1 1 0 0 0-2 0v1h-3V1a1 1 0 0 0-2 0v1H6V1a1 1 0 0 0-2 0v1H2a2 2 0 0 0-2 2v2h20V4ZM0 18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8H0v10Zm5-8h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z"/>
|
||||
</svg>
|
||||
结束时间 {{ activity.end_time| date:"Y年m月d日" }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
{% empty %}
|
||||
<div class="p-8 text-center text-gray-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-3 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||
</svg>
|
||||
暂无活动
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="h-px my-8 bg-gray-200 border-0 dark:bg-gray-700">
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-gray-300 to-transparent"></div>
|
||||
{% endfor %}
|
||||
|
||||
<time class="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
今年的
|
||||
{% for scope, scope_data in grouped_activities.items %}
|
||||
{{ scope }}{{ scope_data.branch_count }}个{% if forloop.last %}。{% else %},{% endif %}
|
||||
{% endfor %}
|
||||
</time>
|
||||
<hr class="h-px my-8 bg-gray-200 border-0 dark:bg-gray-700">
|
||||
<!-- 今年统计汇总 -->
|
||||
<div class="w-full max-w-5xl mx-auto p-6">
|
||||
<div class="bg-gradient-to-r from-teal-50 to-cyan-50 rounded-xl p-6 border border-teal-200">
|
||||
<h3 class="text-lg font-bold text-teal-800 mb-3 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="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||
</svg>
|
||||
今年统计
|
||||
</h3>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
{% for scope, scope_data in grouped_activities.items %}
|
||||
<span class="inline-flex items-center px-4 py-2 rounded-full bg-white shadow-sm border border-teal-100">
|
||||
<span class="w-2 h-2 rounded-full bg-teal-500 mr-2"></span>
|
||||
<span class="font-medium text-gray-700">{{ scope }}</span>
|
||||
<span class="ml-2 text-teal-600 font-bold">{{ scope_data.branch_count }}个</span>
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-indigo-400 to-transparent"></div>
|
||||
|
||||
<!-- 历年活动统计 -->
|
||||
{% for year in historical_years %}
|
||||
{% with year_data=historical_grouped_activities|get_item:year %}
|
||||
{% if year_data %}
|
||||
<time class="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
{{ year }}年的
|
||||
{% for scope, scope_data in year_data.items %}
|
||||
{{ scope }}{{ scope_data.branch_count }}个{% if forloop.last %}。{% else %},{% endif %}
|
||||
{% endfor %}
|
||||
</time>
|
||||
<hr class="h-px my-8 bg-gray-200 border-0 dark:bg-gray-700">
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
<div class="w-full max-w-5xl mx-auto p-6">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-indigo-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-indigo-500 via-indigo-600 to-purple-600">
|
||||
<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="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
历年活动统计
|
||||
</h2>
|
||||
</div>
|
||||
<div class="p-6 space-y-4">
|
||||
{% for year in historical_years %}
|
||||
{% with year_data=historical_grouped_activities|get_item:year %}
|
||||
{% if year_data %}
|
||||
<div class="bg-gradient-to-r from-indigo-50 to-purple-50 rounded-xl p-5 border border-indigo-100">
|
||||
<h3 class="text-lg font-bold text-indigo-800 mb-3 flex items-center gap-2">
|
||||
<span class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-indigo-600 text-white text-sm font-bold">{{ year }}</span>
|
||||
<span>年统计</span>
|
||||
</h3>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
{% for scope, scope_data in year_data.items %}
|
||||
<span class="inline-flex items-center px-4 py-2 rounded-full bg-white shadow-sm border border-indigo-100">
|
||||
<span class="w-2 h-2 rounded-full bg-indigo-500 mr-2"></span>
|
||||
<span class="font-medium text-gray-700">{{ scope }}</span>
|
||||
<span class="ml-2 text-indigo-600 font-bold">{{ scope_data.branch_count }}个</span>
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -2,51 +2,73 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Component starts here -->
|
||||
<h2 class="flex flex-row flex-nowrap items-center my-8">
|
||||
<span class="flex-grow block border-t border-black" aria-hidden="true" role="presentation"></span>
|
||||
<span class="flex-none block mx-4 px-4 py-2.5 text-base leading-none font-medium uppercase bg-black text-white">
|
||||
{{ branch.name }}
|
||||
</span>
|
||||
<span class="flex-grow block border-t border-black" aria-hidden="true" role="presentation"></span>
|
||||
</h2>
|
||||
<!-- Component ends here -->
|
||||
<!-- 页面标题 -->
|
||||
<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-blue-500 to-transparent"></div>
|
||||
<div class="relative z-10 bg-gradient-to-r from-blue-600 to-indigo-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="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>
|
||||
{{ branch.name }}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 投入预算表 -->
|
||||
<div class="bg-white rounded-lg shadow-md p-4 mb-6">
|
||||
<h2 class="text-2xl font-bold mb-4">投入预算表</h2>
|
||||
<p class="text-gray-700 mb-4">分支机构项目的预算表,包括设备和基础设施明细</p>
|
||||
<div class="w-full max-w-6xl mx-auto p-6">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-blue-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-blue-600 via-blue-700 to-indigo-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="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
|
||||
</svg>
|
||||
投入预算表
|
||||
</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<p class="text-gray-600 mb-6">分支机构项目的预算表,包括设备和基础设施明细</p>
|
||||
|
||||
<!-- 预算模板导入功能 -->
|
||||
{% if budget_templates %} <!-- 只有当有模板时才显示导入功能 -->
|
||||
<div class="mb-6 p-4 bg-blue-50 rounded-lg">
|
||||
<h3 class="text-lg font-semibold mb-2">预算模板导入</h3>
|
||||
<p class="text-sm text-gray-600 mb-3">从模板一键导入预算,快速生成预算表</p>
|
||||
|
||||
<form method="POST" action="{% url 'import-budget-template' branch.id %}">
|
||||
{% csrf_token %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label for="template" class="block text-sm font-medium text-gray-700 mb-1">选择模板</label>
|
||||
<select id="template" name="template" class="w-full p-2 border border-gray-300 rounded-md">
|
||||
{% for template in budget_templates %}
|
||||
<option value="{{ template.id }}">{{ template.name }}{% if template.is_default %} (默认){% endif %}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="budget_name" class="block text-sm font-medium text-gray-700 mb-1">预算名称</label>
|
||||
<input type="text" id="budget_name" name="budget_name" placeholder="请输入预算名称" class="w-full p-2 border border-gray-300 rounded-md">
|
||||
</div>
|
||||
<div class="flex items-end">
|
||||
<button type="submit" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md">
|
||||
一键导入
|
||||
</button>
|
||||
</div>
|
||||
<!-- 预算模板导入功能 -->
|
||||
{% if budget_templates %}
|
||||
<div class="mb-6 p-5 bg-gradient-to-r from-blue-50 to-indigo-50 rounded-xl border border-blue-200">
|
||||
<h3 class="text-lg font-semibold mb-2 text-blue-800 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="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
|
||||
</svg>
|
||||
预算模板导入
|
||||
</h3>
|
||||
<p class="text-sm text-gray-600 mb-4">从模板一键导入预算,快速生成预算表</p>
|
||||
|
||||
<form method="POST" action="{% url 'import-budget-template' branch.id %}">
|
||||
{% csrf_token %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label for="template" class="block text-sm font-medium text-gray-700 mb-1">选择模板</label>
|
||||
<select id="template" name="template" class="w-full p-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all">
|
||||
{% for template in budget_templates %}
|
||||
<option value="{{ template.id }}">{{ template.name }}{% if template.is_default %} (默认){% endif %}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="budget_name" class="block text-sm font-medium text-gray-700 mb-1">预算名称</label>
|
||||
<input type="text" id="budget_name" name="budget_name" placeholder="请输入预算名称" class="w-full p-2.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition-all">
|
||||
</div>
|
||||
<div class="flex items-end">
|
||||
<button type="submit" class="w-full bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-800 text-white px-6 py-2.5 rounded-lg font-medium shadow-md hover:shadow-lg transition-all duration-200 flex items-center justify-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12" />
|
||||
</svg>
|
||||
一键导入
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if budgets %}
|
||||
{% for budget in budgets %}
|
||||
@@ -54,215 +76,438 @@
|
||||
<h3 class="text-lg font-semibold mb-3">{{ budget.name }} - 总预算: ¥{{ budget.total_budget }}</h3>
|
||||
|
||||
<!-- 设备预算部分 -->
|
||||
<div class="mb-4">
|
||||
<h4 class="text-md font-semibold mb-2">设备预算明细</h4>
|
||||
<div class="mb-6">
|
||||
<h4 class="text-md font-bold mb-3 text-gray-800 flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z" />
|
||||
</svg>
|
||||
设备预算明细
|
||||
</h4>
|
||||
{% if budget.equipment_budgets.all %}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="overflow-x-auto rounded-xl border border-gray-200">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<thead class="bg-gradient-to-r from-slate-50 to-gray-100">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">项目</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">型号</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">单价</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">采购方式</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">数量</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">小计</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">项目</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">型号</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">单价</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">采购方式</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">数量</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">小计</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
<tbody class="bg-white divide-y divide-gray-100">
|
||||
{% for equipment in budget.equipment_budgets.all %}
|
||||
<tr>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ equipment.project }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ equipment.model }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">¥{{ equipment.unit_price }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ equipment.get_procurement_method_display }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ equipment.quantity }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">¥{{ equipment.subtotal }}</td>
|
||||
<tr class="hover:bg-blue-50/50 transition-colors">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">{{ equipment.project }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ equipment.model }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-blue-600">¥{{ equipment.unit_price }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ equipment.get_procurement_method_display }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">{{ equipment.quantity }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-bold text-green-600">¥{{ equipment.subtotal }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-gray-500 italic">暂无设备预算明细</p>
|
||||
<div class="p-6 text-center bg-gray-50 rounded-xl border border-gray-200">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-3 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z" />
|
||||
</svg>
|
||||
<p class="text-gray-500">暂无设备预算明细</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- 基础设施预算部分 -->
|
||||
<div>
|
||||
<h4 class="text-md font-semibold mb-2">基础设施预算明细</h4>
|
||||
<h4 class="text-md font-bold mb-3 text-gray-800 flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 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>
|
||||
基础设施预算明细
|
||||
</h4>
|
||||
{% if budget.infrastructure_budgets.all %}
|
||||
<div class="overflow-x-auto">
|
||||
<div class="overflow-x-auto rounded-xl border border-gray-200">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<thead class="bg-gradient-to-r from-slate-50 to-gray-100">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">名称</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">备注</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">单价</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">单位</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">数量</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">小计</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">说明</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">名称</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">备注</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">单价</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">单位</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">数量</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">小计</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">说明</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
<tbody class="bg-white divide-y divide-gray-100">
|
||||
{% for infrastructure in budget.infrastructure_budgets.all %}
|
||||
<tr>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ infrastructure.name }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ infrastructure.remarks }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">¥{{ infrastructure.unit_price }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ infrastructure.unit }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ infrastructure.quantity }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">¥{{ infrastructure.subtotal }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ infrastructure.description }}</td>
|
||||
<tr class="hover:bg-teal-50/50 transition-colors">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">{{ infrastructure.name }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ infrastructure.remarks }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-blue-600">¥{{ infrastructure.unit_price }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ infrastructure.unit }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800">{{ infrastructure.quantity }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-bold text-green-600">¥{{ infrastructure.subtotal }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ infrastructure.description }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-gray-500 italic">暂无基础设施预算明细</p>
|
||||
<div class="p-6 text-center bg-gray-50 rounded-xl border border-gray-200">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-3 text-gray-300" 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>
|
||||
<p class="text-gray-500">暂无基础设施预算明细</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="text-gray-500 italic">暂无预算信息</p>
|
||||
<div class="p-8 text-center bg-gray-50 rounded-xl border border-gray-200">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 mx-auto mb-4 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<p class="text-gray-500 text-lg">暂无预算信息</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="bg-white rounded-lg shadow-md p-4 mb-6">
|
||||
<h2 class="text-2xl font-bold mb-4">基本信息</h2>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<p class="text-gray-700"><strong>信息系统分类:</strong> {{ branch.category|default:"暂无" }}</p>
|
||||
<p class="text-gray-700"><strong>联系人:</strong> {{ branch.contact_person|default:"暂无" }}</p>
|
||||
<p class="text-gray-700"><strong>联系电话:</strong> {{ branch.contact_phone|default:"暂无" }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-700"><strong>地址:</strong> {{ branch.address|default:"暂无" }}</p>
|
||||
<p class="text-gray-700"><strong>成立时间:</strong> {{ branch.established_date|date:"Y-m-d"|default:"暂无" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 事件信息 -->
|
||||
<div class="bg-white rounded-lg shadow-md p-4 mb-6">
|
||||
<h2 class="text-2xl font-bold mb-4">关联事件</h2>
|
||||
{% if events %}
|
||||
<div class="space-y-3">
|
||||
{% for event in events %}
|
||||
<div class="border-l-4 border-blue-500 pl-4 py-2 bg-blue-50 rounded">
|
||||
<h3 class="font-semibold text-lg">{{ event.name }}</h3>
|
||||
<p class="text-sm text-gray-600">
|
||||
{% if event.end_time %}
|
||||
开始日期{{ event.start_time|date:"Y年m月d日" }} 结束日期{{ event.end_time|date:"Y年m月d日" }}
|
||||
{% else %}
|
||||
开始日期{{ event.start_time|date:"Y年m月d日" }},现在进行中
|
||||
{% endif %}
|
||||
</p>
|
||||
<p class="mt-1 text-gray-700">{{ event.description|truncatechars:100 }}</p>
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-cyan-400 to-transparent"></div>
|
||||
|
||||
<!-- 基本信息 -->
|
||||
<div class="w-full max-w-6xl mx-auto p-6">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-cyan-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-cyan-500 via-cyan-600 to-teal-600">
|
||||
<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="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
基本信息
|
||||
</h2>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-gray-500 italic">暂无事件记录</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- 设备间图片 -->
|
||||
<div class="bg-white rounded-lg shadow-md p-4 mb-6">
|
||||
<h2 class="text-2xl font-bold mb-4">设备间图片</h2>
|
||||
{% if equipment_images %}
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
|
||||
{% for image in equipment_images %}
|
||||
<div class="overflow-hidden rounded-lg shadow">
|
||||
<img src="{{ image.image.url }}" alt="设备间图片" class="w-full h-48 object-cover">
|
||||
<div class="p-2 bg-gray-50">
|
||||
<p class="text-sm text-gray-700">{{ image.description|default:"无描述" }}</p>
|
||||
<p class="text-xs text-gray-500 mt-1">{{ image.upload_date|date:"Y-m-d" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-gray-500 italic">暂无设备间图片</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- 公共电子屏 -->
|
||||
<div class="bg-white rounded-lg shadow-md p-4 mb-6">
|
||||
<h2 class="text-2xl font-bold mb-4">公共电子屏</h2>
|
||||
{% if public_screens %}
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">类型</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">描述</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">最后演练</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">更新时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
{% for screen in public_screens %}
|
||||
<tr>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ screen.get_screen_type_display }}</td>
|
||||
<td class="px-6 py-4">{{ screen.description|default:"无" }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ screen.last_drill.date|date:"Y-m-d"|default:"未演练" }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ screen.updated_at|date:"Y-m-d H:i" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-gray-500 italic">暂无公共电子屏信息</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% for scope, activities in grouped_activities.items %}
|
||||
|
||||
<div class="p-5 border border-gray-100 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700">
|
||||
<time class="text-lg font-semibold text-gray-900 dark:text-white">{{ scope }}</time>
|
||||
<ol class="mt-3 divide-y divider-gray-200 dark:divide-gray-700">
|
||||
{% for huodong in activities %}
|
||||
<li style="background-color: {{ huodong.branch.background_color }};">
|
||||
<div class="items-center block p-3 sm:flex hover:bg-gray-100 dark:hover:bg-gray-700">
|
||||
<div class="text-gray-600 dark:text-gray-400">
|
||||
<span class="inline-flex items-center text-xs font-normal text-gray-400 dark:text-gray-400">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-2.5 h-2.5 text-blue-800 dark:text-blue-300">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0 0 13.5 3h-6a2.25 2.25 0 0 0-2.25 2.25v13.5A2.25 2.25 0 0 0 7.5 21h6a2.25 2.25 0 0 0 2.25-2.25V15m3 0 3-3m0 0-3-3m3 3H9" />
|
||||
</svg>
|
||||
开始时间 {{ huodong.start_time| date:"Y年m月d日" }}
|
||||
</span>
|
||||
<div class="text-base font-normal">
|
||||
<span class="font-medium text-gray-900 dark:text-white">
|
||||
{% if not huodong.end_time %}
|
||||
<span class="text-lg font-semibold text-red-900 dark:text-white">
|
||||
{{ huodong.name }}-未完成
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
{{ huodong.name }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
<div class="p-6">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-start gap-3 p-4 bg-gray-50 rounded-xl">
|
||||
<div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-blue-600" 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>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500 mb-1">信息系统分类</p>
|
||||
<p class="text-base font-medium text-gray-800">{{ branch.category|default:"暂无" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm font-normal">
|
||||
{{ huodong.description }}
|
||||
<div class="flex items-start gap-3 p-4 bg-gray-50 rounded-xl">
|
||||
<div class="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center flex-shrink-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-green-600" 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>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500 mb-1">联系人</p>
|
||||
<p class="text-base font-medium text-gray-800">{{ branch.contact_person|default:"暂无" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start gap-3 p-4 bg-gray-50 rounded-xl">
|
||||
<div class="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center flex-shrink-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-purple-600" 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>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500 mb-1">联系电话</p>
|
||||
<p class="text-base font-medium text-gray-800">{{ branch.contact_phone|default:"暂无" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-start gap-3 p-4 bg-gray-50 rounded-xl">
|
||||
<div class="w-10 h-10 rounded-full bg-orange-100 flex items-center justify-center flex-shrink-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-orange-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500 mb-1">地址</p>
|
||||
<p class="text-base font-medium text-gray-800">{{ branch.address|default:"暂无" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-start gap-3 p-4 bg-gray-50 rounded-xl">
|
||||
<div class="w-10 h-10 rounded-full bg-pink-100 flex items-center justify-center flex-shrink-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-pink-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500 mb-1">成立时间</p>
|
||||
<p class="text-base font-medium text-gray-800">{{ branch.established_date|date:"Y年m月d日"|default:"暂无" }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<span class="inline-flex items-center text-xs font-normal text-gray-400 dark:text-gray-400">
|
||||
<svg class="w-2.5 h-2.5 text-blue-800 dark:text-blue-300" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path d="M20 4a2 2 0 0 0-2-2h-2V1a1 1 0 0 0-2 0v1h-3V1a1 1 0 0 0-2 0v1H6V1a1 1 0 0 0-2 0v1H2a2 2 0 0 0-2 2v2h20V4ZM0 18a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8H0v10Zm5-8h10a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z"/>
|
||||
</svg>
|
||||
结束时间 {{ huodong.end_time| date:"Y年m月d日" }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="h-px my-8 bg-gray-200 border-0 dark:bg-gray-700">
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-purple-400 to-transparent"></div>
|
||||
|
||||
<!-- 事件信息 -->
|
||||
<div class="w-full max-w-6xl mx-auto p-6">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-purple-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-purple-600 via-purple-700 to-indigo-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="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
关联事件
|
||||
</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
{% if events %}
|
||||
<div class="space-y-4">
|
||||
{% for event in events %}
|
||||
<div class="p-5 bg-gradient-to-r from-purple-50 to-indigo-50 rounded-xl border-l-4 border-purple-500 hover:shadow-md transition-shadow">
|
||||
<h3 class="font-bold text-lg text-purple-800 mb-2">{{ event.name }}</h3>
|
||||
<div class="flex flex-wrap items-center gap-3 mb-3">
|
||||
<span class="inline-flex items-center gap-1 text-xs bg-white px-2.5 py-1 rounded-full text-purple-700 shadow-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
{{ event.start_time|date:"Y年m月d日" }}
|
||||
</span>
|
||||
{% if event.end_time %}
|
||||
<span class="inline-flex items-center gap-1 text-xs bg-green-100 px-2.5 py-1 rounded-full text-green-700">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
{{ event.end_time|date:"Y年m月d日" }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="inline-flex items-center gap-1 text-xs bg-red-100 px-2.5 py-1 rounded-full text-red-700">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
进行中
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="text-gray-700">{{ event.description|truncatechars:100 }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="p-8 text-center bg-gray-50 rounded-xl">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 mx-auto mb-4 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<p class="text-gray-500 text-lg">暂无事件记录</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-emerald-400 to-transparent"></div>
|
||||
|
||||
<!-- 设备间图片 -->
|
||||
<div class="w-full max-w-6xl mx-auto p-6">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-emerald-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-emerald-500 via-emerald-600 to-teal-600">
|
||||
<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="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
设备间图片
|
||||
</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
{% if equipment_images %}
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
|
||||
{% for image in equipment_images %}
|
||||
<div class="overflow-hidden rounded-xl shadow-lg hover:shadow-xl transition-shadow group">
|
||||
<div class="relative overflow-hidden">
|
||||
<img src="{{ image.image.url }}" alt="设备间图片" class="w-full h-48 object-cover group-hover:scale-105 transition-transform duration-300">
|
||||
</div>
|
||||
<div class="p-4 bg-gray-50">
|
||||
<p class="text-sm font-medium text-gray-800">{{ image.description|default:"无描述" }}</p>
|
||||
<p class="text-xs text-gray-500 mt-2 flex items-center gap-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
{{ image.upload_date|date:"Y年m月d日" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="p-8 text-center bg-gray-50 rounded-xl">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 mx-auto mb-4 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<p class="text-gray-500 text-lg">暂无设备间图片</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-amber-400 to-transparent"></div>
|
||||
|
||||
<!-- 公共电子屏 -->
|
||||
<div class="w-full max-w-6xl mx-auto p-6">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-amber-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-amber-500 via-amber-600 to-orange-600">
|
||||
<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="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
公共电子屏
|
||||
</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
{% if public_screens %}
|
||||
<div class="overflow-x-auto rounded-xl border border-gray-200">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gradient-to-r from-slate-50 to-gray-100">
|
||||
<tr>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">类型</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">描述</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">最后演练</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">更新时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-100">
|
||||
{% for screen in public_screens %}
|
||||
<tr class="hover:bg-amber-50/50 transition-colors">
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-amber-100 text-amber-800">
|
||||
{{ screen.get_screen_type_display }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-sm text-gray-700">{{ screen.description|default:"无" }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm">
|
||||
{% if screen.last_drill %}
|
||||
<span class="inline-flex items-center gap-1 text-green-700">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
{{ screen.last_drill.date|date:"Y-m-d" }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="text-gray-400">未演练</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ screen.updated_at|date:"Y-m-d H:i" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="p-8 text-center bg-gray-50 rounded-xl">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 mx-auto mb-4 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<p class="text-gray-500 text-lg">暂无公共电子屏信息</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-teal-400 to-transparent"></div>
|
||||
|
||||
<!-- 活动列表 -->
|
||||
{% for scope, activities in grouped_activities.items %}
|
||||
<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">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-teal-500 via-teal-600 to-cyan-600">
|
||||
<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="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||
</svg>
|
||||
{{ scope }}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="divide-y divide-gray-100">
|
||||
{% for huodong in activities %}
|
||||
<div class="p-5 hover:bg-teal-50/50 transition-colors duration-200" style="background-color: {{ huodong.branch.background_color }};">
|
||||
<div class="flex flex-col sm:flex-row sm:items-start gap-4">
|
||||
<!-- 状态标记 -->
|
||||
<div class="flex-shrink-0">
|
||||
<div class="w-10 h-10 rounded-full {% if not huodong.end_time %}bg-gradient-to-br from-red-400 to-red-600{% else %}bg-gradient-to-br from-teal-400 to-teal-600{% endif %} flex items-center justify-center text-white shadow-md">
|
||||
{% if not huodong.end_time %}
|
||||
<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="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
{% else %}
|
||||
<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="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<!-- 内容 -->
|
||||
<div class="flex-grow min-w-0">
|
||||
<div class="flex flex-wrap items-center gap-2 mb-2">
|
||||
<h3 class="text-lg font-bold {% if not huodong.end_time %}text-red-700{% else %}text-gray-800{% endif %}">
|
||||
{{ huodong.name }}
|
||||
</h3>
|
||||
{% if not huodong.end_time %}
|
||||
<span class="text-xs font-medium text-white bg-red-500 px-2 py-0.5 rounded-full">未完成</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 mb-3">{{ huodong.description }}</p>
|
||||
<div class="flex flex-wrap items-center gap-4 text-xs text-gray-500">
|
||||
<span class="inline-flex items-center gap-1 bg-blue-50 text-blue-700 px-2.5 py-1 rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
{{ huodong.start_time|date:"Y年m月d日" }}
|
||||
</span>
|
||||
{% if huodong.end_time %}
|
||||
<span class="inline-flex items-center gap-1 bg-green-50 text-green-700 px-2.5 py-1 rounded-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
{{ huodong.end_time|date:"Y年m月d日" }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="p-8 text-center text-gray-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto mb-3 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||
</svg>
|
||||
暂无活动
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-gray-300 to-transparent"></div>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,67 +1,202 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
<table class="items-center bg-transparent w-full border-collapse ">
|
||||
<thead>
|
||||
<tr class="bg-gray-100">
|
||||
<th class="px-6 bg-blueGray-50 text-blueGray-500 align-middle border border-solid border-blueGray-100 py-3 text-base uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left">
|
||||
分支机构名称
|
||||
<br>
|
||||
基础信息
|
||||
</th>
|
||||
<th class="px-6 bg-blueGray-50 text-blueGray-500 align-middle border border-solid border-blueGray-100 py-3 text-base uppercase border-l-0 border-r-0 whitespace-nowrap font-semibold text-left">
|
||||
信息系统类别
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in branches %}
|
||||
<!-- 这里是其他行的处理逻辑 -->
|
||||
<tr class="{% if forloop.counter|divisibleby:2 %}bg-gray-100{% else %}bg-white{% endif %}">
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-left border-b border-gray-200">
|
||||
<a href="{% url 'branch-detail' item.pk %}"
|
||||
class="bg-transparent hover:bg-blue-900 hover:text-white p-2 rounded-md">
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-left border-b border-gray-200">
|
||||
{{ item.category }}
|
||||
</td>
|
||||
<!-- 页面标题 -->
|
||||
<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-indigo-500 to-transparent"></div>
|
||||
<div class="relative z-10 bg-gradient-to-r from-indigo-600 to-purple-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="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>
|
||||
分支机构信息
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tr class="bg-gray-200 font-bold">
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-left border-b border-gray-200">
|
||||
分支机构类别统计
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-left border-b border-gray-200">
|
||||
A型: {{ type_a_count }}家 | B型: {{ type_b_count }}家 | C型: {{ type_c_count }}家
|
||||
</td>
|
||||
</tr>
|
||||
<tfoot>
|
||||
<tr class="bg-gray-50">
|
||||
<td colspan="2" class="px-6 py-4 text-right border-b border-gray-200">
|
||||
<div class="flex justify-end space-x-3">
|
||||
<a href="{% url 'export-branches-xls' %}" class="inline-flex items-center px-4 py-2 bg-blue-600 hover:bg-blue-700 text-black font-medium rounded-lg shadow-md transition duration-150 ease-in-out transform hover:scale-105">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm3.293-7.707a1 1 0 011.414 0L9 10.586V3a1 1 0 112 0v7.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
<!-- 分公司/营业部数量统计 -->
|
||||
<div class="w-full max-w-6xl mx-auto px-6 mt-2 mb-6">
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-indigo-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-indigo-600 via-indigo-700 to-purple-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="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||
</svg>
|
||||
机构数量统计
|
||||
</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div class="flex flex-wrap items-center gap-x-6 gap-y-3 text-base">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-gradient-to-br from-blue-500 to-indigo-600 shadow-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-white" 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>
|
||||
</span>
|
||||
<span class="text-gray-600">分支机构总数</span>
|
||||
<span class="text-xl font-bold text-gray-800">{{ all_branch_count }}</span>
|
||||
<span class="text-gray-500">个</span>
|
||||
</div>
|
||||
<span class="text-gray-300">|</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-gradient-to-br from-emerald-500 to-teal-600 shadow-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 14v3m4-3v3m4-3v3M3 21h18M3 10h18M3 7l9-4 9 4M4 10h16v11H4V10z" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="text-gray-600">分公司数量</span>
|
||||
<span class="text-xl font-bold text-emerald-700">{{ fen_company_count }}</span>
|
||||
<span class="text-gray-500">个</span>
|
||||
</div>
|
||||
<span class="text-gray-300">|</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-gradient-to-br from-amber-500 to-orange-600 shadow-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="text-gray-600">营业部数量</span>
|
||||
<span class="text-xl font-bold text-amber-700">{{ yingyebu_count }}</span>
|
||||
<span class="text-gray-500">个</span>
|
||||
</div>
|
||||
</div>
|
||||
{% if preparing_count > 0 %}
|
||||
<div class="mt-4 pt-4 border-t border-gray-100 flex items-center gap-2">
|
||||
<span class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-gradient-to-br from-rose-400 to-pink-500 shadow-sm">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="text-gray-600">筹建中的分公司或营业部数量</span>
|
||||
<span class="text-xl font-bold text-rose-600">{{ preparing_count }}</span>
|
||||
<span class="text-gray-500">个</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</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-indigo-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-indigo-600 via-indigo-700 to-purple-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="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0121 18.382V7.618a1 1 0 01-.553-.894L15 7m0 13V7" />
|
||||
</svg>
|
||||
分支机构列表
|
||||
</h2>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="bg-gradient-to-r from-slate-50 to-gray-100 border-b-2 border-indigo-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-indigo-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</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-indigo-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-indigo-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>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100">
|
||||
{% for province, branches in branches_by_province.items %}
|
||||
{% for item in branches %}
|
||||
<tr class="{% if forloop.parentloop.counter|divisibleby:2 %}bg-slate-50/50{% else %}bg-white{% endif %} hover:bg-indigo-50/50 transition-colors duration-200">
|
||||
{% if forloop.first %}
|
||||
<td class="px-6 py-4 whitespace-nowrap text-left font-medium text-gray-800" rowspan="{{ branches|length }}">
|
||||
<span class="inline-flex items-center px-3 py-1 rounded-full bg-indigo-100 text-indigo-700 text-sm">
|
||||
{{ province }}
|
||||
</span>
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="px-6 py-4 whitespace-nowrap text-left">
|
||||
<a href="{% url 'branch-detail' item.pk %}"
|
||||
class="inline-flex items-center px-3 py-1.5 rounded-lg text-sm font-medium text-gray-700 bg-gray-100 hover:bg-indigo-600 hover:text-white transition-all duration-200">
|
||||
{{ item.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-left">
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium {% if item.category == 'A型' %}bg-blue-100 text-blue-700{% elif item.category == 'B型' %}bg-green-100 text-green-700{% elif item.category == 'C型' %}bg-orange-100 text-orange-700{% else %}bg-gray-100 text-gray-700{% endif %}">
|
||||
{{ item.category }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<!-- 统计行 -->
|
||||
<tr class="bg-gradient-to-r from-indigo-50 to-purple-50 border-t-2 border-indigo-200">
|
||||
<td class="px-6 py-4 whitespace-nowrap font-bold text-gray-800">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-indigo-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||
</svg>
|
||||
分支机构类别统计
|
||||
</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap" colspan="2">
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<span class="inline-flex items-center px-3 py-1.5 rounded-full bg-blue-100 text-blue-700 text-sm font-medium">
|
||||
<span class="w-2 h-2 rounded-full bg-blue-500 mr-2"></span>
|
||||
A型: {{ type_a_count }}家
|
||||
</span>
|
||||
<span class="inline-flex items-center px-3 py-1.5 rounded-full bg-green-100 text-green-700 text-sm font-medium">
|
||||
<span class="w-2 h-2 rounded-full bg-green-500 mr-2"></span>
|
||||
B型: {{ type_b_count }}家
|
||||
</span>
|
||||
<span class="inline-flex items-center px-3 py-1.5 rounded-full bg-orange-100 text-orange-700 text-sm font-medium">
|
||||
<span class="w-2 h-2 rounded-full bg-orange-500 mr-2"></span>
|
||||
C型: {{ type_c_count }}家
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<!-- 导出按钮 -->
|
||||
<div class="px-6 py-4 bg-gray-50 border-t border-gray-100">
|
||||
<div class="flex justify-end gap-3">
|
||||
<a href="{% url 'export-branches-xls' %}" class="inline-flex items-center px-5 py-2.5 bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-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>
|
||||
导出为XLS
|
||||
</a>
|
||||
<a href="{% url 'export-branches-pdf' %}" class="inline-flex items-center px-4 py-2 bg-purple-600 hover:bg-purple-800 text-black font-medium rounded-lg shadow-md transition duration-300 ease-in-out transform hover:scale-105 hover:shadow-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm3.293-7.707a1 1 0 011.414 0L9 10.586V3a1 1 0 112 0v7.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
<a href="{% url 'export-branches-pdf' %}" 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>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-purple-400 to-transparent"></div>
|
||||
|
||||
<hr class="h-px my-8 bg-red-500 border-1 dark:bg-red-700">
|
||||
{% endblock %}
|
||||
@@ -1,336 +1,444 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto p-4">
|
||||
<h2 class="text-xl font-bold mb-4">联系人信息</h2>
|
||||
|
||||
<!-- 新增筛选表单 -->
|
||||
<form method="GET" class="mb-4 p-4 bg-gray-100 rounded-lg" 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">分支机构(可多选)</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-300 rounded-lg focus:ring-2 focus:ring-blue-300 focus:border-blue-500 outline-none text-sm"
|
||||
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-md overflow-hidden hidden">
|
||||
<!-- 搜索输入框 -->
|
||||
<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-blue-300 focus:border-blue-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-gray-100 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" 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-blue-500 text-white rounded hover:bg-blue-600" 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" 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" 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">联系人类别</label>
|
||||
<input type="text" name="category" class="mt-1 p-2 border rounded" placeholder="输入类别名称筛选" value="{{ selected_category|default:'' }}">
|
||||
</div>
|
||||
|
||||
<!-- 联系人姓名筛选(保持原结构) -->
|
||||
<div class="flex flex-col w-full md:w-1/3">
|
||||
<label class="text-sm font-medium">联系人姓名</label>
|
||||
<input type="text" name="contact_name" class="mt-1 p-2 border rounded" placeholder="输入联系人姓名筛选" value="{{ selected_contact_name|default:'' }}">
|
||||
</div>
|
||||
|
||||
<div class="flex items-end gap-2">
|
||||
<button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">筛选</button>
|
||||
<button type="button" class="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600 transition-colors 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>
|
||||
|
||||
<table class="min-w-full border-collapse border border-gray-300">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">分支机构</th>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">分类</th>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">姓名</th>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">电话</th>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">邮箱</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for contact in contacts %}
|
||||
<tr class="{% cycle 'bg-white' 'bg-gray-50' %}">
|
||||
<td class="p-2 border border-gray-300">{{ contact.branch.name }}</td>
|
||||
<td class="p-2 border border-gray-300">{{ contact.category|default:"" }}</td>
|
||||
<td class="p-2 border border-gray-300">{{ contact.name|default:"" }}</td>
|
||||
<td class="p-2 border border-gray-300">{{ contact.phone|default:"" }}</td>
|
||||
<td class="p-2 border border-gray-300">{{ contact.email|default:"" }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="5" class="p-4 text-center text-gray-500">没有找到匹配的联系人</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</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>
|
||||
{% 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 gap-4">
|
||||
<a href="{% url 'export-contacts-xls' %}{% if request.GET.urlencode %}?{{ request.GET.urlencode }}{% endif %}" class="inline-flex items-center px-5 py-2.5 bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-700 hover:to-blue-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>
|
||||
导出为Excel
|
||||
</a>
|
||||
<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 %}
|
||||
@@ -1,66 +1,186 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<h1 class="text-3xl font-bold mb-8 text-center">分支机构设备间图片列表</h1>
|
||||
<div class="flex justify-center mb-6">
|
||||
<form method="get" action="" class="w-full max-w-md">
|
||||
<div class="flex">
|
||||
<input type="text" name="search" placeholder="搜索分支机构名称..." value="{{ request.GET.search }}"
|
||||
class="flex-1 px-4 py-2 border border-gray-300 rounded-l-md focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
<button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded-r-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
<!-- 页面标题 -->
|
||||
<div class="w-full max-w-7xl 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-emerald-500 to-transparent"></div>
|
||||
<div class="relative z-10 bg-gradient-to-r from-emerald-600 to-teal-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="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
分支机构设备间图片列表
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-full max-w-7xl mx-auto p-6">
|
||||
<!-- 搜索区域 -->
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-emerald-100 mb-6">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-emerald-600 via-emerald-700 to-teal-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="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
搜索分支机构
|
||||
</h2>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<form method="get" action="" class="flex flex-col sm:flex-row gap-4 items-center justify-center">
|
||||
<div class="relative flex-1 max-w-md w-full">
|
||||
<input type="text" name="search" placeholder="搜索分支机构名称..." value="{{ request.GET.search }}"
|
||||
class="w-full px-4 py-3 pl-12 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 bg-gray-50 hover:bg-white transition-colors">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400 absolute left-4 top-1/2 transform -translate-y-1/2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<button type="submit" class="px-6 py-3 bg-gradient-to-r from-emerald-600 to-emerald-700 hover:from-emerald-700 hover:to-emerald-800 text-white rounded-lg shadow-md hover:shadow-lg transition-all duration-200 font-medium 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="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
搜索
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 统计信息 -->
|
||||
<div class="mb-6 text-center">
|
||||
<span class="inline-flex items-center px-4 py-2 rounded-full bg-emerald-100 text-emerald-700 text-sm font-medium">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-2" 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>
|
||||
共 {{ total_count }} 个分支机构
|
||||
</span>
|
||||
</div>
|
||||
<p class="text-gray-600 mb-6 text-center">共 {{ total_count }} 个分支机构</p>
|
||||
|
||||
{% if branches %}
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||
{% for branch in branches %}
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300">
|
||||
<div class="p-4">
|
||||
<h2 class="text-xl font-semibold text-gray-900 mb-1">{{ branch.name }}</h2>
|
||||
<a href="{% url 'branch-detail' branch.id %}" class="text-blue-600 hover:text-blue-800 text-sm font-medium">
|
||||
查看分支机构详情 →
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-emerald-100 hover:shadow-2xl transition-all duration-300 group">
|
||||
<div class="p-5 bg-gradient-to-r from-emerald-50 to-teal-50 border-b border-emerald-100">
|
||||
<h2 class="text-lg font-bold text-gray-900 mb-2">{{ branch.name }}</h2>
|
||||
<a href="{% url 'branch-detail' branch.id %}" class="inline-flex items-center text-emerald-600 hover:text-emerald-800 text-sm font-medium transition-colors">
|
||||
查看分支机构详情
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-1 group-hover:translate-x-1 transition-transform" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="bg-gray-100 p-2">
|
||||
|
||||
<!-- 设备间图片 -->
|
||||
<div class="p-4 bg-gray-50">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-emerald-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<span class="text-sm font-semibold text-gray-700">设备间图片</span>
|
||||
</div>
|
||||
{% if branch.equipment_images.exists %}
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2">
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
{% for image in branch.equipment_images.all %}
|
||||
<img src="{{ image.image.url }}" alt="{{ branch.name }}设备间图片"
|
||||
class="h-[100px] md:h-[150px] lg:h-[200px] w-auto object-cover cursor-pointer"
|
||||
class="h-[80px] w-full object-cover rounded-lg cursor-pointer hover:scale-105 transition-transform duration-300"
|
||||
data-branch-id="{{ branch.id }}" data-image-type="equipment" data-index="{{ forloop.counter0 }}"
|
||||
onclick="openImageModal(this)">
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="flex items-center justify-center h-48 bg-gray-200">
|
||||
<span class="text-gray-400 text-sm">无图片</span>
|
||||
<div class="flex items-center justify-center h-24 bg-gray-100 rounded-lg">
|
||||
<div class="text-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-gray-300 mx-auto mb-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<span class="text-gray-400 text-xs">无图片</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- 图纸显示区域 -->
|
||||
<div class="bg-gray-100 p-2 mt-4">
|
||||
<h3 class="text-lg font-semibold mb-2">图纸</h3>
|
||||
<div class="p-4 bg-gray-50 border-t border-gray-100">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-emerald-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0121 18.382V7.618a1 1 0 01-.553-.894L15 7m0 13V7" />
|
||||
</svg>
|
||||
<span class="text-sm font-semibold text-gray-700">图纸</span>
|
||||
</div>
|
||||
{% if branch.drawings.exists %}
|
||||
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2">
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
{% for drawing in branch.drawings.all %}
|
||||
<img src="{{ drawing.image.url }}" alt="{{ branch.name }}图纸"
|
||||
class="h-[100px] md:h-[150px] lg:h-[200px] w-auto object-cover cursor-pointer"
|
||||
class="h-[80px] w-full object-cover rounded-lg cursor-pointer hover:scale-105 transition-transform duration-300"
|
||||
data-branch-id="{{ branch.id }}" data-image-type="drawings" data-index="{{ forloop.counter0 }}"
|
||||
onclick="openImageModal(this)">
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="flex items-center justify-center h-48 bg-gray-200">
|
||||
<span class="text-gray-400 text-sm">无图纸</span>
|
||||
<div class="flex items-center justify-center h-24 bg-gray-100 rounded-lg">
|
||||
<div class="text-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-gray-300 mx-auto mb-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0121 18.382V7.618a1 1 0 01-.553-.894L15 7m0 13V7" />
|
||||
</svg>
|
||||
<span class="text-gray-400 text-xs">无图纸</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- 分页控件 -->
|
||||
<div class="mt-10 flex justify-center">
|
||||
<nav class="inline-flex rounded-xl shadow-lg overflow-hidden border border-emerald-100">
|
||||
{% if branches.has_previous %}
|
||||
<a href="?page=1" class="relative inline-flex items-center px-4 py-3 bg-white text-sm font-medium text-gray-700 hover:bg-emerald-50 transition-colors border-r border-gray-100">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 19l-7-7 7-7m8 14l-7-7 7-7" />
|
||||
</svg>
|
||||
首页
|
||||
</a>
|
||||
<a href="?page={{ branches.previous_page_number }}" class="relative inline-flex items-center px-4 py-3 bg-white text-sm font-medium text-gray-700 hover:bg-emerald-50 transition-colors border-r border-gray-100">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
上一页
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<span class="relative inline-flex items-center px-6 py-3 bg-gradient-to-r from-emerald-50 to-teal-50 text-sm font-bold text-emerald-700">
|
||||
第 {{ branches.number }} 页,共 {{ branches.paginator.num_pages }} 页
|
||||
</span>
|
||||
|
||||
{% if branches.has_next %}
|
||||
<a href="?page={{ branches.next_page_number }}" class="relative inline-flex items-center px-4 py-3 bg-white text-sm font-medium text-gray-700 hover:bg-emerald-50 transition-colors border-l border-gray-100">
|
||||
下一页
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</a>
|
||||
<a href="?page={{ branches.paginator.num_pages }}" class="relative inline-flex items-center px-4 py-3 bg-white text-sm font-medium text-gray-700 hover:bg-emerald-50 transition-colors border-l border-gray-100">
|
||||
末页
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5l7 7-7 7M5 5l7 7-7 7" />
|
||||
</svg>
|
||||
</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-12 bg-white rounded-2xl shadow-lg border border-emerald-100">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 text-gray-300 mx-auto mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<p class="text-gray-500 text-lg">暂无分支机构设备间图片数据</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-emerald-400 to-transparent"></div>
|
||||
|
||||
<!-- 图片查看模态框 -->
|
||||
<div id="imageModal" class="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50 hidden">
|
||||
@@ -135,9 +255,7 @@ document.getElementById('imageModal').addEventListener('click', function(e) {
|
||||
});
|
||||
</script>
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 分页控件 -->
|
||||
<div class="mt-10 flex justify-center">
|
||||
@@ -165,10 +283,6 @@ document.getElementById('imageModal').addEventListener('click', function(e) {
|
||||
{% endif %}
|
||||
</nav>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-12 bg-gray-50 rounded-lg">
|
||||
<p class="text-gray-500 text-lg">暂无分支机构设备间图片数据</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -2,78 +2,146 @@
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto p-4">
|
||||
<h1 class="text-2xl font-bold mb-6">公共电子屏列表</h1>
|
||||
<!-- 页面标题 -->
|
||||
<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-cyan-500 to-transparent"></div>
|
||||
<div class="relative z-10 bg-gradient-to-r from-cyan-600 to-blue-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="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
公共电子屏列表
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-full max-w-6xl mx-auto p-6">
|
||||
<!-- 筛选区域 -->
|
||||
<div class="bg-gray-100 p-4 rounded-lg mb-6">
|
||||
<form method="get" class="flex flex-col md:flex-row gap-4">
|
||||
<div>
|
||||
<label class="block mb-2">分支机构</label>
|
||||
<select name="branch" class="border rounded p-2 w-full md:w-48">
|
||||
<option value="">所有分支机构</option>
|
||||
{% for branch in branches %}
|
||||
<option value="{{ branch.id }}" {% if request.GET.branch == branch.id|stringformat:"i" %}selected{% endif %}>{{ branch.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block mb-2">屏幕类型</label>
|
||||
<select name="screen_type" class="border rounded p-2 w-full md:w-48">
|
||||
<option value="">所有类型</option>
|
||||
<option value="marquee" {% if request.GET.screen_type == 'marquee' %}selected{% endif %}>跑马灯</option>
|
||||
<option value="advertisement" {% if request.GET.screen_type == 'advertisement' %}selected{% endif %}>广告屏</option>
|
||||
<option value="information" {% if request.GET.screen_type == 'information' %}selected{% endif %}>信息发布屏</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="self-end">
|
||||
<button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded">筛选</button>
|
||||
{% if request.GET.branch or request.GET.screen_type %}
|
||||
<a href="{% url 'public-screens' %}" class="ml-2 text-gray-600">清除筛选</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-cyan-100 mb-6">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-cyan-600 via-cyan-700 to-blue-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" class="flex flex-col md:flex-row gap-4 items-end">
|
||||
<div class="flex flex-col w-full md:w-48">
|
||||
<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-cyan-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>
|
||||
<select name="branch" class="p-2.5 border border-gray-200 rounded-lg focus:ring-2 focus:ring-cyan-300 focus:border-cyan-500 outline-none text-sm bg-gray-50 hover:bg-white transition-colors">
|
||||
<option value="">所有分支机构</option>
|
||||
{% for branch in branches %}
|
||||
<option value="{{ branch.id }}" {% if request.GET.branch == branch.id|stringformat:"i" %}selected{% endif %}>{{ branch.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex flex-col w-full md:w-48">
|
||||
<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-cyan-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
屏幕类型
|
||||
</label>
|
||||
<select name="screen_type" class="p-2.5 border border-gray-200 rounded-lg focus:ring-2 focus:ring-cyan-300 focus:border-cyan-500 outline-none text-sm bg-gray-50 hover:bg-white transition-colors">
|
||||
<option value="">所有类型</option>
|
||||
<option value="marquee" {% if request.GET.screen_type == 'marquee' %}selected{% endif %}>跑马灯</option>
|
||||
<option value="advertisement" {% if request.GET.screen_type == 'advertisement' %}selected{% endif %}>广告屏</option>
|
||||
<option value="information" {% if request.GET.screen_type == 'information' %}selected{% endif %}>信息发布屏</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="submit" class="px-5 py-2.5 bg-gradient-to-r from-cyan-600 to-cyan-700 hover:from-cyan-700 hover:to-cyan-800 text-white rounded-lg shadow-md hover:shadow-lg transition-all duration-200 font-medium flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" 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>
|
||||
筛选
|
||||
</button>
|
||||
{% if request.GET.branch or request.GET.screen_type %}
|
||||
<a href="{% url 'public-screens' %}" class="px-4 py-2.5 text-gray-600 hover:text-cyan-600 hover:bg-cyan-50 rounded-lg transition-colors font-medium">
|
||||
清除筛选
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 电子屏列表 -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{% for screen in public_screens %}
|
||||
<div class="border rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow">
|
||||
<div class="bg-white rounded-2xl overflow-hidden shadow-lg hover:shadow-2xl transition-all duration-300 border border-cyan-100 group">
|
||||
<div class="relative">
|
||||
{% if screen.image %}
|
||||
<img src="{{ screen.image.url }}" alt="{{ screen.get_screen_type_display }}" class="w-full h-[150px] object-cover cursor-pointer" onclick="openModal('{{ screen.image.url }}')">
|
||||
<img src="{{ screen.image.url }}" alt="{{ screen.get_screen_type_display }}" class="w-full h-[180px] object-cover cursor-pointer group-hover:scale-105 transition-transform duration-500" onclick="openModal('{{ screen.image.url }}')">
|
||||
{% else %}
|
||||
<div class="w-full h-[150px] bg-gray-200 flex items-center justify-center">
|
||||
<span class="text-gray-500">暂无图片</span>
|
||||
<div class="w-full h-[180px] bg-gradient-to-br from-gray-100 to-gray-200 flex items-center justify-center">
|
||||
<div class="text-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 text-gray-400 mx-auto mb-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<span class="text-gray-500 text-sm">暂无图片</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="absolute top-2 right-2 bg-black bg-opacity-50 text-white px-2 py-1 rounded text-sm">
|
||||
<div class="absolute top-3 right-3 bg-gradient-to-r from-cyan-600 to-blue-600 text-white px-3 py-1 rounded-full text-xs font-medium shadow-md">
|
||||
{{ screen.get_screen_type_display }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="font-semibold text-lg mb-2">{{ screen.branch.name }}</h3>
|
||||
<div class="p-5">
|
||||
<h3 class="font-bold text-lg mb-2 text-gray-800">{{ screen.branch.name }}</h3>
|
||||
{% if screen.description %}
|
||||
<p class="text-gray-700 mb-2">{{ screen.description|truncatechars:100 }}</p>
|
||||
<p class="text-gray-600 mb-3 text-sm leading-relaxed">{{ screen.description|truncatechars:100 }}</p>
|
||||
{% endif %}
|
||||
<div class="text-sm text-gray-500">
|
||||
<div class="text-sm space-y-1">
|
||||
{% if screen.last_drill %}
|
||||
<p>最后演练: {{ screen.last_drill.date|date:"Y-m-d H:i" }}</p>
|
||||
<p class="flex items-center gap-2 text-gray-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
最后演练: {{ screen.last_drill.date|date:"Y-m-d H:i" }}
|
||||
</p>
|
||||
{% else %}
|
||||
<p class="text-yellow-500">暂无演练记录</p>
|
||||
<p class="flex items-center gap-2 text-amber-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
暂无演练记录
|
||||
</p>
|
||||
{% endif %}
|
||||
<p>更新时间: {{ screen.updated_at|date:"Y-m-d H:i" }}</p>
|
||||
<p class="flex items-center gap-2 text-gray-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
更新时间: {{ screen.updated_at|date:"Y-m-d H:i" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="col-span-full text-center py-10">
|
||||
<p class="text-gray-500">暂无公共电子屏记录</p>
|
||||
<div class="col-span-full text-center py-12">
|
||||
<div class="bg-white rounded-2xl shadow-lg p-8 border border-cyan-100">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 text-gray-300 mx-auto mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
||||
</svg>
|
||||
<p class="text-gray-500 text-lg">暂无公共电子屏记录</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-cyan-400 to-transparent"></div>
|
||||
|
||||
<!-- 图片预览模态框 -->
|
||||
<div id="imageModal" class="fixed inset-0 bg-black bg-opacity-80 flex items-center justify-center hidden z-50">
|
||||
<button onclick="closeModal()" class="absolute top-4 right-4 text-white text-2xl">×</button>
|
||||
|
||||
@@ -1,79 +1,189 @@
|
||||
{% extends "base.html" %}
|
||||
{% load custom_filters %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto p-4">
|
||||
<!-- 筛选表单 -->
|
||||
<form method="GET" class="mb-8 p-4 bg-gray-100 rounded-lg">
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<!-- 年份选择 -->
|
||||
<div class="flex flex-col">
|
||||
<label class="text-sm font-medium">选择年份</label>
|
||||
<select name="year" class="mt-1 p-2 border rounded">
|
||||
<option value="all">全部年份</option>
|
||||
<option value="2023" {% if selected_year == '2023' %}selected{% endif %}>2023年</option>
|
||||
<option value="2024" {% if selected_year == '2024' %}selected{% endif %}>2024年</option>
|
||||
<option value="2025" {% if selected_year == '2025' %}selected{% endif %}>2025年</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 分支机构选择 -->
|
||||
<div class="flex flex-col">
|
||||
<label class="text-sm font-medium">分支机构</label>
|
||||
<select name="branch" class="mt-1 p-2 border rounded">
|
||||
<option value="all" {% if selected_branch == 'all' %}selected{% endif %}>全部分支机构</option>
|
||||
{% for branch in branches %}
|
||||
<option value="{{ branch.id }}" {% if selected_branch == branch.id|stringformat:"s" %}selected{% endif %}>
|
||||
{{ branch.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 状态选择 -->
|
||||
<div class="flex flex-col">
|
||||
<label class="text-sm font-medium">活动状态</label>
|
||||
<select name="status" class="mt-1 p-2 border rounded">
|
||||
<option value="completed" {% if selected_status == 'completed' %}selected{% endif %}>已完成</option>
|
||||
<option value="ongoing" {% if selected_status == 'ongoing' %}selected{% endif %}>未完成</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="self-end px-4 py-2 bg-blue-200 text-white rounded hover:bg-blue-700">
|
||||
筛选
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 统计结果展示 -->
|
||||
<div class="mt-4">
|
||||
<h2 class="text-xl font-bold mb-4">活动统计结果(共{{ activities.count }}条)</h2>
|
||||
<table class="min-w-full border-collapse border border-gray-300">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">活动名称</th>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">分支机构</th>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">活动分类</th>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">开始时间</th>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">结束时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for activity in activities %}
|
||||
<tr>
|
||||
<td class="p-2 border border-gray-300">{{ activity.name }}</td>
|
||||
<td class="p-2 border border-gray-300">{{ activity.branch.name }}</td>
|
||||
<td class="p-2 border border-gray-300">{{ activity.scope }}</td>
|
||||
<td class="p-2 border border-gray-300">{{ activity.start_time|format_chinese_full_date }}</td>
|
||||
<td class="p-2 border border-gray-300">{{ activity.end_time|format_chinese_full_date|default:"未结束" }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td class="p-2 border border-gray-300 text-center" colspan="4">无符合条件的活动记录</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% extends "base.html" %}
|
||||
{% load custom_filters %}
|
||||
|
||||
{% 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-rose-500 to-transparent"></div>
|
||||
<div class="relative z-10 bg-gradient-to-r from-rose-600 to-pink-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="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||
</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-rose-100 mb-6">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-rose-600 via-rose-700 to-pink-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" class="flex flex-wrap gap-4 items-end">
|
||||
<!-- 年份选择 -->
|
||||
<div class="flex flex-col">
|
||||
<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-rose-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
选择年份
|
||||
</label>
|
||||
<select name="year" class="mt-1 p-2.5 border border-gray-200 rounded-lg focus:ring-2 focus:ring-rose-300 focus:border-rose-500 outline-none text-sm bg-gray-50 hover:bg-white transition-colors">
|
||||
<option value="all">全部年份</option>
|
||||
<option value="2023" {% if selected_year == '2023' %}selected{% endif %}>2023年</option>
|
||||
<option value="2024" {% if selected_year == '2024' %}selected{% endif %}>2024年</option>
|
||||
<option value="2025" {% if selected_year == '2025' %}selected{% endif %}>2025年</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 分支机构选择 -->
|
||||
<div class="flex flex-col">
|
||||
<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-rose-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>
|
||||
<select name="branch" class="mt-1 p-2.5 border border-gray-200 rounded-lg focus:ring-2 focus:ring-rose-300 focus:border-rose-500 outline-none text-sm bg-gray-50 hover:bg-white transition-colors">
|
||||
<option value="all" {% if selected_branch == 'all' %}selected{% endif %}>全部分支机构</option>
|
||||
{% for branch in branches %}
|
||||
<option value="{{ branch.id }}" {% if selected_branch == branch.id|stringformat:"s" %}selected{% endif %}>
|
||||
{{ branch.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 状态选择 -->
|
||||
<div class="flex flex-col">
|
||||
<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-rose-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
活动状态
|
||||
</label>
|
||||
<select name="status" class="mt-1 p-2.5 border border-gray-200 rounded-lg focus:ring-2 focus:ring-rose-300 focus:border-rose-500 outline-none text-sm bg-gray-50 hover:bg-white transition-colors">
|
||||
<option value="completed" {% if selected_status == 'completed' %}selected{% endif %}>已完成</option>
|
||||
<option value="ongoing" {% if selected_status == 'ongoing' %}selected{% endif %}>未完成</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="px-5 py-2.5 bg-gradient-to-r from-rose-600 to-rose-700 hover:from-rose-700 hover:to-rose-800 text-white rounded-lg shadow-md hover:shadow-lg transition-all duration-200 font-medium flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" 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>
|
||||
筛选
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 统计结果展示 -->
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-rose-100">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-rose-50 to-pink-50 border-b-2 border-rose-200">
|
||||
<h2 class="text-lg font-bold text-gray-800 flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-rose-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||
</svg>
|
||||
活动统计结果
|
||||
<span class="ml-2 px-3 py-1 bg-rose-100 text-rose-700 rounded-full text-sm font-medium">共 {{ activities.count }} 条</span>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="bg-gradient-to-r from-rose-50 to-pink-50 border-b-2 border-rose-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-rose-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</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-rose-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-rose-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-rose-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</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-rose-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
结束时间
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100">
|
||||
{% for activity in activities %}
|
||||
<tr class="{% cycle 'bg-white' 'bg-rose-50/30' %} hover:bg-rose-50/50 transition-colors duration-200">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 font-medium">{{ activity.name }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ activity.branch.name }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-rose-100 text-rose-700">
|
||||
{{ activity.scope }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ activity.start_time|format_chinese_full_date }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">
|
||||
{% if activity.end_time %}
|
||||
{{ activity.end_time|format_chinese_full_date }}
|
||||
{% else %}
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-amber-100 text-amber-700">
|
||||
未结束
|
||||
</span>
|
||||
{% endif %}
|
||||
</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>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-rose-400 to-transparent"></div>
|
||||
{% endblock %}
|
||||
@@ -1,94 +1,178 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto p-4">
|
||||
<h2 class="text-xl font-bold mb-4">视频设备终端列表</h2>
|
||||
|
||||
<!-- 筛选表单 -->
|
||||
<form method="GET" class="mb-4 p-4 bg-gray-100 rounded-lg">
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<!-- 分支机构筛选 -->
|
||||
<div class="flex flex-col w-full md:w-1/3">
|
||||
<label class="text-sm font-medium">分支机构</label>
|
||||
<div x-data="{ open: false, search: '{{ selected_branch_name|default:'' }}', selectedId: '{{ selected_branch|default:'' }}', branches: [{% for branch in branches %}{id: {{ branch.id }}, name: '{{ branch.name }}'}{% if not forloop.last %},{% endif %}{% endfor %}] }" class="relative">
|
||||
<input type="text"
|
||||
x-model="search"
|
||||
@focus="open = true"
|
||||
@input.debounce.300ms="open = true"
|
||||
@click.away="open = false"
|
||||
placeholder="搜索分支机构..."
|
||||
class="mt-1 p-2 border rounded w-full"
|
||||
x-on:keydown.backspace="if (!search) selectedId = ''; search = ''"
|
||||
>
|
||||
<div x-show="open" class="absolute z-10 mt-1 w-full bg-white border rounded shadow-lg max-h-60 overflow-y-auto">
|
||||
<div @click="selectedId = ''; search = ''; open = false" class="p-2 hover:bg-gray-100 cursor-pointer">全部分支机构</div>
|
||||
<div x-for="branch in branches.filter(b => b.name.toLowerCase().includes(search.toLowerCase()))"
|
||||
:key="branch.id"
|
||||
@click="selectedId = branch.id; search = branch.name; open = false"
|
||||
class="p-2 hover:bg-gray-100 cursor-pointer"
|
||||
x-text="branch.name"
|
||||
></div>
|
||||
</div>
|
||||
<input type="hidden" name="branch" x-model="selectedId">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 设备类型筛选 -->
|
||||
<div class="flex flex-col w-full md:w-1/3">
|
||||
<label class="text-sm font-medium">设备类型</label>
|
||||
<div x-data="{ open: false, search: '{{ selected_type_name|default:'' }}', selectedCode: '{{ selected_type|default:'' }}', types: [{% for type_code, type_name in terminal_types %}{code: '{{ type_code }}', name: '{{ type_name }}'}{% if not forloop.last %},{% endif %}{% endfor %}] }" class="relative">
|
||||
<input type="text"
|
||||
x-model="search"
|
||||
@focus="open = true"
|
||||
@input.debounce.300ms="open = true"
|
||||
@click.away="open = false"
|
||||
placeholder="搜索设备类型..."
|
||||
class="mt-1 p-2 border rounded w-full"
|
||||
x-on:keydown.backspace="if (!search) selectedCode = ''; search = ''"
|
||||
>
|
||||
<div x-show="open" class="absolute z-10 mt-1 w-full bg-white border rounded shadow-lg max-h-60 overflow-y-auto">
|
||||
<div @click="selectedCode = ''; search = ''; open = false" class="p-2 hover:bg-gray-100 cursor-pointer">全部类型</div>
|
||||
<div x-for="type in types.filter(t => t.name.toLowerCase().includes(search.toLowerCase()))"
|
||||
:key="type.code"
|
||||
@click="selectedCode = type.code; search = type.name; open = false"
|
||||
class="p-2 hover:bg-gray-100 cursor-pointer"
|
||||
x-text="type.name"
|
||||
></div>
|
||||
</div>
|
||||
<input type="hidden" name="type" x-model="selectedCode">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-end">
|
||||
<button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">筛选</button>
|
||||
</div>
|
||||
<!-- 页面标题 -->
|
||||
<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-violet-500 to-transparent"></div>
|
||||
<div class="relative z-10 bg-gradient-to-r from-violet-600 to-purple-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="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
||||
</svg>
|
||||
视频设备终端列表
|
||||
</h1>
|
||||
</div>
|
||||
</form>
|
||||
</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-violet-100 mb-6">
|
||||
<div class="px-6 py-4 bg-gradient-to-r from-violet-600 via-violet-700 to-purple-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" class="flex flex-wrap gap-4 items-end">
|
||||
<!-- 分支机构筛选 -->
|
||||
<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-violet-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 x-data="{ open: false, search: '{{ selected_branch_name|default:'' }}', selectedId: '{{ selected_branch|default:'' }}', branches: [{% for branch in branches %}{id: {{ branch.id }}, name: '{{ branch.name }}'}{% if not forloop.last %},{% endif %}{% endfor %}] }" class="relative">
|
||||
<input type="text"
|
||||
x-model="search"
|
||||
@focus="open = true"
|
||||
@input.debounce.300ms="open = true"
|
||||
@click.away="open = false"
|
||||
placeholder="搜索分支机构..."
|
||||
class="w-full p-2.5 border border-gray-200 rounded-lg focus:ring-2 focus:ring-violet-300 focus:border-violet-500 outline-none text-sm bg-gray-50 hover:bg-white transition-colors"
|
||||
x-on:keydown.backspace="if (!search) selectedId = ''; search = ''"
|
||||
>
|
||||
<div x-show="open" class="absolute z-10 mt-1 w-full bg-white border border-gray-100 rounded-lg shadow-lg max-h-60 overflow-y-auto">
|
||||
<div @click="selectedId = ''; search = ''; open = false" class="p-2 hover:bg-violet-50 cursor-pointer">全部分支机构</div>
|
||||
<div x-for="branch in branches.filter(b => b.name.toLowerCase().includes(search.toLowerCase()))"
|
||||
:key="branch.id"
|
||||
@click="selectedId = branch.id; search = branch.name; open = false"
|
||||
class="p-2 hover:bg-violet-50 cursor-pointer"
|
||||
x-text="branch.name"
|
||||
></div>
|
||||
</div>
|
||||
<input type="hidden" name="branch" x-model="selectedId">
|
||||
</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-violet-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>
|
||||
<div x-data="{ open: false, search: '{{ selected_type_name|default:'' }}', selectedCode: '{{ selected_type|default:'' }}', types: [{% for type_code, type_name in terminal_types %}{code: '{{ type_code }}', name: '{{ type_name }}'}{% if not forloop.last %},{% endif %}{% endfor %}] }" class="relative">
|
||||
<input type="text"
|
||||
x-model="search"
|
||||
@focus="open = true"
|
||||
@input.debounce.300ms="open = true"
|
||||
@click.away="open = false"
|
||||
placeholder="搜索设备类型..."
|
||||
class="w-full p-2.5 border border-gray-200 rounded-lg focus:ring-2 focus:ring-violet-300 focus:border-violet-500 outline-none text-sm bg-gray-50 hover:bg-white transition-colors"
|
||||
x-on:keydown.backspace="if (!search) selectedCode = ''; search = ''"
|
||||
>
|
||||
<div x-show="open" class="absolute z-10 mt-1 w-full bg-white border border-gray-100 rounded-lg shadow-lg max-h-60 overflow-y-auto">
|
||||
<div @click="selectedCode = ''; search = ''; open = false" class="p-2 hover:bg-violet-50 cursor-pointer">全部类型</div>
|
||||
<div x-for="type in types.filter(t => t.name.toLowerCase().includes(search.toLowerCase()))"
|
||||
:key="type.code"
|
||||
@click="selectedCode = type.code; search = type.name; open = false"
|
||||
class="p-2 hover:bg-violet-50 cursor-pointer"
|
||||
x-text="type.name"
|
||||
></div>
|
||||
</div>
|
||||
<input type="hidden" name="type" x-model="selectedCode">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-end">
|
||||
<button type="submit" class="px-5 py-2.5 bg-gradient-to-r from-violet-600 to-violet-700 hover:from-violet-700 hover:to-violet-800 text-white rounded-lg shadow-md hover:shadow-lg transition-all duration-200 font-medium flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" 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>
|
||||
筛选
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 终端列表表格 -->
|
||||
<table class="min-w-full border-collapse border border-gray-300">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">分支机构</th>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">设备类型</th>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">设备描述</th>
|
||||
<th class="p-2 border border-gray-300 bg-gray-100">创建时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for terminal in terminals %}
|
||||
<tr class="{% cycle 'bg-white' 'bg-gray-50' %}">
|
||||
<td class="p-2 border border-gray-300">{{ terminal.branch.name }}</td>
|
||||
<td class="p-2 border border-gray-300">{{ terminal.get_terminal_type_display }}</td>
|
||||
<td class="p-2 border border-gray-300">{{ terminal.description|default:"" }}</td>
|
||||
<td class="p-2 border border-gray-300">{{ terminal.created_at|date:"Y-m-d H:i" }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="4" class="p-4 text-center text-gray-500">没有找到匹配的视频设备终端</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="bg-white rounded-2xl shadow-lg overflow-hidden border border-violet-100">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr class="bg-gradient-to-r from-violet-50 to-purple-50 border-b-2 border-violet-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-violet-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-violet-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-violet-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</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-violet-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
创建时间
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100">
|
||||
{% for terminal in terminals %}
|
||||
<tr class="{% cycle 'bg-white' 'bg-violet-50/30' %} hover:bg-violet-50/50 transition-colors duration-200">
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 font-medium">{{ terminal.branch.name }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium bg-violet-100 text-violet-700">
|
||||
{{ terminal.get_terminal_type_display }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-600">{{ terminal.description|default:"-" }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ terminal.created_at|date:"Y-m-d H:i" }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="4" 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>
|
||||
|
||||
<!-- 分隔线 -->
|
||||
<div class="h-1 my-8 rounded-full bg-gradient-to-r from-transparent via-violet-400 to-transparent"></div>
|
||||
{% endblock %}
|
||||
Binary file not shown.
@@ -28,3 +28,47 @@ def format_chinese_full_date(value):
|
||||
weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
|
||||
weekday = weekdays[date_obj.weekday()]
|
||||
return f"{date_obj.year}年{date_obj.month}月{date_obj.day}日 {weekday}"
|
||||
|
||||
|
||||
@register.filter
|
||||
def get_current_year(value=None):
|
||||
"""
|
||||
获取当前年份
|
||||
"""
|
||||
# 只有当value是datetime对象时才使用它,否则使用当前时间
|
||||
if isinstance(value, datetime):
|
||||
now = value
|
||||
else:
|
||||
now = datetime.now()
|
||||
return now.year
|
||||
|
||||
|
||||
@register.filter
|
||||
def get_statistic_period(value=None):
|
||||
"""
|
||||
计算统计周期
|
||||
规则:
|
||||
- 在2026年1月,实际统计的是2025年11月至2026年1月
|
||||
- 在2026年2月,实际统计的是2025年12月至2026年2月
|
||||
- 以此类推
|
||||
"""
|
||||
# 只有当value是datetime对象时才使用它,否则使用当前时间
|
||||
if isinstance(value, datetime):
|
||||
now = value
|
||||
else:
|
||||
now = datetime.now()
|
||||
current_year = now.year
|
||||
current_month = now.month
|
||||
|
||||
# 计算统计周期的开始月份和年份
|
||||
if current_month <= 2:
|
||||
start_year = current_year - 1
|
||||
start_month = 11 + current_month
|
||||
else:
|
||||
start_year = current_year
|
||||
start_month = current_month - 2
|
||||
|
||||
# 构建统计周期字符串
|
||||
period = f"{start_year}年{start_month}月至{current_year}年{current_month}月"
|
||||
|
||||
return period
|
||||
|
||||
@@ -15,6 +15,8 @@ urlpatterns = [
|
||||
path('branch/info/', views.Branchinfo, name='branchinfo'),
|
||||
path('statistics/', views.Statistics, name='statistics'),
|
||||
path('contact/', views.contact_list, name='contact-list'),
|
||||
path('contact/export/pdf/', views.export_contacts_pdf, name='export-contacts-pdf'),
|
||||
path('contact/export/xls/', views.export_contacts_xls, name='export-contacts-xls'),
|
||||
path('equipment-images/', views.equipment_images, name='equipment-images'),
|
||||
path('public-screens/', views.public_screens, name='public-screens'),
|
||||
path('video-terminals/', views.video_terminal_list, name='video-terminals'),
|
||||
|
||||
@@ -13,7 +13,7 @@ from django.http import HttpResponse
|
||||
import openpyxl
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.pagesizes import letter
|
||||
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph
|
||||
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
|
||||
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
||||
|
||||
import os
|
||||
@@ -135,6 +135,8 @@ def BranchAll(request):
|
||||
total_branch_count = len(branches_with_counts)
|
||||
# 获取所有分支机构总数(包括没有活动的)
|
||||
all_branch_count = Branch.objects.count()
|
||||
fen_company_count = Branch.objects.filter(name__contains='分公司').count()
|
||||
yingyebu_count = Branch.objects.filter(name__contains='营业部').count()
|
||||
# 比如说end_time()的year是2024年,但是now()是2025年的2月,fileter出来,但是如果now()是2025年3月,则不显示
|
||||
now = datetime.now()
|
||||
print(f"当前月份是{now.month},年是{now.year}")
|
||||
@@ -215,6 +217,8 @@ def BranchAll(request):
|
||||
'latest_act': latest_act,
|
||||
'total_branch_count':total_branch_count,
|
||||
'all_branch_count': all_branch_count,
|
||||
'fen_company_count': fen_company_count,
|
||||
'yingyebu_count': yingyebu_count,
|
||||
'branch_count': branch_count,
|
||||
'ongoing_activities': ongoing_activities,
|
||||
'total_activities': total_activities,
|
||||
@@ -228,16 +232,28 @@ def BranchAll(request):
|
||||
|
||||
# 生成branchinfo的视图
|
||||
def Branchinfo(request):
|
||||
branches = Branch.objects.all()
|
||||
# 统计A型、B型、C型分支机构的数量
|
||||
branches = Branch.objects.all().order_by('location', 'name')
|
||||
from collections import defaultdict
|
||||
branches_by_province = defaultdict(list)
|
||||
for branch in branches:
|
||||
branches_by_province[branch.location].append(branch)
|
||||
branches_by_province = dict(sorted(branches_by_province.items()))
|
||||
type_a_count = branches.filter(category='A型').count()
|
||||
type_b_count = branches.filter(category='B型').count()
|
||||
type_c_count = branches.filter(category='C型').count()
|
||||
all_branch_count = branches.count()
|
||||
fen_company_count = branches.filter(name__contains='分公司').exclude(name__contains='(筹)').count()
|
||||
yingyebu_count = branches.filter(name__contains='营业部').exclude(name__contains='(筹)').count()
|
||||
preparing_count = branches.filter(name__contains='(筹)').count()
|
||||
context = {
|
||||
'branches': branches,
|
||||
'branches_by_province': branches_by_province,
|
||||
'type_a_count': type_a_count,
|
||||
'type_b_count': type_b_count,
|
||||
'type_c_count': type_c_count,
|
||||
'all_branch_count': all_branch_count,
|
||||
'fen_company_count': fen_company_count,
|
||||
'yingyebu_count': yingyebu_count,
|
||||
'preparing_count': preparing_count,
|
||||
}
|
||||
return render(request, 'branch_info.html', context)
|
||||
|
||||
@@ -286,17 +302,74 @@ def export_branches_xls(request):
|
||||
worksheet.title = "分支机构信息"
|
||||
|
||||
# 添加表头
|
||||
headers = ['分支机构名称', '信息系统类别']
|
||||
headers = ['所在省份', '分支机构名称', '信息系统类别']
|
||||
for col_num, header in enumerate(headers, 1):
|
||||
worksheet.cell(row=1, column=col_num, value=header)
|
||||
|
||||
# 获取所有分支机构数据
|
||||
branches = Branch.objects.all()
|
||||
# 获取所有分支机构数据并按省份分组
|
||||
branches = Branch.objects.all().order_by('location', 'name')
|
||||
from collections import defaultdict
|
||||
branches_by_province = defaultdict(list)
|
||||
for branch in branches:
|
||||
branches_by_province[branch.location].append(branch)
|
||||
branches_by_province = dict(sorted(branches_by_province.items()))
|
||||
|
||||
# 填充数据
|
||||
for row_num, branch in enumerate(branches, 2):
|
||||
worksheet.cell(row=row_num, column=1, value=branch.name)
|
||||
worksheet.cell(row=row_num, column=2, value=branch.category)
|
||||
row_num = 2
|
||||
for province, province_branches in branches_by_province.items():
|
||||
# 添加省份标题行
|
||||
worksheet.cell(row=row_num, column=1, value=f"{province}({len(province_branches)})")
|
||||
worksheet.cell(row=row_num, column=2, value="")
|
||||
worksheet.cell(row=row_num, column=3, value="")
|
||||
|
||||
# 设置省份标题行样式
|
||||
province_row = worksheet[row_num]
|
||||
for cell in province_row:
|
||||
cell.font = Font(bold=True)
|
||||
cell.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3", fill_type="solid")
|
||||
|
||||
row_num += 1
|
||||
|
||||
# 填充该省份的分支机构数据
|
||||
for branch in province_branches:
|
||||
worksheet.cell(row=row_num, column=1, value=branch.location)
|
||||
worksheet.cell(row=row_num, column=2, value=branch.name)
|
||||
worksheet.cell(row=row_num, column=3, value=branch.category)
|
||||
row_num += 1
|
||||
|
||||
row_num += 1 # 空行分隔
|
||||
|
||||
# 添加统计信息
|
||||
row_num += 1
|
||||
worksheet.cell(row=row_num, column=1, value="省份统计")
|
||||
worksheet.cell(row=row_num, column=2, value=f"总计 {len(branches)} 个分支机构,分布在 {len(branches_by_province)} 个省份")
|
||||
worksheet.cell(row=row_num, column=3, value="")
|
||||
|
||||
# 设置统计行样式
|
||||
stats_row = worksheet[row_num]
|
||||
for cell in stats_row:
|
||||
cell.font = Font(bold=True)
|
||||
cell.fill = PatternFill(start_color="FFD700", end_color="FFD700", fill_type="solid")
|
||||
|
||||
# 添加类别统计
|
||||
row_num += 1
|
||||
type_a_count = branches.filter(category='A型').count()
|
||||
type_b_count = branches.filter(category='B型').count()
|
||||
type_c_count = branches.filter(category='C型').count()
|
||||
worksheet.cell(row=row_num, column=1, value="类别统计")
|
||||
worksheet.cell(row=row_num, column=2, value=f"A型: {type_a_count}家 | B型: {type_b_count}家 | C型: {type_c_count}家")
|
||||
worksheet.cell(row=row_num, column=3, value="")
|
||||
|
||||
# 设置类别统计行样式
|
||||
category_row = worksheet[row_num]
|
||||
for cell in category_row:
|
||||
cell.font = Font(bold=True)
|
||||
cell.fill = PatternFill(start_color="FFD700", end_color="FFD700", fill_type="solid")
|
||||
|
||||
# 设置列宽
|
||||
worksheet.column_dimensions['A'].width = 25
|
||||
worksheet.column_dimensions['B'].width = 40
|
||||
worksheet.column_dimensions['C'].width = 15
|
||||
|
||||
# 设置响应
|
||||
response = HttpResponse(content_type='application/vnd.ms-excel')
|
||||
@@ -349,13 +422,28 @@ def export_branches_pdf(request):
|
||||
title = Paragraph("分支机构信息", title_style)
|
||||
elements.append(title)
|
||||
|
||||
# 获取所有分支机构数据
|
||||
branches = Branch.objects.all()
|
||||
# 获取所有分支机构数据并按省份分组
|
||||
branches = Branch.objects.all().order_by('location', 'name')
|
||||
from collections import defaultdict
|
||||
branches_by_province = defaultdict(list)
|
||||
for branch in branches:
|
||||
branches_by_province[branch.location].append(branch)
|
||||
branches_by_province = dict(sorted(branches_by_province.items()))
|
||||
|
||||
# 准备表格数据
|
||||
data = [['分支机构名称', '信息系统类别']] # 表头
|
||||
for branch in branches:
|
||||
data.append([branch.name, branch.category])
|
||||
data = [['所在省份', '分支机构名称', '信息系统类别']] # 表头
|
||||
|
||||
# 按省份填充数据
|
||||
for province, province_branches in branches_by_province.items():
|
||||
# 添加省份标题行
|
||||
data.append([f"{province}({len(province_branches)})", '', ''])
|
||||
|
||||
# 填充该省份的分支机构数据
|
||||
for branch in province_branches:
|
||||
data.append([branch.location, branch.name, branch.category])
|
||||
|
||||
# 添加空行分隔
|
||||
data.append(['', '', ''])
|
||||
|
||||
# 创建表格
|
||||
table = Table(data)
|
||||
@@ -364,19 +452,59 @@ def export_branches_pdf(request):
|
||||
style = TableStyle([
|
||||
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
|
||||
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
|
||||
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
|
||||
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
|
||||
('FONTNAME', (0, 0), (-1, 0), chinese_font), # 使用中文字体
|
||||
('FONTSIZE', (0, 0), (-1, 0), 14),
|
||||
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
|
||||
('BACKGROUND', (0, 1), (-1, -1), colors.beige),
|
||||
('FONTNAME', (0, 1), (-1, -1), chinese_font), # 使用中文字体
|
||||
('GRID', (0, 0), (-1, -1), 1, colors.black)
|
||||
])
|
||||
|
||||
# 设置省份标题行的样式
|
||||
current_row = 1
|
||||
for province, province_branches in branches_by_province.items():
|
||||
# 省份标题行
|
||||
style.add('BACKGROUND', (0, current_row), (-1, current_row), colors.lightgrey)
|
||||
style.add('FONTNAME', (0, current_row), (-1, current_row), chinese_font)
|
||||
style.add('FONTSIZE', (0, current_row), (-1, current_row), 12)
|
||||
style.add('TEXTCOLOR', (0, current_row), (-1, current_row), colors.black)
|
||||
|
||||
current_row += 1
|
||||
|
||||
# 分支机构数据行
|
||||
for _ in province_branches:
|
||||
style.add('BACKGROUND', (0, current_row), (-1, current_row), colors.beige)
|
||||
current_row += 1
|
||||
|
||||
# 空行
|
||||
current_row += 1
|
||||
|
||||
table.setStyle(style)
|
||||
|
||||
# 添加表格到文档
|
||||
elements.append(table)
|
||||
|
||||
# 添加统计信息
|
||||
elements.append(Spacer(1, 20))
|
||||
|
||||
# 省份统计
|
||||
stats_style = ParagraphStyle(
|
||||
'Stats',
|
||||
parent=styles['Normal'],
|
||||
fontName=chinese_font,
|
||||
fontSize=12,
|
||||
spaceAfter=10
|
||||
)
|
||||
stats_text = f"省份统计:总计 {len(branches)} 个分支机构,分布在 {len(branches_by_province)} 个省份"
|
||||
elements.append(Paragraph(stats_text, stats_style))
|
||||
|
||||
# 类别统计
|
||||
type_a_count = branches.filter(category='A型').count()
|
||||
type_b_count = branches.filter(category='B型').count()
|
||||
type_c_count = branches.filter(category='C型').count()
|
||||
category_text = f"类别统计:A型: {type_a_count}家 | B型: {type_b_count}家 | C型: {type_c_count}家"
|
||||
elements.append(Paragraph(category_text, stats_style))
|
||||
|
||||
# 构建PDF
|
||||
doc.build(elements)
|
||||
|
||||
@@ -466,6 +594,176 @@ def contact_list(request):
|
||||
return render(request, 'contact_list.html', context)
|
||||
|
||||
|
||||
def export_contacts_xls(request):
|
||||
# 获取筛选参数
|
||||
branches_param = request.GET.get('branches')
|
||||
category = request.GET.get('category')
|
||||
contact_name = request.GET.get('contact_name')
|
||||
|
||||
# 构建查询条件
|
||||
filters = Q()
|
||||
|
||||
# 分支机构筛选(支持多选)
|
||||
if branches_param:
|
||||
branch_ids = [bid.strip() for bid in branches_param.split(',') if bid.strip().isdigit()]
|
||||
if branch_ids:
|
||||
filters &= Q(branch_id__in=branch_ids)
|
||||
|
||||
# 联系人类别筛选
|
||||
if category:
|
||||
filters &= Q(category__contains=category)
|
||||
|
||||
# 联系人姓名筛选
|
||||
if contact_name:
|
||||
filters &= Q(name__icontains=contact_name)
|
||||
|
||||
# 获取筛选后的联系人数据
|
||||
contacts = Contact.objects.filter(filters).order_by('branch__location', 'branch__name', 'name')
|
||||
|
||||
# 创建一个工作簿
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Font, PatternFill
|
||||
|
||||
workbook = Workbook()
|
||||
worksheet = workbook.active
|
||||
worksheet.title = "联系人信息"
|
||||
|
||||
# 添加表头
|
||||
headers = ['分支机构', '联系人类别', '姓名', '电话', '邮箱']
|
||||
for col_num, header in enumerate(headers, 1):
|
||||
cell = worksheet.cell(row=1, column=col_num, value=header)
|
||||
# 设置表头样式
|
||||
cell.font = Font(bold=True)
|
||||
cell.fill = PatternFill(start_color="4A90A4", end_color="4A90A4", fill_type="solid")
|
||||
|
||||
# 填充数据
|
||||
row_num = 2
|
||||
for contact in contacts:
|
||||
worksheet.cell(row=row_num, column=1, value=contact.branch.name)
|
||||
worksheet.cell(row=row_num, column=2, value=contact.category if contact.category else '')
|
||||
worksheet.cell(row=row_num, column=3, value=contact.name if contact.name else '')
|
||||
worksheet.cell(row=row_num, column=4, value=contact.phone if contact.phone else '')
|
||||
worksheet.cell(row=row_num, column=5, value=contact.email if contact.email else '')
|
||||
row_num += 1
|
||||
|
||||
# 设置列宽
|
||||
worksheet.column_dimensions['A'].width = 30
|
||||
worksheet.column_dimensions['B'].width = 20
|
||||
worksheet.column_dimensions['C'].width = 12
|
||||
worksheet.column_dimensions['D'].width = 15
|
||||
worksheet.column_dimensions['E'].width = 30
|
||||
|
||||
# 创建响应对象
|
||||
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
|
||||
response['Content-Disposition'] = 'attachment; filename="contacts_info.xlsx"'
|
||||
workbook.save(response)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def export_contacts_pdf(request):
|
||||
# 创建响应对象
|
||||
response = HttpResponse(content_type='application/pdf')
|
||||
response['Content-Disposition'] = 'attachment; filename="contacts_info.pdf"'
|
||||
|
||||
# 注册中文字体
|
||||
from reportlab.pdfbase import pdfmetrics
|
||||
from reportlab.pdfbase.ttfonts import TTFont
|
||||
|
||||
# 尝试注册系统中文字体,这里使用Windows系统自带的中文字体
|
||||
try:
|
||||
# 尝试注册微软雅黑字体
|
||||
pdfmetrics.registerFont(TTFont('MSYaHei', 'C:/Windows/Fonts/msyh.ttc'))
|
||||
chinese_font = 'MSYaHei'
|
||||
except:
|
||||
try:
|
||||
# 如果微软雅黑不存在,尝试注册宋体
|
||||
pdfmetrics.registerFont(TTFont('SimSun', 'C:/Windows/Fonts/simsun.ttc'))
|
||||
chinese_font = 'SimSun'
|
||||
except:
|
||||
# 如果都找不到,使用默认字体(可能仍会有乱码)
|
||||
chinese_font = 'Helvetica'
|
||||
|
||||
# 创建PDF文档
|
||||
doc = SimpleDocTemplate(response, pagesize=letter)
|
||||
elements = []
|
||||
|
||||
# 添加标题
|
||||
styles = getSampleStyleSheet()
|
||||
# 复制Title样式并修改字体
|
||||
title_style = ParagraphStyle(
|
||||
'ChineseTitle',
|
||||
parent=styles['Title'],
|
||||
fontName=chinese_font,
|
||||
fontSize=18,
|
||||
spaceAfter=30,
|
||||
alignment=1 # 1表示居中
|
||||
)
|
||||
title = Paragraph("联系人信息", title_style)
|
||||
elements.append(title)
|
||||
|
||||
# 获取筛选参数
|
||||
branches_param = request.GET.get('branches')
|
||||
category = request.GET.get('category')
|
||||
contact_name = request.GET.get('contact_name')
|
||||
|
||||
# 构建查询条件
|
||||
filters = Q()
|
||||
|
||||
# 分支机构筛选(支持多选)
|
||||
if branches_param:
|
||||
branch_ids = [bid.strip() for bid in branches_param.split(',') if bid.strip().isdigit()]
|
||||
if branch_ids:
|
||||
filters &= Q(branch_id__in=branch_ids)
|
||||
|
||||
# 联系人类别筛选
|
||||
if category:
|
||||
filters &= Q(category__contains=category)
|
||||
|
||||
# 联系人姓名筛选
|
||||
if contact_name:
|
||||
filters &= Q(name__icontains=contact_name)
|
||||
|
||||
# 获取筛选后的联系人
|
||||
contacts = Contact.objects.filter(filters)
|
||||
|
||||
# 准备表格数据
|
||||
data = [['分支机构', '分类', '姓名', '电话', '邮箱']] # 表头
|
||||
for contact in contacts:
|
||||
data.append([
|
||||
contact.branch.name if contact.branch else '',
|
||||
contact.category or '',
|
||||
contact.name or '',
|
||||
contact.phone or '',
|
||||
contact.email or ''
|
||||
])
|
||||
|
||||
# 创建表格
|
||||
table = Table(data)
|
||||
|
||||
# 设置表格样式
|
||||
style = TableStyle([
|
||||
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
|
||||
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
|
||||
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
|
||||
('FONTNAME', (0, 0), (-1, 0), chinese_font), # 使用中文字体
|
||||
('FONTSIZE', (0, 0), (-1, 0), 14),
|
||||
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
|
||||
('BACKGROUND', (0, 1), (-1, -1), colors.beige),
|
||||
('FONTNAME', (0, 1), (-1, -1), chinese_font), # 使用中文字体
|
||||
('GRID', (0, 0), (-1, -1), 1, colors.black)
|
||||
])
|
||||
table.setStyle(style)
|
||||
|
||||
# 添加表格到文档
|
||||
elements.append(table)
|
||||
|
||||
# 构建PDF
|
||||
doc.build(elements)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def video_terminal_list(request):
|
||||
# 获取筛选参数
|
||||
selected_branch = request.GET.get('branch', '')
|
||||
|
||||
382
requirements.txt
Normal file
382
requirements.txt
Normal file
@@ -0,0 +1,382 @@
|
||||
absl-py==2.3.1
|
||||
aiofiles==23.2.1
|
||||
aiohttp==3.8.5
|
||||
aiosignal==1.3.1
|
||||
altgraph==0.17.4
|
||||
annotated-types==0.6.0
|
||||
anyio==3.7.1
|
||||
appdirs==1.4.4
|
||||
argcomplete==1.10.0
|
||||
argon2-cffi==23.1.0
|
||||
argon2-cffi-bindings==21.2.0
|
||||
arrow==1.2.3
|
||||
asgiref==3.7.2
|
||||
astor==0.8.1
|
||||
asttokens==3.0.0
|
||||
astunparse==1.6.3
|
||||
async-lru==2.0.5
|
||||
async-timeout==4.0.3
|
||||
attrdict==2.0.1
|
||||
attrs==23.1.0
|
||||
autobahn==24.4.2
|
||||
Babel==2.12.1
|
||||
bce-python-sdk==0.8.90
|
||||
bcrypt==4.3.0
|
||||
beautifulsoup4==4.8.0
|
||||
binaryornot==0.4.4
|
||||
bleach==6.2.0
|
||||
blinker==1.6.2
|
||||
briefcase==0.3.19
|
||||
brotli==1.2.0
|
||||
build==0.10.0
|
||||
cachetools==5.3.1
|
||||
certifi==2023.7.22
|
||||
cffi==1.15.1
|
||||
chardet==3.0.4
|
||||
charset-normalizer==3.2.0
|
||||
ci-info==0.3.0
|
||||
click==8.1.6
|
||||
clr-loader==0.2.6
|
||||
cnocr==2.2.4
|
||||
cnstd==1.2.3.4
|
||||
colorama==0.4.6
|
||||
coloredlogs==15.0.1
|
||||
comm==0.2.2
|
||||
comtypes==1.4.8
|
||||
configobj==5.0.8
|
||||
configparser==6.0.0
|
||||
contourpy==1.1.1
|
||||
cookiecutter==2.6.0
|
||||
cryptography==41.0.3
|
||||
cssselect==1.2.0
|
||||
cssselect2==0.8.0
|
||||
cssutils==2.7.1
|
||||
cycler==0.11.0
|
||||
Cython==3.0.2
|
||||
dashscope==1.20.14
|
||||
debugpy==1.8.13
|
||||
decorator==5.1.1
|
||||
defusedxml==0.7.1
|
||||
diskcache==5.6.3
|
||||
distro==1.9.0
|
||||
Django==5.0.6
|
||||
django-appconf==1.0.6
|
||||
django-select2==8.2.1
|
||||
django-unfold==0.36.0
|
||||
djangorestframework==3.15.1
|
||||
docker-pycreds==0.4.0
|
||||
docx2pdf==0.1.8
|
||||
docx2txt==0.8
|
||||
EasyProcess==1.1
|
||||
EbookLib==0.17.1
|
||||
entrypoint2==1.1
|
||||
et-xmlfile==1.1.0
|
||||
etelemetry==0.3.0
|
||||
exceptiongroup==1.1.3
|
||||
executing==2.2.0
|
||||
extract-msg==0.23.1
|
||||
factory_boy==3.3.3
|
||||
Faker==25.2.0
|
||||
fastapi==0.103.2
|
||||
fastjsonschema==2.21.1
|
||||
filelock==3.12.4
|
||||
fire==0.5.0
|
||||
FLAML==2.1.1
|
||||
Flask==2.3.3
|
||||
flask-babel==3.1.0
|
||||
flatbuffers==25.2.10
|
||||
fonttools==4.61.1
|
||||
fqdn==1.5.1
|
||||
frontend==0.0.3
|
||||
frozenlist==1.4.0
|
||||
fsspec==2023.9.2
|
||||
future==0.18.3
|
||||
gast==0.6.0
|
||||
gevent==23.7.0
|
||||
gitdb==4.0.10
|
||||
GitPython==3.1.32
|
||||
google-pasta==0.2.0
|
||||
greenlet==3.0.1
|
||||
grpcio==1.74.0
|
||||
h11==0.14.0
|
||||
h5py==3.14.0
|
||||
httpcore==0.18.0
|
||||
httplib2==0.22.0
|
||||
httpx==0.25.0
|
||||
huggingface-hub==0.17.3
|
||||
humanfriendly==10.0
|
||||
hyperlink==21.0.0
|
||||
idna==3.4
|
||||
imageio==2.31.4
|
||||
imagekitio==4.1.0
|
||||
IMAPClient==2.1.0
|
||||
imgaug==0.4.0
|
||||
iniconfig==2.0.0
|
||||
ipykernel==6.29.5
|
||||
ipython==9.0.2
|
||||
ipython_pygments_lexers==1.1.1
|
||||
ipywidgets==8.1.5
|
||||
isodate==0.6.1
|
||||
isoduration==20.11.0
|
||||
itsdangerous==2.1.2
|
||||
jedi==0.19.2
|
||||
Jinja2==3.1.2
|
||||
jiter==0.12.0
|
||||
joblib==1.5.1
|
||||
json5==0.12.0
|
||||
jsonpointer==3.0.0
|
||||
jsonschema==4.23.0
|
||||
jsonschema-specifications==2024.10.1
|
||||
jupyter==1.1.1
|
||||
jupyter-console==6.6.3
|
||||
jupyter-events==0.12.0
|
||||
jupyter-lsp==2.2.5
|
||||
jupyter_client==8.6.3
|
||||
jupyter_core==5.7.2
|
||||
jupyter_server==2.15.0
|
||||
jupyter_server_proxy==4.4.0
|
||||
jupyter_server_terminals==0.5.3
|
||||
jupyterlab==4.3.6
|
||||
jupyterlab_pygments==0.3.0
|
||||
jupyterlab_server==2.27.3
|
||||
jupyterlab_vpython==3.1.8
|
||||
jupyterlab_widgets==3.0.13
|
||||
jwt==1.3.1
|
||||
keras==3.11.1
|
||||
keyboard==0.13.5
|
||||
kiwisolver==1.4.5
|
||||
lazy_loader==0.3
|
||||
libclang==18.1.1
|
||||
lightning-utilities==0.9.0
|
||||
livekit-api==0.2.1
|
||||
livekit-protocol==1.0.2
|
||||
lmdb==1.4.1
|
||||
loguru==0.7.2
|
||||
looseversion==1.3.0
|
||||
lxml==4.9.3
|
||||
Markdown==3.8.2
|
||||
markdown-it-py==3.0.0
|
||||
MarkupSafe==2.1.3
|
||||
matplotlib==3.8.0
|
||||
matplotlib-inline==0.1.7
|
||||
mdurl==0.1.2
|
||||
mistune==3.1.3
|
||||
ml_dtypes==0.5.3
|
||||
MouseInfo==0.1.3
|
||||
mpmath==1.3.0
|
||||
mss==9.0.1
|
||||
multidict==6.0.4
|
||||
namex==0.1.0
|
||||
nbclient==0.10.2
|
||||
nbconvert==7.16.6
|
||||
nbformat==5.10.4
|
||||
nest-asyncio==1.6.0
|
||||
networkx==3.1
|
||||
nibabel==5.1.0
|
||||
nipype==1.8.6
|
||||
notebook==7.3.3
|
||||
notebook_shim==0.2.4
|
||||
Nuitka==2.7.13
|
||||
numpy==1.26.0
|
||||
olefile==0.46
|
||||
onnx==1.14.1
|
||||
onnxruntime==1.16.0
|
||||
openai==2.14.0
|
||||
opencv-contrib-python==4.6.0.66
|
||||
opencv-python==4.11.0.86
|
||||
openpyxl==3.1.2
|
||||
opt-einsum==3.3.0
|
||||
optree==0.17.0
|
||||
ordered-set==4.1.0
|
||||
outcome==1.2.0
|
||||
overrides==7.7.0
|
||||
packaging==23.1
|
||||
paddle-bfloat==0.1.7
|
||||
paddleocr==2.7.0.3
|
||||
paddlepaddle==2.5.1
|
||||
pandas==2.1.1
|
||||
pandocfilters==1.5.1
|
||||
paramiko==3.5.1
|
||||
parso==0.8.4
|
||||
pathtools==0.1.2
|
||||
pdf2docx==0.5.6
|
||||
pdf2image==1.17.0
|
||||
pdfkit==1.0.0
|
||||
pdfminer.six==20181108
|
||||
pefile==2023.2.7
|
||||
Pillow==10.0.1
|
||||
platformdirs==3.10.0
|
||||
playwright==1.40.0
|
||||
pluggy==1.5.0
|
||||
Polygon3==3.0.9.1
|
||||
premailer==3.10.0
|
||||
prometheus_client==0.21.1
|
||||
prompt_toolkit==3.0.50
|
||||
protobuf==3.20.2
|
||||
prov==2.0.0
|
||||
psutil==5.9.5
|
||||
pure_eval==0.2.3
|
||||
pyasn1==0.6.1
|
||||
PyAudio==0.2.14
|
||||
pyautogen==0.1.10
|
||||
PyAutoGUI==0.9.54
|
||||
pyclipper==1.3.0.post5
|
||||
pycparser==2.21
|
||||
pycryptodome==3.19.0
|
||||
pydantic==2.10.4
|
||||
pydantic_core==2.27.2
|
||||
pydot==1.4.2
|
||||
pydyf==0.12.1
|
||||
pyee==11.0.1
|
||||
PyGetWindow==0.0.9
|
||||
Pygments==2.16.1
|
||||
pyinstaller==6.9.0
|
||||
pyinstaller-hooks-contrib==2024.7
|
||||
PyJWT==2.10.1
|
||||
PyMsgBox==1.0.9
|
||||
PyMuPDF @ file:///C:/Users/dxzq/Downloads/PyMuPDF-1.20.2-cp311-cp311-win_amd64.whl#sha256=8969f3a8462352d8ddb3b679e87e85f84ae4fb49d2ef5d927563ceaca9a2aeaa
|
||||
PyMuPDFb==1.23.3
|
||||
PyNaCl==1.5.0
|
||||
pynput==1.7.6
|
||||
pyoxidizer==0.24.0
|
||||
pyparsing==3.1.1
|
||||
PyPDF2==3.0.1
|
||||
pyperclip==1.8.2
|
||||
pyphen==0.17.2
|
||||
pyproject_hooks==1.0.0
|
||||
PyQt5==5.15.11
|
||||
PyQt5-Qt5==5.15.2
|
||||
PyQt5-stubs==5.15.6.0
|
||||
PyQt5_sip==12.17.0
|
||||
PyQt6==6.10.0
|
||||
PyQt6-Qt6==6.10.0
|
||||
PyQt6_sip==13.10.2
|
||||
pyreadline3==3.4.1
|
||||
PyRect==0.2.0
|
||||
pyscreenshot==3.1
|
||||
PyScreeze==0.1.29
|
||||
pyserial==3.5
|
||||
PySide6==6.9.1
|
||||
PySide6_Addons==6.9.1
|
||||
PySide6_Essentials==6.9.1
|
||||
pysnmp==7.1.15
|
||||
PySocks==1.7.1
|
||||
pytesseract==0.3.10
|
||||
pytest==8.3.2
|
||||
pytest-django==4.11.1
|
||||
pytest-qt==4.5.0
|
||||
python-dateutil==2.9.0.post0
|
||||
python-docx==0.8.11
|
||||
python-dotenv==1.0.0
|
||||
python-json-logger==3.3.0
|
||||
python-multipart==0.0.6
|
||||
python-pptx==0.6.18
|
||||
python-slugify==8.0.1
|
||||
pythonnet==3.0.1
|
||||
pytorch-lightning==2.0.9
|
||||
pytweening==1.0.7
|
||||
pytz==2023.3.post1
|
||||
PyWavelets==1.4.1
|
||||
pywin32==308
|
||||
pywin32-ctypes==0.2.2
|
||||
pywinauto==0.6.9
|
||||
pywinpty==2.0.15
|
||||
pyxnat==1.6
|
||||
PyYAML==6.0.1
|
||||
pyzmq==26.4.0
|
||||
rapidfuzz==3.3.1
|
||||
rarfile==4.1
|
||||
rdflib==7.0.0
|
||||
redis==7.0.1
|
||||
referencing==0.36.2
|
||||
reportlab==4.4.3
|
||||
requests==2.31.0
|
||||
requests-toolbelt==0.10.1
|
||||
rfc3339-validator==0.1.4
|
||||
rfc3986-validator==0.1.1
|
||||
rich==13.5.2
|
||||
rpds-py==0.24.0
|
||||
scapy==2.6.1
|
||||
schedule==1.2.2
|
||||
scikit-image==0.21.0
|
||||
scikit-learn==1.7.1
|
||||
scipy==1.11.2
|
||||
seaborn==0.12.2
|
||||
selenium==4.11.2
|
||||
Send2Trash==1.8.3
|
||||
sentry-sdk==1.31.0
|
||||
setproctitle==1.3.2
|
||||
shapely==2.0.1
|
||||
shiboken6==6.9.1
|
||||
simpervisor==1.0.0
|
||||
simplejson==3.19.1
|
||||
six==1.14.0
|
||||
smmap==5.0.0
|
||||
sniffio==1.3.0
|
||||
sortedcontainers==2.4.0
|
||||
soupsieve==2.5
|
||||
SpeechRecognition==3.8.1
|
||||
sqlparse==0.4.4
|
||||
stack-data==0.6.3
|
||||
starlette==0.27.0
|
||||
sympy==1.12
|
||||
tensorboard==2.19.0
|
||||
tensorboard-data-server==0.7.2
|
||||
tensorflow==2.19.0
|
||||
tensorflow-io-gcs-filesystem==0.31.0
|
||||
termcolor==2.3.0
|
||||
terminado==0.18.1
|
||||
text-unidecode==1.3
|
||||
textract==1.6.3
|
||||
threadpoolctl==3.6.0
|
||||
tifffile==2023.9.26
|
||||
tinycss2==1.5.1
|
||||
tinyhtml5==2.0.0
|
||||
toga==0.3.1
|
||||
toga-core==0.4.6
|
||||
toga-winforms==0.4.6
|
||||
tomli_w==1.0.0
|
||||
torch==2.0.1
|
||||
torchmetrics==1.2.0
|
||||
torchvision==0.15.2
|
||||
tornado==6.4.2
|
||||
tqdm==4.66.1
|
||||
traitlets==5.14.3
|
||||
traits==6.3.2
|
||||
travertino==0.3.0
|
||||
trio==0.22.2
|
||||
trio-websocket==0.10.3
|
||||
txaio==23.1.1
|
||||
types-protobuf==5.29.1.20250403
|
||||
typing_extensions==4.12.2
|
||||
tzdata==2023.3
|
||||
tzlocal==1.5.1
|
||||
Unidecode==1.3.7
|
||||
uri-template==1.3.0
|
||||
urllib3==1.26.20
|
||||
uvicorn==0.23.2
|
||||
visualdl==2.5.3
|
||||
vpython==7.6.5
|
||||
wandb==0.15.11
|
||||
wcwidth==0.2.13
|
||||
weasyprint==67.0
|
||||
webcolors==24.11.1
|
||||
webdriver-manager==4.0.0
|
||||
webencodings==0.5.1
|
||||
websocket==0.2.1
|
||||
websocket-client==1.8.0
|
||||
Werkzeug==2.3.7
|
||||
wget==3.2
|
||||
widgetsnbextension==4.0.13
|
||||
win32-setctime==1.1.0
|
||||
wrapt==1.17.2
|
||||
wsproto==1.2.0
|
||||
xlrd==1.2.0
|
||||
XlsxWriter==3.2.0
|
||||
yarl==1.9.2
|
||||
zai-sdk==0.0.4
|
||||
zhipuai==2.1.5.20250106
|
||||
zope.event==5.0
|
||||
zope.interface==6.0
|
||||
zopfli==0.4.0
|
||||
zstandard==0.24.0
|
||||
Reference in New Issue
Block a user