fix(workspace): 兼容成员ID匹配与我相关任务

This commit is contained in:
2026-07-06 11:22:43 +08:00
parent 84344e81f6
commit b170ac9caf
4 changed files with 56 additions and 18 deletions

View File

@@ -77,8 +77,10 @@ export default function WorkspacePage() {
useEffect(() => { fetchWorklogs(); }, [fetchWorklogs]); useEffect(() => { fetchWorklogs(); }, [fetchWorklogs]);
useEffect(() => { fetchActivities(); }, [fetchActivities]); useEffect(() => { fetchActivities(); }, [fetchActivities]);
const userId = user?.id ?? '';
const userName = user?.name ?? ''; const userName = user?.name ?? '';
const workspaceUserKey = userName || user?.id || ''; const workspaceUserKey = userId || userName;
const workspaceUserRefs = useMemo(() => [userName, userId].filter(Boolean), [userId, userName]);
useEffect(() => { useEffect(() => {
if (!workspaceUserKey.trim()) { if (!workspaceUserKey.trim()) {
@@ -151,7 +153,7 @@ export default function WorkspacePage() {
const workItems = useMemo(() => const workItems = useMemo(() =>
aggregateWorkItems( aggregateWorkItems(
userName, workspaceUserRefs,
workspaceCollections.versionPlans, workspaceCollections.versionPlans,
workspaceCollections.devTasks, workspaceCollections.devTasks,
workspaceCollections.testCases, workspaceCollections.testCases,
@@ -159,7 +161,7 @@ export default function WorkspacePage() {
versionMap, versionMap,
requirementVersionMap, requirementVersionMap,
), ),
[userName, workspaceCollections, versionMap, requirementVersionMap] [workspaceUserRefs, workspaceCollections, versionMap, requirementVersionMap]
); );
const pendingCountByVersion = useMemo(() => getWorkspacePendingCountByVersion(workItems), [workItems]); const pendingCountByVersion = useMemo(() => getWorkspacePendingCountByVersion(workItems), [workItems]);
@@ -198,10 +200,10 @@ export default function WorkspacePage() {
activities, activities,
worklogs, worklogs,
workItems, workItems,
userId: userName, userId: userName || userId,
date: today, date: today,
}), }),
[activities, worklogs, workItems, userName, today] [activities, userId, worklogs, workItems, userName, today]
); );
// 待办数量按 tab 分(受 version filter 影响) // 待办数量按 tab 分(受 version filter 影响)

View File

@@ -27,8 +27,10 @@ export function useWorkspaceWorkItems({ autoFetch = true }: { autoFetch?: boolea
useEffect(() => { if (autoFetch) fetchOverview(); }, [autoFetch, fetchOverview]); useEffect(() => { if (autoFetch) fetchOverview(); }, [autoFetch, fetchOverview]);
const userId = user?.id ?? '';
const userName = user?.name ?? ''; const userName = user?.name ?? '';
const workspaceUserKey = userName || user?.id || ''; const workspaceUserKey = userId || userName;
const workspaceUserRefs = useMemo(() => [userName, userId].filter(Boolean), [userId, userName]);
useEffect(() => { useEffect(() => {
if (!autoFetch || !workspaceUserKey.trim()) { if (!autoFetch || !workspaceUserKey.trim()) {
setV22WorkspaceData(null); setV22WorkspaceData(null);
@@ -110,7 +112,7 @@ export function useWorkspaceWorkItems({ autoFetch = true }: { autoFetch?: boolea
const workItems = useMemo( const workItems = useMemo(
() => aggregateWorkItems( () => aggregateWorkItems(
userName, workspaceUserRefs,
workspaceCollections.versionPlans, workspaceCollections.versionPlans,
workspaceCollections.devTasks, workspaceCollections.devTasks,
workspaceCollections.testCases, workspaceCollections.testCases,
@@ -118,7 +120,7 @@ export function useWorkspaceWorkItems({ autoFetch = true }: { autoFetch?: boolea
versionMap, versionMap,
requirementVersionMap, requirementVersionMap,
), ),
[userName, workspaceCollections, versionMap, requirementVersionMap], [workspaceUserRefs, workspaceCollections, versionMap, requirementVersionMap],
); );
return { return {

View File

@@ -91,3 +91,30 @@ test('aggregateWorkItems uses direct version id for no-requirement dev tasks', (
assert.equal(items[0].versionId, 'ver-1'); assert.equal(items[0].versionId, 'ver-1');
assert.equal(items[0].versionName, 'V1.0'); assert.equal(items[0].versionName, 'V1.0');
}); });
test('aggregateWorkItems matches V2.2 member ids as current user references', () => {
const items = aggregateWorkItems(
['超级管理员', 'm-8'],
[{
id: 'plan-1',
versionId: 'ver-1',
type: 'product',
title: '案例学习 V1.3 产品方案',
owner: 'm-8',
startTime: '2026-07-06T09:00:00.000Z',
endTime: '2026-07-06T18:00:00.000Z',
status: 'pending',
tasks: [],
createdAt: '2026-07-06T09:00:00.000Z',
} as any],
[],
[],
[],
new Map([['ver-1', { id: 'ver-1', name: '案例学习V1.3', productName: '案例学习', projectName: '案例学习' }]]),
new Map(),
);
assert.equal(items.length, 1);
assert.equal(items[0].type, 'plan_product');
assert.equal(items[0].title, '案例学习 V1.3 产品方案');
});

View File

@@ -28,7 +28,7 @@ interface VersionContext {
} }
export function aggregateWorkItems( export function aggregateWorkItems(
userName: string, userRef: string | string[],
plans: VersionPlan[], plans: VersionPlan[],
devTasks: DevTask[], devTasks: DevTask[],
testCases: TestCase[], testCases: TestCase[],
@@ -37,10 +37,12 @@ export function aggregateWorkItems(
requirementVersionMap: Map<string, string>, requirementVersionMap: Map<string, string>,
): WorkItem[] { ): WorkItem[] {
const items: WorkItem[] = []; const items: WorkItem[] = [];
if (!userName.trim()) return items; const userRefs = normalizeUserRefs(userRef);
if (userRefs.size === 0) return items;
const isCurrentUser = (value?: string | null): boolean => Boolean(value && userRefs.has(value));
// Plans: owner === userName // Plans: owner matches the current user's name or stable member id.
plans.filter((p) => p.owner === userName).forEach((p) => { plans.filter((p) => isCurrentUser(p.owner)).forEach((p) => {
const ver = versionMap.get(p.versionId); const ver = versionMap.get(p.versionId);
items.push({ items.push({
id: p.id, id: p.id,
@@ -57,8 +59,8 @@ export function aggregateWorkItems(
}); });
}); });
// DevTasks: assigneeId === userName // DevTasks: assignee matches the current user's name or stable member id.
devTasks.filter((t) => t.assigneeId === userName).forEach((t) => { devTasks.filter((t) => isCurrentUser(t.assigneeId)).forEach((t) => {
const versionId = t.versionId || requirementVersionMap.get(t.requirementId) || ''; const versionId = t.versionId || requirementVersionMap.get(t.requirementId) || '';
const ver = versionMap.get(versionId); const ver = versionMap.get(versionId);
items.push({ items.push({
@@ -83,8 +85,8 @@ export function aggregateWorkItems(
}); });
}); });
// TestCases: assigneeId === userName // TestCases: assignee matches the current user's name or stable member id.
testCases.filter((c) => c.assigneeId === userName).forEach((c) => { testCases.filter((c) => isCurrentUser(c.assigneeId)).forEach((c) => {
const ver = versionMap.get(c.versionId); const ver = versionMap.get(c.versionId);
items.push({ items.push({
id: c.id, id: c.id,
@@ -102,8 +104,8 @@ export function aggregateWorkItems(
}); });
}); });
// Bugs: assigneeId === userName // Bugs: assignee matches the current user's name or stable member id.
bugs.filter((b) => b.assigneeId === userName).forEach((b) => { bugs.filter((b) => isCurrentUser(b.assigneeId)).forEach((b) => {
const ver = versionMap.get(b.versionId); const ver = versionMap.get(b.versionId);
items.push({ items.push({
id: b.id, id: b.id,
@@ -124,6 +126,11 @@ export function aggregateWorkItems(
return items; return items;
} }
function normalizeUserRefs(userRef: string | string[]): Set<string> {
const refs = Array.isArray(userRef) ? userRef : [userRef];
return new Set(refs.map((ref) => ref.trim()).filter(Boolean));
}
export function getWorkspacePendingCount(items: ReadonlyArray<Pick<WorkItem, 'completed'>>): number { export function getWorkspacePendingCount(items: ReadonlyArray<Pick<WorkItem, 'completed'>>): number {
return items.reduce((sum, item) => sum + (item.completed ? 0 : 1), 0); return items.reduce((sum, item) => sum + (item.completed ? 0 : 1), 0);
} }