diff --git a/dashboard/src/i18n/locales/en-US/features/extension.json b/dashboard/src/i18n/locales/en-US/features/extension.json index 8184dcce4f..13b023bab5 100644 --- a/dashboard/src/i18n/locales/en-US/features/extension.json +++ b/dashboard/src/i18n/locales/en-US/features/extension.json @@ -177,6 +177,7 @@ "sourceResolved": "Source resolved successfully", "installPlugin": "Install Plugin", "randomPlugins": "🎲 Random Plugins", + "itemsPerPage": "Items per page", "sourceSafetyWarning": "Even with the default source, plugin stability and security cannot be fully guaranteed. Please verify carefully before use." }, "sort": { diff --git a/dashboard/src/i18n/locales/zh-CN/features/extension.json b/dashboard/src/i18n/locales/zh-CN/features/extension.json index d7afc3971c..cd5175e8ed 100644 --- a/dashboard/src/i18n/locales/zh-CN/features/extension.json +++ b/dashboard/src/i18n/locales/zh-CN/features/extension.json @@ -177,6 +177,7 @@ "sourceResolved": "插件源可用", "installPlugin": "安装插件", "randomPlugins": "🎲 随机插件", + "itemsPerPage": "\u6bcf\u9875\u663e\u793a", "sourceSafetyWarning": "即使是默认插件源,我们也不能完全保证插件的稳定性和安全性,使用前请谨慎核查。" }, "sort": { diff --git a/dashboard/src/views/extension/MarketPluginsTab.vue b/dashboard/src/views/extension/MarketPluginsTab.vue index 0bc8750e80..052764bc4e 100644 --- a/dashboard/src/views/extension/MarketPluginsTab.vue +++ b/dashboard/src/views/extension/MarketPluginsTab.vue @@ -354,13 +354,30 @@ const openMarketPluginDetail = (plugin) => { -
- + @@ -469,6 +486,45 @@ const openMarketPluginDetail = (plugin) => { .market-filter-control :deep(.v-field__prepend-inner) { font-size: 0.875rem; } +.market-pagination-footer { + display: grid; + grid-template-columns: 1fr auto 1fr; + align-items: center; + gap: 12px; + margin-top: 16px; +} + +.market-pagination-footer__pagination { + display: flex; + justify-content: center; +} + +.market-pagination-footer__page-size { + display: flex; + justify-content: flex-end; + align-items: center; + gap: 8px; +} + +.market-pagination-footer__select { + width: 110px; +} + +@media (max-width: 960px) { + .market-pagination-footer { + grid-template-columns: 1fr; + } + + .market-pagination-footer__spacer { + display: none; + } + + .market-pagination-footer__pagination, + .market-pagination-footer__page-size { + justify-content: center; + } +} + @media (max-width: 700px) { .market-header-row { diff --git a/dashboard/src/views/extension/useExtensionPage.js b/dashboard/src/views/extension/useExtensionPage.js index 7937bb2cb7..6841049852 100644 --- a/dashboard/src/views/extension/useExtensionPage.js +++ b/dashboard/src/views/extension/useExtensionPage.js @@ -206,6 +206,17 @@ export const useExtensionPage = (initialTab = "installed") => { const upload_file = ref(null); const uploadTab = ref("file"); const showPluginFullName = ref(false); + const marketItemsPerPageOptions = [9, 25, 50, 100]; + const getInitialMarketItemsPerPage = () => { + if (typeof window !== "undefined" && window.localStorage) { + const rawValue = Number(localStorage.getItem("pluginMarketItemsPerPage")); + if (marketItemsPerPageOptions.includes(rawValue)) { + return rawValue; + } + } + return 9; + }; + const marketItemsPerPage = ref(getInitialMarketItemsPerPage()); const marketSearch = ref(""); const debouncedMarketSearch = ref(""); const refreshingMarket = ref(false); @@ -460,12 +471,12 @@ export const useExtensionPage = (initialTab = "installed") => { const displayItemsPerPage = 9; // 固定每页显示9个卡片(3行) const totalPages = computed(() => { - return Math.ceil(sortedPlugins.value.length / displayItemsPerPage); + return Math.ceil(sortedPlugins.value.length / marketItemsPerPage.value); }); const paginatedPlugins = computed(() => { - const start = (currentPage.value - 1) * displayItemsPerPage; - const end = start + displayItemsPerPage; + const start = (currentPage.value - 1) * marketItemsPerPage.value; + const end = start + marketItemsPerPage.value; return sortedPlugins.value.slice(start, end); }); @@ -2415,6 +2426,13 @@ export const useExtensionPage = (initialTab = "installed") => { }, 300); // 300ms 防抖延迟 }); + watch(marketItemsPerPage, (newVal) => { + currentPage.value = 1; + if (typeof window !== "undefined" && window.localStorage) { + localStorage.setItem("pluginMarketItemsPerPage", String(newVal)); + } + }); + watch( [() => dialog.value, () => extension_url.value, () => uploadTab.value], async ([dialogOpen, _, currentUploadTab]) => { @@ -2569,6 +2587,8 @@ export const useExtensionPage = (initialTab = "installed") => { randomPlugins, shufflePlugins, refreshRandomPlugins, + marketItemsPerPage, + marketItemsPerPageOptions, displayItemsPerPage, totalPages, paginatedPlugins,