后台管理接口修复 后端BUG修复
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user