后台管理接口修复 后端BUG修复

This commit is contained in:
super
2026-05-12 21:03:42 +08:00
parent 5c990e651e
commit 0d78d63437
30 changed files with 3444 additions and 394 deletions

View File

@@ -8,7 +8,7 @@ import threading
import requests
from requests.adapters import HTTPAdapter
from flask import Blueprint, request, jsonify, session, current_app, g
from flask import Blueprint, request, jsonify, session, current_app, g, Response
import pymysql
from werkzeug.security import generate_password_hash
@@ -149,14 +149,24 @@ def _proxy_backend_java(method, path, *, params=None, json_data=None, files=None
def _format_permission_item(item):
created_at = item.get('createdAt')
if created_at in (None, ''):
created_at = item.get('created_at')
if hasattr(created_at, 'strftime'):
created_at_text = created_at.strftime('%Y-%m-%d %H:%M')
else:
created_at_text = (str(created_at).replace('T', ' ')[:16]) if created_at else ''
sort_order = item.get('sortOrder')
if sort_order is None:
sort_order = item.get('sort_order')
return {
'id': item.get('id'),
'name': item.get('name') or '',
'column_key': item.get('columnKey') or '',
'menu_type': item.get('menuType') or 'app',
'route_path': item.get('routePath') or '',
'sort_order': item.get('sortOrder') if item.get('sortOrder') is not None else 0,
'created_at': (item.get('createdAt') or '').replace('T', ' ')[:16],
'column_key': item.get('columnKey') or item.get('column_key') or '',
'menu_type': item.get('menuType') or item.get('menu_type') or 'app',
'route_path': item.get('routePath') or item.get('route_path') or '',
'sort_order': sort_order if sort_order is not None else 0,
'created_at': created_at_text,
}
@@ -792,11 +802,9 @@ def create_user():
(username, pwd_hash, is_admin, want_role, want_created_by),
)
new_uid = cur.lastrowid
_set_user_column_permissions(cur, new_uid, column_ids)
conn.commit()
conn.close()
error_response, status = _sync_user_column_permissions(new_uid, column_ids)
if error_response is not None:
return error_response, status
return jsonify({'success': True, 'msg': '用户创建成功'})
except pymysql.IntegrityError:
return jsonify({'success': False, 'error': '用户名已存在'})
@@ -807,7 +815,7 @@ def create_user():
@admin_api.route('/user/<int:uid>', methods=['PUT'])
@admin_required
def update_user(uid):
"""更新用户(密码、角色)"""
"""更新用户(密码、角色、栏目权限"""
data = request.get_json() or {}
_, _, denied = _ensure_admin_menu_access('users')
if denied:
@@ -817,7 +825,7 @@ def update_user(uid):
role, current_row = get_current_admin_role()
if not role:
return jsonify({'success': False, 'error': '需要管理员权限'}), 403
if want_role is None and not password:
if want_role is None and not password and 'column_ids' not in data:
return jsonify({'success': False, 'error': '请提供要修改的内容'})
try:
conn = get_db()
@@ -852,13 +860,10 @@ def update_user(uid):
"UPDATE users SET is_admin = %s, role = %s WHERE id = %s",
(is_admin, want_role, uid),
)
column_ids = data.get('column_ids')
if 'column_ids' in data:
_set_user_column_permissions(cur, uid, data.get('column_ids'))
conn.commit()
conn.close()
if column_ids is not None:
error_response, status = _sync_user_column_permissions(uid, column_ids)
if error_response is not None:
return error_response, status
return jsonify({'success': True, 'msg': '更新成功'})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
@@ -1139,15 +1144,7 @@ def get_user_columns(uid):
if denied:
return denied
menu_type = (request.args.get('menu_type') or '').strip()
result, error_response, status = _proxy_backend_java(
'GET',
f'/api/admin/permission-users/{uid}/columns',
params={'menuType': menu_type} if menu_type else None,
)
if error_response is not None:
return error_response, status
payload = result.get('data') or {}
return jsonify({'success': True, 'column_ids': payload.get('columnIds') or []})
return jsonify({'success': True, 'column_ids': _get_local_user_column_ids(uid, menu_type or None)})
@admin_api.route('/user/<int:uid>/column-permissions')
@@ -1157,14 +1154,8 @@ def get_user_column_permissions(uid):
if denied:
return denied
menu_type = (request.args.get('menu_type') or '').strip()
result, error_response, status = _proxy_backend_java(
'GET',
f'/api/admin/permission-users/{uid}/column-permissions',
params={'menuType': menu_type} if menu_type else None,
)
if error_response is not None:
return error_response, status
return jsonify({'success': True, 'items': [_format_permission_item(item) for item in (result.get('data') or [])]})
items = _get_local_user_column_permission_items(uid, menu_type or None)
return jsonify({'success': True, 'items': [_format_permission_item(item) for item in items]})
def _set_user_column_permissions(cur, user_id, column_ids):
@@ -2006,18 +1997,18 @@ def list_skip_price_asins():
group_id_raw = (request.args.get('group_id') or '').strip()
shop_name = (request.args.get('shop_name') or '').strip()
asin = (request.args.get('asin') or '').strip()
params = {'page': page, 'pageSize': page_size}
if current_row and current_row.get('id'):
params['operatorId'] = current_row.get('id')
params['superAdmin'] = 'true' if role == 'super_admin' else 'false'
params = {'page': page, 'page_size': page_size, 'pageSize': page_size}
params.update(_skip_price_asin_auth_params(role, current_row))
if group_id_raw:
try:
group_id = int(group_id_raw)
if group_id > 0:
params['group_id'] = group_id
params['groupId'] = group_id
except (TypeError, ValueError):
pass
if shop_name:
params['shop_name'] = shop_name
params['shopName'] = shop_name
if asin:
params['asin'] = asin
@@ -2059,6 +2050,64 @@ def list_skip_price_asins():
})
def _skip_price_asin_auth_params(role, current_row):
operator_id = current_row.get('id') if current_row else None
super_admin = 'true' if role == 'super_admin' else 'false'
return {
'operator_id': operator_id,
'operatorId': operator_id,
'super_admin': super_admin,
'superAdmin': super_admin,
}
@admin_api.route('/skip-price-asins/export')
@login_required
def export_skip_price_asins():
role, current_row, denied = _ensure_backend_menu_access('skip-price-asin')
if denied:
return denied
params = _skip_price_asin_auth_params(role, current_row)
group_id_raw = (request.args.get('group_id') or request.args.get('groupId') or '').strip()
shop_name = (request.args.get('shop_name') or request.args.get('shopName') or '').strip()
asin = (request.args.get('asin') or '').strip()
if group_id_raw:
params['group_id'] = group_id_raw
params['groupId'] = group_id_raw
if shop_name:
params['shop_name'] = shop_name
params['shopName'] = shop_name
if asin:
params['asin'] = asin
url = f"{backend_java_base_url}/api/admin/skip-price-asins/export"
try:
resp = _get_backend_java_session().get(url, params=params, timeout=60)
except requests.RequestException:
return jsonify({'success': False, 'error': 'backend-java 服务不可用'}), 502
if resp.status_code >= 400:
try:
data = resp.json()
error = data.get('message') or data.get('error') or '导出失败'
except ValueError:
error = '导出失败'
return jsonify({'success': False, 'error': error}), resp.status_code
headers = {}
disposition = resp.headers.get('Content-Disposition')
if disposition:
headers['Content-Disposition'] = disposition
return Response(
resp.content,
status=resp.status_code,
headers=headers,
content_type=resp.headers.get(
'Content-Type',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
),
)
@admin_api.route('/skip-price-asin', methods=['POST'])
@login_required
def create_skip_price_asin():
@@ -2092,10 +2141,7 @@ def create_skip_price_asin():
result, error_response, status = _proxy_backend_java(
'POST',
'/api/admin/skip-price-asins',
params={
'operatorId': current_row.get('id') if current_row else None,
'superAdmin': 'true' if role == 'super_admin' else 'false',
},
params=_skip_price_asin_auth_params(role, current_row),
json_data=payload,
)
if error_response is not None:
@@ -2134,10 +2180,7 @@ def delete_skip_price_asin_country(item_id, country):
result, error_response, status = _proxy_backend_java(
'DELETE',
f'/api/admin/skip-price-asins/{item_id}/countries/{country}',
params={
'operatorId': current_row.get('id') if current_row else None,
'superAdmin': 'true' if role == 'super_admin' else 'false',
},
params=_skip_price_asin_auth_params(role, current_row),
)
if error_response is not None:
return error_response, status
@@ -2177,10 +2220,7 @@ def update_skip_price_asin_country(item_id, country):
result, error_response, status = _proxy_backend_java(
'PUT',
f'/api/admin/skip-price-asins/{item_id}/countries/{country}',
params={
'operatorId': current_row.get('id') if current_row else None,
'superAdmin': 'true' if role == 'super_admin' else 'false',
},
params=_skip_price_asin_auth_params(role, current_row),
json_data=payload,
)
if error_response is not None:
@@ -2240,11 +2280,9 @@ def import_skip_price_asins():
group_id_raw = (request.form.get('group_id') or '').strip()
if not group_id_raw:
return jsonify({'success': False, 'error': '请先选择分组'})
params = {
'groupId': group_id_raw,
'operatorId': current_row.get('id') if current_row else None,
'superAdmin': 'true' if role == 'super_admin' else 'false',
}
params = _skip_price_asin_auth_params(role, current_row)
params['group_id'] = group_id_raw
params['groupId'] = group_id_raw
files = {
'file': (file_storage.filename, file_storage.stream, file_storage.mimetype or 'application/octet-stream')
}
@@ -2295,11 +2333,9 @@ def delete_import_skip_price_asins():
group_id_raw = (request.form.get('group_id') or '').strip()
if not group_id_raw:
return jsonify({'success': False, 'error': '请先选择分组'})
params = {
'groupId': group_id_raw,
'operatorId': current_row.get('id') if current_row else None,
'superAdmin': 'true' if role == 'super_admin' else 'false',
}
params = _skip_price_asin_auth_params(role, current_row)
params['group_id'] = group_id_raw
params['groupId'] = group_id_raw
files = {
'file': (file_storage.filename, file_storage.stream, file_storage.mimetype or 'application/octet-stream')
}
@@ -2584,3 +2620,46 @@ def update_query_asin_country(item_id, country):
'msg': result.get('message') or '保存成功',
'item': _format_query_asin_item(result.get('data') or {}),
})
def _get_local_user_column_ids(user_id, menu_type=None):
conn = get_db()
try:
with conn.cursor() as cur:
sql = """
SELECT c.id
FROM user_column_permission ucp
INNER JOIN columns c ON c.id = ucp.column_id
WHERE ucp.user_id = %s
"""
params = [user_id]
if menu_type:
sql += " AND c.menu_type = %s"
params.append(menu_type)
sql += " ORDER BY c.sort_order ASC, c.id ASC"
cur.execute(sql, params)
rows = cur.fetchall()
return [int(row['id']) for row in rows if row.get('id') is not None]
finally:
conn.close()
def _get_local_user_column_permission_items(user_id, menu_type=None):
conn = get_db()
try:
with conn.cursor() as cur:
sql = """
SELECT c.id, c.name, c.column_key, c.menu_type, c.route_path, c.sort_order, c.created_at
FROM user_column_permission ucp
INNER JOIN columns c ON c.id = ucp.column_id
WHERE ucp.user_id = %s
"""
params = [user_id]
if menu_type:
sql += " AND c.menu_type = %s"
params.append(menu_type)
sql += " ORDER BY c.sort_order ASC, c.id ASC"
cur.execute(sql, params)
return cur.fetchall()
finally:
conn.close()