| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 | import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';import { CommonModule } from '@angular/common';import { FormsModule } from '@angular/forms';import { FmodeObject, FmodeQuery, FmodeParse } from 'fmode-ng/parse';import { WxworkCorp, WxworkSDK } from 'fmode-ng/core';import { getGroupChat } from '../get-group-joinway';const Parse = FmodeParse.with('nova');export interface ProjectMember {  id: string;  name: string;  userid: string;  avatar?: string;  role: string;  department?: string;  isInGroupChat: boolean;  isInProjectTeam: boolean;  projectTeamId?: string;  profileId?: string;}export interface GroupChatMember {  userid: string;  name: string;  type: number; // 1: 内部成员 2: 外部联系人  avatar?: string;}@Component({  selector: 'app-project-members-modal',  standalone: true,  imports: [CommonModule, FormsModule],  templateUrl: './project-members-modal.component.html',  styleUrls: ['./project-members-modal.component.scss']})export class ProjectMembersModalComponent implements OnInit {  @Input() project: FmodeObject | null = null;  @Input() groupChat: FmodeObject | null = null;  @Input() currentUser: FmodeObject | null = null;  @Input() isVisible: boolean = false;  @Input() cid: string = '';  @Output() close = new EventEmitter<void>();  members: ProjectMember[] = [];  loading: boolean = false;  error: string | null = null;  isWxworkEnvironment: boolean = false;  // 统计信息  totalMembers: number = 0;  groupChatMembers: number = 0;  projectTeamMembers: number = 0;  pendingAddMembers: number = 0;  // 过滤和搜索  searchQuery: string = '';  memberFilter: 'all' | 'ingroup' | 'team' | 'pending' = 'all';  // 企业微信API  private wecorp: WxworkCorp | null = null;  private wwsdk: WxworkSDK | null = null;  isWechat:boolean = false;  constructor() {    let ua = navigator.userAgent.toLowerCase();    this.isWechat = ua.indexOf('micromessenger') !== -1;    this.checkWxworkEnvironment();  }  ngOnInit(): void {    if (this.isVisible && this.project) {      this.loadMembers();    }  }  ngOnChanges(): void {    if (this.isVisible && this.project) {      this.loadMembers();    }  }  private checkWxworkEnvironment(): void {    // 检查是否在企业微信环境中    let cid = this.project?.get("company")?.id || localStorage.getItem("company")    this.wecorp = new WxworkCorp(cid);    this.wwsdk = new WxworkSDK({cid:cid,appId:'crm'});    console.log('✅ 企业微信环境检测成功');  }  async loadMembers(): Promise<void> {    if (!this.project) return;    try {      this.loading = true;      this.error = null;      // 1. 加载项目团队成员      const projectTeamMembers = await this.loadProjectTeamMembers();      // 2. 加载群聊成员      if(!this.groupChat?.id){        const gcQuery2 = new Parse.Query('GroupChat');        gcQuery2.equalTo('project', this.project?.id);        this.groupChat = await gcQuery2.first();      }      if(this.groupChat?.id && !this.groupChat?.get("joinUrl")){        this.groupChat = await getGroupChat(this.groupChat?.id)      }      const groupChatMembers = await this.loadGroupChatMembers();      // 3. 合并成员数据      console.log("999",projectTeamMembers, groupChatMembers)      this.mergeMembersData(projectTeamMembers, groupChatMembers);      this.calculateStats();      console.log(`✅ 加载了 ${this.members.length} 个成员信息`);    } catch (error) {      console.error('❌ 加载成员失败:', error);      this.error = error instanceof Error ? error.message : '加载成员失败';    } finally {      this.loading = false;    }  }  private async loadProjectTeamMembers(): Promise<FmodeObject[]> {    try {      const query = new FmodeQuery('ProjectTeam');      if (this.project) {        query.equalTo('project', this.project.toPointer());      }      query.include('profile','department','profile.department');      query.notEqualTo('isDeleted', true);      return await query.find();    } catch (error) {      console.error('加载项目团队成员失败:', error);      return [];    }  }  private async loadGroupChatMembers(): Promise<GroupChatMember[]> {    if (!this.groupChat) return [];    try {      const memberList = this.groupChat.get('member_list') || [];      return memberList    } catch (error) {      console.error('加载群聊成员失败:', error);      return [];    }  }  private mergeMembersData(projectTeamMembers: FmodeObject[], groupChatMembers: GroupChatMember[]): void {    const memberMap = new Map<string, ProjectMember>();    // 1. 添加项目团队成员    projectTeamMembers.forEach(team => {      const profile = team.get('profile');      if (profile) {        const member: ProjectMember = {          id: profile.id,          name: profile.get('name') || '未知',          userid: profile.get('userid') || '',          avatar: profile.get('data')?.avatar,          role: profile.get('roleName') || '未知',          department: profile.get('department')?.get('name'),          isInGroupChat: false,          isInProjectTeam: true,          projectTeamId: team.id,          profileId: profile.id        };        memberMap.set(profile.id, member);      }    });    // 2. 添加群聊成员(包括外部联系人)    groupChatMembers.forEach(groupMember => {      // 查找是否已在项目团队中      const existingMember = Array.from(memberMap.values()).find(        m => m.userid === groupMember.userid      );      if (existingMember) {        existingMember.isInGroupChat = true;      } else {        // 添加仅存在于群聊中的成员        const member: ProjectMember = {          id: groupMember.userid,          name: groupMember.name,          userid: groupMember.userid,          avatar: groupMember.avatar,          role: groupMember.type === 1 ? '外部联系人' : '内部成员',          isInGroupChat: true,          isInProjectTeam: false,          projectTeamId: undefined,          profileId: undefined        };        memberMap.set(groupMember.userid, member);      }    });    this.members = Array.from(memberMap.values());  }  calculateStats(): void {    this.totalMembers = this.members.length;    this.groupChatMembers = this.members.filter(m => m.isInGroupChat).length;    this.projectTeamMembers = this.members.filter(m => m.isInProjectTeam).length;    this.pendingAddMembers = this.members.filter(m => m.isInProjectTeam && !m.isInGroupChat).length;  }  onClose(): void {    this.close.emit();  }  onBackdropClick(event: MouseEvent): void {    if (event.target === event.currentTarget) {      this.onClose();    }  }  getFilteredMembers(): ProjectMember[] {    let filtered = this.members;    // 搜索过滤    if (this.searchQuery) {      const query = this.searchQuery.toLowerCase();      filtered = filtered.filter(member =>        member.name.toLowerCase().includes(query) ||        member.role.toLowerCase().includes(query) ||        member.department?.toLowerCase().includes(query)      );    }    // 状态过滤    switch (this.memberFilter) {      case 'ingroup':        filtered = filtered.filter(m => m.isInGroupChat);        break;      case 'team':        filtered = filtered.filter(m => m.isInProjectTeam);        break;      case 'pending':        filtered = filtered.filter(m => m.isInProjectTeam && !m.isInGroupChat);        break;    }    return filtered.sort((a, b) => {      // 优先级:项目团队成员 > 仅群聊成员      if (a.isInProjectTeam && !b.isInProjectTeam) return -1;      if (!a.isInProjectTeam && b.isInProjectTeam) return 1;      // 按名称排序      return a.name.localeCompare(b.name, 'zh-CN');    });  }  async addMemberToGroupChat(member: ProjectMember): Promise<void> {       if (!member.userid) {      alert('该成员没有用户ID,无法添加到群聊');      return;    }    try {      const chatId = this.groupChat?.get('chat_id');      if (!chatId) {        alert('群聊ID不存在');        return;      }      console.log(`🚀 开始添加成员 ${member.name} (${member.userid}) 到群聊 ${chatId}`);      // TODO: 实现正确的企业微信API调用        // console.log(this.groupChat?.get("joinUrl"),this.groupChat)          this.wecorp?.message.sendNews({            agentid:"1000017",            touser: member.userid || '',            articles:[              {                 title: this.project?.get('title'),                description: "点击加入项目群聊",                url: this.groupChat?.get("joinUrl")?.qr_code,                picurl: this.groupChat?.get("joinQrcode")?.qr_code,              }            ]          });          const md = `${this.project?.get('title')} 项目开始啦!\n就等你来啦!快点上面进群\n`;          this.wecorp?.message.sendMarkdown({            agentid:"1000017",            touser: member.userid || '',            content: md          });      let result = await this.wwsdk?.ww.updateEnterpriseChat({        chatId: chatId,        userIdsToAdd: [member.userid]      });      // 临时:直接更新本地状态用于演示      if(result){        member.isInGroupChat = true;        this.calculateStats();      }      alert(`✅ 已将 ${member.name} 添加到群聊`);      console.log(`✅ 成功添加成员 ${member.name} 到群聊`);    } catch (error) {      console.error('❌ 添加成员到群聊失败:', error);      alert(`添加失败: ${error instanceof Error ? error.message : '未知错误'}`);    }  }  // 新增:移出项目(软删除 ProjectTeam)  async removeMemberFromProject(member: ProjectMember): Promise<void> {    if (!member.isInProjectTeam || !member.projectTeamId) {      alert('该成员未在项目团队中,无法移出项目');      return;    }    if (!this.project) {      alert('项目不存在,无法执行移出操作');      return;    }    const confirmMsg = `确定将 \"${member.name}\" 移出项目吗?`;    if (!confirm(confirmMsg)) return;    try {      this.loading = true;      const query = new Parse.Query('ProjectTeam');      const team = await query.get(member.projectTeamId);      team.set('isDeleted', true);      await team.save();      // 重新加载成员数据,保持列表与统计一致      await this.loadMembers();      alert(`✅ 已将 ${member.name} 移出项目`);    } catch (error) {      console.error('❌ 移出项目失败:', error);      alert(`移出失败: ${error instanceof Error ? error.message : '未知错误'}`);    } finally {      this.loading = false;    }  }  getRoleBadgeClass(role: string): string {    switch (role) {      case '客服':        return 'role-customer-service';      case '组员':      case '设计师':        return 'role-designer';      case '组长':        return 'role-team-leader';      case '管理员':        return 'role-admin';      case '外部联系人':        return 'role-external';      default:        return 'role-default';    }  }  getMemberStatusClass(member: ProjectMember): string {    if (member.isInProjectTeam && member.isInGroupChat) {      return 'status-active';    } else if (member.isInProjectTeam) {      return 'status-pending';    } else {      return 'status-group-only';    }  }  getMemberStatusText(member: ProjectMember): string {    if (member.isInProjectTeam && member.isInGroupChat) {      return '已加入';    } else if (member.isInProjectTeam) {      return '待加入';    } else {      return '仅群聊';    }  }}
 |