diff --git a/frontend/admin-web/src/views/app-versions/AppVersionManagementPage.tsx b/frontend/admin-web/src/views/app-versions/AppVersionManagementPage.tsx index 5d72ac1..5367105 100644 --- a/frontend/admin-web/src/views/app-versions/AppVersionManagementPage.tsx +++ b/frontend/admin-web/src/views/app-versions/AppVersionManagementPage.tsx @@ -2,12 +2,17 @@ // ============================================================ // Presentation — App Version Management Page -// Clean Architecture: 纯表现层,只读 Redux/Zustand 状态,调用 Use Cases -// 不直接使用 HttpClient / apiClient / fetch +// 严格四层 Clean Architecture: +// Domain → Infrastructure → Application(Use Cases) → Presentation +// +// 本文件只做声明式渲染: +// - Redux (version.slice) → 全局 UI 状态(tab/filter/modal 开关) +// - Zustand (upload.store) → 上传表单临时状态 +// - Custom Hooks → 桥接 Application 层(数据/副作用) +// - 零直接 HTTP 调用,零 Use Case 直接调用 // ============================================================ import React, { useState } from 'react'; -import { useQuery, useQueryClient } from '@tanstack/react-query'; import { t } from '@/i18n/locales'; import { useAppDispatch, useAppSelector } from '@/store'; import { @@ -16,14 +21,10 @@ import { openEditModal, closeEditModal, } from '@/store/slices/version.slice'; import { useUploadStore } from '@/store/zustand/upload.store'; -import { - listVersionsUseCase, - parsePackageUseCase, - uploadVersionUseCase, - updateVersionUseCase, - toggleVersionUseCase, - deleteVersionUseCase, -} from '@/application/use-cases/version.use-cases'; +import { updateVersionUseCase } from '@/application/use-cases/version.use-cases'; +import { useVersionList } from './hooks/use-version-list'; +import { useVersionMutations } from './hooks/use-version-mutations'; +import { useUpload } from './hooks/use-upload'; import type { AppVersion, AppType, AppPlatform } from '@/domain/entities'; import type { UpdateVersionInput } from '@/domain/repositories/version.repository.interface'; @@ -84,7 +85,6 @@ const labelStyle: React.CSSProperties = { function formatFileSize(bytes: string | number | null | undefined): string { const n = typeof bytes === 'string' ? parseInt(bytes, 10) : (bytes ?? 0); if (!n || isNaN(n)) return '-'; - if (n < 1024) return `${n} B`; if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`; if (n < 1024 * 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MB`; return `${(n / (1024 * 1024 * 1024)).toFixed(2)} GB`; @@ -98,45 +98,28 @@ function formatDate(iso: string | null | undefined): string { }); } -/* ── Query key factory ── */ -const versionKeys = { - list: (appType: AppType, platform: AppPlatform | '') => - ['versions', appType, platform] as const, -}; - -/* ── Main Page ── */ +/* ── Main Page — 纯声明式,无业务逻辑 ── */ export const AppVersionManagementPage: React.FC = () => { const dispatch = useAppDispatch(); const { appType, platformFilter, showUpload, editingVersionId } = useAppSelector((s) => s.versions); - const queryClient = useQueryClient(); - const { data: versions, isLoading, error } = useQuery({ - queryKey: versionKeys.list(appType, platformFilter), - queryFn: () => listVersionsUseCase.execute(appType, platformFilter as AppPlatform | undefined), - staleTime: 30_000, - }); + // Data hook (React Query + Use Case) + const { data: versions, isLoading, error, invalidate } = + useVersionList(appType, platformFilter); - const invalidate = () => - queryClient.invalidateQueries({ queryKey: ['versions', appType] }); + // Mutation hooks + const { toggle, remove } = useVersionMutations(invalidate); - const handleToggle = async (v: AppVersion) => { - await toggleVersionUseCase.execute(v.id, !v.isEnabled); - invalidate(); - }; - - const handleDelete = async (v: AppVersion) => { - if (!confirm(t('app_version_confirm_delete'))) return; - await deleteVersionUseCase.execute(v.id); - invalidate(); - }; - - const list = Array.isArray(versions) ? versions : []; - const editingVersion = editingVersionId ? list.find((v) => v.id === editingVersionId) ?? null : null; + const list = versions ?? []; + const editingVersion = editingVersionId + ? list.find((v) => v.id === editingVersionId) ?? null + : null; return (