EMPLOYEE-MANAGEMENT-UPDATE.md 12 KB

员工管理功能更新说明

🎯 更新内容

1. 修复会话激活组件样式导入错误 ✅

问题:SCSS 文件导入路径错误

// 错误路径
@use '../../../../shared/styles/_ios-theme.scss' as *;

// 正确路径
@use '../../../../app/shared/styles/_ios-theme.scss' as *;

修复文件src/modules/project/pages/chat-activation/chat-activation.component.scss


2. 优化员工管理手机号显示逻辑 ✅

问题分析

  • 员工手机号来源多样:企微同步、用户填写、Parse表字段
  • 需要优先显示企微手机号
  • 需要兼容多种数据结构

解决方案

数据优先级设置

字段 优先级 说明
name(昵称) wxwork.name > json.name > data.name 优先使用企微昵称,方便内部沟通
realname(真实姓名) data.realname 用户填写的真实姓名,用于正式场合
mobile(手机号) wxwork.mobile > data.mobile > json.mobile 优先使用企微手机号

代码实现

const empList: Employee[] = emps.map(e => {
  const json = this.employeeService.toJSON(e);
  const data = (e as any).get ? ((e as any).get('data') || {}) : {};
  const wxwork = data.wxworkInfo || {};
  
  // 优先级说明:
  // 1. name(昵称):优先使用企微昵称 wxwork.name
  // 2. realname(真实姓名):优先使用用户填写的 data.realname
  // 3. mobile(手机号):优先使用企微手机号 wxwork.mobile
  
  const wxworkName = wxwork.name || '';  // 企微昵称
  const wxworkMobile = wxwork.mobile || '';  // 企微手机号
  const dataMobile = data.mobile || '';  // data字段中的手机号
  const jsonMobile = json.mobile || '';  // Parse表字段的手机号
  
  // 手机号优先级:企微手机号 > data.mobile > json.mobile
  let finalMobile = wxworkMobile || dataMobile || jsonMobile || '';
  
  // 如果手机号为空或格式不对,尝试从其他字段获取
  if (!finalMobile || !/^1[3-9]\d{9}$/.test(finalMobile)) {
    finalMobile = data.phone || data.telephone || wxwork.telephone || jsonMobile || '';
  }
  
  return {
    id: json.objectId,
    name: wxworkName || json.name || data.name || '未知',  // 优先企微昵称
    realname: data.realname || '',  // 用户填写的真实姓名
    mobile: finalMobile,  // 优先企微手机号
    userid: json.userid || wxwork.userid || '',
    // ... 其他字段
  };
});

3. 页面显示逻辑优化 ✅

表格显示

<td>
  <div style="display:flex;align-items:center;gap:8px;">
    <img [src]="emp.avatar || '/assets/images/default-avatar.svg'" alt="" 
         style="width:32px;height:32px;border-radius:50%;object-fit:cover;"/>
    <div>
      <!-- 优先显示真实姓名,如果有昵称则括号显示 -->
      <div style="font-weight:600;">
        {{ emp.realname || emp.name }}
        <span style="font-size:12px;color:#999;font-weight:400;" *ngIf="emp.realname && emp.name">
          ({{ emp.name }})
        </span>
      </div>
      <div style="font-size:12px;color:#888;" *ngIf="emp.position">{{ emp.position }}</div>
    </div>
  </div>
</td>
<td>{{ emp.mobile }}</td>

显示效果

  • 如果有真实姓名:显示 "张三 (小张)"
  • 如果只有昵称:显示 "小张"
  • 手机号:显示企微同步的手机号

编辑表单

<!-- 真实姓名 -->
<div class="form-group">
  <label class="form-label required">真实姓名</label>
  <input 
    type="text" 
    class="form-input" 
    [(ngModel)]="formModel.realname"
    placeholder="请输入真实姓名(用于正式场合)"
    required
  />
  <div class="form-hint">用于正式文档、合同签署等场合</div>
