From 8089ad91da1bcceb8f3289d458f05af40fe03013 Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Thu, 6 Nov 2025 13:57:46 +0800 Subject: [PATCH] perf: improve extension market ui --- .../locales/en-US/features/extension.json | 8 + .../locales/zh-CN/features/extension.json | 8 + dashboard/src/views/ExtensionPage.vue | 321 +++++++++++++----- 3 files changed, 256 insertions(+), 81 deletions(-) diff --git a/dashboard/src/i18n/locales/en-US/features/extension.json b/dashboard/src/i18n/locales/en-US/features/extension.json index f2fc8c6eb..911523e22 100644 --- a/dashboard/src/i18n/locales/en-US/features/extension.json +++ b/dashboard/src/i18n/locales/en-US/features/extension.json @@ -79,6 +79,14 @@ "devDocs": "Extension Development Docs", "submitRepo": "Submit Extension Repository" }, + "sort": { + "default": "Default", + "stars": "Stars", + "author": "Author", + "updated": "Last Updated", + "ascending": "Ascending", + "descending": "Descending" + }, "tags": { "danger": "Danger" }, diff --git a/dashboard/src/i18n/locales/zh-CN/features/extension.json b/dashboard/src/i18n/locales/zh-CN/features/extension.json index 940e43e20..e52494d7c 100644 --- a/dashboard/src/i18n/locales/zh-CN/features/extension.json +++ b/dashboard/src/i18n/locales/zh-CN/features/extension.json @@ -79,6 +79,14 @@ "devDocs": "插件开发文档", "submitRepo": "提交插件仓库" }, + "sort": { + "default": "默认排序", + "stars": "Star数", + "author": "作者名", + "updated": "更新时间", + "ascending": "升序", + "descending": "降序" + }, "tags": { "danger": "危险" }, diff --git a/dashboard/src/views/ExtensionPage.vue b/dashboard/src/views/ExtensionPage.vue index a25497d74..bb83dc912 100644 --- a/dashboard/src/views/ExtensionPage.vue +++ b/dashboard/src/views/ExtensionPage.vue @@ -10,7 +10,7 @@ import { pinyin } from 'pinyin-pro'; import { useCommonStore } from '@/stores/common'; import { useI18n, useModuleI18n } from '@/i18n/composables'; -import { ref, computed, onMounted, reactive, inject } from 'vue'; +import { ref, computed, onMounted, reactive, inject, watch } from 'vue'; const commonStore = useCommonStore(); @@ -53,6 +53,10 @@ const isListView = ref(false); const pluginSearch = ref(""); const loading_ = ref(false); +// 分页相关 +const currentPage = ref(1); +const itemsPerPage = ref(6); // 每页显示6个卡片 (2行 x 3列,避免滚动) + // 危险插件确认对话框 const dangerConfirmDialog = ref(false); const selectedDangerPlugin = ref(null); @@ -68,8 +72,11 @@ const upload_file = ref(null); const uploadTab = ref('file'); const showPluginFullName = ref(false); const marketSearch = ref(""); +const debouncedMarketSearch = ref(""); const filterKeys = ['name', 'desc', 'author']; const refreshingMarket = ref(false); +const sortBy = ref('default'); // default, stars, author, updated +const sortOrder = ref('desc'); // desc (降序) or asc (升序) // 插件市场拼音搜索 const normalizeStr = (s) => (s ?? '').toString().toLowerCase().trim(); @@ -153,6 +160,71 @@ const pinnedPlugins = computed(() => { return pluginMarketData.value.filter(plugin => plugin?.pinned); }); +// 过滤后的插件市场数据(带搜索) +const filteredMarketPlugins = computed(() => { + if (!debouncedMarketSearch.value) { + return pluginMarketData.value; + } + + const search = debouncedMarketSearch.value.toLowerCase(); + return pluginMarketData.value.filter(plugin => { + // 使用自定义过滤器 + return marketCustomFilter(plugin.name, search, plugin) || + marketCustomFilter(plugin.desc, search, plugin) || + marketCustomFilter(plugin.author, search, plugin); + }); +}); + +// 所有插件列表,推荐插件排在前面 +const sortedPlugins = computed(() => { + let plugins = [...filteredMarketPlugins.value]; + + // 根据排序选项排序 + if (sortBy.value === 'stars') { + // 按 star 数排序 + plugins.sort((a, b) => { + const starsA = a.stars ?? 0; + const starsB = b.stars ?? 0; + return sortOrder.value === 'desc' ? starsB - starsA : starsA - starsB; + }); + } else if (sortBy.value === 'author') { + // 按作者名字典序排序 + plugins.sort((a, b) => { + const authorA = (a.author ?? '').toLowerCase(); + const authorB = (b.author ?? '').toLowerCase(); + const result = authorA.localeCompare(authorB); + return sortOrder.value === 'desc' ? -result : result; + }); + } else if (sortBy.value === 'updated') { + // 按更新时间排序 + plugins.sort((a, b) => { + const dateA = a.updated_at ? new Date(a.updated_at).getTime() : 0; + const dateB = b.updated_at ? new Date(b.updated_at).getTime() : 0; + return sortOrder.value === 'desc' ? dateB - dateA : dateA - dateB; + }); + } else { + // default: 推荐插件排在前面 + const pinned = plugins.filter(plugin => plugin?.pinned); + const notPinned = plugins.filter(plugin => !plugin?.pinned); + return [...pinned, ...notPinned]; + } + + return plugins; +}); + +// 分页计算属性 +const displayItemsPerPage = 9; // 固定每页显示6个卡片(2行) + +const totalPages = computed(() => { + return Math.ceil(sortedPlugins.value.length / displayItemsPerPage); +}); + +const paginatedPlugins = computed(() => { + const start = (currentPage.value - 1) * displayItemsPerPage; + const end = start + displayItemsPerPage; + return sortedPlugins.value.slice(start, end); +}); + // 方法 const toggleShowReserved = () => { showReserved.value = !showReserved.value; @@ -534,6 +606,7 @@ const refreshPluginMarket = async () => { trimExtensionName(); checkAlreadyInstalled(); checkUpdate(); + currentPage.value = 1; // 重置到第一页 toast(tm('messages.refreshSuccess'), "success"); } catch (err) { @@ -575,6 +648,20 @@ onMounted(async () => { } }); +// 搜索防抖处理 +let searchDebounceTimer = null; +watch(marketSearch, (newVal) => { + if (searchDebounceTimer) { + clearTimeout(searchDebounceTimer); + } + + searchDebounceTimer = setTimeout(() => { + debouncedMarketSearch.value = newVal; + // 搜索时重置到第一页 + currentPage.value = 1; + }, 300); // 300ms 防抖延迟 +}); + @@ -786,10 +873,12 @@ onMounted(async () => { - - @@ -809,85 +898,158 @@ onMounted(async () => { @click="dialog = true" color="darkprimary"> -
-

