# Admin项目管理 - 设计师分配弹窗增强 **日期**: 2025-10-24 **任务**: 在Admin项目管理中增强设计师分配功能 **状态**: 🚧 进行中 --- ## 📋 需求概述 ### 核心需求 1. 在Admin项目管理列表中添加"分配设计师"操作按钮 2. 复用`designer-team-assignment-modal`组件 3. 对接Parse Server真实数据,显示实际项目成员 4. 修改弹窗中的日历组件,改为**按月日历显示**(单屏完整显示) 5. 增加**工序分工**功能: - 空间分配 - 建模分配 - 软装分配 - 渲染分配 - 后期分配 --- ## 🎯 实现步骤 ### 步骤1: 在项目管理列表添加"分配设计师"按钮 ✅ **文件**: `src/app/pages/admin/project-management/project-management.html` 在操作列添加新按钮: ```html ``` ### 步骤2: 在TypeScript中实现弹窗逻辑 **文件**: `src/app/pages/admin/project-management/project-management.ts` 添加: - 导入`DesignerTeamAssignmentModalComponent` - 添加弹窗状态管理 - 实现`openTeamAssignmentModal(project)`方法 - 实现`closeTeamAssignmentModal()`方法 - 实现`confirmTeamAssignment(result)`方法 - 从Parse加载真实项目数据和团队数据 ### 步骤3: 创建工序分工数据结构 **新增接口**: ```typescript export interface WorkflowAssignment { workflowType: 'space' | 'modeling' | 'furnishing' | 'rendering' | 'postprocessing'; workflowName: string; assignedDesigners: string[]; // Designer IDs productIds?: string[]; // 关联的产品/空间ID estimatedHours?: number; deadline?: Date; } export interface EnhancedDesignerAssignmentData { projectId: string; primaryTeamId: string; workflowAssignments: WorkflowAssignment[]; crossTeamCollaborators: string[]; notes?: string; } ``` ### 步骤4: 修改弹窗组件以支持工序分工 **文件**: `src/app/pages/designer/project-detail/components/designer-team-assignment-modal/designer-team-assignment-modal.component.html` 在弹窗中添加新的"工序分工"部分: ```html @if (internalSelectedTeamId && showWorkflowAssignment) {

工序分工

{{ workflow.name }}

