# 修复项目负责人和空间场景问题 **日期**: 2025-10-24 **问题**: 1. 分配设计师时没有空间场景可选 2. 项目列表中负责人显示"未分配",应该显示组长名字 --- ## 🔍 问题分析 ### 问题1: 空间场景为空 **现象**: 在 `http://localhost:4200/admin/project-detail/APwk78jnrh/order` 分配设计师时,"指派空间场景"没有选项。 **原因**: `team-assign.component.ts` 通过 `ProductSpaceService.getProjectProductSpaces()` 获取项目空间: ```typescript // team-assign.component.ts 第94-107行 async loadProjectSpaces(): Promise { if (!this.project) return; try { this.loadingSpaces = true; const projectId = this.project.id || ''; // 从Product表查询该项目的空间 this.projectSpaces = await this.productSpaceService.getProjectProductSpaces(projectId); } catch (err) { console.error('加载项目空间失败:', err); } finally { this.loadingSpaces = false; this.cdr.markForCheck(); } } ``` `ProductSpaceService.getProjectProductSpaces()` 从 `Product` 表查询: ```typescript // product-space.service.ts 第125-143行 async getProjectProductSpaces(projectId: string): Promise { try { const query = new Parse.Query('Product'); query.equalTo('project', { __type: 'Pointer', className: 'Project', objectId: projectId }); query.include('profile'); query.ascending('createdAt'); const results = await query.find(); return results.map(product => this.parseProductData(product)); } catch (error) { console.error('获取项目产品空间失败:', error); return []; } } ``` **根本原因**: 项目ID为 `APwk78jnrh` 的项目在 `Product` 表中没有任何记录。 --- ### 问题2: 项目负责人显示"未分配" **现象**: 项目列表中"负责人"列显示"未分配",应该显示组长名字。 **数据流**: ``` Parse数据库 Project表 ↓ assignee字段 (Pointer) = null ↓ project-management.ts 第107行 assignee: json.assigneeName || '未分配' ↓ 前端显示 "未分配" ``` **根本原因**: 项目创建时,`assignee` 字段没有被设置。按业务逻辑,项目的负责人应该是项目组的组长(`department.leader`)。 --- ## ✅ 解决方案 ### 方案1: 空间场景问题 **方案A: 在"订单分配"阶段创建空间(推荐)** 在 `stage-order.component.ts` 的订单分配阶段,用户填写空间信息后自动创建 `Product` 记录。 **位置**: `src/modules/project/pages/project-detail/stages/stage-order.component.ts` **逻辑**: ```typescript async saveSpaces() { // 遍历用户添加的空间 for (const space of this.spaces) { // 调用 ProductSpaceService.createProductSpace() 创建Product记录 await this.productSpaceService.createProductSpace(this.project.id, { name: space.name, type: space.type, area: space.area, priority: space.priority, complexity: space.complexity, estimatedBudget: space.budget }); } } ``` **方案B: 在分配设计师时动态创建空间** 如果没有空间,显示提示:"请先在订单分配阶段添加空间"。 **方案C: 提供手动添加空间的入口** 在分配设计师弹窗中添加"添加空间"按钮。 --- ### 方案2: 项目负责人问题 **关键修改**: 在选择项目组(Department)时,自动将组长(`department.leader`)设置为项目的 `assignee`。 #### 修改1: team-assign.component.ts **位置**: `src/modules/project/components/team-assign/team-assign.component.ts` 第128-134行 **修改 `selectDepartment` 方法**: ```typescript async selectDepartment(department: FmodeObject) { this.selectedDepartment = department; this.selectedDesigner = null; this.departmentMembers = []; // ✅ 新增:自动设置组长为项目负责人 const leader = department.get('leader'); if (leader && this.project) { try { // 更新项目的assignee字段为组长 this.project.set('assignee', leader); this.project.set('department', department); await this.project.save(); console.log('✅ 项目负责人已设置为组长:', leader.get('name')); } catch (error) { console.error('❌ 设置项目负责人失败:', error); } } await this.loadDepartmentMembers(department); } ``` **说明**: - 当选择项目组时,自动获取组长(`department.leader`) - 将组长设置为项目的 `assignee` 字段 - 同时设置项目的 `department` 字段 - 保存到数据库 #### 修改2: 项目创建时的默认逻辑 **位置**: `src/app/pages/admin/services/project.service.ts` 第65-110行 **在 `createProject` 方法中添加逻辑**: ```typescript async createProject(data: { title: string; customerId?: string; assigneeId?: string; // 可以是组长ID departmentId?: string; // 新增:项目组ID status?: string; currentStage?: string; deadline?: Date; data?: any; }): Promise { const projectData: any = { title: data.title, status: data.status || '待分配', currentStage: data.currentStage || '订单分配' }; // 设置客户指针 if (data.customerId) { projectData.customer = { __type: 'Pointer', className: 'ContactInfo', objectId: data.customerId }; } // ✅ 新增:如果提供了项目组,获取组长作为默认负责人 if (data.departmentId) { const departmentQuery = new Parse.Query('Department'); departmentQuery.include('leader'); const department = await departmentQuery.get(data.departmentId); if (department) { projectData.department = department.toPointer(); // 获取组长 const leader = department.get('leader'); if (leader && !data.assigneeId) { projectData.assignee = leader.toPointer(); console.log('✅ 项目负责人默认为组长:', leader.get('name')); } } } // 设置负责人指针(如果明确指定) if (data.assigneeId) { projectData.assignee = { __type: 'Pointer', className: 'Profile', objectId: data.assigneeId }; } if (data.deadline) { projectData.deadline = data.deadline; } if (data.data) { projectData.data = data.data; } const project = this.adminData.createObject('Project', projectData); return await this.adminData.save(project); } ``` --- ## 📊 数据库结构 ### Project 表 | 字段 | 类型 | 说明 | 新增/修改 | |------|------|------|----------| | `department` | Pointer | 项目组 | ✅ 确保填充 | | `assignee` | Pointer | 项目负责人(组长) | ✅ 自动设置为组长 | | `title` | String | 项目名称 | 已有 | | `customer` | Pointer | 客户 | 已有 | | `status` | String | 项目状态 | 已有 | | `currentStage` | String | 当前阶段 | 已有 | ### Product 表 | 字段 | 类型 | 说明 | |------|------|------| | `project` | Pointer | 所属项目 | | `productName` | String | 空间名称(如"客厅") | | `productType` | String | 空间类型(如"living_room") | | `space` | Object | 空间详细信息 | | `space.area` | Number | 面积 | | `space.priority` | Number | 优先级 | | `space.complexity` | String | 复杂度 | | `quotation` | Object | 报价信息 | | `requirements` | Object | 需求信息 | | `profile` | Pointer | 负责该空间的设计师 | ### Department 表 | 字段 | 类型 | 说明 | |------|------|------| | `name` | String | 项目组名称 | | `leader` | Pointer | 组长 | | `type` | String | 'project' (项目组) | | `company` | String | 公司ID | ### Profile 表 | 字段 | 类型 | 说明 | |------|------|------| | `name` | String | 姓名 | | `roleName` | String | '组长' 或 '组员' | | `department` | String | 部门ID | | `company` | String | 公司ID | --- ## 🧪 测试步骤 ### 测试1: 空间场景 1. **进入订单分配阶段** ``` http://localhost:4200/admin/project-detail/APwk78jnrh/order ``` 2. **添加空间** - 点击"添加空间"按钮 - 填写空间信息(客厅、卧室等) - 保存 3. **分配设计师** - 选择项目组 - 选择设计师 - **预期**: 能看到刚才添加的空间列表 - 选择空间并确认分配 ### 测试2: 项目负责人 1. **创建新项目时指定项目组** ``` POST /Project { "title": "测试项目", "departmentId": "xxx", // 项目组ID "status": "待分配" } ``` 2. **验证数据库** ``` // Parse Dashboard 查看 Project 表 - assignee字段应该指向组长的Profile - department字段应该指向该项目组 ``` 3. **在项目详情页选择项目组** - 进入项目详情页订单分配阶段 - 选择一个项目组 - **预期**: - 项目的assignee自动更新为该组长 - 刷新项目列表,负责人列显示组长名字 4. **验证项目列表** ``` http://localhost:4200/admin/project-management ``` - **预期**: "负责人"列显示组长名字,而不是"未分配" --- ## 🎯 核心逻辑总结 ### 项目负责人(assignee)的设置规则 1. **项目创建时**: - 如果指定了 `departmentId`,自动获取组长作为 `assignee` - 如果明确指定了 `assigneeId`,使用指定的人员 2. **选择项目组时**: - 在 `team-assign` 组件中选择项目组 - 自动将组长设置为项目的 `assignee` - 更新 `department` 字段 3. **项目列表显示**: - 从 `assignee.name` 获取负责人名字 - 如果为空,显示"未分配" ### 空间场景的创建流程 1. **订单分配阶段** (stage-order): - 用户填写空间信息(客厅、卧室等) - 调用 `ProductSpaceService.createProductSpace()` 创建 Product 记录 2. **分配设计师时** (team-assign): - 从 `Product` 表查询该项目的所有空间 - 显示空间列表供选择 - 将选中的空间保存到 `ProjectTeam.data.spaces` 中 --- ## 📁 需要修改的文件 1. ✅ `src/modules/project/components/team-assign/team-assign.component.ts` - 第128-134行:修改 `selectDepartment` 方法 2. ✅ `src/app/pages/admin/services/project.service.ts` - 第65-110行:修改 `createProject` 方法 3. ⚠️ `src/modules/project/pages/project-detail/stages/stage-order.component.ts` - 需要确保空间信息保存时创建 Product 记录 --- ## 🎉 预期效果 ### 修改前 **项目列表**: ``` 项目名称 | 客户 | 负责人 | 状态 张家界凤凰城三期项目 紫空居.. | 未知客户 | 未分配 | 待分配 ``` **分配设计师**: ``` 指派空间场景 (空) ``` ### 修改后 **项目列表**: ``` 项目名称 | 客户 | 负责人 | 状态 张家界凤凰城三期项目 紫空居.. | 张先生 | 汪奥 | 进行中 ``` **分配设计师**: ``` 指派空间场景 * ☑ 客厅 ☐ 主卧 ☐ 次卧 ☐ 厨房 ``` --- **修改完成后,项目负责人将自动设置为组长,且分配设计师时能看到项目的所有空间!** ✨