CHAT-ACTIVATION-LOCAL-TEST.md 21 KB

会话激活功能 - 本地测试指南

🎯 测试目标

在电脑端使用 localStorage 模拟企微环境,测试会话激活功能的完整流程。


📋 准备工作

1. 启动开发服务器

cd yss-project
npm install  # 如果还没安装依赖
ng serve

服务器启动后,访问:http://localhost:4200


🔧 步骤一:配置 localStorage 模拟数据

1.1 打开浏览器控制台

F12 或右键 → 检查,打开开发者工具,切换到 Console 标签页。

1.2 设置基础数据

在控制台中依次执行以下代码:

// ========== 1. 设置公司ID ==========
localStorage.setItem('company', 'test-company-001');

// ========== 2. 设置当前用户 ==========
const mockUser = {
  objectId: 'user-001',
  id: 'user-001',
  userid: 'wxwork-user-001',
  name: '测试技术员',
  realName: '张三',
  roleName: '技术',
  department: {
    __type: 'Pointer',
    className: 'Department',
    objectId: 'dept-001'
  },
  company: {
    __type: 'Pointer',
    className: 'Company',
    objectId: 'test-company-001'
  }
};
localStorage.setItem('currentUser', JSON.stringify(mockUser));

// ========== 3. 设置项目数据 ==========
const mockProject = {
  objectId: 'project-001',
  id: 'project-001',
  title: '测试项目 - 现代简约风格装修',
  description: '客厅、卧室、厨房三室一厅装修,预算15-20万',
  status: '进行中',
  contact: {
    __type: 'Pointer',
    className: 'ContactInfo',
    objectId: 'contact-001'
  },
  assignee: {
    __type: 'Pointer',
    className: 'Profile',
    objectId: 'user-001'
  },
  department: {
    __type: 'Pointer',
    className: 'Department',
    objectId: 'dept-001'
  }
};
localStorage.setItem('mockProject', JSON.stringify(mockProject));

// ========== 4. 设置客户数据 ==========
const mockContact = {
  objectId: 'contact-001',
  id: 'contact-001',
  name: '李女士',
  external_userid: 'external-user-001',
  mobile: '138****8888',
  company: 'test-company-001',
  data: {
    avatar: 'https://via.placeholder.com/100',
    wechat: 'lixiaojie123',
    tags: {
      preference: '现代简约',
      budget: { min: 150000, max: 200000 },
      colorAtmosphere: '暖色调'
    }
  }
};
localStorage.setItem('mockContact', JSON.stringify(mockContact));

// ========== 5. 设置群聊数据 ==========
const mockGroupChat = {
  objectId: 'groupchat-001',
  id: 'groupchat-001',
  chat_id: 'wrkSFfCgAAXXXXXXXXXXXXXXXXXXXX',
  name: '【李女士】现代简约装修项目群',
  company: 'test-company-001',
  project: {
    __type: 'Pointer',
    className: 'Project',
    objectId: 'project-001'
  },
  introSent: false,
  introSentAt: null,
  joinQrcode: {
    qr_code: 'https://via.placeholder.com/300?text=QR+Code'
  },
  joinUrl: {
    join_url: 'https://work.weixin.qq.com/ca/cawcde123456'
  },
  member_list: [
    {
      userid: 'wxwork-user-001',
      type: 1,
      name: '张三',
      invitor: {
        userid: 'admin-001'
      }
    },
    {
      userid: 'external-user-001',
      type: 2,
      name: '李女士',
      invitor: {
        userid: 'wxwork-user-001'
      }
    },
    {
      userid: 'wxwork-user-002',
      type: 1,
      name: '王组长',
      invitor: {
        userid: 'admin-001'
      }
    }
  ],
  messages: [
    {
      msgid: 'msg-001',
      from: 'external-user-001',
      msgtime: Math.floor(Date.now() / 1000) - 3600,
      msgtype: 'text',
      text: {
        content: '你好,我想了解一下项目的进度'
      }
    },
    {
      msgid: 'msg-002',
      from: 'wxwork-user-001',
      msgtime: Math.floor(Date.now() / 1000) - 3500,
      msgtype: 'text',
      text: {
        content: '您好李女士,目前我们正在进行方案设计,预计明天可以给您看初稿'
      }
    },
    {
      msgid: 'msg-003',
      from: 'external-user-001',
      msgtime: Math.floor(Date.now() / 1000) - 3400,
      msgtype: 'text',
      text: {
        content: '好的,那我等你们的消息'
      }
    },
    {
      msgid: 'msg-004',
      from: 'external-user-001',
      msgtime: Math.floor(Date.now() / 1000) - 700,
      msgtype: 'text',
      text: {
        content: '对了,我想把客厅的颜色改成浅灰色,可以吗?'
      }
    },
    {
      msgid: 'msg-005',
      from: 'external-user-001',
      msgtime: Math.floor(Date.now() / 1000) - 650,
      msgtype: 'text',
      text: {
        content: '还有厨房的橱柜我想换个品牌'
      }
    }
  ]
};
localStorage.setItem('mockGroupChat', JSON.stringify(mockGroupChat));

