# 会话激活功能 - 本地测试指南 ## 🎯 测试目标 在电脑端使用 `localStorage` 模拟企微环境,测试会话激活功能的完整流程。 --- ## 📋 准备工作 ### 1. 启动开发服务器 ```bash cd yss-project npm install # 如果还没安装依赖 ng serve ``` 服务器启动后,访问:`http://localhost:4200` --- ## 🔧 步骤一:配置 localStorage 模拟数据 ### 1.1 打开浏览器控制台 按 `F12` 或右键 → 检查,打开开发者工具,切换到 **Console** 标签页。 ### 1.2 设置基础数据 在控制台中依次执行以下代码: ```javascript // ========== 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 支持: ```typescript 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 修改发送消息方法(开发环境模拟) ```typescript 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. **群介绍文案** - [ ] 显示预览文案 - [ ] 文案包含:项目主管(王组长)、执行技术(张三)、项目需求 - [ ] 点击"自动发送群介绍"按钮 - [ ] 显示发送成功提示 - [ ] 刷新后显示"群介绍已发送"状态 #### ✅ 消息功能测试 4. **消息列表** - [ ] 显示5条消息 - [ ] 客户消息有蓝色标识 - [ ] 显示统计:5条消息,3条客户消息 5. **筛选功能** - [ ] 点击"全部"显示5条消息 - [ ] 点击"客户消息"显示3条客户消息 - [ ] 点击"未回复"显示未回复的客户消息 6. **未回复提醒** - [ ] 最后两条客户消息显示"未回复"警告 - [ ] 显示未回复时长 - [ ] 红色或橙色警告样式 #### ✅ 辅助回复测试 7. **快速回复** - [ ] 点击未回复消息的"快速回复"按钮 - [ ] 弹出建议回复面板 - [ ] 显示3-5条建议回复 - [ ] 选择一条回复 - [ ] 显示发送成功提示 - [ ] 消息列表更新 #### ✅ 移动端测试 8. **响应式布局** - [ ] 按 `F12` 打开开发者工具 - [ ] 点击"Toggle device toolbar"(手机图标) - [ ] 选择 iPhone 12 Pro - [ ] 检查布局是否正常 - [ ] 入群方式改为单列 - [ ] 筛选按钮垂直排列 - [ ] 消息列表适配良好 --- ## 📊 步骤四:查看控制台日志 测试过程中,控制台会输出详细日志: ``` 🔧 开发模式:使用 localStorage 模拟数据 ✅ 用户加载成功: 张三 ✅ 项目加载成功: 测试项目 - 现代简约风格装修 ✅ 客户加载成功: 李女士 ✅ 群聊加载成功: 【李女士】现代简约装修项目群 ✅ 部门和组长加载成功 ✅ 消息加载完成: {总消息数: 5, 客户消息: 3, 未回复: 2} ``` --- ## 🎨 步骤五:测试不同场景 ### 场景1:测试超时未回复(10分钟以上) 修改消息时间为10分钟前: ```javascript 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:测试已发送群介绍 ```javascript const groupChat = JSON.parse(localStorage.getItem('mockGroupChat')); groupChat.introSent = true; groupChat.introSentAt = new Date().toISOString(); localStorage.setItem('mockGroupChat', JSON.stringify(groupChat)); location.reload(); ``` 预期效果: - 显示绿色"群介绍已发送"状态 - 显示发送时间 ### 场景3:测试更多消息 ```javascript 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:页面显示空白 **解决方法**: ```javascript // 检查 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:消息列表为空 **解决方法**: ```javascript // 检查群聊消息 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:点击按钮无反应 **解决方法**: ```javascript // 检查是否进入开发模式 console.log('wxwork:', this.wxwork); console.log('wecorp:', this.wecorp); // 如果为 null,说明进入了开发模式 // 查看控制台是否有 "🔧 开发模式:..." 的日志 ``` --- ## 🔄 清除测试数据 测试完成后,清除所有模拟数据: ```javascript // 清除所有测试数据 localStorage.removeItem('company'); localStorage.removeItem('currentUser'); localStorage.removeItem('mockProject'); localStorage.removeItem('mockContact'); localStorage.removeItem('mockGroupChat'); localStorage.removeItem('mockDepartment'); localStorage.removeItem('mockLeader'); console.log('✅ 所有测试数据已清除'); ``` 或者清除所有 localStorage: ```javascript localStorage.clear(); console.log('✅ localStorage 已完全清空'); ``` --- ## 📸 测试截图建议 测试时建议截图保存以下内容: 1. ✅ 页面整体布局 2. ✅ 入群方式卡片 3. ✅ 群介绍文案预览 4. ✅ 消息列表(全部消息) 5. ✅ 消息列表(客户消息筛选) 6. ✅ 消息列表(未回复筛选) 7. ✅ 未回复警告样式 8. ✅ 辅助回复面板 9. ✅ 二维码弹窗 10. ✅ 移动端布局 --- ## 🎯 测试完成标准 所有以下项目都通过即为测试完成: - [x] 页面正常加载,无报错 - [x] 所有卡片正常显示 - [x] 消息列表正常显示 - [x] 筛选功能正常工作 - [x] 未回复提醒正常显示 - [x] 辅助回复功能正常 - [x] 模拟发送功能正常 - [x] 移动端布局正常 - [x] 控制台无错误日志 --- ## 📝 测试报告模板 ```markdown # 会话激活功能测试报告 **测试时间**: 2025-11-01 **测试人员**: [你的名字] **测试环境**: Chrome 浏览器 + localhost:4200 ## 测试结果 ### 1. 基础功能 - [ ] 页面加载: ✅ 通过 / ❌ 失败 - [ ] 入群方式: ✅ 通过 / ❌ 失败 - [ ] 群介绍: ✅ 通过 / ❌ 失败 ### 2. 消息功能 - [ ] 消息列表: ✅ 通过 / ❌ 失败 - [ ] 筛选功能: ✅ 通过 / ❌ 失败 - [ ] 未回复提醒: ✅ 通过 / ❌ 失败 ### 3. 辅助回复 - [ ] 快速回复: ✅ 通过 / ❌ 失败 - [ ] 发送消息: ✅ 通过 / ❌ 失败 ### 4. 响应式 - [ ] 移动端布局: ✅ 通过 / ❌ 失败 ## 发现的问题 1. [问题描述] 2. [问题描述] ## 改进建议 1. [建议内容] 2. [建议内容] ``` --- ## 🚀 下一步 测试通过后,可以: 1. 部署到测试服务器 2. 在真实企微环境中测试 3. 收集用户反馈 4. 优化和改进功能 --- **祝测试顺利!** 🎉 如有问题,请查看控制台日志或联系开发团队。