增加公共下载进度、增加接收SKU、密钥分别存放
This commit is contained in:
@@ -78,6 +78,11 @@ ADMIN_MENU_ACCESS_CONFIG = {
|
||||
'route_path': 'product-categories',
|
||||
'error': '无权访问商品类目模块',
|
||||
},
|
||||
'invalid-asin-data': {
|
||||
'column_key': 'admin_invalid_asin_data',
|
||||
'route_path': 'invalid-asin-data',
|
||||
'error': '无权访问不符合ASIN数据模块',
|
||||
},
|
||||
}
|
||||
|
||||
ADMIN_MENU_ACCESS_CONFIG.update({
|
||||
@@ -1760,6 +1765,115 @@ def delete_dedupe_total_data(item_id):
|
||||
})
|
||||
|
||||
|
||||
# ---------- 不符合 ASIN 数据 ----------
|
||||
|
||||
|
||||
def _format_invalid_asin_data_item(item):
|
||||
return {
|
||||
'id': item.get('id'),
|
||||
'data_value': item.get('dataValue') or '',
|
||||
'brand': item.get('brand') or '',
|
||||
'created_at': (item.get('createdAt') or '').replace('T', ' ')[:16],
|
||||
}
|
||||
|
||||
|
||||
@admin_api.route('/invalid-asin-data')
|
||||
@admin_required
|
||||
def list_invalid_asin_data():
|
||||
_, _, denied = _ensure_admin_menu_access('invalid-asin-data')
|
||||
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()
|
||||
data, error_response, status = _proxy_backend_java(
|
||||
'GET',
|
||||
'/api/admin/invalid-asin-data',
|
||||
params={'page': page, 'pageSize': page_size, 'keyword': keyword},
|
||||
)
|
||||
if error_response is not None:
|
||||
return error_response, status
|
||||
payload = data.get('data') or {}
|
||||
items = [_format_invalid_asin_data_item(item) for item in (payload.get('items') or [])]
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'items': items,
|
||||
'total': payload.get('total') or 0,
|
||||
'page': payload.get('page') or page,
|
||||
'page_size': payload.get('pageSize') or page_size,
|
||||
})
|
||||
|
||||
|
||||
@admin_api.route('/invalid-asin-data', methods=['POST'])
|
||||
@admin_required
|
||||
def create_invalid_asin_data():
|
||||
_, _, denied = _ensure_admin_menu_access('invalid-asin-data')
|
||||
if denied:
|
||||
return denied
|
||||
data = request.get_json() or {}
|
||||
payload = {
|
||||
'dataValue': (data.get('data_value') or '').strip(),
|
||||
'brand': (data.get('brand') or '').strip(),
|
||||
}
|
||||
result, error_response, status = _proxy_backend_java(
|
||||
'POST',
|
||||
'/api/admin/invalid-asin-data',
|
||||
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': _format_invalid_asin_data_item(item),
|
||||
})
|
||||
|
||||
|
||||
@admin_api.route('/invalid-asin-data/<int:item_id>', methods=['PUT'])
|
||||
@admin_required
|
||||
def update_invalid_asin_data(item_id):
|
||||
_, _, denied = _ensure_admin_menu_access('invalid-asin-data')
|
||||
if denied:
|
||||
return denied
|
||||
data = request.get_json() or {}
|
||||
payload = {
|
||||
'dataValue': (data.get('data_value') or '').strip(),
|
||||
'brand': (data.get('brand') or '').strip(),
|
||||
}
|
||||
result, error_response, status = _proxy_backend_java(
|
||||
'PUT',
|
||||
f'/api/admin/invalid-asin-data/{item_id}',
|
||||
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': _format_invalid_asin_data_item(item),
|
||||
})
|
||||
|
||||
|
||||
@admin_api.route('/invalid-asin-data/<int:item_id>', methods=['DELETE'])
|
||||
@admin_required
|
||||
def delete_invalid_asin_data(item_id):
|
||||
_, _, denied = _ensure_admin_menu_access('invalid-asin-data')
|
||||
if denied:
|
||||
return denied
|
||||
result, error_response, status = _proxy_backend_java(
|
||||
'DELETE',
|
||||
f'/api/admin/invalid-asin-data/{item_id}',
|
||||
)
|
||||
if error_response is not None:
|
||||
return error_response, status
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'msg': result.get('message') or '删除成功',
|
||||
})
|
||||
|
||||
|
||||
# ---------- 店铺管理 ----------
|
||||
|
||||
def _format_shop_manage_item(item):
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
'users': 'panel-users',
|
||||
'columns': 'panel-columns',
|
||||
'dedupe-total-data': 'panel-dedupe-total-data',
|
||||
'invalid-asin-data': 'panel-invalid-asin-data',
|
||||
'shop-keys': 'panel-shop-keys',
|
||||
'shop-manage': 'panel-shop-manage',
|
||||
'skip-price-asin': 'panel-skip-price-asin',
|
||||
@@ -113,6 +114,7 @@
|
||||
if (tabName === 'users') { loadUsers(1); loadColumnsForPermission(); }
|
||||
else if (tabName === 'columns') loadColumns();
|
||||
else if (tabName === 'dedupe-total-data') loadDedupeTotalData(1);
|
||||
else if (tabName === 'invalid-asin-data') loadInvalidAsinData(1);
|
||||
else if (tabName === 'shop-keys') loadShopKeys(1);
|
||||
else if (tabName === 'shop-manage') loadShopManage(1);
|
||||
else if (tabName === 'skip-price-asin') loadSkipPriceAsin(1);
|
||||
@@ -1165,6 +1167,135 @@
|
||||
document.getElementById('editDedupeTotalDataModal').classList.remove('show');
|
||||
};
|
||||
|
||||
// ========== 不符合ASIN数据 ==========
|
||||
var invalidAsinDataPage = 1, invalidAsinDataPageSize = 15;
|
||||
function buildInvalidAsinDataQuery(page) {
|
||||
var q = 'page=' + (page || 1) + '&page_size=' + invalidAsinDataPageSize;
|
||||
var keyword = (document.getElementById('searchInvalidAsinData').value || '').trim();
|
||||
if (keyword) q += '&keyword=' + encodeURIComponent(keyword);
|
||||
return q;
|
||||
}
|
||||
function loadInvalidAsinData(page) {
|
||||
invalidAsinDataPage = page || 1;
|
||||
fetch('/api/admin/invalid-asin-data?' + buildInvalidAsinDataQuery(invalidAsinDataPage))
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
var tbody = document.getElementById('invalidAsinDataListBody');
|
||||
if (!res.success) {
|
||||
tbody.innerHTML = '<tr><td colspan="5" class="empty-tip">加载失败: ' + (res.error || '') + '</td></tr>';
|
||||
return;
|
||||
}
|
||||
var items = res.items || [];
|
||||
if (items.length === 0) {
|
||||
tbody.innerHTML = '<tr><td colspan="5" class="empty-tip">暂无数据</td></tr>';
|
||||
} else {
|
||||
tbody.innerHTML = items.map(function (item) {
|
||||
var dataValueAttr = (item.data_value || '').replace(/"/g, '"');
|
||||
var brandAttr = (item.brand || '').replace(/"/g, '"');
|
||||
return '<tr><td>' + item.id + '</td><td>' + (item.data_value || '') + '</td><td>' + (item.brand || '') + '</td><td>' + (item.created_at || '') + '</td><td>' +
|
||||
'<button class="btn btn-sm" data-invalid-asin-edit="' + item.id + '" data-value="' + dataValueAttr + '" data-brand="' + brandAttr + '">编辑</button> ' +
|
||||
'<button class="btn btn-sm btn-danger" data-invalid-asin-delete="' + item.id + '" data-value="' + dataValueAttr + '">删除</button>' +
|
||||
'</td></tr>';
|
||||
}).join('');
|
||||
}
|
||||
renderPagination('invalidAsinDataPagination', res.total, res.page, res.page_size, loadInvalidAsinData);
|
||||
bindInvalidAsinDataActions();
|
||||
})
|
||||
.catch(function () {
|
||||
document.getElementById('invalidAsinDataListBody').innerHTML = '<tr><td colspan="5" class="empty-tip">请求失败</td></tr>';
|
||||
});
|
||||
}
|
||||
function bindInvalidAsinDataActions() {
|
||||
document.querySelectorAll('[data-invalid-asin-edit]').forEach(function (btn) {
|
||||
btn.onclick = function () {
|
||||
document.getElementById('editInvalidAsinDataId').value = btn.dataset.invalidAsinEdit || '';
|
||||
document.getElementById('editInvalidAsinDataValue').value = (btn.dataset.value || '').replace(/"/g, '"');
|
||||
document.getElementById('editInvalidAsinDataBrand').value = (btn.dataset.brand || '').replace(/"/g, '"');
|
||||
document.getElementById('msgEditInvalidAsinData').textContent = '';
|
||||
document.getElementById('msgEditInvalidAsinData').className = 'msg';
|
||||
document.getElementById('editInvalidAsinDataModal').classList.add('show');
|
||||
};
|
||||
});
|
||||
document.querySelectorAll('[data-invalid-asin-delete]').forEach(function (btn) {
|
||||
btn.onclick = function () {
|
||||
var value = (btn.dataset.value || '').replace(/"/g, '"');
|
||||
if (!confirm('确定删除“' + value + '”吗?')) return;
|
||||
fetch('/api/admin/invalid-asin-data/' + btn.dataset.invalidAsinDelete, { method: 'DELETE' })
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (res.success) { loadInvalidAsinData(invalidAsinDataPage); }
|
||||
else { alert(res.error || '删除失败'); }
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
document.getElementById('btnSearchInvalidAsinData').onclick = function () { loadInvalidAsinData(1); };
|
||||
document.getElementById('btnAddInvalidAsinData').onclick = function () {
|
||||
var dataValue = (document.getElementById('invalidAsinDataValue').value || '').trim();
|
||||
var brand = (document.getElementById('invalidAsinDataBrand').value || '').trim();
|
||||
var msgEl = document.getElementById('msgInvalidAsinData');
|
||||
msgEl.textContent = '';
|
||||
msgEl.className = 'msg';
|
||||
if (!dataValue) {
|
||||
msgEl.textContent = '请填写 ASIN';
|
||||
msgEl.classList.add('err');
|
||||
return;
|
||||
}
|
||||
fetch('/api/admin/invalid-asin-data', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ data_value: dataValue, brand: brand })
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (res.success) {
|
||||
msgEl.textContent = res.msg || '创建成功';
|
||||
msgEl.classList.add('ok');
|
||||
document.getElementById('invalidAsinDataValue').value = '';
|
||||
document.getElementById('invalidAsinDataBrand').value = '';
|
||||
loadInvalidAsinData(1);
|
||||
} else {
|
||||
msgEl.textContent = res.error || '创建失败';
|
||||
msgEl.classList.add('err');
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
msgEl.textContent = '请求失败';
|
||||
msgEl.classList.add('err');
|
||||
});
|
||||
};
|
||||
document.getElementById('btnSaveInvalidAsinData').onclick = function () {
|
||||
var itemId = document.getElementById('editInvalidAsinDataId').value;
|
||||
var dataValue = (document.getElementById('editInvalidAsinDataValue').value || '').trim();
|
||||
var brand = (document.getElementById('editInvalidAsinDataBrand').value || '').trim();
|
||||
var msgEl = document.getElementById('msgEditInvalidAsinData');
|
||||
msgEl.textContent = '';
|
||||
msgEl.className = 'msg';
|
||||
if (!dataValue) {
|
||||
msgEl.textContent = '请填写 ASIN';
|
||||
msgEl.classList.add('err');
|
||||
return;
|
||||
}
|
||||
fetch('/api/admin/invalid-asin-data/' + itemId, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ data_value: dataValue, brand: brand })
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (res.success) {
|
||||
document.getElementById('editInvalidAsinDataModal').classList.remove('show');
|
||||
loadInvalidAsinData(invalidAsinDataPage);
|
||||
} else {
|
||||
msgEl.textContent = res.error || '保存失败';
|
||||
msgEl.classList.add('err');
|
||||
}
|
||||
});
|
||||
};
|
||||
document.getElementById('btnCloseEditInvalidAsinData').onclick = function () {
|
||||
document.getElementById('editInvalidAsinDataModal').classList.remove('show');
|
||||
};
|
||||
|
||||
// ========== 店铺密钥管理 ==========
|
||||
var shopKeyPage = 1, shopKeyPageSize = 15;
|
||||
function buildShopKeyQuery(page) {
|
||||
|
||||
@@ -786,6 +786,7 @@
|
||||
<div class="tab active" data-tab="users">用户管理</div>
|
||||
<div class="tab" data-tab="columns">栏目权限配置</div>
|
||||
<div class="tab" data-tab="dedupe-total-data">数据去重总数据</div>
|
||||
<div class="tab" data-tab="invalid-asin-data">不符合ASIN数据</div>
|
||||
<div class="tab" data-tab="shop-keys">店铺密钥管理</div>
|
||||
<div class="tab" data-tab="shop-manage">店铺管理</div>
|
||||
<div class="tab" data-tab="skip-price-asin">跳过跟价 ASIN</div>
|
||||
@@ -1010,6 +1011,48 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 不符合ASIN数据 -->
|
||||
<div id="panel-invalid-asin-data" class="tab-panel">
|
||||
<div class="form-box">
|
||||
<h3 style="margin-bottom:16px;font-size:15px;">新增不符合ASIN数据</h3>
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="min-width:220px;">
|
||||
<label>ASIN</label>
|
||||
<input type="text" id="invalidAsinDataValue" placeholder="请输入 ASIN">
|
||||
</div>
|
||||
<div class="form-group" style="min-width:220px;">
|
||||
<label>品牌</label>
|
||||
<input type="text" id="invalidAsinDataBrand" placeholder="请输入品牌(可选)">
|
||||
</div>
|
||||
<button class="btn" id="btnAddInvalidAsinData">新增</button>
|
||||
</div>
|
||||
<p class="msg" id="msgInvalidAsinData"></p>
|
||||
</div>
|
||||
<div class="panel-box">
|
||||
<h3 style="margin-bottom:16px;font-size:15px;">不符合ASIN数据列表</h3>
|
||||
<div class="form-row" style="margin-bottom:16px;">
|
||||
<div class="form-group" style="min-width:220px;">
|
||||
<label>ASIN / 品牌(模糊搜索)</label>
|
||||
<input type="text" id="searchInvalidAsinData" placeholder="输入关键字">
|
||||
</div>
|
||||
<button class=" btn" id="btnSearchInvalidAsinData">查询</button>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>ASIN</th>
|
||||
<th>品牌</th>
|
||||
<th>创建时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="invalidAsinDataListBody"></tbody>
|
||||
</table>
|
||||
<div class="pagination" id="invalidAsinDataPagination"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 店铺密钥管理 -->
|
||||
<div id="panel-shop-keys" class="tab-panel">
|
||||
<div class="form-box">
|
||||
@@ -1494,6 +1537,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 编辑不符合ASIN数据弹窗 -->
|
||||
<div class="modal-mask" id="editInvalidAsinDataModal">
|
||||
<div class="modal">
|
||||
<h3>编辑不符合ASIN数据</h3>
|
||||
<input type="hidden" id="editInvalidAsinDataId">
|
||||
<div class="form-group">
|
||||
<label>ASIN</label>
|
||||
<input type="text" id="editInvalidAsinDataValue" placeholder="请输入 ASIN">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>品牌</label>
|
||||
<input type="text" id="editInvalidAsinDataBrand" placeholder="请输入品牌(可选)">
|
||||
</div>
|
||||
<p class=" msg" id="msgEditInvalidAsinData"></p>
|
||||
<div style="margin-top:16px;display:flex;gap:8px;">
|
||||
<button class="btn" id="btnSaveInvalidAsinData">保存</button>
|
||||
<button class="btn btn-secondary" id="btnCloseEditInvalidAsinData">取消</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 编辑栏目弹窗 -->
|
||||
<div class="modal-mask" id="editColumnModal">
|
||||
<div class="modal">
|
||||
|
||||
Reference in New Issue
Block a user