Skip to content

Commit e413a00

Browse files
authored
perf: list view mode toggle with localStorage support in ExtensionPage (#4288)
closes: #4253
1 parent 6437d75 commit e413a00

1 file changed

Lines changed: 32 additions & 30 deletions

File tree

dashboard/src/views/ExtensionPage.vue

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,19 @@ const readmeDialog = reactive({
7878
});
7979
8080
// 新增变量支持列表视图
81-
const isListView = ref(false);
81+
// 从 localStorage 恢复显示模式,默认为 false(卡片视图)
82+
const getInitialListViewMode = () => {
83+
if (typeof window !== 'undefined' && window.localStorage) {
84+
return localStorage.getItem('pluginListViewMode') === 'true';
85+
}
86+
return false;
87+
};
88+
const isListView = ref(getInitialListViewMode());
8289
const pluginSearch = ref("");
8390
const loading_ = ref(false);
8491
8592
// 分页相关
8693
const currentPage = ref(1);
87-
const itemsPerPage = ref(6); // 每页显示6个卡片 (2行 x 3列,避免滚动)
8894
8995
// 危险插件确认对话框
9096
const dangerConfirmDialog = ref(false);
@@ -113,7 +119,6 @@ const uploadTab = ref('file');
113119
const showPluginFullName = ref(false);
114120
const marketSearch = ref("");
115121
const debouncedMarketSearch = ref("");
116-
const filterKeys = ['name', 'desc', 'author'];
117122
const refreshingMarket = ref(false);
118123
const sortBy = ref('default'); // default, stars, author, updated
119124
const sortOrder = ref('desc'); // desc (降序) or asc (升序)
@@ -162,18 +167,6 @@ const pluginHeaders = computed(() => [
162167
]);
163168
164169
165-
// 插件市场表头
166-
const pluginMarketHeaders = computed(() => [
167-
{ title: tm('table.headers.name'), key: 'name', maxWidth: '200px' },
168-
{ title: tm('table.headers.description'), key: 'desc', maxWidth: '250px' },
169-
{ title: tm('table.headers.author'), key: 'author', maxWidth: '90px' },
170-
{ title: tm('table.headers.stars'), key: 'stars', maxWidth: '80px' },
171-
{ title: tm('table.headers.lastUpdate'), key: 'updated_at', maxWidth: '100px' },
172-
{ title: tm('table.headers.tags'), key: 'tags', maxWidth: '100px' },
173-
{ title: tm('table.headers.actions'), key: 'actions', sortable: false }
174-
]);
175-
176-
177170
// 过滤要显示的插件
178171
const filteredExtensions = computed(() => {
179172
const data = Array.isArray(extension_data?.data) ? extension_data.data : [];
@@ -197,9 +190,6 @@ const filteredPlugins = computed(() => {
197190
});
198191
});
199192
200-
const pinnedPlugins = computed(() => {
201-
return pluginMarketData.value.filter(plugin => plugin?.pinned);
202-
});
203193
204194
// 过滤后的插件市场数据(带搜索)
205195
const filteredMarketPlugins = computed(() => {
@@ -552,14 +542,6 @@ const viewReadme = (plugin) => {
552542
readmeDialog.show = true;
553543
};
554544
555-
556-
557-
const open = (link) => {
558-
if (link) {
559-
window.open(link, '_blank');
560-
}
561-
};
562-
563545
// 为表格视图创建一个处理安装插件的函数
564546
const handleInstallPlugin = async (plugin) => {
565547
if (plugin.tags && plugin.tags.includes('danger')) {
@@ -918,6 +900,13 @@ watch(marketSearch, (newVal) => {
918900
}, 300); // 300ms 防抖延迟
919901
});
920902
903+
// 监听显示模式变化并保存到 localStorage
904+
watch(isListView, (newVal) => {
905+
if (typeof window !== 'undefined' && window.localStorage) {
906+
localStorage.setItem('pluginListViewMode', String(newVal));
907+
}
908+
});
909+
921910
922911
</script>
923912
@@ -1037,8 +1026,21 @@ watch(marketSearch, (newVal) => {
10371026
10381027
<template v-slot:item.name="{ item }">
10391028
<div class="d-flex align-center py-2">
1029+
<div v-if="item.logo" class="mr-3" style="flex-shrink: 0;">
1030+
<img :src="item.logo" :alt="item.name"
1031+
style="height: 40px; width: 40px; border-radius: 8px; object-fit: cover;" />
1032+
</div>
1033+
<div v-else class="mr-3" style="flex-shrink: 0;">
1034+
<img :src="defaultPluginIcon" :alt="item.name"
1035+
style="height: 40px; width: 40px; border-radius: 8px; object-fit: cover;" />
1036+
</div>
10401037
<div>
1041-
<div class="text-subtitle-1 font-weight-medium">{{ item.name }}</div>
1038+
<div class="text-subtitle-1 font-weight-medium">
1039+
{{ item.display_name && item.display_name.length ? item.display_name : item.name }}
1040+
</div>
1041+
<div v-if="item.display_name && item.display_name.length" class="text-caption text-medium-emphasis mt-1">
1042+
{{ item.name }}
1043+
</div>
10421044
<div v-if="item.reserved" class="d-flex align-center mt-1">
10431045
<v-chip color="primary" size="x-small" class="font-weight-medium">{{ tm('status.system')
10441046
}}</v-chip>
@@ -1048,7 +1050,7 @@ watch(marketSearch, (newVal) => {
10481050
</template>
10491051
10501052
<template v-slot:item.desc="{ item }">
1051-
<div class="text-body-2 text-medium-emphasis">{{ item.desc }}</div>
1053+
<div class="text-body-2 text-medium-emphasis mt-2 mb-2" style="display: -webkit-box; -webkit-line-clamp: 3; line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis;">{{ item.desc }}</div>
10521054
</template>
10531055
10541056
<template v-slot:item.version="{ item }">
@@ -1084,7 +1086,7 @@ watch(marketSearch, (newVal) => {
10841086
<v-tooltip activator="parent" location="top">{{ tm('tooltips.disable') }}</v-tooltip>
10851087
</v-btn>
10861088
1087-
<v-btn icon size="small" color="info" @click="reloadPlugin(item.name)">
1089+
<v-btn icon size="small" @click="reloadPlugin(item.name)">
10881090
<v-icon>mdi-refresh</v-icon>
10891091
<v-tooltip activator="parent" location="top">{{ tm('tooltips.reload') }}</v-tooltip>
10901092
</v-btn>
@@ -1104,7 +1106,7 @@ watch(marketSearch, (newVal) => {
11041106
<v-tooltip activator="parent" location="top">{{ tm('tooltips.viewDocs') }}</v-tooltip>
11051107
</v-btn>
11061108
1107-
<v-btn icon size="small" color="warning" @click="updateExtension(item.name)"
1109+
<v-btn icon size="small" @click="updateExtension(item.name)"
11081110
:v-show="item.has_update">
11091111
<v-icon>mdi-update</v-icon>
11101112
<v-tooltip activator="parent" location="top">{{ tm('tooltips.update') }}</v-tooltip>

0 commit comments

Comments
 (0)