| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707 | 
							- import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
 
- import { CommonModule } from '@angular/common';
 
- import { Router, ActivatedRoute, RouterModule } from '@angular/router';
 
- import { IonicModule } from '@ionic/angular';
 
- import { WxworkSDK, WxworkCorp, WxworkAuth } from 'fmode-ng/core';
 
- import { FmodeParse, FmodeObject } from 'fmode-ng/parse';
 
- import { ProfileService } from '../../../../app/services/profile.service';
 
- import { ProjectBottomCardComponent } from '../../components/project-bottom-card/project-bottom-card.component';
 
- import { ProjectFilesModalComponent } from '../../components/project-files-modal/project-files-modal.component';
 
- import { ProjectMembersModalComponent } from '../../components/project-members-modal/project-members-modal.component';
 
- import { ProjectIssuesModalComponent } from '../../components/project-issues-modal/project-issues-modal.component';
 
- import { ProjectIssueService } from '../../services/project-issue.service';
 
- import { FormsModule } from '@angular/forms';
 
- import { CustomerSelectorComponent } from '../../components/contact-selector/contact-selector.component';
 
- import { OrderApprovalPanelComponent } from '../../../../app/shared/components/order-approval-panel/order-approval-panel.component';
 
- import { GroupChatSummaryComponent } from '../../components/group-chat-summary/group-chat-summary.component';
 
- const Parse = FmodeParse.with('nova');
 
- /**
 
-  * 项目详情核心组件
 
-  *
 
-  * 功能:
 
-  * 1. 展示四阶段导航(订单分配、确认需求、交付执行、售后归档)
 
-  * 2. 根据角色控制权限
 
-  * 3. 子路由切换阶段内容
 
-  * 4. 支持@Input和路由参数两种数据加载方式
 
-  *
 
-  * 路由:/wxwork/:cid/project/:projectId
 
-  */
 
- @Component({
 
-   selector: 'app-project-detail',
 
-   standalone: true,
 
-   imports: [
 
-     CommonModule,
 
-     IonicModule,
 
-     RouterModule,
 
-     ProjectBottomCardComponent,
 
-     ProjectFilesModalComponent,
 
-     ProjectMembersModalComponent,
 
-     ProjectIssuesModalComponent,
 
-     CustomerSelectorComponent,
 
-     OrderApprovalPanelComponent,
 
-     GroupChatSummaryComponent
 
-   ],
 
-   templateUrl: './project-detail.component.html',
 
-   styleUrls: ['./project-detail.component.scss']
 
- })
 
