Propagate plugin rating updates and preserve rating snapshots

This commit is contained in:
jxxghp
2026-08-04 13:39:27 +08:00
parent b4afba99bd
commit 2728896a1e
7 changed files with 175 additions and 38 deletions
+3 -2
View File
@@ -2,7 +2,7 @@
import { useToast } from 'vue-toastification'
import { useConfirm } from '@/composables/useConfirm'
import api from '@/api'
import type { ApiResponse, Plugin } from '@/api/types'
import type { ApiResponse, Plugin, PluginRating } from '@/api/types'
import { getLogoUrl } from '@/utils/imageUtils'
import { getCardAccentRgbFromImage } from '@/composables/useCardAccentColor'
import { formatDownloadCount } from '@/@core/utils/formatters'
@@ -34,7 +34,7 @@ const props = defineProps({
})
// 定义触发的自定义事件
const emit = defineEmits(['remove', 'save', 'actionDone'])
const emit = defineEmits(['remove', 'save', 'actionDone', 'rating'])
// 多语言
const { t } = useI18n()
@@ -392,6 +392,7 @@ async function showPluginAbout() {
// 详情弹窗的安装事件只刷新父列表,动态导航由卡片补充同步。
void pluginSidebarNavStore.ensureSidebarNav(true)
},
rating: (pluginRating: PluginRating) => emit('rating', pluginRating),
},
{ closeOn: ['close', 'install', 'update:modelValue'] },
)
@@ -1,4 +1,5 @@
<script lang="ts" setup>
import type { PluginRating } from '@/api/types'
import PluginCard from './PluginCard.vue'
import PluginFolderCard from './PluginFolderCard.vue'
@@ -30,6 +31,7 @@ const emit = defineEmits<{
renameFolder: [oldName: string, newName: string]
updateFolderConfig: [folderName: string, config: any]
refreshData: []
rating: [pluginRating: PluginRating]
actionDone: [pluginId: string]
removeFromFolder: [pluginId: string]
dropToFolder: [event: DragEvent, folderName: string]
@@ -108,6 +110,7 @@ function handleDropToFolder(event: DragEvent) {
:sortable="sortable"
@remove="$emit('refreshData')"
@save="$emit('refreshData')"
@rating="$emit('rating', $event)"
@action-done="$emit('actionDone', item.id)"
/>
@@ -82,7 +82,17 @@ describe('PluginCard about menu', () => {
expect(mocks.openSharedDialog.mock.calls[0][3]).toEqual({
closeOn: ['close', 'install', 'update:modelValue'],
})
const dialogEvents = mocks.openSharedDialog.mock.calls[0][2] as { install: () => void }
const dialogEvents = mocks.openSharedDialog.mock.calls[0][2] as {
install: () => void
rating: (pluginRating: { plugin_id: string; average_rating: number; rating_count: number }) => void
}
dialogEvents.rating({ plugin_id: 'DemoPlugin', average_rating: 4.5, rating_count: 13 })
expect(emitted().rating).toContainEqual([
expect.objectContaining({ plugin_id: 'DemoPlugin', average_rating: 4.5, rating_count: 13 }),
])
expect(emitted()).not.toHaveProperty('save')
expect(sidebarStore.ensureSidebarNav).not.toHaveBeenCalled()
dialogEvents.install()
expect(emitted().save).toHaveLength(1)
expect(sidebarStore.ensureSidebarNav).toHaveBeenCalledWith(true)