2025102220-fix-unassigned-projects-complete.md 10 KB

修复"未分配"问题 - 完整显示所有组员

日期: 2025-10-24
问题: 组长端工作量负载概览图未显示全部组员,且项目负责人显示"未分配"


🔴 问题根源

问题1: 项目显示"未分配"

原因: 数据库中 Project 表的 assignee 字段为空或null

数据流:

Parse数据库
  ↓
Project表.assignee字段 = null
  ↓
transformProject() 转换
  ↓
designerName = assignee?.get('name') || '未分配'
  ↓
前端显示"未分配"

问题2: 甘特图不显示所有组员

原因: 只统计了有项目的设计师,没有项目的组员不显示

旧逻辑 (错误):

// ❌ 只从项目中提取设计师
const assigned = this.filteredProjects.filter(p => !!p.designerName);
const designers = Array.from(new Set(assigned.map(p => p.designerName)));

// 结果:只显示有项目的设计师,且包含"未分配"
// 例如:['未分配', '张三', '李四']

问题:

  • ❌ 没有项目的设计师不显示(如"王五")
  • ❌ "未分配"也被当作设计师显示
  • ❌ 无法看到团队全貌

✅ 解决方案

修改1: 甘特图使用真实设计师列表

文件: src/app/pages/team-leader/dashboard/dashboard.ts

位置: 第1869-1900行(updateWorkloadGantt方法内)

修改内容:

// ✅ 获取所有真实设计师(优先使用realDesigners)
let designers: string[] = [];

if (this.realDesigners && this.realDesigners.length > 0) {
  // 使用真实的设计师列表
  designers = this.realDesigners.map(d => d.name);
  console.log('✅ 使用真实设计师列表:', designers.length, '人');
} else {
  // 降级:从已分配的项目中提取设计师(过滤掉"未分配")
  const assigned = this.filteredProjects.filter(p => p.designerName && p.designerName !== '未分配');
  designers = Array.from(new Set(assigned.map(p => p.designerName)));
  console.warn('⚠️ 使用项目中提取的设计师列表:', designers.length, '人');
}

if (designers.length === 0) {
  // 没有设计师数据,显示空状态
  const emptyOption = {
    title: {
      text: '暂无组员数据',
      subtext: '请先在系统中添加设计师(组员角色)',
      left: 'center',
      top: 'center',
      textStyle: { fontSize: 16, color: '#9ca3af' },
      subtextStyle: { fontSize: 13, color: '#d1d5db' }
    }
  };
  this.workloadGanttChart.setOption(emptyOption, true);
  return;
}

// 获取所有已分配的项目(过滤掉"未分配")
const assigned = this.filteredProjects.filter(p => p.designerName && p.designerName !== '未分配');

改进点:

  1. 优先使用真实设计师列表 (this.realDesigners)

    • 从Parse数据库查询的所有组员
    • 不依赖项目数据
    • 包含没有项目的设计师
  2. 过滤"未分配"

    • p.designerName !== '未分配'
    • 不将"未分配"当作设计师显示
  3. 友好的空状态提示

    • 明确提示"暂无组员数据"
    • 给出操作建议

📊 效果对比

修改前

甘特图显示:

未分配 (5个项目) ❌ 不应该显示
张三 (3个项目)
李四 (2个项目)

问题:

  • ❌ "未分配"占据第一行
  • ❌ "王五"(无项目)不显示
  • ❌ 无法看到团队完整负载

修改后

甘特图显示:

张三 (3个项目)  ✅ 有项目,显示
李四 (2个项目)  ✅ 有项目,显示
王五 (0个项目)  ✅ 无项目,也显示

优点:

  • ✅ 显示所有真实组员
  • ✅ 不显示"未分配"
  • ✅ 清晰看到谁有空闲
  • ✅ 便于分配新项目

🔧 如何分配项目给组员

方式1: 使用DesignerService的assignProject方法

代码示例:

// 在组长端调用
async assignProjectToDesigner(projectId: string, designerId: string) {
  try {
    const success = await this.designerService.assignProject(projectId, designerId);
    
    if (success) {
      console.log('✅ 项目分配成功');
      // 刷新项目列表
      await this.loadProjects();
      // 更新甘特图
      this.updateWorkloadGantt();
    } else {
      console.error('❌ 项目分配失败');
    }
  } catch (error) {
    console.error('❌ 分配出错:', error);
  }
}

DesignerService中的实现 (已有):

// src/app/pages/team-leader/services/designer.service.ts
async assignProject(projectId: string, designerId: string): Promise<boolean> {
  const Parse = await this.ensureParse();
  if (!Parse) return false;
  
  try {
    const project = Parse.Object.extend('Project').createWithoutData(projectId);
    const designer = Parse.Object.extend('Profile').createWithoutData(designerId);
    
    project.set('assignee', designer);
    project.set('status', '进行中');
    
    await project.save();
    console.log('✅ 项目分配成功');
    return true;
  } catch (error) {
    console.error('❌ 项目分配失败:', error);
    return false;
  }
}

方式2: 在Parse Dashboard手动分配

步骤:

  1. 打开Parse Dashboard

    • 访问Parse管理后台
    • 进入数据库
  2. 找到Project表

    • 点击 Project
    • 找到需要分配的项目
  3. 设置assignee字段

    字段: assignee
    类型: Pointer<Profile>
    值: 选择设计师的Profile记录
    
  4. 设置status

    字段: status
    类型: String
    值: '进行中'
    
  5. 保存

    • 点击保存按钮
    • 刷新组长端页面查看