- export class ProjectDetailComponent implements OnInit {
 
-   // 输入参数(支持组件复用)
 
-   @Input() project: FmodeObject | null = null;
 
-   @Input() groupChat: FmodeObject | null = null;
 
-   @Input() currentUser: FmodeObject | null = null;
 
-   // 问题统计
 
-   issueCount: number = 0;
 
-   // 路由参数
 
-   cid: string = '';
 
-   projectId: string = '';
 
-   groupId: string = '';
 
-   profileId: string = '';
 
-   chatId: string = ''; // 从企微进入时的 chat_id
 
-   // 企微SDK
 
-   wxwork: WxworkSDK | null = null;
 
-   wecorp: WxworkCorp | null = null;
 
-   wxAuth: WxworkAuth | null = null; // WxworkAuth 实例
 
-   // 加载状态
 
-   loading: boolean = true;
 
-   error: string | null = null;
 
-   // 项目数据
 
-   contact: FmodeObject | null = null;
 
-   assignee: FmodeObject | null = null;
 
-   // 当前阶段
 
-   currentStage: string = 'order'; // order | requirements | delivery | aftercare
 
-   stages = [
 
-     { id: 'order', name: '订单分配', icon: 'document-text-outline', number: 1 },
 
-     { id: 'requirements', name: '确认需求', icon: 'checkmark-circle-outline', number: 2 },
 
-     { id: 'delivery', name: '交付执行', icon: 'rocket-outline', number: 3 },
 
-     { id: 'aftercare', name: '售后归档', icon: 'archive-outline', number: 4 }
 
-   ];
 
-   // 权限
 
-   canEdit: boolean = false;
 
-   canViewCustomerPhone: boolean = false;
 
-   role: string = '';
 
-   // 模态框状态
 
-   showFilesModal: boolean = false;
 
-   showMembersModal: boolean = false;
 
-   showIssuesModal: boolean = false;
 
-   // 新增:客户详情侧栏面板状态
 
-   showContactPanel: boolean = false;
 
-   // 问卷状态
 
-   surveyStatus: {
 
-     filled: boolean;
 
-     text: string;
 
-     icon: string;
 
-     surveyLog?: FmodeObject;
 
-     contact?: FmodeObject;
 
-   } = {
 
-     filled: false,
 
-     text: '发送问卷',
 
-     icon: 'document-text-outline'
 
-   };
 
-   constructor(
 
-     private router: Router,
 
-     private route: ActivatedRoute,
 
-     private profileService: ProfileService,
 
-     private issueService: ProjectIssueService
 
-   ) {}
 
-   async ngOnInit() {
 
-     // 获取路由参数
 
-     this.cid = this.route.snapshot.paramMap.get('cid') || '';
 
-     this.projectId = this.route.snapshot.paramMap.get('projectId') || '';
 
-     this.groupId = this.route.snapshot.queryParamMap.get('groupId') || '';
 
-     this.profileId = this.route.snapshot.queryParamMap.get('profileId') || '';
 
-     this.chatId = this.route.snapshot.queryParamMap.get('chatId') || '';
 
-     // 监听路由变化
 
-     this.route.firstChild?.url.subscribe((segments) => {
 
-       if (segments.length > 0) {
 
-         this.currentStage = segments[0].path;
 
-       }
 
-     });
 
-     // 初始化企微授权(不阻塞页面加载)
 
-     await this.initWxworkAuth();
 
-     await this.loadData();
 
-   }
 
-   /**
 
-    * 初始化企微授权(不阻塞页面)
 
-    */
 
-   async initWxworkAuth() {
 
-     try {
 
-       let cid = this.cid || localStorage.getItem("company") || "";
 
-       
 
-       // 如果没有cid,记录警告但不抛出错误
 
-       if (!cid) {
 
-         console.warn('⚠️ 未找到company ID (cid),企微功能将不可用');
 
-         return;
 
-       }
 
-       
 
-       this.wxAuth = new WxworkAuth({ cid: cid });
 
-       this.wxwork = new WxworkSDK({ cid: cid, appId: 'crm' });
 
-       this.wecorp = new WxworkCorp(cid);
 
-       
 
-       console.log('✅ 企微SDK初始化成功,cid:', cid);
 
-     } catch (error) {
 
-       console.error('❌ 企微SDK初始化失败:', error);
 
-       // 不阻塞页面加载
 
-     }
 
-   }
 
-   /**
 
-    * 加载数据
 
-    */
 
-   async loadData() {
 
-     try {
 
-       this.loading = true;
 
-       // 2. 获取当前用户(优先从全局服务获取)
 
-       if (!this.currentUser?.id && this.wxAuth) {
 
-         try {
 
-           this.currentUser = await this.wxAuth.currentProfile();
 
-         } catch (error) {
 
-           console.warn('⚠️ 获取当前用户Profile失败:', error);
 
-         }
 
-       }
 
-       // 设置权限
 
-       this.role = this.currentUser?.get('roleName') || '';
 
-       this.canEdit = ['客服', '组员', '组长', '管理员'].includes(this.role);
 
-       this.canViewCustomerPhone = ['客服', '组长', '管理员'].includes(this.role);
 
-       const companyId = this.currentUser?.get('company')?.id || localStorage?.getItem("company");
 
-           // 3. 加载项目
 
-       if (!this.project) {
 
-         if (this.projectId) {
 
-           // 通过 projectId 加载(从后台进入)
 
-           const query = new Parse.Query('Project');
 
-           query.include('contact', 'assignee','department','department.leader');
 
-           this.project = await query.get(this.projectId);
 
-         } else if (this.chatId) {
 
-           // 通过 chat_id 查找项目(从企微群聊进入)
 
-           if (companyId) {
 
-             // 先查找 GroupChat
 
-             const gcQuery = new Parse.Query('GroupChat');
 
-             gcQuery.equalTo('chat_id', this.chatId);
 
-             gcQuery.equalTo('company', companyId);
 
-             let groupChat = await gcQuery.first();
 
-             if (groupChat) {
 
-               this.groupChat = groupChat;
 
-               const projectPointer = groupChat.get('project');
 
-               if (projectPointer) {
 
-                 const pQuery = new Parse.Query('Project');
 
-                 pQuery.include('contact', 'assignee','department','department.leader');
 
-                 this.project = await pQuery.get(projectPointer.id);
 
-               }
 
-             }
 
-             if (!this.project) {
 
-               throw new Error('该群聊尚未关联项目,请先在后台创建项目');
 
-             }
 
-           }
 
-         }
 
-       }
 
-      
 
-       if(!this.groupChat?.id){
 
-         const gcQuery2 = new Parse.Query('GroupChat');
 
-         gcQuery2.equalTo('project', this.projectId);
 
-         gcQuery2.equalTo('company', companyId);
 
-         this.groupChat = await gcQuery2.first();
 
-       }
 
-       this.wxwork?.syncGroupChat(this.groupChat?.toJSON())
 
-       if (!this.project) {
 
-         throw new Error('无法加载项目信息');
 
-       }
 
-       this.contact = this.project.get('contact');
 
-       this.assignee = this.project.get('assignee');
 
-       // 加载问卷状态
 
-       await this.loadSurveyStatus();
 
-       // 更新问题计数
 
-       try {
 
-         if (this.project?.id) {
 
-           this.issueService.seed(this.project.id!);
 
-           const counts = this.issueService.getCounts(this.project.id!);
 
-           this.issueCount = counts.total;
 
-         }
 
-       } catch (e) {
 
-         console.warn('统计问题数量失败:', e);
 
-       }
 
-       // 4. 加载群聊(如果没有传入且有groupId)
 
-       if (!this.groupChat && this.groupId) {
 
-         try {
 
-           const gcQuery = new Parse.Query('GroupChat');
 
-           this.groupChat = await gcQuery.get(this.groupId);
 
-         } catch (err) {
 
-           console.warn('加载群聊失败:', err);
 
-         }
 
-       }
 
-       // 5. 根据项目当前阶段设置默认路由
 
-       const projectStage = this.project.get('currentStage');
 
-       const stageMap: any = {
 
-         '订单分配': 'order',
 
-         '确认需求': 'requirements',
 
-         '方案确认': 'requirements',
 
-         '方案深化': 'requirements',
 
-         '交付执行': 'delivery',
 
-         '建模': 'delivery',
 
-         '软装': 'delivery',
 
-         '渲染': 'delivery',
 
-         '后期': 'delivery',
 
-         '尾款结算': 'aftercare',
 
-         '客户评价': 'aftercare',
 
-         '投诉处理': 'aftercare'
 
-       };
 
-       const targetStage = stageMap[projectStage] || 'order';
 
-       // 如果当前没有子路由,跳转到对应阶段
 
-       if (!this.route.firstChild) {
 
-         this.router.navigate([targetStage], { relativeTo: this.route, replaceUrl: true });
 
-       }
 
-     } catch (err: any) {
 
-       console.error('加载失败:', err);
 
-       this.error = err.message || '加载失败';
 
-     } finally {
 
-       this.loading = false;
 
-     }
 
-   }
 
-   /**
 
-    * 切换阶段
 
-    */
 
-   switchStage(stageId: string) {
 
-     this.currentStage = stageId;
 
-     this.router.navigate([stageId], { relativeTo: this.route });
 
-   }
 
-   /**
 
-    * 获取阶段状态
 
-    */
 
-   getStageStatus(stageId: string): 'completed' | 'active' | 'pending' {
 
-     const projectStage = this.project?.get('currentStage') || '';
 
-     const stageOrder = ['订单分配', '确认需求', '建模', '软装', '渲染', '后期', '尾款结算', '客户评价'];
 
-     const currentIndex = stageOrder.indexOf(projectStage);
 
-     const stageIndexMap: any = {
 
-       'order': 0,
 
-       'requirements': 1,
 
-       'delivery': 3,
 
-       'aftercare': 6
 
-     };
 
-     const targetIndex = stageIndexMap[stageId];
 
-     if (currentIndex > targetIndex) {
 
-       return 'completed';
 
-     } else if (this.currentStage === stageId) {
 
-       return 'active';
 
-     } else {
 
-       return 'pending';
 
-     }
 
-   }
 
-   /**
 
-    * 返回
 
-    */
 
-   goBack() {
 
-     let ua = navigator.userAgent.toLowerCase();
 
-     let isWeixin = ua.indexOf("micromessenger") != -1;
 
-     if(isWeixin){
 
-       this.router.navigate(['/wxwork', this.cid, 'project-loader']);
 
-     }else{
 
-       history.back();
 
-     }
 
-   }
 
-   /**
 
-    * 更新项目阶段
 
-    */
 
-   async updateProjectStage(stage: string) {
 
-     if (!this.project || !this.canEdit) return;
 
-     try {
 
-       this.project.set('currentStage', stage);
 
-       await this.project.save();
 
-       // 添加阶段历史
 
-       const data = this.project.get('data') || {};
 
-       const stageHistory = data.stageHistory || [];
 
-       stageHistory.push({
 
-         stage,
 
-         startTime: new Date(),
 
-         status: 'current',
 
-         operator: {
 
-           id: this.currentUser!.id,
 
-           name: this.currentUser!.get('name'),
 
-           role: this.role
 
-         }
 
-       });
 
-       this.project.set('data', { ...data, stageHistory });
 
-       await this.project.save();
 
-     } catch (err) {
 
-       console.error('更新阶段失败:', err);
 
-      window?.fmode?.alert('更新失败');
 
-     }
 
-   }
 
-   /**
 
-    * 发送企微消息
 
-    */
 
-   async sendWxMessage(message: string) {
 
-     if (!this.groupChat || !this.wecorp) return;
 
-     try {
 
-       const chatId = this.groupChat.get('chat_id');
 
-       await this.wecorp.appchat.sendText(chatId, message);
 
-     } catch (err) {
 
-       console.error('发送消息失败:', err);
 
-     }
 
-   }
 
-   /**
 
-    * 选择客户(从群聊成员中选择外部联系人)
 
-    */
 
-   async selectCustomer() {
 
-     console.log(this.canEdit, this.groupChat)
 
-     if (!this.groupChat) return;
 
-     try {
 
-       const memberList = this.groupChat.get('member_list') || [];
 
-       const externalMembers = memberList.filter((m: any) => m.type === 2);
 
-       if (externalMembers.length === 0) {
 
-        window?.fmode?.alert('当前群聊中没有外部联系人');
 
-         return;
 
-       }
 
-       console.log(externalMembers)
 
-       // 简单实现:选择第一个外部联系人
 
-       // TODO: 实现选择器UI
 
-       const selectedMember = externalMembers[0];
 
-       await this.setCustomerFromMember(selectedMember);
 
-     } catch (err) {
 
-       console.error('选择客户失败:', err);
 
-      window?.fmode?.alert('选择客户失败');
 
-     }
 
-   }
 
-   /**
 
-    * 从群成员设置客户
 
-    */
 
-   async setCustomerFromMember(member: any) {
 
-     if (!this.wecorp) return;
 
-     try {
 
-       const companyId = this.currentUser?.get('company')?.id || localStorage.getItem("company");
 
-       if (!companyId) throw new Error('无法获取企业信息');
 
-       // 1. 查询是否已存在 ContactInfo
 
-       const query = new Parse.Query('ContactInfo');
 
-       query.equalTo('external_userid', member.userid);
 
-       query.equalTo('company', companyId);
 
-       let contactInfo = await query.first();
 
-       // 2. 如果不存在,通过企微API获取并创建
 
-       if (!contactInfo) {
 
-         contactInfo = new Parse.Object("ContactInfo");
 
-       }
 
-         const externalContactData = await this.wecorp.externalContact.get(member.userid);
 
-         console.log("externalContactData",externalContactData)
 
-         const ContactInfo = Parse.Object.extend('ContactInfo');
 
-         contactInfo.set('name', externalContactData.name);
 
-         contactInfo.set('external_userid', member.userid);
 
-         const company = new Parse.Object('Company');
 
-         company.id = companyId;
 
-         const companyPointer = company.toPointer();
 
-         contactInfo.set('company', companyPointer);
 
-         contactInfo.set('data', externalContactData);
 
-         await contactInfo.save();
 
-       // 3. 设置为项目客户
 
-       if (this.project) {
 
-         this.project.set('contact', contactInfo.toPointer());
 
-         await this.project.save();
 
-         this.contact = contactInfo;
 
-        window?.fmode?.alert('客户设置成功');
 
-       }
 
-     } catch (err) {
 
-       console.error('设置客户失败:', err);
 
-       throw err;
 
-     }
 
-   }
 
-   /**
 
-    * 显示文件模态框
 
-    */
 
-   showFiles() {
 
-     this.showFilesModal = true;
 
-   }
 
-   /**
 
-    * 显示成员模态框
 
-    */
 
-   showMembers() {
 
-     this.showMembersModal = true;
 
-   }
 
-   /** 显示问题模态框 */
 
-   showIssues() {
 
-     this.showIssuesModal = true;
 
-   }
 
-   /**
 
-    * 关闭文件模态框
 
-    */
 
-   closeFilesModal() {
 
-     this.showFilesModal = false;
 
-   }
 
-   /**
 
-    * 关闭成员模态框
 
-    */
 
-   closeMembersModal() {
 
-     this.showMembersModal = false;
 
-   }
 
-   /** 显示客户详情面板 */
 
-   openContactPanel() {
 
-     if (this.contact) {
 
-       this.showContactPanel = true;
 
-     }
 
-   }
 
-   /** 关闭客户详情面板 */
 
-   closeContactPanel() {
 
-     this.showContactPanel = false;
 
-   }
 
-   /** 关闭问题模态框 */
 
-   closeIssuesModal() {
 
-     this.showIssuesModal = false;
 
-     if (this.project?.id) {
 
-       const counts = this.issueService.getCounts(this.project.id!);
 
-       this.issueCount = counts.total;
 
-     }
 
-   }
 
-   /** 客户选择事件回调(接收子组件输出) */
 
-   onContactSelected(evt: { contact: FmodeObject; isNewCustomer: boolean; action: 'selected' | 'created' | 'updated' }) {
 
-     this.contact = evt.contact;
 
-     // 重新加载问卷状态
 
-     this.loadSurveyStatus();
 
-   }
 
-   /**
 
-    * 加载问卷状态
 
-    */
 
-   async loadSurveyStatus() {
 
-     if (!this.project?.id) return;
 
-     try {
 
-       const query = new Parse.Query('SurveyLog');
 
-       query.equalTo('project', this.project.toPointer());
 
-       query.equalTo('type', 'survey-project');
 
-       query.equalTo('isCompleted', true);
 
-       query.include("contact")
 
-       const surveyLog = await query.first();
 
-       if (surveyLog) {
 
-         this.surveyStatus = {
 
-           filled: true,
 
-           text: '查看问卷',
 
-           icon: 'checkmark-circle',
 
-           surveyLog,
 
-           contact:surveyLog?.get("contact")
 
-         };
 
-         console.log('✅ 问卷已填写');
 
-       } else {
 
-         this.surveyStatus = {
 
-           filled: false,
 
-           text: '发送问卷',
 
-           icon: 'document-text-outline'
 
-         };
 
-         console.log('✅ 问卷未填写');
 
-       }
 
-     } catch (err) {
 
-       console.error('❌ 查询问卷状态失败:', err);
 
-     }
 
-   }
 
-   /**
 
-    * 发送问卷
 
-    */
 
-   async sendSurvey() {
 
-     if (!this.groupChat || !this.wxwork) {
 
-      window?.fmode?.alert('无法发送问卷:未找到群聊或企微SDK未初始化');
 
-       return;
 
-     }
 
-     try {
 
-       const chatId = this.groupChat.get('chat_id');
 
-       const surveyUrl = `${document.baseURI}/wxwork/${this.cid}/survey/project/${this.project?.id}`;
 
-       await this.wxwork.ww.openExistedChatWithMsg({
 
-         chatId: chatId,
 
-         msg: {
 
-           msgtype: 'link',
 
-           link: {
 
-             title: '《家装效果图服务需求调查表》',
 
-             desc: '为让本次服务更贴合您的需求,请花3-5分钟填写简短问卷,感谢支持!',
 
-             url: surveyUrl,
 
-             imgUrl: `${document.baseURI}/assets/logo.jpg`
 
-           }
 
-         }
 
-       });
 
-      window?.fmode?.alert('问卷已发送到群聊!');
 
-     } catch (err) {
 
-       console.error('❌ 发送问卷失败:', err);
 
-      window?.fmode?.alert('发送失败,请重试');
 
-     }
 
-   }
 
-   /**
 
-    * 查看问卷结果
 
-    */
 
-   async viewSurvey() {
 
-     if (!this.surveyStatus.surveyLog) return;
 
-     // 跳转到问卷页面查看结果
 
-     this.router.navigate(['/wxwork', this.cid, 'survey', 'project', this.project?.id]);
 
-   }
 
-   /**
 
-    * 处理问卷点击
 
-    */
 
-   async handleSurveyClick(event: Event) {
 
-     event.stopPropagation();
 
-     if (this.surveyStatus.filled) {
 
-       // 已填写,查看结果
 
-       await this.viewSurvey();
 
-     } else {
 
-       // 未填写,发送问卷
 
-       await this.sendSurvey();
 
-     }
 
-   }
 
-   /**
 
-    * 是否显示审批面板
 
-    * 条件:当前用户是组长 + 项目处于订单分配阶段 + 审批状态为待审批
 
-    * ⚠️ 临时放开权限:允许所有角色查看审批面板(测试用)
 
-    */
 
-   get showApprovalPanel(): boolean {
 
-     if (!this.project || !this.currentUser) {
 
-       console.log('🔍 审批面板检查: 缺少项目或用户数据');
 
-       return false;
 
-     }
 
-     
 
-     const userRole = this.currentUser.get('roleName') || '';
 
-     // ⚠️ 临时注释角色检查,允许所有角色访问
 
-     // const isTeamLeader = userRole === '设计组长' || userRole === 'team-leader';
 
-     const isTeamLeader = true; // 临时放开权限
 
-     
 
-     const currentStage = this.project.get('currentStage') || '';
 
-     const isOrderStage = currentStage === '订单分配' || currentStage === 'order';
 
-     
 
-     const data = this.project.get('data') || {};
 
-     const approvalStatus = data.approvalStatus;
 
-     const isPending = approvalStatus === 'pending';
 
-     
 
-     console.log('🔍 审批面板检查 [临时放开权限]:', {
 
-       userRole,
 
-       isTeamLeader,
 
-       currentStage,
 
-       isOrderStage,
 
-       approvalStatus,
 
-       isPending,
 
-       result: isTeamLeader && isOrderStage && isPending
 
-     });
 
-     
 
-     return isTeamLeader && isOrderStage && isPending;
 
-   }
 
-   /**
 
-    * 处理审批完成事件
 
-    */
 
-   async onApprovalCompleted(event: { action: 'approved' | 'rejected'; reason?: string; comment?: string }) {
 
-     if (!this.project) return;
 
-     try {
 
-       const data = this.project.get('data') || {};
 
-       const approvalHistory = data.approvalHistory || [];
 
-       const latestRecord = approvalHistory[approvalHistory.length - 1];
 
-       if (latestRecord) {
 
-         latestRecord.status = event.action;
 
-         latestRecord.approver = {
 
-           id: this.currentUser?.id,
 
-           name: this.currentUser?.get('name'),
 
-           role: this.currentUser?.get('roleName')
 
-         };
 
-         latestRecord.approvalTime = new Date();
 
-         latestRecord.comment = event.comment;
 
-         latestRecord.reason = event.reason;
 
-       }
 
-       if (event.action === 'approved') {
 
-         // 通过审批:推进到确认需求阶段
 
-         data.approvalStatus = 'approved';
 
-         this.project.set('currentStage', '确认需求');
 
-         this.project.set('data', data);
 
-         await this.project.save();
 
-         
 
-         alert('✅ 审批通过,项目已进入确认需求阶段');
 
-         
 
-         // 刷新页面数据
 
-         await this.loadData();
 
-       } else {
 
-         // 驳回:保持在订单分配阶段,记录驳回原因
 
-         data.approvalStatus = 'rejected';
 
-         data.lastRejectionReason = event.reason || '未提供原因';
 
-         this.project.set('data', data);
 
-         await this.project.save();
 
-         
 
-         alert('✅ 已驳回订单,客服将收到通知');
 
-         
 
-         // 刷新页面数据
 
-         await this.loadData();
 
-       }
 
-     } catch (err) {
 
-       console.error('处理审批失败:', err);
 
-       alert('审批操作失败,请重试');
 
-     }
 
-   }
 
- }
 
- // duplicate inline CustomerSelectorComponent removed (we keep single declaration above)
 
 
  |