徐福静0235668 ffdeb21132 feat: enhance designer team assignment modal with calendar functionality and UI improvements 3 долоо хоног өмнө
..
DEMO_GUIDE.md e1351fb117 feat: integrate reusable EmployeeInfoPanelComponent into admin employee management 3 долоо хоног өмнө
README.md e1351fb117 feat: integrate reusable EmployeeInfoPanelComponent into admin employee management 3 долоо хоног өмнө
USAGE_EXAMPLE.md e1351fb117 feat: integrate reusable EmployeeInfoPanelComponent into admin employee management 3 долоо хоног өмнө
employee-info-panel.component.html ffdeb21132 feat: enhance designer team assignment modal with calendar functionality and UI improvements 3 долоо хоног өмнө
employee-info-panel.component.scss ba6809c2e7 feat: implement aftercare improvements and customer service enhancements 3 долоо хоног өмнө
employee-info-panel.component.ts ffdeb21132 feat: enhance designer team assignment modal with calendar functionality and UI improvements 3 долоо хоног өмнө
index.ts ba6809c2e7 feat: implement aftercare improvements and customer service enhancements 3 долоо хоног өмнө

README.md

员工信息侧边栏组件 (EmployeeInfoPanel)

概述

这是一个集成了基本信息项目负载两个视角的员工信息侧边栏组件。通过顶部导航标签可以在两个板块之间切换查看。

功能特性

📋 基本信息标签页(管理员视角)

  • ✅ 员工头像、姓名、职位展示
  • ✅ 联系方式(手机、邮箱、企微ID)
  • ✅ 组织信息(身份、部门、职级)
  • ✅ 技能标签
  • ✅ 工作量统计
  • ✅ 在线编辑基本信息(姓名、手机号、身份、部门、状态)

📊 项目负载标签页(组长视角)

  • ✅ 负载概况(当前项目数、核心项目列表)
  • ✅ 负载详细日历(月视图、项目数量可视化)
  • ✅ 请假明细(未来7天)
  • ✅ 红色标记说明
  • ✅ 能力问卷展示(摘要/完整)
  • ✅ 详细工作日历(复用设计师日历组件)

使用方法

1. 导入组件

import { EmployeeInfoPanelComponent, EmployeeFullInfo } from '@shared/components/employee-info-panel';

@Component({
  // ...
  imports: [EmployeeInfoPanelComponent]
})
export class YourComponent {
  showEmployeePanel = false;
  selectedEmployee: EmployeeFullInfo | null = null;
  departments = [
    { id: 'dept1', name: '设计一组' },
    { id: 'dept2', name: '设计二组' }
  ];
}

2. 在模板中使用

<app-employee-info-panel
  [visible]="showEmployeePanel"
  [employee]="selectedEmployee"
  [departments]="departments"
  [roles]="['客服', '组员', '组长', '人事', '财务', '管理员']"
  (close)="handleClose()"
  (update)="handleUpdate($event)"
  (calendarMonthChange)="handleMonthChange($event)"
  (projectClick)="handleProjectClick($event)"
  (refreshSurvey)="handleRefreshSurvey()">
</app-employee-info-panel>

3. 准备员工数据

// 基础信息(必填)
const employee: EmployeeFullInfo = {
  id: 'emp001',
  name: '张三',
  realname: '张三丰',
  mobile: '13800138000',
  userid: 'zhangsan',
  roleName: '组员',
  department: '设计一组',
  departmentId: 'dept1',
  isDisabled: false,
  avatar: 'https://example.com/avatar.jpg',
  email: 'zhangsan@example.com',
  position: '高级设计师',
  gender: '1',
  level: 'P5',
  skills: ['现代风格', '中式风格', '3D建模'],
  joinDate: '2023-01-01',
  createdAt: new Date('2023-01-01'),
  
  // 项目负载信息(可选,用于"项目负载"标签页)
  currentProjects: 3,
  projectNames: ['项目A', '项目B', '项目C'],
  projectData: [
    { id: 'proj1', name: '项目A' },
    { id: 'proj2', name: '项目B' },
    { id: 'proj3', name: '项目C' }
  ],
  
  // 请假记录(可选)
  leaveRecords: [
    {
      id: 'leave1',
      employeeName: '张三',
      date: '2024-01-15',
      isLeave: true,
      leaveType: 'annual',
      reason: '年假'
    }
  ],
  
  // 日历数据(可选)
  calendarData: {
    currentMonth: new Date(),
    days: [
      {
        date: new Date('2024-01-15'),
        projectCount: 2,
        projects: [
          { id: 'proj1', name: '项目A', deadline: new Date('2024-01-20') },
          { id: 'proj2', name: '项目B' }
        ],
        isToday: true,
        isCurrentMonth: true
      }
      // ... more days
    ]
  },
  
  // 红色标记说明(可选)
  redMarkExplanation: '该设计师项目负载较高,建议暂缓分配新项目',
  
  // 工作量统计(可选)
  workload: {
    currentProjects: 3,
    completedProjects: 15,
    averageQuality: 8.5
  },
  
  // 能力问卷(可选)
  surveyCompleted: true,
  surveyData: {
    createdAt: new Date('2023-12-01'),
    answers: [
      {
        questionId: 'q1_expertise_styles',
        question: '您擅长的设计风格?',
        type: 'multiple',
        answer: ['现代', '中式', '北欧']
      },
      // ... more answers
    ]
  },
  profileId: 'profile123'
};

4. 处理事件

export class YourComponent {
  // 关闭面板
  handleClose() {
    this.showEmployeePanel = false;
    this.selectedEmployee = null;
  }