</div>

<!-- 昵称 -->
<div class="form-group">
  <label class="form-label required">昵称</label>
  <input 
    type="text" 
    class="form-input" 
    [(ngModel)]="formModel.name"
    placeholder="请输入昵称(内部沟通用)"
    required
  />
  <div class="form-hint">用于日常沟通,可以是昵称、花名等</div>
</div>

<!-- 手机号 -->
<div class="form-group">
  <label class="form-label required">手机号</label>
  <input 
    type="tel" 
    class="form-input" 
    [(ngModel)]="formModel.mobile"
    placeholder="请输入手机号"
    maxlength="11"
    required
  />
</div>

📊 数据结构说明

Parse Profile 表结构

{
  objectId: String,           // 员工ID
  name: String,               // 昵称(内部沟通用)
  mobile: String,             // 手机号(Parse表字段)
  userid: String,             // 企微用户ID
  roleName: String,           // 身份(客服/组员/组长/人事/财务/管理员)
  department: Pointer,        // 部门关联
  isDisabled: Boolean,        // 是否禁用
  data: {                     // 扩展数据
    realname: String,         // 真实姓名(用户填写)
    mobile: String,           // 手机号(data字段)
    phone: String,            // 备用手机号字段
    telephone: String,        // 备用电话字段
    wxworkInfo: {             // 企微同步信息
      name: String,           // 企微昵称
      mobile: String,         // 企微手机号 ⭐ 优先使用
      userid: String,         // 企微用户ID
      avatar: String,         // 企微头像
      email: String,          // 企微邮箱
      position: String,       // 企微职位
      gender: String,         // 性别
      telephone: String       // 企微电话
    },
    avatar: String,           // 头像
    email: String,            // 邮箱
    gender: String,           // 性别
    level: String,            // 职级
    skills: Array,            // 技能列表
    joinDate: String,         // 入职日期
    workload: {               // 工作量统计
      currentProjects: Number,
      completedProjects: Number,
      averageQuality: Number
    }
  }
}

🔍 手机号获取逻辑

优先级顺序

// 1. 企微手机号(最优先)
const wxworkMobile = data.wxworkInfo?.mobile || '';

// 2. data字段中的手机号
const dataMobile = data.mobile || '';

// 3. Parse表字段的手机号
const jsonMobile = json.mobile || '';

// 4. 其他备用字段
const backupMobile = data.phone || data.telephone || wxwork.telephone || '';

// 最终手机号
let finalMobile = wxworkMobile || dataMobile || jsonMobile || backupMobile || '';

// 格式验证
if (!finalMobile || !/^1[3-9]\d{9}$/.test(finalMobile)) {
  // 尝试从备用字段获取
  finalMobile = backupMobile || '';
}

手机号格式验证

// 中国大陆手机号格式:1[3-9]开头,共11位数字
const mobileRegex = /^1[3-9]\d{9}$/;

if (!mobileRegex.test(mobile)) {
  alert('请输入正确的手机号格式');
  return;
}

🎨 显示效果

表格显示示例

姓名 手机号 企微ID 身份 部门 状态
张三 (小张) 13812345678 wxwork-001 组员 设计部 正常
李四 13987654321 wxwork-002 组长 设计部 正常
王五 (老王) 13611112222 wxwork-003 客服 客服部 正常

说明

  • 有真实姓名的显示 "真实姓名 (昵称)"
  • 只有昵称的显示 "昵称"
  • 手机号优先显示企微同步的号码

🔧 保存逻辑

更新员工信息

