后台管理跳过asin、后台相关数据做数据隔离

This commit is contained in:
super
2026-04-14 10:04:50 +08:00
parent 9ad6e037dc
commit ecc8b6ce6c
60 changed files with 1659 additions and 365 deletions

View File

@@ -32,7 +32,7 @@ def _ensure_dedupe_total_data_access():
return _ensure_admin_menu_access('dedupe-total-data')
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 None, None, (jsonify({'success': False, 'error': '无权访问数据去重总数据'}), 403)
return role, current_row, None
from ali_oss import upload_file as oss_upload_file
@@ -48,23 +48,23 @@ ADMIN_MENU_ACCESS_CONFIG = {
'dedupe-total-data': {
'column_key': 'admin_dedupe_total_data',
'route_path': 'dedupe-total-data',
'error': '鏃犳潈闄愯闂暟鎹幓閲嶆€绘暟鎹?',
'error': '无权访问数据去重汇总数据',
},
'shop-manage': {
'column_key': 'admin_shop_manage',
'route_path': 'shop-manage',
'error': '鏃犳潈闄愯闂簵閾虹鐞嗘ā鍧?',
'error': '无权访问店铺管理模块',
},
'skip-price-asin': {
'column_key': 'admin_skip_price_asin',
'route_path': 'skip-price-asin',
'error': '鏃犳潈闄愯闂烦杩囪窡浠稟SIN 妯″潡',
'error': '无权访问跳过跟价 ASIN 模块',
},
}
def _safe_version_key(version):
"""将版本号转为安全的 OSS 对象名部分"""
"""将版本号转为安全的 OSS 对象名片段"""
s = (version or '').strip()
s = re.sub(r'[^\w.\-]', '_', s)
return s or 'unknown'
@@ -138,7 +138,7 @@ def _ensure_admin_menu_access(*menu_names):
if role == 'super_admin':
return role, current_row, None
if role != 'admin' or not current_row:
return role, current_row, (jsonify({'success': False, 'error': '闇€瑕佺鐞嗗憳鏉冮檺'}), 403)
return role, current_row, (jsonify({'success': False, 'error': '需要管理员权限'}), 403)
key_set, route_set = _get_current_admin_permission_sets()
for menu_name in menu_names:
config = ADMIN_MENU_ACCESS_CONFIG.get(menu_name) or {}
@@ -148,7 +148,7 @@ def _ensure_admin_menu_access(*menu_names):
return role, current_row, None
fallback_menu = menu_names[0] if menu_names else ''
fallback_config = ADMIN_MENU_ACCESS_CONFIG.get(fallback_menu) or {}
error_message = fallback_config.get('error') or '鏃犳潈闄愯闂綋鍓嶆ā鍧?'
error_message = fallback_config.get('error') or '无权访问当前模块'
return role, current_row, (jsonify({'success': False, 'error': error_message}), 403)
@@ -157,7 +157,7 @@ def _ensure_admin_menu_access(*menu_names):
@admin_api.route('/users')
@admin_required
def list_users():
"""分页获取用户列表支持用户名模糊搜索、指定管理员所属普通用户筛选"""
"""分页获取用户列表支持用户名模糊搜索和按管理员归属筛选普通用户"""
role, current_row = get_current_admin_role()
if not role:
return jsonify({'success': False, 'error': '需要管理员权限'}), 403
@@ -998,7 +998,7 @@ def delete_dedupe_total_data(item_id):
@admin_api.route('/shop-manages')
@admin_required
def list_shop_manages():
_, _, denied = _ensure_admin_menu_access('shop-manage')
role, current_row, denied = _ensure_admin_menu_access('shop-manage')
if denied:
return denied
page = max(1, int(request.args.get('page', 1)))
@@ -1007,6 +1007,8 @@ def list_shop_manages():
shop_name = (request.args.get('shop_name') or '').strip()
params = {'page': page, 'pageSize': page_size}
if role != 'super_admin' and current_row and current_row.get('id'):
params['createdById'] = current_row.get('id')
if group_id_raw:
try:
group_id = int(group_id_raw)
@@ -1051,7 +1053,7 @@ def list_shop_manages():
@admin_api.route('/shop-manage', methods=['POST'])
@admin_required
def create_shop_manage():
_, _, denied = _ensure_admin_menu_access('shop-manage')
role, current_row, denied = _ensure_admin_menu_access('shop-manage')
if denied:
return denied
data = request.get_json() or {}
@@ -1061,10 +1063,15 @@ def create_shop_manage():
'mallName': (data.get('mall_name') or '').strip(),
'account': (data.get('account') or '').strip(),
'password': (data.get('password') or '').strip(),
'createdById': current_row.get('id') if current_row else None,
}
result, error_response, status = _proxy_backend_java(
'POST',
'/api/admin/shop-manages',
params={
'operatorId': current_row.get('id') if current_row else None,
'superAdmin': 'true' if role == 'super_admin' else 'false',
},
json_data=payload,
)
if error_response is not None:
@@ -1090,7 +1097,7 @@ def create_shop_manage():
@admin_api.route('/shop-manage/<int:item_id>', methods=['PUT'])
@admin_required
def update_shop_manage(item_id):
_, _, denied = _ensure_admin_menu_access('shop-manage')
role, current_row, denied = _ensure_admin_menu_access('shop-manage')
if denied:
return denied
data = request.get_json() or {}
@@ -1104,6 +1111,10 @@ def update_shop_manage(item_id):
result, error_response, status = _proxy_backend_java(
'PUT',
f'/api/admin/shop-manages/{item_id}',
params={
'operatorId': current_row.get('id') if current_row else None,
'superAdmin': 'true' if role == 'super_admin' else 'false',
},
json_data=payload,
)
if error_response is not None:
@@ -1128,12 +1139,16 @@ def update_shop_manage(item_id):
@admin_api.route('/shop-manage/<int:item_id>', methods=['DELETE'])
@admin_required
def delete_shop_manage(item_id):
_, _, denied = _ensure_admin_menu_access('shop-manage')
role, current_row, denied = _ensure_admin_menu_access('shop-manage')
if denied:
return denied
result, error_response, status = _proxy_backend_java(
'DELETE',
f'/api/admin/shop-manages/{item_id}',
params={
'operatorId': current_row.get('id') if current_row else None,
'superAdmin': 'true' if role == 'super_admin' else 'false',
},
)
if error_response is not None:
return error_response, status
@@ -1146,12 +1161,13 @@ def delete_shop_manage(item_id):
@admin_api.route('/shop-manage-groups')
@admin_required
def list_shop_manage_groups():
_, _, denied = _ensure_admin_menu_access('shop-manage', 'skip-price-asin')
role, current_row, denied = _ensure_admin_menu_access('shop-manage', 'skip-price-asin')
if denied:
return denied
result, error_response, status = _proxy_backend_java(
'GET',
'/api/admin/shop-manages/groups',
params={'createdById': current_row.get('id')} if role != 'super_admin' and current_row and current_row.get('id') else None,
)
if error_response is not None:
return error_response, status
@@ -1170,11 +1186,14 @@ def list_shop_manage_groups():
@admin_api.route('/shop-manage-group', methods=['POST'])
@admin_required
def create_shop_manage_group():
_, _, denied = _ensure_admin_menu_access('shop-manage', 'skip-price-asin')
_, current_row, denied = _ensure_admin_menu_access('shop-manage', 'skip-price-asin')
if denied:
return denied
data = request.get_json() or {}
payload = {'groupName': (data.get('group_name') or '').strip()}
payload = {
'groupName': (data.get('group_name') or '').strip(),
'createdById': current_row.get('id') if current_row else None,
}
result, error_response, status = _proxy_backend_java(
'POST',
'/api/admin/shop-manages/groups',
@@ -1198,7 +1217,7 @@ def create_shop_manage_group():
@admin_api.route('/shop-manage-group/<int:item_id>', methods=['PUT'])
@admin_required
def update_shop_manage_group(item_id):
_, _, denied = _ensure_admin_menu_access('shop-manage', 'skip-price-asin')
role, current_row, denied = _ensure_admin_menu_access('shop-manage', 'skip-price-asin')
if denied:
return denied
data = request.get_json() or {}
@@ -1206,6 +1225,10 @@ def update_shop_manage_group(item_id):
result, error_response, status = _proxy_backend_java(
'PUT',
f'/api/admin/shop-manages/groups/{item_id}',
params={
'operatorId': current_row.get('id') if current_row else None,
'superAdmin': 'true' if role == 'super_admin' else 'false',
},
json_data=payload,
)
if error_response is not None:
@@ -1302,7 +1325,7 @@ def create_skip_price_asin():
item = result.get('data') or {}
return jsonify({
'success': True,
'msg': result.get('message') or '淇濆瓨鎴愬姛',
'msg': result.get('message') or '保存成功',
'item': {
'id': item.get('id'),
'group_id': item.get('groupId'),
@@ -1331,19 +1354,58 @@ def delete_skip_price_asin_country(item_id, country):
)
if error_response is not None:
return error_response, status
return jsonify({'success': True, 'msg': result.get('message') or '鍒犻櫎鎴愬姛'})
return jsonify({'success': True, 'msg': result.get('message') or '删除成功'})
@admin_api.route('/shop-manage-group/<int:item_id>', methods=['DELETE'])
@admin_required
def delete_shop_manage_group(item_id):
_, _, denied = _ensure_admin_menu_access('shop-manage', 'skip-price-asin')
role, current_row, denied = _ensure_admin_menu_access('shop-manage', 'skip-price-asin')
if denied:
return denied
result, error_response, status = _proxy_backend_java(
'DELETE',
f'/api/admin/shop-manages/groups/{item_id}',
params={
'operatorId': current_row.get('id') if current_row else None,
'superAdmin': 'true' if role == 'super_admin' else 'false',
},
)
if error_response is not None:
return error_response, status
return jsonify({'success': True, 'msg': result.get('message') or '删除成功'})
@admin_api.route('/skip-price-asin/<int:item_id>/country/<country>', methods=['PUT'])
@admin_required
def update_skip_price_asin_country(item_id, country):
_, _, denied = _ensure_admin_menu_access('skip-price-asin')
if denied:
return denied
data = request.get_json() or {}
payload = {'asin': (data.get('asin') or '').strip()}
result, error_response, status = _proxy_backend_java(
'PUT',
f'/api/admin/skip-price-asins/{item_id}/countries/{country}',
json_data=payload,
)
if error_response is not None:
return error_response, status
item = result.get('data') or {}
return jsonify({
'success': True,
'msg': result.get('message') or '保存成功',
'item': {
'id': item.get('id'),
'group_id': item.get('groupId'),
'group_name': item.get('groupName') or '',
'shop_name': item.get('shopName') or '',
'asin_de': item.get('asinDe') or '',
'asin_uk': item.get('asinUk') or '',
'asin_fr': item.get('asinFr') or '',
'asin_it': item.get('asinIt') or '',
'asin_es': item.get('asinEs') or '',
'created_at': (item.get('createdAt') or '').replace('T', ' ')[:16],
'updated_at': (item.get('updatedAt') or '').replace('T', ' ')[:16],
},
})

View File

@@ -23,8 +23,8 @@ bucket_path = "nanri-image/"
file_url_pre = f"https://{bucket}.oss-cn-hangzhou.aliyuncs.com/"
import os
# backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://127.0.0.1:18080').rstrip('/')
backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://8.136.19.173:18080').rstrip('/')
backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://127.0.0.1:18080').rstrip('/')
# backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://8.136.19.173:18080').rstrip('/')
os.environ['OSS_ACCESS_KEY_ID'] = accessKeyId
os.environ['OSS_ACCESS_KEY_SECRET'] = accessKeySecret
os.environ['SECRET_KEY'] = "ddffc7c1d02121d9554d7b080b2511b6"

View File

@@ -1995,10 +1995,35 @@
if (!value) return '<span style="color:#999;">-</span>';
return '<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">' +
'<span>' + value + '</span>' +
'<button class="btn btn-sm" data-skip-price-asin-edit="' + item.id + '" data-country="' + country.code + '" data-asin="' + value.replace(/"/g, '&quot;') + '" data-shop-name="' + (item.shop_name || '').replace(/"/g, '&quot;') + '">编辑</button>' +
'<button class="btn btn-sm btn-danger" data-skip-price-asin-delete="' + item.id + '" data-country="' + country.code + '" data-shop-name="' + (item.shop_name || '').replace(/"/g, '&quot;') + '">删除</button>' +
'</div>';
}
function bindSkipPriceAsinActions() {
document.querySelectorAll('[data-skip-price-asin-edit]').forEach(function(btn) {
btn.onclick = function() {
var shopName = (btn.dataset.shopName || '').replace(/&quot;/g, '"');
var countryCode = btn.dataset.country || '';
var currentAsin = (btn.dataset.asin || '').replace(/&quot;/g, '"');
var nextAsin = prompt('请输入店铺“' + shopName + '”在 ' + countryCode + ' 的 ASIN', currentAsin);
if (nextAsin === null) return;
nextAsin = (nextAsin || '').trim();
if (!nextAsin) {
alert('ASIN 不能为空');
return;
}
fetch('/api/admin/skip-price-asin/' + btn.dataset.skipPriceAsinEdit + '/country/' + countryCode, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ asin: nextAsin })
})
.then(function(r) { return r.json(); })
.then(function(res) {
if (res.success) loadSkipPriceAsin(skipPriceAsinPage);
else alert(res.error || '保存失败');
});
};
});
document.querySelectorAll('[data-skip-price-asin-delete]').forEach(function(btn) {
btn.onclick = function() {
var shopName = (btn.dataset.shopName || '').replace(/&quot;/g, '"');