feat: 用户登录/管理 + 操作日志模块

- tb_user 用户表、tb_log 日志表
- Flask-Login 认证(login/logout/权限装饰器)
- 用户管理页(admin 专有):增删改查、改密、角色设置
- 操作日志页:分页查询、按用户/类型筛选
- 测试操作区指令自动记录日志
- 所有页面加 @login_required 保护
- 默认管理员 admin/admin123(首次启动自动创建)
This commit is contained in:
wangfq
2026-05-28 13:58:19 +08:00
parent 56e3b03121
commit 322563dab0
19 changed files with 614 additions and 5 deletions

View File

@@ -1,7 +1,7 @@
"""测试操作 API"""
import time
from flask import Blueprint, jsonify, render_template, request
from flask_login import login_required, current_user
from app.models import (
get_device_by_id,
insert_serialnet,
@@ -9,12 +9,12 @@ from app.models import (
get_latest_test_state,
get_automation_averages,
clear_serialnet_records,
insert_log,
)
bp = Blueprint("test_op", __name__)
# DG430 指令 (addr=0x01, ADDR=0x81)
# XOR/SUM 预计算值
COMMANDS = {
"B0": "7F8101B03032", # 开始测试
"B1": "7F8101B13133", # 测试复原
@@ -23,8 +23,17 @@ COMMANDS = {
"BC": "7F8101BC3C3E", # 电机停止
}
CMD_NAMES = {
"B0": "开始测试",
"B1": "测试复原",
"BA": "电机前进",
"BB": "电机后退",
"BC": "电机停止",
}
@bp.route("/test/<int:dnt_id>")
@login_required
def test_page(dnt_id):
"""测试操作页面"""
device = get_device_by_id(dnt_id)
@@ -34,6 +43,7 @@ def test_page(dnt_id):
@bp.route("/api/command", methods=["POST"])
@login_required
def api_command():
"""发送单次指令"""
data = request.get_json()
@@ -43,21 +53,54 @@ def api_command():
if cmd not in COMMANDS:
return jsonify({"ok": False, "error": f"未知指令: {cmd}"}), 400
device = get_device_by_id(dnt_id)
target = f"{device['serial']}" if device else f"dnt_id={dnt_id}"
send_pkg = COMMANDS[cmd]
record_id = insert_serialnet(dnt_id, send_pkg)
return jsonify({"ok": True, "record_id": record_id, "send_pkg": send_pkg})
cmd_name = CMD_NAMES.get(cmd, cmd)
try:
record_id = insert_serialnet(dnt_id, send_pkg)
insert_log(
current_user.id, current_user.username, "command",
target=target,
detail=f"{cmd_name}({cmd}) → {send_pkg}",
result="ok",
ip=request.remote_addr or "",
)
return jsonify({"ok": True, "record_id": record_id, "send_pkg": send_pkg})
except Exception as e:
insert_log(
current_user.id, current_user.username, "command",
target=target,
detail=f"{cmd_name}({cmd}) 失败: {e}",
result="error",
ip=request.remote_addr or "",
)
return jsonify({"ok": False, "error": str(e)}), 500
@bp.route("/api/automation/start", methods=["POST"])
@login_required
def api_automation_start():
"""开始自动化测试"""
data = request.get_json()
dnt_id = data.get("dnt_id")
count = int(data.get("count", 1))
device = get_device_by_id(dnt_id)
target = f"{device['serial']}" if device else f"dnt_id={dnt_id}"
# 清除旧记录,然后插入第一条 0xB0
clear_serialnet_records(dnt_id)
record_id = insert_serialnet(dnt_id, COMMANDS["B0"])
insert_log(
current_user.id, current_user.username, "command",
target=target,
detail=f"自动化测试开始 ×{count}",
result="ok",
ip=request.remote_addr or "",
)
return jsonify({
"ok": True,
"total": count,
@@ -66,6 +109,7 @@ def api_automation_start():
@bp.route("/api/automation/<int:dnt_id>/progress")
@login_required
def api_automation_progress(dnt_id):
"""获取自动化进度"""
stats = get_serialnet_stats(dnt_id)