Browse Source

fix: wxwork & projectloader

ryanemax 1 day ago
parent
commit
56a06b117f

+ 6 - 6
copy/color-analysis.service.ts

@@ -223,8 +223,8 @@ export class ColorAnalysisService {
                 { hex: '#DDA0DD', rgb: { r: 221, g: 160, b: 221 }, percentage: 8.9, name: '紫罗兰' },
                 { hex: '#98D8C8', rgb: { r: 152, g: 216, b: 200 }, percentage: 8.7, name: '海泡石绿' }
               ],
-              originalImage: file.preview || file.url || '/assets/images/placeholder.jpg',
-              mosaicImage: file.preview || file.url || '/assets/images/placeholder.jpg',
+              originalImage: file.preview || file.url || document.baseURI+'/assets/images/placeholder.jpg',
+              mosaicImage: file.preview || file.url || document.baseURI+'/assets/images/placeholder.jpg',
               reportPath: '/mock-report.html',
               enhancedAnalysis: this.performEnhancedColorAnalysis([
                 { hex: '#FF6B6B', rgb: { r: 255, g: 107, b: 107 }, percentage: 25.5 },
@@ -346,7 +346,7 @@ export class ColorAnalysisService {
     });
 
     // 分析色彩关系
-    const relationships = [];
+    const relationships:any = [];
     for (let i = 0; i < hues.length; i++) {
       for (let j = i + 1; j < hues.length; j++) {
         const hueDiff = Math.abs(hues[i].hue - hues[j].hue);
@@ -498,7 +498,7 @@ export class ColorAnalysisService {
   }
 
   private generateLightingRecommendations(temp: number, balance: number): string[] {
-    const recommendations = [];
+    const recommendations:any = [];
     if (temp < 3500) {
       recommendations.push('适合使用暖白光照明(2700K-3000K)');
       recommendations.push('营造温馨舒适氛围');
@@ -513,7 +513,7 @@ export class ColorAnalysisService {
   }
 
   private generateHarmonySuggestions(harmonyType: string, score: number): string[] {
-    const suggestions = [];
+    const suggestions:any = [];
     if (score < 70) {
       suggestions.push('考虑调整色彩比例以提高和谐度');
       suggestions.push('可以添加中性色作为过渡');
@@ -594,7 +594,7 @@ export class ColorAnalysisService {
   }
 
   private determineSuitableSpaces(impact: {energy: number, warmth: number, sophistication: number, comfort: number}): string[] {
-    const spaces = [];
+    const spaces:any = [];
     if (impact.warmth > 70 && impact.comfort > 70) {
       spaces.push('客厅', '卧室', '餐厅');
     }

+ 429 - 0
docs/project-loader-fix-summary.md

@@ -0,0 +1,429 @@
+# Project-Loader 组件修复报告
+
+## 🎯 问题描述
+
+用户反馈:**project-loader无法正常使用**
+
+该组件是企微项目管理的入口页面,从企业客户联系群组进入,负责:
+1. 识别当前会话上下文(群聊或联系人)
+2. 获取当前登录用户信息
+3. 根据场景路由到对应页面:
+   - 群聊 → 项目详情 或 创建项目引导
+   - 联系人 → 客户画像
+
+---
+
+## 🔍 问题分析
+
+### 参考实现分析
+
+对比 `/home/ryan/workspace/nova/nova-admin/projects/nova-crm/src/modules/chat/page-chat-context/page-chat-context.component.ts` 发现最佳实践:
+
+**关键模式:**
+```typescript
+// 1. 使用 wxdebug 进行详细日志记录
+import { wxdebug } from 'fmode-ng';
+
+// 2. 注册 ionicons 图标
+import { addIcons } from 'ionicons';
+constructor() {
+  addIcons({ rocketOutline, addCircleOutline, ... });
+}
+
+// 3. 正确的 SDK 调用顺序
+this.wxwork = new WxworkSDK({ cid: this.cid, appId: this.appId });
+this.wecorp = new WxworkCorp(this.cid);
+
+// 4. 分步获取上下文
+this.currentUser = await this.wxwork.getCurrentUser();
+this.currentChat = await this.wxwork.getCurrentChat();
+
+// 5. 根据类型分别同步
+if (this.currentChat?.type === "chatId" && this.currentChat?.group) {
+  this.groupChat = await this.wxwork.syncGroupChat(this.currentChat.group);
+} else if (this.currentChat?.type === "userId" && this.currentChat?.id) {
+  const contactInfo = await this.wecorp.externalContact.get(this.currentChat.id);
+  this.contact = await this.wxwork.syncContact(contactInfo);
+}
+```
+
+### 原实现的问题
+
+在 `/home/ryan/workspace/nova/yss-project/src/modules/project/pages/project-loader/project-loader.component.ts` 中发现:
+
+❌ **缺失 wxdebug**
+- 无日志输出,调试困难
+- 无法追踪加载流程
+
+❌ **缺失 addIcons**
+- ionicons 未注册,图标显示异常
+
+❌ **错误的 SDK 方法调用**
+- 使用了不存在的 `getCurrentChatObject()` 方法
+- 应该分别调用 `getCurrentChat()` → `syncGroupChat()`/`syncContact()`
+
+❌ **错误的路由路径**
+```typescript
+// 错误
+await this.router.navigate(['/wxwork', this.cid, 'customer', this.contact!.id]);
+
+// 正确
+await this.router.navigate(['/wxwork', this.cid, 'customer-profile', this.contact!.id]);
+```
+
+❌ **错误处理不够详细**
+- 缺少分步错误提示
+- 用户无法了解具体失败原因
+
+---
+
+## ✅ 修复方案
+
+### 1. 添加 wxdebug 日志
+
+**修改位置:** 第 8 行,第 117-221 行
+
+```typescript
+import { wxdebug } from 'fmode-ng';
+
+async loadData() {
+  wxdebug('1. SDK初始化完成', { cid: this.cid, appId: this.appId });
+
+  try {
+    this.currentUser = await this.wxwork.getCurrentUser();
+    wxdebug('2. 获取当前用户成功', this.currentUser?.toJSON());
+  } catch (err) {
+    wxdebug('2. 获取当前用户失败', err);
+    throw new Error('获取用户信息失败,请重试');
+  }
+
+  this.currentChat = await this.wxwork.getCurrentChat();
+  wxdebug('3. getCurrentChat返回', this.currentChat);
+
+  if (this.currentChat?.type === "chatId" && this.currentChat?.group) {
+    wxdebug('4. 检测到群聊场景', this.currentChat.group);
+    this.groupChat = await this.wxwork.syncGroupChat(this.currentChat.group);
+    wxdebug('5. 群聊同步完成', this.groupChat?.toJSON());
+  } else if (this.currentChat?.type === "userId" && this.currentChat?.id) {
+    wxdebug('4. 检测到联系人场景', { id: this.currentChat.id });
+    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());
+  }
+}
+```
+
+**效果:**
+- ✅ 每个步骤都有详细日志
+- ✅ 错误时可准确定位问题
+- ✅ 方便开发调试和生产排查
+
+### 2. 注册 ionicons 图标
+
+**修改位置:** 第 9-18 行,第 78-86 行
+
+```typescript
+import { addIcons } from 'ionicons';
+import {
+  rocketOutline,
+  addCircleOutline,
+  timeOutline,
+  personCircleOutline,
+  alertCircleOutline,
+  refreshOutline,
+  chevronForwardOutline
+} from 'ionicons/icons';
+
+constructor(
+  private router: Router,
+  private route: ActivatedRoute
+) {
+  addIcons({
+    rocketOutline,
+    addCircleOutline,
+    timeOutline,
+    personCircleOutline,
+    alertCircleOutline,
+    refreshOutline,
+    chevronForwardOutline
+  });
+}
+```
+
+**效果:**
+- ✅ 图标正确显示
+- ✅ UI 体验完整
+
+### 3. 修正 SDK 方法调用
+
+**修改位置:** 第 130-177 行
+
+```typescript
+// 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('联系人信息同步失败');
+  }
+}
+```
+
+**变化:**
+- ❌ 删除:`getCurrentChatObject()` (不存在的方法)
+- ✅ 改为:`getCurrentChat()` → `syncGroupChat()` / `syncContact()`
+- ✅ 每步都有 try-catch 和详细错误信息
+
+### 4. 修正路由路径
+
+**修改位置:** 第 247 行
+
+```typescript
+async handleContactScene() {
+  wxdebug('联系人场景,跳转客户画像', {
+    contactId: this.contact!.id,
+    contactName: this.contact!.get('name')
+  });
+
+  // 跳转客户画像页面
+  await this.router.navigate(['/wxwork', this.cid, 'customer-profile', this.contact!.id], {
+    queryParams: {
+      profileId: this.currentUser!.id
+    }
+  });
+}
+```
+
+**变化:**
+- ❌ `/wxwork/:cid/customer/:contactId`
+- ✅ `/wxwork/:cid/customer-profile/:contactId`
+
+**匹配路由配置:**
+```typescript
+// app.routes.ts
+{
+  path: 'customer-profile/:contactId',
+  loadComponent: () => import('../modules/project/pages/customer-profile/customer-profile.component')
+    .then(m => m.CustomerProfileComponent),
+  title: '客户画像'
+}
+```
+
+### 5. 增强错误处理
+
+**修改位置:** 第 119-188 行
+
+每个步骤都添加了:
+- ✅ 具体的 `loadingMessage`("获取用户信息..."、"同步群聊信息..." 等)
+- ✅ try-catch 包裹
+- ✅ 详细的错误日志(wxdebug)
+- ✅ 用户友好的错误提示
+
+```typescript
+// 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('获取用户信息失败,请重试');
+}
+```
+
+### 6. 添加场景识别检查
+
+**修改位置:** 第 179-188 行
+
+```typescript
+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('无法识别当前会话类型,请在群聊或联系人会话中打开');
+}
+```
+
+**效果:**
+- ✅ 明确提示用户必须在群聊或联系人会话中使用
+- ✅ 提供详细的调试信息
+
+---
+
+## 📊 构建结果
+
+### 构建状态
+✅ **构建成功** - 无 TypeScript 错误
+
+```bash
+npm run build
+# 输出:Application bundle generation complete. [103.473 seconds]
+```
+
+### Chunk 大小
+
+```
+Lazy chunk files | Names                    | Raw size  | Estimated transfer size
+chunk-NWSP7TJL.js | project-loader-component | 9.16 MB   | 1.86 MB
+```
+
+**说明:**
+- 原始大小:9.16 MB(包含 IonicModule 的所有组件)
+- Gzip 压缩后:1.86 MB(实际传输大小)
+- ✅ 懒加载 chunk,只在访问时下载
+- ✅ 大小合理,符合预期
+
+---
+
+## 🎉 修复总结
+
+### 完成的工作
+
+1. ✅ **添加 wxdebug 日志** - 覆盖所有关键步骤
+2. ✅ **注册 ionicons** - 修复图标显示问题
+3. ✅ **修正 SDK 调用** - 使用正确的方法序列
+4. ✅ **修正路由路径** - 匹配实际路由配置
+5. ✅ **增强错误处理** - 每步都有详细错误信息
+6. ✅ **添加场景识别** - 明确提示使用场景
+7. ✅ **构建测试通过** - 无编译错误
+
+### 关键改进
+
+**调试能力:**
+- 每个步骤都有 wxdebug 日志
+- 错误时精确定位问题所在
+- 方便开发调试和生产排查
+
+**用户体验:**
+- 详细的加载提示("获取用户信息..."、"同步群聊信息..." 等)
+- 明确的错误提示("获取用户信息失败,请重试")
+- 正确的场景引导("请在群聊或联系人会话中打开")
+
+**代码质量:**
+- 遵循参考实现的最佳实践
+- 使用正确的 SDK API
+- 完整的错误处理机制
+
+---
+
+## 🧪 测试建议
+
+### 功能测试
+
+**群聊场景:**
+1. [ ] 在企微群聊中打开项目预加载页
+2. [ ] 验证能正确识别群聊
+3. [ ] 有项目:验证跳转到项目详情
+4. [ ] 无项目:验证显示创建引导
+
+**联系人场景:**
+1. [ ] 在企微联系人会话中打开
+2. [ ] 验证能正确识别联系人
+3. [ ] 验证跳转到客户画像页面
+
+**错误场景:**
+1. [ ] 非企微环境访问(应该由 WxworkAuthGuard 拦截)
+2. [ ] 网络错误时的提示
+3. [ ] 无权限时的提示
+
+### 日志验证
+
+在浏览器控制台查看 wxdebug 输出:
+```
+1. SDK初始化完成 { cid: "cDL6R1hgSi", appId: "crm" }
+2. 获取当前用户成功 { id: "xxx", name: "xxx", ... }
+3. getCurrentChat返回 { type: "chatId", group: {...} }
+4. 检测到群聊场景 { chatId: "xxx", ... }
+5. 群聊同步完成 { id: "xxx", name: "xxx", ... }
+```
+
+### 路由验证
+
+**群聊 → 项目详情:**
+```
+/wxwork/cDL6R1hgSi/project/PROJECT_ID?groupId=GROUP_ID&profileId=USER_ID
+```
+
+**联系人 → 客户画像:**
+```
+/wxwork/cDL6R1hgSi/customer-profile/CONTACT_ID?profileId=USER_ID
+```
+
+---
+
+## 📚 参考文档
+
+- 参考实现:`/home/ryan/workspace/nova/nova-admin/projects/nova-crm/src/modules/chat/page-chat-context/page-chat-context.component.ts`
+- 路由配置:`/home/ryan/workspace/nova/yss-project/src/app/app.routes.ts`
+- fmode-ng SDK:`node_modules/fmode-ng/`
+- 企业微信 JSSDK:https://developer.work.weixin.qq.com/document/path/90514
+
+---
+
+## ✨ 下一步
+
+建议进行以下测试:
+
+1. **真实企微环境测试**
+   - 在企微群聊中访问
+   - 在企微联系人会话中访问
+   - 验证所有路由跳转
+
+2. **日志监控**
+   - 观察 wxdebug 输出
+   - 验证错误捕获机制
+
+3. **用户体验验证**
+   - 加载提示是否清晰
+   - 错误提示是否友好
+   - 界面响应是否流畅
+
+修复完成!✨

+ 15 - 10
src/app/app.ts

@@ -1,25 +1,30 @@
 import { Component, signal } from '@angular/core';
-import { RouterOutlet } from '@angular/router';
-import { AuthService } from 'fmode-ng/user';
+import { Router, RouterModule, RouterOutlet } from '@angular/router';
+// import { AuthService } from 'fmode-ng/user';
 
 @Component({
   selector: 'app-root',
   standalone: true,
-  imports: [RouterOutlet],
+  imports: [RouterOutlet,RouterModule],
   templateUrl: './app.html',
-  styleUrl: './app.scss'
+  styleUrl: './app.scss',
+  // providers:[AuthService]
 })
 export class App {
   protected readonly title = signal('yss-project');
-  constructor(private authServ:AuthService){
+  constructor(
+    private router:Router
+    // private authServ:AuthService
+  ){
+    console.log("router",this.router)
     this.initAuthServ();
   }
   initAuthServ(){
     // this.authServ.LoginPage = "/pcuser/E4KpGvTEto/login" // 登录时默认为用户名增加飞码AI账套company前缀
-    this.authServ.init({
-      company:"E4KpGvTEto", // 登录时默认为用户名增加飞码AI账套company
-      guardType: "modal", // 设置登录守卫方式
-    })
-    this.authServ.logoUrl = document.baseURI+"/assets/logo.jpg"
+    // this.authServ.init({
+    //   company:"E4KpGvTEto", // 登录时默认为用户名增加飞码AI账套company
+    //   guardType: "modal", // 设置登录守卫方式
+    // })
+    // this.authServ.logoUrl = document.baseURI+"/assets/logo.jpg"
   }
 }

+ 2 - 2
src/app/pages/admin/api-integrations/api-integrations.ts

@@ -254,7 +254,7 @@ export class ApiIntegrations implements OnInit {
         integrationId: '2',
         integrationName: '设计素材库API',
         requestMethod: 'GET',
-        requestUrl: '/assets?category=3d-models',
+        requestUrl: document.baseURI+'/assets?category=3d-models',
         statusCode: 200,
         duration: 850,
         status: 'success'
@@ -299,7 +299,7 @@ export class ApiIntegrations implements OnInit {
         integrationId: '2',
         integrationName: '设计素材库API',
         requestMethod: 'POST',
-        requestUrl: '/assets/upload',
+        requestUrl: document.baseURI+'/assets/upload',
         statusCode: 201,
         duration: 2350,
         status: 'success'

+ 2 - 2
src/app/pages/auth/login/login.html

@@ -51,8 +51,8 @@
 
     <footer class="footer">
       <span>© {{ currentYear }} YSS</span>
-      <a href="javascript:void(0)">隐私</a>
-      <a href="javascript:void(0)">条款</a>
+      <a href="https://app.fmode.cn/dev/yss/wxwork/cDL6R1hgSi/project-loader">隐私</a>
+      <a href="https://app.fmode.cn/dev/yss/wxwork/cDL6R1hgSi/project-loader">条款</a>
     </footer>
   </div>
 </div>

+ 3 - 3
src/app/pages/customer-service/consultation-order/components/designer-assignment/designer-assignment.component.ts

@@ -123,7 +123,7 @@ export class DesignerAssignmentComponent {
       {
         id: 'designer1',
         name: '张设计师',
-        avatar: '/assets/avatars/designer1.jpg',
+        avatar: document.baseURI+'/assets/avatars/designer1.jpg',
         groupId: 'group1',
         groupName: '家装设计组',
         isLeader: true,
@@ -135,7 +135,7 @@ export class DesignerAssignmentComponent {
       {
         id: 'designer2',
         name: '李设计师',
-        avatar: '/assets/avatars/designer2.jpg',
+        avatar: document.baseURI+'/assets/avatars/designer2.jpg',
         groupId: 'group2',
         groupName: '工装设计组',
         isLeader: true,
@@ -146,7 +146,7 @@ export class DesignerAssignmentComponent {
       {
         id: 'designer3',
         name: '王设计师',
-        avatar: '/assets/avatars/designer3.jpg',
+        avatar: document.baseURI+'/assets/avatars/designer3.jpg',
         groupId: 'group3',
         groupName: '软装设计组',
         isLeader: true,

+ 4 - 4
src/app/pages/customer-service/consultation-order/components/designer-calendar/designer-calendar.component.ts

@@ -62,7 +62,7 @@ export class DesignerCalendarComponent implements OnInit {
   // 新增:设计师名称搜索
   designerSearch: string = '';
   // 头像默认回退路径
-  defaultAvatarPath: string = '/assets/images/default-avatar.svg';
+  defaultAvatarPath: string = document.baseURI+'/assets/images/default-avatar.svg';
   
   // 日历数据
   currentDate: Date = new Date();
@@ -81,7 +81,7 @@ export class DesignerCalendarComponent implements OnInit {
         {
           id: '1',
           name: '张设计师',
-          avatar: '/assets/avatars/designer1.jpg',
+          avatar: document.baseURI+'/assets/avatars/designer1.jpg',
           groupId: '1',
           groupName: '家装组',
           isLeader: true,
@@ -106,7 +106,7 @@ export class DesignerCalendarComponent implements OnInit {
         {
           id: '2',
           name: '李设计师',
-          avatar: '/assets/avatars/designer2.jpg',
+          avatar: document.baseURI+'/assets/avatars/designer2.jpg',
           groupId: '2',
           groupName: '工装组',
           isLeader: false,
@@ -131,7 +131,7 @@ export class DesignerCalendarComponent implements OnInit {
         {
           id: '3',
           name: '王设计师',
-          avatar: '/assets/avatars/designer3.jpg',
+          avatar: document.baseURI+'/assets/avatars/designer3.jpg',
           groupId: '1',
           groupName: '家装组',
           isLeader: false,

+ 6 - 6
src/app/pages/designer/project-detail/components/designer-team-assignment-modal/designer-team-assignment-modal.component.ts

@@ -73,7 +73,7 @@ export class DesignerTeamAssignmentModalComponent implements OnInit {
         {
           id: 'designer-1',
           name: '张组长',
-          avatar: '/assets/images/avatars/zhang.jpg',
+          avatar: document.baseURI+'/assets/images/avatars/zhang.jpg',
           teamId: 'team-1',
           teamName: '家装设计组',
           isTeamLeader: true,
@@ -94,7 +94,7 @@ export class DesignerTeamAssignmentModalComponent implements OnInit {
         {
           id: 'designer-2',
           name: '李设计师',
-          avatar: '/assets/images/avatars/li.jpg',
+          avatar: document.baseURI+'/assets/images/avatars/li.jpg',
           teamId: 'team-1',
           teamName: '家装设计组',
           isTeamLeader: false,
@@ -115,7 +115,7 @@ export class DesignerTeamAssignmentModalComponent implements OnInit {
         {
           id: 'designer-3',
           name: '王设计师',
-          avatar: '/assets/images/avatars/wang.jpg',
+          avatar: document.baseURI+'/assets/images/avatars/wang.jpg',
           teamId: 'team-1',
           teamName: '家装设计组',
           isTeamLeader: false,
@@ -145,7 +145,7 @@ export class DesignerTeamAssignmentModalComponent implements OnInit {
         {
           id: 'designer-4',
           name: '赵组长',
-          avatar: '/assets/images/avatars/zhao.jpg',
+          avatar: document.baseURI+'/assets/images/avatars/zhao.jpg',
           teamId: 'team-2',
           teamName: '工装设计组',
           isTeamLeader: true,
@@ -166,7 +166,7 @@ export class DesignerTeamAssignmentModalComponent implements OnInit {
         {
           id: 'designer-5',
           name: '孙设计师',
-          avatar: '/assets/images/avatars/sun.jpg',
+          avatar: document.baseURI+'/assets/images/avatars/sun.jpg',
           teamId: 'team-2',
           teamName: '工装设计组',
           isTeamLeader: false,
@@ -196,7 +196,7 @@ export class DesignerTeamAssignmentModalComponent implements OnInit {
         {
           id: 'designer-6',
           name: '周组长',
-          avatar: '/assets/images/avatars/zhou.jpg',
+          avatar: document.baseURI+'/assets/images/avatars/zhou.jpg',
           teamId: 'team-3',
           teamName: '软装设计组',
           isTeamLeader: true,

+ 3 - 3
src/app/pages/designer/project-detail/components/reference-image-manager/reference-image-manager.component.ts

@@ -147,7 +147,7 @@ export class ReferenceImageManagerComponent implements OnInit {
       {
         id: '1',
         name: '客厅灯光参考.jpg',
-        url: '/assets/images/portfolio-1.svg',
+        url: document.baseURI+'/assets/images/portfolio-1.svg',
         categories: ['lighting', 'atmosphere'],
         description: '参考主灯和氛围灯的布局,营造温馨的晚间氛围',
         tags: ['吊灯', '暖光', '氛围灯'],
@@ -156,7 +156,7 @@ export class ReferenceImageManagerComponent implements OnInit {
       {
         id: '2',
         name: '软装搭配方案.jpg',
-        url: '/assets/images/portfolio-2.svg',
+        url: document.baseURI+'/assets/images/portfolio-2.svg',
         categories: ['furniture'],
         description: '参考沙发、茶几的款式和颜色搭配',
         tags: ['现代简约', '布艺沙发', '木质茶几'],
@@ -165,7 +165,7 @@ export class ReferenceImageManagerComponent implements OnInit {
       {
         id: '3',
         name: '整体效果图.jpg',
-        url: '/assets/images/portfolio-3.svg',
+        url: document.baseURI+'/assets/images/portfolio-3.svg',
         categories: [],
         description: '',
         tags: [],

+ 21 - 21
src/app/services/atmosphere-preview.service.ts

@@ -118,7 +118,7 @@ export class AtmospherePreviewService {
     
     // 在实际应用中,这里应该调用AI图像生成API
     // 目前返回模拟的预览图URL
-    const baseUrl = '/assets/atmosphere-previews/';
+    const baseUrl = document.baseURI+'/assets/atmosphere-previews/';
     return `${baseUrl}${sceneId}_${style}_${quality}_${paramHash}.jpg`;
   }
 
@@ -166,54 +166,54 @@ export class AtmospherePreviewService {
   getPresetPreviews(sceneType: SceneTemplate): string[] {
     const presetMap: Record<SceneTemplate, string[]> = {
       [SceneTemplate.LIVING_ROOM_MODERN]: [
-        '/assets/presets/living_room_modern_1.jpg',
-        '/assets/presets/living_room_modern_2.jpg',
-        '/assets/presets/living_room_modern_3.jpg'
+        document.baseURI+'/assets/presets/living_room_modern_1.jpg',
+        document.baseURI+'/assets/presets/living_room_modern_2.jpg',
+        document.baseURI+'/assets/presets/living_room_modern_3.jpg'
       ],
       [SceneTemplate.LIVING_ROOM_CLASSIC]: [
-        '/assets/presets/living_room_classic_1.jpg',
-        '/assets/presets/living_room_classic_2.jpg'
+        document.baseURI+'/assets/presets/living_room_classic_1.jpg',
+        document.baseURI+'/assets/presets/living_room_classic_2.jpg'
       ],
       [SceneTemplate.BEDROOM_COZY]: [
-        '/assets/presets/bedroom_cozy_1.jpg',
-        '/assets/presets/bedroom_cozy_2.jpg'
+        document.baseURI+'/assets/presets/bedroom_cozy_1.jpg',
+        document.baseURI+'/assets/presets/bedroom_cozy_2.jpg'
       ],
       [SceneTemplate.BEDROOM_MINIMAL]: [
-        '/assets/presets/bedroom_minimal_1.jpg'
+        document.baseURI+'/assets/presets/bedroom_minimal_1.jpg'
       ],
       [SceneTemplate.KITCHEN_CONTEMPORARY]: [
-        '/assets/presets/kitchen_contemporary_1.jpg',
-        '/assets/presets/kitchen_contemporary_2.jpg'
+        document.baseURI+'/assets/presets/kitchen_contemporary_1.jpg',
+        document.baseURI+'/assets/presets/kitchen_contemporary_2.jpg'
       ],
       [SceneTemplate.KITCHEN_TRADITIONAL]: [
-        '/assets/presets/kitchen_traditional_1.jpg'
+        document.baseURI+'/assets/presets/kitchen_traditional_1.jpg'
       ],
       [SceneTemplate.BATHROOM_LUXURY]: [
-        '/assets/presets/bathroom_luxury_1.jpg'
+        document.baseURI+'/assets/presets/bathroom_luxury_1.jpg'
       ],
       [SceneTemplate.BATHROOM_MINIMAL]: [
-        '/assets/presets/bathroom_minimal_1.jpg'
+        document.baseURI+'/assets/presets/bathroom_minimal_1.jpg'
       ],
       [SceneTemplate.OFFICE_MODERN]: [
-        '/assets/presets/office_modern_1.jpg'
+        document.baseURI+'/assets/presets/office_modern_1.jpg'
       ],
       [SceneTemplate.OFFICE_TRADITIONAL]: [
-        '/assets/presets/office_traditional_1.jpg'
+        document.baseURI+'/assets/presets/office_traditional_1.jpg'
       ],
       [SceneTemplate.DINING_FORMAL]: [
-        '/assets/presets/dining_formal_1.jpg'
+        document.baseURI+'/assets/presets/dining_formal_1.jpg'
       ],
       [SceneTemplate.DINING_CASUAL]: [
-        '/assets/presets/dining_casual_1.jpg'
+        document.baseURI+'/assets/presets/dining_casual_1.jpg'
       ],
       [SceneTemplate.STUDIO_APARTMENT]: [
-        '/assets/presets/studio_apartment_1.jpg'
+        document.baseURI+'/assets/presets/studio_apartment_1.jpg'
       ],
       [SceneTemplate.OUTDOOR_PATIO]: [
-        '/assets/presets/outdoor_patio_1.jpg'
+        document.baseURI+'/assets/presets/outdoor_patio_1.jpg'
       ],
       [SceneTemplate.OUTDOOR_GARDEN]: [
-        '/assets/presets/outdoor_garden_1.jpg'
+        document.baseURI+'/assets/presets/outdoor_garden_1.jpg'
       ]
     };
     

+ 2 - 2
src/app/services/requirement-mapping.service.ts

@@ -380,7 +380,7 @@ export class RequirementMappingService {
   private generateAtmospherePreview(params: any, sceneType: SceneTemplate): string {
     // 这里应该调用实际的预览图生成服务
     // 目前返回模拟的URL
-    const baseUrl = '/assets/previews/atmosphere/';
+    const baseUrl = document.baseURI+'/assets/previews/atmosphere/';
     const sceneId = sceneType.toString();
     const timestamp = Date.now();
     return `${baseUrl}${sceneId}_${timestamp}.jpg`;
@@ -390,7 +390,7 @@ export class RequirementMappingService {
    * 生成默认预览图
    */
   private generateDefaultPreview(sceneType: SceneTemplate): string {
-    return `/assets/previews/default/${sceneType}.jpg`;
+    return document.baseURI+`/assets/previews/default/${sceneType}.jpg`;
   }
 
   /**

+ 1 - 1
src/app/services/scene-generation.service.ts

@@ -242,7 +242,7 @@ export class SceneGenerationService {
   private generateAtmospherePreview(params: SceneParams, sceneType: SceneTemplate): string {
     // 这里应该调用实际的预览图生成服务
     // 目前返回模拟的URL
-    const baseUrl = '/assets/previews/';
+    const baseUrl = document.baseURI+'/assets/previews/';
     const sceneId = sceneType.toString();
     const styleHash = this.generateStyleHash(params);
     return `${baseUrl}${sceneId}_${styleHash}.jpg`;

+ 13 - 13
src/app/shared/components/consultation-order-panel/consultation-order-panel.component.ts

@@ -89,7 +89,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
       currentProjects: 1,
       maxCapacity: 5,
       skills: ['现代简约', '北欧风格', '工业风'],
-      avatar: '/assets/images/default-avatar.svg'
+      avatar: document.baseURI+'/assets/images/default-avatar.svg'
     },
     {
       id: '2',
@@ -99,7 +99,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
       maxCapacity: 5,
       availableFrom: '2024-01-25',
       skills: ['欧式古典', '美式乡村', '中式传统'],
-      avatar: '/assets/images/default-avatar.svg'
+      avatar: document.baseURI+'/assets/images/default-avatar.svg'
     },
     {
       id: '3',
@@ -109,7 +109,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
       maxCapacity: 5,
       availableFrom: '2024-02-01',
       skills: ['极简主义', '日式禅风', '斯堪的纳维亚'],
-      avatar: '/assets/images/default-avatar.svg'
+      avatar: document.baseURI+'/assets/images/default-avatar.svg'
     },
     {
       id: '4',
@@ -118,7 +118,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
       currentProjects: 2,
       maxCapacity: 5,
       skills: ['新中式', '轻奢风格', '混搭风格'],
-      avatar: '/assets/images/default-avatar.svg'
+      avatar: document.baseURI+'/assets/images/default-avatar.svg'
     },
     {
       id: '5',
@@ -128,7 +128,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
       maxCapacity: 5,
       availableFrom: '2024-02-10',
       skills: ['现代简约', '北欧风格'],
-      avatar: '/assets/images/default-avatar.svg'
+      avatar: document.baseURI+'/assets/images/default-avatar.svg'
     },
     {
       id: '6',
@@ -137,7 +137,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
       currentProjects: 0,
       maxCapacity: 5,
       skills: ['现代简约', '工业风'],
-      avatar: '/assets/images/default-avatar.svg'
+      avatar: document.baseURI+'/assets/images/default-avatar.svg'
     },
     {
       id: '7',
@@ -147,7 +147,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
       maxCapacity: 5,
       availableFrom: '2024-01-20',
       skills: ['新中式', '轻奢风格'],
-      avatar: '/assets/images/default-avatar.svg'
+      avatar: document.baseURI+'/assets/images/default-avatar.svg'
     }
   ];
 
@@ -157,7 +157,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
       id: '1',
       name: '张设计师',
       role: '高级室内设计师',
-      avatar: '/assets/images/default-avatar.svg',
+      avatar: document.baseURI+'/assets/images/default-avatar.svg',
       skills: ['现代简约', '北欧风格', '工业风'],
       workload: { level: 'low', percentage: 30, text: '轻度' },
       recentTasks: [
@@ -169,7 +169,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
       id: '2',
       name: '李设计师',
       role: '资深设计总监',
-      avatar: '/assets/images/default-avatar.svg',
+      avatar: document.baseURI+'/assets/images/default-avatar.svg',
       skills: ['欧式古典', '美式乡村', '中式传统'],
       workload: { level: 'medium', percentage: 65, text: '中度' },
       recentTasks: [
@@ -182,7 +182,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
       id: '3',
       name: '王设计师',
       role: '创意设计师',
-      avatar: '/assets/images/default-avatar.svg',
+      avatar: document.baseURI+'/assets/images/default-avatar.svg',
       skills: ['极简主义', '日式禅风', '斯堪的纳维亚'],
       workload: { level: 'high', percentage: 85, text: '重度' },
       recentTasks: [
@@ -196,7 +196,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
       id: '4',
       name: '陈设计师',
       role: '室内设计师',
-      avatar: '/assets/images/default-avatar.svg',
+      avatar: document.baseURI+'/assets/images/default-avatar.svg',
       skills: ['新中式', '轻奢风格', '混搭风格'],
       workload: { level: 'low', percentage: 20, text: '轻度' },
       recentTasks: [
@@ -208,7 +208,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
       id: '5',
       name: '赵设计师',
       role: '室内设计师',
-      avatar: '/assets/images/default-avatar.svg',
+      avatar: document.baseURI+'/assets/images/default-avatar.svg',
       skills: ['现代简约', '北欧风格'],
       workload: { level: 'low', percentage: 0, text: '空闲' },
       recentTasks: []
@@ -485,7 +485,7 @@ export class ConsultationOrderPanelComponent implements OnInit, OnChanges {
             id: selectedDesigner.id,
             name: selectedDesigner.name,
             role: '室内设计师',
-            avatar: selectedDesigner.avatar || '/assets/images/default-avatar.svg',
+            avatar: selectedDesigner.avatar || document.baseURI+'/assets/images/default-avatar.svg',
             skills: selectedDesigner.skills,
             workload: { level: 'low', percentage: 0, text: '空闲' },
             recentTasks: []

+ 10 - 10
src/app/shared/components/team-assignment-dialog/team-assignment-dialog.component.ts

@@ -53,7 +53,7 @@ export class TeamAssignmentDialogComponent {
       id: 'designer-1',
       name: '张设计',
       role: '高级设计师',
-      avatar: '/assets/avatars/designer1.jpg',
+      avatar: document.baseURI+'/assets/avatars/designer1.jpg',
       taskCount: 3,
       department: '设计部',
       skills: ['现代简约', '北欧风', '工业风'],
@@ -63,7 +63,7 @@ export class TeamAssignmentDialogComponent {
       id: 'designer-2',
       name: '李美美',
       role: '资深设计师',
-      avatar: '/assets/avatars/designer2.jpg',
+      avatar: document.baseURI+'/assets/avatars/designer2.jpg',
       taskCount: 2,
       department: '设计部',
       skills: ['新中式', '法式轻奢', '美式'],
@@ -73,7 +73,7 @@ export class TeamAssignmentDialogComponent {
       id: 'designer-3',
       name: '王创意',
       role: '首席设计师',
-      avatar: '/assets/avatars/designer3.jpg',
+      avatar: document.baseURI+'/assets/avatars/designer3.jpg',
       taskCount: 1,
       department: '设计部',
       skills: ['高端定制', '别墅设计', '商业空间'],
@@ -83,7 +83,7 @@ export class TeamAssignmentDialogComponent {
       id: 'designer-4',
       name: '陈艺术',
       role: '设计师',
-      avatar: '/assets/avatars/designer4.jpg',
+      avatar: document.baseURI+'/assets/avatars/designer4.jpg',
       taskCount: 4,
       department: '设计部',
       skills: ['日式', '混搭', '小户型'],
@@ -96,7 +96,7 @@ export class TeamAssignmentDialogComponent {
       id: 'assistant-1',
       name: '小刘',
       role: '助理设计师',
-      avatar: '/assets/avatars/assistant1.jpg',
+      avatar: document.baseURI+'/assets/avatars/assistant1.jpg',
       taskCount: 2,
       department: '设计部',
       skills: ['效果图制作', '方案整理'],
@@ -106,7 +106,7 @@ export class TeamAssignmentDialogComponent {
       id: 'assistant-2',
       name: '小周',
       role: '助理设计师',
-      avatar: '/assets/avatars/assistant2.jpg',
+      avatar: document.baseURI+'/assets/avatars/assistant2.jpg',
       taskCount: 3,
       department: '设计部',
       skills: ['CAD绘图', '材料整理'],
@@ -116,7 +116,7 @@ export class TeamAssignmentDialogComponent {
       id: 'assistant-3',
       name: '小王',
       role: '助理设计师',
-      avatar: '/assets/avatars/assistant3.jpg',
+      avatar: document.baseURI+'/assets/avatars/assistant3.jpg',
       taskCount: 1,
       department: '设计部',
       skills: ['3D建模', '渲染'],
@@ -129,7 +129,7 @@ export class TeamAssignmentDialogComponent {
       id: 'manager-1',
       name: '赵经理',
       role: '项目经理',
-      avatar: '/assets/avatars/manager1.jpg',
+      avatar: document.baseURI+'/assets/avatars/manager1.jpg',
       taskCount: 5,
       department: '项目部',
       skills: ['项目管理', '客户沟通'],
@@ -139,7 +139,7 @@ export class TeamAssignmentDialogComponent {
       id: 'manager-2',
       name: '孙总监',
       role: '高级项目经理',
-      avatar: '/assets/avatars/manager2.jpg',
+      avatar: document.baseURI+'/assets/avatars/manager2.jpg',
       taskCount: 3,
       department: '项目部',
       skills: ['团队协调', '质量控制'],
@@ -149,7 +149,7 @@ export class TeamAssignmentDialogComponent {
       id: 'manager-3',
       name: '钱主管',
       role: '项目经理',
-      avatar: '/assets/avatars/manager3.jpg',
+      avatar: document.baseURI+'/assets/avatars/manager3.jpg',
       taskCount: 4,
       department: '项目部',
       skills: ['进度管控', '成本控制'],

+ 5 - 5
src/app/shared/components/team-assignment-modal/team-assignment-modal.component.ts

@@ -41,7 +41,7 @@ export class TeamAssignmentModalComponent {
       id: '1',
       name: '张设计师',
       role: '高级室内设计师',
-      avatar: '/assets/images/default-avatar.svg',
+      avatar: document.baseURI+'/assets/images/default-avatar.svg',
       skills: ['现代简约', '北欧风格', '工业风'],
       workload: {
         level: 'low',
@@ -69,7 +69,7 @@ export class TeamAssignmentModalComponent {
       id: '2',
       name: '李设计师',
       role: '资深设计总监',
-      avatar: '/assets/images/default-avatar.svg',
+      avatar: document.baseURI+'/assets/images/default-avatar.svg',
       skills: ['欧式古典', '美式乡村', '中式传统'],
       workload: {
         level: 'medium',
@@ -104,7 +104,7 @@ export class TeamAssignmentModalComponent {
       id: '3',
       name: '王设计师',
       role: '创意设计师',
-      avatar: '/assets/images/default-avatar.svg',
+      avatar: document.baseURI+'/assets/images/default-avatar.svg',
       skills: ['极简主义', '日式禅风', '斯堪的纳维亚'],
       workload: {
         level: 'high',
@@ -146,7 +146,7 @@ export class TeamAssignmentModalComponent {
       id: '4',
       name: '陈设计师',
       role: '室内设计师',
-      avatar: '/assets/images/default-avatar.svg',
+      avatar: document.baseURI+'/assets/images/default-avatar.svg',
       skills: ['新中式', '轻奢风格', '混搭风格'],
       workload: {
         level: 'low',
@@ -193,7 +193,7 @@ export class TeamAssignmentModalComponent {
 
   // 图片加载错误处理
   onImageError(event: any, designer: Designer): void {
-    event.target.src = '/assets/images/default-avatar.svg';
+    event.target.src = document.baseURI+'/assets/images/default-avatar.svg';
   }
 
   getWorkloadClass(workload: { level: 'low' | 'medium' | 'high'; percentage: number; text: string }): string {

+ 1 - 1
src/app/shared/components/upload-success-modal/upload-success-modal.component.ts

@@ -176,7 +176,7 @@ export class UploadSuccessModalComponent implements OnInit, OnDestroy, OnChanges
           { hex: '#F5F5DC', rgb: { r: 245, g: 245, b: 220 }, percentage: 2.8 }
         ],
         originalImage: this.uploadedFiles[0]?.url || '',
-        mosaicImage: '/assets/images/mock-mosaic.jpg',
+        mosaicImage: document.baseURI+'/assets/images/mock-mosaic.jpg',
         reportPath: '/reports/color-analysis-' + Date.now() + '.html',
         enhancedAnalysis: {
           colorWheel: {

+ 2 - 2
src/app/shared/services/color-analysis.service.ts

@@ -268,8 +268,8 @@ export class ColorAnalysisService {
                 { hex: '#DDA0DD', rgb: { r: 221, g: 160, b: 221 }, percentage: 8.9, name: '紫罗兰' },
                 { hex: '#98D8C8', rgb: { r: 152, g: 216, b: 200 }, percentage: 8.7, name: '海泡石绿' }
               ],
-              originalImage: file.preview || file.url || '/assets/images/placeholder.jpg',
-              mosaicImage: file.preview || file.url || '/assets/images/placeholder.jpg',
+              originalImage: file.preview || file.url || document.baseURI+'/assets/images/placeholder.jpg',
+              mosaicImage: file.preview || file.url || document.baseURI+'/assets/images/placeholder.jpg',
               reportPath: '/mock-report.html',
               enhancedAnalysis: this.performEnhancedColorAnalysis([
                 { hex: '#FF6B6B', rgb: { r: 255, g: 107, b: 107 }, percentage: 25.5 },

+ 2 - 2
src/index.html

@@ -14,12 +14,12 @@
     <script type="importmap">
       {
         "imports": {
-          "echarts": "/assets/echarts/echarts.esm.js"
+          "echarts": document.baseURI+"/assets/echarts/echarts.esm.js"
         }
       }
     </script>
     <!-- Use local UMD build to provide window.echarts globally (avoid external CDN errors) -->
-    <script defer src="/assets/echarts/echarts.min.js"></script>
+    <script defer src="assets/echarts/echarts.min.js"></script>
   </head>
 <body>
   <app-root></app-root>

+ 182 - 43
src/modules/project/pages/project-loader/project-loader.component.ts

@@ -5,6 +5,17 @@ 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');
 
@@ -19,6 +30,8 @@ const Parse = FmodeParse.with('nova');
  *    - 联系人 → 客户画像
  *
  * 路由:/wxwork/:cid/project-loader
+ *
+ * 参考实现:nova-admin/projects/nova-crm/src/modules/chat/page-chat-context
  */
 @Component({
   selector: 'app-project-loader',
@@ -42,8 +55,9 @@ export class ProjectLoaderComponent implements OnInit {
   wecorp: WxworkCorp | null = null;
 
   // 上下文数据
-  currentUser: FmodeObject | null = null;   // Profile
+  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
@@ -60,56 +74,126 @@ export class ProjectLoaderComponent implements OnInit {
   constructor(
     private router: Router,
     private route: ActivatedRoute
-  ) {}
+  ) {
+    addIcons({
+      rocketOutline,
+      addCircleOutline,
+      timeOutline,
+      personCircleOutline,
+      alertCircleOutline,
+      refreshOutline,
+      chevronForwardOutline
+    });
+  }
 
   async ngOnInit() {
     // 获取路由参数
-    this.cid = this.route.snapshot.paramMap.get('cid') || '';
-    this.appId = this.route.snapshot.queryParamMap.get('appId') || 'crm';
-
-    if (!this.cid) {
-      this.error = '缺少企业ID参数';
-      this.loading = false;
-      return;
-    }
+    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();
+      await this.loadData();
+    });
   }
 
   /**
-   * 加载数据主流程
+   * 加载数据主流程(参考 page-chat-context 实现)
    */
   async loadData() {
     try {
       this.loading = true;
       this.loadingMessage = '初始化企微SDK...';
 
-      // 1. 初始化SDK
+      // 1️⃣ 初始化 SDK
       this.wxwork = new WxworkSDK({ cid: this.cid, appId: this.appId });
       this.wecorp = new WxworkCorp(this.cid);
 
-      // 2. 获取企微上下文(群聊或联系人)
-      this.loadingMessage = '获取会话信息...';
-      const chatObject = await this.wxwork.getCurrentChatObject();
-      this.currentChat = chatObject.currentChat;
-      this.groupChat = chatObject.GroupChat || null;
-      this.contact = chatObject.Contact || null;
+      wxdebug('1. SDK初始化完成', { cid: this.cid, appId: this.appId });
 
-      // 3. 获取当前登录用户
+      // 2️⃣ 加载当前登录员工信息(由 WxworkAuthGuard 自动登录)
       this.loadingMessage = '获取用户信息...';
-      this.currentUser = await this.wxwork.getCurrentUser();
+      try {
+        this.currentUser = await this.wxwork.getCurrentUser();
+        wxdebug('2. 获取当前用户成功', this.currentUser?.toJSON());
+      } catch (err) {
+        console.error('获取当前用户失败:', err);
+        wxdebug('2. 获取当前用户失败', err);
+        throw new Error('获取用户信息失败,请重试');
+      }
 
-      console.log('当前用户:', this.currentUser?.get('name'), '角色:', this.currentUser?.get('role'));
-      console.log('会话类型:', this.currentChat?.type);
+      // 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.groupChat) {
-        await this.handleGroupChatScene();
-      } else if (this.contact) {
-        await this.handleContactScene();
+      // 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 {
-        this.error = '无法识别当前会话类型';
+        // 未检测到有效场景
+        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 || '加载失败,请重试';
@@ -134,12 +218,13 @@ export class ProjectLoaderComponent implements OnInit {
         query.include('customer', 'assignee');
         this.project = await query.get(projectPointer.id);
 
-        console.log('找到项目:', this.project.get('title'));
+        wxdebug('找到项目', this.project.toJSON());
 
         // 跳转项目详情
         await this.navigateToProjectDetail();
       } catch (err) {
         console.error('加载项目失败:', err);
+        wxdebug('加载项目失败', err);
         this.error = '项目已删除或无权访问';
       }
     } else {
@@ -153,9 +238,13 @@ export class ProjectLoaderComponent implements OnInit {
    * 处理联系人场景
    */
   async handleContactScene() {
-    console.log('联系人场景,跳转客户画像');
+    wxdebug('联系人场景,跳转客户画像', {
+      contactId: this.contact!.id,
+      contactName: this.contact!.get('name')
+    });
+
     // 跳转客户画像页面
-    await this.router.navigate(['/wxwork', this.cid, 'customer', this.contact!.id], {
+    await this.router.navigate(['/wxwork', this.cid, 'customer-profile', this.contact!.id], {
       queryParams: {
         profileId: this.currentUser!.id
       }
@@ -171,15 +260,17 @@ export class ProjectLoaderComponent implements OnInit {
       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'));
 
-      console.log('找到历史项目:', this.historyProjects.length, '个');
+      wxdebug('找到历史项目', { count: this.historyProjects.length });
     } catch (err) {
       console.error('加载历史项目失败:', err);
+      wxdebug('加载历史项目失败', err);
     }
   }
 
@@ -190,6 +281,10 @@ export class ProjectLoaderComponent implements OnInit {
     this.showCreateGuide = true;
     this.defaultProjectName = this.groupChat!.get('name') || '新项目';
     this.projectName = this.defaultProjectName;
+    wxdebug('显示创建项目引导', {
+      groupName: this.groupChat!.get('name'),
+      historyProjectsCount: this.historyProjects.length
+    });
   }
 
   /**
@@ -210,6 +305,12 @@ export class ProjectLoaderComponent implements OnInit {
 
     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');
@@ -221,16 +322,17 @@ export class ProjectLoaderComponent implements OnInit {
       project.set('currentStage', '订单分配');
       project.set('data', {
         createdBy: this.currentUser!.id,
-        createdFrom: 'wxwork_groupchat'
+        createdFrom: 'wxwork_groupchat',
+        groupChatId: this.groupChat!.id
       });
 
       await project.save();
-
-      console.log('项目创建成功:', project.id);
+      wxdebug('项目创建成功', { projectId: project.id });
 
       // 2. 关联群聊
       this.groupChat!.set('project', project.toPointer());
       await this.groupChat!.save();
+      wxdebug('群聊关联项目成功');
 
       // 3. 创建 ProjectGroup 关联(支持多项目多群)
       const ProjectGroup = Parse.Object.extend('ProjectGroup');
@@ -238,13 +340,16 @@ export class ProjectLoaderComponent implements OnInit {
       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;
@@ -255,19 +360,35 @@ export class ProjectLoaderComponent implements OnInit {
    * 选择历史项目
    */
   async selectHistoryProject(project: FmodeObject) {
-    // 更新群聊的当前项目
-    this.groupChat!.set('project', project.toPointer());
-    await this.groupChat!.save();
+    try {
+      wxdebug('选择历史项目', {
+        projectId: project.id,
+        projectTitle: project.get('title')
+      });
 
-    // 跳转项目详情
-    this.project = project;
-    await this.navigateToProjectDetail();
+      // 更新群聊的当前项目
+      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,
@@ -282,9 +403,27 @@ export class ProjectLoaderComponent implements OnInit {
   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') || '未知';
+  }
+
   /**
    * 获取项目状态的显示样式类
    */
@@ -305,6 +444,6 @@ export class ProjectLoaderComponent implements OnInit {
   formatDate(date: Date): string {
     if (!date) return '';
     const d = new Date(date);
-    return `${d.getMonth() + 1}/${d.getDate()}`;
+    return `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}`;
   }
 }