{{ tm('market.recommended') }}

- - - - - - -
-
-
-

{{ tm('market.allPlugins') }}

-
- +
+
+

{{ tm('market.allPlugins') }}({{ filteredMarketPlugins.length }})

+ mdi-refresh - {{ tm('buttons.refresh') }} - +
+ +
+ + + + + + + + + + {{ sortOrder === 'desc' ? 'mdi-sort-descending' : 'mdi-sort-ascending' + }} + + {{ sortOrder === 'desc' ? tm('sort.descending') : tm('sort.ascending') }} + + +
- - - - - - - - - - - +
+ + +
+ {{ plugin.desc }} +
+ + +
+
+ + {{ plugin.stars }} +
+
+ + {{ new Date(plugin.updated_at).toLocaleString() }} +
+
+
+ + + + + + {{ tag === 'danger' ? tm('tags.danger') : tag }} + + + + + + + {{ tag === 'danger' ? tm('tags.danger') : tag }} + + + + + + + + 仓库 + + + {{ tm('buttons.install') }} + + + ✓ {{ tm('status.installed') }} + + + + + + + +
+ +
@@ -900,7 +1062,7 @@ onMounted(async () => {
- + {{ tm('market.devDocs') }} | {{ tm('market.submitRepo') }} @@ -997,10 +1159,7 @@ onMounted(async () => { :repo-url="readmeDialog.repoUrl" /> - +