Files
ftb-project-management/apps/web/hooks/useXiaobaoWarningRisks.ts
Script Generator eef3c8f000 feat(版本): 优化概览与只读状态
关键改动:

- 增加需求排序和版本只读状态规则及测试

- 完善版本概览阶段耗时、项目页和工作台展示

- 优化小宝预警请求节流、建议状态和风险过滤

Co-Authored-By: Codex GPT-5 <codex@openai.com>
2026-06-30 18:18:18 +08:00

135 lines
4.9 KiB
TypeScript

'use client';
import { useEffect, useMemo, useState } from 'react';
import { useHasPermission } from '@/components/auth/Guard';
import { useAuthStore } from '@/stores/useAuthStore';
import { useBugStore } from '@/stores/useBugStore';
import { useDevTaskStore } from '@/stores/useDevTaskStore';
import { useProductStore } from '@/stores/useProductStore';
import { useRequirementStore } from '@/stores/useRequirementStore';
import { useTaskWorklogStore } from '@/stores/useTaskWorklogStore';
import { useTestCaseStore } from '@/stores/useTestCaseStore';
import { useVersionPlanStore } from '@/stores/useVersionPlanStore';
import { useWorkActivityStore } from '@/stores/useWorkActivityStore';
import { useXiaobaoRiskStore } from '@/stores/useXiaobaoRiskStore';
import { flattenVersions } from '@/lib/derive';
import { calcXiaobaoVersionRisk } from '@/lib/xiaobao-risk';
import { buildVersionDailyEvidence, buildXiaobaoWorkItems } from '@/lib/xiaobao-risk-evidence';
import { filterXiaobaoWarningVersions } from '@/lib/xiaobao-warning-view';
export function useXiaobaoWarningRisks({ loadRiskCache = false }: { loadRiskCache?: boolean } = {}) {
const canManage = useHasPermission('xiaobao.warning:manage');
const user = useAuthStore((s) => s.user);
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 { activities, fetchActivities } = useWorkActivityStore();
const { worklogs, fetchWorklogs } = useTaskWorklogStore();
const {
snapshots,
insights,
pendingInsightKeys,
insightRequestAttempts,
riskDataLoaded,
fetchRiskData,
saveSnapshot,
saveInsight,
beginInsightUpdate,
finishInsightUpdate,
} = useXiaobaoRiskStore();
const [calculationNow] = useState(() => new Date());
const today = useMemo(() => new Date().toISOString().slice(0, 10), []);
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 (loadRiskCache) fetchRiskData();
}, [fetchRiskData, loadRiskCache]);
const allVersions = useMemo(() => flattenVersions(overview), [overview]);
const visibleVersions = useMemo(
() => filterXiaobaoWarningVersions(allVersions, { canManage, userName: user?.name }),
[allVersions, canManage, user?.name],
);
const requirementVersionMap = useMemo(() => {
const map = new Map<string, string>();
requirements.forEach((requirement) => {
if (requirement.versionId) map.set(requirement.id, requirement.versionId);
});
return map;
}, [requirements]);
const workItems = useMemo(() => buildXiaobaoWorkItems({
plans,
devTasks,
testCases,
bugs,
versions: allVersions.map((version) => ({
id: version.id,
name: version.name,
productName: version.productName,
projectName: version.projectName,
})),
requirementVersionMap,
}), [allVersions, bugs, devTasks, plans, requirementVersionMap, testCases]);
const risks = useMemo(() => visibleVersions.map((version) => {
const versionRequirements = requirements.filter((requirement) => requirement.versionId === version.id);
const requirementIds = new Set(versionRequirements.map((requirement) => requirement.id));
const dailyEvidence = buildVersionDailyEvidence({
versionId: version.id,
workItems,
activities,
worklogs,
});
return calcXiaobaoVersionRisk({
version,
devTasks: devTasks.filter((task) => requirementIds.has(task.requirementId)),
testCases: testCases.filter((testCase) => testCase.versionId === version.id),
bugs: bugs.filter((bug) => bug.versionId === version.id),
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,
bugs,
devTasks,
requirements,
testCases,
visibleVersions,
workItems,
worklogs,
snapshots,
today,
calculationNow,
]);
return {
risks,
snapshots,
insights,
pendingInsightKeys,
insightRequestAttempts,
riskDataLoaded,
saveSnapshot,
saveInsight,
beginInsightUpdate,
finishInsightUpdate,
today,
};
}