修复商品风险多店铺问题
This commit is contained in:
@@ -1990,6 +1990,116 @@ def update_skip_price_asin_country(item_id, country):
|
||||
})
|
||||
|
||||
|
||||
@admin_api.route('/skip-price-asins/import/<import_id>')
|
||||
@login_required
|
||||
def skip_price_asin_import_progress(import_id):
|
||||
role, current_row, denied = _ensure_backend_menu_access('skip-price-asin')
|
||||
if denied:
|
||||
return denied
|
||||
result, error_response, status = _proxy_backend_java(
|
||||
'GET',
|
||||
f'/api/admin/skip-price-asins/import/{import_id}',
|
||||
)
|
||||
if error_response is not None:
|
||||
return error_response, status
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'progress': _format_query_asin_import_progress(result.get('data') or {}),
|
||||
})
|
||||
|
||||
|
||||
@admin_api.route('/skip-price-asins/import', methods=['POST'])
|
||||
@login_required
|
||||
def import_skip_price_asins():
|
||||
role, current_row, denied = _ensure_backend_menu_access('skip-price-asin')
|
||||
if denied:
|
||||
return denied
|
||||
file_storage = request.files.get('file')
|
||||
if not file_storage or file_storage.filename == '':
|
||||
return jsonify({'success': False, 'error': '请选择 Excel 文件'})
|
||||
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',
|
||||
}
|
||||
files = {
|
||||
'file': (file_storage.filename, file_storage.stream, file_storage.mimetype or 'application/octet-stream')
|
||||
}
|
||||
result, error_response, status = _proxy_backend_java(
|
||||
'POST',
|
||||
'/api/admin/skip-price-asins/import',
|
||||
params=params,
|
||||
files=files,
|
||||
timeout=60,
|
||||
)
|
||||
if error_response is not None:
|
||||
return error_response, status
|
||||
summary = result.get('data') or {}
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'msg': result.get('message') or '开始导入',
|
||||
'import_id': summary.get('importId') or '',
|
||||
})
|
||||
|
||||
|
||||
@admin_api.route('/skip-price-asins/delete-import/<import_id>')
|
||||
@login_required
|
||||
def skip_price_asin_delete_import_progress(import_id):
|
||||
role, current_row, denied = _ensure_backend_menu_access('skip-price-asin')
|
||||
if denied:
|
||||
return denied
|
||||
result, error_response, status = _proxy_backend_java(
|
||||
'GET',
|
||||
f'/api/admin/skip-price-asins/delete-import/{import_id}',
|
||||
)
|
||||
if error_response is not None:
|
||||
return error_response, status
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'progress': _format_query_asin_import_progress(result.get('data') or {}),
|
||||
})
|
||||
|
||||
|
||||
@admin_api.route('/skip-price-asins/delete-import', methods=['POST'])
|
||||
@login_required
|
||||
def delete_import_skip_price_asins():
|
||||
role, current_row, denied = _ensure_backend_menu_access('skip-price-asin')
|
||||
if denied:
|
||||
return denied
|
||||
file_storage = request.files.get('file')
|
||||
if not file_storage or file_storage.filename == '':
|
||||
return jsonify({'success': False, 'error': '请选择 Excel 文件'})
|
||||
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',
|
||||
}
|
||||
files = {
|
||||
'file': (file_storage.filename, file_storage.stream, file_storage.mimetype or 'application/octet-stream')
|
||||
}
|
||||
result, error_response, status = _proxy_backend_java(
|
||||
'POST',
|
||||
'/api/admin/skip-price-asins/delete-import',
|
||||
params=params,
|
||||
files=files,
|
||||
timeout=60,
|
||||
)
|
||||
if error_response is not None:
|
||||
return error_response, status
|
||||
summary = result.get('data') or {}
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'msg': result.get('message') or '开始删除',
|
||||
'import_id': summary.get('importId') or '',
|
||||
})
|
||||
|
||||
|
||||
def _format_query_asin_item(item):
|
||||
return {
|
||||
'id': item.get('id'),
|
||||
|
||||
@@ -26,6 +26,7 @@ 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://47.111.163.154:18080').rstrip('/')
|
||||
# backend_java_base_url = os.environ.get('BACKEND_JAVA_BASE_URL', 'http://121.196.149.225:18080').rstrip('/')
|
||||
os.environ['OSS_ACCESS_KEY_ID'] = accessKeyId
|
||||
os.environ['OSS_ACCESS_KEY_SECRET'] = accessKeySecret
|
||||
os.environ['SECRET_KEY'] = "ddffc7c1d02121d9554d7b080b2511b6"
|
||||
|
||||
@@ -227,6 +227,65 @@
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.request-loading-bar {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 3px;
|
||||
background: #667eea;
|
||||
opacity: 0;
|
||||
z-index: 3000;
|
||||
transition: width 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.request-loading-bar.show {
|
||||
width: 74%;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.request-loading-bar.finishing {
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.request-loading {
|
||||
position: fixed;
|
||||
right: 24px;
|
||||
top: 72px;
|
||||
display: none;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 14px;
|
||||
color: #333;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border: 1px solid #e6eaf2;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
||||
font-size: 13px;
|
||||
z-index: 3000;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.request-loading.show {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.request-spinner {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid #dce2ff;
|
||||
border-top-color: #667eea;
|
||||
border-radius: 50%;
|
||||
animation: request-spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes request-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
@@ -661,6 +720,11 @@
|
||||
|
||||
<body>
|
||||
<!-- <div class="nav"><a href="/home">返回首页</a></div> -->
|
||||
<div class="request-loading-bar" id="requestLoadingBar"></div>
|
||||
<div class="request-loading" id="requestLoading">
|
||||
<span class="request-spinner"></span>
|
||||
<span>请求处理中...</span>
|
||||
</div>
|
||||
<h1>管理后台</h1>
|
||||
|
||||
<div class="admin-user-box" style="position:absolute;top:24px;right:24px;z-index:10;">
|
||||
@@ -1042,6 +1106,42 @@
|
||||
<button class="btn" id="btnCreateSkipPriceAsin">新增 ASIN</button>
|
||||
</div>
|
||||
<p class="msg" id="msgSkipPriceAsin"></p>
|
||||
<div class="form-row" style="align-items:flex-start;gap:16px;margin-top:18px;border-top:1px solid #f0f0f0;padding-top:16px;">
|
||||
<div style="flex:1;min-width:320px;">
|
||||
<h3 style="margin-bottom:12px;font-size:14px;">导入文件新增</h3>
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="min-width:320px;">
|
||||
<label>上传 Excel(先选择分组;文件名必须是该分组下的店铺名;表头为 国家 / 删除ASIN / 最低价)</label>
|
||||
<input type="file" id="skipPriceAsinImportFile" accept=".xlsx,.xls">
|
||||
</div>
|
||||
<button class="btn" id="btnImportSkipPriceAsin" type="button">上传并新增</button>
|
||||
</div>
|
||||
<p class="msg" id="msgSkipPriceAsinImport"></p>
|
||||
<div class="progress-wrap" id="skipPriceAsinImportProgressWrap" style="display:none;">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" id="skipPriceAsinImportProgressFill"></div>
|
||||
</div>
|
||||
<div class="progress-text" id="skipPriceAsinImportProgressText"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex:1;min-width:320px;">
|
||||
<h3 style="margin-bottom:12px;font-size:14px;">导入文件删除</h3>
|
||||
<div class="form-row">
|
||||
<div class="form-group" style="min-width:320px;">
|
||||
<label>上传 Excel(先选择分组;文件名必须是该分组下的店铺名;按各国家删除ASIN列匹配删除)</label>
|
||||
<input type="file" id="skipPriceAsinDeleteImportFile" accept=".xlsx,.xls">
|
||||
</div>
|
||||
<button class="btn btn-danger" id="btnDeleteImportSkipPriceAsin" type="button">上传并删除</button>
|
||||
</div>
|
||||
<p class="msg" id="msgSkipPriceAsinDeleteImport"></p>
|
||||
<div class="progress-wrap" id="skipPriceAsinDeleteImportProgressWrap" style="display:none;">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" id="skipPriceAsinDeleteImportProgressFill"></div>
|
||||
</div>
|
||||
<div class="progress-text" id="skipPriceAsinDeleteImportProgressText"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-box">
|
||||
<h3 style="margin-bottom:16px;font-size:15px;">店铺列表</h3>
|
||||
@@ -1578,6 +1678,100 @@
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
// 全局请求动画:拦截本页所有 fetch 和 XMLHttpRequest 请求。
|
||||
(function installRequestLoadingInterceptor() {
|
||||
if (window.__adminRequestLoadingInstalled) return;
|
||||
window.__adminRequestLoadingInstalled = true;
|
||||
var activeRequests = 0;
|
||||
var showTimer = null;
|
||||
var hideTimer = null;
|
||||
var showDelayMs = 180;
|
||||
var loadingEl = document.getElementById('requestLoading');
|
||||
var loadingBarEl = document.getElementById('requestLoadingBar');
|
||||
|
||||
function showRequestLoading() {
|
||||
if (hideTimer) {
|
||||
clearTimeout(hideTimer);
|
||||
hideTimer = null;
|
||||
}
|
||||
if (!loadingEl || !loadingBarEl) return;
|
||||
loadingBarEl.classList.remove('finishing');
|
||||
loadingBarEl.classList.add('show');
|
||||
loadingEl.classList.add('show');
|
||||
}
|
||||
|
||||
function hideRequestLoading() {
|
||||
if (showTimer) {
|
||||
clearTimeout(showTimer);
|
||||
showTimer = null;
|
||||
}
|
||||
if (!loadingEl || !loadingBarEl) return;
|
||||
loadingBarEl.classList.remove('show');
|
||||
loadingBarEl.classList.add('finishing');
|
||||
loadingEl.classList.remove('show');
|
||||
hideTimer = setTimeout(function () {
|
||||
loadingBarEl.classList.remove('finishing');
|
||||
}, 220);
|
||||
}
|
||||
|
||||
function beginRequest() {
|
||||
activeRequests += 1;
|
||||
if (activeRequests === 1) {
|
||||
showTimer = setTimeout(showRequestLoading, showDelayMs);
|
||||
}
|
||||
}
|
||||
|
||||
function endRequest() {
|
||||
activeRequests = Math.max(0, activeRequests - 1);
|
||||
if (activeRequests === 0) {
|
||||
hideRequestLoading();
|
||||
}
|
||||
}
|
||||
|
||||
if (window.fetch) {
|
||||
var nativeFetch = window.fetch.bind(window);
|
||||
window.fetch = function (input, init) {
|
||||
var options = init || {};
|
||||
var skipLoading = !!options.__skipLoading;
|
||||
if (skipLoading) {
|
||||
options = Object.assign({}, options);
|
||||
delete options.__skipLoading;
|
||||
} else {
|
||||
beginRequest();
|
||||
}
|
||||
try {
|
||||
return nativeFetch(input, options).finally(function () {
|
||||
if (!skipLoading) endRequest();
|
||||
});
|
||||
} catch (err) {
|
||||
if (!skipLoading) endRequest();
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (window.XMLHttpRequest) {
|
||||
var nativeOpen = XMLHttpRequest.prototype.open;
|
||||
var nativeSend = XMLHttpRequest.prototype.send;
|
||||
XMLHttpRequest.prototype.open = function () {
|
||||
this.__adminSkipLoading = false;
|
||||
return nativeOpen.apply(this, arguments);
|
||||
};
|
||||
XMLHttpRequest.prototype.send = function () {
|
||||
if (!this.__adminSkipLoading) {
|
||||
beginRequest();
|
||||
this.addEventListener('loadend', endRequest, { once: true });
|
||||
}
|
||||
try {
|
||||
return nativeSend.apply(this, arguments);
|
||||
} catch (err) {
|
||||
if (!this.__adminSkipLoading) endRequest();
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
// Tab 切换
|
||||
var adminTabsEl = document.getElementById('adminTabs');
|
||||
if (adminTabsEl) adminTabsEl.innerHTML = '';
|
||||
@@ -3441,6 +3635,270 @@
|
||||
document.getElementById('skipPriceAsinListBody').innerHTML = '<tr><td colspan="8" class="empty-tip">请求失败</td></tr>';
|
||||
});
|
||||
}
|
||||
var skipPriceAsinImportPollTimer = null;
|
||||
var skipPriceAsinDeleteImportPollTimer = null;
|
||||
var skipPriceAsinImportPollSeq = 0;
|
||||
var skipPriceAsinDeleteImportPollSeq = 0;
|
||||
function stopSkipPriceAsinImportProgress() {
|
||||
skipPriceAsinImportPollSeq += 1;
|
||||
if (skipPriceAsinImportPollTimer) {
|
||||
clearTimeout(skipPriceAsinImportPollTimer);
|
||||
skipPriceAsinImportPollTimer = null;
|
||||
}
|
||||
}
|
||||
function stopSkipPriceAsinDeleteImportProgress() {
|
||||
skipPriceAsinDeleteImportPollSeq += 1;
|
||||
if (skipPriceAsinDeleteImportPollTimer) {
|
||||
clearTimeout(skipPriceAsinDeleteImportPollTimer);
|
||||
skipPriceAsinDeleteImportPollTimer = null;
|
||||
}
|
||||
}
|
||||
function setSkipPriceAsinImportProgress(percent, text) {
|
||||
var wrap = document.getElementById('skipPriceAsinImportProgressWrap');
|
||||
var fill = document.getElementById('skipPriceAsinImportProgressFill');
|
||||
var textEl = document.getElementById('skipPriceAsinImportProgressText');
|
||||
wrap.style.display = 'block';
|
||||
fill.style.width = Math.max(0, Math.min(100, percent || 0)) + '%';
|
||||
textEl.textContent = text || '';
|
||||
}
|
||||
function setSkipPriceAsinDeleteImportProgress(percent, text) {
|
||||
var wrap = document.getElementById('skipPriceAsinDeleteImportProgressWrap');
|
||||
var fill = document.getElementById('skipPriceAsinDeleteImportProgressFill');
|
||||
var textEl = document.getElementById('skipPriceAsinDeleteImportProgressText');
|
||||
wrap.style.display = 'block';
|
||||
fill.style.width = Math.max(0, Math.min(100, percent || 0)) + '%';
|
||||
textEl.textContent = text || '';
|
||||
}
|
||||
function pollSkipPriceAsinImport(importId) {
|
||||
stopSkipPriceAsinImportProgress();
|
||||
var pollSeq = ++skipPriceAsinImportPollSeq;
|
||||
var finished = false;
|
||||
var inFlight = false;
|
||||
var attempts = 0;
|
||||
var maxAttempts = 300;
|
||||
function isActive() {
|
||||
return !finished && pollSeq === skipPriceAsinImportPollSeq;
|
||||
}
|
||||
function finish() {
|
||||
finished = true;
|
||||
if (skipPriceAsinImportPollTimer) {
|
||||
clearTimeout(skipPriceAsinImportPollTimer);
|
||||
skipPriceAsinImportPollTimer = null;
|
||||
}
|
||||
}
|
||||
function schedule() {
|
||||
if (isActive()) {
|
||||
skipPriceAsinImportPollTimer = setTimeout(tick, 1500);
|
||||
}
|
||||
}
|
||||
function tick() {
|
||||
if (!isActive() || inFlight) {
|
||||
return;
|
||||
}
|
||||
attempts += 1;
|
||||
if (attempts > maxAttempts) {
|
||||
finish();
|
||||
document.getElementById('msgSkipPriceAsinImport').textContent = '查询导入进度超时,请稍后刷新列表确认结果';
|
||||
document.getElementById('msgSkipPriceAsinImport').className = 'msg err';
|
||||
return;
|
||||
}
|
||||
inFlight = true;
|
||||
fetch('/api/admin/skip-price-asins/import/' + encodeURIComponent(importId))
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (!isActive()) {
|
||||
return;
|
||||
}
|
||||
if (!res.success) {
|
||||
finish();
|
||||
document.getElementById('msgSkipPriceAsinImport').textContent = res.error || '查询导入进度失败';
|
||||
document.getElementById('msgSkipPriceAsinImport').className = 'msg err';
|
||||
return;
|
||||
}
|
||||
var progress = res.progress || {};
|
||||
var totalRows = progress.total_rows || 0;
|
||||
var processedRows = progress.processed_rows || 0;
|
||||
var percent = totalRows > 0 ? Math.round(processedRows * 100 / totalRows) : 0;
|
||||
setSkipPriceAsinImportProgress(percent, '处理中:已处理 ' + processedRows + ' / ' + totalRows + ',新增 ' + (progress.inserted_count || 0) + ',跳过 ' + (progress.skipped_count || 0));
|
||||
if (progress.status === 'success') {
|
||||
finish();
|
||||
document.getElementById('msgSkipPriceAsinImport').textContent = '导入成功:总行数 ' + totalRows + ',ASIN 数量 ' + (progress.asin_count || 0) + ',新增 ' + (progress.inserted_count || 0) + ',跳过 ' + (progress.skipped_count || 0);
|
||||
document.getElementById('msgSkipPriceAsinImport').className = 'msg ok';
|
||||
loadSkipPriceAsin(1);
|
||||
} else if (progress.status === 'failed') {
|
||||
finish();
|
||||
document.getElementById('msgSkipPriceAsinImport').textContent = progress.error_message || '导入失败';
|
||||
document.getElementById('msgSkipPriceAsinImport').className = 'msg err';
|
||||
} else {
|
||||
schedule();
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
if (!isActive()) {
|
||||
return;
|
||||
}
|
||||
finish();
|
||||
document.getElementById('msgSkipPriceAsinImport').textContent = '查询导入进度失败';
|
||||
document.getElementById('msgSkipPriceAsinImport').className = 'msg err';
|
||||
})
|
||||
.finally(function () {
|
||||
inFlight = false;
|
||||
});
|
||||
}
|
||||
tick();
|
||||
}
|
||||
function pollSkipPriceAsinDeleteImport(importId) {
|
||||
stopSkipPriceAsinDeleteImportProgress();
|
||||
var pollSeq = ++skipPriceAsinDeleteImportPollSeq;
|
||||
var finished = false;
|
||||
var inFlight = false;
|
||||
var attempts = 0;
|
||||
var maxAttempts = 300;
|
||||
function isActive() {
|
||||
return !finished && pollSeq === skipPriceAsinDeleteImportPollSeq;
|
||||
}
|
||||
function finish() {
|
||||
finished = true;
|
||||
if (skipPriceAsinDeleteImportPollTimer) {
|
||||
clearTimeout(skipPriceAsinDeleteImportPollTimer);
|
||||
skipPriceAsinDeleteImportPollTimer = null;
|
||||
}
|
||||
}
|
||||
function schedule() {
|
||||
if (isActive()) {
|
||||
skipPriceAsinDeleteImportPollTimer = setTimeout(tick, 1500);
|
||||
}
|
||||
}
|
||||
function tick() {
|
||||
if (!isActive() || inFlight) {
|
||||
return;
|
||||
}
|
||||
attempts += 1;
|
||||
if (attempts > maxAttempts) {
|
||||
finish();
|
||||
document.getElementById('msgSkipPriceAsinDeleteImport').textContent = '查询删除进度超时,请稍后刷新列表确认结果';
|
||||
document.getElementById('msgSkipPriceAsinDeleteImport').className = 'msg err';
|
||||
return;
|
||||
}
|
||||
inFlight = true;
|
||||
fetch('/api/admin/skip-price-asins/delete-import/' + encodeURIComponent(importId))
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (res) {
|
||||
if (!isActive()) {
|
||||
return;
|
||||
}
|
||||
if (!res.success) {
|
||||
finish();
|
||||
document.getElementById('msgSkipPriceAsinDeleteImport').textContent = res.error || '查询删除进度失败';
|
||||
document.getElementById('msgSkipPriceAsinDeleteImport').className = 'msg err';
|
||||
return;
|
||||
}
|
||||
var progress = res.progress || {};
|
||||
var totalRows = progress.total_rows || 0;
|
||||
var processedRows = progress.processed_rows || 0;
|
||||
var percent = totalRows > 0 ? Math.round(processedRows * 100 / totalRows) : 0;
|
||||
setSkipPriceAsinDeleteImportProgress(percent, '处理中:已处理 ' + processedRows + ' / ' + totalRows + ',删除 ' + (progress.deleted_count || 0) + ',跳过 ' + (progress.skipped_count || 0));
|
||||
if (progress.status === 'success') {
|
||||
finish();
|
||||
document.getElementById('msgSkipPriceAsinDeleteImport').textContent = '删除成功:总行数 ' + totalRows + ',ASIN 数量 ' + (progress.asin_count || 0) + ',删除 ' + (progress.deleted_count || 0) + ',跳过 ' + (progress.skipped_count || 0);
|
||||
document.getElementById('msgSkipPriceAsinDeleteImport').className = 'msg ok';
|
||||
loadSkipPriceAsin(1);
|
||||
} else if (progress.status === 'failed') {
|
||||
finish();
|
||||
document.getElementById('msgSkipPriceAsinDeleteImport').textContent = progress.error_message || '删除失败';
|
||||
document.getElementById('msgSkipPriceAsinDeleteImport').className = 'msg err';
|
||||
} else {
|
||||
schedule();
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
if (!isActive()) {
|
||||
return;
|
||||
}
|
||||
finish();
|
||||
document.getElementById('msgSkipPriceAsinDeleteImport').textContent = '查询删除进度失败';
|
||||
document.getElementById('msgSkipPriceAsinDeleteImport').className = 'msg err';
|
||||
})
|
||||
.finally(function () {
|
||||
inFlight = false;
|
||||
});
|
||||
}
|
||||
tick();
|
||||
}
|
||||
function uploadSkipPriceAsinImport(deleteMode) {
|
||||
var fileInput = document.getElementById(deleteMode ? 'skipPriceAsinDeleteImportFile' : 'skipPriceAsinImportFile');
|
||||
var msgEl = document.getElementById(deleteMode ? 'msgSkipPriceAsinDeleteImport' : 'msgSkipPriceAsinImport');
|
||||
msgEl.textContent = '';
|
||||
msgEl.className = 'msg';
|
||||
if (deleteMode) {
|
||||
stopSkipPriceAsinDeleteImportProgress();
|
||||
document.getElementById('skipPriceAsinDeleteImportProgressWrap').style.display = 'none';
|
||||
} else {
|
||||
stopSkipPriceAsinImportProgress();
|
||||
document.getElementById('skipPriceAsinImportProgressWrap').style.display = 'none';
|
||||
}
|
||||
var groupId = (document.getElementById('skipPriceAsinGroupSelect').value || '').trim();
|
||||
if (!groupId) {
|
||||
msgEl.textContent = '请先选择分组';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
if (!fileInput.files || fileInput.files.length === 0) {
|
||||
msgEl.textContent = '请选择 Excel 文件';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
var file = fileInput.files[0];
|
||||
var lowerName = (file.name || '').toLowerCase();
|
||||
if (!(lowerName.endsWith('.xlsx') || lowerName.endsWith('.xls'))) {
|
||||
msgEl.textContent = '仅支持 .xlsx 或 .xls 文件';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
if (deleteMode && !confirm('确定按 Excel 中的删除ASIN批量删除该店铺跳过跟价 ASIN 吗?')) {
|
||||
return;
|
||||
}
|
||||
var formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('group_id', groupId);
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', deleteMode ? '/api/admin/skip-price-asins/delete-import' : '/api/admin/skip-price-asins/import', true);
|
||||
xhr.upload.onprogress = function (event) {
|
||||
if (event.lengthComputable) {
|
||||
var percent = Math.round(event.loaded * 100 / event.total);
|
||||
if (deleteMode) setSkipPriceAsinDeleteImportProgress(percent, '上传中:' + percent + '%');
|
||||
else setSkipPriceAsinImportProgress(percent, '上传中:' + percent + '%');
|
||||
}
|
||||
};
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState !== 4) return;
|
||||
if (xhr.status < 200 || xhr.status >= 300) {
|
||||
msgEl.textContent = '请求失败';
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
var res;
|
||||
try { res = JSON.parse(xhr.responseText || '{}'); } catch (e) { res = { success: false, error: '返回格式错误' }; }
|
||||
if (!res.success) {
|
||||
msgEl.textContent = res.error || (deleteMode ? '删除失败' : '导入失败');
|
||||
msgEl.className = 'msg err';
|
||||
return;
|
||||
}
|
||||
if (deleteMode) {
|
||||
setSkipPriceAsinDeleteImportProgress(100, '上传完成,后端处理中...');
|
||||
pollSkipPriceAsinDeleteImport(res.import_id);
|
||||
} else {
|
||||
setSkipPriceAsinImportProgress(100, '上传完成,后端处理中...');
|
||||
pollSkipPriceAsinImport(res.import_id);
|
||||
}
|
||||
fileInput.value = '';
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
msgEl.textContent = '请求失败';
|
||||
msgEl.className = 'msg err';
|
||||
};
|
||||
xhr.send(formData);
|
||||
}
|
||||
document.getElementById('btnChooseSkipPriceAsinShop').onclick = openChooseSkipPriceAsinShopModal;
|
||||
document.getElementById('btnSearchChooseSkipPriceAsinShop').onclick = function () {
|
||||
loadChooseSkipPriceAsinShops(1);
|
||||
@@ -3590,6 +4048,12 @@
|
||||
};
|
||||
setupSkipPriceAsinShopPicker();
|
||||
initDropdownMultiSelect('skipPriceAsinCountries', '请选择国家');
|
||||
document.getElementById('btnImportSkipPriceAsin').onclick = function () {
|
||||
uploadSkipPriceAsinImport(false);
|
||||
};
|
||||
document.getElementById('btnDeleteImportSkipPriceAsin').onclick = function () {
|
||||
uploadSkipPriceAsinImport(true);
|
||||
};
|
||||
renderSkipPriceAsinInputs();
|
||||
|
||||
// ========== 查询 ASIN ==========
|
||||
|
||||
Reference in New Issue
Block a user