perf(web): 优化大数据量页面切换与聚合性能

This commit is contained in:
Script Generator
2026-07-03 09:43:36 +08:00
parent 554ab520d1
commit a509bb4922
32 changed files with 1087 additions and 360 deletions

View File

@@ -20,12 +20,20 @@ import { SearchInput, matchTitleOrNo } from '@/components/SearchInput';
import { useDebouncedValue } from '@/hooks/useDebouncedValue';
import { orderByRequirementForGrouping } from '@/lib/requirement-grouping';
import { buildEffortSummaryMetrics, sumPositiveHours } from '@/lib/effort-summary';
import type { Bug } from '@/lib/bug';
import type { DevTask } from '@/lib/dev-task';
import type { Requirement } from '@/lib/requirement';
import type { TestCase } from '@/lib/test-case';
import type { TestCaseStatus } from '@/lib/test-case';
interface Props {
versionId: string;
requirementIds: string[];
readOnly?: boolean;
versionCases?: TestCase[];
versionBugs?: Bug[];
versionDevTasks?: DevTask[];
versionRequirements?: Requirement[];
}
const NO_REQUIREMENT_GROUP_PREFIX = '__no_requirement__';
@@ -38,7 +46,15 @@ function getNoRequirementGroupName(groupKey: string): string {
return groupKey.slice(NO_REQUIREMENT_GROUP_PREFIX.length) || '未命名需求';
}
export function TestCaseTab({ versionId, requirementIds, readOnly = false }: Props) {
export function TestCaseTab({
versionId,
requirementIds,
readOnly = false,
versionCases: scopedVersionCases,
versionBugs: scopedVersionBugs,
versionDevTasks: scopedVersionDevTasks,
versionRequirements,
}: Props) {
const { testCases, fetchTestCases, createTestCases, deleteTestCase } = useTestCaseStore();
const { bugs, fetchBugs } = useBugStore();
const { tasks: devTasks } = useDevTaskStore();
@@ -46,15 +62,20 @@ export function TestCaseTab({ versionId, requirementIds, readOnly = false }: Pro
const user = useAuthStore((s) => s.user);
const { categories, fetchCategories } = useTaskCategoryStore();
useEffect(() => { fetchTestCases(); }, [fetchTestCases]);
useEffect(() => { fetchBugs(); }, [fetchBugs]);
useEffect(() => {
if (!scopedVersionCases) fetchTestCases();
}, [fetchTestCases, scopedVersionCases]);
useEffect(() => {
if (!scopedVersionBugs) fetchBugs();
}, [fetchBugs, scopedVersionBugs]);
useEffect(() => { fetchCategories(); }, [fetchCategories]);
const reqIdSet = useMemo(() => new Set(requirementIds), [requirementIds]);
const versionCases = useMemo(
const fallbackVersionCases = useMemo(
() => testCases.filter((c) => c.versionId === versionId),
[testCases, versionId],
);
const versionCases = scopedVersionCases ?? fallbackVersionCases;
const rounds = useMemo(
() => Array.from(new Set(versionCases.map((testCase) => getTestCaseRoundNo(testCase)))).sort((a, b) => a - b),
[versionCases],
@@ -75,15 +96,17 @@ export function TestCaseTab({ versionId, requirementIds, readOnly = false }: Pro
() => versionCases.filter((testCase) => getTestCaseRoundNo(testCase) === 1),
[versionCases],
);
const versionBugs = useMemo(
const fallbackVersionBugs = useMemo(
() => bugs.filter((bug) => bug.versionId === versionId),
[bugs, versionId],
);
const versionBugs = scopedVersionBugs ?? fallbackVersionBugs;
const versionDevTasks = useMemo(
const fallbackVersionDevTasks = useMemo(
() => devTasks.filter((t) => t.versionId === versionId || (!t.versionId && reqIdSet.has(t.requirementId))),
[devTasks, reqIdSet, versionId],
);
const versionDevTasks = scopedVersionDevTasks ?? fallbackVersionDevTasks;
const stats = calcTestProgress(activeRoundCases, versionBugs);
const { actual: tcActualHours } = aggregateTestCaseHours(versionCases);
@@ -168,7 +191,8 @@ export function TestCaseTab({ versionId, requirementIds, readOnly = false }: Pro
return map;
}, [paged]);
const requirementMap = useMemo(() => new Map(requirements.map((r) => [r.id, r])), [requirements]);
const visibleRequirements = versionRequirements ?? requirements;
const requirementMap = useMemo(() => new Map(visibleRequirements.map((r) => [r.id, r])), [visibleRequirements]);
const categoryMap = useMemo(() => new Map(categories.map((c) => [c.id, c])), [categories]);
const categoryLabelWidthEm = useMemo(
() => Math.max(4, ...categories.map((category) => category.name.length)) + 1,