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

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

---

## 🔴 问题根源

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

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

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

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

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

**旧逻辑** (错误):
```typescript
// ❌ 只从项目中提取设计师
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方法内）

**修改内容**:

```typescript
// ✅ 获取所有真实设计师（优先使用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方法

**代码示例**:

```typescript
// 在组长端调用
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中的实现** (已有):

```typescript
// 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表):
   ```javascript
   // 应该有至少3个组员
   设计师1: { name: '张三', roleName: '组员' }
   设计师2: { name: '李四', roleName: '组员' }
   设计师3: { name: '王五', roleName: '组员' }
   ```

   **项目数据** (Project表):
   ```javascript
   项目1: { title: '项目A', assignee: 指向张三 }
   项目2: { title: '项目B', assignee: 指向张三 }
   项目3: { title: '项目C', assignee: 指向李四 }
   项目4: { title: '项目D', assignee: null }  // 未分配
   ```

2. **访问组长端Dashboard**
   ```
   http://localhost:4200/team-leader/dashboard
   ```

3. **查看工作量负载概览图**

   **预期显示**:
   ```
   张三 (2个项目) 🔥  ← 有项目，显示项目数
   李四 (1个项目) ✓   ← 有项目，显示项目数
   王五 (0个项目) ○   ← 无项目，也显示
   ```

   **不应显示**:
   ```
   ❌ 未分配 (1个项目)  ← 不应该出现
   ```

4. **验证控制台日志**
   ```javascript
   ✅ 使用真实设计师列表: 3 人
   ✅ 加载设计师数据成功: 3 人
   ✅ 加载真实项目数据成功: 4 个项目
   ```

5. **测试项目分配**
   
   **在浏览器控制台执行**:
   ```javascript
   // 获取组件实例
   const dashboard = angular.element(document.querySelector('app-dashboard')).scope();
   
   // 分配项目D给王五
   await dashboard.designerService.assignProject('项目D的ID', '王五的ID');
   
   // 刷新页面
   location.reload();
   ```

   **预期结果**:
   - 项目D的负责人从"未分配"变为"王五"
   - 甘特图中王五显示 (1个项目)

---

## 📋 数据库检查清单

### 检查Profile表

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

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

### 检查Project表

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

-- 预期：未分配的项目列表
```

### 修复未分配的项目

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

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

---

## 🎯 核心改进

### 1. 数据源优化

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

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

### 2. 过滤逻辑

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

### 3. 降级策略

```typescript
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<Profile> (负责人)
   - `status`: 项目状态
   - `company`: 公司ID
   - `isDeleted`: 软删除标记

---

## 🎉 总结

### 修改前的问题

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

### 修改后的效果

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

### 解决路径

1. **短期**：修改前端逻辑（本次修改）
   - 使用真实设计师列表
   - 过滤"未分配"

2. **长期**：数据质量保证
   - 新项目创建时必须分配设计师
   - 使用智能推荐功能
   - 定期检查未分配项目

---

**修复完成！** ✨

现在刷新浏览器，应该能看到：
1. 所有真实组员都显示在甘特图中
2. 不再显示"未分配"
3. 可以清楚看到谁有空闲



