123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- import { Component, OnInit } from '@angular/core';
- import { CommonModule } from '@angular/common';
- import { Router, ActivatedRoute } from '@angular/router';
- import { FormsModule } from '@angular/forms';
- import { IonicModule } from '@ionic/angular';
- import { WxworkSDK, WxworkCorp, WxworkCurrentChat } from 'fmode-ng/core';
- import { FmodeParse, FmodeObject } from 'fmode-ng/parse';
- import { wxdebug } from 'fmode-ng';
- import { addIcons } from 'ionicons';
- import {
- rocketOutline,
- addCircleOutline,
- timeOutline,
- personCircleOutline,
- alertCircleOutline,
- refreshOutline,
- chevronForwardOutline
- } from 'ionicons/icons';
- const Parse = FmodeParse.with('nova');
- /**
- * 项目预加载页面
- *
- * 功能:
- * 1. 从企微会话获取上下文(群聊或联系人)
- * 2. 获取当前登录用户(Profile)
- * 3. 根据场景跳转到对应页面
- * - 群聊 → 项目详情 或 创建项目引导
- * - 联系人 → 客户画像
- *
- * 路由:/wxwork/:cid/project-loader
- *
- * 参考实现:nova-admin/projects/nova-crm/src/modules/chat/page-chat-context
- */
- @Component({
- selector: 'app-project-loader',
- standalone: true,
- imports: [CommonModule, FormsModule, IonicModule],
- templateUrl: './project-loader.component.html',
- styleUrls: ['./project-loader.component.scss']
- })
- export class ProjectLoaderComponent implements OnInit {
- // 基础数据
- cid: string = '';
- appId: string = 'crm';
- // 加载状态
- loading: boolean = true;
- loadingMessage: string = '正在加载...';
- error: string | null = null;
- // 企微SDK
- wxwork: WxworkSDK | null = null;
- wecorp: WxworkCorp | null = null;
- // 上下文数据
- currentUser: FmodeObject | null = null; // Profile 或 UserSocial
- currentChat: WxworkCurrentChat | null = null;
- chatType: 'group' | 'contact' | 'none' = 'none';
- groupChat: FmodeObject | null = null; // GroupChat
- contact: FmodeObject | null = null; // ContactInfo
- project: FmodeObject | null = null; // Project
- // 创建项目引导
- showCreateGuide: boolean = false;
- defaultProjectName: string = '';
- projectName: string = '';
- creating: boolean = false;
- // 历史项目(当前群聊无项目时展示)
- historyProjects: FmodeObject[] = [];
- constructor(
- private router: Router,
- private route: ActivatedRoute
- ) {
- addIcons({
- rocketOutline,
- addCircleOutline,
- timeOutline,
- personCircleOutline,
- alertCircleOutline,
- refreshOutline,
- chevronForwardOutline
- });
- }
- async ngOnInit() {
- // 获取路由参数
- this.route.paramMap.subscribe(async params => {
- this.cid = params.get('cid') || '';
- this.appId = params.get('appId') || 'crm';
- if (!this.cid) {
- this.error = '缺少企业ID参数';
- this.loading = false;
- return;
- }
- await this.loadData();
- });
- }
- /**
- * 加载数据主流程(参考 page-chat-context 实现)
- */
- async loadData() {
- try {
- this.loading = true;
- this.loadingMessage = '初始化企微SDK...';
- // 1️⃣ 初始化 SDK
- this.wxwork = new WxworkSDK({ cid: this.cid, appId: this.appId });
- this.wecorp = new WxworkCorp(this.cid);
- wxdebug('1. SDK初始化完成', { cid: this.cid, appId: this.appId });
- // 2️⃣ 加载当前登录员工信息(由 WxworkAuthGuard 自动登录)
- this.loadingMessage = '获取用户信息...';
- try {
- this.currentUser = await this.wxwork.getCurrentUser();
- wxdebug('2. 获取当前用户成功', this.currentUser?.toJSON());
- } catch (err) {
- console.error('获取当前用户失败:', err);
- wxdebug('2. 获取当前用户失败', err);
- throw new Error('获取用户信息失败,请重试');
- }
- // 3️⃣ 加载当前聊天上下文
- this.loadingMessage = '获取会话信息...';
- try {
- this.currentChat = await this.wxwork.getCurrentChat();
- wxdebug('3. getCurrentChat返回', this.currentChat);
- } catch (err) {
- console.error('getCurrentChat失败:', err);
- wxdebug('3. getCurrentChat失败', err);
- }
- // 4️⃣ 根据场景同步数据
- if (this.currentChat?.type === "chatId" && this.currentChat?.group) {
- // 群聊场景
- wxdebug('4. 检测到群聊场景', this.currentChat.group);
- this.loadingMessage = '同步群聊信息...';
- try {
- this.chatType = 'group';
- this.groupChat = await this.wxwork.syncGroupChat(this.currentChat.group);
- wxdebug('5. 群聊同步完成', this.groupChat?.toJSON());
- // 处理群聊场景
- await this.handleGroupChatScene();
- } catch (err) {
- console.error('群聊同步失败:', err);
- wxdebug('5. 群聊同步失败', err);
- throw new Error('群聊信息同步失败');
- }
- } else if (this.currentChat?.type === "userId" && this.currentChat?.id) {
- // 联系人场景
- wxdebug('4. 检测到联系人场景', { id: this.currentChat.id });
- this.loadingMessage = '同步联系人信息...';
- try {
- this.chatType = 'contact';
- // 获取完整联系人信息
- const contactInfo = await this.wecorp!.externalContact.get(this.currentChat.id);
- wxdebug('5. 获取完整联系人信息', contactInfo);
- this.contact = await this.wxwork.syncContact(contactInfo);
- wxdebug('6. 联系人同步完成', this.contact?.toJSON());
- // 处理联系人场景
- await this.handleContactScene();
- } catch (err) {
- console.error('联系人同步失败:', err);
- wxdebug('联系人同步失败', err);
- throw new Error('联系人信息同步失败');
- }
- } else {
- // 未检测到有效场景
- wxdebug('4. 未检测到有效场景', {
- currentChat: this.currentChat,
- type: this.currentChat?.type,
- hasGroup: !!this.currentChat?.group,
- hasContact: !!this.currentChat?.contact,
- hasId: !!this.currentChat?.id
- });
- throw new Error('无法识别当前会话类型,请在群聊或联系人会话中打开');
- }
- wxdebug('加载完成', {
- chatType: this.chatType,
- hasGroupChat: !!this.groupChat,
- hasContact: !!this.contact,
- hasCurrentUser: !!this.currentUser
- });
- } catch (err: any) {
- console.error('加载失败:', err);
- this.error = err.message || '加载失败,请重试';
- } finally {
- this.loading = false;
- }
- }
- /**
- * 处理群聊场景
- */
- async handleGroupChatScene() {
- this.loadingMessage = '查询项目信息...';
- // 查询群聊关联的项目
- const projectPointer = this.groupChat!.get('project');
- if (projectPointer) {
- // 有项目,加载项目详情
- try {
- const query = new Parse.Query('Project');
- query.include('customer', 'assignee');
- this.project = await query.get(projectPointer.id);
- wxdebug('找到项目', this.project.toJSON());
- // 跳转项目详情
- await this.navigateToProjectDetail();
- } catch (err) {
- console.error('加载项目失败:', err);
- wxdebug('加载项目失败', err);
- this.error = '项目已删除或无权访问';
- }
- } else {
- // 无项目,查询历史项目并显示创建引导
- await this.loadHistoryProjects();
- this.showCreateProjectGuide();
- }
- }
- /**
- * 处理联系人场景
- */
- async handleContactScene() {
- wxdebug('联系人场景,跳转客户画像', {
- contactId: this.contact!.id,
- contactName: this.contact!.get('name')
- });
- // 跳转客户画像页面
- await this.router.navigate(['/wxwork', this.cid, 'contact', this.contact!.id], {
- queryParams: {
- profileId: this.currentUser!.id
- }
- });
- }
- /**
- * 加载历史项目(当前群聊相关的其他项目)
- */
- async loadHistoryProjects() {
- try {
- // 通过 ProjectGroup 查询该群聊的所有项目
- const pgQuery = new Parse.Query('ProjectGroup');
- pgQuery.equalTo('groupChat', this.groupChat!.toPointer());
- pgQuery.include('project');
- pgQuery.descending('createdAt');
- const projectGroups = await pgQuery.find();
- this.historyProjects = projectGroups
- .map(pg => pg.get('project'))
- .filter(p => p && !p.get('isDeleted'));
- wxdebug('找到历史项目', { count: this.historyProjects.length });
- } catch (err) {
- console.error('加载历史项目失败:', err);
- wxdebug('加载历史项目失败', err);
- }
- }
- /**
- * 显示创建项目引导
- */
- showCreateProjectGuide() {
- this.showCreateGuide = true;
- this.defaultProjectName = this.groupChat!.get('name') || '新项目';
- this.projectName = this.defaultProjectName;
- wxdebug('显示创建项目引导', {
- groupName: this.groupChat!.get('name'),
- historyProjectsCount: this.historyProjects.length
- });
- }
- /**
- * 创建项目
- */
- async createProject() {
- if (!this.projectName.trim()) {
- alert('请输入项目名称');
- return;
- }
- // 权限检查
- const role = this.currentUser!.get('role');
- if (!['客服', '组长', '管理员'].includes(role)) {
- alert('您没有权限创建项目');
- return;
- }
- try {
- this.creating = true;
- wxdebug('开始创建项目', {
- projectName: this.projectName,
- groupChatId: this.groupChat!.id,
- currentUserId: this.currentUser!.id,
- role: role
- });
- // 1. 创建项目
- const Project = Parse.Object.extend('Project');
- const project = new Project();
- project.set('title', this.projectName.trim());
- project.set('company', this.currentUser!.get('company'));
- project.set('status', '待分配');
- project.set('currentStage', '订单分配');
- project.set('data', {
- createdBy: this.currentUser!.id,
- createdFrom: 'wxwork_groupchat',
- groupChatId: this.groupChat!.id
- });
- await project.save();
- wxdebug('项目创建成功', { projectId: project.id });
- // 2. 关联群聊
- this.groupChat!.set('project', project.toPointer());
- await this.groupChat!.save();
- wxdebug('群聊关联项目成功');
- // 3. 创建 ProjectGroup 关联(支持多项目多群)
- const ProjectGroup = Parse.Object.extend('ProjectGroup');
- const pg = new ProjectGroup();
- pg.set('project', project.toPointer());
- pg.set('groupChat', this.groupChat!.toPointer());
- pg.set('isPrimary', true);
- pg.set('company', this.currentUser!.get('company'));
- await pg.save();
- wxdebug('ProjectGroup关联创建成功');
- // 4. 跳转项目详情
- this.project = project;
- await this.navigateToProjectDetail();
- } catch (err: any) {
- console.error('创建项目失败:', err);
- wxdebug('创建项目失败', err);
- alert('创建失败: ' + (err.message || '未知错误'));
- } finally {
- this.creating = false;
- }
- }
- /**
- * 选择历史项目
- */
- async selectHistoryProject(project: FmodeObject) {
- try {
- wxdebug('选择历史项目', {
- projectId: project.id,
- projectTitle: project.get('title')
- });
- // 更新群聊的当前项目
- this.groupChat!.set('project', project.toPointer());
- await this.groupChat!.save();
- // 跳转项目详情
- this.project = project;
- await this.navigateToProjectDetail();
- } catch (err: any) {
- console.error('关联项目失败:', err);
- alert('关联失败: ' + (err.message || '未知错误'));
- }
- }
- /**
- * 跳转项目详情
- */
- async navigateToProjectDetail() {
- wxdebug('跳转项目详情', {
- projectId: this.project!.id,
- cid: this.cid,
- groupChatId: this.groupChat?.id
- });
- await this.router.navigate(['/wxwork', this.cid, 'project', this.project!.id], {
- queryParams: {
- groupId: this.groupChat?.id,
- profileId: this.currentUser!.id
- }
- });
- }
- /**
- * 重新加载
- */
- async reload() {
- this.error = null;
- this.showCreateGuide = false;
- this.historyProjects = [];
- this.chatType = 'none';
- await this.loadData();
- }
- /**
- * 获取当前员工姓名
- */
- getCurrentUserName(): string {
- if (!this.currentUser) return '未知';
- return this.currentUser.get('name') || this.currentUser.get('userid') || '未知';
- }
- /**
- * 获取当前员工角色
- */
- getCurrentUserRole(): string {
- if (!this.currentUser) return '未知';
- return this.currentUser.get('role') || '未知';
- }
- /**
- * 获取项目状态的显示样式类
- */
- getProjectStatusClass(status: string): string {
- const classMap: any = {
- '待分配': 'status-pending',
- '进行中': 'status-active',
- '已完成': 'status-completed',
- '已暂停': 'status-paused',
- '已取消': 'status-cancelled'
- };
- return classMap[status] || 'status-default';
- }
- /**
- * 格式化日期
- */
- formatDate(date: Date): string {
- if (!date) return '';
- const d = new Date(date);
- return `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}`;
- }
- }
|