完成后台管理开发

This commit is contained in:
super
2026-03-22 13:33:37 +08:00
parent 5b636c3dfd
commit 64e32523cd
8 changed files with 303 additions and 35 deletions

View File

@@ -631,6 +631,30 @@ def list_dedupe_total_data():
})
@admin_api.route('/dedupe-total-data/import/<import_id>')
@admin_required
def dedupe_total_data_import_progress(import_id):
result, error_response, status = _proxy_backend_java(
'GET',
f'/api/admin/dedupe-total-data/import/{import_id}',
)
if error_response is not None:
return error_response, status
progress = result.get('data') or {}
return jsonify({
'success': True,
'progress': {
'status': progress.get('status') or 'pending',
'total_rows': progress.get('totalRows') or 0,
'processed_rows': progress.get('processedRows') or 0,
'asin_count': progress.get('asinCount') or 0,
'inserted_count': progress.get('insertedCount') or 0,
'skipped_count': progress.get('skippedCount') or 0,
'error_message': progress.get('errorMessage') or '',
},
})
@admin_api.route('/dedupe-total-data/import', methods=['POST'])
@admin_required
def import_dedupe_total_data():
@@ -650,13 +674,8 @@ def import_dedupe_total_data():
summary = result.get('data') or {}
return jsonify({
'success': True,
'msg': result.get('message') or '导入成功',
'summary': {
'total_rows': summary.get('totalRows') or 0,
'asin_count': summary.get('asinCount') or 0,
'inserted_count': summary.get('insertedCount') or 0,
'skipped_count': summary.get('skippedCount') or 0,
},
'msg': result.get('message') or '开始导入',
'import_id': summary.get('importId') or '',
})

View File

@@ -23,7 +23,7 @@ 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('/')
os.environ['OSS_ACCESS_KEY_ID'] = accessKeyId
os.environ['OSS_ACCESS_KEY_SECRET'] = accessKeySecret
os.environ['SECRET_KEY'] = "ddffc7c1d02121d9554d7b080b2511b6"

View File

