# 企业微信拖拽集成指南 ## 🎯 目标 实现从企业微信群聊拖拽图片和文字到侧边栏,自动上传并启动AI分析。 ## 📊 企业微信拖拽特性 ### 支持的拖拽内容 | 内容类型 | dataTransfer属性 | 说明 | |---------|-----------------|------| | **图片文件** | `files` | File对象数组,包含图片二进制数据 | | **纯文本** | `getData('text/plain')` | 消息文本内容 | | **HTML** | `getData('text/html')` | 富文本消息(可能包含图片标签) | | **URL** | `getData('text/uri-list')` | 图片或文件的URL链接 | ### 拖拽事件序列 ``` 1. dragenter → 鼠标进入目标区域 2. dragover → 鼠标在目标区域移动(持续触发) 3. dragleave → 鼠标离开目标区域 4. drop → 释放拖拽内容 ``` ## 🔧 实现方案 ### 方案1: 增强现有拖拽区域 **位置**: `space-requirements-management.component.html` ```html
@if (isWeChatEnv) {
💬

从群聊拖拽到这里

支持图片、文字、混合内容

🤖 AI将自动分析并智能归类

} @else {

拖拽参考图片到此

或点击下方按钮上传

AI将自动分析图片并智能分类

} @if (isDragOver && dragOverSpaceId === space.id) {

松开鼠标即可上传

}
``` ### 方案2: 拖拽内容解析 **位置**: `stage-requirements.component.ts` ```typescript /** * 解析企业微信拖拽数据 */ private parseWeChatDragData(event: DragEvent): { images: File[]; text: string; html: string; urls: string[]; hasContent: boolean; autoAnalyze: boolean; } { const dataTransfer = event.dataTransfer; if (!dataTransfer) { return { images: [], text: '', html: '', urls: [], hasContent: false, autoAnalyze: false }; } console.log('🔍 [企业微信拖拽] dataTransfer.types:', dataTransfer.types); console.log('🔍 [企业微信拖拽] files.length:', dataTransfer.files.length); // 1. 提取图片文件 const images: File[] = []; if (dataTransfer.files && dataTransfer.files.length > 0) { for (let i = 0; i < dataTransfer.files.length; i++) { const file = dataTransfer.files[i]; if (file.type.startsWith('image/')) { images.push(file); console.log(`📸 [图片文件] ${file.name} (${(file.size/1024).toFixed(2)}KB)`); } } } // 2. 提取文本内容 const text = dataTransfer.getData('text/plain') || ''; if (text) { console.log(`📝 [文本内容] ${text.substring(0, 100)}${text.length > 100 ? '...' : ''}`); } // 3. 提取HTML内容(可能包含图片标签) const html = dataTransfer.getData('text/html') || ''; if (html) { console.log(`🌐 [HTML内容] 长度: ${html.length}`); // 可选:从HTML中提取图片URL const imgUrls = this.extractImageUrlsFromHtml(html); if (imgUrls.length > 0) { console.log(`🖼️ [HTML图片] ${imgUrls.length}个`, imgUrls); } } // 4. 提取URL列表 const urlList = dataTransfer.getData('text/uri-list') || ''; const urls = urlList.split('\n').filter(url => url.trim() && !url.startsWith('#')); if (urls.length > 0) { console.log(`🔗 [URL列表] ${urls.length}个`, urls); } // 5. 判断是否有内容 const hasContent = images.length > 0 || text.length > 0 || urls.length > 0; // 6. 判断是否自动启动AI分析(有图片或有丰富文本) const autoAnalyze = images.length > 0 || text.length > 50; return { images, text, html, urls, hasContent, autoAnalyze }; } /** * 从HTML中提取图片URL */ private extractImageUrlsFromHtml(html: string): string[] { const imgRegex = /]+src="([^"]+)"/gi; const urls: string[] = []; let match; while ((match = imgRegex.exec(html)) !== null) { urls.push(match[1]); } return urls; } /** * 检测是否为企业微信环境 */ private isWeChatWorkEnv(): boolean { const ua = window.navigator.userAgent.toLowerCase(); return ua.includes('wxwork') || ua.includes('qywechat'); } ``` ### 方案3: 增强的拖拽处理 **位置**: `stage-requirements.component.ts` ```typescript /** * 增强的拖拽处理(支持企业微信) */ async onDrop(event: DragEvent, spaceId: string): Promise { event.preventDefault(); event.stopPropagation(); this.isDragOver = false; this.dragOverSpaceId = ''; console.log('📥 [拖拽放下] 空间ID:', spaceId); console.log('📥 [拖拽放下] 环境:', this.isWeChatWorkEnv() ? '企业微信' : '普通浏览器'); // 1. 解析拖拽数据 const dragData = this.parseWeChatDragData(event); if (!dragData.hasContent) { console.warn('⚠️ [拖拽放下] 未检测到有效内容'); return; } console.log('✅ [拖拽放下] 解析结果:', { 图片数量: dragData.images.length, 文字长度: dragData.text.length, URL数量: dragData.urls.length, 自动分析: dragData.autoAnalyze }); // 2. 处理图片文件 if (dragData.images.length > 0) { console.log(`📤 [开始上传] ${dragData.images.length}个图片文件`); await this.uploadAndAnalyzeImages(dragData.images, spaceId); } // 3. 处理URL列表(下载并上传) if (dragData.urls.length > 0) { console.log(`🔗 [处理URL] ${dragData.urls.length}个图片链接`); await this.downloadAndUploadFromUrls(dragData.urls, spaceId); } // 4. 处理文本内容(保存到特殊需求) if (dragData.text && dragData.text.length > 0) { console.log(`💾 [保存文本] 到特殊需求 (${dragData.text.length}字)`); const existingReq = this.getSpaceSpecialRequirements(spaceId) || ''; const newReq = existingReq ? `${existingReq}\n\n--- 从企业微信拖拽 ---\n${dragData.text}` : dragData.text; this.setSpaceSpecialRequirements(spaceId, newReq); } // 5. 可选:自动启动AI设计分析 if (dragData.autoAnalyze && dragData.images.length > 0) { console.log('🤖 [自动分析] 启动AI设计分析'); setTimeout(() => { this.openAIDesignDialogWithFiles(spaceId, dragData.images, dragData.text); }, 1000); // 等待上传完成 } this.cdr.markForCheck(); } /** * 从URL下载并上传图片 */ private async downloadAndUploadFromUrls(urls: string[], spaceId: string): Promise { for (const url of urls) { try { // 检查是否为图片URL if (!this.isImageUrl(url)) { console.warn(`⚠️ [非图片URL] ${url}`); continue; } console.log(`📥 [下载图片] ${url}`); // 使用fetch下载图片 const response = await fetch(url); if (!response.ok) { throw new Error(`下载失败: ${response.statusText}`); } const blob = await response.blob(); const fileName = this.extractFileNameFromUrl(url) || `image_${Date.now()}.jpg`; const file = new File([blob], fileName, { type: blob.type || 'image/jpeg' }); console.log(`✅ [下载完成] ${fileName} (${(blob.size/1024).toFixed(2)}KB)`); // 上传图片 await this.uploadAndAnalyzeImages([file], spaceId); } catch (error) { console.error(`❌ [下载失败] ${url}`, error); } } } /** * 判断是否为图片URL */ private isImageUrl(url: string): boolean { const imageExts = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.svg']; const lowerUrl = url.toLowerCase(); return imageExts.some(ext => lowerUrl.includes(ext)) || lowerUrl.includes('image') || lowerUrl.includes('photo'); } /** * 从URL提取文件名 */ private extractFileNameFromUrl(url: string): string | null { try { const urlObj = new URL(url); const pathname = urlObj.pathname; const segments = pathname.split('/'); return segments[segments.length - 1] || null; } catch { return null; } } /** * 打开AI设计分析弹窗并预填内容 */ private openAIDesignDialogWithFiles(spaceId: string, files: File[], text: string): void { // 1. 打开弹窗 const space = this.projectProducts.find(p => p.id === spaceId); if (!space) return; this.openAIDesignDialog(space); // 2. 等待组件初始化后,预填内容 setTimeout(() => { // 假设有AI分析组件引用 if (this.aiDesignAnalysisComponent) { this.aiDesignAnalysisComponent.aiDesignTextDescription = text; this.aiDesignAnalysisComponent.processAIFiles(files); // 可选:自动启动分析 // this.aiDesignAnalysisComponent.startAIDesignAnalysis(); } }, 500); } ``` ## 🎨 UI优化 ### 企业微信侧边栏适配 **位置**: `space-requirements-management.component.scss` ```scss // 企业微信环境检测 .wechat-mode { // 侧边栏宽度:280-400px .drag-drop-zone { min-height: 100px; // 减小高度 padding: 16px; .wechat-hint { text-align: center; .wechat-icon { font-size: 32px; margin-bottom: 8px; animation: pulse 2s infinite; } h4 { font-size: 14px; margin: 8px 0; color: #1a202c; } p { font-size: 12px; color: #718096; margin: 4px 0; } .ai-hint { color: #667eea; font-weight: 600; margin-top: 8px; } } } // 拖拽反馈 &.drag-over { .drag-feedback { display: flex; flex-direction: column; align-items: center; .feedback-icon { font-size: 48px; animation: bounce 0.6s infinite; } p { margin-top: 8px; font-size: 14px; font-weight: 600; color: #667eea; } } } } @keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.8; transform: scale(1.1); } } @keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } } // 移动端和企业微信侧边栏 @media (max-width: 480px) { .space-requirements-card { padding: 12px; .drag-drop-zone { min-height: 80px; padding: 12px; h4 { font-size: 13px; } p { font-size: 11px; } } // 图片类型标签:2x2网格 .image-type-tabs-scroll { grid-template-columns: repeat(2, 1fr); gap: 6px; .tab-button { padding: 8px 12px; font-size: 12px; min-height: 40px; } } // 图片展示:2列网格 .images-grid { grid-template-columns: repeat(2, 1fr); gap: 8px; } } } ``` ## 📱 进度提示优化 ### 上传进度Toast **位置**: `stage-requirements.component.ts` ```typescript /** * 显示上传摘要(企业微信友好) */ private showUploadSummary(results: { success: string[], failed: Array<{name: string, error: string}> }): void { const successCount = results.success.length; const failedCount = results.failed.length; if (failedCount === 0) { // 全部成功 - 使用Toast if (window?.fmode?.toast?.success) { window.fmode.toast.success(`✅ 成功上传 ${successCount} 个文件\n🤖 AI正在分析中...`); } else { console.log(`✅ 成功上传 ${successCount} 个文件,AI正在分析中...`); } } else if (successCount === 0) { // 全部失败 - 使用Alert const message = `上传失败\n\n${results.failed.map(f => `• ${f.name}\n ${f.error}`).join('\n\n')}`; window?.fmode?.alert?.(message); } else { // 部分成功 - 使用详细Alert const message = [ `上传完成`, ``, `✅ 成功: ${successCount} 个`, `❌ 失败: ${failedCount} 个`, ``, `失败文件:`, ...results.failed.map(f => `• ${f.name}\n ${f.error}`) ].join('\n'); window?.fmode?.alert?.(message); } } ``` ## 🧪 测试场景 ### 测试1: 拖拽单张图片 ``` 操作:从企业微信群聊拖拽1张图片到侧边栏 预期: ✅ 图片成功上传 ✅ AI自动分析并归类 ✅ 显示在对应类型标签页 ✅ Toast提示"成功上传1个文件" ``` ### 测试2: 拖拽多张图片 ``` 操作:从企业微信群聊拖拽3张图片到侧边栏 预期: ✅ 3张图片全部上传 ✅ AI批量分析 ✅ 按类型自动归类 ✅ Toast提示"成功上传3个文件" ``` ### 测试3: 拖拽图片+文字 ``` 操作:从企业微信群聊拖拽图片和文字到侧边栏 预期: ✅ 图片上传成功 ✅ 文字保存到特殊需求 ✅ 自动打开AI分析弹窗 ✅ 文字预填到描述框 ``` ### 测试4: 拖拽纯文字 ``` 操作:从企业微信群聊拖拽文字到侧边栏 预期: ✅ 文字保存到特殊需求 ⚠️ 不启动AI分析(无图片) ✅ Toast提示"已保存到特殊需求" ``` ### 测试5: 拖拽失败场景 ``` 操作:拖拽超大文件(>10MB) 预期: ❌ 上传被拒绝 ✅ Alert提示"文件过大" ✅ 显示失败文件列表 ``` ## 🔍 调试技巧 ### 控制台日志 ```typescript // 在onDrop方法中添加详细日志 console.log('🔍 [拖拽调试] dataTransfer:', { types: Array.from(event.dataTransfer?.types || []), files: event.dataTransfer?.files, filesCount: event.dataTransfer?.files?.length || 0, items: event.dataTransfer?.items, itemsCount: event.dataTransfer?.items?.length || 0 }); // 遍历DataTransferItem if (event.dataTransfer?.items) { for (let i = 0; i < event.dataTransfer.items.length; i++) { const item = event.dataTransfer.items[i]; console.log(`🔍 [Item ${i}]`, { kind: item.kind, type: item.type }); } } ``` ### 网络面板检查 1. 打开开发者工具 → Network 2. 筛选:XHR/Fetch 3. 查找上传请求: - URL包含`upload`或`file` - Method: POST/PUT - Status: 200(成功)或 631(失败) 4. 查看Request Payload:文件数据 5. 查看Response:返回的URL ### 企业微信调试 ```typescript // 检测企业微信环境 console.log('📱 [环境检测]', { userAgent: navigator.userAgent, isWeChatWork: /wxwork|qywechat/i.test(navigator.userAgent), platform: navigator.platform, viewport: { width: window.innerWidth, height: window.innerHeight } }); ``` ## 📝 注意事项 ### 1. 企业微信限制 - **文件大小**: 建议 < 10MB - **文件格式**: JPG、PNG(避免HEIC、WebP) - **并发上传**: 建议 <= 3个文件 - **URL访问**: 需要公网可访问(AI分析需要) ### 2. 安全考虑 - **文件名**: 自动清理中文和特殊字符 - **URL验证**: 检查是否为HTTP/HTTPS - **大小检查**: 限制单文件10MB - **类型检查**: 只允许图片和CAD文件 ### 3. 性能优化 - **异步上传**: 不阻塞UI - **进度反馈**: 实时显示上传进度 - **错误重试**: 自动重试3次 - **批量优化**: 限制并发数量 ### 4. 用户体验 - **拖拽提示**: 明确告知用户可拖拽 - **视觉反馈**: 拖拽中高亮目标区域 - **结果提示**: Toast/Alert显示上传结果 - **AI提示**: 告知AI正在分析 --- **文档版本**: 1.0.0 **创建时间**: 2025-12-03 **适用环境**: 企业微信侧边栏 **兼容性**: 支持Chrome、Safari、企业微信内置浏览器