import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { IonicModule } from '@ionic/angular'; import { FmodeParse, FmodeObject } from 'fmode-ng/parse'; import { WxworkCorp } from 'fmode-ng/core'; import { CustomerProfileComponent } from '../../pages/contact/contact.component'; const Parse: any = FmodeParse.with('nova'); @Component({ selector: 'app-contact-selector', standalone: true, imports: [CommonModule, FormsModule, IonicModule, CustomerProfileComponent], templateUrl: './contact-selector.component.html', styleUrls: ['./contact-selector.component.scss'] }) export class CustomerSelectorComponent implements OnInit { @Input() project: FmodeObject | null = null; @Input() groupChat: FmodeObject | null = null; @Input() currentUser: FmodeObject | null = null; @Input() placeholder: string = '请选择项目客户'; @Input() disabled: boolean = false; @Input() showCreateButton: boolean = true; @Output() contactSelected = new EventEmitter<{ contact: FmodeObject; isNewCustomer: boolean; action: 'selected' | 'created' | 'updated' }>(); loading: boolean = false; searchKeyword: string = ''; currentCustomer: FmodeObject | null = null; availableCustomers: FmodeObject[] = []; externalMembers: Array<{ userid: string; name?: string }> = []; unbuiltExternalMembers: Array<{ userid: string; name?: string }> = []; showCustomerPanel: boolean = false; get canViewSensitiveInfo(): boolean { const role = this.currentUser?.get?.('roleName') || ''; return ['客服', '组长', '管理员'].includes(role); } async ngOnInit() { await this.init(); } private async init() { if (!this.project || !this.groupChat) return; try { this.loading = true; await this.checkProjectCustomer(); await this.loadExternalMembers(); await this.loadAvailableCustomers(); this.computeUnbuiltMembers(); } finally { this.loading = false; } } private async checkProjectCustomer() { const ptr = this.project!.get('contact'); if (!ptr) { this.currentCustomer = null; return; } try { if (ptr.id && (ptr as any).get) { this.currentCustomer = ptr as any; } else if (ptr.id) { const query = new Parse.Query('ContactInfo'); this.currentCustomer = await query.get(ptr.id); } } catch { this.currentCustomer = null; } } private async loadExternalMembers() { const list = this.groupChat!.get('member_list') || []; const external = Array.isArray(list) ? list.filter((m: any) => m && m.type === 2) : []; this.externalMembers = external.map((m: any) => ({ userid: m.userid, name: m.name })); } private async loadAvailableCustomers() { const companyId = this.project!.get('company')?.id || localStorage.getItem('company'); if (!companyId) return; const extIds = this.externalMembers.map(m => m.userid); if (extIds.length === 0) { this.availableCustomers = []; return; } const query = new Parse.Query('ContactInfo'); query.equalTo('company', companyId); query.containedIn('external_userid', extIds); query.notEqualTo('isDeleted', true); this.availableCustomers = await query.find(); } private computeUnbuiltMembers() { const builtIds = new Set( this.availableCustomers.map((c: any) => c.get('external_userid')).filter(Boolean) ); this.unbuiltExternalMembers = this.externalMembers.filter(m => !builtIds.has(m.userid)); } private getMemberInfo(userid: string): any { const list = this.groupChat!.get('member_list') || []; return (list || []).find((m: any) => m && m.userid === userid) || null; } get filteredCustomers(): FmodeObject[] { const kw = (this.searchKeyword || '').trim().toLowerCase(); const base = this.availableCustomers; if (!kw) return base; return base.filter(c => { const name = (c.get('name') || c.get('data')?.name || '').toLowerCase(); const mobile = (c.get('mobile') || '').toLowerCase(); return name.includes(kw) || mobile.includes(kw); }); } async selectExistingCustomer(contact: FmodeObject) { if (this.disabled || !this.project) return; const nameMissing = !contact.get('name') && !contact.get('data')?.name && !contact.get('data')?.external_contact?.name; const extid = contact.get('external_userid'); if (nameMissing && extid) { await this.refreshContactInfo(contact); } this.project.set('contact', contact.toPointer()); await this.project.save(); this.currentCustomer = contact; this.contactSelected.emit({ contact, isNewCustomer: false, action: 'selected' }); } switchToSelecting() { this.currentCustomer = null; this.searchKeyword = ''; } async createFromMember(memberUserid: string) { if (this.disabled || !this.project) return; const companyId = this.project.get('company')?.id || localStorage.getItem('company'); if (!companyId) throw new Error('无法获取企业信息'); const query = new Parse.Query('ContactInfo'); query.equalTo('external_userid', memberUserid); query.equalTo('company', companyId); let contactInfo = await query.first(); if (!contactInfo) { const corp = new WxworkCorp(companyId); const extData = await corp.externalContact.get(memberUserid); const ext = (extData && extData.external_contact) ? extData.external_contact : {}; const follow = (extData && extData.follow_user) ? extData.follow_user : []; const ContactInfo = Parse.Object.extend('ContactInfo'); contactInfo = new ContactInfo(); contactInfo.set('name', ext.name || this.getMemberInfo(memberUserid)?.name || '客户'); contactInfo.set('external_userid', memberUserid); const company = new Parse.Object('Company'); company.id = companyId; contactInfo.set('company', company.toPointer()); const mapped = { external_contact: ext, follow_user: follow, member: this.getMemberInfo(memberUserid), name: ext.name || this.getMemberInfo(memberUserid)?.name, avatar: ext.avatar, gender: ext.gender, type: ext.type } as any; contactInfo.set('data', mapped); contactInfo = await contactInfo.save(); await this.loadAvailableCustomers(); this.computeUnbuiltMembers(); } this.project.set('contact', contactInfo.toPointer()); await this.project.save(); this.currentCustomer = contactInfo; this.contactSelected.emit({ contact: contactInfo, isNewCustomer: true, action: 'created' }); } async refreshContactInfo(contact: any) { const externalUserId = contact.get('external_userid'); const companyId = this.project?.get('company')?.id || localStorage.getItem('company'); if (!externalUserId || !companyId) return; const corp = new WxworkCorp(companyId); const extData = await corp.externalContact.get(externalUserId); const ext = (extData && extData.external_contact) ? extData.external_contact : {}; const follow = (extData && extData.follow_user) ? extData.follow_user : []; if (ext.name) contact.set('name', ext.name); const mapped = { external_contact: ext, follow_user: follow, member: this.getMemberInfo(externalUserId), name: ext.name || this.getMemberInfo(externalUserId)?.name, avatar: ext.avatar, gender: ext.gender, type: ext.type } as any; contact.set('data', mapped); await contact.save(); } viewCustomerDetail() { this.showCustomerPanel = true; } closeCustomerDetail() { this.showCustomerPanel = false; } }