设计师组分配弹窗(@designer-team-assignment-modal)中,所有成员显示的项目数量都是 0,即使这些设计师实际上手上有项目。
通过详细的代码分析和对比团队组长端(@team-leader/dashboard)的实现,发现了以下几个关键问题:
teamQuery.containedIn('profile', profilePointers) 限制查询范围
ProjectTeam 记录profilePointers 中的 ID 与数据库中的 profile.id 不匹配,会查不到数据profile 范围ProjectTeam 记录团队组长端:
ProjectTeam 表查询项目ProjectTeam 表为空,降级到使用 Project.assignee 字段设计师分配弹窗(修复前):
ProjectTeam + Project.assignee)isActiveProject() 过滤器,过滤掉了很多项目已完成、已交付、已取消、已归档 等状态delivery、已完成 等阶段isActiveProject() 方法排除了大量状态和阶段:
const excludedStatuses = new Set(['已完成','已交付','已取消','已归档','归档','archived','cancelled','canceled','done','delivered']);
const excludedStages = new Set(['delivery','已完成']);
这导致很多实际存在的项目被过滤掉,显示项目数为 0。
在使用 Project.assignee 作为降级方案时,修复前的代码没有检查 assignee.roleName === '组员',可能统计了组长或其他角色的项目。
// ❌ 修复前:限制查询范围
const Profile = Parse.Object.extend('Profile');
const profilePointers = allMembers.map(m => {
const p = new Profile();
p.id = m.id;
return p;
});
teamQuery.containedIn('profile', profilePointers); // ❌ 查询范围过窄
// ✅ 修复后:查询所有公司的 ProjectTeam(对齐组长端)
const teamQuery = new Parse.Query('ProjectTeam');
teamQuery.matchesQuery('project', companyProjectQuery);
// ✅ 不限制 profile 范围,后续在代码中筛选
// ❌ 修复前:使用 isActiveProject 过滤
if (!this.isActiveProject(project)) {
filteredOutCount++;
console.log(` ⏭️ 已过滤非活跃项目...`);
} else {
// 添加到 profileIdToProjects
}
// ✅ 修复后:统计所有项目,不过滤
const arr = profileIdToProjects.get(profile.id) || [];
arr.push(project);
profileIdToProjects.set(profile.id, arr);
// ✅ 修复后:只统计组员角色的项目
const assigneeRole = assignee.get('roleName');
if (assigneeRole === '组员') {
const arr = profileIdToProjects.get(assignee.id) || [];
arr.push(project);
profileIdToProjects.set(assignee.id, arr);
} else {
nonMemberRoleCount++;
console.log(` ⏭️ 跳过非组员角色的项目 (角色: ${assigneeRole || '未知'})`)
}
ProjectTeam 表Project.assigneeconsole.log('📊 [项目数据加载] 统计结果:', {
'数据源': teamRecords.length > 0 ? 'ProjectTeam 表' : 'Project 表(降级)',
'总记录数': teamRecords.length > 0 ? teamRecords.length : projects.length,
'缺少assignee': noAssigneeCount,
'非组员角色': nonMemberRoleCount, // 新增
'有效项目数': Array.from(profileIdToProjects.values()).reduce((sum, arr) => sum + arr.length, 0)
});
在 showDesignerEmployeeDetail() 方法中,也移除了 isActiveProject 过滤:
// ❌ 修复前
const projects = allProjects.filter(p => this.isActiveProject(p));
// ✅ 修复后
const projects = allProjects;
yss-project/src/app/pages/designer/project-detail/components/designer-team-assignment-modal/designer-team-assignment-modal.component.tsenrichMembersWithProjectAssignments() 方法 (约 line 477-870)
teamQuery.containedIn('profile', profilePointers) 限制(line 500-524)isActiveProject 过滤(line 665-672, 698-709)showDesignerEmployeeDetail() 方法 (约 line 1290-1450)
isActiveProject 过滤(line 1373-1376)保留了详细的彩色控制台日志:
测试步骤:
1. 打开订单分配阶段的任意项目
2. 点击"添加协作成员"按钮
3. 观察设计师列表中每个成员的项目数量
4. 查看控制台输出的详细日志
预期结果:
- 每个设计师显示的项目数应该是他们手上所有项目(不过滤状态)
- 项目数 = 0:显示绿色(空闲)
- 项目数 1-5:显示橙色(有项目)
- 项目数 > 5:显示红色(繁忙)
测试场景 A:ProjectTeam 表有数据
- 预期:控制台显示"使用 ProjectTeam 表数据"
- 验证:项目数量与 ProjectTeam 表记录一致
测试场景 B:ProjectTeam 表为空
- 预期:控制台显示"ProjectTeam 表为空,使用 Project.assignee 作为降级方案"
- 验证:项目数量与 Project.assignee 字段一致(仅统计组员角色)
测试步骤:
1. 第一次打开弹窗(冷加载)
2. 关闭弹窗
3. 30秒内再次打开弹窗(使用缓存)
4. 等待 30 秒后再次打开(缓存过期)
预期结果:
- 第一次:显示完整查询日志
- 30秒内:显示"⚡ [使用缓存]"日志
- 30秒后:再次显示完整查询日志
测试步骤:
1. 在设计师列表中点击任意设计师的名字
2. 查看右侧员工详情面板
3. 验证显示的项目数量和日历数据
预期结果:
- 项目数量应与列表中显示的一致
- 日历应显示所有项目的时间线
- 控制台应输出详细的项目列表
修复后的设计师分配弹窗现在完全对齐团队组长端(@team-leader/dashboard)的以下行为:
ProjectTeam → Project.assigneeroleName === '组员' 的项目Map<profileId, projects[]> 聚合数据❓ 为什么要统计已完成的项目?
❓ 项目数量会不会太多?
loadDesignerWorkload() 方法enrichMembersWithProjectAssignments() 方法考虑在后端提供一个聚合 API:
GET /api/designer-workload?companyId=xxx&includeCompleted=false
本次修复通过完全对齐团队组长端的逻辑,解决了设计师分配弹窗项目数量显示为 0 的问题。
ProjectTeam 查询的 profile 限制(最关键)
containedIn('profile', profilePointers) 导致查询范围过窄ProjectTeam,与团队组长端一致isActiveProject() 过滤项目roleName === '组员' 的项目修复后的代码保留了详细的调试日志,方便后续排查问题和验证数据来源。同时,30秒缓存机制确保了良好的用户体验。