# 违禁品查获排行榜系统 - 开发文档 ## 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 新增 姓名(班次)` 示例: ```bash python3 update_security_ranking_v2.py 新增 张三(早班) python3 update_security_ranking_v2.py 新增 李四(晚班) ``` #### 3.1.2 去除成员 (标记为离职) 格式:`python3 update_security_ranking_v2.py 去除 姓名` 示例: ```bash python3 update_security_ranking_v2.py 去除 张三 ``` 被去除的成员将不再参与排名,但历史记录仍保留。 #### 3.1.3 录入查获记录 格式:`python3 update_security_ranking_v2.py 姓名 查获内容` 示例: ```bash 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` (日期格式为 `月-日`,年份默认为当前年份) 示例: ```bash python3 update_security_ranking_v2.py 张三 不明液体1瓶 02-05 ``` 这会在当前年份的2月5日为张三补录一条记录。 #### 3.1.5 删除查获记录 (标记为删除) 格式:`python3 update_security_ranking_v2.py 删除 #索引号` 示例: ```bash 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/`。 ```bash # 假设你在项目根目录 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` 文件: ```ini [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`: ```ini [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点执行): ```ini [Unit] Description=Run Contraband Ranking Data Update Daily [Timer] OnCalendar=*-*-* 02:00:00 Persistent=true [Install] WantedBy=timers.target ``` ##### 4.2.3.3 启用并启动服务 ```bash 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 查看状态和日志 ```bash 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`: ```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/` 目录下执行: ```bash sudo docker build -t contraband-ranking-app . ``` ##### 4.2.4.3 运行 Docker 容器 ```bash 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 容器状态和日志 ```bash sudo docker ps sudo docker logs -f contraband-ranking ``` #### 4.2.5 使用 Nginx 进行反向代理和 HTTPS (可选,生产环境推荐) 如果你希望通过域名访问并启用 HTTPS,可以使用 Nginx 作为反向代理。 ##### 4.2.5.1 安装 Nginx ```bash sudo apt update sudo apt install nginx ``` ##### 4.2.5.2 配置 Nginx 在 `/etc/nginx/sites-available/` 目录下创建或编辑配置文件 (例如 `contraband_ranking.conf`): ```nginx 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 配置并重启 ```bash 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。 ```bash sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d your_domain.com ``` 按照提示操作即可。Certbot 会自动修改 Nginx 配置并设置证书自动续期。 ## 5. 数据文件结构 (`security_data_v2.json`) ```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` 中的JavaScript `replace` 正则表达式。