// ========== 6. 设置部门数据 ==========
const mockDepartment = {
  objectId: 'dept-001',
  id: 'dept-001',
  name: '设计部',
  leader: {
    __type: 'Pointer',
    className: 'Profile',
    objectId: 'leader-001'
  }
};
localStorage.setItem('mockDepartment', JSON.stringify(mockDepartment));

// ========== 7. 设置组长数据 ==========
const mockLeader = {
  objectId: 'leader-001',
  id: 'leader-001',
  name: '王组长',
  userid: 'wxwork-user-002',
  roleName: '组长'
};
localStorage.setItem('mockLeader', JSON.stringify(mockLeader));

console.log('✅ 所有模拟数据已设置完成!');
console.log('📝 数据清单:');
console.log('- 公司ID:', localStorage.getItem('company'));
console.log('- 当前用户:', JSON.parse(localStorage.getItem('currentUser')).name);
console.log('- 项目:', JSON.parse(localStorage.getItem('mockProject')).title);
console.log('- 客户:', JSON.parse(localStorage.getItem('mockContact')).name);
console.log('- 群聊:', JSON.parse(localStorage.getItem('mockGroupChat')).name);
console.log('- 消息数量:', JSON.parse(localStorage.getItem('mockGroupChat')).messages.length);

🔨 步骤二:修改组件以支持 localStorage 测试

2.1 修改 chat-activation.component.ts

在组件的 loadData() 方法中添加 localStorage 支持:

async loadData() {
  try {
    this.loading = true;
    
    // ========== 开发环境:使用 localStorage ==========
    if (!this.wxwork && typeof window !== 'undefined') {
      console.log('🔧 开发模式:使用 localStorage 模拟数据');
      
      // 1. 加载当前用户
      const userStr = localStorage.getItem('currentUser');
      if (userStr) {
        this.currentUser = JSON.parse(userStr) as any;
        console.log('✅ 用户加载成功:', this.currentUser.name);
      }
      
      // 2. 加载项目
      const projectStr = localStorage.getItem('mockProject');
      if (projectStr) {
        this.project = JSON.parse(projectStr) as any;
        console.log('✅ 项目加载成功:', this.project.title);
      }
      
      // 3. 加载客户
      const contactStr = localStorage.getItem('mockContact');
      if (contactStr) {
        this.contact = JSON.parse(contactStr) as any;
        console.log('✅ 客户加载成功:', this.contact.name);
      }
      
      // 4. 加载群聊
      const groupChatStr = localStorage.getItem('mockGroupChat');
      if (groupChatStr) {
        this.groupChat = JSON.parse(groupChatStr) as any;
        this.chatId = this.groupChat.chat_id;
        this.introSent = this.groupChat.introSent || false;
        console.log('✅ 群聊加载成功:', this.groupChat.name);
        
        // 加载入群方式
        this.joinMethods.qrCode = this.groupChat.joinQrcode?.qr_code || '';
        this.joinMethods.link = this.groupChat.joinUrl?.join_url || '';
      }
      
      // 5. 加载部门和组长
      const deptStr = localStorage.getItem('mockDepartment');
      const leaderStr = localStorage.getItem('mockLeader');
      if (deptStr && leaderStr && this.project) {
        const dept = JSON.parse(deptStr);
        const leader = JSON.parse(leaderStr);
        this.project.department = dept;
        this.project.department.leader = leader;
        console.log('✅ 部门和组长加载成功');
      }
      
      // 6. 生成介绍文案
      this.generateIntroTemplate();
      
      // 7. 加载消息(使用 mock 数据)
      await this.loadChatMessagesFromLocalStorage();
      
      this.loading = false;
      this.cdr.markForCheck();
      return;
    }
    
    // ========== 生产环境:正常流程 ==========
    // ... 原有代码保持不变
    
  } catch (error) {
    console.error('❌ 加载数据失败:', error);
    this.error = error.message || '加载失败';
  } finally {
    this.loading = false;
  }
}

