# 设计师分配弹窗数据同步问题分析 ## 问题描述 总管理员端的项目管理中,点击"分配设计师"按钮后,设计师的**繁忙情况**和**接单情况**没有显示,与其他端看到的数据不一致。 --- ## 数据来源分析 ### 1️⃣ 设计师基础数据来源 #### **Department 表** (项目组信息) - `name` - 项目组名称 - `leader` - 组长 (Pointer → Profile) - `type` - 类型 ('project' = 项目组) - `company` - 所属公司 - `data.description` - 项目组描述 #### **Profile 表** (设计师信息) - `name` - 设计师姓名 - `department` - 所属项目组 (String, departmentId) - `data.avatar` - 头像 - `data.skills` - 技能列表 - `data.status` - 初始状态 (通常为空,由项目数据计算) - `data.workload` - 初始工作量 (通常为空,由项目数据计算) - `data.currentProjects` - 初始项目数 (通常为空,由项目数据计算) --- ### 2️⃣ 设计师项目数据来源 (关键!) 设计师分配弹窗在 `enrichMembersWithProjectAssignments()` 方法中动态加载项目数据: #### **查询方案1:ProjectTeam 表 (优先)** ```typescript // 查询 ProjectTeam 表 const teamQuery = new Parse.Query('ProjectTeam'); teamQuery.matchesQuery('project', companyProjectQuery); teamQuery.include('project'); teamQuery.include('profile'); ``` **字段说明:** - `project` - 关联的项目 (Pointer → Project) - `profile` - 关联的设计师 (Pointer → Profile) - `role` - 项目角色 - `isDeleted` - 是否删除 **聚合逻辑:** - 遍历 `ProjectTeam` 记录 - 按 `profile.id` 分组统计项目数量 - **不过滤项目状态**,统计所有项目 #### **查询方案2:Project 表 (降级方案)** 如果 ProjectTeam 表为空,使用 Project 表的 `assignee` 字段: ```typescript const projectQuery = new Parse.Query('Project'); projectQuery.equalTo('company', companyId); projectQuery.include('assignee'); ``` **字段说明:** - `assignee` - 项目负责人 (Pointer → Profile) - `status` - 项目状态 - `currentStage` / `stage` - 项目阶段 - `createdAt` - 创建时间 - `title` / `name` - 项目名称 --- ### 3️⃣ 状态计算逻辑 设计师的状态根据**项目数量**自动计算: ```typescript // 第808-818行 if (member.currentProjects === 0) { member.status = 'idle'; // 🟢 绿色 - 空闲 } else if (member.currentProjects >= 1 && member.currentProjects <= 5) { member.status = 'reviewing'; // 🟠 橙色 - 有项目 } else { member.status = 'stagnant'; // 🔴 红色 - 繁忙 (超过5个项目) } ``` **关键指标:** - `currentProjects` - 当前项目总数(所有状态的项目) - `workload` - 工作量 = `Math.min(100, currentProjects * 20)` - `idleDays` - 闲置天数(如果有项目则为0) - `recentOrders` - 近30天接单数 - `lastOrderDate` - 最后接单日期 - `status` - 状态 (idle/reviewing/stagnant) --- ## 核心问题定位 ### ❌ 问题根源:项目管理端缺少关键输入 查看 `project-management.ts` 第322-340行: ```typescript openTeamAssignmentModal(project: Project): void { this.selectedProject = project; // ❌ 使用的是模拟数据 this.projectTeams = this.mockProjectTeams; // ❌ 没有传递 loadRealData 参数 // ❌ 没有传递 projectId 参数 this.showTeamAssignmentModal = true; } ``` 查看 `project-management.html` 第268-278行: ```html ``` --- ## 对比其他端的调用方式 ### ✅ 正确的调用方式(参考设计师端/组长端) ```html ``` ### 🔑 关键参数说明 | 参数 | 类型 | 默认值 | 作用 | |------|------|--------|------| | `loadRealData` | boolean | true | 是否从数据库加载真实的项目组和成员数据 | | `projectId` | string | '' | 项目ID,用于查询项目相关数据 | | `loadRealSpaces` | boolean | true | 是否自动加载项目的空间数据 | | `enableSpaceAssignment` | boolean | false | 是否启用空间分配功能 | --- ## 数据加载流程对比 ### ❌ 当前项目管理端(错误流程) ``` 打开弹窗 ↓ loadRealData = undefined (默认 true) ↓ 调用 loadRealProjectTeams() ↓ ✅ 从 Department/Profile 表加载设计师基础信息 ↓ ❌ projectId 未传递 (空字符串) ↓ ❌ enrichMembersWithProjectAssignments() 方法中 查询 ProjectTeam 时没有项目上下文 ↓ ❌ 无法统计设计师的项目数量 ↓ ❌ currentProjects = 0 (默认值) ↓ ❌ status = 'idle' (默认值) ↓ ❌ workload = 0 (默认值) ↓ 显示:所有设计师都是"空闲"状态 ❌ ``` ### ✅ 其他端(正确流程) ``` 打开弹窗 ↓ [loadRealData]="true" [projectId]="currentProjectId" ↓ 调用 loadRealProjectTeams() ↓ ✅ 从 Department/Profile 表加载设计师基础信息 ↓ ✅ enrichMembersWithProjectAssignments() ↓ ✅ 查询 ProjectTeam 表(或 Project 表) 按公司ID查询所有项目 ↓ ✅ 为每个设计师统计项目数量 currentProjects = 实际项目数 ↓ ✅ 根据项目数量计算状态 0个项目 → idle (绿色) 1-5个项目 → reviewing (橙色) >5个项目 → stagnant (红色) ↓ ✅ 计算工作量 workload = Math.min(100, currentProjects * 20) ↓ ✅ 计算闲置天数 有项目 → idleDays = 0 无项目 → 根据 lastOrderDate 计算 ↓ 显示:设计师真实的繁忙情况 ✅ ``` --- ## 修复方案 ### 方案1:修改 HTML 模板(推荐) ```html ``` ### 方案2:修改 TypeScript 逻辑(可选) ```typescript // project-management.ts openTeamAssignmentModal(project: Project): void { this.selectedProject = project; // ✅ 不再使用模拟数据,让弹窗组件自动加载 // ❌ this.projectTeams = this.mockProjectTeams; this.projectTeams = []; // 让弹窗组件自动加载真实数据 // 初始化当前团队分配信息 this.currentTeamAssignment = { primaryTeamId: project.assigneeId || null, quotationAssignments: [], crossTeamCollaborators: [] }; // TODO: 从Parse Server加载报价项数据 this.currentQuotationItems = []; this.showTeamAssignmentModal = true; console.log('✅ 打开团队分配弹窗:', project.id, project.title); } ``` --- ## 验证步骤 ### 1️⃣ 修改后重新打开弹窗 控制台应该输出: ``` 🚀 [设计师分配弹窗] 初始化,loadRealData: true 🔄 [设计师分配弹窗] 弹窗打开,重新加载项目数据... ✅ [项目数据加载] ProjectTeam 查询成功! 📊 [项目数据加载] 查询结果: X 条记录 🔍 [张佳乐] Member ID: designer-1 从 profileIdToProjects 获取到 3 个项目 ✅ 已设置 currentProjects(所有项目) = 3 🟠 [张佳乐] 3个项目 - 有项目 (工作量:60%, 闲置:0天) ``` ### 2️⃣ 检查设计师卡片显示 - **状态指示器**: - 🟢 绿色 = 0个项目(空闲) - 🟠 橙色 = 1-5个项目(有项目) - 🔴 红色 = >5个项目(繁忙) - **项目数量**:显示实际项目数,例如 "当前项目: 3个" - **工作量进度条**:根据项目数量计算,例如 60% - **闲置天数**:有项目时为0天,无项目时显示实际天数 --- ## 潜在风险 ### ⚠️ 如果 ProjectTeam 表为空 系统会自动启用降级方案,从 `Project.assignee` 字段查询: ```typescript // 降级方案:查询 Project 表 const projectQuery = new Parse.Query('Project'); projectQuery.equalTo('company', companyId); projectQuery.include('assignee'); const allProjects = await projectQuery.find(); const projects = allProjects.filter(p => { const assignee = p.get('assignee'); return assignee && profileIds.has(assignee.id); }); ``` **注意事项:** 1. 确保 `Project.assignee` 字段已正确设置 2. 只统计角色为"组员"的项目 3. 项目必须属于当前公司 --- ## 数据持久化位置 ### ✅ Profile 表(设计师基础信息) - **位置**:Parse Server → Profile 表 - **字段**:name, department, data.avatar, data.skills ### ✅ ProjectTeam 表(项目-设计师关联) - **位置**:Parse Server → ProjectTeam 表 - **字段**:project (Pointer), profile (Pointer), role ### ✅ Project 表(项目信息) - **位置**:Parse Server → Project 表 - **字段**:assignee (Pointer), status, currentStage, title ### ❌ 动态计算(不持久化) - `currentProjects` - 每次打开弹窗时动态查询 - `workload` - 根据项目数量计算 - `status` - 根据项目数量判断 - `idleDays` - 根据最后接单日期计算 - `recentOrders` - 统计近30天项目 --- ## 总结 ### 问题根源 项目管理端调用设计师分配弹窗时,**没有传递 `projectId` 参数**,导致弹窗无法查询设计师的项目数据,所有设计师都显示为默认的空闲状态。 ### 解决方案 在 `project-management.html` 中添加 `[projectId]="selectedProject?.id || ''"` 输入属性,让弹窗组件能够查询真实的项目数据。 ### 关键参数 - `loadRealData="true"` - 启用真实数据加载(默认已是true) - `projectId="项目ID"` - **关键!** 必须传递,用于查询项目数据 ### 数据流程 ``` 传递 projectId ↓ 查询 ProjectTeam/Project 表 ↓ 统计每个设计师的项目数量 ↓ 计算状态 (idle/reviewing/stagnant) ↓ 显示繁忙情况和接单情况 ```