refactor(data): 收口关系表运行时数据源
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:
2026-07-09 14:59:49 +08:00
parent 1e6fb0c7aa
commit 2e595c7e72
98 changed files with 2938 additions and 1441 deletions

View File

@@ -1,11 +1,10 @@
'use client';
import { RouteGuard } from '@/components/auth/Guard';
import { useEffect, useMemo, useState } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import {
Search,
Plus,
Lightbulb,
ArrowUp,
ArrowDown,
ChevronDown,
@@ -42,7 +41,6 @@ import { getRequirementVersionSelectionPatch } from '@/lib/requirement-version-l
import { Pagination } from '@/components/Pagination';
import { RequirementModal } from '@/components/requirement/RequirementModal';
import { RequirementDetail } from '@/components/requirement/RequirementDetail';
import { DictDrawer, SourceDrawer } from '@/components/requirement/DictDrawer';
import { FilterSelect } from '@/components/FilterSelect';
import { buildV22RequirementQuery } from '@/lib/requirement-v22-query';
import { loadV22RequirementsPage } from '@/lib/v22-api';
@@ -199,9 +197,6 @@ function RequirementsPageContent() {
const {
requirements, fetchRequirements, createRequirement, updateRequirement, deleteRequirement,
sourceTargets, types, platforms,
addSourceTarget, updateSourceTarget, deleteSourceTarget,
addType, updateType, deleteType,
addPlatform, updatePlatform, deletePlatform,
loaded: requirementsLoaded,
} = useRequirementStore();
const { overview, fetchOverview } = useProductStore();
@@ -233,7 +228,6 @@ function RequirementsPageContent() {
const [showModal, setShowModal] = useState(false);
const [editingReq, setEditingReq] = useState<Requirement | null>(null);
const [viewingReq, setViewingReq] = useState<Requirement | null>(null);
const [drawerType, setDrawerType] = useState<null | 'source' | 'type' | 'platform'>(null);
const [rejectingReq, setRejectingReq] = useState<Requirement | null>(null);
const [rejectReason, setRejectReason] = useState('');
const [dateSort, setDateSort] = useState<RequirementDateSort>('desc');
@@ -274,6 +268,23 @@ function RequirementsPageContent() {
if (selectedScope.type === 'project') return allVersions.filter((v) => v.projectId === selectedScope.projectId);
return allVersions;
}, [allVersions, selectedScope]);
const hydrateRequirementStoreFallback = useCallback(async () => {
const pendingLoads: Array<Promise<void>> = [];
if (selectedScope.type === 'product') {
pendingLoads.push(fetchRequirements({ productId: selectedScope.productId }));
} else if (selectedScope.type === 'project') {
const project = allProjects.find((item) => item.id === selectedScope.projectId);
if (project) pendingLoads.push(fetchRequirements({ productId: project.productId, projectId: selectedScope.projectId }));
} else {
for (const product of overview) {
pendingLoads.push(fetchRequirements({ productId: product.id }));
}
}
for (const version of scopedVersions) {
pendingLoads.push(fetchDevTasks({ versionId: version.id }));
}
await Promise.all(pendingLoads);
}, [allProjects, fetchDevTasks, fetchRequirements, overview, scopedVersions, selectedScope]);
const filterResetKey = useMemo(() => JSON.stringify({
selectedScopeKey,
@@ -319,9 +330,8 @@ function RequirementsPageContent() {
useEffect(() => {
if (v22RequirementQuery && !v22RequirementsFailed) return;
fetchRequirements();
fetchDevTasks();
}, [fetchDevTasks, fetchRequirements, v22RequirementQuery, v22RequirementsFailed]);
void hydrateRequirementStoreFallback();
}, [hydrateRequirementStoreFallback, v22RequirementQuery, v22RequirementsFailed]);
useEffect(() => {
setV22RequirementsFailed(false);
@@ -354,8 +364,7 @@ function RequirementsPageContent() {
setV22Requirements([]);
setV22NextCursor(undefined);
setV22RequirementsFailed(true);
fetchRequirements();
fetchDevTasks();
void hydrateRequirementStoreFallback();
})
.finally(() => {
if (!cancelled) setV22RequirementsLoading(false);
@@ -364,7 +373,7 @@ function RequirementsPageContent() {
return () => {
cancelled = true;
};
}, [fetchDevTasks, fetchRequirements, page, v22RequirementQuery]);
}, [hydrateRequirementStoreFallback, page, v22RequirementQuery]);
const selectedScopeTitle = useMemo(() => {
if (selectedScope.type === 'product') {
@@ -472,7 +481,7 @@ function RequirementsPageContent() {
};
const handleCreate = async () => {
await fetchRequirements();
await hydrateRequirementStoreFallback();
setEditingReq(null);
setShowModal(true);
};
@@ -480,10 +489,6 @@ function RequirementsPageContent() {
const handleSelectScope = (scope: RequirementScopeSelection) => {
setAutoScopeSelected(true);
setSelectedScope(scope);
if (scope.type === 'all') {
fetchRequirements();
fetchDevTasks();
}
};
return (
@@ -552,13 +557,6 @@ function RequirementsPageContent() {
<p className="mt-0.5 text-[11px] text-[var(--ink-muted)]">{selectedScopeMeta}</p>
</div>
<div className="flex items-center gap-2">
<button
onClick={() => { fetchRequirements(); setDrawerType('source'); }}
className="flex h-8 items-center gap-1.5 rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[13px] font-medium text-[var(--ink-soft)] hover:border-[var(--accent)] hover:text-[var(--accent)] transition-colors"
>
<Lightbulb className="h-3.5 w-3.5" strokeWidth={2} />
</button>
<button
onClick={handleCreate}
className="flex h-8 items-center gap-1.5 rounded-lg bg-[var(--accent)] px-3 text-[13px] font-medium text-white shadow-[var(--shadow-sm)] hover:bg-[var(--accent-hover)] transition-colors"
@@ -888,41 +886,6 @@ function RequirementsPageContent() {
setShowModal(false);
setEditingReq(null);
}}
onOpenDrawer={(type) => setDrawerType(type)}
/>
)}
{/* Drawer */}
{drawerType === 'source' && (
<SourceDrawer
open={true}
items={sourceTargets}
onClose={() => setDrawerType(null)}
onAdd={addSourceTarget}
onUpdate={updateSourceTarget}
onDelete={deleteSourceTarget}
/>
)}
{drawerType === 'type' && (
<DictDrawer
open={true}
title="需求类型管理"
items={types}
onClose={() => setDrawerType(null)}
onAdd={addType}
onUpdate={updateType}
onDelete={deleteType}
/>
)}
{drawerType === 'platform' && (
<DictDrawer
open={true}
title="支持端管理"
items={platforms}
onClose={() => setDrawerType(null)}
onAdd={addPlatform}
onUpdate={updatePlatform}
onDelete={deletePlatform}
/>
)}