// 新增:从 localStorage 加载消息
async loadChatMessagesFromLocalStorage() {
  try {
    this.loadingMessages = true;
    
    if (!this.groupChat) {
      this.messages = [];
      this.updateStatistics();
      return;
    }
    
    const messagesData = this.groupChat.messages || [];
    const memberList = this.groupChat.member_list || [];
    const customerUserId = this.contact?.external_userid || '';
    
    // 转换为 ChatMessage 格式
    this.messages = messagesData.map((msg: any, index: number) => {
      const isCustomer = msg.from === customerUserId || 
                        memberList.some((m: any) => 
                          m.type === 2 && m.userid === msg.from
                        );
      
      const msgTime = new Date(msg.msgtime * 1000);
      const needsReply = isCustomer && this.checkNeedsReply(msg, messagesData, index);
      
      return {
        id: msg.msgid || `msg-${index}`,
        senderName: this.getSenderName(msg.from, memberList),
        senderUserId: msg.from,
        content: this.getMessageContent(msg),
        time: msgTime,
        isCustomer,
        needsReply,
        msgType: msg.msgtype
      };
    }).sort((a: ChatMessage, b: ChatMessage) => b.time.getTime() - a.time.getTime());
    
    this.updateStatistics();
    this.applyFilters();
    
    console.log('✅ 消息加载完成:', {
      总消息数: this.totalMessages,
      客户消息: this.customerMessageCount,
      未回复: this.unreadCount
    });
    
  } catch (error) {
    console.error('❌ 加载消息失败:', error);
  } finally {
    this.loadingMessages = false;
    this.cdr.markForCheck();
  }
}

2.2 修改发送消息方法(开发环境模拟)

async sendGroupIntro() {
  try {
    if (!this.chatId) {
      window?.fmode?.alert('群聊信息不完整');
      return;
    }
    
    this.sendingIntro = true;
    
    // ========== 开发环境:模拟发送 ==========
    if (!this.wecorp) {
      console.log('🔧 开发模式:模拟发送群介绍');
      console.log('📝 文案内容:', this.introTemplate);
      
      // 模拟延迟
      await new Promise(resolve => setTimeout(resolve, 1000));
      
      // 更新 localStorage
      if (this.groupChat) {
        this.groupChat.introSent = true;
        this.groupChat.introSentAt = new Date();
        localStorage.setItem('mockGroupChat', JSON.stringify(this.groupChat));
        this.introSent = true;
      }
      
      alert('✅ 群介绍已发送(模拟)!');
      this.sendingIntro = false;
      this.cdr.markForCheck();
      return;
    }
    
    // ========== 生产环境:实际发送 ==========
    // @ts-ignore - 企微API类型定义问题
    await this.wecorp.message.send({
      chatid: this.chatId,
      msgtype: 'text',
      text: {
        content: this.introTemplate
      }
    });
    
    // 更新数据库标记
    if (this.groupChat) {
      this.groupChat.set('introSent', true);
      this.groupChat.set('introSentAt', new Date());
      await this.groupChat.save();
      this.introSent = true;
    }
    
    window?.fmode?.alert('群介绍已发送!');
    
  } catch (error) {
    console.error('发送群介绍失败:', error);
    window?.fmode?.alert('发送失败,请重试');
  } finally {
    this.sendingIntro = false;
    this.cdr.markForCheck();
  }
}

async sendSuggestedReply(reply: SuggestedReply) {
  try {
    if (!this.chatId) {
      window?.fmode?.alert('无法发送消息');
      return;
    }
    
    // ========== 开发环境:模拟发送 ==========
    if (!this.wecorp) {
      console.log('🔧 开发模式:模拟发送回复');
      console.log('📝 回复内容:', reply.text);
      
      // 模拟延迟
      await new Promise(resolve => setTimeout(resolve, 500));
      
      // 添加新消息到 localStorage
      const groupChatStr = localStorage.getItem('mockGroupChat');
      if (groupChatStr) {
        const groupChat = JSON.parse(groupChatStr);
        const newMessage = {
          msgid: `msg-${Date.now()}`,
          from: this.currentUser?.userid || 'wxwork-user-001',
          msgtime: Math.floor(Date.now() / 1000),
          msgtype: 'text',
          text: {
            content: reply.text
          }
        };
        groupChat.messages.push(newMessage);
        localStorage.setItem('mockGroupChat', JSON.stringify(groupChat));
        this.groupChat = groupChat;
      }
      
      alert('✅ 消息已发送(模拟)!');
      
      // 关闭建议面板
      this.showSuggestions = false;
      this.selectedMessage = null;
      
      // 刷新消息列表
      await this.loadChatMessagesFromLocalStorage();
      
      return;
    }
    
    // ========== 生产环境:实际发送 ==========
    // @ts-ignore - 企微API类型定义问题
    await this.wecorp.message.send({
      chatid: this.chatId,
      msgtype: 'text',
      text: {
        content: reply.text
      }
    });
    
    window?.fmode?.alert('消息已发送!');
    
    // 关闭建议面板
    this.showSuggestions = false;
    this.selectedMessage = null;
    
    // 刷新消息列表
    await this.loadChatMessages();
    
  } catch (error) {
    console.error('发送消息失败:', error);
    window?.fmode?.alert('发送失败,请重试');
  }
}

