diff --git a/src/api/types.ts b/src/api/types.ts index 9e1fa848..6b4a3b1f 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -1839,6 +1839,10 @@ export interface RecognitionCacheData { recognized: number // 未识别数量 unrecognized: number + // 共享识别成功命中数量 + shared_recognized: number + // 是否开启共享识别 + shared_recognize_enabled: boolean // 缓存数据 data: RecognitionCacheItem[] } diff --git a/src/components/cache/RecognitionCachePanel.vue b/src/components/cache/RecognitionCachePanel.vue index ec275cf8..012b2a62 100644 --- a/src/components/cache/RecognitionCachePanel.vue +++ b/src/components/cache/RecognitionCachePanel.vue @@ -45,6 +45,8 @@ const cacheData = ref({ count: 0, recognized: 0, unrecognized: 0, + shared_recognized: 0, + shared_recognize_enabled: false, data: [], }) const mobileVisibleCount = ref(MOBILE_CACHE_PAGE_SIZE) @@ -111,9 +113,18 @@ async function loadCacheData(showSuccess = false) { loading.value = true const response = (await api.get(recognitionCacheEndpoint.value)) as unknown as ApiResponse if (requestId !== cacheLoadRequestId) return - const responseData = response.data ?? { count: 0, recognized: 0, unrecognized: 0, data: [] } + const responseData = response.data ?? { + count: 0, + recognized: 0, + unrecognized: 0, + shared_recognized: 0, + shared_recognize_enabled: false, + data: [], + } cacheData.value = { ...responseData, + shared_recognized: responseData.shared_recognized ?? 0, + shared_recognize_enabled: responseData.shared_recognize_enabled ?? false, data: responseData.data.map(item => ({ ...item, recognition_id: getRecognitionId(item) })), } selectedItems.value = selectedItems.value.filter(key => cacheData.value.data.some(item => item.key === key)) @@ -276,13 +287,20 @@ watch(recognitionSource, () => { {{ t('setting.cache.recognized') }} -
+
{{ cacheData.unrecognized }} {{ t('setting.cache.unrecognized') }}
+
+ +
+ {{ cacheData.shared_recognized }} + {{ t('setting.cache.sharedRecognized') }} +
+
@@ -550,6 +568,10 @@ watch(recognitionSource, () => { color: rgb(var(--v-theme-warning)); } +.cache-panel-stat--info { + color: rgb(var(--v-theme-info)); +} + .cache-panel-actions { display: flex; flex: 0 0 auto; diff --git a/src/components/cache/__tests__/RecognitionCachePanel.spec.ts b/src/components/cache/__tests__/RecognitionCachePanel.spec.ts new file mode 100644 index 00000000..5650ac4a --- /dev/null +++ b/src/components/cache/__tests__/RecognitionCachePanel.spec.ts @@ -0,0 +1,82 @@ +import RecognitionCachePanel from '@/components/cache/RecognitionCachePanel.vue' +import { screen, waitFor } from '@testing-library/vue' +import { renderWithProviders } from '@tests/support/render' +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const mocks = vi.hoisted(() => ({ + apiGet: vi.fn(), + toastError: vi.fn(), + toastSuccess: vi.fn(), +})) + +vi.mock('@/api', () => ({ + default: { + get: mocks.apiGet, + }, +})) + +vi.mock('vue-toastification', () => ({ + useToast: () => ({ + error: mocks.toastError, + success: mocks.toastSuccess, + }), +})) + +async function renderRecognitionCachePanel() { + return renderWithProviders(RecognitionCachePanel, { + initialState: { + globalSettings: { + data: { + GLOBAL_IMAGE_CACHE: false, + RECOGNIZE_SOURCE: 'themoviedb', + TMDB_IMAGE_DOMAIN: 'image.tmdb.org', + }, + }, + }, + }) +} + +describe('RecognitionCachePanel shared recognition statistics', () => { + beforeEach(() => { + mocks.apiGet.mockReset() + mocks.toastError.mockReset() + mocks.toastSuccess.mockReset() + }) + + it('shows the persisted shared recognition count when sharing is enabled', async () => { + mocks.apiGet.mockResolvedValue({ + data: { + count: 12, + recognized: 9, + unrecognized: 3, + shared_recognized: 27, + shared_recognize_enabled: true, + data: [], + }, + }) + + await renderRecognitionCachePanel() + + expect(await screen.findByText('共享识别')).toBeInTheDocument() + expect(screen.getByText('27')).toBeInTheDocument() + expect(screen.getByText('未识别')).toBeInTheDocument() + }) + + it('hides shared recognition statistics when sharing is disabled', async () => { + mocks.apiGet.mockResolvedValue({ + data: { + count: 12, + recognized: 9, + unrecognized: 3, + shared_recognized: 27, + shared_recognize_enabled: false, + data: [], + }, + }) + + await renderRecognitionCachePanel() + await waitFor(() => expect(mocks.apiGet).toHaveBeenCalledWith('tmdb/cache')) + + expect(screen.queryByText('共享识别')).not.toBeInTheDocument() + }) +}) diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index e8a14459..4909958a 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -2536,6 +2536,7 @@ export default { totalCount: 'Total Count', siteCount: 'Site Count', recognized: 'Recognized', + sharedRecognized: 'Shared Recognition', recognizedOnly: 'Recognized Only', unrecognizedOnly: 'Unrecognized Only', allStatuses: 'All Statuses', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 2ffec864..42209740 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -2485,6 +2485,7 @@ export default { totalCount: '总条数', siteCount: '站点数', recognized: '已识别', + sharedRecognized: '共享识别', recognizedOnly: '仅已识别', unrecognizedOnly: '仅未识别', allStatuses: '全部状态', diff --git a/src/locales/zh-TW.ts b/src/locales/zh-TW.ts index 02e9f145..cc2ad155 100644 --- a/src/locales/zh-TW.ts +++ b/src/locales/zh-TW.ts @@ -2484,6 +2484,7 @@ export default { totalCount: '總條數', siteCount: '站點數', recognized: '已識別', + sharedRecognized: '共享識別', recognizedOnly: '僅已識別', unrecognizedOnly: '僅未識別', allStatuses: '全部狀態',