feat: 增加 analyst 角色——仅测试数据查询/下载+修改密码
This commit is contained in:
@@ -42,6 +42,23 @@ def load_user(user_id):
|
||||
def init_auth(app):
|
||||
login_manager.init_app(app)
|
||||
|
||||
# analyst 角色:全局路由白名单拦截
|
||||
ANALYST_ALLOWED = {
|
||||
"auth.login", "auth.logout", "auth.change_password",
|
||||
"test_data.test_data_page",
|
||||
"test_data.api_test_data",
|
||||
"test_data.api_chart_data",
|
||||
"test_data.api_export",
|
||||
"test_data.api_delete", # 自身有 inline 角色检查
|
||||
}
|
||||
|
||||
@app.before_request
|
||||
def _restrict_analyst():
|
||||
if current_user.is_authenticated and current_user.role == "analyst":
|
||||
ep = request.endpoint or ""
|
||||
if ep not in ANALYST_ALLOWED and not ep.startswith("static"):
|
||||
return "权限不足:当前角色为 analyst,仅可访问测试数据", 403
|
||||
|
||||
|
||||
# ─── 装饰器 ────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
@@ -10,12 +10,14 @@ bp = Blueprint("test_data", __name__)
|
||||
|
||||
|
||||
@bp.route("/test-data")
|
||||
@login_required
|
||||
def test_data_page():
|
||||
"""测试信息页"""
|
||||
return render_template("test_data.html")
|
||||
|
||||
|
||||
@bp.route("/api/test-data")
|
||||
@login_required
|
||||
def api_test_data():
|
||||
"""分页查询测试数据"""
|
||||
page = request.args.get("page", 1, type=int)
|
||||
@@ -38,6 +40,7 @@ def api_test_data():
|
||||
|
||||
|
||||
@bp.route("/api/test-data/chart")
|
||||
@login_required
|
||||
def api_chart_data():
|
||||
"""返回图表所需全部数据(不分页)"""
|
||||
serial = request.args.get("serial", "", type=str)
|
||||
@@ -51,6 +54,7 @@ def api_chart_data():
|
||||
return jsonify({"records": records, "total": len(records)})
|
||||
|
||||
@bp.route("/api/test-data/export")
|
||||
@login_required
|
||||
def api_export():
|
||||
"""导出测试数据为 CSV"""
|
||||
serial = request.args.get("serial", "", type=str)
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
</head>
|
||||
<body>
|
||||
<nav class="top-menu">
|
||||
{% if current_user.is_authenticated and current_user.role != 'analyst' %}
|
||||
<a href="/" class="{% if request.path == '/' %}active{% endif %}">设备</a>
|
||||
{% endif %}
|
||||
<a href="/test-data" class="{% if request.path == '/test-data' %}active{% endif %}">测试信息</a>
|
||||
{% if current_user.is_authenticated and current_user.role in ('admin', 'manager') %}
|
||||
<a href="/device-logs" class="{% if request.path == '/device-logs' %}active{% endif %}">设备日志</a>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<label>角色:
|
||||
<select id="new-role" style="margin:0 8px;">
|
||||
<option value="operator">operator</option>
|
||||
<option value="analyst">analyst</option>
|
||||
<option value="manager">manager</option>
|
||||
<option value="admin">admin</option>
|
||||
</select>
|
||||
@@ -52,6 +53,7 @@ async function loadUsers() {
|
||||
<td>
|
||||
<select onchange="updateUser(${u.id}, this, 'role')" data-field="role">
|
||||
<option value="operator" ${u.role==='operator'?'selected':''}>operator</option>
|
||||
<option value="analyst" ${u.role==='analyst'?'selected':''}>analyst</option>
|
||||
<option value="manager" ${u.role==='manager'?'selected':''}>manager</option>
|
||||
<option value="admin" ${u.role==='admin'?'selected':''}>admin</option>
|
||||
</select>
|
||||
|
||||
Reference in New Issue
Block a user