违禁品查获排行榜系统 - 开发文档
1. 项目概述
“违禁品查获排行榜系统”是一个用于记录、统计和展示安检团队违禁品查获数据的应用。它包含一个Web界面用于实时展示排行榜,以及一个后端脚本用于数据管理和通知。系统设计旨在提供直观的排行榜展示、便捷的数据管理和自动化的通知功能。
2. 逻辑实现
2.1 架构概览
项目采用前后端分离的轻量级架构:
- 数据管理层:
/root/.openclaw/workspace/contraband_manager/update_security_ranking_v2.py负责数据的增删改查、人员管理、数据备份和企业微信通知。 - 展示层:
/root/.openclaw/workspace/contraband_manager/app.py是一个基于 Flask 的Web应用,负责从数据文件读取数据并渲染到前端页面,提供实时的排行榜展示和查获详情。 - 数据存储: 使用
security_data_v2.json作为主要数据存储文件。 - 前端界面:
/root/.openclaw/workspace/contraband_manager/templates/index.html使用HTML、CSS和JavaScript实现响应式设计,提供“本月榜”和“总榜”切换、三甲配色、列表渐入动画、数字滚动特效和详情弹窗功能。
2.2 数据管理脚本 (update_security_ranking_v2.py)
该脚本是系统的核心数据处理器,提供命令行接口进行数据操作。
2.2.1 核心功能
- 数据加载与保存:
load_data()和save_data()函数负责从security_data_v2.json加载和保存数据。save_data()会自动更新元数据(如脚本版本、最后更新时间)并触发异步备份到WebDAV。 - 人员管理:
add_member(name_with_shift): 新增活跃人员,支持“姓名(班次)”格式。remove_member(name): 将人员标记为“离职”状态,不再参与排名,但历史记录保留。
- 记录管理:
record_entry(name, content, biz_date_manual): 录入新的查获记录。支持手动指定业务日期,否则根据当前时间(凌晨0-5点算前一日)自动判定。每条记录会被分配一个唯一ID。delete_entry(log_id): 根据记录ID,将记录标记为“已删除”,数据不会真正移除,但不会在排名和查询中显示。
- 查询功能:
query_logs(mode, value): 根据姓名或日期查询查获记录。
- 排行榜统计:
get_ranking(target_month): 统计指定月份或当前月份(根据业务日期逻辑)的违禁品查获排行榜。
- 企业微信通知:
send_notification(action_text, data)函数在每次数据更新后,异步发送包含最新排名和最近动态的企业微信通知。通知内容经过格式化,支持姓名对齐。 - WebDAV 备份:
upload_to_webdav(local_path, remote_sub_path)函数负责将security_data_v2.json和脚本自身备份到WebDAV服务器,确保数据和代码版本安全。
2.2.2 业务日期修正逻辑
- 脚本内定义了北京时区 (
BEIJING_TZ)。 record_entry函数在自动判定业务日期时,如果当前时间是当日00:00到05:00之间,则记录归属于前一个日历日。这有助于正确处理跨夜班的查获记录。
2.3 Web展示应用 (app.py)
这是一个轻量级的Flask应用,专注于数据展示。
2.3.1 核心功能
- Flask 应用初始化: 创建Flask应用实例。
- 数据加载与处理:
load_and_process_data()函数负责从security_data_v2.json读取数据。它将原始数据处理成前端所需的“月榜”和“总榜”格式,并对人员按分数降序排序。- “月榜”: 仅统计当月有查获记录的活跃人员。
- “总榜”: 统计所有活跃人员(包括0记录),显示他们的总查获数。
- 路由:
/(根路径): 渲染index.html模板,并将处理后的排行榜数据以JSON格式嵌入到页面中。/api/rankings: 提供一个API接口,返回纯JSON格式的排行榜数据,供前端进行异步刷新。
- 环境变量支持:
DATA_FILE、FLASK_DEBUG、FLASK_HOST和FLASK_PORT可以通过环境变量进行配置。
2.4 前端界面 (templates/index.html)
采用响应式设计,提供良好的移动端体验。
2.4.1 主要组件与功能
- 头部 (Header): 显示应用标题和副标题。
- Tab 切换: “本月”和“总榜”两个Tab按钮,用于切换排行榜显示。
- 列表容器: 动态加载和显示排行榜列表。
- 列表项 (Item):
- 显示排名、姓名、班次和查获票数。
- 前三名有特殊的金/银/铜配色和阴影效果。
- 列表项支持点击,会弹出详情弹窗。
- 列表项采用渐入动画 (
fadeInUp)。 - 查获票数有数字滚动动画 (
countPop)。
- 详情弹窗 (Modal):
- 点击列表项后弹出,显示该人员的所有查获记录详情。
- 详情内容中的特定关键词(如“打火机”、“管制刀具”等)会被高亮显示。
- 支持点击弹窗外部或关闭按钮来关闭。
- 详情列表项也有渐入动画 (
fadeInDetail)。
- 数据嵌入与异步刷新:
- 初始数据通过
data_json变量从Flask后端嵌入到HTML中。 - 页面每15秒通过
/api/rankings接口异步获取最新数据并刷新列表,实现实时更新。
- 初始数据通过
- 空状态: 当无数据时,显示友好的“暂无数据”提示。
3. 使用指南
3.1 数据管理 (通过命令行脚本 update_security_ranking_v2.py)
你可以通过在终端执行 Python 脚本来管理数据。
3.1.1 新增成员
格式:python3 update_security_ranking_v2.py 新增 姓名(班次)
示例:
python3 update_security_ranking_v2.py 新增 张三(早班)
python3 update_security_ranking_v2.py 新增 李四(晚班)
3.1.2 去除成员 (标记为离职)
格式:python3 update_security_ranking_v2.py 去除 姓名
示例:
python3 update_security_ranking_v2.py 去除 张三
被去除的成员将不再参与排名,但历史记录仍保留。
3.1.3 录入查获记录
格式:python3 update_security_ranking_v2.py 姓名 查获内容
示例:
python3 update_security_ranking_v2.py 张三 打火机2个
python3 update_security_ranking_v2.py 李四 仿真枪1把
注意:
- 脚本会自动判断业务日期(凌晨0-5点算前一日)。
- 每次录入都会增加该成员的查获票数。
3.1.4 补录查获记录 (指定日期)
格式:python3 update_security_ranking_v2.py 姓名 查获内容 YYYY-MM-DD (日期格式为 月-日,年份默认为当前年份)
示例:
python3 update_security_ranking_v2.py 张三 不明液体1瓶 02-05
这会在当前年份的2月5日为张三补录一条记录。
3.1.5 删除查获记录 (标记为删除)
格式:python3 update_security_ranking_v2.py 删除 #索引号
示例:
python3 update_security_ranking_v2.py 删除 #123
记录将被标记为删除,不再显示在排行榜和查询结果中。
3.1.6 查询记录
- 按姓名查询:
python3 update_security_ranking_v2.py 违禁品查询 姓名示例:python3 update_security_ranking_v2.py 违禁品查询 张三 - 按日期查询:
python3 update_security_ranking_v2.py 违禁品查询 月-日(日期格式为月-日) 示例:python3 update_security_ranking_v2.py 违禁品查询 02-06
3.1.7 查看排行榜
格式:python3 update_security_ranking_v2.py 排行榜 [月份]
- 查看当前月份排行榜(根据业务日期逻辑):
python3 update_security_ranking_v2.py 排行榜 - 查看指定月份排行榜:
python3 update_security_ranking_v2.py 排行榜 01(表示1月) 或python3 update_security_ranking_v2.py 排行榜 2026-01
3.2 Web展示 (通过Web应用 app.py)
Web界面提供了排行榜的实时展示。
- 访问地址: 默认通过
http://127.0.0.1:9517访问。如果部署到服务器,则访问服务器IP和对应端口。 - 功能:
- 切换“本月”和“总榜”查看不同维度的排名。
- 点击任意列表项可查看该人员的详细查获记录。
- 页面每15秒自动刷新数据。
4. 部署指南
本系统推荐使用 systemd 或 Docker 进行部署,并可选择性地使用 Nginx 进行反向代理和SSL加密。
4.1 前置条件
- Python 3.x 及
pip。 Flask库 (pip install Flask)。requests库 (pip install requests)。supervisor(推荐用于进程守护,或使用systemd)。curl(用于WebDAV备份)。
4.2 部署步骤
4.2.1 准备项目文件
将 contraband_manager 目录下的所有文件(包括 app.py, update_security_ranking_v2.py, templates/ 等)上传到服务器的指定目录,例如 /opt/contraband_ranking/。
# 假设你在项目根目录
sudo mkdir -p /opt/contraband_ranking
sudo cp -r contraband_manager/* /opt/contraband_ranking/
sudo cp security_data_v2.json /opt/contraband_ranking/ # 如果数据文件在上一级目录
cd /opt/contraband_ranking
pip install -r requirements.txt # 如果有requirements.txt
注意: 确保 security_data_v2.json 数据文件与 app.py 位于同一目录,或者根据 app.py 中的 DATA_FILE 路径进行配置。建议将 security_data_v2.json 放在 /opt/contraband_ranking/ 目录下。
4.2.2 配置环境变量
你可以在启动脚本或 systemd 配置中设置环境变量来覆盖默认值:
CONTRABAND_DATA_FILE: 数据文件的绝对路径 (默认为app.py同目录下的security_data_v2.json)。FLASK_DEBUG:True或False,控制 Flask 调试模式 (默认为False)。FLASK_HOST: Flask 监听的IP地址 (默认为127.0.0.1)。设置为0.0.0.0可以从外部访问。FLASK_PORT: Flask 监听的端口 (默认为9517)。WEBHOOK_URL: 企业微信Webhook URL (在update_security_ranking_v2.py中配置)。
4.2.3 方式一:使用 Systemd 部署 (推荐)
4.2.3.1 创建 Flask Web 应用的 Systemd 服务
在 /etc/systemd/system/ 目录下创建 contraband_ranking_web.service 文件:
[Unit]
Description=Contraband Ranking Web Application
After=network.target
[Service]
User=root
WorkingDirectory=/opt/contraband_ranking
ExecStart=/usr/bin/python3 app.py
Restart=always
Environment="FLASK_HOST=0.0.0.0"
Environment="FLASK_PORT=9517"
Environment="CONTRABAND_DATA_FILE=/opt/contraband_ranking/security_data_v2.json"
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
注意: User 可以改为非root用户,但需要确保该用户对 /opt/contraband_ranking/ 目录和 security_data_v2.json 文件有读写权限。
4.2.3.2 创建数据管理脚本的 Systemd Timer (可选,用于定时执行统计或清理任务)
如果你需要定时执行 update_security_ranking_v2.py 的某些功能(例如每日/每月统计、数据清理等),可以创建 systemd timer。
创建 contraband_ranking_update.service:
[Unit]
Description=Contraband Ranking Data Update
After=network.target
[Service]
User=root
WorkingDirectory=/opt/contraband_ranking
ExecStart=/usr/bin/python3 update_security_ranking_v2.py # 这里可以添加具体参数,例如 排行榜
StandardOutput=journal
StandardError=journal
创建 contraband_ranking_update.timer (例如,每天凌晨2点执行):
[Unit]
Description=Run Contraband Ranking Data Update Daily
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
4.2.3.3 启用并启动服务
sudo systemctl daemon-reload
sudo systemctl enable contraband_ranking_web.service
sudo systemctl start contraband_ranking_web.service
# 如果创建了timer
sudo systemctl enable contraband_ranking_update.timer
sudo systemctl start contraband_ranking_update.timer
4.2.3.4 查看状态和日志
sudo systemctl status contraband_ranking_web.service
sudo journalctl -u contraband_ranking_web.service -f
4.2.4 方式二:使用 Docker 部署 (推荐,更易于环境隔离和迁移)
4.2.4.1 创建 Dockerfile
在 /opt/contraband_ranking/ 目录下创建 Dockerfile:
# 使用官方Python运行时作为父镜像
FROM python:3.9-slim-buster
# 设置工作目录
WORKDIR /app
# 复制requirements.txt并安装依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 复制项目文件
COPY . .
# 暴露端口
EXPOSE 9517
# 定义默认命令来运行应用程序
CMD ["python3", "app.py"]
如果 requirements.txt 不存在,你需要根据 app.py 和 update_security_ranking_v2.py 的依赖(Flask, requests)手动创建。
4.2.4.2 构建 Docker 镜像
在 /opt/contraband_ranking/ 目录下执行:
sudo docker build -t contraband-ranking-app .
4.2.4.3 运行 Docker 容器
sudo docker run -d \
--name contraband-ranking \
-p 9517:9517 \
-v /opt/contraband_ranking/security_data_v2.json:/app/security_data_v2.json \
-e FLASK_HOST=0.0.0.0 \
-e FLASK_PORT=9517 \
contraband-ranking-app
说明:
-d: 后台运行容器。--name contraband-ranking: 为容器指定名称。-p 9517:9517: 将主机的 9517 端口映射到容器的 9517 端口。-v /opt/contraband_ranking/security_data_v2.json:/app/security_data_v2.json: 将主机上的数据文件挂载到容器内部,以便数据持久化和外部管理。-e: 设置环境变量。
4.2.4.4 查看 Docker 容器状态和日志
sudo docker ps
sudo docker logs -f contraband-ranking
4.2.5 使用 Nginx 进行反向代理和 HTTPS (可选,生产环境推荐)
如果你希望通过域名访问并启用 HTTPS,可以使用 Nginx 作为反向代理。
4.2.5.1 安装 Nginx
sudo apt update
sudo apt install nginx
4.2.5.2 配置 Nginx
在 /etc/nginx/sites-available/ 目录下创建或编辑配置文件 (例如 contraband_ranking.conf):
server {
listen 80;
server_name your_domain.com; # 替换为你的域名
location / {
proxy_pass http://127.0.0.1:9517; # 指向你的Flask应用监听地址和端口
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 如果需要 HTTPS,使用 Certbot 配置
# listen 443 ssl;
# ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
# include /etc/letsencrypt/options-ssl-nginx.conf;
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
4.2.5.3 启用 Nginx 配置并重启
sudo ln -s /etc/nginx/sites-available/contraband_ranking.conf /etc/nginx/sites-enabled/
sudo nginx -t # 测试配置
sudo systemctl restart nginx
4.2.5.4 配置 HTTPS (推荐使用 Certbot)
如果你有域名,强烈建议使用 Let's Encrypt 和 Certbot 来获取免费的 SSL 证书并配置 HTTPS。
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your_domain.com
按照提示操作即可。Certbot 会自动修改 Nginx 配置并设置证书自动续期。
5. 数据文件结构 (security_data_v2.json)
{
"meta": {
"script_version": "v2.3.8",
"last_update": "2026-02-06T20:30:00+08:00"
},
"members": {
"张三": {
"shift": "早班",
"status": "active"
},
"李四": {
"shift": "晚班",
"status": "offboarded"
}
},
"logs": [
{
"id": 0,
"name": "张三",
"content": "打火机2个",
"actual_time": "2026-02-06T10:00:00+08:00",
"biz_date": "2026-02-06",
"biz_month": "2026-02",
"is_deleted": false
},
{
"id": 1,
"name": "李四",
"content": "仿真枪1把",
"actual_time": "2026-02-06T03:00:00+08:00",
"biz_date": "2026-02-05",
"biz_month": "2026-02",
"is_deleted": false
}
],
"last_id": 1
}
meta: 包含脚本版本和最后更新时间等元数据。members: 存储所有人员信息。name: 成员姓名。shift: 班次。status:active(活跃) 或offboarded(离职)。
logs: 存储所有查获记录。id: 唯一记录ID。name: 查获人员姓名。content: 查获内容。actual_time: 记录的实际时间(ISO格式)。biz_date: 业务日期 (yyyy-mm-dd格式,考虑了跨夜班逻辑)。biz_month: 业务月份 (yyyy-mm格式)。is_deleted: 布尔值,标记记录是否被删除。
last_id: 最后一个记录的ID,用于生成新的唯一ID。
6. 维护与扩展
- 数据备份:
update_security_ranking_v2.py已集成WebDAV备份功能,请确保WebDAV配置正确。 - 日志: Web应用和脚本的输出都建议通过
systemd journal或 Docker 日志进行监控。 - 扩展功能:
- 如果需要新的数据管理功能,可以直接修改
update_security_ranking_v2.py。 - 如果需要新的Web展示页面或功能,可以修改
app.py和templates/index.html。 - 新增关键词高亮:修改
index.html中的JavaScriptreplace正则表达式。
- 如果需要新的数据管理功能,可以直接修改