feat: 升级到v0.8.0版本并新增审计日志等功能 - 升级版本号从v0.7.0到v0.8.0 - 新增审计日志功能,支持全量操作记录、筛选查询和CSV导出 - 新增设备更换记录功能,支持MAC地址更换历史与库存序列号联动 - 新增iOS PWA主屏幕支持,实现standalone模式safe area适配 - 删除过时的技术流程文档 - 补充开发规范说明,包括Alembic迁移、Celery worker重建、区域管理员过滤等重要规则 ```
14 KiB
H3C ONU设备管理系统 - Claude开发指南
项目概述
这是一个基于 Python FastAPI + Vue 3 的 H3C OLT 设备监控管理系统,用于监控 4000+ ONU 设备的在线状态。
当前版本: v0.8.0 开发状态: 核心功能已完成,权限与运维功能完善中
已实现功能:
- ✅ SSH 连接 H3C OLT 设备查询 ONU 状态(支持 More 分页、终端控制字符清理)
- ✅ Excel 数据导入和批量管理
- ✅ 定时自动状态检查(可配置间隔,最小5分钟)+ 手动触发
- ✅ Casdoor 统一认证和 JWT 令牌管理
- ✅ 设备管理(列表、详情、筛选、分页)
- ✅ 统计仪表板(总数、在线、离线)+ 区域分布饼图 + 7天趋势折线图
- ✅ 完整 RBAC 权限管理(角色、权限、用户管理页面)
- ✅ OLT 管理(增删改查、批量导入、区域动态同步)
- ✅ OLT 端口管理(查看端口状态、开关端口)
- ✅ 重复 MAC 检测与清除
- ✅ 新设备发现与信息补全
- ✅ 快速扫描(多线程并发)
- ✅ 环路检测
- ✅ 系统设置(管理员可配置检查间隔,显示下次扫描时间/扫描中状态)
- ✅ 库存管理模块(物料、序列号设备、出入库、盘点)
- ✅ 每日状态快照(凌晨1点聚合,用于趋势图性能优化)
- ✅ 审计日志(全量操作记录、筛选查询、CSV 导出)
- ✅ 设备更换记录(MAC 地址更换历史,与库存序列号联动)
- ✅ iOS PWA 主屏幕支持(standalone 模式 safe area 适配)
技术栈:
- 后端:Python FastAPI + PostgreSQL + Celery + Redis + Paramiko
- 前端:Vue 3 + Element Plus + Pinia + Axios
- 部署:Docker Compose
已实现的 API 端点
认证相关
GET /api/auth/login- 获取 Casdoor 登录 URLPOST /api/auth/callback- Casdoor 登录回调GET /api/auth/profile- 获取当前用户信息
设备管理
GET /api/devices- 获取设备列表(分页、筛选)GET /api/devices/{id}- 获取设备详情
状态检查
POST /api/check/status- 手动触发状态检查
数据导入
POST /api/import/upload- 上传并导入 Excel 文件
统计信息
GET /api/stats/summary- 获取统计摘要(总数、在线、离线)
系统
GET /health- 健康检查GET /docs- API 文档(Swagger UI)
Rules
代码规范
Python 后端规范
- 遵循 PEP 8 规范
- 使用 Black 进行代码格式化
- 使用 isort 进行导入排序
- 使用类型注解(Type Hints)
- 异步函数使用 async/await
- 错误处理使用自定义异常类
Vue 前端规范
- 使用 Composition API(setup script)
- 组件使用 PascalCase 命名
- 使用 TypeScript 类型检查
- 遵循 Vue 官方风格指南
- 使用 ESLint + Prettier 格式化
Git 提交规范
使用 Conventional Commits 格式:
<type>(<scope>): <subject>
类型:feat, fix, docs, style, refactor, test, chore
示例:feat(device): 添加设备导入功能
架构规则
后端架构
- 分层架构:API → Service → Model
- API 层:仅处理请求/响应,调用 Service
- Service 层:业务逻辑,不直接操作数据库
- Model 层:SQLAlchemy 模型定义
- 异步任务:耗时操作使用 Celery
前端架构
- 组件分类:
components/common/:通用组件components/business/:业务组件views/:页面组件
- 状态管理:使用 Pinia stores
- API 调用:统一在
api/目录封装
安全规则
数据安全
- SSH 密码必须加密存储(使用 Fernet 加密)
- 敏感信息通过环境变量配置
- 数据库连接使用 SSL
- 定期备份数据(90天历史记录)
应用安全
- 所有 API 端点需要认证(除登录接口)
- 实现 CSRF 保护
- 输入验证使用 Pydantic
- SQL 注入防护(使用 ORM)
- XSS 防护(前端转义)
访问控制
- 基于 RBAC 的权限控制
- 数据级权限过滤(按区域/学校)
- 操作审计日志记录
- 设备信息变更需要审核
性能规则
数据库优化
- 为常用查询字段添加索引
- 使用连接池(pool_size=20)
- 避免 N+1 查询问题
- 定期清理历史数据(保留90天)
缓存策略
- Redis 缓存热点数据(设备状态)
- 缓存过期时间:30分钟
- 手动刷新有5分钟冷却限制
异步处理
- SSH 状态检查使用 Celery 异步任务
- 批量导入使用后台任务
- 定时任务使用 Celery Beat
开发规则
环境配置
- 开发环境使用
.env.development - 生产环境使用
.env.production - 不提交
.env文件到 Git - 提供
.env.example模板
测试要求
- 核心业务逻辑需要单元测试
- API 端点需要集成测试
- 测试覆盖率目标:≥80%
文档要求
- API 变更及时更新 Swagger 文档
- 复杂业务逻辑添加注释
- 重要配置添加说明
部署规则
Docker 部署
- 使用 Docker Compose 编排
- 外部 PostgreSQL 和 Redis(不在容器内)
- 日志挂载到宿主机
- 使用 Nginx 反向代理
环境变量
必需配置:
DATABASE_URL:PostgreSQL 连接字符串REDIS_URL:Redis 连接字符串CASDOOR_*:Casdoor 认证配置SECRET_KEY:应用密钥
监控告警
- 健康检查端点:
/health - 性能指标端点:
/metrics - 日志级别:生产环境使用 INFO
部署陷阱与经验教训
修改代码后必须重新构建镜像
问题:修改了宿主机上的源码后,直接 docker compose up -d 或 docker compose restart 不会让容器使用新代码。容器运行的是构建时打包进镜像的旧代码。
正确流程:
# 1. 重新构建镜像(必须加 --no-cache 确保不用旧层)
docker compose build --no-cache backend # 或 frontend,或两者
# 2. 重新创建容器(必须用 rm + up,或 up --force-recreate)
docker compose rm -f backend
docker compose up -d backend
# 3. 如有数据库模型变更,执行迁移
docker compose exec backend alembic upgrade head
不要用:
docker compose restart:只重启进程,不更新镜像docker compose up -d(无 build):容器配置变了会重建,但镜像不变
端口被占用导致容器启动但无端口映射
问题:如果宿主机端口已被其他容器占用,新容器会启动成功(docker compose up 不报错),但端口映射为空 {},外部无法访问。
排查方法:
# 检查端口映射是否正常
docker inspect <container> --format '{{json .NetworkSettings.Ports}}'
# 查看谁占用了端口
docker ps | grep <port>
解决方法:先停掉占用端口的旧容器,再 docker compose rm -f && docker compose up -d。
frontend 容器必须配置 VITE_API_PROXY_TARGET
问题:根目录 docker-compose.yml 的 frontend 服务如果没有配置 VITE_API_PROXY_TARGET,Vite 代理会默认打到 http://localhost:8001,导致所有 /api 请求 500 或无法到达后端。
必须在 docker-compose.yml 中配置:
frontend:
build: ./frontend
ports:
- "5173:5173"
environment:
- VITE_API_PROXY_TARGET=http://backend:8000
新增数据库模型后必须执行迁移
问题:新增了 SQLAlchemy 模型(如 DeviceDailySnapshot、SystemSetting),重建镜像后如果不执行 alembic upgrade head,表不存在会导致 500 错误。
每次新增模型的完整流程:
# 1. 创建迁移文件(在宿主机或容器内)
docker compose exec backend alembic revision --autogenerate -m "描述"
# 2. 重建镜像
docker compose build --no-cache backend
# 3. 重启容器
docker compose rm -f backend && docker compose up -d backend
# 4. 执行迁移
docker compose exec backend alembic upgrade head
Alembic 迁移文件 revision ID 不能重复
问题:手动创建迁移文件时,如果 revision 字段与已有文件重复,alembic upgrade head 会报 Multiple head revisions are present 错误。
规则:手动创建迁移文件时,revision ID 使用不与现有文件冲突的唯一字符串(如 h8i9j0k1l2m3),并确认 down_revision 指向正确的上一个版本。
Celery worker 必须重建才能识别新任务
问题:新增 Celery 任务模块后,如果只重建 backend 而不重建 celery-worker,worker 不会注册新任务,消息会被丢弃并报 KeyError。
规则:新增任务模块后,backend 和 celery-worker 都必须重建:
docker compose build --no-cache backend celery-worker
docker compose rm -f backend celery-worker
docker compose up -d backend celery-worker
验证任务是否注册:
docker compose exec celery-worker celery -A celery_worker.celery_app inspect registered
区域管理员多区域过滤必须用 .in_() 而非 ==
问题:assigned_area 字段存储逗号分隔的多个区域(如 "城区,郊区"),用 == 只能匹配整个字符串,导致多区域管理员只能看到第一个区域的数据。
规则:所有涉及 assigned_area 的过滤都必须先 split 再用 .in_():
areas = [a.strip() for a in current['assigned_area'].split(',') if a.strip()]
query = query.filter(Model.region.in_(areas))
Vite dev server 通过反向代理访问需配置 allowedHosts
问题:通过域名反向代理访问 Vite dev server 时,会报 Blocked request. This host is not allowed。
解决:在 vite.config.js 中设置:
server: {
allowedHosts: ['all', 'your-domain.com'],
}
iOS PWA standalone 模式与 Safari 的 safe area 差异
问题:env(safe-area-inset-top) 在 Safari 浏览器中为 0(有地址栏占位),在 standalone 模式(添加到主屏幕)下为真实刘海高度(44-59px)。直接使用会导致 Safari 中布局正常但 standalone 中顶栏/弹窗重叠。
规则:所有 safe area 相关样式必须包在 @media (display-mode: standalone) 中,Safari 不受影响:
@media (display-mode: standalone) {
.mobile-topbar {
height: calc(52px + env(safe-area-inset-top));
}
}
ElMessage 的 offset 通过 src/utils/message.js 封装统一处理,所有页面从该文件导入而非直接从 element-plus 导入。
Docker healthcheck 镜像内无 curl
问题:backend 镜像基于 Python slim,没有 curl,healthcheck 用 curl 会导致所有依赖服务启动失败。
规则:healthcheck 使用 Python 内置模块:
healthcheck:
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
interval: 15s
timeout: 10s
retries: 5
start_period: 40s
项目结构
H3ConuMS2/
├── backend/ # Python 后端
│ ├── app/
│ │ ├── api/ # API 路由
│ │ ├── core/ # 核心配置
│ │ ├── models/ # 数据模型
│ │ ├── schemas/ # Pydantic 模式
│ │ ├── services/ # 业务逻辑
│ │ ├── tasks/ # Celery 任务
│ │ └── utils/ # 工具函数
│ ├── alembic/ # 数据库迁移
│ └── tests/ # 测试代码
├── frontend/ # Vue 前端
│ └── src/
│ ├── api/ # API 调用
│ ├── components/ # 组件
│ ├── router/ # 路由
│ ├── stores/ # 状态管理
│ ├── views/ # 页面
│ └── utils/ # 工具函数
├── deploy/ # 部署配置
│ ├── docker-compose.yml
│ └── nginx.conf
└── docs/ # 文档
核心业务逻辑
SSH 状态检查流程
- 从数据库获取 OLT 设备配置
- 建立 SSH 连接(使用连接池)
- 执行命令:
display onu slot {slot_number} - 解析返回结果:
- 包含 "Up" → 在线
- 包含 "Offline" → 离线
- 更新设备状态到数据库
- 记录历史状态
权限控制逻辑
- 超级管理员:所有权限
- 管理员:管理所有设备和用户
- 区域管理员:管理指定区域的设备
- 学校管理员:管理指定学校的设备
- 普通用户:只读权限
数据导入流程
- 上传 Excel 文件
- 使用 Pandas 解析数据
- 数据验证(MAC 地址格式、必填字段)
- 批量插入数据库
- 返回导入结果(成功/失败记录)
开发指南
快速启动
后端:
cd backend
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
前端:
cd frontend
npm install
npm run dev
Celery Worker:
cd backend
celery -A app.core.celery_app worker --loglevel=info
Celery Beat:
cd backend
celery -A app.core.celery_app beat --loglevel=info
Docker 部署:
# 配置环境变量
cp backend/.env.example backend/.env
# 启动所有服务
docker-compose up -d
# 初始化数据库
docker-compose exec backend python scripts/init_db.py
数据库迁移
# 创建迁移
alembic revision --autogenerate -m "描述"
/home/v6ole/pyproject/H3ConuMS2/CLAUDE.md
# 执行迁移
alembic upgrade head
# 回滚
alembic downgrade -1
添加新功能
-
后端 API:
- 在
app/api/v1/创建路由文件 - 在
app/services/创建服务文件 - 在
app/schemas/定义请求/响应模式 - 在
app/models/定义数据模型(如需要)
- 在
-
前端页面:
- 在
views/创建页面组件 - 在
api/添加 API 调用 - 在
router/添加路由配置 - 在
stores/添加状态管理(如需要)
- 在
常见问题
SSH 连接失败
- 检查网络连通性
- 验证 SSH 凭证
- 检查防火墙设置
- 查看日志:
docker-compose logs backend
数据库连接失败
- 检查
DATABASE_URL配置 - 验证数据库服务状态
- 检查网络权限
Casdoor 登录失败
- 检查 Casdoor 服务状态
- 验证
CASDOOR_*配置 - 检查回调地址配置