🧪 步骤三:开始测试

3.1 访问测试页面

在浏览器中访问:

http://localhost:4200/wxwork/test-company-001/project/project-001/chat-activation

或者如果有查询参数:

http://localhost:4200/wxwork/test-company-001/project/project-001/chat-activation?chatId=wrkSFfCgAAXXXXXXXXXXXXXXXXXXXX

3.2 测试功能清单

✅ 基础功能测试

  1. 页面加载

    • 页面正常显示
    • 显示项目名称:"测试项目 - 现代简约风格装修"
    • 显示群聊名称:"【李女士】现代简约装修项目群"
  2. 入群方式卡片

    • 显示三种入群方式
    • 点击"查看二维码"弹出二维码图片
    • 点击"复制链接"提示复制成功
    • 点击"管理成员"打开群聊
  3. 群介绍文案

    • 显示预览文案
    • 文案包含:项目主管(王组长)、执行技术(张三)、项目需求
    • 点击"自动发送群介绍"按钮
    • 显示发送成功提示
    • 刷新后显示"群介绍已发送"状态

✅ 消息功能测试

  1. 消息列表

    • 显示5条消息
    • 客户消息有蓝色标识
    • 显示统计:5条消息,3条客户消息
  2. 筛选功能

    • 点击"全部"显示5条消息
    • 点击"客户消息"显示3条客户消息
    • 点击"未回复"显示未回复的客户消息
  3. 未回复提醒

    • 最后两条客户消息显示"未回复"警告
    • 显示未回复时长
    • 红色或橙色警告样式

✅ 辅助回复测试

  1. 快速回复
    • 点击未回复消息的"快速回复"按钮
    • 弹出建议回复面板
    • 显示3-5条建议回复
    • 选择一条回复
    • 显示发送成功提示
    • 消息列表更新

✅ 移动端测试

  1. 响应式布局
    • F12 打开开发者工具
    • 点击"Toggle device toolbar"(手机图标)
    • 选择 iPhone 12 Pro
    • 检查布局是否正常
    • 入群方式改为单列
    • 筛选按钮垂直排列
    • 消息列表适配良好

📊 步骤四:查看控制台日志

测试过程中,控制台会输出详细日志:

🔧 开发模式:使用 localStorage 模拟数据
✅ 用户加载成功: 张三
✅ 项目加载成功: 测试项目 - 现代简约风格装修
✅ 客户加载成功: 李女士
✅ 群聊加载成功: 【李女士】现代简约装修项目群
✅ 部门和组长加载成功
✅ 消息加载完成: {总消息数: 5, 客户消息: 3, 未回复: 2}

🎨 步骤五:测试不同场景

场景1:测试超时未回复(10分钟以上)

修改消息时间为10分钟前:

const groupChat = JSON.parse(localStorage.getItem('mockGroupChat'));
// 将最后一条客户消息改为15分钟前
groupChat.messages[3].msgtime = Math.floor(Date.now() / 1000) - 900; // 15分钟前
groupChat.messages[4].msgtime = Math.floor(Date.now() / 1000) - 850; // 14分钟前
localStorage.setItem('mockGroupChat', JSON.stringify(groupChat));
// 刷新页面
location.reload();

预期效果:

  • 消息显示红色危险警告
  • 显示"15分钟未回复"

场景2:测试已发送群介绍

const groupChat = JSON.parse(localStorage.getItem('mockGroupChat'));
groupChat.introSent = true;
groupChat.introSentAt = new Date().toISOString();
localStorage.setItem('mockGroupChat', JSON.stringify(groupChat));
location.reload();

预期效果:

  • 显示绿色"群介绍已发送"状态
  • 显示发送时间

场景3:测试更多消息