  // 更新员工信息
  async handleUpdate(updates: Partial<EmployeeFullInfo>) {
    try {
      await this.employeeService.updateEmployee(updates.id!, {
        name: updates.name,
        realname: updates.realname,
        mobile: updates.mobile,
        roleName: updates.roleName,
        departmentId: updates.departmentId,
        isDisabled: updates.isDisabled
      });
      
      // 重新加载员工列表
      await this.loadEmployees();
      
      // 关闭面板
      this.handleClose();
      
      alert('更新成功!');
    } catch (error) {
      console.error('更新失败:', error);
      alert('更新失败,请重试');
    }
  }

  // 切换月份
  handleMonthChange(direction: number) {
    // direction: -1 (上月) | 1 (下月)
    // 重新计算日历数据
    const currentMonth = this.selectedEmployee!.calendarData!.currentMonth;
    const newMonth = new Date(currentMonth);
    newMonth.setMonth(newMonth.getMonth() + direction);
    
    // 更新日历数据
    this.updateCalendarData(newMonth);
  }

  // 项目点击
  handleProjectClick(projectId: string) {
    // 跳转到项目详情页
    this.router.navigate(['/project-detail', projectId]);
  }

  // 刷新问卷
  async handleRefreshSurvey() {
    try {
      // 重新查询员工的问卷数据
      const surveyData = await this.surveyService.getEmployeeSurvey(this.selectedEmployee!.id);
      
      // 更新员工信息
      this.selectedEmployee = {
        ...this.selectedEmployee!,
        surveyCompleted: !!surveyData,
        surveyData: surveyData
      };
    } catch (error) {
      console.error('刷新问卷失败:', error);
    }
  }
}

Props(输入属性)

属性名 类型 必填 默认值 说明
visible boolean false 面板是否可见
employee EmployeeFullInfo \| null null 员工完整信息
departments Array<{id: string; name: string}> [] 部门列表(用于编辑时选择)
roles string[] ['客服', '组员', '组长', '人事', '财务', '管理员'] 角色列表

Events(输出事件)

事件名 参数类型 说明
close void 关闭面板
update Partial<EmployeeFullInfo> 更新员工信息
calendarMonthChange number 切换日历月份(-1或1)
calendarDayClick EmployeeCalendarDay 点击日历日期
projectClick string 点击项目(项目ID)
refreshSurvey void 刷新问卷数据

数据接口

EmployeeFullInfo

完整的员工信息接口,整合了基本信息和项目负载信息。

interface EmployeeFullInfo {
  // === 基础信息(必填) ===
  id: string;
  name: string;
  realname?: string;
  mobile: string;
  userid: string;
  roleName: string;
  department: string;
  departmentId?: string;
  isDisabled?: boolean;
  createdAt?: Date;
  
  // === 扩展信息(可选) ===
  avatar?: string;
  email?: string;
  position?: string;
  gender?: string;
  level?: string;
  skills?: string[];
  joinDate?: Date | string;
  
  // === 工作量统计(可选) ===
  workload?: {
    currentProjects?: number;
    completedProjects?: number;
    averageQuality?: number;
  };
  
  // === 项目负载信息(可选) ===
  currentProjects?: number;
  projectNames?: string[];
  projectData?: Array<{ id: string; name: string }>;
  leaveRecords?: LeaveRecord[];
  redMarkExplanation?: string;
  calendarData?: EmployeeCalendarData;
  
  // === 能力问卷(可选) ===
  surveyCompleted?: boolean;
  surveyData?: any;
  profileId?: string;
}

样式定制

组件使用渐变紫色主题,可以通过修改 SCSS 变量自定义:

// 主色调
$primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);

// 状态颜色
$color-active: #4caf50;  // 正常/在职
$color-disabled: #f44336; // 禁用/离职
$color-warning: #ff9800;  // 高负载/今天

// 圆角
$border-radius: 12px;

// 阴影
$box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);

注意事项

  1. DesignerCalendar 依赖: 组件依赖 DesignerCalendarComponent,确保该组件可用。
  2. 响应式设计: 移动端会自动调整为单列布局。
  3. 数据完整性: 基本信息字段为必填,项目负载字段为可选(如果不需要"项目负载"标签页,可以不提供相关数据)。
  4. 性能优化: 日历数据较大时,建议按需加载(只加载当前月份)。

与原有组件的关系

  • ✅ 不影响原有的管理员端 employees.html 面板
  • ✅ 不影响原有的组长端 employee-detail-panel 组件
  • ✅ 作为独立组件,可在任何需要展示员工完整信息的地方复用
  • ✅ 通过顶部导航切换,集成了两个视角的所有信息

示例场景

场景1:管理员查看员工详情

// 只需要基本信息,不需要项目负载数据
viewEmployee(emp: Employee) {
  this.selectedEmployee = {
    ...emp,
    // 不提供 projectData、calendarData 等字段
  };
  this.showEmployeePanel = true;
}

场景2:组长查看设计师负载

// 需要完整信息,包括项目负载
async viewDesignerWorkload(designerId: string) {
  // 查询基本信息
  const basicInfo = await this.employeeService.getEmployee(designerId);
  
  // 查询项目负载
  const projects = await this.projectService.getDesignerProjects(designerId);
  
  // 查询日历数据
  const calendarData = await this.calendarService.getDesignerCalendar(designerId);
  
  // 查询请假记录
  const leaveRecords = await this.leaveService.getLeaveRecords(designerId);
  
  // 查询问卷
  const surveyData = await this.surveyService.getEmployeeSurvey(designerId);
  
  this.selectedEmployee = {
    ...basicInfo,
    currentProjects: projects.length,
    projectData: projects,
    calendarData,
    leaveRecords,
    surveyCompleted: !!surveyData,
    surveyData
  };
  
  this.showEmployeePanel = true;
}

更新日志

  • 2024-01-08: 初始版本,集成基本信息和项目负载两个视角