diff --git a/backend/static/admin.js b/backend/static/admin.js index 55498f9e..33e9396e 100644 --- a/backend/static/admin.js +++ b/backend/static/admin.js @@ -388,7 +388,44 @@ } var allColumnsList = []; var columnPermissionCatalogReady = false; + var columnPermissionCatalogState = 'idle'; // idle | loading | ready | failed + var columnPermissionCatalogError = ''; var columnCardsContainerMap = { createColumnPermissionWrap: 'createColumnCards', editColumnPermissionWrap: 'editColumnCards' }; + function fetchCatalogWithRetry(url, attempts) { + return fetch(url).then(function (r) { + if (!r.ok) throw new Error('请求失败(' + r.status + ')'); + return r.json(); + }).catch(function (error) { + if (attempts <= 1) throw error; + return new Promise(function (resolve) { setTimeout(resolve, 700); }) + .then(function () { return fetchCatalogWithRetry(url, attempts - 1); }); + }); + } + function renderPermissionCatalogStatus() { + var wrap = document.getElementById('createColumnPermissionWrap'); + if (!wrap) return; + if (columnPermissionCatalogState === 'loading') { + wrap.textContent = '菜单权限加载中…'; + } else if (columnPermissionCatalogState === 'failed') { + wrap.innerHTML = ''; + var tip = document.createElement('div'); + tip.style.color = '#e5484d'; + tip.style.fontSize = '13px'; + tip.style.padding = '8px 0'; + tip.textContent = '菜单权限加载失败' + + (columnPermissionCatalogError ? '(' + columnPermissionCatalogError + ')' : '') + + ':'; + var retryBtn = document.createElement('button'); + retryBtn.type = 'button'; + retryBtn.className = 'col-perm-retry'; + retryBtn.textContent = '重新加载'; + retryBtn.style.marginLeft = '6px'; + retryBtn.style.padding = '2px 10px'; + retryBtn.onclick = loadColumnsForPermission; + tip.appendChild(retryBtn); + wrap.appendChild(tip); + } + } // Hierarchical permission editor: only direct IDs are submitted; descendants are visual inheritance. function columnParentId(item) { var value = item && item.parent_id != null ? item.parent_id : item && item.parentId; @@ -424,12 +461,16 @@ return columnTreeFullyCovered(columnId(child), directIds); }); } + var columnPermissionCatalogPending = null; function loadColumnsForPermission() { + if (columnPermissionCatalogPending) return columnPermissionCatalogPending; columnPermissionCatalogReady = false; + columnPermissionCatalogState = 'loading'; + columnPermissionCatalogError = ''; + renderPermissionCatalogStatus(); var ownedKeys = {}, ownedRoutes = {}; var ownPermissionRequest = (currentUserRole === 'admin' && currentUserId) - ? fetch('/api/admin/user/' + currentUserId + '/column-permissions') - .then(function (r) { return r.json(); }) + ? fetchCatalogWithRetry('/api/admin/user/' + currentUserId + '/column-permissions', 3) .then(function (res) { if (!res.success) throw new Error(res.error || '当前用户权限加载失败'); (res.items || []).forEach(function (item) { @@ -438,10 +479,9 @@ }); }) : Promise.resolve(); - ownPermissionRequest.then(function () { return fetch('/api/admin/columns'); }) - .then(function (r) { return r.json(); }) + var catalogChain = ownPermissionRequest.then(function () { return fetchCatalogWithRetry('/api/admin/columns', 3); }) .then(function (res) { - if (!res.success) return; + if (!res.success) throw new Error(res.error || '菜单列表加载失败'); var availableColumns = (res.items || []).filter(function (item) { if (item.column_key === 'admin_image_video_task_data' || item.column_key === 'admin_shop_data_crawl_task_data') return false; @@ -477,17 +517,25 @@ }); } columnPermissionCatalogReady = true; + columnPermissionCatalogState = 'ready'; renderColumnPermissionWrap('createColumnPermissionWrap'); renderColumnPermissionWrap('editColumnPermissionWrap'); populateColumnParentSelects(); - }).catch(function () { + }).catch(function (error) { columnPermissionCatalogReady = false; + columnPermissionCatalogState = 'failed'; + columnPermissionCatalogError = (error && error.message) ? error.message : ''; allColumnsList = []; var editPermissionWrap = document.getElementById('editColumnPermissionWrap'); if (editPermissionWrap) editPermissionWrap._permissionsReady = false; renderColumnPermissionWrap('createColumnPermissionWrap'); renderColumnPermissionWrap('editColumnPermissionWrap'); + renderPermissionCatalogStatus(); + }).finally(function () { + columnPermissionCatalogPending = null; }); + columnPermissionCatalogPending = catalogChain; + return catalogChain; } function renderColumnCards(wrapId) { var wrap = document.getElementById(wrapId); @@ -748,6 +796,9 @@ editPermissionWrap._directIds = {}; editPermissionWrap._permissionsReady = false; renderColumnPermissionWrap('editColumnPermissionWrap'); + if (!columnPermissionCatalogReady && (columnPermissionCatalogState === 'failed' || columnPermissionCatalogState === 'idle')) { + loadColumnsForPermission(); + } fetch('/api/admin/user/' + (u.id) + '/columns') .then(function (r) { return r.json(); }) .then(function (res) { @@ -800,7 +851,13 @@ return; } if (!columnPermissionCatalogReady) { - msgEl.textContent = '菜单权限尚未加载,请稍后重试'; + if (columnPermissionCatalogState === 'failed' || columnPermissionCatalogState === 'idle') { + loadColumnsForPermission(); + msgEl.textContent = '菜单权限加载失败,已重新加载,请稍后重试'; + msgEl.classList.add('err'); + return; + } + msgEl.textContent = '菜单权限尚未加载(加载中),请稍后重试'; msgEl.classList.add('err'); return; } diff --git a/backend/web_source/admin.html b/backend/web_source/admin.html index f2ef9acf..1d8005fa 100644 --- a/backend/web_source/admin.html +++ b/backend/web_source/admin.html @@ -3209,7 +3209,7 @@ - +