import { Injectable } from '@angular/core'; import { AdminDataService } from './admin-data.service'; import { FmodeObject, FmodeParse } from 'fmode-ng/core'; /** * 员工管理数据服务 (Profile表) */ @Injectable({ providedIn: 'root' }) export class EmployeeService { constructor(private adminData: AdminDataService) {} /** * 查询员工列表 */ async findEmployees(options?: { roleName?: string; departmentId?: string; keyword?: string; skip?: number; limit?: number; }): Promise { return await this.adminData.findAll('Profile', { include: ['department'], skip: options?.skip || 0, limit: options?.limit || 100, descending: 'createdAt', additionalQuery: query => { if (options?.roleName) { query.equalTo('roleName', options.roleName); } if (options?.departmentId) { query.equalTo('department', { __type: 'Pointer', className: 'Department', objectId: options.departmentId }); } if (options?.keyword) { const kw = options.keyword.trim(); if (kw) { query.matches('name', new RegExp(kw, 'i')); } } } }); } /** * 统计员工数量 */ async countEmployees(roleName?: string): Promise { return await this.adminData.count('Profile', query => { if (roleName) { query.equalTo('roleName', roleName); } }); } /** * 根据ID获取员工 */ async getEmployee(objectId: string): Promise { return await this.adminData.getById('Profile', objectId, ['department']); } /** * 创建员工 (注意: 员工从企微同步,实际可能不需要创建功能) */ async createEmployee(data: { name: string; mobile?: string; userId?: string; roleName: string; departmentId?: string; data?: any; }): Promise { const employeeData: any = { name: data.name, mobile: data.mobile || '', userId: data.userId || '', roleName: data.roleName }; if (data.departmentId) { employeeData.department = { __type: 'Pointer', className: 'Department', objectId: data.departmentId }; } if (data.data) { employeeData.data = data.data; } const employee = this.adminData.createObject('Profile', employeeData); return await this.adminData.save(employee); } /** * 更新员工 */ async updateEmployee( objectId: string, updates: { name?: string; mobile?: string; roleName?: string; departmentId?: string; isDisabled?: boolean; data?: any; } ): Promise { const employee = await this.getEmployee(objectId); if (!employee) { return null; } if (updates.name !== undefined) { employee.set('name', updates.name); } if (updates.mobile !== undefined) { employee.set('mobile', updates.mobile); } if (updates.roleName !== undefined) { employee.set('roleName', updates.roleName); } if (updates.departmentId !== undefined) { employee.set('department', { __type: 'Pointer', className: 'Department', objectId: updates.departmentId }); } if (updates.isDisabled !== undefined) { employee.set('isDisabled', updates.isDisabled); } if (updates.data !== undefined) { const currentData = employee.get('data') || {}; employee.set('data', { ...currentData, ...updates.data }); } return await this.adminData.save(employee); } /** * 禁用/启用员工 */ async toggleEmployee(objectId: string, isDisabled: boolean): Promise { const employee = await this.getEmployee(objectId); if (!employee) { return false; } employee.set('isDisabled', isDisabled); await this.adminData.save(employee); return true; } /** * 转换为JSON */ toJSON(employee: FmodeObject): any { const json = this.adminData.toJSON(employee); // 处理部门关联 if (json.department && typeof json.department === 'object') { json.departmentName = json.department.name || ''; json.departmentId = json.department.objectId; } return json; } /** * 批量转换 */ toJSONArray(employees: FmodeObject[]): any[] { return employees.map(e => this.toJSON(e)); } /** * 获取员工的项目负载数据 * 🔥 核心修复:完全参照组长端实现,通过 ProjectTeam 表查询(避免 OR 查询导致的 500 错误) * @param employeeId 员工ID(Profile表的objectId) * @returns 员工的项目统计信息 */ async getEmployeeWorkload(employeeId: string): Promise<{ currentProjects: number; completedProjects: number; ongoingProjects: any[]; completedProjectsList: any[]; }> { try { const Parse = FmodeParse.with("nova"); if (!Parse) { console.error('❌ [EmployeeService] Parse未初始化'); return { currentProjects: 0, completedProjects: 0, ongoingProjects: [], completedProjectsList: [] }; } const companyId = this.adminData.getCompanyPointer().objectId || 'cDL6R1hgSi'; const employeePointer = { __type: 'Pointer', className: 'Profile', objectId: employeeId }; console.log(`🔍 [EmployeeService] 查询员工项目负载:`, { 员工ID: employeeId, 公司ID: companyId }); // 🔥 方案1:优先通过 ProjectTeam 表查询(组长端的方式,最稳定) console.log(`🔍 [EmployeeService] 通过 ProjectTeam 查询员工 ${employeeId} 的项目...`); const projectQuery = new Parse.Query('Project'); projectQuery.equalTo('company', companyId); projectQuery.notEqualTo('isDeleted', true); projectQuery.select('title', 'status', 'currentStage', 'deadline', 'createdAt', 'completedAt', 'updatedAt'); const teamQuery = new Parse.Query('ProjectTeam'); teamQuery.equalTo('profile', employeePointer); teamQuery.notEqualTo('isDeleted', true); teamQuery.matchesQuery('project', projectQuery); teamQuery.include('project'); teamQuery.limit(1000); const teamRecords = await teamQuery.find(); const allProjects = teamRecords .map((r: any) => r.get('project')) .filter((p: any) => !!p); console.log(`✅ [EmployeeService] 通过 ProjectTeam 找到 ${allProjects.length} 个项目`); // 🔥 方案2:补充查询 Project.assignee(兼容旧数据/未用 ProjectTeam 的项目) console.log(`🔍 [EmployeeService] 补充查询 Project.assignee 字段...`); let assigneeProjects: any[] = []; try { const assigneeQuery = new Parse.Query('Project'); assigneeQuery.equalTo('company', companyId); assigneeQuery.equalTo('assignee', employeePointer); assigneeQuery.notEqualTo('isDeleted', true); assigneeQuery.select('title', 'status', 'currentStage', 'deadline', 'createdAt', 'completedAt', 'updatedAt'); assigneeQuery.limit(1000); assigneeProjects = await assigneeQuery.find(); console.log(`✅ [EmployeeService] 通过 assignee 找到 ${assigneeProjects.length} 个项目`); } catch (assigneeErr) { console.warn('⚠️ [EmployeeService] 查询 assignee 失败(忽略):', assigneeErr); } // 合并两种途径的项目(去重) const projectMap = new Map(); [...allProjects, ...assigneeProjects].forEach(p => { if (p && p.id) { projectMap.set(p.id, p); } }); const mergedProjects = Array.from(projectMap.values()); console.log(`✅ [EmployeeService] 合并去重后共 ${mergedProjects.length} 个项目`); // 按状态和阶段分类 const ongoingProjects: any[] = []; const completedProjects: any[] = []; for (const p of mergedProjects) { const status = p.get('status'); const stage = p.get('currentStage'); // 进行中:待分配、进行中 if (['待分配', '进行中'].includes(status)) { ongoingProjects.push(p); } // 已完成:已完成、已归档,或售后归档阶段 else if (['已完成', '已归档'].includes(status) || stage === '售后归档') { completedProjects.push(p); } } console.log(`✅ [EmployeeService] 项目分类: 进行中 ${ongoingProjects.length} 个, 已完成 ${completedProjects.length} 个`); // 转换为简单对象 const ongoingList = ongoingProjects.map(p => ({ id: p.id, name: p.get('title') || '未命名项目', status: p.get('status'), currentStage: p.get('currentStage'), deadline: p.get('deadline'), createdAt: p.get('createdAt') })); const completedList = completedProjects.map(p => ({ id: p.id, name: p.get('title') || '未命名项目', status: p.get('status'), currentStage: p.get('currentStage'), completedAt: p.get('completedAt') || p.get('updatedAt'), createdAt: p.get('createdAt') })); return { currentProjects: ongoingList.length, completedProjects: completedList.length, ongoingProjects: ongoingList, completedProjectsList: completedList }; } catch (error: any) { console.error('❌ [EmployeeService] 获取员工项目负载失败:', error); console.error('错误详情:', { message: error?.message, code: error?.code, stack: error?.stack?.split('\n').slice(0, 3) }); return { currentProjects: 0, completedProjects: 0, ongoingProjects: [], completedProjectsList: [] }; } } }