| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- 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<FmodeObject[]> {
- 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<number> {
- return await this.adminData.count('Profile', query => {
- if (roleName) {
- query.equalTo('roleName', roleName);
- }
- });
- }
- /**
- * 根据ID获取员工
- */
- async getEmployee(objectId: string): Promise<FmodeObject | null> {
- return await this.adminData.getById('Profile', objectId, ['department']);
- }
- /**
- * 创建员工 (注意: 员工从企微同步,实际可能不需要创建功能)
- */
- async createEmployee(data: {
- name: string;
- mobile?: string;
- userId?: string;
- roleName: string;
- departmentId?: string;
- data?: any;
- }): Promise<FmodeObject> {
- 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<FmodeObject | null> {
- 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<boolean> {
- 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<string, any>();
- [...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: [] };
- }
- }
- }
|