已分配: {{ getWorkflowAssignedCount(workflow.type) }}人
@for (designerId of getWorkflowAssignedDesigners(workflow.type); track designerId) {
{{ getDesignerById(designerId)?.name }}
}
} ``` ### 步骤5: 修改日历组件为月视图 **目标**: 修改`designer-calendar.component`,使其显示类似iOS日历的月视图 **参考图片要求**: - 单月视图,所有日期在一屏内显示 - 清晰标注工作日、休息日、已占用日期 - 支持点击查看当日详情 - 不需要左右滑动 **实现方案**: 创建新的月历组件或修改现有组件: ```html
{{ currentMonth }} {{ currentYear }}
{{ day }}
{{ date.getDate() }} @if (hasEvents(date)) {
}
@if (selectedDate) {

{{ selectedDate | date:'yyyy-MM-dd' }}

{{ event.description }}
}
``` ### 步骤6: Parse数据对接 **查询项目团队成员**: ```typescript async loadProjectTeamMembers(projectId: string): Promise { const query = new Parse.Query('ProjectTeam'); query.equalTo('project', { __type: 'Pointer', className: 'Project', objectId: projectId }); query.include('profile'); query.notEqualTo('isDeleted', true); const teamMembers = await query.find(); return teamMembers.map(member => { const profile = member.get('profile'); return { id: profile.id, name: profile.get('name'), teamId: member.get('team')?.id, teamName: member.get('team')?.get('name'), // ... 其他字段 }; }); } ``` **查询工序分配**: ```typescript async loadWorkflowAssignments(projectId: string): Promise { const query = new Parse.Query('ProjectWorkflowAssignment'); query.equalTo('project', { __type: 'Pointer', className: 'Project', objectId: projectId }); query.include(['assignedTo', 'product']); const assignments = await query.find(); return assignments.map(assignment => ({ workflowType: assignment.get('workflowType'), workflowName: assignment.get('workflowName'), assignedDesigners: assignment.get('assignedTo').map(d => d.id), productIds: assignment.get('products')?.map(p => p.id), })); } ``` **保存分配结果**: ```typescript async saveTeamAssignment(projectId: string, data: EnhancedDesignerAssignmentData): Promise { // 1. 更新ProjectTeam表 for (const designerId of data.selectedDesigners) { const ProjectTeam = Parse.Object.extend('ProjectTeam'); const teamMember = new ProjectTeam(); teamMember.set('project', { __type: 'Pointer', className: 'Project', objectId: projectId }); teamMember.set('profile', { __type: 'Pointer', className: 'Profile', objectId: designerId }); teamMember.set('role', 'member'); await teamMember.save(); } // 2. 保存工序分配 for (const workflow of data.workflowAssignments) { const WorkflowAssignment = Parse.Object.extend('ProjectWorkflowAssignment'); const assignment = new WorkflowAssignment(); assignment.set('project', { __type: 'Pointer', className: 'Project', objectId: projectId }); assignment.set('workflowType', workflow.workflowType); assignment.set('workflowName', workflow.workflowName); assignment.set('assignedTo', workflow.assignedDesigners.map(id => ({ __type: 'Pointer', className: 'Profile', objectId: id }))); await assignment.save(); } } ``` --- ## 📐 UI/UX设计要点 ### 1. 弹窗布局优化 - **单屏显示**: 所有关键信息在一屏内,避免过度滚动 - **左右布局**: 左侧团队选择+工序分工,右侧设计师列表+日历 - **固定高度**: 弹窗最大高度90vh,内容区域可滚动 ### 2. 工序分工设计 ``` ┌─────────────┬──────────────────────────────┐ │ 工序分工 │ │ ├─────────────┼──────────────────────────────┤ │ 🏠 空间设计 │ [张三] [李四] [+ 添加] │ │ 🔨 建模制作 │ [王五] [+ 添加] │ │ 🪑 软装搭配 │ [赵六] [+ 添加] │ │ 🎨 效果渲染 │ [+ 添加] │ │ ✨ 后期处理 │ [+ 添加] │ └─────────────┴──────────────────────────────┘ ``` ### 3. 月历视图设计 ``` 2025年 10月 一 二 三 四 五 六 日 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 图例: 🟢 空闲可分配 🔴 已占用 🟡 对图日期 🔵 当前选中 ``` --- ## 🔧 技术实现细节 ### Parse Schema扩展 可能需要新增表: ```typescript TABLE(ProjectWorkflowAssignment, "项目工序分配表") { FIELD(objectId, String) FIELD(project, Pointer→Project) FIELD(company, Pointer→Company) FIELD(workflowType, String) // "space" | "modeling" | "furnishing" | "rendering" | "postprocessing" FIELD(workflowName, String) FIELD(assignedTo, Array) FIELD(products, Array) // 关联的空间产品 FIELD(estimatedHours, Number) FIELD(deadline, Date) FIELD(isDeleted, Boolean) FIELD(createdAt, Date) FIELD(updatedAt, Date) } ``` --- ## ✅ 验收标准 1. ✅ 项目管理列表中有"分配设计师"按钮 2. ✅ 点击按钮弹出设计师分配弹窗 3. ✅ 弹窗显示真实的项目团队成员(从Parse加载) 4. ✅ 弹窗中有工序分工区域,可分配5种工序 5. ✅ 日历组件改为月视图,单屏完整显示 6. ✅ 可以查看每个设计师的月度日历 7. ✅ 保存后数据写入Parse Server 8. ✅ 刷新页面后分配信息保持 --- ## 📝 开发备注 - 复用现有的`designer-team-assignment-modal`组件 - 日历组件可参考iOS原生日历风格 - 工序分工为新增功能,需要扩展数据模型 - 注意多租户隔离(company字段) - 所有查询都要过滤`isDeleted` --- **开发者**: Claude AI **预计完成时间**: 2025-10-24