关键改动: - 增加需求排序和版本只读状态规则及测试 - 完善版本概览阶段耗时、项目页和工作台展示 - 优化小宝预警请求节流、建议状态和风险过滤 Co-Authored-By: Codex GPT-5 <codex@openai.com>
135 lines
4.9 KiB
TypeScript
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,
|
|
};
|
|
}
|