(function () { // Tab 鍒囨崲 var adminTabsEl = document.getElementById('adminTabs'); if (adminTabsEl) adminTabsEl.innerHTML = ''; var activeAdminTabName = ''; var ADMIN_PANEL_MAP = { 'users': 'panel-users', 'columns': 'panel-columns', 'dedupe-total-data': 'panel-dedupe-total-data', 'shop-keys': 'panel-shop-keys', 'shop-manage': 'panel-shop-manage', 'skip-price-asin': 'panel-skip-price-asin', 'history': 'panel-history', 'version': 'panel-version' }; function runTabLoader(tabName) { if (tabName === 'users') { loadUsers(1); loadColumnsForPermission(); } else if (tabName === 'columns') loadColumns(); else if (tabName === 'dedupe-total-data') loadDedupeTotalData(1); else if (tabName === 'shop-keys') loadShopKeys(1); else if (tabName === 'shop-manage') loadShopManage(1); else if (tabName === 'skip-price-asin') loadSkipPriceAsin(1); else if (tabName === 'history') loadHistory(1); else if (tabName === 'version') loadVersions(); } function hideAllAdminPanels() { document.querySelectorAll('.tab-panel').forEach(function (panel) { panel.classList.remove('active'); panel.style.display = 'none'; }); } function getActiveAdminTabName() { return activeAdminTabName; } function activateAdminTab(tabName) { var panelId = ADMIN_PANEL_MAP[tabName]; var panel = panelId ? document.getElementById(panelId) : null; if (!panel) return; activeAdminTabName = tabName; document.querySelectorAll('#adminTabs .tab').forEach(function (tab) { tab.classList.toggle('active', tab.dataset.tab === tabName); }); hideAllAdminPanels(); panel.style.display = ''; panel.classList.add('active'); runTabLoader(tabName); } function renderAdminTabs(items) { var knownItems = (items || []).filter(function (item) { return !!ADMIN_PANEL_MAP[item.route_path]; }); if (!knownItems.length) { activeAdminTabName = ''; if (adminTabsEl) adminTabsEl.innerHTML = '
鏆傛棤鍙敤鑿滃崟
'; hideAllAdminPanels(); return; } if (adminTabsEl) { adminTabsEl.innerHTML = knownItems.map(function (item) { return '
' + (item.name || item.route_path) + '
'; }).join(''); } document.querySelectorAll('#adminTabs .tab').forEach(function (tab) { tab.onclick = function () { activateAdminTab(tab.dataset.tab); }; }); var fallbackTab = activeAdminTabName && knownItems.some(function (item) { return item.route_path === activeAdminTabName; }) ? activeAdminTabName : knownItems[0].route_path; activateAdminTab(fallbackTab); } function loadAdminMenus(preferredTab) { if (preferredTab) activeAdminTabName = preferredTab; fetch('/api/admin/current-user/menus') .then(function (r) { return r.json(); }) .then(function (res) { if (!res.success) { if (adminTabsEl) adminTabsEl.innerHTML = '
鑿滃崟鍔犺浇澶辫触
'; hideAllAdminPanels(); return; } renderAdminTabs(res.items || []); }) .catch(function () { if (adminTabsEl) adminTabsEl.innerHTML = '
鑿滃崟鍔犺浇澶辫触
'; hideAllAdminPanels(); }); } hideAllAdminPanels(); // ========== 鐢ㄦ埛绠$悊 ========== var userPage = 1, userPageSize = 15; var currentUserId = null; var currentUserRole = 'admin'; var currentUserUsername = ''; var adminsList = []; function roleLabel(role) { if (role === 'super_admin') return '瓒呯骇绠$悊鍛?; if (role === 'admin') return '绠$悊鍛?; return '鏅€氳处鍙?; } function buildUserListQuery(page) { var q = 'page=' + (page || 1) + '&page_size=' + userPageSize; var kw = (document.getElementById('searchUsername').value || '').trim(); if (kw) q += '&username=' + encodeURIComponent(kw); var cby = document.getElementById('filterCreatedBy').value; if (cby) q += '&created_by_id=' + encodeURIComponent(cby); return q; } function loadUsers(page) { userPage = page || 1; fetch('/api/admin/users?' + buildUserListQuery(userPage)) .then(function (r) { return r.json(); }) .then(function (res) { var tbody = document.getElementById('userListBody'); if (!res.success) { tbody.innerHTML = '鍔犺浇澶辫触: ' + (res.error || '') + ''; return; } currentUserId = res.current_user_id || null; currentUserRole = res.current_user_role || 'admin'; currentUserUsername = (res.current_user_username || '').trim(); adminsList = res.admins || []; var items = res.items || []; if (items.length === 0) { tbody.innerHTML = '鏆傛棤鐢ㄦ埛'; } else { tbody.innerHTML = items.map(function (u) { return '' + u.id + '' + (u.username || '') + '' + roleLabel(u.role || 'normal') + '' + (u.creator_username || '-') + '' + (u.created_at || '') + '' + ' ' + '' + ''; }).join(''); } renderPagination('userPagination', res.total, res.page, res.page_size, loadUsers); bindUserActions(); updateCreateFormByRole(); updateUserFilterByRole(); }) .catch(function () { document.getElementById('userListBody').innerHTML = '璇锋眰澶辫触'; }); } function updateUserFilterByRole() { var grp = document.getElementById('filterCreatedByGroup'); var sel = document.getElementById('filterCreatedBy'); if (currentUserRole === 'super_admin') { grp.style.display = 'block'; var cur = sel.value; sel.innerHTML = ''; adminsList.forEach(function (a) { var opt = document.createElement('option'); opt.value = a.id; opt.textContent = a.username; sel.appendChild(opt); }); sel.value = cur || ''; } else { grp.style.display = 'none'; } } function updateDedupeTotalDataAccess() { var tab = document.querySelector('.tab[data-tab="dedupe-total-data"]'); var panel = document.getElementById('panel-dedupe-total-data'); var canUse = currentUserRole === 'super_admin' || (currentUserRole === 'admin' && currentUserUsername === ''); 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'); } } function updateShopManageAccess() { var tab = document.querySelector('.tab[data-tab="shop-manage"]'); var panel = document.getElementById('panel-shop-manage'); if (!tab || !panel) return; var canUse = currentUserRole === 'super_admin' || !!currentUserAdminPermissionKeys['admin_shop_manage'] || !!currentUserAdminPermissionRoutes['shop-manage']; tab.style.display = canUse ? '' : 'none'; panel.style.display = canUse ? '' : 'none'; if (!canUse && tab.classList.contains('active')) { tab.classList.remove('active'); 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'); } } function loadCurrentUserAdminPermissions() { currentUserAdminPermissionKeys = {}; currentUserAdminPermissionRoutes = {}; if (!currentUserId || currentUserRole === 'super_admin') { updateShopManageAccess(); return; } fetch('/api/admin/user/' + currentUserId + '/column-permissions?menu_type=admin') .then(function (r) { return r.json(); }) .then(function (res) { if (!res.success) { updateShopManageAccess(); return; } (res.items || []).forEach(function (item) { var columnKey = (item.column_key || '').trim(); var routePath = (item.route_path || '').trim(); if (columnKey) currentUserAdminPermissionKeys[columnKey] = true; if (routePath) currentUserAdminPermissionRoutes[routePath] = true; }); updateShopManageAccess(); }) .catch(function () { updateShopManageAccess(); }); } function applyTabAccess(tabName, canUse) { var tab = document.querySelector('.tab[data-tab="' + tabName + '"]'); var panel = document.getElementById('panel-' + tabName); 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'); } } function hasAdminTabAccess(tabName) { var config = ADMIN_TAB_ACCESS_CONFIG[tabName]; if (!config) return true; if (currentUserRole === 'super_admin') return true; if (config.superAdminOnly) return false; return !!currentUserAdminPermissionKeys[config.columnKey] || !!currentUserAdminPermissionRoutes[config.routePath]; } function refreshAdminTabAccess() { Object.keys(ADMIN_TAB_ACCESS_CONFIG).forEach(function (tabName) { applyTabAccess(tabName, hasAdminTabAccess(tabName)); }); } function loadCurrentUserAdminPermissions() { currentUserAdminPermissionKeys = {}; currentUserAdminPermissionRoutes = {}; if (!currentUserId || currentUserRole === 'super_admin') { refreshAdminTabAccess(); return; } fetch('/api/admin/user/' + currentUserId + '/column-permissions?menu_type=admin') .then(function (r) { return r.json(); }) .then(function (res) { if (!res.success) { refreshAdminTabAccess(); return; } (res.items || []).forEach(function (item) { var columnKey = (item.column_key || '').trim(); var routePath = (item.route_path || '').trim(); if (columnKey) currentUserAdminPermissionKeys[columnKey] = true; if (routePath) currentUserAdminPermissionRoutes[routePath] = true; }); refreshAdminTabAccess(); }) .catch(function () { refreshAdminTabAccess(); }); } var allColumnsList = []; function loadColumnsForPermission() { fetch('/api/admin/columns?menu_type=admin') .then(function (r) { return r.json(); }) .then(function (res) { if (!res.success) return; allColumnsList = res.items || []; renderColumnPermissionWrap('createColumnPermissionWrap'); renderColumnPermissionWrap('editColumnPermissionWrap'); var selCreate = document.getElementById('createColumnPermissionWrap'); var selEdit = document.getElementById('editColumnPermissionWrap'); if (selCreate && !selCreate._colCardsBound) { selCreate._colCardsBound = true; selCreate.onchange = function () { renderColumnCards('createColumnPermissionWrap'); }; } if (selEdit && !selEdit._colCardsBound) { selEdit._colCardsBound = true; selEdit.onchange = function () { renderColumnCards('editColumnPermissionWrap'); }; } }) .catch(function () { }); } var columnCardsContainerMap = { createColumnPermissionWrap: 'createColumnCards', editColumnPermissionWrap: 'editColumnCards' }; function renderColumnCards(selectId) { var sel = document.getElementById(selectId); var cardsId = columnCardsContainerMap[selectId]; var cardsEl = cardsId ? document.getElementById(cardsId) : null; if (!sel || sel.tagName !== 'SELECT' || !cardsEl) return; cardsEl.innerHTML = ''; for (var i = 0; i < sel.options.length; i++) { var opt = sel.options[i]; if (opt.disabled || !opt.selected) continue; var card = document.createElement('span'); card.className = 'column-permission-card'; card.textContent = opt.textContent; var btn = document.createElement('button'); btn.type = 'button'; btn.className = 'col-card-remove'; btn.setAttribute('aria-label', '绉婚櫎'); btn.textContent = '脳'; (function (option, seldId) { btn.onclick = function () { option.selected = false; renderColumnCards(seldId); }; })(opt, selectId); card.appendChild(btn); cardsEl.appendChild(card); } } function renderColumnPermissionWrap(wrapId) { var sel = document.getElementById(wrapId); if (!sel || sel.tagName !== 'SELECT') return; sel.innerHTML = ''; allColumnsList.forEach(function (c) { var opt = document.createElement('option'); opt.value = c.id; opt.textContent = c.name + ' (' + c.column_key + ')'; sel.appendChild(opt); }); if (allColumnsList.length === 0) { var opt = document.createElement('option'); opt.disabled = true; opt.textContent = '鏆傛棤鑿滃崟锛岃鍏堝湪鈥滄爮鐩潈闄愰厤缃€濅腑鏂板鑿滃崟'; sel.appendChild(opt); } renderColumnCards(wrapId); } function getSelectedColumnIds(wrapId) { var sel = document.getElementById(wrapId); if (!sel || sel.tagName !== 'SELECT') return []; var ids = []; for (var i = 0; i < sel.options.length; i++) { if (sel.options[i].selected) { var v = parseInt(sel.options[i].value, 10); if (!isNaN(v)) ids.push(v); } } return ids; } function setColumnPermissionCheckboxes(wrapId, columnIds) { var sel = document.getElementById(wrapId); if (!sel || sel.tagName !== 'SELECT') return; var set = {}; (columnIds || []).forEach(function (id) { set[id] = true; }); for (var i = 0; i < sel.options.length; i++) { var opt = sel.options[i]; if (opt.disabled) continue; opt.selected = set[parseInt(opt.value, 10)] || false; } renderColumnCards(wrapId); } function updateCreateFormByRole() { var roleSel = document.getElementById('createRole'); var optAdmin = document.getElementById('optAdmin'); var formCreatedBy = document.getElementById('formGroupCreatedBy'); var selCreatedBy = document.getElementById('createCreatedBy'); if (currentUserRole === 'super_admin') { if (optAdmin) optAdmin.style.display = ''; formCreatedBy.style.display = (roleSel.value === 'normal') ? 'block' : 'none'; selCreatedBy.innerHTML = ''; (res.items || []).forEach(function (u) { var opt = document.createElement('option'); opt.value = u.id; opt.textContent = u.username + ' (' + roleLabel(u.role || 'normal') + ')'; sel.appendChild(opt); }); sel.value = cur || ''; }); } var shopManageGroupUsers = []; function refreshShopManageGroupUserSelect(selectedUserId) { var sel = document.getElementById('shopManageGroupUserSelect'); if (!sel) return; var opts = ['']; shopManageGroupUsers.forEach(function (u) { opts.push(''); }); sel.innerHTML = opts.join(''); if (selectedUserId != null && selectedUserId !== '') { sel.value = String(selectedUserId); } syncShopManageGroupNameWithUser(); } function syncShopManageGroupNameWithUser() { var sel = document.getElementById('shopManageGroupUserSelect'); var input = document.getElementById('shopManageGroupInput'); if (!sel || !input) return; var selectedUser = null; shopManageGroupUsers.some(function (u) { if (String(u.id) === String(sel.value || '')) { selectedUser = u; return true; } return false; }); input.value = selectedUser ? (selectedUser.username || '') : ''; } function loadUserOptions() { return fetch('/api/admin/users?page=1&page_size=999') .then(function (r) { return r.json(); }) .then(function (res) { var items = res.items || []; shopManageGroupUsers = items.map(function (u) { return { id: u.id, username: u.username || '', role: u.role || 'normal' }; }); refreshShopManageGroupUserSelect(document.getElementById('shopManageGroupUserSelect') ? document.getElementById('shopManageGroupUserSelect').value : ''); var sel = document.getElementById('filterUser'); var cur = sel.value; sel.innerHTML = ''; items.forEach(function (u) { var opt = document.createElement('option'); opt.value = u.id; opt.textContent = u.username + ' (' + roleLabel(u.role || 'normal') + ')'; sel.appendChild(opt); }); sel.value = cur || ''; }); } document.getElementById('btnFilterHistory').onclick = function () { loadHistory(1); }; // ========== 鏁版嵁鍘婚噸鎬绘暟鎹?========== var dedupeTotalDataPage = 1, dedupeTotalDataPageSize = 15; function buildDedupeTotalDataQuery(page) { var q = 'page=' + (page || 1) + '&page_size=' + dedupeTotalDataPageSize; var keyword = (document.getElementById('searchDedupeTotalData').value || '').trim(); if (keyword) q += '&keyword=' + encodeURIComponent(keyword); return q; } function loadDedupeTotalData(page) { dedupeTotalDataPage = page || 1; fetch('/api/admin/dedupe-total-data?' + buildDedupeTotalDataQuery(dedupeTotalDataPage)) .then(function (r) { return r.json(); }) .then(function (res) { var tbody = document.getElementById('dedupeTotalDataListBody'); if (!res.success) { tbody.innerHTML = '鍔犺浇澶辫触: ' + (res.error || '') + ''; return; } var items = res.items || []; if (items.length === 0) { tbody.innerHTML = '鏆傛棤鎬绘暟鎹?/td>'; } else { tbody.innerHTML = items.map(function (item) { return '' + item.id + '' + (item.data_value || '') + '' + (item.created_at || '') + '' + ' ' + '' + ''; }).join(''); } renderPagination('dedupeTotalDataPagination', res.total, res.page, res.page_size, loadDedupeTotalData); bindDedupeTotalDataActions(); }) .catch(function () { document.getElementById('dedupeTotalDataListBody').innerHTML = '璇锋眰澶辫触'; }); } function bindDedupeTotalDataActions() { document.querySelectorAll('[data-dedupe-total-edit]').forEach(function (btn) { btn.onclick = function () { document.getElementById('editDedupeTotalDataId').value = btn.dataset.dedupeTotalEdit || ''; document.getElementById('editDedupeTotalDataValue').value = (btn.dataset.value || '').replace(/"/g, '"'); document.getElementById('msgEditDedupeTotalData').textContent = ''; document.getElementById('msgEditDedupeTotalData').className = 'msg'; document.getElementById('editDedupeTotalDataModal').classList.add('show'); }; }); document.querySelectorAll('[data-dedupe-total-delete]').forEach(function (btn) { btn.onclick = function () { var value = (btn.dataset.value || '').replace(/"/g, '"'); if (!confirm('纭畾鍒犻櫎鎬绘暟鎹€? + value + '鈥濆悧锛?)) return; fetch('/api/admin/dedupe-total-data/' + btn.dataset.dedupeTotalDelete, { method: 'DELETE' }) .then(function (r) { return r.json(); }) .then(function (res) { if (res.success) { loadDedupeTotalData(dedupeTotalDataPage); } else { alert(res.error || '鍒犻櫎澶辫触'); } }); }; }); } document.getElementById('btnSearchDedupeTotalData').onclick = function () { loadDedupeTotalData(1); }; var dedupeImportPollTimer = null; var dedupeDeleteImportPollTimer = null; function stopDedupeImportProgress() { if (dedupeImportPollTimer) { clearInterval(dedupeImportPollTimer); dedupeImportPollTimer = null; } } function stopDedupeDeleteImportProgress() { if (dedupeDeleteImportPollTimer) { clearInterval(dedupeDeleteImportPollTimer); dedupeDeleteImportPollTimer = 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 setDedupeDeleteImportProgress(percent, text) { var wrap = document.getElementById('dedupeTotalDataDeleteProgressWrap'); var fill = document.getElementById('dedupeTotalDataDeleteProgressFill'); var textEl = document.getElementById('dedupeTotalDataDeleteProgressText'); 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) + '锛孉SIN 鏁伴噺 ' + (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); } function pollDedupeDeleteImport(importId) { stopDedupeDeleteImportProgress(); function tick() { fetch('/api/admin/dedupe-total-data/delete-import/' + encodeURIComponent(importId)) .then(function (r) { return r.json(); }) .then(function (res) { if (!res.success) { stopDedupeDeleteImportProgress(); document.getElementById('msgDeleteDedupeTotalData').textContent = res.error || '鏌ヨ鍒犻櫎杩涘害澶辫触'; document.getElementById('msgDeleteDedupeTotalData').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; setDedupeDeleteImportProgress(percent, '澶勭悊涓細宸插鐞?' + processedRows + ' / ' + totalRows + '锛屽垹闄?' + (progress.deleted_count || 0) + '锛岃烦杩?' + (progress.skipped_count || 0)); if (progress.status === 'success') { stopDedupeDeleteImportProgress(); document.getElementById('msgDeleteDedupeTotalData').textContent = '鍒犻櫎鎴愬姛锛氭€昏鏁?' + (progress.total_rows || 0) + '锛孉SIN 鏁伴噺 ' + (progress.asin_count || 0) + '锛屽垹闄?' + (progress.deleted_count || 0) + '锛岃烦杩?' + (progress.skipped_count || 0); document.getElementById('msgDeleteDedupeTotalData').className = 'msg ok'; loadDedupeTotalData(1); } else if (progress.status === 'failed') { stopDedupeDeleteImportProgress(); document.getElementById('msgDeleteDedupeTotalData').textContent = progress.error_message || '鍒犻櫎澶辫触'; document.getElementById('msgDeleteDedupeTotalData').className = 'msg err'; } }) .catch(function () { stopDedupeDeleteImportProgress(); document.getElementById('msgDeleteDedupeTotalData').textContent = '鏌ヨ鍒犻櫎杩涘害澶辫触'; document.getElementById('msgDeleteDedupeTotalData').className = 'msg err'; }); } tick(); dedupeDeleteImportPollTimer = 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'); return; } var file = fileInput.files[0]; var lowerName = (file.name || '').toLowerCase(); if (!(lowerName.endsWith('.xlsx') || lowerName.endsWith('.xls'))) { msgEl.textContent = '浠呮敮鎸?.xlsx 鎴?.xls 鏂囦欢'; msgEl.classList.add('err'); return; } var formData = new FormData(); formData.append('file', file); 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 + '%'); } }; 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.className = 'msg err'; }; xhr.send(formData); }; document.getElementById('btnDeleteImportDedupeTotalData').onclick = function () { var fileInput = document.getElementById('dedupeTotalDataDeleteFile'); var msgEl = document.getElementById('msgDeleteDedupeTotalData'); msgEl.textContent = ''; msgEl.className = 'msg'; stopDedupeDeleteImportProgress(); document.getElementById('dedupeTotalDataDeleteProgressWrap').style.display = 'none'; if (!fileInput.files || fileInput.files.length === 0) { msgEl.textContent = '璇烽€夋嫨 Excel 鏂囦欢'; msgEl.classList.add('err'); return; } var file = fileInput.files[0]; var lowerName = (file.name || '').toLowerCase(); if (!(lowerName.endsWith('.xlsx') || lowerName.endsWith('.xls'))) { msgEl.textContent = '浠呮敮鎸?.xlsx 鎴?.xls 鏂囦欢'; msgEl.classList.add('err'); return; } if (!confirm('纭畾鎸?Excel 涓殑 ASIN 鎵归噺鍒犻櫎鍖归厤鐨勬€绘暟鎹悧锛?)) { return; } var formData = new FormData(); formData.append('file', file); var xhr = new XMLHttpRequest(); xhr.open('POST', '/api/admin/dedupe-total-data/delete-import', true); xhr.upload.onprogress = function (event) { if (event.lengthComputable) { var percent = Math.round(event.loaded * 100 / event.total); setDedupeDeleteImportProgress(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 || '鍒犻櫎澶辫触'; msgEl.className = 'msg err'; return; } setDedupeDeleteImportProgress(100, '涓婁紶瀹屾垚锛屽悗绔鐞嗕腑...'); pollDedupeDeleteImport(res.import_id); fileInput.value = ''; }; xhr.onerror = function () { msgEl.textContent = '璇锋眰澶辫触'; msgEl.className = 'msg err'; }; xhr.send(formData); }; document.getElementById('btnSaveDedupeTotalData').onclick = function () { var itemId = document.getElementById('editDedupeTotalDataId').value; var value = (document.getElementById('editDedupeTotalDataValue').value || '').trim(); var msgEl = document.getElementById('msgEditDedupeTotalData'); msgEl.textContent = ''; msgEl.className = 'msg'; if (!value) { msgEl.textContent = '璇峰~鍐欐€绘暟鎹€?; msgEl.classList.add('err'); return; } fetch('/api/admin/dedupe-total-data/' + itemId, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ data_value: value }) }) .then(function (r) { return r.json(); }) .then(function (res) { if (res.success) { document.getElementById('editDedupeTotalDataModal').classList.remove('show'); loadDedupeTotalData(dedupeTotalDataPage); } else { msgEl.textContent = res.error || '淇濆瓨澶辫触'; msgEl.classList.add('err'); } }); }; document.getElementById('btnCloseEditDedupeTotalData').onclick = function () { document.getElementById('editDedupeTotalDataModal').classList.remove('show'); }; // ========== 搴楅摵瀵嗛挜绠$悊 ========== var shopKeyPage = 1, shopKeyPageSize = 15; function buildShopKeyQuery(page) { return 'page=' + (page || 1) + '&page_size=' + shopKeyPageSize; } function loadShopKeys(page) { shopKeyPage = page || 1; fetch('/api/admin/shop-keys?' + buildShopKeyQuery(shopKeyPage)) .then(function (r) { return r.json(); }) .then(function (res) { var tbody = document.getElementById('shopKeyListBody'); if (!res.success) { tbody.innerHTML = '鍔犺浇澶辫触: ' + (res.error || '') + ''; return; } var items = res.items || []; if (items.length === 0) { tbody.innerHTML = '鏆傛棤搴楅摵瀵嗛挜'; } else { tbody.innerHTML = items.map(function (item, index) { var rowNo = (shopKeyPage - 1) * shopKeyPageSize + index + 1; return '' + rowNo + '' + (item.ziniao_account_name || '') + '' + (item.ziniao_token || '') + '' + (item.created_at || '') + '' + (item.updated_at || '') + '' + ' ' + '' + ''; }).join(''); } renderPagination('shopKeyPagination', res.total, res.page, res.page_size, loadShopKeys); bindShopKeyActions(); }) .catch(function () { document.getElementById('shopKeyListBody').innerHTML = '璇锋眰澶辫触'; }); } function bindShopKeyActions() { document.querySelectorAll('[data-shop-key-edit]').forEach(function (btn) { btn.onclick = function () { var item = {}; try { item = JSON.parse((btn.dataset.shopKey || '').replace(/"/g, '"')); } catch (e) { item = {}; } document.getElementById('editShopKeyId').value = item.id || ''; document.getElementById('editShopKeyZiniaoAccountName').value = item.ziniao_account_name || ''; document.getElementById('editShopKeyZiniaoToken').value = item.ziniao_token || ''; document.getElementById('msgEditShopKey').textContent = ''; document.getElementById('msgEditShopKey').className = 'msg'; document.getElementById('editShopKeyModal').classList.add('show'); }; }); document.querySelectorAll('[data-shop-key-delete]').forEach(function (btn) { btn.onclick = function () { var name = (btn.dataset.ziniaoAccountName || '').replace(/"/g, '"'); if (!confirm('纭畾鍒犻櫎搴楅摵瀵嗛挜鈥? + name + '鈥濆悧锛?)) return; fetch('/api/admin/shop-key/' + btn.dataset.shopKeyDelete, { method: 'DELETE' }) .then(function (r) { return r.json(); }) .then(function (res) { if (res.success) { loadShopKeys(shopKeyPage); } else { alert(res.error || '鍒犻櫎澶辫触'); } }); }; }); } document.getElementById('btnCreateShopKey').onclick = function () { var ziniaoAccountName = (document.getElementById('shopKeyZiniaoAccountName').value || '').trim(); var ziniaoToken = (document.getElementById('shopKeyZiniaoToken').value || '').trim(); var msgEl = document.getElementById('msgShopKey'); msgEl.textContent = ''; msgEl.className = 'msg'; if (!ziniaoAccountName || !ziniaoToken) { msgEl.textContent = '璇峰畬鏁村~鍐欑传楦熻处鍙峰悕绉般€佺传楦熶护鐗?; msgEl.classList.add('err'); return; } fetch('/api/admin/shop-key', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ziniao_account_name: ziniaoAccountName, ziniao_token: ziniaoToken }) }) .then(function (r) { return r.json(); }) .then(function (res) { if (res.success) { document.getElementById('shopKeyZiniaoAccountName').value = ''; document.getElementById('shopKeyZiniaoToken').value = ''; msgEl.textContent = res.msg || '鍒涘缓鎴愬姛'; msgEl.className = 'msg ok'; loadShopKeys(1); } else { msgEl.textContent = res.error || '鍒涘缓澶辫触'; msgEl.className = 'msg err'; } }) .catch(function () { msgEl.textContent = '璇锋眰澶辫触'; msgEl.className = 'msg err'; }); }; document.getElementById('btnSaveShopKey').onclick = function () { var itemId = document.getElementById('editShopKeyId').value; var ziniaoAccountName = (document.getElementById('editShopKeyZiniaoAccountName').value || '').trim(); var ziniaoToken = (document.getElementById('editShopKeyZiniaoToken').value || '').trim(); var msgEl = document.getElementById('msgEditShopKey'); msgEl.textContent = ''; msgEl.className = 'msg'; if (!ziniaoAccountName || !ziniaoToken) { msgEl.textContent = '璇峰畬鏁村~鍐欑传楦熻处鍙峰悕绉般€佺传楦熶护鐗?; msgEl.classList.add('err'); return; } fetch('/api/admin/shop-key/' + itemId, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ziniao_account_name: ziniaoAccountName, ziniao_token: ziniaoToken }) }) .then(function (r) { return r.json(); }) .then(function (res) { if (res.success) { document.getElementById('editShopKeyModal').classList.remove('show'); loadShopKeys(shopKeyPage); } else { msgEl.textContent = res.error || '淇濆瓨澶辫触'; msgEl.classList.add('err'); } }) .catch(function () { msgEl.textContent = '璇锋眰澶辫触'; msgEl.classList.add('err'); }); }; document.getElementById('btnCloseEditShopKey').onclick = function () { document.getElementById('editShopKeyModal').classList.remove('show'); }; // ========== 搴楅摵绠$悊 ========== var shopManagePage = 1, shopManagePageSize = 15; var shopManageGroups = []; function buildShopManageQuery(page) { var query = 'page=' + (page || 1) + '&page_size=' + shopManagePageSize; var groupId = (document.getElementById('shopManageFilterGroupId').value || '').trim(); var shopName = (document.getElementById('shopManageFilterShopName').value || '').trim(); if (groupId) query += '&group_id=' + encodeURIComponent(groupId); if (shopName) query += '&shop_name=' + encodeURIComponent(shopName); return query; } function refreshShopGroupSelects(selectedCreateId, selectedEditId) { var createSel = document.getElementById('shopManageGroupSelect'); var editSel = document.getElementById('editShopManageGroupSelect'); var filterSel = document.getElementById('shopManageFilterGroupId'); var skipCreateSel = document.getElementById('skipPriceAsinGroupSelect'); var skipFilterSel = document.getElementById('skipPriceAsinFilterGroupId'); var chooseSkipShopSel = document.getElementById('chooseSkipPriceAsinShopGroupId'); var selectedFilterId = filterSel ? filterSel.value : ''; var selectedSkipCreateId = skipCreateSel ? skipCreateSel.value : ''; var selectedSkipFilterId = skipFilterSel ? skipFilterSel.value : ''; var selectedChooseSkipShopId = chooseSkipShopSel ? chooseSkipShopSel.value : ''; var createOpts = ['']; var filterOpts = ['']; shopManageGroups.forEach(function (g) { var option = ''; createOpts.push(option); filterOpts.push(option); }); createSel.innerHTML = createOpts.join(''); editSel.innerHTML = createOpts.join(''); if (skipCreateSel) skipCreateSel.innerHTML = createOpts.join(''); if (filterSel) filterSel.innerHTML = filterOpts.join(''); if (skipFilterSel) skipFilterSel.innerHTML = filterOpts.join(''); if (chooseSkipShopSel) chooseSkipShopSel.innerHTML = filterOpts.join(''); if (selectedCreateId != null) createSel.value = String(selectedCreateId); if (selectedEditId != null) editSel.value = String(selectedEditId); if (filterSel && selectedFilterId) filterSel.value = selectedFilterId; if (skipCreateSel && selectedSkipCreateId) skipCreateSel.value = selectedSkipCreateId; if (skipFilterSel && selectedSkipFilterId) skipFilterSel.value = selectedSkipFilterId; if (chooseSkipShopSel && selectedChooseSkipShopId) chooseSkipShopSel.value = selectedChooseSkipShopId; } function loadShopManageGroups(selectedCreateId, selectedEditId) { return fetch('/api/admin/shop-manage-groups') .then(function (r) { return r.json(); }) .then(function (res) { if (!res.success) throw new Error(res.error || '鍔犺浇鍒嗙粍澶辫触'); shopManageGroups = res.items || []; refreshShopGroupSelects(selectedCreateId, selectedEditId); return shopManageGroups; }) .catch(function () { shopManageGroups = []; refreshShopGroupSelects(); return []; }); } function openShopManageGroupModal() { document.getElementById('shopManageGroupEditId').value = ''; document.getElementById('shopManageGroupInput').value = ''; document.getElementById('msgShopManageGroup').textContent = ''; document.getElementById('msgShopManageGroup').className = 'msg'; loadShopManageGroups().then(function () { renderShopManageGroupRows(); document.getElementById('shopManageGroupModal').classList.add('show'); }); } function renderShopManageGroupRows() { var tbody = document.getElementById('shopManageGroupListBody'); if (!shopManageGroups.length) { tbody.innerHTML = '鏆傛棤鍒嗙粍'; return; } tbody.innerHTML = shopManageGroups.map(function (item, index) { return '' + (index + 1) + '' + (item.group_name || '') + '' + (item.created_at || '') + '' + (item.updated_at || '') + '' + ' ' + '' + ''; }).join(''); document.querySelectorAll('[data-shop-group-edit]').forEach(function (btn) { btn.onclick = function () { document.getElementById('shopManageGroupEditId').value = btn.dataset.shopGroupEdit; document.getElementById('shopManageGroupInput').value = (btn.dataset.shopGroupName || '').replace(/"/g, '"'); }; }); document.querySelectorAll('[data-shop-group-delete]').forEach(function (btn) { btn.onclick = function () { var gid = btn.dataset.shopGroupDelete; var gname = (btn.dataset.shopGroupName || '').replace(/"/g, '"'); if (!confirm('纭畾鍒犻櫎鍒嗙粍鈥? + gname + '鈥濆悧锛?)) return; fetch('/api/admin/shop-manage-group/' + gid, { method: 'DELETE' }) .then(function (r) { return r.json(); }) .then(function (res) { if (!res.success) { alert(res.error || '鍒犻櫎澶辫触'); return; } loadShopManageGroups().then(function () { renderShopManageGroupRows(); loadShopManage(shopManagePage); loadSkipPriceAsin(skipPriceAsinPage); }); }); }; }); } function loadShopManage(page) { shopManagePage = page || 1; fetch('/api/admin/shop-manages?' + buildShopManageQuery(shopManagePage)) .then(function (r) { return r.json(); }) .then(function (res) { var tbody = document.getElementById('shopManageListBody'); if (!res.success) { tbody.innerHTML = '鍔犺浇澶辫触: ' + (res.error || '') + ''; return; } var items = res.items || []; if (items.length === 0) { tbody.innerHTML = '鏆傛棤搴楅摵'; } else { tbody.innerHTML = items.map(function (item, index) { var rowNo = (shopManagePage - 1) * shopManagePageSize + index + 1; return '' + rowNo + '' + (item.group_name || '') + '' + (item.shop_name || '') + '' + (item.mall_name || '') + '' + (item.account || '') + '' + (item.password || '') + '' + (item.created_at || '') + '' + (item.updated_at || '') + '' + ' ' + '' + ''; }).join(''); } renderPagination('shopManagePagination', res.total, res.page, res.page_size, loadShopManage); bindShopManageActions(); }) .catch(function () { document.getElementById('shopManageListBody').innerHTML = '璇锋眰澶辫触'; }); } function bindShopManageActions() { document.querySelectorAll('[data-shop-manage-edit]').forEach(function (btn) { btn.onclick = function () { var item = {}; try { item = JSON.parse((btn.dataset.shopManage || '').replace(/"/g, '"')); } catch (e) { item = {}; } document.getElementById('editShopManageId').value = item.id || ''; document.getElementById('editShopManageShopName').value = item.shop_name || ''; document.getElementById('editShopManageMallName').value = item.mall_name || ''; document.getElementById('editShopManageAccount').value = item.account || ''; document.getElementById('editShopManagePassword').value = item.password || ''; document.getElementById('msgEditShopManage').textContent = ''; document.getElementById('msgEditShopManage').className = 'msg'; loadShopManageGroups(null, item.group_id).then(function () { document.getElementById('editShopManageModal').classList.add('show'); }); }; }); document.querySelectorAll('[data-shop-manage-delete]').forEach(function (btn) { btn.onclick = function () { var name = (btn.dataset.shopManageName || '').replace(/"/g, '"'); if (!confirm('纭畾鍒犻櫎搴楅摵鈥? + name + '鈥濆悧锛?)) return; fetch('/api/admin/shop-manage/' + btn.dataset.shopManageDelete, { method: 'DELETE' }) .then(function (r) { return r.json(); }) .then(function (res) { if (res.success) { loadShopManage(shopManagePage); } else { alert(res.error || '鍒犻櫎澶辫触'); } }); }; }); } document.getElementById('btnManageShopGroups').onclick = openShopManageGroupModal; document.getElementById('btnManageShopGroupsFromEdit').onclick = openShopManageGroupModal; document.getElementById('btnSearchShopManage').onclick = function () { loadShopManage(1); }; document.getElementById('shopManageFilterShopName').addEventListener('keydown', function (e) { if (e.key === 'Enter') { e.preventDefault(); loadShopManage(1); } }); document.getElementById('btnCloseShopManageGroupModal').onclick = function () { document.getElementById('shopManageGroupModal').classList.remove('show'); }; document.getElementById('btnCancelShopManageGroupEdit').onclick = function () { document.getElementById('shopManageGroupEditId').value = ''; document.getElementById('shopManageGroupInput').value = ''; }; document.getElementById('btnSaveShopManageGroup').onclick = function () { var editId = (document.getElementById('shopManageGroupEditId').value || '').trim(); var groupName = (document.getElementById('shopManageGroupInput').value || '').trim(); var msgEl = document.getElementById('msgShopManageGroup'); msgEl.textContent = ''; msgEl.className = 'msg'; if (!groupName) { msgEl.textContent = '璇疯緭鍏ュ垎缁勫悕绉?; msgEl.className = 'msg err'; return; } var method = editId ? 'PUT' : 'POST'; var url = editId ? ('/api/admin/shop-manage-group/' + editId) : '/api/admin/shop-manage-group'; fetch(url, { method: method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ group_name: groupName }) }) .then(function (r) { return r.json(); }) .then(function (res) { if (!res.success) { msgEl.textContent = res.error || '淇濆瓨澶辫触'; msgEl.className = 'msg err'; return; } document.getElementById('shopManageGroupEditId').value = ''; document.getElementById('shopManageGroupInput').value = ''; msgEl.textContent = res.msg || '淇濆瓨鎴愬姛'; msgEl.className = 'msg ok'; loadShopManageGroups().then(function () { renderShopManageGroupRows(); loadShopManage(shopManagePage); loadSkipPriceAsin(skipPriceAsinPage); }); }) .catch(function () { msgEl.textContent = '璇锋眰澶辫触'; msgEl.className = 'msg err'; }); }; function refreshShopGroupSelects(selectedCreateId, selectedEditId) { var createSel = document.getElementById('shopManageGroupSelect'); var editSel = document.getElementById('editShopManageGroupSelect'); var filterSel = document.getElementById('shopManageFilterGroupId'); var skipCreateSel = document.getElementById('skipPriceAsinGroupSelect'); var skipFilterSel = document.getElementById('skipPriceAsinFilterGroupId'); var chooseSkipShopSel = document.getElementById('chooseSkipPriceAsinShopGroupId'); var selectedFilterId = filterSel ? filterSel.value : ''; var selectedSkipCreateId = skipCreateSel ? skipCreateSel.value : ''; var selectedSkipFilterId = skipFilterSel ? skipFilterSel.value : ''; var selectedChooseSkipShopId = chooseSkipShopSel ? chooseSkipShopSel.value : ''; var createOpts = ['']; var filterOpts = ['']; shopManageGroups.forEach(function (g) { var option = ''; createOpts.push(option); filterOpts.push(option); }); createSel.innerHTML = createOpts.join(''); editSel.innerHTML = createOpts.join(''); if (skipCreateSel) skipCreateSel.innerHTML = createOpts.join(''); if (filterSel) filterSel.innerHTML = filterOpts.join(''); if (skipFilterSel) skipFilterSel.innerHTML = filterOpts.join(''); if (chooseSkipShopSel) chooseSkipShopSel.innerHTML = filterOpts.join(''); if (selectedCreateId != null) createSel.value = String(selectedCreateId); if (selectedEditId != null) editSel.value = String(selectedEditId); if (filterSel && selectedFilterId) filterSel.value = selectedFilterId; if (skipCreateSel && selectedSkipCreateId) skipCreateSel.value = selectedSkipCreateId; if (skipFilterSel && selectedSkipFilterId) skipFilterSel.value = selectedSkipFilterId; if (chooseSkipShopSel && selectedChooseSkipShopId) chooseSkipShopSel.value = selectedChooseSkipShopId; } function loadShopManageGroups(selectedCreateId, selectedEditId) { return fetch('/api/admin/shop-manage-groups') .then(function (r) { return r.json(); }) .then(function (res) { if (!res.success) throw new Error(res.error || '鍔犺浇鍒嗙粍澶辫触'); shopManageGroups = res.items || []; refreshShopGroupSelects(selectedCreateId, selectedEditId); return shopManageGroups; }) .catch(function () { shopManageGroups = []; refreshShopGroupSelects(); return []; }); } function resetShopManageGroupForm() { document.getElementById('shopManageGroupEditId').value = ''; document.getElementById('shopManageGroupInput').value = ''; document.getElementById('msgShopManageGroup').textContent = ''; document.getElementById('msgShopManageGroup').className = 'msg'; refreshShopManageGroupUserSelect(''); } function openShopManageGroupModal() { resetShopManageGroupForm(); loadUserOptions() .then(function () { return loadShopManageGroups(); }) .then(function () { renderShopManageGroupRows(); document.getElementById('shopManageGroupModal').classList.add('show'); }); } function renderShopManageGroupRows() { var tbody = document.getElementById('shopManageGroupListBody'); if (!shopManageGroups.length) { tbody.innerHTML = '鏆傛棤鍒嗙粍'; return; } tbody.innerHTML = shopManageGroups.map(function (item, index) { return '' + (index + 1) + '' + (item.group_name || '') + '' + (item.username || '') + '' + (item.created_at || '') + '' + (item.updated_at || '') + '' + ' ' + '' + ''; }).join(''); document.querySelectorAll('[data-shop-group-edit]').forEach(function (btn) { btn.onclick = function () { document.getElementById('shopManageGroupEditId').value = btn.dataset.shopGroupEdit; refreshShopManageGroupUserSelect(btn.dataset.shopGroupUserId || ''); }; }); document.querySelectorAll('[data-shop-group-delete]').forEach(function (btn) { btn.onclick = function () { var gid = btn.dataset.shopGroupDelete; var gname = (btn.dataset.shopGroupName || '').replace(/"/g, '"'); if (!confirm('纭畾鍒犻櫎鍒嗙粍鈥? + gname + '鈥濆悧锛?)) return; fetch('/api/admin/shop-manage-group/' + gid, { method: 'DELETE' }) .then(function (r) { return r.json(); }) .then(function (res) { if (!res.success) { alert(res.error || '鍒犻櫎澶辫触'); return; } loadShopManageGroups().then(function () { renderShopManageGroupRows(); loadShopManage(shopManagePage); loadSkipPriceAsin(skipPriceAsinPage); }); }); }; }); } document.getElementById('shopManageGroupUserSelect').onchange = syncShopManageGroupNameWithUser; document.getElementById('btnManageShopGroups').onclick = openShopManageGroupModal; document.getElementById('btnManageShopGroupsFromEdit').onclick = openShopManageGroupModal; document.getElementById('btnManageSkipPriceAsinGroups').onclick = openShopManageGroupModal; document.getElementById('btnCloseShopManageGroupModal').onclick = function () { document.getElementById('shopManageGroupModal').classList.remove('show'); }; document.getElementById('btnCancelShopManageGroupEdit').onclick = resetShopManageGroupForm; document.getElementById('btnSaveShopManageGroup').onclick = function () { var editId = (document.getElementById('shopManageGroupEditId').value || '').trim(); var groupName = (document.getElementById('shopManageGroupInput').value || '').trim(); var userId = (document.getElementById('shopManageGroupUserSelect').value || '').trim(); var msgEl = document.getElementById('msgShopManageGroup'); msgEl.textContent = ''; msgEl.className = 'msg'; if (!userId || !groupName) { msgEl.textContent = '璇烽€夋嫨鍏宠仈鐢ㄦ埛'; msgEl.className = 'msg err'; return; } var method = editId ? 'PUT' : 'POST'; var url = editId ? ('/api/admin/shop-manage-group/' + editId) : '/api/admin/shop-manage-group'; fetch(url, { method: method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ group_name: groupName, user_id: Number(userId) }) }) .then(function (r) { return r.json(); }) .then(function (res) { if (!res.success) { msgEl.textContent = res.error || '淇濆瓨澶辫触'; msgEl.className = 'msg err'; return; } resetShopManageGroupForm(); msgEl.textContent = res.msg || '淇濆瓨鎴愬姛'; msgEl.className = 'msg ok'; loadShopManageGroups().then(function () { renderShopManageGroupRows(); loadShopManage(shopManagePage); loadSkipPriceAsin(skipPriceAsinPage); }); }) .catch(function () { msgEl.textContent = '璇锋眰澶辫触'; msgEl.className = 'msg err'; }); }; document.getElementById('btnCreateShopManage').onclick = function () { var groupId = (document.getElementById('shopManageGroupSelect').value || '').trim(); var shopName = (document.getElementById('shopManageShopName').value || '').trim(); var mallName = (document.getElementById('shopManageMallName').value || '').trim(); var account = (document.getElementById('shopManageAccount').value || '').trim(); var password = (document.getElementById('shopManagePassword').value || '').trim(); var msgEl = document.getElementById('msgShopManage'); msgEl.textContent = ''; msgEl.className = 'msg'; if (!groupId || !shopName || !mallName || !account || !password) { msgEl.textContent = '璇峰畬鏁村~鍐欏垎缁勩€佸簵閾哄悕銆佸簵閾哄晢鍩庡悕銆佽处鍙枫€佸瘑鐮?; msgEl.classList.add('err'); return; } fetch('/api/admin/shop-manage', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ group_id: Number(groupId), shop_name: shopName, mall_name: mallName, account: account, password: password }) }) .then(function (r) { return r.json(); }) .then(function (res) { if (res.success) { document.getElementById('shopManageGroupSelect').value = ''; document.getElementById('shopManageShopName').value = ''; document.getElementById('shopManageMallName').value = ''; document.getElementById('shopManageAccount').value = ''; document.getElementById('shopManagePassword').value = ''; msgEl.textContent = res.msg || '鍒涘缓鎴愬姛'; msgEl.className = 'msg ok'; loadShopManage(1); } else { msgEl.textContent = res.error || '鍒涘缓澶辫触'; msgEl.className = 'msg err'; } }) .catch(function () { msgEl.textContent = '璇锋眰澶辫触'; msgEl.className = 'msg err'; }); }; document.getElementById('btnSaveShopManage').onclick = function () { var itemId = document.getElementById('editShopManageId').value; var groupId = (document.getElementById('editShopManageGroupSelect').value || '').trim(); var shopName = (document.getElementById('editShopManageShopName').value || '').trim(); var mallName = (document.getElementById('editShopManageMallName').value || '').trim(); var account = (document.getElementById('editShopManageAccount').value || '').trim(); var password = (document.getElementById('editShopManagePassword').value || '').trim(); var msgEl = document.getElementById('msgEditShopManage'); msgEl.textContent = ''; msgEl.className = 'msg'; if (!groupId || !shopName || !mallName || !account || !password) { msgEl.textContent = '璇峰畬鏁村~鍐欏垎缁勩€佸簵閾哄悕銆佸簵閾哄晢鍩庡悕銆佽处鍙枫€佸瘑鐮?; msgEl.classList.add('err'); return; } fetch('/api/admin/shop-manage/' + itemId, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ group_id: Number(groupId), shop_name: shopName, mall_name: mallName, account: account, password: password }) }) .then(function (r) { return r.json(); }) .then(function (res) { if (res.success) { document.getElementById('editShopManageModal').classList.remove('show'); loadShopManage(shopManagePage); } else { msgEl.textContent = res.error || '淇濆瓨澶辫触'; msgEl.classList.add('err'); } }) .catch(function () { msgEl.textContent = '璇锋眰澶辫触'; msgEl.classList.add('err'); }); }; document.getElementById('btnCloseEditShopManage').onclick = function () { document.getElementById('editShopManageModal').classList.remove('show'); }; // ========== 鐗堟湰绠$悊 ========== // ========== 璺宠繃璺熶环 ASIN ========== var skipPriceAsinPage = 1, skipPriceAsinPageSize = 15; var chooseSkipPriceAsinShopPage = 1, chooseSkipPriceAsinShopPageSize = 10; var skipPriceCountryColumns = [ { code: 'DE', field: 'asin_de', label: '寰峰浗' }, { code: 'UK', field: 'asin_uk', label: '鑻卞浗' }, { code: 'FR', field: 'asin_fr', label: '娉曞浗' }, { code: 'IT', field: 'asin_it', label: '鎰忓ぇ鍒? }, { code: 'ES', field: 'asin_es', label: '瑗跨彮鐗? } ]; function buildChooseSkipPriceAsinShopQuery(page) { var query = 'page=' + (page || 1) + '&page_size=' + chooseSkipPriceAsinShopPageSize; var groupId = (document.getElementById('chooseSkipPriceAsinShopGroupId').value || '').trim(); var shopName = (document.getElementById('chooseSkipPriceAsinShopKeyword').value || '').trim(); if (groupId) query += '&group_id=' + encodeURIComponent(groupId); if (shopName) query += '&shop_name=' + encodeURIComponent(shopName); return query; } function loadChooseSkipPriceAsinShops(page) { chooseSkipPriceAsinShopPage = page || 1; fetch('/api/admin/shop-manages?' + buildChooseSkipPriceAsinShopQuery(chooseSkipPriceAsinShopPage)) .then(function (r) { return r.json(); }) .then(function (res) { var tbody = document.getElementById('chooseSkipPriceAsinShopListBody'); if (!res.success) { tbody.innerHTML = '鍔犺浇澶辫触: ' + (res.error || '') + ''; return; } var items = res.items || []; if (!items.length) { tbody.innerHTML = '鏆傛棤搴楅摵'; } else { tbody.innerHTML = items.map(function (item, index) { var rowNo = (chooseSkipPriceAsinShopPage - 1) * chooseSkipPriceAsinShopPageSize + index + 1; return '' + rowNo + '' + (item.group_name || '') + '' + (item.shop_name || '') + '' + (item.mall_name || '') + '' + (item.account || '') + '' + '' + ''; }).join(''); } renderPagination('chooseSkipPriceAsinShopPagination', res.total, res.page, res.page_size, loadChooseSkipPriceAsinShops); bindChooseSkipPriceAsinShopActions(); }) .catch(function () { document.getElementById('chooseSkipPriceAsinShopListBody').innerHTML = '璇锋眰澶辫触'; }); } function bindChooseSkipPriceAsinShopActions() { document.querySelectorAll('[data-choose-skip-price-asin-shop]').forEach(function (btn) { btn.onclick = function () { document.getElementById('skipPriceAsinShopName').value = (btn.dataset.shopName || '').replace(/"/g, '"'); if (!document.getElementById('skipPriceAsinGroupSelect').value && btn.dataset.groupId) { document.getElementById('skipPriceAsinGroupSelect').value = btn.dataset.groupId; } document.getElementById('chooseSkipPriceAsinShopModal').classList.remove('show'); }; }); } function openChooseSkipPriceAsinShopModal() { var currentGroupId = (document.getElementById('skipPriceAsinGroupSelect').value || '').trim(); if (currentGroupId) { document.getElementById('chooseSkipPriceAsinShopGroupId').value = currentGroupId; } document.getElementById('chooseSkipPriceAsinShopKeyword').value = (document.getElementById('skipPriceAsinShopName').value || '').trim(); document.getElementById('chooseSkipPriceAsinShopModal').classList.add('show'); loadChooseSkipPriceAsinShops(1); } function setupSkipPriceAsinShopPicker() { var input = document.getElementById('skipPriceAsinShopName'); var button = document.getElementById('btnChooseSkipPriceAsinShop'); if (!input || !button) return; var inputParent = input.parentNode; if (inputParent && inputParent.style && inputParent.style.display === 'flex') return; var legacyWrap = button.parentNode; var wrapper = document.createElement('div'); wrapper.style.display = 'flex'; wrapper.style.gap = '8px'; wrapper.style.alignItems = 'center'; input.parentNode.insertBefore(wrapper, input); wrapper.appendChild(input); wrapper.appendChild(button); button.style.whiteSpace = 'nowrap'; button.style.marginTop = '0'; if (legacyWrap && legacyWrap !== wrapper) { legacyWrap.style.display = 'none'; } } function getSelectedSkipPriceCountries() { return Array.from(document.getElementById('skipPriceAsinCountries').selectedOptions).map(function (option) { return option.value; }); } function renderSkipPriceAsinInputs() { var container = document.getElementById('skipPriceAsinInputs'); var selectedCountries = getSelectedSkipPriceCountries(); var existingValues = {}; container.querySelectorAll('[data-skip-price-country-input]').forEach(function (input) { existingValues[input.getAttribute('data-skip-price-country-input')] = input.value; }); if (!selectedCountries.length) { container.innerHTML = '
璇烽€夋嫨鍥藉鍚庤緭鍏?ASIN
'; return; } container.innerHTML = selectedCountries.map(function (countryCode) { var country = skipPriceCountryColumns.find(function (item) { return item.code === countryCode; }); var label = country ? country.label : countryCode; var value = existingValues[countryCode] || ''; return '
' + '' + label + '' + '' + '
'; }).join(''); } function collectSkipPriceAsinMappings(countries) { var mappings = {}; for (var i = 0; i < countries.length; i++) { var countryCode = countries[i]; var input = document.querySelector('[data-skip-price-country-input="' + countryCode + '"]'); var asin = input ? (input.value || '').trim().toUpperCase() : ''; if (!asin) { var country = skipPriceCountryColumns.find(function (item) { return item.code === countryCode; }); var label = country ? country.label : countryCode; throw new Error(label + ' ASIN 涓嶈兘涓虹┖'); } mappings[countryCode] = asin; } return mappings; } function buildSkipPriceAsinQuery(page) { var query = 'page=' + (page || 1) + '&page_size=' + skipPriceAsinPageSize; var groupId = (document.getElementById('skipPriceAsinFilterGroupId').value || '').trim(); var shopName = (document.getElementById('skipPriceAsinFilterShopName').value || '').trim(); var asin = (document.getElementById('skipPriceAsinFilterAsin').value || '').trim(); if (groupId) query += '&group_id=' + encodeURIComponent(groupId); if (shopName) query += '&shop_name=' + encodeURIComponent(shopName); if (asin) query += '&asin=' + encodeURIComponent(asin); return query; } function renderSkipPriceAsinCell(item, country) { var value = item[country.field] || ''; if (!value) return '-'; return '
' + '' + value + '' + '' + '' + '
'; } function bindSkipPriceAsinActions() { document.querySelectorAll('[data-skip-price-asin-edit]').forEach(function (btn) { btn.onclick = function () { var shopName = (btn.dataset.shopName || '').replace(/"/g, '"'); var countryCode = btn.dataset.country || ''; var currentAsin = (btn.dataset.asin || '').replace(/"/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(/"/g, '"'); var countryCode = btn.dataset.country || ''; if (!confirm('纭畾鍒犻櫎搴楅摵鈥? + shopName + '鈥濆湪 ' + countryCode + ' 鐨?ASIN 鍚楋紵')) return; fetch('/api/admin/skip-price-asin/' + btn.dataset.skipPriceAsinDelete + '/country/' + countryCode, { method: 'DELETE' }) .then(function (r) { return r.json(); }) .then(function (res) { if (res.success) loadSkipPriceAsin(skipPriceAsinPage); else alert(res.error || '鍒犻櫎澶辫触'); }); }; }); } function loadSkipPriceAsin(page) { skipPriceAsinPage = page || 1; fetch('/api/admin/skip-price-asins?' + buildSkipPriceAsinQuery(skipPriceAsinPage)) .then(function (r) { return r.json(); }) .then(function (res) { var tbody = document.getElementById('skipPriceAsinListBody'); if (!res.success) { tbody.innerHTML = '鍔犺浇澶辫触: ' + (res.error || '') + ''; return; } var items = res.items || []; if (items.length === 0) { tbody.innerHTML = '鏆傛棤鏁版嵁'; } else { tbody.innerHTML = items.map(function (item, index) { var rowNo = (skipPriceAsinPage - 1) * skipPriceAsinPageSize + index + 1; return '' + rowNo + '' + (item.group_name || '') + '' + (item.shop_name || '') + '' + skipPriceCountryColumns.map(function (country) { return '' + renderSkipPriceAsinCell(item, country) + ''; }).join('') + ''; }).join(''); } renderPagination('skipPriceAsinPagination', res.total, res.page, res.page_size, loadSkipPriceAsin); bindSkipPriceAsinActions(); }) .catch(function () { document.getElementById('skipPriceAsinListBody').innerHTML = '璇锋眰澶辫触'; }); } document.getElementById('btnManageSkipPriceAsinGroups').onclick = openShopManageGroupModal; document.getElementById('btnChooseSkipPriceAsinShop').onclick = openChooseSkipPriceAsinShopModal; document.getElementById('btnSearchChooseSkipPriceAsinShop').onclick = function () { loadChooseSkipPriceAsinShops(1); }; document.getElementById('chooseSkipPriceAsinShopGroupId').onchange = function () { loadChooseSkipPriceAsinShops(1); }; document.getElementById('chooseSkipPriceAsinShopKeyword').addEventListener('keydown', function (e) { if (e.key === 'Enter') { e.preventDefault(); loadChooseSkipPriceAsinShops(1); } }); document.getElementById('btnCloseChooseSkipPriceAsinShopModal').onclick = function () { document.getElementById('chooseSkipPriceAsinShopModal').classList.remove('show'); }; document.getElementById('skipPriceAsinCountries').addEventListener('change', renderSkipPriceAsinInputs); document.getElementById('btnSearchSkipPriceAsin').onclick = function () { loadSkipPriceAsin(1); }; document.getElementById('skipPriceAsinFilterShopName').addEventListener('keydown', function (e) { if (e.key === 'Enter') { e.preventDefault(); loadSkipPriceAsin(1); } }); document.getElementById('skipPriceAsinFilterAsin').addEventListener('keydown', function (e) { if (e.key === 'Enter') { e.preventDefault(); loadSkipPriceAsin(1); } }); document.getElementById('btnCreateSkipPriceAsin').onclick = function () { var groupId = (document.getElementById('skipPriceAsinGroupSelect').value || '').trim(); var shopName = (document.getElementById('skipPriceAsinShopName').value || '').trim(); var countries = getSelectedSkipPriceCountries(); var msgEl = document.getElementById('msgSkipPriceAsin'); msgEl.textContent = ''; msgEl.className = 'msg'; if (!groupId || !shopName || !countries.length) { msgEl.textContent = '璇峰畬鏁村~鍐欏垎缁勩€佸簵閾哄悕銆佸浗瀹跺拰 ASIN'; msgEl.className = 'msg err'; return; } var asinMappings = {}; try { asinMappings = collectSkipPriceAsinMappings(countries); } catch (err) { msgEl.textContent = err.message || '璇疯緭鍏?ASIN'; msgEl.className = 'msg err'; return; } var fallbackAsin = ''; Object.keys(asinMappings).some(function (countryCode) { fallbackAsin = asinMappings[countryCode] || ''; return !!fallbackAsin; }); fetch('/api/admin/skip-price-asin', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ group_id: Number(groupId), shop_name: shopName, countries: countries, asin: fallbackAsin, asin_mappings: asinMappings }) }) .then(function (r) { return r.json(); }) .then(function (res) { if (!res.success) { msgEl.textContent = res.error || '淇濆瓨澶辫触'; msgEl.className = 'msg err'; return; } document.getElementById('skipPriceAsinGroupSelect').value = ''; document.getElementById('skipPriceAsinShopName').value = ''; Array.from(document.getElementById('skipPriceAsinCountries').options).forEach(function (option) { option.selected = false; }); renderSkipPriceAsinInputs(); msgEl.textContent = res.msg || '淇濆瓨鎴愬姛'; msgEl.className = 'msg ok'; loadSkipPriceAsin(1); }) .catch(function () { msgEl.textContent = '璇锋眰澶辫触'; msgEl.className = 'msg err'; }); }; setupSkipPriceAsinShopPicker(); renderSkipPriceAsinInputs(); function loadVersions() { fetch('/api/admin/versions') .then(function (r) { return r.json(); }) .then(function (res) { var tbody = document.getElementById('versionListBody'); if (!res.success) { tbody.innerHTML = '鍔犺浇澶辫触: ' + (res.error || '') + ''; return; } var items = res.items || []; if (items.length === 0) { tbody.innerHTML = '鏆傛棤鐗堟湰璁板綍'; } else { tbody.innerHTML = items.map(function (v) { var url = (v.file_url || '').replace(/"/g, '"'); return '' + (v.version || '') + '' + url + '' + (v.created_at || '') + '涓嬭浇'; }).join(''); } }) .catch(function () { document.getElementById('versionListBody').innerHTML = '璇锋眰澶辫触'; }); } document.getElementById('btnUploadVersion').onclick = function () { var version = (document.getElementById('versionNumber').value || '').trim(); var fileInput = document.getElementById('versionZip'); var msgEl = document.getElementById('msgVersion'); msgEl.textContent = ''; msgEl.className = 'msg'; if (!version) { msgEl.textContent = '璇峰~鍐欑増鏈彿'; msgEl.classList.add('err'); return; } if (!fileInput.files || fileInput.files.length === 0) { msgEl.textContent = '璇烽€夋嫨 zip 鍘嬬缉鍖?; msgEl.classList.add('err'); return; } var file = fileInput.files[0]; if (!(file.name || '').toLowerCase().endsWith('.zip')) { msgEl.textContent = '浠呮敮鎸?.zip 鏍煎紡'; msgEl.classList.add('err'); return; } var formData = new FormData(); formData.append('version', version); formData.append('file', file); msgEl.textContent = '涓婁紶涓?..'; msgEl.classList.remove('err', 'ok'); fetch('/api/admin/version', { method: 'POST', body: formData }) .then(function (r) { return r.json(); }) .then(function (res) { if (res.success) { msgEl.textContent = '鍙戝竷鎴愬姛銆傜増鏈細' + res.version + '锛岄摼鎺ワ細' + (res.file_url || ''); msgEl.classList.add('ok'); document.getElementById('versionNumber').value = ''; fileInput.value = ''; loadVersions(); } else { msgEl.textContent = res.error || '涓婁紶澶辫触'; msgEl.classList.add('err'); } }) .catch(function () { msgEl.textContent = '璇锋眰澶辫触'; msgEl.classList.add('err'); }); }; // ========== 鏍忕洰鏉冮檺閰嶇疆 ========== function loadColumns() { fetch('/api/admin/columns') .then(function (r) { return r.json(); }) .then(function (res) { var tbody = document.getElementById('columnListBody'); if (!res.success) { tbody.innerHTML = '鍔犺浇澶辫触: ' + (res.error || '') + ''; return; } allColumnsList = res.items || []; if (allColumnsList.length === 0) { tbody.innerHTML = '鏆傛棤鑿滃崟锛岃鍦ㄤ笂鏂规柊澧?/td>'; } else { tbody.innerHTML = allColumnsList.map(function (c) { return '' + c.id + '' + (c.name || '') + '' + (c.column_key || '') + '' + (c.created_at || '') + '' + ' ' + ''; }).join(''); } bindColumnActions(); }) .catch(function () { document.getElementById('columnListBody').innerHTML = '璇锋眰澶辫触'; }); } function bindColumnActions() { document.querySelectorAll('[data-column-edit]').forEach(function (btn) { btn.onclick = function () { document.getElementById('editColumnId').value = btn.dataset.columnEdit || ''; document.getElementById('editColumnName').value = (btn.dataset.name || '').replace(/"/g, '"'); document.getElementById('editColumnKey').value = (btn.dataset.key || '').replace(/"/g, '"'); document.getElementById('msgEditColumn').textContent = ''; document.getElementById('editColumnModal').classList.add('show'); }; }); document.querySelectorAll('[data-column-delete]').forEach(function (btn) { btn.onclick = function () { if (!confirm('纭畾鍒犻櫎鑿滃崟鈥? + (btn.dataset.name || '').replace(/"/g, '"') + '鈥濆悧锛?)) return; fetch('/api/admin/column/' + btn.dataset.columnDelete, { method: 'DELETE' }) .then(function (r) { return r.json(); }) .then(function (res) { if (res.success) { loadColumns(); loadColumnsForPermission(); loadAdminMenus(getActiveAdminTabName()); } else { alert(res.error || '鍒犻櫎澶辫触'); } }); }; }); } document.getElementById('btnAddColumn').onclick = function () { var name = (document.getElementById('columnName').value || '').trim(); var key = (document.getElementById('columnKey').value || '').trim(); var msgEl = document.getElementById('msgColumn'); msgEl.textContent = ''; msgEl.className = 'msg'; if (!name) { msgEl.textContent = '璇峰~鍐欒彍鍗曞悕绉?; msgEl.classList.add('err'); return; } if (!key) { msgEl.textContent = '璇峰~鍐欐爮鐩爣璇?; msgEl.classList.add('err'); return; } fetch('/api/admin/column', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: name, column_key: key }) }) .then(function (r) { return r.json(); }) .then(function (res) { if (res.success) { msgEl.textContent = res.msg || '鏂板鎴愬姛'; msgEl.classList.add('ok'); document.getElementById('columnName').value = ''; document.getElementById('columnKey').value = ''; loadColumns(); loadColumnsForPermission(); loadAdminMenus(getActiveAdminTabName()); } else {