import { Injectable } from '@angular/core'; import { FmodeParse } from 'fmode-ng/parse'; export interface DesignerTask { id: string; projectId: string; projectName: string; stage: string; deadline: Date; isOverdue: boolean; priority: 'high' | 'medium' | 'low'; customerName: string; space?: string; // 空间名称(如"主卧") productId?: string; // 关联的Product ID } @Injectable({ providedIn: 'root' }) export class DesignerTaskService { private Parse: any = null; private cid: string = ''; constructor() { this.initParse(); } private async initParse(): Promise { try { const { FmodeParse } = await import('fmode-ng/parse'); this.Parse = FmodeParse.with('nova'); this.cid = localStorage.getItem('company') || ''; } catch (error) { console.error('DesignerTaskService: Parse初始化失败:', error); } } /** * 获取当前设计师的任务列表 * @param designerId Profile的objectId */ async getMyTasks(designerId: string): Promise { if (!this.Parse) await this.initParse(); if (!this.Parse || !this.cid) { console.error('❌ Parse 未初始化或缺少 CID'); return []; } try { console.log('🔍 开始查询设计师任务,Profile ID:', designerId); console.log('📋 当前公司 ID:', this.cid); // 方案1:从ProjectTeam表查询(设计师实际负责的项目) const ProfileClass = this.Parse.Object.extend('Profile'); const profilePointer = new ProfileClass(); profilePointer.id = designerId; const teamQuery = new this.Parse.Query('ProjectTeam'); teamQuery.equalTo('profile', profilePointer); teamQuery.notEqualTo('isDeleted', true); teamQuery.include('project'); teamQuery.include('project.contact'); teamQuery.limit(1000); console.log('🔍 查询 ProjectTeam 表...'); const teamRecords = await teamQuery.find(); console.log(`✅ ProjectTeam 查询结果: ${teamRecords.length} 条记录`); if (teamRecords.length === 0) { console.warn('⚠️ ProjectTeam 表中未找到该设计师的项目'); console.log('🔄 尝试降级方案:从 Project.assignee 查询'); return await this.getMyTasksFromAssignee(designerId); } console.log('📋 ProjectTeam 记录详情:'); teamRecords.forEach((record: any, index: number) => { const project = record.get('project'); console.log(` ${index + 1}. 项目:`, { projectId: project?.id, projectName: project?.get('title'), currentStage: project?.get('currentStage'), status: project?.get('status') }); }); const tasks: DesignerTask[] = []; for (const teamRecord of teamRecords) { try { const project = teamRecord.get('project'); if (!project) { console.warn('⚠️ ProjectTeam 记录缺少 project 对象,跳过'); continue; } const projectId = project.id; const projectName = project.get('title') || '未命名项目'; const currentStage = project.get('currentStage') || '未知'; // 安全获取 deadline let deadline = project.get('deadline') || project.get('deliveryDate') || project.get('expectedDeliveryDate'); if (!deadline) { deadline = new Date(); console.warn(`⚠️ 项目 ${projectName} 缺少 deadline,使用当前时间`); } const contact = project.get('contact'); const customerName = contact?.get('name') || '未知客户'; console.log(`✅ 处理项目: ${projectName} (${projectId})`); // 查询该项目下该设计师负责的Product(空间设计产品) let products: any[] = []; try { const ProfileClass = this.Parse.Object.extend('Profile'); const profilePointer = new ProfileClass(); profilePointer.id = designerId; const productQuery = new this.Parse.Query('Product'); productQuery.equalTo('project', project); productQuery.equalTo('profile', profilePointer); productQuery.notEqualTo('isDeleted', true); productQuery.containedIn('status', ['in_progress', 'awaiting_review']); console.log(`🔍 查询项目 ${projectName} 的 Product...`); products = await productQuery.find(); console.log(`✅ 找到 ${products.length} 个 Product`); } catch (productError: any) { console.warn(`⚠️ Product 查询失败,将创建项目级任务`); console.warn(`⚠️ Product 错误:`, productError.message || productError.toString()); products = []; // 查询失败时视为没有 Product } if (products.length === 0) { // 如果没有具体的Product,创建项目级任务 console.log(`📝 创建项目级任务: ${projectName}`); tasks.push({ id: projectId, projectId, projectName, stage: currentStage, deadline: new Date(deadline), isOverdue: new Date(deadline) < new Date(), priority: this.calculatePriority(deadline, currentStage), customerName }); } else { // 如果有Product,为每个Product创建任务 console.log(`📝 为 ${products.length} 个 Product 创建任务`); products.forEach((product: any) => { const productName = product.get('productName') || '未命名空间'; const productStage = product.get('stage') || currentStage; tasks.push({ id: `${projectId}-${product.id}`, projectId, projectName: `${projectName} - ${productName}`, stage: productStage, deadline: new Date(deadline), isOverdue: new Date(deadline) < new Date(), priority: this.calculatePriority(deadline, productStage), customerName, space: productName, productId: product.id }); }); } } catch (recordError: any) { console.error('❌ 处理 ProjectTeam 记录时出错'); console.error('❌ 错误类型:', typeof recordError); // Parse 错误对象特殊处理 const errorDetails: any = {}; for (const key in recordError) { if (recordError.hasOwnProperty(key)) { errorDetails[key] = recordError[key]; } } console.error('❌ 错误对象属性:', errorDetails); console.error('❌ 完整错误:', recordError); if (recordError.message) console.error('❌ 错误消息:', recordError.message); if (recordError.code) console.error('❌ Parse错误代码:', recordError.code); if (recordError.stack) console.error('❌ 错误堆栈:', recordError.stack); continue; } } // 按截止日期排序 tasks.sort((a, b) => a.deadline.getTime() - b.deadline.getTime()); console.log(`✅ 成功加载 ${tasks.length} 个任务`); return tasks; } catch (error: any) { console.error('❌ 获取设计师任务失败'); console.error('❌ 错误类型:', typeof error); // Parse 错误对象特殊处理 const errorDetails: any = {}; for (const key in error) { if (error.hasOwnProperty(key)) { errorDetails[key] = error[key]; } } console.error('❌ 错误对象属性:', errorDetails); console.error('❌ 完整错误:', error); if (error.message) console.error('❌ 错误消息:', error.message); if (error.code) console.error('❌ Parse错误代码:', error.code); if (error.stack) console.error('❌ 错误堆栈:', error.stack); return []; } } /** * 计算任务优先级 */ private calculatePriority(deadline: Date, stage: string): 'high' | 'medium' | 'low' { const now = new Date(); const daysLeft = Math.ceil((new Date(deadline).getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); // 超期或临期(3天内) if (daysLeft < 0 || daysLeft <= 3) { return 'high'; } // 渲染阶段优先级高 if (stage === 'rendering' || stage === '渲染') { return 'high'; } // 7天内 if (daysLeft <= 7) { return 'medium'; } return 'low'; } /** * 方案2:从Project.assignee查询(降级方案) */ async getMyTasksFromAssignee(designerId: string): Promise { if (!this.Parse) await this.initParse(); if (!this.Parse || !this.cid) { console.error('❌ [降级方案] Parse 未初始化或缺少 CID'); return []; } try { console.log('🔍 [降级方案] 从 Project.assignee 查询,Profile ID:', designerId); const ProfileClass = this.Parse.Object.extend('Profile'); const profilePointer = new ProfileClass(); profilePointer.id = designerId; const query = new this.Parse.Query('Project'); query.equalTo('assignee', profilePointer); query.equalTo('company', this.cid); query.containedIn('status', ['进行中', '待审核']); query.notEqualTo('isDeleted', true); query.include('contact'); query.ascending('deadline'); query.limit(1000); console.log('🔍 [降级方案] 查询 Project 表...'); const projects = await query.find(); console.log(`✅ [降级方案] 从Project.assignee加载 ${projects.length} 个项目`); if (projects.length > 0) { console.log('📋 [降级方案] 项目详情:'); projects.forEach((project: any, index: number) => { console.log(` ${index + 1}. 项目:`, { projectId: project.id, projectName: project.get('title'), currentStage: project.get('currentStage'), status: project.get('status'), deadline: project.get('deadline') }); }); } else { console.warn('⚠️ [降级方案] 也未找到项目'); console.log('💡 提示:请检查 ProjectTeam 或 Project.assignee 字段是否正确设置'); } return projects.map((project: any) => { const deadline = project.get('deadline') || project.get('deliveryDate') || project.get('expectedDeliveryDate') || new Date(); const currentStage = project.get('currentStage') || '未知'; const contact = project.get('contact'); return { id: project.id, projectId: project.id, projectName: project.get('title') || '未命名项目', stage: currentStage, deadline: new Date(deadline), isOverdue: new Date(deadline) < new Date(), priority: this.calculatePriority(deadline, currentStage), customerName: contact?.get('name') || '未知客户' }; }); } catch (error: any) { console.error('❌ [降级方案] 从Project.assignee获取任务失败'); console.error('❌ 错误类型:', typeof error); // Parse 错误对象特殊处理 const errorDetails: any = {}; for (const key in error) { if (error.hasOwnProperty(key)) { errorDetails[key] = error[key]; } } console.error('❌ 错误对象属性:', errorDetails); console.error('❌ 完整错误:', error); if (error.message) console.error('❌ 错误消息:', error.message); if (error.code) console.error('❌ Parse错误代码:', error.code); if (error.stack) console.error('❌ 错误堆栈:', error.stack); return []; } } }