From 7ffe5279a3bcd6aac01e05444b64d3d465b3af84 Mon Sep 17 00:00:00 2001 From: super <2903208875@qq.com> Date: Sun, 22 Mar 2026 21:27:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=94=A8=E6=88=B7=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=E6=95=B0=E6=8D=AE=E6=80=BB=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__pycache__/admin_api.cpython-312.pyc | Bin 40572 -> 41980 bytes backend/blueprints/admin_api.py | 43 ++++++++++++++++++ backend/web_source/admin.html | 4 +- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/backend/blueprints/__pycache__/admin_api.cpython-312.pyc b/backend/blueprints/__pycache__/admin_api.cpython-312.pyc index 4957fddd472a057d67a93505b5b99403dce3894c..f0b8657c9cd3ac434f75657df307ae2960f87ed5 100644 GIT binary patch delta 9524 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 diff --git a/backend/blueprints/admin_api.py b/backend/blueprints/admin_api.py index 180ed78..bc7c75f 100644 --- a/backend/blueprints/admin_api.py +++ b/backend/blueprints/admin_api.py @@ -13,6 +13,24 @@ from werkzeug.security import generate_password_hash from utils.db import get_db from utils.auth import admin_required, get_current_admin_role + + +ALLOWED_DEDUPE_TOTAL_DATA_ADMIN_USERNAMES = {'刘丽泓'} + + +def _can_access_dedupe_total_data(role, current_row): + if role == 'super_admin': + return True + if role != 'admin' or not current_row: + return False + return (current_row.get('username') or '').strip() in ALLOWED_DEDUPE_TOTAL_DATA_ADMIN_USERNAMES + + +def _ensure_dedupe_total_data_access(): + role, current_row = get_current_admin_role() + if not _can_access_dedupe_total_data(role, current_row): + return None, None, (jsonify({'success': False, 'error': '无权限访问数据去重总数据'}), 403) + return role, current_row, None from ali_oss import upload_file as oss_upload_file try: @@ -138,6 +156,7 @@ def list_users(): 'page': page, 'page_size': page_size, 'current_user_role': role, + 'current_user_username': current_row.get('username') or '', 'admins': admins, }) except Exception as e: @@ -603,6 +622,9 @@ def upload_version(): @admin_api.route('/dedupe-total-data') @admin_required def list_dedupe_total_data(): + _, _, denied = _ensure_dedupe_total_data_access() + if denied: + return denied page = max(1, int(request.args.get('page', 1))) page_size = min(100, max(1, int(request.args.get('page_size', 15)))) keyword = (request.args.get('keyword') or '').strip() @@ -634,6 +656,9 @@ def list_dedupe_total_data(): @admin_api.route('/dedupe-total-data/import/') @admin_required def dedupe_total_data_import_progress(import_id): + _, _, denied = _ensure_dedupe_total_data_access() + if denied: + return denied result, error_response, status = _proxy_backend_java( 'GET', f'/api/admin/dedupe-total-data/import/{import_id}', @@ -658,6 +683,9 @@ def dedupe_total_data_import_progress(import_id): @admin_api.route('/dedupe-total-data/import', methods=['POST']) @admin_required def import_dedupe_total_data(): + _, _, denied = _ensure_dedupe_total_data_access() + if denied: + return denied file_storage = request.files.get('file') if not file_storage or file_storage.filename == '': return jsonify({'success': False, 'error': '请选择 Excel 文件'}) @@ -682,6 +710,9 @@ def import_dedupe_total_data(): @admin_api.route('/dedupe-total-data/delete-import/') @admin_required def dedupe_total_data_delete_import_progress(import_id): + _, _, denied = _ensure_dedupe_total_data_access() + if denied: + return denied result, error_response, status = _proxy_backend_java( 'GET', f'/api/admin/dedupe-total-data/delete-import/{import_id}', @@ -706,6 +737,9 @@ def dedupe_total_data_delete_import_progress(import_id): @admin_api.route('/dedupe-total-data/delete-import', methods=['POST']) @admin_required def delete_import_dedupe_total_data(): + _, _, denied = _ensure_dedupe_total_data_access() + if denied: + return denied file_storage = request.files.get('file') if not file_storage or file_storage.filename == '': return jsonify({'success': False, 'error': '请选择 Excel 文件'}) @@ -730,6 +764,9 @@ def delete_import_dedupe_total_data(): @admin_api.route('/dedupe-total-data', methods=['POST']) @admin_required def create_dedupe_total_data(): + _, _, denied = _ensure_dedupe_total_data_access() + if denied: + return denied data = request.get_json() or {} payload = {'dataValue': (data.get('data_value') or '').strip()} result, error_response, status = _proxy_backend_java( @@ -754,6 +791,9 @@ def create_dedupe_total_data(): @admin_api.route('/dedupe-total-data/', methods=['PUT']) @admin_required def update_dedupe_total_data(item_id): + _, _, denied = _ensure_dedupe_total_data_access() + if denied: + return denied data = request.get_json() or {} payload = {'dataValue': (data.get('data_value') or '').strip()} result, error_response, status = _proxy_backend_java( @@ -778,6 +818,9 @@ def update_dedupe_total_data(item_id): @admin_api.route('/dedupe-total-data/', methods=['DELETE']) @admin_required def delete_dedupe_total_data(item_id): + _, _, denied = _ensure_dedupe_total_data_access() + if denied: + return denied result, error_response, status = _proxy_backend_java( 'DELETE', f'/api/admin/dedupe-total-data/{item_id}', diff --git a/backend/web_source/admin.html b/backend/web_source/admin.html index 55177a3..4a27176 100644 --- a/backend/web_source/admin.html +++ b/backend/web_source/admin.html @@ -444,6 +444,7 @@ // ========== 用户管理 ========== var userPage = 1, userPageSize = 15; var currentUserRole = 'admin'; + var currentUserUsername = ''; var adminsList = []; function roleLabel(role) { if (role === 'super_admin') return '超级管理员'; @@ -469,6 +470,7 @@ return; } currentUserRole = res.current_user_role || 'admin'; + currentUserUsername = (res.current_user_username || '').trim(); adminsList = res.admins || []; var items = res.items || []; if (items.length === 0) { @@ -514,7 +516,7 @@ function updateDedupeTotalDataAccess() { var tab = document.querySelector('.tab[data-tab="dedupe-total-data"]'); var panel = document.getElementById('panel-dedupe-total-data'); - var canUse = currentUserRole === 'admin' || currentUserRole === 'super_admin'; + var canUse = currentUserRole === 'super_admin' || (currentUserRole === 'admin' && currentUserUsername === '刘丽泓'); if (tab) tab.style.display = canUse ? '' : 'none'; if (panel) panel.style.display = canUse ? '' : 'none'; if (!canUse && tab && tab.classList.contains('active')) {