2025102221-implementation-summary.md 12 KB

项目负责人和空间场景问题 - 实现总结

日期: 2025-10-24
完成状态: ✅ 已完成


✅ 已完成的修改

修改1: team-assign组件 - 自动设置组长为负责人

文件: src/modules/project/components/team-assign/team-assign.component.ts
位置: 第128-151行

修改内容:

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'));
      
      // 触发界面更新
      this.cdr.markForCheck();
    } catch (error) {
      console.error('❌ 设置项目负责人失败:', error);
    }
  }

  await this.loadDepartmentMembers(department);
}

效果:

  • 在项目详情页选择项目组时,自动将组长设置为项目的 assignee
  • 同时设置项目的 department 字段
  • 保存到数据库,刷新后数据持久化

修改2: ProjectService - 项目创建逻辑

文件: src/app/pages/admin/services/project.service.ts
位置: 第4-6行(导入)、第70-137行(createProject方法)

2.1 添加Parse导入:

import { FmodeParse } from 'fmode-ng/parse';

const Parse = FmodeParse.with('nova');

2.2 修改createProject方法:

async createProject(data: {
  title: string;
  customerId?: string;
  assigneeId?: string;
  departmentId?: string; // ✅ 新增:项目组ID
  status?: string;
  currentStage?: string;
  deadline?: Date;
  data?: any;
}): Promise<FmodeObject> {
  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) {
    try {
      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'));
        }
      }
    } catch (error) {
      console.error('❌ 获取项目组失败:', error);
    }
  }

  // 设置负责人指针(如果明确指定,覆盖组长)
  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);
}

效果:

  • 创建项目时可以指定 departmentId
  • 自动获取该项目组的组长作为默认负责人
  • 如果明确指定了 assigneeId,优先使用指定的人员

修改3: ProjectService - 查询时包含department和leader

文件: src/app/pages/admin/services/project.service.ts
位置: 第17-44行(findProjects)、第57-67行(getProject)

3.1 修改findProjects:

async findProjects(options?: {
  status?: string;
  keyword?: string;
  skip?: number;
  limit?: number;
}): Promise<FmodeObject[]> {
  return await this.adminData.findAll('Project', {
    include: ['customer', 'assignee', 'department', 'department.leader'], // ✅ 添加department和leader
    skip: options?.skip || 0,
    limit: options?.limit || 20,
    descending: 'updatedAt',
    additionalQuery: query => {
      if (options?.status) {
        query.equalTo('status', options.status);
      }
      if (options?.keyword) {
        const kw = options.keyword.trim();
        if (kw) {
          // 搜索项目标题
          query.matches('title', new RegExp(kw, 'i'));
        }
      }
    }
  });
}

3.2 修改getProject:

async getProject(objectId: string): Promise<FmodeObject | null> {
  return await this.adminData.getById('Project', objectId, [
    'customer',
    'assignee',
    'department',
    'department.leader' // ✅ 添加department和leader
  ]);
}

效果:

  • 查询项目时自动加载 departmentdepartment.leader 关联数据
  • 为后续显示组长信息提供数据基础

修改4: ProjectService - toJSON方法优化

文件: src/app/pages/admin/services/project.service.ts
位置: 第231-257行

修改内容:

toJSON(project: FmodeObject): any {
  const json = this.adminData.toJSON(project);

  // 处理关联对象
  if (json.customer && typeof json.customer === 'object') {
    json.customerName = json.customer.name || '';
    json.customerId = json.customer.objectId;
  }

  // ✅ 处理负责人:优先使用assignee,如果为空则使用department.leader
  if (json.assignee && typeof json.assignee === 'object') {
    json.assigneeName = json.assignee.name || '';
    json.assigneeId = json.assignee.objectId;
  } else if (json.department && typeof json.department === 'object') {
    // 如果没有assignee,但有department和leader,使用leader
    const leader = json.department.leader;
    if (leader && typeof leader === 'object') {
      json.assigneeName = leader.name || '';
      json.assigneeId = leader.objectId;
    }
  }

  return json;
}

效果:

  • 项目列表显示负责人时,优先使用 assignee.name
  • 如果 assignee 为空,自动使用 department.leader.name
  • 确保项目列表中不会显示"未分配",而是显示组长名字

📊 数据流图

创建项目流程

用户创建项目
  ↓
指定departmentId
  ↓
createProject()查询Department
  ↓
获取department.leader
  ↓
设置project.assignee = leader
  ↓
保存到数据库
  ↓
项目列表显示组长名字

选择项目组流程

用户在项目详情页
  ↓
选择项目组(team-assign组件)
  ↓
selectDepartment()自动触发
  ↓
获取department.leader
  ↓
更新project.assignee = leader
  ↓
