refactor(data): 收口关系表运行时数据源
Some checks failed
Deploy Production / Build, push, deploy, verify (push) Has been cancelled
Some checks failed
Deploy Production / Build, push, deploy, verify (push) Has been cancelled
- 移除已迁移业务 AppData 运行时 fallback,改走领域 API 和关系表快读 - 补齐需求产品负责人、版本计划任务 JSON 和成员 username 回填迁移 - 统一治理字典入口,并补充 AI provider、数据源契约和领域服务测试 Co-Authored-By: Codex GPT-5 <codex@openai.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useMemo, useState, type FormEvent } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState, type FormEvent } from 'react';
|
||||
import { useParams, useRouter } from 'next/navigation';
|
||||
import { AlertTriangle, Calendar, Check, ChevronLeft, Clock, FileText, Link2, Pencil, Search, Settings, Sparkles, UserPlus, X } from 'lucide-react';
|
||||
import { useProductStore } from '@/stores/useProductStore';
|
||||
@@ -142,6 +142,7 @@ export default function VersionDetailPage() {
|
||||
() => allMembers.map((member) => ({
|
||||
id: member.id,
|
||||
name: member.name,
|
||||
username: member.username,
|
||||
departmentName: departments.find((department) => department.id === member.departmentId)?.name,
|
||||
})),
|
||||
[allMembers, departments],
|
||||
@@ -163,6 +164,12 @@ export default function VersionDetailPage() {
|
||||
const [showAnalysisDrawer, setShowAnalysisDrawer] = useState(false);
|
||||
const [recommendationDataReady, setRecommendationDataReady] = useState(false);
|
||||
const [v22Scope, setV22Scope] = useState<VersionDataScope | null>(null);
|
||||
const version = useMemo(() => getVersionDetail(overview, versionId), [overview, versionId]);
|
||||
const fetchScopedRequirements = useCallback((force = false) => {
|
||||
if (!version) return Promise.resolve();
|
||||
if (force) return fetchRequirements({ productId: version.productId, versionId, force: true });
|
||||
return fetchRequirements({ productId: version.productId, versionId });
|
||||
}, [fetchRequirements, version, versionId]);
|
||||
|
||||
useEffect(() => { fetchOverview(); }, [fetchOverview]);
|
||||
useEffect(() => {
|
||||
@@ -182,43 +189,44 @@ export default function VersionDetailPage() {
|
||||
fetchRecords();
|
||||
return;
|
||||
}
|
||||
if (!version) return;
|
||||
if (activeTab === 'requirements') {
|
||||
fetchRequirements();
|
||||
fetchDevTasks();
|
||||
fetchScopedRequirements();
|
||||
fetchDevTasks({ versionId });
|
||||
return;
|
||||
}
|
||||
if (activeTab === 'research' || activeTab === 'product' || activeTab === 'ui') {
|
||||
fetchRequirements();
|
||||
fetchPlans();
|
||||
fetchScopedRequirements();
|
||||
fetchPlans({ versionId });
|
||||
return;
|
||||
}
|
||||
if (activeTab === 'tasks') {
|
||||
fetchRequirements();
|
||||
fetchDevTasks();
|
||||
fetchScopedRequirements();
|
||||
fetchDevTasks({ versionId });
|
||||
return;
|
||||
}
|
||||
if (activeTab === 'testcases') {
|
||||
fetchRequirements();
|
||||
fetchDevTasks();
|
||||
fetchTestCases();
|
||||
fetchBugs();
|
||||
fetchScopedRequirements();
|
||||
fetchDevTasks({ versionId });
|
||||
fetchTestCases({ versionId });
|
||||
fetchBugs({ versionId });
|
||||
return;
|
||||
}
|
||||
if (activeTab === 'bugs') {
|
||||
fetchRequirements();
|
||||
fetchTestCases();
|
||||
fetchBugs();
|
||||
fetchScopedRequirements();
|
||||
fetchTestCases({ versionId });
|
||||
fetchBugs({ versionId });
|
||||
}
|
||||
}, [activeTab, fetchBugs, fetchDevTasks, fetchPlans, fetchRecords, fetchRequirements, fetchTestCases]);
|
||||
}, [activeTab, fetchBugs, fetchDevTasks, fetchPlans, fetchRecords, fetchScopedRequirements, fetchTestCases, version, versionId]);
|
||||
useEffect(() => {
|
||||
if (!showRecommendModal) return;
|
||||
fetchRecords();
|
||||
fetchRequirements();
|
||||
fetchPlans();
|
||||
fetchDevTasks();
|
||||
fetchTestCases();
|
||||
fetchBugs();
|
||||
}, [fetchBugs, fetchDevTasks, fetchPlans, fetchRecords, fetchRequirements, fetchTestCases, showRecommendModal]);
|
||||
fetchScopedRequirements(true);
|
||||
fetchPlans({ versionId });
|
||||
fetchDevTasks({ versionId });
|
||||
fetchTestCases({ versionId });
|
||||
fetchBugs({ versionId });
|
||||
}, [fetchBugs, fetchDevTasks, fetchPlans, fetchRecords, fetchScopedRequirements, fetchTestCases, showRecommendModal, versionId]);
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
setRecommendationDataReady(false);
|
||||
@@ -228,8 +236,7 @@ export default function VersionDetailPage() {
|
||||
return () => { active = false; };
|
||||
}, [fetchMembers, fetchCategories]);
|
||||
|
||||
const version = useMemo(() => getVersionDetail(overview, versionId), [overview, versionId]);
|
||||
const appDataVersionScope = useMemo(
|
||||
const storeVersionScope = useMemo(
|
||||
() => version
|
||||
? buildVersionDataScope({
|
||||
versionId: version.id,
|
||||
@@ -250,19 +257,20 @@ export default function VersionDetailPage() {
|
||||
const testCaseWriteReady = requirementsLoaded && devTasksLoaded && testCasesLoaded && bugsLoaded;
|
||||
const bugWriteReady = requirementsLoaded && testCasesLoaded && bugsLoaded;
|
||||
const loadAllVersionStores = () => {
|
||||
if (!version) return;
|
||||
fetchRecords();
|
||||
fetchRequirements();
|
||||
fetchPlans();
|
||||
fetchDevTasks();
|
||||
fetchTestCases();
|
||||
fetchBugs();
|
||||
fetchRequirements({ productId: version.productId, versionId, force: true });
|
||||
fetchPlans({ versionId });
|
||||
fetchDevTasks({ versionId });
|
||||
fetchTestCases({ versionId });
|
||||
fetchBugs({ versionId });
|
||||
};
|
||||
const versionScope = useMemo(
|
||||
() => selectVersionDataScope({
|
||||
appDataScope: appDataVersionScope,
|
||||
v22Scope: versionWriteStoresReady ? null : v22Scope,
|
||||
storeScope: storeVersionScope,
|
||||
v22Scope,
|
||||
}),
|
||||
[appDataVersionScope, v22Scope, versionWriteStoresReady],
|
||||
[storeVersionScope, v22Scope],
|
||||
);
|
||||
const releaseProgress = versionScope
|
||||
? calcScopedVersionProgress(versionScope.plans, versionScope.devTasks, versionScope.testCases)
|
||||
@@ -327,15 +335,12 @@ export default function VersionDetailPage() {
|
||||
.some((permission) => canWriteVersionPermission(permission));
|
||||
|
||||
const scopedVersionData = versionScope!;
|
||||
const appDataScopedVersionData = appDataVersionScope ?? scopedVersionData;
|
||||
const displayRequirements = requirementsLoaded ? requirements : scopedVersionData.requirements;
|
||||
const displayPlans = plansLoaded ? appDataScopedVersionData.plans : scopedVersionData.plans;
|
||||
const displayDevTasks = devTasksLoaded ? appDataScopedVersionData.devTasks : scopedVersionData.devTasks;
|
||||
const displayTestCases = testCasesLoaded ? appDataScopedVersionData.testCases : scopedVersionData.testCases;
|
||||
const displayBugs = bugsLoaded ? appDataScopedVersionData.bugs : scopedVersionData.bugs;
|
||||
const displayRequirementIds = requirementsLoaded
|
||||
? appDataScopedVersionData.requirementIds
|
||||
: scopedVersionData.requirementIds;
|
||||
const displayRequirements = scopedVersionData.requirements;
|
||||
const displayPlans = scopedVersionData.plans;
|
||||
const displayDevTasks = scopedVersionData.devTasks;
|
||||
const displayTestCases = scopedVersionData.testCases;
|
||||
const displayBugs = scopedVersionData.bugs;
|
||||
const displayRequirementIds = scopedVersionData.requirementIds;
|
||||
const memberRecommendationGroups = showRecommendModal && recommendationDataReady ? (() => {
|
||||
const currentSystemParticipation = new Map<string, number>();
|
||||
overview.forEach((product) => {
|
||||
@@ -1066,8 +1071,10 @@ export default function VersionDetailPage() {
|
||||
version={version}
|
||||
versionDeadline={version.expectedReleaseDate ?? undefined}
|
||||
currentUserName={user?.name ?? ''}
|
||||
currentUserReference={user?.username ?? user?.id ?? user?.name ?? ''}
|
||||
planType={pt}
|
||||
versionMembers={version.members ?? []}
|
||||
allMembers={memberCandidates}
|
||||
linkedRequirements={versionLinkedReqs}
|
||||
allRequirements={displayRequirements}
|
||||
readOnly={versionReadonly || !planWriteReady || !canWriteVersionPermission(PLAN_MANAGE_PERMISSION[pt])}
|
||||
|
||||
@@ -94,16 +94,9 @@ function VersionsPageContent() {
|
||||
useEffect(() => { fetchOverview(); }, [fetchOverview]);
|
||||
|
||||
const { requirements, fetchRequirements, updateRequirement } = useRequirementStore();
|
||||
useEffect(() => { fetchRequirements(); }, [fetchRequirements]);
|
||||
|
||||
const { plans, fetchPlans } = useVersionPlanStore();
|
||||
useEffect(() => { fetchPlans(); }, [fetchPlans]);
|
||||
|
||||
const { tasks: devTasks, fetchTasks: fetchDevTasks } = useDevTaskStore();
|
||||
useEffect(() => { fetchDevTasks(); }, [fetchDevTasks]);
|
||||
|
||||
const { testCases, fetchTestCases } = useTestCaseStore();
|
||||
useEffect(() => { fetchTestCases(); }, [fetchTestCases]);
|
||||
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const currentUserName = user?.name || '';
|
||||
@@ -125,6 +118,14 @@ function VersionsPageContent() {
|
||||
if (!v.members || v.members.length === 0) return true;
|
||||
return v.members.some((m) => m.name === currentUserName);
|
||||
}), [allVersionsRaw, currentUserName, isSuperAdmin]);
|
||||
useEffect(() => {
|
||||
for (const version of allVersions) {
|
||||
void fetchRequirements({ productId: version.productId, versionId: version.id });
|
||||
void fetchPlans({ versionId: version.id });
|
||||
void fetchDevTasks({ versionId: version.id });
|
||||
void fetchTestCases({ versionId: version.id });
|
||||
}
|
||||
}, [allVersions, fetchDevTasks, fetchPlans, fetchRequirements, fetchTestCases]);
|
||||
const versionTree = useMemo(() => buildVersionScopeTree(allVersions, treeKeyword), [allVersions, treeKeyword]);
|
||||
|
||||
// Compute overall progress per version from actual data
|
||||
|
||||
Reference in New Issue
Block a user