feat(v2.2): 完成高频读取热路径
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useProductStore } from '@/stores/useProductStore';
|
||||
import { useVersionPlanStore } from '@/stores/useVersionPlanStore';
|
||||
import { useRequirementStore } from '@/stores/useRequirementStore';
|
||||
@@ -10,6 +10,8 @@ import { useBugStore } from '@/stores/useBugStore';
|
||||
import { useAuthStore } from '@/stores/useAuthStore';
|
||||
import { flattenVersions } from '@/lib/derive';
|
||||
import { aggregateWorkItems } from '@/lib/workspace-engine';
|
||||
import { loadV22WorkspaceData, type V22WorkspaceData } from '@/lib/v22-api';
|
||||
import { selectWorkspaceCollections } from '@/lib/workspace-v22-source';
|
||||
|
||||
export function useWorkspaceWorkItems({ autoFetch = true }: { autoFetch?: boolean } = {}) {
|
||||
const { overview, fetchOverview } = useProductStore();
|
||||
@@ -19,15 +21,60 @@ export function useWorkspaceWorkItems({ autoFetch = true }: { autoFetch?: boolea
|
||||
const { testCases, fetchTestCases } = useTestCaseStore();
|
||||
const { bugs, fetchBugs } = useBugStore();
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const [v22WorkspaceData, setV22WorkspaceData] = useState<V22WorkspaceData | null>(null);
|
||||
const [v22WorkspaceLoaded, setV22WorkspaceLoaded] = useState(false);
|
||||
const [v22WorkspaceFailed, setV22WorkspaceFailed] = useState(false);
|
||||
|
||||
useEffect(() => { if (autoFetch) fetchOverview(); }, [autoFetch, fetchOverview]);
|
||||
useEffect(() => { if (autoFetch) fetchPlans(); }, [autoFetch, fetchPlans]);
|
||||
useEffect(() => { if (autoFetch) fetchRequirements(); }, [autoFetch, fetchRequirements]);
|
||||
useEffect(() => { if (autoFetch) fetchTasks(); }, [autoFetch, fetchTasks]);
|
||||
useEffect(() => { if (autoFetch) fetchTestCases(); }, [autoFetch, fetchTestCases]);
|
||||
useEffect(() => { if (autoFetch) fetchBugs(); }, [autoFetch, fetchBugs]);
|
||||
|
||||
const userName = user?.name ?? '';
|
||||
const workspaceUserKey = userName || user?.id || '';
|
||||
useEffect(() => {
|
||||
if (!autoFetch || !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;
|
||||
};
|
||||
}, [autoFetch, workspaceUserKey]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!autoFetch || !workspaceUserKey.trim() || !v22WorkspaceFailed) return;
|
||||
void fetchPlans();
|
||||
void fetchRequirements();
|
||||
void fetchTasks();
|
||||
void fetchTestCases();
|
||||
void fetchBugs();
|
||||
}, [
|
||||
autoFetch,
|
||||
fetchBugs,
|
||||
fetchPlans,
|
||||
fetchRequirements,
|
||||
fetchTasks,
|
||||
fetchTestCases,
|
||||
v22WorkspaceFailed,
|
||||
workspaceUserKey,
|
||||
]);
|
||||
|
||||
const allVersions = useMemo(() => flattenVersions(overview), [overview]);
|
||||
|
||||
const versionMap = useMemo(() => {
|
||||
@@ -51,9 +98,27 @@ export function useWorkspaceWorkItems({ autoFetch = true }: { autoFetch?: boolea
|
||||
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],
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -62,8 +127,8 @@ export function useWorkspaceWorkItems({ autoFetch = true }: { autoFetch?: boolea
|
||||
versionMap,
|
||||
requirementVersionMap,
|
||||
workItems,
|
||||
devTasks,
|
||||
testCases,
|
||||
bugs,
|
||||
devTasks: workspaceCollections.devTasks,
|
||||
testCases: workspaceCollections.testCases,
|
||||
bugs: workspaceCollections.bugs,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,7 +13,14 @@ import { useVersionPlanStore } from '@/stores/useVersionPlanStore';
|
||||
import { useWorkActivityStore } from '@/stores/useWorkActivityStore';
|
||||
import { useXiaobaoRiskStore } from '@/stores/useXiaobaoRiskStore';
|
||||
import { flattenVersions } from '@/lib/derive';
|
||||
import { loadV22XiaobaoWarnings, type V22XiaobaoWarningSummary } from '@/lib/v22-api';
|
||||
import { buildVersionDataScopeMap } from '@/lib/version-data-scope';
|
||||
import {
|
||||
buildXiaobaoRisksFromV22Summaries,
|
||||
filterV22XiaobaoSummariesForVisibleVersions,
|
||||
shouldLoadXiaobaoAppDataFallback,
|
||||
type V22XiaobaoSummaryLoadState,
|
||||
} from '@/lib/xiaobao-v22-summary';
|
||||
import { calcXiaobaoVersionRisk } from '@/lib/xiaobao-risk';
|
||||
import { buildVersionDailyEvidence, buildXiaobaoWorkItems } from '@/lib/xiaobao-risk-evidence';
|
||||
import { filterXiaobaoWarningVersions } from '@/lib/xiaobao-warning-view';
|
||||
@@ -42,16 +49,46 @@ export function useXiaobaoWarningRisks({ loadRiskCache = false }: { loadRiskCach
|
||||
finishInsightUpdate,
|
||||
} = useXiaobaoRiskStore();
|
||||
const [calculationNow] = useState(() => new Date());
|
||||
const [v22SummaryState, setV22SummaryState] = useState<V22XiaobaoSummaryLoadState>('idle');
|
||||
const [v22Summaries, setV22Summaries] = useState<V22XiaobaoWarningSummary[]>([]);
|
||||
const today = useMemo(() => new Date().toISOString().slice(0, 10), []);
|
||||
const v22UserId = user?.name || user?.id || '';
|
||||
const shouldLoadFallback = shouldLoadXiaobaoAppDataFallback(v22SummaryState);
|
||||
|
||||
useEffect(() => { fetchOverview(); }, [fetchOverview]);
|
||||
useEffect(() => { fetchPlans(); }, [fetchPlans]);
|
||||
useEffect(() => { fetchRequirements(); }, [fetchRequirements]);
|
||||
useEffect(() => { fetchTasks(); }, [fetchTasks]);
|
||||
useEffect(() => { fetchTestCases(); }, [fetchTestCases]);
|
||||
useEffect(() => { fetchBugs(); }, [fetchBugs]);
|
||||
useEffect(() => { fetchActivities(); }, [fetchActivities]);
|
||||
useEffect(() => { fetchWorklogs(); }, [fetchWorklogs]);
|
||||
useEffect(() => {
|
||||
if (!canManage && !v22UserId) {
|
||||
setV22SummaryState('idle');
|
||||
setV22Summaries([]);
|
||||
return;
|
||||
}
|
||||
|
||||
let ignore = false;
|
||||
setV22SummaryState('loading');
|
||||
loadV22XiaobaoWarnings({
|
||||
userId: v22UserId || undefined,
|
||||
manager: canManage,
|
||||
}).then((summaries) => {
|
||||
if (ignore) return;
|
||||
setV22Summaries(summaries);
|
||||
setV22SummaryState(summaries.length > 0 ? 'ready' : 'empty');
|
||||
}).catch(() => {
|
||||
if (ignore) return;
|
||||
setV22Summaries([]);
|
||||
setV22SummaryState('failed');
|
||||
});
|
||||
|
||||
return () => {
|
||||
ignore = true;
|
||||
};
|
||||
}, [canManage, v22UserId]);
|
||||
useEffect(() => { if (shouldLoadFallback) fetchPlans(); }, [fetchPlans, shouldLoadFallback]);
|
||||
useEffect(() => { if (shouldLoadFallback) fetchRequirements(); }, [fetchRequirements, shouldLoadFallback]);
|
||||
useEffect(() => { if (shouldLoadFallback) fetchTasks(); }, [fetchTasks, shouldLoadFallback]);
|
||||
useEffect(() => { if (shouldLoadFallback) fetchTestCases(); }, [fetchTestCases, shouldLoadFallback]);
|
||||
useEffect(() => { if (shouldLoadFallback) fetchBugs(); }, [fetchBugs, shouldLoadFallback]);
|
||||
useEffect(() => { if (shouldLoadFallback) fetchActivities(); }, [fetchActivities, shouldLoadFallback]);
|
||||
useEffect(() => { if (shouldLoadFallback) fetchWorklogs(); }, [fetchWorklogs, shouldLoadFallback]);
|
||||
useEffect(() => {
|
||||
if (loadRiskCache) fetchRiskData();
|
||||
}, [fetchRiskData, loadRiskCache]);
|
||||
@@ -93,28 +130,39 @@ export function useXiaobaoWarningRisks({ loadRiskCache = false }: { loadRiskCach
|
||||
return map;
|
||||
}, [visibleVersionScopeMap, visibleVersions]);
|
||||
|
||||
const risks = useMemo(() => visibleVersions.map((version) => {
|
||||
const scope = visibleVersionScopeMap[version.id];
|
||||
const workItems = workItemsByVersion.get(version.id) ?? [];
|
||||
const dailyEvidence = buildVersionDailyEvidence({
|
||||
versionId: version.id,
|
||||
workItems,
|
||||
activities,
|
||||
worklogs,
|
||||
});
|
||||
const risks = useMemo(() => {
|
||||
if (v22SummaryState === 'ready') {
|
||||
return buildXiaobaoRisksFromV22Summaries({
|
||||
summaries: filterV22XiaobaoSummariesForVisibleVersions(v22Summaries, visibleVersions),
|
||||
versions: visibleVersions,
|
||||
snapshots,
|
||||
now: calculationNow,
|
||||
});
|
||||
}
|
||||
|
||||
return calcXiaobaoVersionRisk({
|
||||
version,
|
||||
devTasks: scope?.devTasks ?? [],
|
||||
testCases: scope?.testCases ?? [],
|
||||
bugs: scope?.bugs ?? [],
|
||||
dailyEvidence,
|
||||
recentActivityCount: dailyEvidence.recentActivityCount,
|
||||
lastActivityAt: dailyEvidence.lastActivityAt,
|
||||
snapshots: snapshots.filter((snapshot) => snapshot.versionId === version.id && snapshot.date < today),
|
||||
now: calculationNow,
|
||||
});
|
||||
}).sort((a, b) => b.riskScore - a.riskScore), [
|
||||
return visibleVersions.map((version) => {
|
||||
const scope = visibleVersionScopeMap[version.id];
|
||||
const workItems = workItemsByVersion.get(version.id) ?? [];
|
||||
const dailyEvidence = buildVersionDailyEvidence({
|
||||
versionId: version.id,
|
||||
workItems,
|
||||
activities,
|
||||
worklogs,
|
||||
});
|
||||
|
||||
return calcXiaobaoVersionRisk({
|
||||
version,
|
||||
devTasks: scope?.devTasks ?? [],
|
||||
testCases: scope?.testCases ?? [],
|
||||
bugs: scope?.bugs ?? [],
|
||||
dailyEvidence,
|
||||
recentActivityCount: dailyEvidence.recentActivityCount,
|
||||
lastActivityAt: dailyEvidence.lastActivityAt,
|
||||
snapshots: snapshots.filter((snapshot) => snapshot.versionId === version.id && snapshot.date < today),
|
||||
now: calculationNow,
|
||||
});
|
||||
}).sort((a, b) => b.riskScore - a.riskScore);
|
||||
}, [
|
||||
activities,
|
||||
visibleVersionScopeMap,
|
||||
visibleVersions,
|
||||
@@ -123,6 +171,8 @@ export function useXiaobaoWarningRisks({ loadRiskCache = false }: { loadRiskCach
|
||||
snapshots,
|
||||
today,
|
||||
calculationNow,
|
||||
v22Summaries,
|
||||
v22SummaryState,
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user