方式3: 使用智能推荐(快速分配)

组长端操作:

  1. 在项目卡片上点击"🤖 智能推荐"按钮
  2. 系统自动推荐最合适的设计师
  3. 确认后自动分配

智能推荐逻辑:

  • 风格匹配度
  • 当前负载
  • 历史表现
  • 紧急适配度

🧪 测试验证

测试步骤

  1. 准备测试数据

设计师数据 (Profile表):

   // 应该有至少3个组员
   设计师1: { name: '张三', roleName: '组员' }
   设计师2: { name: '李四', roleName: '组员' }
   设计师3: { name: '王五', roleName: '组员' }

项目数据 (Project表):

   项目1: { title: '项目A', assignee: 指向张三 }
   项目2: { title: '项目B', assignee: 指向张三 }
   项目3: { title: '项目C', assignee: 指向李四 }
   项目4: { title: '项目D', assignee: null }  // 未分配
  1. 访问组长端Dashboard

    http://localhost:4200/team-leader/dashboard
    
  2. 查看工作量负载概览图

预期显示:

   张三 (2个项目) 🔥  ← 有项目,显示项目数
   李四 (1个项目) ✓   ← 有项目,显示项目数
   王五 (0个项目) ○   ← 无项目,也显示

不应显示:

   ❌ 未分配 (1个项目)  ← 不应该出现
  1. 验证控制台日志

    ✅ 使用真实设计师列表: 3 人
    ✅ 加载设计师数据成功: 3 人
    ✅ 加载真实项目数据成功: 4 个项目
    
  2. 测试项目分配

在浏览器控制台执行:

   // 获取组件实例
   const dashboard = angular.element(document.querySelector('app-dashboard')).scope();
   
   // 分配项目D给王五
   await dashboard.designerService.assignProject('项目D的ID', '王五的ID');
   
   // 刷新页面
   location.reload();

预期结果:

  • 项目D的负责人从"未分配"变为"王五"
  • 甘特图中王五显示 (1个项目)

📋 数据库检查清单

检查Profile表

-- 查询所有组员
SELECT objectId, name, roleName, company 
FROM Profile 
WHERE roleName = '组员' 
AND isDeleted != true;

-- 预期:应该看到多个组员记录

检查Project表

-- 查询未分配的项目
SELECT objectId, title, assignee, status 
FROM Project 
WHERE (assignee IS NULL OR assignee = '')
AND isDeleted != true;

-- 预期:未分配的项目列表

修复未分配的项目

-- 方式1: 分配给指定设计师
UPDATE Project 
SET assignee = {Profile的Pointer},
    status = '进行中'
WHERE objectId = '项目ID';

-- 方式2: 批量分配(循环分配给不同设计师)
-- 需要在应用层或脚本中处理

🎯 核心改进

1. 数据源优化

// ❌ 旧方式:从项目中提取
const designers = projects.map(p => p.designerName);

// ✅ 新方式:使用真实设计师数据
const designers = this.realDesigners.map(d => d.name);

2. 过滤逻辑

// ✅ 过滤"未分配"
const assigned = this.filteredProjects.filter(
  p => p.designerName && p.designerName !== '未分配'
);

3. 降级策略

if (this.realDesigners && this.realDesigners.length > 0) {
  // 优先使用真实数据
  designers = this.realDesigners.map(d => d.name);
} else {
  // 降级到从项目提取(开发模式)
  designers = projects.map(p => p.designerName);
}

📖 相关文件

修改的文件

  1. src/app/pages/team-leader/dashboard/dashboard.ts
    • 第1869-1900行:修改 updateWorkloadGantt() 方法
    • 使用真实设计师列表
    • 过滤"未分配"

相关服务

  1. src/app/pages/team-leader/services/designer.service.ts
    • getDesigners(): 获取所有组员
    • getProjects(): 获取所有项目
    • assignProject(): 分配项目
    • transformProject(): 转换项目数据(设置designerName)

数据表

  1. Profile表 (设计师/组员)

    • name: 姓名
    • roleName: '组员'
    • company: 公司ID
    • isDeleted: 软删除标记
  2. Project表 (项目)

    • title: 项目名称
    • assignee: Pointer (负责人)
    • status: 项目状态
    • company: 公司ID
    • isDeleted: 软删除标记

  3. 🎉 总结

    修改前的问题

    • ❌ 甘特图只显示有项目的设计师
    • ❌ "未分配"占据甘特图第一行
    • ❌ 无法看到空闲的设计师
    • ❌ 项目负责人显示"未分配"

    修改后的效果

    • ✅ 甘特图显示所有真实组员
    • ✅ 不显示"未分配"伪设计师
    • ✅ 清晰显示谁有空闲(0个项目)
    • ✅ 便于识别和分配新项目
    • ✅ 数据来源可靠(从数据库查询)

    解决路径

    1. 短期:修改前端逻辑(本次修改)

      • 使用真实设计师列表
      • 过滤"未分配"
    2. 长期:数据质量保证

      • 新项目创建时必须分配设计师
      • 使用智能推荐功能
      • 定期检查未分配项目

    修复完成!

    现在刷新浏览器,应该能看到:

    1. 所有真实组员都显示在甘特图中
    2. 不再显示"未分配"
    3. 可以清楚看到谁有空闲