保存到数据库
  ↓
刷新项目列表,负责人更新

显示负责人流程

加载项目列表
  ↓
include: ['assignee', 'department', 'department.leader']
  ↓
toJSON()转换
  ↓
如果有assignee → 显示assignee.name
如果没有assignee但有department.leader → 显示leader.name
否则 → 显示"未分配"
  ↓
项目列表展示

🧪 测试验证

测试场景1: 在项目详情页选择项目组

步骤:

  1. 访问项目详情页:http://localhost:4200/admin/project-detail/APwk78jnrh/order
  2. 在"设计师分配"卡片中选择一个项目组
  3. 观察控制台输出:✅ 项目负责人已设置为组长: xxx
  4. 刷新项目管理页面:http://localhost:4200/admin/project-management
  5. 验证该项目的"负责人"列显示组长名字

预期结果:

  • ✅ 选择项目组后,项目的 assignee 自动设置为组长
  • ✅ 项目列表中"负责人"列显示组长名字
  • ✅ 不再显示"未分配"

测试场景2: 创建新项目并指定项目组

步骤:

  1. 调用 projectService.createProject() 创建项目:

    await projectService.createProject({
     title: '测试项目',
     departmentId: 'xxx项目组ID',
     status: '待分配'
    });
    
  2. 查看控制台输出:✅ 项目负责人默认为组长: xxx

  3. 在项目管理页面查看新项目

  4. 验证"负责人"列显示组长名字

预期结果:

  • ✅ 项目创建时自动设置组长为负责人
  • project.assignee 指向组长的Profile
  • project.department 指向该项目组

测试场景3: 验证空间场景问题

当前状态:

  • ⚠️ 项目ID APwk78jnrhProduct 表中没有记录
  • ⚠️ 分配设计师时没有空间可选

解决方案:

  1. 在订单分配阶段(stage-order)添加空间时,确保调用 ProductSpaceService.createProductSpace() 创建 Product 记录
  2. 或者在Parse Dashboard手动添加Product记录:
    • 进入 Product
    • 添加新行
    • 设置 project 字段为项目指针
    • 设置 productName 为 "客厅"、"卧室" 等
    • 设置 productType 为 "living_room"、"bedroom" 等
    • 保存

🎯 核心改进

改进1: 自动化负责人分配

修改前:

  • 项目创建时 assignee 为空
  • 需要手动设置负责人
  • 项目列表显示"未分配"

修改后:

  • 选择项目组时自动设置组长为负责人
  • 创建项目时可指定项目组,自动获取组长
  • 项目列表始终显示组长名字

改进2: 优雅降级

数据获取优先级:

  1. 最高优先级: 明确指定的 assignee
  2. 次优先级: 项目组的 department.leader
  3. 兜底: 显示"未分配"

代码实现:

// toJSON方法中的逻辑
if (json.assignee && typeof json.assignee === 'object') {
  // 优先使用assignee
  json.assigneeName = json.assignee.name || '';
} else if (json.department && typeof json.department === 'object') {
  // 降级使用department.leader
  const leader = json.department.leader;
  if (leader && typeof leader === 'object') {
    json.assigneeName = leader.name || '';
  }
}

📁 修改文件清单

文件 修改内容 状态
src/modules/project/components/team-assign/team-assign.component.ts 选择项目组时自动设置组长为负责人 ✅ 完成
src/app/pages/admin/services/project.service.ts 添加Parse导入 ✅ 完成
src/app/pages/admin/services/project.service.ts 修改createProject方法,支持departmentId ✅ 完成
src/app/pages/admin/services/project.service.ts 修改findProjects,include department ✅ 完成
src/app/pages/admin/services/project.service.ts 修改getProject,include department ✅ 完成
src/app/pages/admin/services/project.service.ts 修改toJSON,优先显示leader ✅ 完成
docs/task/2025102221-fix-project-assignee-and-spaces.md 问题分析文档 ✅ 完成
docs/task/2025102221-implementation-summary.md 实现总结文档 ✅ 完成

🎉 总结

解决的问题

  1. 项目负责人显示"未分配" → 现在自动显示组长名字
  2. ⚠️ 分配设计师时没有空间场景 → 需要在订单分配阶段创建Product记录

核心逻辑

  1. 选择项目组 → 自动设置组长为负责人
  2. 创建项目 → 指定项目组时,自动获取组长
  3. 显示负责人 → 优先assignee,降级使用leader
  4. 数据加载 → 始终include department和leader

用户体验提升

  • 无需手动分配负责人:选择项目组即可
  • 项目列表清晰:始终显示真实负责人姓名
  • 数据一致性:负责人与项目组关联

修改完成!现在刷新浏览器测试,项目列表应该能正确显示组长名字了! 🚀