@@ -61,6 +61,10 @@
.msg { margin-top: 12px; font-size: 14px; }
.msg.ok { color: #27ae60; }
.msg.err { color: #e74c3c; }
.progress-wrap { margin-top: 12px; }
.progress-bar { width: 100%; height: 10px; background: #edf0f5; border-radius: 999px; overflow: hidden; }
.progress-fill { width: 0; height: 100%; background: #667eea; transition: width 0.2s ease; }
.progress-text { margin-top: 8px; font-size: 13px; color: #666; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #eee; font-size: 14px; }
@@ -256,6 +260,10 @@
<button class="btn" id="btnAddDedupeTotalData">上传并导入</button>
</div>
<p class="msg" id="msgDedupeTotalData"></p>
<div class="progress-wrap" id="dedupeTotalDataProgressWrap" style="display:none;">
<div class="progress-bar"><div class="progress-fill" id="dedupeTotalDataProgressFill"></div></div>
<div class="progress-text" id="dedupeTotalDataProgressText"></div>
</div>
</div>
<div class="panel-box">
<h3 style="margin-bottom:16px;font-size:15px;">总数据列表</h3>
@@ -459,12 +467,28 @@
bindUserActions();
updateCreateFormByRole();
updateUserFilterByRole();
updateDedupeTotalDataAccess();
})
.catch(function() {
document.getElementById('userListBody').innerHTML = '<tr><td colspan="6" class="empty-tip">请求失败</td></tr>';
});
}
function updateUserFilterByRole() {
function updateDedupeTotalDataAccess() {
var tab = document.querySelector('.tab[data-tab="dedupe-total-data"]');
var panel = document.getElementById('panel-dedupe-total-data');
var canUse = currentUserRole === 'admin' || currentUserRole === 'super_admin';
if (tab) tab.style.display = canUse ? '' : 'none';
if (panel) panel.style.display = canUse ? '' : 'none';
if (!canUse && tab && tab.classList.contains('active')) {
tab.classList.remove('active');
if (panel) panel.classList.remove('active');
var usersTab = document.querySelector('.tab[data-tab="users"]');
var usersPanel = document.getElementById('panel-users');
if (usersTab) usersTab.classList.add('active');
if (usersPanel) usersPanel.classList.add('active');
}
}
var grp = document.getElementById('filterCreatedByGroup');
var sel = document.getElementById('filterCreatedBy');
if (currentUserRole === 'super_admin') {
@@ -843,11 +867,66 @@
});
}
document.getElementById('btnSearchDedupeTotalData').onclick = function() { loadDedupeTotalData(1); };
var dedupeImportPollTimer = null;
function stopDedupeImportProgress() {
if (dedupeImportPollTimer) {
clearInterval(dedupeImportPollTimer);
dedupeImportPollTimer = null;
}
}
function setDedupeImportProgress(percent, text) {
var wrap = document.getElementById('dedupeTotalDataProgressWrap');
var fill = document.getElementById('dedupeTotalDataProgressFill');
var textEl = document.getElementById('dedupeTotalDataProgressText');
wrap.style.display = 'block';
fill.style.width = Math.max(0, Math.min(100, percent || 0)) + '%';
textEl.textContent = text || '';
}
function pollDedupeImport(importId) {
stopDedupeImportProgress();
function tick() {
fetch('/api/admin/dedupe-total-data/import/' + encodeURIComponent(importId))
.then(function(r) { return r.json(); })
.then(function(res) {
if (!res.success) {
stopDedupeImportProgress();
document.getElementById('msgDedupeTotalData').textContent = res.error || '查询导入进度失败';
document.getElementById('msgDedupeTotalData').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;
setDedupeImportProgress(percent, '处理中:已处理 ' + processedRows + ' / ' + totalRows + ',新增 ' + (progress.inserted_count || 0) + ',跳过 ' + (progress.skipped_count || 0));
if (progress.status === 'success') {
stopDedupeImportProgress();
document.getElementById('msgDedupeTotalData').textContent = '导入成功:总行数 ' + (progress.total_rows || 0) + 'ASIN 数量 ' + (progress.asin_count || 0) + ',新增 ' + (progress.inserted_count || 0) + ',跳过 ' + (progress.skipped_count || 0);
document.getElementById('msgDedupeTotalData').className = 'msg ok';
loadDedupeTotalData(1);
} else if (progress.status === 'failed') {
stopDedupeImportProgress();
document.getElementById('msgDedupeTotalData').textContent = progress.error_message || '导入失败';
document.getElementById('msgDedupeTotalData').className = 'msg err';
}
})
.catch(function() {
stopDedupeImportProgress();
document.getElementById('msgDedupeTotalData').textContent = '查询导入进度失败';
document.getElementById('msgDedupeTotalData').className = 'msg err';
});
}
tick();
dedupeImportPollTimer = setInterval(tick, 1000);
}
document.getElementById('btnAddDedupeTotalData').onclick = function() {
var fileInput = document.getElementById('dedupeTotalDataFile');
var msgEl = document.getElementById('msgDedupeTotalData');
msgEl.textContent = '';
msgEl.className = 'msg';
stopDedupeImportProgress();
document.getElementById('dedupeTotalDataProgressWrap').style.display = 'none';
if (!fileInput.files || fileInput.files.length === 0) {
msgEl.textContent = '请选择 Excel 文件';
msgEl.classList.add('err');
@@ -862,27 +941,37 @@
}
var formData = new FormData();
formData.append('file', file);
fetch('/api/admin/dedupe-total-data/import', {
method: 'POST',
body: formData
})
.then(function(r) { return r.json(); })
.then(function(res) {
if (res.success) {
var summary = res.summary || {};
msgEl.textContent = '导入成功:总行数 ' + (summary.total_rows || 0) + 'ASIN 数量 ' + (summary.asin_count || 0) + ',新增 ' + (summary.inserted_count || 0) + ',跳过 ' + (summary.skipped_count || 0);
msgEl.classList.add('ok');
fileInput.value = '';
loadDedupeTotalData(1);
} else {
msgEl.textContent = res.error || '导入失败';
msgEl.classList.add('err');
var xhr = new XMLHttpRequest();
xhr.open('POST', '/api/admin/dedupe-total-data/import', true);
xhr.upload.onprogress = function(event) {
if (event.lengthComputable) {
var percent = Math.round(event.loaded * 100 / event.total);
setDedupeImportProgress(percent, '上传中:' + percent + '%');
}
})
.catch(function() {
};
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 || '导入失败';
msgEl.className = 'msg err';
return;
}
setDedupeImportProgress(100, '上传完成,后端处理中...');
pollDedupeImport(res.import_id);
fileInput.value = '';
};
xhr.onerror = function() {
msgEl.textContent = '请求失败';
msgEl.classList.add('err');
});
msgEl.className = 'msg err';
};
xhr.send(formData);
};
document.getElementById('btnSaveDedupeTotalData').onclick = function() {
var itemId = document.getElementById('editDedupeTotalDataId').value;