const groupChat = JSON.parse(localStorage.getItem('mockGroupChat'));
// 添加更多消息
for (let i = 0; i < 10; i++) {
  groupChat.messages.push({
    msgid: `msg-extra-${i}`,
    from: i % 2 === 0 ? 'external-user-001' : 'wxwork-user-001',
    msgtime: Math.floor(Date.now() / 1000) - (600 - i * 50),
    msgtype: 'text',
    text: {
      content: i % 2 === 0 ? `客户消息 ${i}` : `技术回复 ${i}`
    }
  });
}
localStorage.setItem('mockGroupChat', JSON.stringify(groupChat));
location.reload();

预期效果:

  • 消息列表显示更多消息
  • 滚动条出现
  • 统计数字更新

🐛 常见问题排查

问题1:页面显示空白

解决方法

// 检查 localStorage 数据
console.log('Company:', localStorage.getItem('company'));
console.log('User:', localStorage.getItem('currentUser'));
console.log('Project:', localStorage.getItem('mockProject'));
console.log('GroupChat:', localStorage.getItem('mockGroupChat'));

// 如果数据不存在,重新执行步骤1.2的代码

问题2:消息列表为空

解决方法

// 检查群聊消息
const groupChat = JSON.parse(localStorage.getItem('mockGroupChat'));
console.log('Messages:', groupChat.messages);
console.log('Messages count:', groupChat.messages.length);

// 如果为空,重新设置
groupChat.messages = [/* 复制步骤1.2中的消息数据 */];
localStorage.setItem('mockGroupChat', JSON.stringify(groupChat));
location.reload();

问题3:路由404错误

解决方法

  1. 确认路由配置是否正确添加
  2. 检查组件是否正确导入
  3. 查看浏览器控制台错误信息

问题4:点击按钮无反应

解决方法

// 检查是否进入开发模式
console.log('wxwork:', this.wxwork);
console.log('wecorp:', this.wecorp);

// 如果为 null,说明进入了开发模式
// 查看控制台是否有 "🔧 开发模式:..." 的日志

🔄 清除测试数据

测试完成后,清除所有模拟数据:

// 清除所有测试数据
localStorage.removeItem('company');
localStorage.removeItem('currentUser');
localStorage.removeItem('mockProject');
localStorage.removeItem('mockContact');
localStorage.removeItem('mockGroupChat');
localStorage.removeItem('mockDepartment');
localStorage.removeItem('mockLeader');

console.log('✅ 所有测试数据已清除');

或者清除所有 localStorage:

localStorage.clear();
console.log('✅ localStorage 已完全清空');

📸 测试截图建议

测试时建议截图保存以下内容:

  1. ✅ 页面整体布局
  2. ✅ 入群方式卡片
  3. ✅ 群介绍文案预览
  4. ✅ 消息列表(全部消息)
  5. ✅ 消息列表(客户消息筛选)
  6. ✅ 消息列表(未回复筛选)
  7. ✅ 未回复警告样式
  8. ✅ 辅助回复面板
  9. ✅ 二维码弹窗
  10. ✅ 移动端布局

🎯 测试完成标准

所有以下项目都通过即为测试完成:

  • 页面正常加载,无报错
  • 所有卡片正常显示
  • 消息列表正常显示
  • 筛选功能正常工作
  • 未回复提醒正常显示
  • 辅助回复功能正常
  • 模拟发送功能正常
  • 移动端布局正常
  • 控制台无错误日志

📝 测试报告模板

# 会话激活功能测试报告

**测试时间**: 2025-11-01
**测试人员**: [你的名字]
**测试环境**: Chrome 浏览器 + localhost:4200

## 测试结果

### 1. 基础功能
- [ ] 页面加载: ✅ 通过 / ❌ 失败
- [ ] 入群方式: ✅ 通过 / ❌ 失败
- [ ] 群介绍: ✅ 通过 / ❌ 失败

### 2. 消息功能
- [ ] 消息列表: ✅ 通过 / ❌ 失败
- [ ] 筛选功能: ✅ 通过 / ❌ 失败
- [ ] 未回复提醒: ✅ 通过 / ❌ 失败

### 3. 辅助回复
- [ ] 快速回复: ✅ 通过 / ❌ 失败
- [ ] 发送消息: ✅ 通过 / ❌ 失败

### 4. 响应式
- [ ] 移动端布局: ✅ 通过 / ❌ 失败

## 发现的问题

1. [问题描述]
2. [问题描述]

## 改进建议

1. [建议内容]
2. [建议内容]

🚀 下一步

测试通过后,可以:

  1. 部署到测试服务器
  2. 在真实企微环境中测试
  3. 收集用户反馈
  4. 优化和改进功能

祝测试顺利! 🎉

如有问题,请查看控制台日志或联系开发团队。