async updateEmployee() {
  if (!this.currentEmployee) return;

  // 表单验证
  if (!this.formModel.name?.trim()) {
    alert('请输入员工姓名');
    return;
  }

  if (!this.formModel.mobile?.trim()) {
    alert('请输入手机号');
    return;
  }

  // 手机号格式验证
  const mobileRegex = /^1[3-9]\d{9}$/;
  if (!mobileRegex.test(this.formModel.mobile)) {
    alert('请输入正确的手机号格式');
    return;
  }

  try {
    // 保存所有可编辑字段到后端数据库
    await this.employeeService.updateEmployee(this.currentEmployee.id, {
      name: this.formModel.name.trim(),          // 昵称
      mobile: this.formModel.mobile.trim(),      // 手机号
      roleName: this.formModel.roleName,         // 身份
      departmentId: this.formModel.departmentId, // 部门
      isDisabled: this.formModel.isDisabled || false,
      data: {
        realname: this.formModel.realname?.trim() || ''  // 真实姓名
      }
    });

    await this.loadEmployees();
    this.closePanel();
    alert('员工信息更新成功!');
  } catch (error) {
    console.error('更新员工失败:', error);
    alert('更新员工失败,请重试');
  }
}

✅ 测试清单

功能测试

  • 页面正常加载,无编译错误
  • 员工列表正确显示手机号
  • 优先显示企微手机号
  • 真实姓名和昵称正确显示
  • 编辑表单可以修改手机号
  • 手机号格式验证正常
  • 保存后数据正确更新

数据验证

// 测试数据示例
const testEmployee = {
  name: '小张',                    // 昵称
  data: {
    realname: '张三',              // 真实姓名
    mobile: '13800000000',         // data字段手机号
    wxworkInfo: {
      name: '张三(设计)',         // 企微昵称
      mobile: '13812345678'        // 企微手机号 ⭐ 应该显示这个
    }
  }
};

// 预期结果
// 显示姓名:张三 (张三(设计))
// 显示手机号:13812345678

📝 使用说明

1. 查看员工列表

访问:http://localhost:4200/admin/employees

  • 姓名列:优先显示真实姓名,括号显示昵称
  • 手机号列:显示企微同步的手机号
  • 可按身份筛选(客服/组员/组长/人事/财务)
  • 可搜索姓名、手机号、企微ID

2. 编辑员工信息

点击"编辑"按钮:

  1. 真实姓名:用于正式文档、合同签署
  2. 昵称:用于日常沟通,可以是花名
  3. 手机号:可以修改,会验证格式
  4. 企微ID:只读,不可修改
  5. 身份:选择员工角色
  6. 部门:选择所属部门

3. 数据来源说明

字段 来源 可编辑
企微昵称 企微同步
真实姓名 用户填写
昵称 企微同步/手动
手机号 企微同步/手动
企微ID 企微同步
头像 企微同步
身份 手动分配
部门 手动分配

🚀 部署说明

1. 编译项目

cd yss-project
ng build

2. 检查编译结果

确保没有错误:

  • ✅ SCSS 文件正常编译
  • ✅ TypeScript 无类型错误
  • ✅ 所有依赖正确导入

3. 测试功能

  1. 启动开发服务器:ng serve
  2. 访问员工管理页面
  3. 检查手机号显示是否正确
  4. 测试编辑保存功能

🐛 常见问题

Q1: 手机号显示为空?

原因:数据库中所有手机号字段都为空

解决

  1. 检查 data.wxworkInfo.mobile 字段
  2. 检查 data.mobile 字段
  3. 检查 json.mobile 字段
  4. 从企微重新同步员工数据

Q2: 昵称显示为"未知"?

原因:所有昵称字段都为空

解决

  1. 检查 data.wxworkInfo.name 字段
  2. 检查 json.name 字段
  3. 手动编辑员工信息填写昵称

Q3: 编辑后手机号没有更新?

原因:可能是保存逻辑问题

解决

  1. 检查浏览器控制台错误
  2. 确认 Parse 数据库连接正常
  3. 检查 updateEmployee 方法是否正确执行

📚 相关文档


更新时间: 2025-11-01
版本: v1.0.0
维护者: 开发团队