feat(v2.2): 完成高频读取热路径
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Search, FileText, Palette, ClipboardList, Code2, ClipboardCheck, Bug as BugIcon, ExternalLink, CheckCircle2, ChevronRight, ChevronDown, FolderOpen, Layers } from 'lucide-react';
|
||||
import { useProductStore } from '@/stores/useProductStore';
|
||||
@@ -28,6 +28,8 @@ import { TEST_CASE_STATUS_LABEL, TEST_CASE_STATUS_COLOR } from '@/lib/test-case'
|
||||
import { BUG_STATUS_LABEL, BUG_STATUS_COLOR, BUG_SEVERITY_LABEL, BUG_SEVERITY_COLOR } from '@/lib/bug';
|
||||
import { getWorkspaceDailyReport } from '@/lib/workspace-daily-report';
|
||||
import { VERSION_STATUS_BG, VERSION_STATUS_LABEL, getVersionReadonlyNotice, isVersionReadonly, type VersionStatus } from '@/lib/version-status';
|
||||
import { loadV22WorkspaceData, type V22WorkspaceData } from '@/lib/v22-api';
|
||||
import { selectWorkspaceCollections } from '@/lib/workspace-v22-source';
|
||||
|
||||
type TabKey = 'all' | 'plan_research' | 'plan_product' | 'plan_ui' | 'devTask' | 'testCase' | 'bug';
|
||||
type WorkspaceVersionContext = { id: string; name: string; productName: string; projectName: string; status: VersionStatus };
|
||||
@@ -54,11 +56,11 @@ const PLAN_STATUS_LABEL: Record<string, string> = { pending: '未开始', in_pro
|
||||
export default function WorkspacePage() {
|
||||
const router = useRouter();
|
||||
const { overview, fetchOverview } = useProductStore();
|
||||
const { plans, fetchPlans } = useVersionPlanStore();
|
||||
const { requirements, fetchRequirements } = useRequirementStore();
|
||||
const { tasks: devTasks, fetchTasks } = useDevTaskStore();
|
||||
const { testCases, fetchTestCases } = useTestCaseStore();
|
||||
const { bugs, fetchBugs } = useBugStore();
|
||||
const { plans, fetchPlans, loaded: plansLoaded } = useVersionPlanStore();
|
||||
const { requirements, fetchRequirements, loaded: requirementsLoaded } = useRequirementStore();
|
||||
const { tasks: devTasks, fetchTasks, loaded: devTasksLoaded } = useDevTaskStore();
|
||||
const { testCases, fetchTestCases, loaded: testCasesLoaded } = useTestCaseStore();
|
||||
const { bugs, fetchBugs, loaded: bugsLoaded } = useBugStore();
|
||||
const { worklogs, fetchWorklogs } = useTaskWorklogStore();
|
||||
const { activities, fetchActivities } = useWorkActivityStore();
|
||||
const user = useAuthStore((s) => s.user);
|
||||
@@ -67,17 +69,62 @@ export default function WorkspacePage() {
|
||||
const [selectedVersionId, setSelectedVersionId] = useState<string | null>(null);
|
||||
const [drawerItem, setDrawerItem] = useState<WorkItem | null>(null);
|
||||
const [bugFromTestCaseId, setBugFromTestCaseId] = useState<string | null>(null);
|
||||
const [v22WorkspaceData, setV22WorkspaceData] = useState<V22WorkspaceData | null>(null);
|
||||
const [v22WorkspaceLoaded, setV22WorkspaceLoaded] = useState(false);
|
||||
const [v22WorkspaceFailed, setV22WorkspaceFailed] = useState(false);
|
||||
|
||||
useEffect(() => { fetchOverview(); }, [fetchOverview]);
|
||||
useEffect(() => { fetchPlans(); }, [fetchPlans]);
|
||||
useEffect(() => { fetchRequirements(); }, [fetchRequirements]);
|
||||
useEffect(() => { fetchTasks(); }, [fetchTasks]);
|
||||
useEffect(() => { fetchTestCases(); }, [fetchTestCases]);
|
||||
useEffect(() => { fetchBugs(); }, [fetchBugs]);
|
||||
useEffect(() => { fetchWorklogs(); }, [fetchWorklogs]);
|
||||
useEffect(() => { fetchActivities(); }, [fetchActivities]);
|
||||
|
||||
const userName = user?.name ?? '';
|
||||
const workspaceUserKey = userName || user?.id || '';
|
||||
|
||||
useEffect(() => {
|
||||
if (!workspaceUserKey.trim()) {
|
||||
setV22WorkspaceData(null);
|
||||
setV22WorkspaceLoaded(false);
|
||||
setV22WorkspaceFailed(false);
|
||||
return;
|
||||
}
|
||||
|
||||
let cancelled = false;
|
||||
setV22WorkspaceLoaded(false);
|
||||
setV22WorkspaceFailed(false);
|
||||
loadV22WorkspaceData(workspaceUserKey)
|
||||
.then((data) => {
|
||||
if (cancelled) return;
|
||||
setV22WorkspaceData(data);
|
||||
setV22WorkspaceLoaded(true);
|
||||
})
|
||||
.catch(() => {
|
||||
if (cancelled) return;
|
||||
setV22WorkspaceData(null);
|
||||
setV22WorkspaceFailed(true);
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [workspaceUserKey]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!workspaceUserKey.trim() || !v22WorkspaceFailed) return;
|
||||
void fetchPlans();
|
||||
void fetchRequirements();
|
||||
void fetchTasks();
|
||||
void fetchTestCases();
|
||||
void fetchBugs();
|
||||
}, [
|
||||
fetchBugs,
|
||||
fetchPlans,
|
||||
fetchRequirements,
|
||||
fetchTasks,
|
||||
fetchTestCases,
|
||||
v22WorkspaceFailed,
|
||||
workspaceUserKey,
|
||||
]);
|
||||
|
||||
const allVersions = useMemo(() => flattenVersions(overview), [overview]);
|
||||
|
||||
const versionMap = useMemo(() => {
|
||||
@@ -92,9 +139,27 @@ export default function WorkspacePage() {
|
||||
return map;
|
||||
}, [requirements]);
|
||||
|
||||
const workspaceCollections = useMemo(
|
||||
() => selectWorkspaceCollections({
|
||||
v22Loaded: v22WorkspaceLoaded,
|
||||
v22Failed: v22WorkspaceFailed,
|
||||
v22Data: v22WorkspaceData,
|
||||
appData: { plans, devTasks, testCases, bugs },
|
||||
}),
|
||||
[bugs, devTasks, plans, testCases, v22WorkspaceData, v22WorkspaceFailed, v22WorkspaceLoaded],
|
||||
);
|
||||
|
||||
const workItems = useMemo(() =>
|
||||
aggregateWorkItems(userName, plans, devTasks, testCases, bugs, versionMap, requirementVersionMap),
|
||||
[userName, plans, devTasks, testCases, bugs, versionMap, requirementVersionMap]
|
||||
aggregateWorkItems(
|
||||
userName,
|
||||
workspaceCollections.versionPlans,
|
||||
workspaceCollections.devTasks,
|
||||
workspaceCollections.testCases,
|
||||
workspaceCollections.bugs,
|
||||
versionMap,
|
||||
requirementVersionMap,
|
||||
),
|
||||
[userName, workspaceCollections, versionMap, requirementVersionMap]
|
||||
);
|
||||
const pendingCountByVersion = useMemo(() => getWorkspacePendingCountByVersion(workItems), [workItems]);
|
||||
|
||||
@@ -158,6 +223,32 @@ export default function WorkspacePage() {
|
||||
const selectedVersion = selectedVersionId ? versionMap.get(selectedVersionId) : undefined;
|
||||
const drawerVersionStatus = drawerItem ? versionMap.get(drawerItem.versionId)?.status : undefined;
|
||||
const drawerReadOnly = drawerVersionStatus ? isVersionReadonly(drawerVersionStatus) : false;
|
||||
const ensureWorkspaceDrawerStores = useCallback(async (item: WorkItem) => {
|
||||
const pendingLoads: Array<Promise<void>> = [];
|
||||
if (!requirementsLoaded) pendingLoads.push(fetchRequirements());
|
||||
if ((item.type === 'plan_research' || item.type === 'plan_product' || item.type === 'plan_ui') && !plansLoaded) {
|
||||
pendingLoads.push(fetchPlans());
|
||||
}
|
||||
if (item.type === 'devTask' && !devTasksLoaded) pendingLoads.push(fetchTasks());
|
||||
if (item.type === 'testCase' && !testCasesLoaded) pendingLoads.push(fetchTestCases());
|
||||
if (item.type === 'bug' && !bugsLoaded) pendingLoads.push(fetchBugs());
|
||||
await Promise.all(pendingLoads);
|
||||
}, [
|
||||
bugsLoaded,
|
||||
devTasksLoaded,
|
||||
fetchBugs,
|
||||
fetchPlans,
|
||||
fetchRequirements,
|
||||
fetchTasks,
|
||||
fetchTestCases,
|
||||
plansLoaded,
|
||||
requirementsLoaded,
|
||||
testCasesLoaded,
|
||||
]);
|
||||
const openWorkItemDrawer = useCallback(async (item: WorkItem) => {
|
||||
await ensureWorkspaceDrawerStores(item);
|
||||
setDrawerItem(item);
|
||||
}, [ensureWorkspaceDrawerStores]);
|
||||
|
||||
return (
|
||||
<div className="flex h-full">
|
||||
@@ -245,7 +336,7 @@ export default function WorkspacePage() {
|
||||
item={item}
|
||||
versionStatus={versionMap.get(item.versionId)?.status}
|
||||
onNavigate={() => item.versionId && router.push(`/versions/${item.versionId}`)}
|
||||
onClick={() => setDrawerItem(item)}
|
||||
onClick={() => { void openWorkItemDrawer(item); }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user