Spaces:
Running
Running
Upload 104 files
Browse files- 前端页面/components/UI交互提示组件.js +6 -4
- 前端页面/components/性能优化工具.js +4 -1
- 前端页面/core/侧边栏数据引擎.js +2 -1
- 前端页面/post/讨论区组件.js +14 -6
- 前端页面/prompt/提示词组件.js +14 -6
- 前端页面/prompt/提示词详情组件.js +12 -5
- 前端页面/task/任务榜组件.js +14 -6
前端页面/components/UI交互提示组件.js
CHANGED
|
@@ -894,10 +894,12 @@ export function createInstallProgress(container) {
|
|
| 894 |
|
| 895 |
return {
|
| 896 |
update(progress, message) {
|
| 897 |
-
|
| 898 |
-
|
| 899 |
-
|
| 900 |
-
|
|
|
|
|
|
|
| 901 |
if (message) {
|
| 902 |
stage.textContent = message;
|
| 903 |
progressTrack.setAttribute("aria-valuetext", message);
|
|
|
|
| 894 |
|
| 895 |
return {
|
| 896 |
update(progress, message) {
|
| 897 |
+
if (Number.isFinite(progress)) {
|
| 898 |
+
const p = Math.max(0, Math.min(100, progress));
|
| 899 |
+
fill.style.width = `${p}%`;
|
| 900 |
+
percent.textContent = `${p}%`;
|
| 901 |
+
progressTrack.setAttribute("aria-valuenow", String(p));
|
| 902 |
+
}
|
| 903 |
if (message) {
|
| 904 |
stage.textContent = message;
|
| 905 |
progressTrack.setAttribute("aria-valuetext", message);
|
前端页面/components/性能优化工具.js
CHANGED
|
@@ -1463,7 +1463,10 @@ export function renderListLoadError(container, message, onRetry, t, error = null
|
|
| 1463 |
retry.type = "button";
|
| 1464 |
retry.className = "comfy-ranking-list-error__retry";
|
| 1465 |
retry.textContent = t("common.retry");
|
| 1466 |
-
retry.addEventListener("click", () =>
|
|
|
|
|
|
|
|
|
|
| 1467 |
|
| 1468 |
status.append(text, retry);
|
| 1469 |
container.replaceChildren(status);
|
|
|
|
| 1463 |
retry.type = "button";
|
| 1464 |
retry.className = "comfy-ranking-list-error__retry";
|
| 1465 |
retry.textContent = t("common.retry");
|
| 1466 |
+
retry.addEventListener("click", () => {
|
| 1467 |
+
if (!status.isConnected || status.parentNode !== container) return;
|
| 1468 |
+
onRetry?.();
|
| 1469 |
+
});
|
| 1470 |
|
| 1471 |
status.append(text, retry);
|
| 1472 |
container.replaceChildren(status);
|
前端页面/core/侧边栏数据引擎.js
CHANGED
|
@@ -176,7 +176,8 @@ export async function loadSidebarContent({
|
|
| 176 |
prompts: { loadModule: getPromptsView, factory: 'createPromptsView', errorKey: 'feedback.load_prompts_failed' },
|
| 177 |
};
|
| 178 |
if (Object.hasOwn(domainViews, tab)) {
|
| 179 |
-
await mountSidebarDomainView({ contentArea, currentUser, keyword, getViewOptions
|
|
|
|
| 180 |
...domainViews[tab] });
|
| 181 |
return;
|
| 182 |
}
|
|
|
|
| 176 |
prompts: { loadModule: getPromptsView, factory: 'createPromptsView', errorKey: 'feedback.load_prompts_failed' },
|
| 177 |
};
|
| 178 |
if (Object.hasOwn(domainViews, tab)) {
|
| 179 |
+
await mountSidebarDomainView({ contentArea, currentUser, keyword, getViewOptions: force === true
|
| 180 |
+
? () => ({ ...getViewOptions?.(), force: true }) : getViewOptions, renderToken, getRenderToken,
|
| 181 |
...domainViews[tab] });
|
| 182 |
return;
|
| 183 |
}
|
前端页面/post/讨论区组件.js
CHANGED
|
@@ -87,7 +87,7 @@ function _generateAvatarHtml(avatar, name) {
|
|
| 87 |
/**
|
| 88 |
* 💬 创建讨论区视图
|
| 89 |
*/
|
| 90 |
-
export function createPostsView(currentUser, keyword = "", { sort: initialSort = "latest" } = {}) {
|
| 91 |
if (activeViewCleanup) activeViewCleanup();
|
| 92 |
|
| 93 |
currentUserCache = currentUser;
|
|
@@ -124,6 +124,7 @@ export function createPostsView(currentUser, keyword = "", { sort: initialSort =
|
|
| 124 |
let networkRequestGeneration = 0;
|
| 125 |
let disposed = false;
|
| 126 |
let firstPageReady = false;
|
|
|
|
| 127 |
const cardNavigation = createCardNavigationScope(window, () => !disposed, {
|
| 128 |
captureSession: captureRequestSession,
|
| 129 |
storageKeys: [CACHE.LEGACY_KEYS.TOKEN, CACHE.LEGACY_KEYS.USER]
|
|
@@ -317,8 +318,10 @@ export function createPostsView(currentUser, keyword = "", { sort: initialSort =
|
|
| 317 |
postsGrid.appendChild(status);
|
| 318 |
};
|
| 319 |
|
| 320 |
-
const loadPosts = async (page = 1, append = false) => {
|
| 321 |
if (disposed) return;
|
|
|
|
|
|
|
| 322 |
if (!append && page === 1) firstPageReady = false;
|
| 323 |
const viewGeneration = !append && page === 1 ? ++listViewGeneration : listViewGeneration;
|
| 324 |
const requestedSort = currentSort;
|
|
@@ -332,7 +335,7 @@ export function createPostsView(currentUser, keyword = "", { sort: initialSort =
|
|
| 332 |
allPostsData = proxyImages(cachedData);
|
| 333 |
renderPostsFromCache(allPostsData, true);
|
| 334 |
// 后台静默更新
|
| 335 |
-
silentRefresh().finally(() => {
|
| 336 |
if (disposed || viewGeneration !== listViewGeneration) return;
|
| 337 |
if (searchKeyword && !allPostsData.some(post => _matchesSearch(post, searchKeyword))) {
|
| 338 |
currentPaginator?.load();
|
|
@@ -351,7 +354,7 @@ export function createPostsView(currentUser, keyword = "", { sort: initialSort =
|
|
| 351 |
requestGeneration = ++networkRequestGeneration;
|
| 352 |
isLoadingFromNetwork = true;
|
| 353 |
const readResponse = captureListRead(cacheKey);
|
| 354 |
-
const res = await api.getPosts(page, PAGE_SIZE, requestedSort);
|
| 355 |
if (viewGeneration !== listViewGeneration || requestGeneration !== networkRequestGeneration) {
|
| 356 |
if (requestGeneration === networkRequestGeneration) {
|
| 357 |
isLoadingFromNetwork = false;
|
|
@@ -443,7 +446,10 @@ export function createPostsView(currentUser, keyword = "", { sort: initialSort =
|
|
| 443 |
renderPostsFromCache(allPostsData);
|
| 444 |
showToast(t('post.network_cache'), "warning");
|
| 445 |
} else {
|
| 446 |
-
renderListLoadError(postsGrid, err?.name === 'ListCacheChangedError' ? t('feedback.list_changed_retry') : t('post.load_failed'), () =>
|
|
|
|
|
|
|
|
|
|
| 447 |
}
|
| 448 |
}
|
| 449 |
}
|
|
@@ -500,7 +506,7 @@ export function createPostsView(currentUser, keyword = "", { sort: initialSort =
|
|
| 500 |
};
|
| 501 |
|
| 502 |
// 后台静默更新
|
| 503 |
-
const silentRefresh = async () => {
|
| 504 |
if (disposed || isLoadingFromNetwork) return;
|
| 505 |
const viewGeneration = listViewGeneration;
|
| 506 |
const requestedSort = currentSort;
|
|
@@ -550,6 +556,8 @@ export function createPostsView(currentUser, keyword = "", { sort: initialSort =
|
|
| 550 |
}
|
| 551 |
isLoadingFromNetwork = false;
|
| 552 |
console.warn("后台更新帖子失败(保留当前内容)");
|
|
|
|
|
|
|
| 553 |
}
|
| 554 |
if (searchKeyword && !allPostsData.some(post => _matchesSearch(post, searchKeyword))) {
|
| 555 |
currentPaginator?.load();
|
|
|
|
| 87 |
/**
|
| 88 |
* 💬 创建讨论区视图
|
| 89 |
*/
|
| 90 |
+
export function createPostsView(currentUser, keyword = "", { sort: initialSort = "latest", force: initialForce = false } = {}) {
|
| 91 |
if (activeViewCleanup) activeViewCleanup();
|
| 92 |
|
| 93 |
currentUserCache = currentUser;
|
|
|
|
| 124 |
let networkRequestGeneration = 0;
|
| 125 |
let disposed = false;
|
| 126 |
let firstPageReady = false;
|
| 127 |
+
let forceRefreshPending = initialForce === true;
|
| 128 |
const cardNavigation = createCardNavigationScope(window, () => !disposed, {
|
| 129 |
captureSession: captureRequestSession,
|
| 130 |
storageKeys: [CACHE.LEGACY_KEYS.TOKEN, CACHE.LEGACY_KEYS.USER]
|
|
|
|
| 318 |
postsGrid.appendChild(status);
|
| 319 |
};
|
| 320 |
|
| 321 |
+
const loadPosts = async (page = 1, append = false, forceRequest = false) => {
|
| 322 |
if (disposed) return;
|
| 323 |
+
const forceRefresh = !append && page === 1 && (forceRefreshPending || forceRequest === true);
|
| 324 |
+
if (forceRefresh) forceRefreshPending = false;
|
| 325 |
if (!append && page === 1) firstPageReady = false;
|
| 326 |
const viewGeneration = !append && page === 1 ? ++listViewGeneration : listViewGeneration;
|
| 327 |
const requestedSort = currentSort;
|
|
|
|
| 335 |
allPostsData = proxyImages(cachedData);
|
| 336 |
renderPostsFromCache(allPostsData, true);
|
| 337 |
// 后台静默更新
|
| 338 |
+
silentRefresh(forceRefresh).finally(() => {
|
| 339 |
if (disposed || viewGeneration !== listViewGeneration) return;
|
| 340 |
if (searchKeyword && !allPostsData.some(post => _matchesSearch(post, searchKeyword))) {
|
| 341 |
currentPaginator?.load();
|
|
|
|
| 354 |
requestGeneration = ++networkRequestGeneration;
|
| 355 |
isLoadingFromNetwork = true;
|
| 356 |
const readResponse = captureListRead(cacheKey);
|
| 357 |
+
const res = await api.getPosts(page, PAGE_SIZE, requestedSort, ...(forceRefresh ? [{ noCache: true }] : []));
|
| 358 |
if (viewGeneration !== listViewGeneration || requestGeneration !== networkRequestGeneration) {
|
| 359 |
if (requestGeneration === networkRequestGeneration) {
|
| 360 |
isLoadingFromNetwork = false;
|
|
|
|
| 446 |
renderPostsFromCache(allPostsData);
|
| 447 |
showToast(t('post.network_cache'), "warning");
|
| 448 |
} else {
|
| 449 |
+
renderListLoadError(postsGrid, err?.name === 'ListCacheChangedError' ? t('feedback.list_changed_retry') : t('post.load_failed'), () => {
|
| 450 |
+
if (disposed || isLoadingFromNetwork || requestedSort !== currentSort) return;
|
| 451 |
+
return loadPosts(1, false, forceRefresh);
|
| 452 |
+
}, t, err);
|
| 453 |
}
|
| 454 |
}
|
| 455 |
}
|
|
|
|
| 506 |
};
|
| 507 |
|
| 508 |
// 后台静默更新
|
| 509 |
+
const silentRefresh = async (notifyFailure = false) => {
|
| 510 |
if (disposed || isLoadingFromNetwork) return;
|
| 511 |
const viewGeneration = listViewGeneration;
|
| 512 |
const requestedSort = currentSort;
|
|
|
|
| 556 |
}
|
| 557 |
isLoadingFromNetwork = false;
|
| 558 |
console.warn("后台更新帖子失败(保留当前内容)");
|
| 559 |
+
if (notifyFailure === true) showToast(t(err?.name === 'ListCacheChangedError'
|
| 560 |
+
? 'feedback.list_changed_retry' : 'feedback.refresh_failed_cached'), 'warning');
|
| 561 |
}
|
| 562 |
if (searchKeyword && !allPostsData.some(post => _matchesSearch(post, searchKeyword))) {
|
| 563 |
currentPaginator?.load();
|
前端页面/prompt/提示词组件.js
CHANGED
|
@@ -124,7 +124,7 @@ function _generateAvatarHtml(avatar, name) {
|
|
| 124 |
/**
|
| 125 |
* 🧩 创建提示词视图
|
| 126 |
*/
|
| 127 |
-
export function createPromptsView(currentUser, keyword = "", { sort: initialSort = "latest", type: initialType = "image", category: initialCategory = null, onFiltersChange } = {}) {
|
| 128 |
if (activeViewCleanup) activeViewCleanup();
|
| 129 |
|
| 130 |
currentUserCache = currentUser;
|
|
@@ -179,6 +179,7 @@ export function createPromptsView(currentUser, keyword = "", { sort: initialSort
|
|
| 179 |
let currentPaginator = null;
|
| 180 |
let disposed = false;
|
| 181 |
let firstPageReady = false;
|
|
|
|
| 182 |
const cardNavigation = createCardNavigationScope(window, () => !disposed, {
|
| 183 |
captureSession: captureRequestSession,
|
| 184 |
storageKeys: [CACHE.LEGACY_KEYS.TOKEN, CACHE.LEGACY_KEYS.USER]
|
|
@@ -441,8 +442,10 @@ export function createPromptsView(currentUser, keyword = "", { sort: initialSort
|
|
| 441 |
}
|
| 442 |
};
|
| 443 |
|
| 444 |
-
const loadPrompts = async (page = 1, append = false) => {
|
| 445 |
if (disposed) return;
|
|
|
|
|
|
|
| 446 |
if (!append && page === 1) firstPageReady = false;
|
| 447 |
const viewGeneration = !append && page === 1 ? ++listViewGeneration : listViewGeneration;
|
| 448 |
const requestedType = currentType;
|
|
@@ -457,7 +460,7 @@ export function createPromptsView(currentUser, keyword = "", { sort: initialSort
|
|
| 457 |
allPromptsData = proxyImages(cachedData);
|
| 458 |
renderPromptsFromCache(allPromptsData, true);
|
| 459 |
// 后台静默更新
|
| 460 |
-
silentRefresh().finally(() => {
|
| 461 |
if (disposed || viewGeneration !== listViewGeneration) return;
|
| 462 |
if (searchKeyword && !allPromptsData.some(prompt => _matchesSearch(prompt, searchKeyword))) {
|
| 463 |
currentPaginator?.load();
|
|
@@ -476,7 +479,7 @@ export function createPromptsView(currentUser, keyword = "", { sort: initialSort
|
|
| 476 |
requestGeneration = ++networkRequestGeneration;
|
| 477 |
isLoadingFromNetwork = true;
|
| 478 |
const readResponse = captureListRead(cacheKey);
|
| 479 |
-
const res = await api.getPrompts(requestedType, requestedCategory, page, PAGE_SIZE, requestedSort);
|
| 480 |
if (viewGeneration !== listViewGeneration || requestGeneration !== networkRequestGeneration) {
|
| 481 |
if (requestGeneration === networkRequestGeneration) {
|
| 482 |
isLoadingFromNetwork = false;
|
|
@@ -567,7 +570,10 @@ export function createPromptsView(currentUser, keyword = "", { sort: initialSort
|
|
| 567 |
renderPromptsFromCache(allPromptsData);
|
| 568 |
showToast(t('prompt.network_cache'), "warning");
|
| 569 |
} else {
|
| 570 |
-
renderListLoadError(promptsGrid, err?.name === 'ListCacheChangedError' ? t('feedback.list_changed_retry') : t('prompt.load_failed'), () =>
|
|
|
|
|
|
|
|
|
|
| 571 |
}
|
| 572 |
}
|
| 573 |
}
|
|
@@ -624,7 +630,7 @@ export function createPromptsView(currentUser, keyword = "", { sort: initialSort
|
|
| 624 |
};
|
| 625 |
|
| 626 |
// 后台静默更新
|
| 627 |
-
const silentRefresh = async () => {
|
| 628 |
if (disposed || isLoadingFromNetwork) return;
|
| 629 |
const viewGeneration = listViewGeneration;
|
| 630 |
const requestedType = currentType;
|
|
@@ -676,6 +682,8 @@ export function createPromptsView(currentUser, keyword = "", { sort: initialSort
|
|
| 676 |
}
|
| 677 |
isLoadingFromNetwork = false;
|
| 678 |
console.warn("后台更新提示词失败(保留当前内容)");
|
|
|
|
|
|
|
| 679 |
}
|
| 680 |
if (searchKeyword && !allPromptsData.some(prompt => _matchesSearch(prompt, searchKeyword))) {
|
| 681 |
currentPaginator?.load();
|
|
|
|
| 124 |
/**
|
| 125 |
* 🧩 创建提示词视图
|
| 126 |
*/
|
| 127 |
+
export function createPromptsView(currentUser, keyword = "", { sort: initialSort = "latest", type: initialType = "image", category: initialCategory = null, onFiltersChange, force: initialForce = false } = {}) {
|
| 128 |
if (activeViewCleanup) activeViewCleanup();
|
| 129 |
|
| 130 |
currentUserCache = currentUser;
|
|
|
|
| 179 |
let currentPaginator = null;
|
| 180 |
let disposed = false;
|
| 181 |
let firstPageReady = false;
|
| 182 |
+
let forceRefreshPending = initialForce === true;
|
| 183 |
const cardNavigation = createCardNavigationScope(window, () => !disposed, {
|
| 184 |
captureSession: captureRequestSession,
|
| 185 |
storageKeys: [CACHE.LEGACY_KEYS.TOKEN, CACHE.LEGACY_KEYS.USER]
|
|
|
|
| 442 |
}
|
| 443 |
};
|
| 444 |
|
| 445 |
+
const loadPrompts = async (page = 1, append = false, forceRequest = false) => {
|
| 446 |
if (disposed) return;
|
| 447 |
+
const forceRefresh = !append && page === 1 && (forceRefreshPending || forceRequest === true);
|
| 448 |
+
if (forceRefresh) forceRefreshPending = false;
|
| 449 |
if (!append && page === 1) firstPageReady = false;
|
| 450 |
const viewGeneration = !append && page === 1 ? ++listViewGeneration : listViewGeneration;
|
| 451 |
const requestedType = currentType;
|
|
|
|
| 460 |
allPromptsData = proxyImages(cachedData);
|
| 461 |
renderPromptsFromCache(allPromptsData, true);
|
| 462 |
// 后台静默更新
|
| 463 |
+
silentRefresh(forceRefresh).finally(() => {
|
| 464 |
if (disposed || viewGeneration !== listViewGeneration) return;
|
| 465 |
if (searchKeyword && !allPromptsData.some(prompt => _matchesSearch(prompt, searchKeyword))) {
|
| 466 |
currentPaginator?.load();
|
|
|
|
| 479 |
requestGeneration = ++networkRequestGeneration;
|
| 480 |
isLoadingFromNetwork = true;
|
| 481 |
const readResponse = captureListRead(cacheKey);
|
| 482 |
+
const res = await api.getPrompts(requestedType, requestedCategory, page, PAGE_SIZE, requestedSort, ...(forceRefresh ? [{ noCache: true }] : []));
|
| 483 |
if (viewGeneration !== listViewGeneration || requestGeneration !== networkRequestGeneration) {
|
| 484 |
if (requestGeneration === networkRequestGeneration) {
|
| 485 |
isLoadingFromNetwork = false;
|
|
|
|
| 570 |
renderPromptsFromCache(allPromptsData);
|
| 571 |
showToast(t('prompt.network_cache'), "warning");
|
| 572 |
} else {
|
| 573 |
+
renderListLoadError(promptsGrid, err?.name === 'ListCacheChangedError' ? t('feedback.list_changed_retry') : t('prompt.load_failed'), () => {
|
| 574 |
+
if (disposed || isLoadingFromNetwork || requestedType !== currentType || requestedCategory !== currentCategory || requestedSort !== currentSort) return;
|
| 575 |
+
return loadPrompts(1, false, forceRefresh);
|
| 576 |
+
}, t, err);
|
| 577 |
}
|
| 578 |
}
|
| 579 |
}
|
|
|
|
| 630 |
};
|
| 631 |
|
| 632 |
// 后台静默更新
|
| 633 |
+
const silentRefresh = async (notifyFailure = false) => {
|
| 634 |
if (disposed || isLoadingFromNetwork) return;
|
| 635 |
const viewGeneration = listViewGeneration;
|
| 636 |
const requestedType = currentType;
|
|
|
|
| 682 |
}
|
| 683 |
isLoadingFromNetwork = false;
|
| 684 |
console.warn("后台更新提示词失败(保留当前内容)");
|
| 685 |
+
if (notifyFailure === true) showToast(t(err?.name === 'ListCacheChangedError'
|
| 686 |
+
? 'feedback.list_changed_retry' : 'feedback.refresh_failed_cached'), 'warning');
|
| 687 |
}
|
| 688 |
if (searchKeyword && !allPromptsData.some(prompt => _matchesSearch(prompt, searchKeyword))) {
|
| 689 |
currentPaginator?.load();
|
前端页面/prompt/提示词详情组件.js
CHANGED
|
@@ -469,18 +469,25 @@ function copyToClipboard(text, btnEl, current) {
|
|
| 469 |
}
|
| 470 |
|
| 471 |
function fallbackCopy(text, onSuccess, onFail) {
|
|
|
|
|
|
|
|
|
|
| 472 |
try {
|
| 473 |
-
|
| 474 |
ta.value = text;
|
| 475 |
ta.style.cssText = "position: fixed; top: -9999px; opacity: 0;";
|
| 476 |
document.body.appendChild(ta);
|
| 477 |
ta.select();
|
| 478 |
-
|
| 479 |
-
ta.remove();
|
| 480 |
-
ok ? onSuccess() : onFail();
|
| 481 |
} catch (e) {
|
| 482 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 483 |
}
|
|
|
|
| 484 |
}
|
| 485 |
|
| 486 |
/**
|
|
|
|
| 469 |
}
|
| 470 |
|
| 471 |
function fallbackCopy(text, onSuccess, onFail) {
|
| 472 |
+
const previousFocus = document.activeElement;
|
| 473 |
+
let ta;
|
| 474 |
+
let copied = false;
|
| 475 |
try {
|
| 476 |
+
ta = document.createElement("textarea");
|
| 477 |
ta.value = text;
|
| 478 |
ta.style.cssText = "position: fixed; top: -9999px; opacity: 0;";
|
| 479 |
document.body.appendChild(ta);
|
| 480 |
ta.select();
|
| 481 |
+
copied = document.execCommand("copy");
|
|
|
|
|
|
|
| 482 |
} catch (e) {
|
| 483 |
+
} finally {
|
| 484 |
+
const restoreFocus = ta && document.activeElement === ta;
|
| 485 |
+
ta?.remove();
|
| 486 |
+
if (restoreFocus && previousFocus?.isConnected && previousFocus.getClientRects().length && document.hasFocus()) {
|
| 487 |
+
previousFocus.focus({ preventScroll: true });
|
| 488 |
+
}
|
| 489 |
}
|
| 490 |
+
copied ? onSuccess() : onFail();
|
| 491 |
}
|
| 492 |
|
| 493 |
/**
|
前端页面/task/任务榜组件.js
CHANGED
|
@@ -89,7 +89,7 @@ function _renderNoTasksView() {
|
|
| 89 |
/**
|
| 90 |
* 📝 创建任务榜视图
|
| 91 |
*/
|
| 92 |
-
export function createTasksView(currentUser, keyword = "", { sort: initialSort = "latest", status: initialStatus = "" } = {}) {
|
| 93 |
if (activeViewCleanup) activeViewCleanup();
|
| 94 |
currentUserCache = currentUser;
|
| 95 |
const searchKeyword = keyword.toLowerCase();
|
|
@@ -128,6 +128,7 @@ export function createTasksView(currentUser, keyword = "", { sort: initialSort =
|
|
| 128 |
let networkRequestGeneration = 0;
|
| 129 |
let disposed = false;
|
| 130 |
let firstPageReady = false;
|
|
|
|
| 131 |
const cardNavigation = createCardNavigationScope(window, () => !disposed, {
|
| 132 |
captureSession: captureRequestSession,
|
| 133 |
storageKeys: [CACHE.LEGACY_KEYS.TOKEN, CACHE.LEGACY_KEYS.USER]
|
|
@@ -234,8 +235,10 @@ export function createTasksView(currentUser, keyword = "", { sort: initialSort =
|
|
| 234 |
};
|
| 235 |
|
| 236 |
// 加载任务列表(支持缓存优先)
|
| 237 |
-
const loadTasks = async (page = 1, append = false) => {
|
| 238 |
if (disposed) return;
|
|
|
|
|
|
|
| 239 |
if (!append && page === 1) firstPageReady = false;
|
| 240 |
const viewGeneration = !append && page === 1 ? ++listViewGeneration : listViewGeneration;
|
| 241 |
const requestedStatus = currentStatus;
|
|
@@ -250,7 +253,7 @@ export function createTasksView(currentUser, keyword = "", { sort: initialSort =
|
|
| 250 |
allTasksData = proxyImages(cachedData);
|
| 251 |
renderTasksFromCache(allTasksData);
|
| 252 |
// 后台静默更新
|
| 253 |
-
silentRefresh().finally(continueSearchPagination);
|
| 254 |
return;
|
| 255 |
}
|
| 256 |
}
|
|
@@ -265,7 +268,7 @@ export function createTasksView(currentUser, keyword = "", { sort: initialSort =
|
|
| 265 |
isLoadingFromNetwork = true;
|
| 266 |
|
| 267 |
const readResponse = captureListRead(cacheKey);
|
| 268 |
-
const res = await api.getTasks(page, PAGE_SIZE, requestedStatus || null, requestedSort);
|
| 269 |
if (viewGeneration !== listViewGeneration || requestGeneration !== networkRequestGeneration) {
|
| 270 |
if (requestGeneration === networkRequestGeneration) {
|
| 271 |
isLoadingFromNetwork = false;
|
|
@@ -348,7 +351,10 @@ export function createTasksView(currentUser, keyword = "", { sort: initialSort =
|
|
| 348 |
showToast(t('task.network_cache'), "warning");
|
| 349 |
continueSearchPagination();
|
| 350 |
} else {
|
| 351 |
-
renderListLoadError(tasksList, err?.name === 'ListCacheChangedError' ? t('feedback.list_changed_retry') : t('task.load_failed'), () =>
|
|
|
|
|
|
|
|
|
|
| 352 |
}
|
| 353 |
}
|
| 354 |
}
|
|
@@ -400,7 +406,7 @@ export function createTasksView(currentUser, keyword = "", { sort: initialSort =
|
|
| 400 |
};
|
| 401 |
|
| 402 |
// 后台静默更新
|
| 403 |
-
const silentRefresh = async () => {
|
| 404 |
if (disposed || isLoadingFromNetwork) return;
|
| 405 |
const viewGeneration = listViewGeneration;
|
| 406 |
const requestedStatus = currentStatus;
|
|
@@ -451,6 +457,8 @@ export function createTasksView(currentUser, keyword = "", { sort: initialSort =
|
|
| 451 |
}
|
| 452 |
isLoadingFromNetwork = false;
|
| 453 |
console.warn("后台更新任务失败(保留当前内容)");
|
|
|
|
|
|
|
| 454 |
}
|
| 455 |
continueSearchPagination();
|
| 456 |
};
|
|
|
|
| 89 |
/**
|
| 90 |
* 📝 创建任务榜视图
|
| 91 |
*/
|
| 92 |
+
export function createTasksView(currentUser, keyword = "", { sort: initialSort = "latest", status: initialStatus = "", force: initialForce = false } = {}) {
|
| 93 |
if (activeViewCleanup) activeViewCleanup();
|
| 94 |
currentUserCache = currentUser;
|
| 95 |
const searchKeyword = keyword.toLowerCase();
|
|
|
|
| 128 |
let networkRequestGeneration = 0;
|
| 129 |
let disposed = false;
|
| 130 |
let firstPageReady = false;
|
| 131 |
+
let forceRefreshPending = initialForce === true;
|
| 132 |
const cardNavigation = createCardNavigationScope(window, () => !disposed, {
|
| 133 |
captureSession: captureRequestSession,
|
| 134 |
storageKeys: [CACHE.LEGACY_KEYS.TOKEN, CACHE.LEGACY_KEYS.USER]
|
|
|
|
| 235 |
};
|
| 236 |
|
| 237 |
// 加载任务列表(支持缓存优先)
|
| 238 |
+
const loadTasks = async (page = 1, append = false, forceRequest = false) => {
|
| 239 |
if (disposed) return;
|
| 240 |
+
const forceRefresh = !append && page === 1 && (forceRefreshPending || forceRequest === true);
|
| 241 |
+
if (forceRefresh) forceRefreshPending = false;
|
| 242 |
if (!append && page === 1) firstPageReady = false;
|
| 243 |
const viewGeneration = !append && page === 1 ? ++listViewGeneration : listViewGeneration;
|
| 244 |
const requestedStatus = currentStatus;
|
|
|
|
| 253 |
allTasksData = proxyImages(cachedData);
|
| 254 |
renderTasksFromCache(allTasksData);
|
| 255 |
// 后台静默更新
|
| 256 |
+
silentRefresh(forceRefresh).finally(continueSearchPagination);
|
| 257 |
return;
|
| 258 |
}
|
| 259 |
}
|
|
|
|
| 268 |
isLoadingFromNetwork = true;
|
| 269 |
|
| 270 |
const readResponse = captureListRead(cacheKey);
|
| 271 |
+
const res = await api.getTasks(page, PAGE_SIZE, requestedStatus || null, requestedSort, ...(forceRefresh ? [{ noCache: true }] : []));
|
| 272 |
if (viewGeneration !== listViewGeneration || requestGeneration !== networkRequestGeneration) {
|
| 273 |
if (requestGeneration === networkRequestGeneration) {
|
| 274 |
isLoadingFromNetwork = false;
|
|
|
|
| 351 |
showToast(t('task.network_cache'), "warning");
|
| 352 |
continueSearchPagination();
|
| 353 |
} else {
|
| 354 |
+
renderListLoadError(tasksList, err?.name === 'ListCacheChangedError' ? t('feedback.list_changed_retry') : t('task.load_failed'), () => {
|
| 355 |
+
if (disposed || isLoadingFromNetwork || requestedStatus !== currentStatus || requestedSort !== currentSort) return;
|
| 356 |
+
return loadTasks(1, false, forceRefresh);
|
| 357 |
+
}, t, err);
|
| 358 |
}
|
| 359 |
}
|
| 360 |
}
|
|
|
|
| 406 |
};
|
| 407 |
|
| 408 |
// 后台静默更新
|
| 409 |
+
const silentRefresh = async (notifyFailure = false) => {
|
| 410 |
if (disposed || isLoadingFromNetwork) return;
|
| 411 |
const viewGeneration = listViewGeneration;
|
| 412 |
const requestedStatus = currentStatus;
|
|
|
|
| 457 |
}
|
| 458 |
isLoadingFromNetwork = false;
|
| 459 |
console.warn("后台更新任务失败(保留当前内容)");
|
| 460 |
+
if (notifyFailure === true) showToast(t(err?.name === 'ListCacheChangedError'
|
| 461 |
+
? 'feedback.list_changed_retry' : 'feedback.refresh_failed_cached'), 'warning');
|
| 462 |
}
|
| 463 |
continueSearchPagination();
|
| 464 |
};
|