Эх сурвалжийг харах

feat:project-loader还原

0235711 2 өдөр өмнө
parent
commit
6bc5806366

+ 50 - 521
src/modules/project/pages/project-loader/project-loader.component.html

@@ -1,7 +1,22 @@
-<div class="personal-board">
+<div class="project-loader">
+  <!-- 头部 -->
+  <div class="header">
+    <h1 class="title">项目管理</h1>
+  </div>
+
   <!-- 加载中状态 -->
   @if (loading) {
     <div class="loading-container">
+      <div class="skeleton-loader">
+        <!-- 骨架屏动画 -->
+        <div class="skeleton-header"></div>
+        <div class="skeleton-card"></div>
+        <div class="skeleton-card"></div>
+        <div class="skeleton-buttons">
+          <div></div>
+          <div></div>
+        </div>
+      </div>
       <div class="spinner">
         <div class="spinner-circle"></div>
       </div>
@@ -29,522 +44,10 @@
     </div>
   }
 
-  <!-- 个人看板主界面 -->
-  @if (chatType === 'personal' && !loading && !error) {
-    <div class="board-container">
-      <!-- 头部个人信息卡片 -->
-      <div class="profile-header">
-        <div class="profile-avatar">
-          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-            <path d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48zM385.32 375.25a4 4 0 01-6.14-.32 124.27 124.27 0 00-32.35-29.59C321.37 329 289.11 320 256 320s-65.37 9-90.83 25.34a124.24 124.24 0 00-32.35 29.58 4 4 0 01-6.14.32A175.32 175.32 0 0180 259c-1.63-97.31 78.22-178.76 175.57-179S432 158.81 432 256a175.32 175.32 0 01-46.68 119.25z"/>
-            <path d="M256 144c-19.72 0-37.55 7.39-50.22 20.82s-19 32-17.57 51.93C191.11 256 221.52 288 256 288s64.83-32 67.79-71.24c1.48-19.74-4.8-38.14-17.68-51.82C293.39 151.44 275.59 144 256 144z"/>
-          </svg>
-        </div>
-        <div class="profile-info">
-          <h1 class="profile-name">{{ getCurrentUserName() }}</h1>
-          <p class="profile-role">{{ getCurrentUserRole() }}</p>
-        </div>
-      </div>
-
-      <!-- 统计卡片组 -->
-      <div class="stats-grid">
-        <div class="stat-card">
-          <div class="stat-icon stat-icon-primary">
-            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-              <path d="M384 240H96V136a40.12 40.12 0 0140-40h240a40.12 40.12 0 0140 40v104zM48 416V304a64.19 64.19 0 0164-64h288a64.19 64.19 0 0164 64v112"/>
-              <path d="M112 208v-64a40.12 40.12 0 0140-40h208a40.12 40.12 0 0140 40v64"/>
-              <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M112 208v-64a40.12 40.12 0 0140-40h208a40.12 40.12 0 0140 40v64M256 208v-72"/>
-            </svg>
-          </div>
-          <div class="stat-content">
-            <p class="stat-label">总项目数</p>
-            <p class="stat-value">{{ totalProjects }}</p>
-          </div>
-        </div>
-
-        <div class="stat-card">
-          <div class="stat-icon stat-icon-success">
-            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-              <path d="M448 256c0-106-86-192-192-192S64 150 64 256s86 192 192 192 192-86 192-192z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/>
-              <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M352 176L217.6 336 160 272"/>
-            </svg>
-          </div>
-          <div class="stat-content">
-            <p class="stat-label">已完成</p>
-            <p class="stat-value">{{ completedProjects }}</p>
-          </div>
-        </div>
-
-        <div class="stat-card">
-          <div class="stat-icon stat-icon-warning">
-            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-              <rect fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32" x="48" y="80" width="416" height="384" rx="48"/>
-              <circle cx="296" cy="232" r="24"/>
-              <circle cx="376" cy="232" r="24"/>
-              <circle cx="296" cy="312" r="24"/>
-              <circle cx="376" cy="312" r="24"/>
-              <circle cx="136" cy="312" r="24"/>
-              <circle cx="216" cy="312" r="24"/>
-              <circle cx="136" cy="392" r="24"/>
-              <circle cx="216" cy="392" r="24"/>
-              <circle cx="296" cy="392" r="24"/>
-              <path fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32" stroke-linecap="round" d="M128 48v32M384 48v32"/>
-              <path fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32" d="M464 160H48"/>
-            </svg>
-          </div>
-          <div class="stat-content">
-            <p class="stat-label">本月项目</p>
-            <p class="stat-value">{{ currentMonthProjects }}</p>
-          </div>
-        </div>
-
-        <div class="stat-card">
-          <div class="stat-icon stat-icon-info">
-            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-              <path d="M256 48C141.13 48 48 141.13 48 256c0 114.69 93.31 208 208 208 114.87 0 208-93.31 208-208 0-114.87-93.13-208-208-208zm0 319.91a20 20 0 1120-20 20 20 0 01-20 20zm21.72-201.15l-5.74 122a16 16 0 01-32 0l-5.74-122v-.05a21.74 21.74 0 1143.44.05z"/>
-            </svg>
-          </div>
-          <div class="stat-content">
-            <p class="stat-label">案例作品</p>
-            <p class="stat-value">{{ caseWorks.length }}</p>
-          </div>
-        </div>
-      </div>
-
-      <!-- 选项卡导航 -->
-      <div class="tabs">
-        <button class="tab-btn" [class.active]="activeTab === 'overview'" (click)="activeTab = 'overview'">
-          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-            <path d="M80 212v236a16 16 0 0016 16h96V328a24 24 0 0124-24h80a24 24 0 0124 24v136h96a16 16 0 0016-16V212"/>
-            <path d="M480 256L266.89 52c-5-5.28-16.69-5.28-21.78 0L32 256M400 179V64h-48v69"/>
-          </svg>
-          概览
-        </button>
-        <button class="tab-btn" [class.active]="activeTab === 'skills'" (click)="activeTab = 'skills'">
-          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-            <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M256 64C132.3 64 32 164.2 32 287.9a223.18 223.18 0 0056.3 148.5c1.1 1.2 2.1 2.4 3.2 3.5a25.19 25.19 0 0037.1-.1 173.13 173.13 0 01254.8 0 25.19 25.19 0 0037.1.1l3.2-3.5A223.18 223.18 0 00480 287.9C480 164.2 379.7 64 256 64z"/>
-            <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32" d="M256 128v32M416 288h-32M128 288H96M165.49 197.49l-22.63-22.63M346.51 197.49l22.63-22.63"/>
-          </svg>
-          技能
-        </button>
-        <button class="tab-btn" [class.active]="activeTab === 'cases'" (click)="activeTab = 'cases'">
-          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-            <rect x="48" y="80" width="416" height="352" rx="48" ry="48" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/>
-            <circle cx="336" cy="176" r="32"/>
-            <path d="M304 335.79l-90.66-90.49a32 32 0 00-43.87-1.3L48 352M224 432l123.34-123.34a32 32 0 0143.11-2L464 368"/>
-          </svg>
-          案例
-        </button>
-        <button class="tab-btn" [class.active]="activeTab === 'stats'" (click)="activeTab = 'stats'">
-          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-            <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M64 400V96h32v304"/>
-            <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M96 432h320"/>
-            <path d="M224 208v192h-64V208z"/>
-            <path d="M288 160v240h64V160z"/>
-            <path d="M160 272v128H96V272z"/>
-            <path d="M416 144v256h-64V144z"/>
-          </svg>
-          统计
-        </button>
-      </div>
-
-      <!-- 概览选项卡 -->
-      @if (activeTab === 'overview') {
-        <div class="tab-content">
-          <!-- 自我评价卡片 -->
-          <div class="card">
-            <div class="card-header">
-              <h3 class="card-title">
-                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-                  <path d="M336 64h32a48 48 0 0148 48v320a48 48 0 01-48 48H144a48 48 0 01-48-48V112a48 48 0 0148-48h32"/>
-                  <rect x="176" y="32" width="160" height="64" rx="26.13" ry="26.13"/>
-                </svg>
-                自我评价
-              </h3>
-              <button class="btn-icon" (click)="openEditEvaluation()">
-                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-                  <path d="M384 224v184a40 40 0 01-40 40H104a40 40 0 01-40-40V168a40 40 0 0140-40h167.48"/>
-                  <path d="M459.94 53.25a16.06 16.06 0 00-23.22-.56L424.35 65a8 8 0 000 11.31l11.34 11.32a8 8 0 0011.34 0l12.06-12c6.1-6.09 6.67-16.01.85-22.38zM399.34 90L218.82 270.2a9 9 0 00-2.31 3.93L208.16 299a3.91 3.91 0 004.86 4.86l24.85-8.35a9 9 0 003.93-2.31L422 112.66a9 9 0 000-12.66l-9.95-10a9 9 0 00-12.71 0z"/>
-                </svg>
-              </button>
-            </div>
-            <div class="card-content">
-              <div class="evaluation-section">
-                <h4 class="section-subtitle">个人陈述</h4>
-                <p class="evaluation-text">{{ selfEvaluation.personalStatement || '暂无个人陈述' }}</p>
-              </div>
-
-              <div class="evaluation-section">
-                <h4 class="section-subtitle">我的优势</h4>
-                <div class="tags">
-                  @for (strength of selfEvaluation.strengths; track strength) {
-                    <span class="tag tag-success">{{ strength }}</span>
-                  }
-                  @if (selfEvaluation.strengths.length === 0) {
-                    <span class="text-muted">暂无优势标签</span>
-                  }
-                </div>
-              </div>
-
-              <div class="evaluation-section">
-                <h4 class="section-subtitle">待提升项</h4>
-                <div class="tags">
-                  @for (improvement of selfEvaluation.improvements; track improvement) {
-                    <span class="tag tag-warning">{{ improvement }}</span>
-                  }
-                  @if (selfEvaluation.improvements.length === 0) {
-                    <span class="text-muted">暂无待提升项</span>
-                  }
-                </div>
-              </div>
-
-              <p class="text-muted small">最后更新: {{ formatDate(selfEvaluation.lastUpdated) }}</p>
-            </div>
-          </div>
-
-          <!-- 月度表现卡片 -->
-          @if (monthlyStats.length > 0) {
-            <div class="card">
-              <div class="card-header">
-                <h3 class="card-title">
-                  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-                    <rect fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32" x="48" y="80" width="416" height="384" rx="48"/>
-                    <path fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32" d="M128 48v32M384 48v32M464 160H48"/>
-                  </svg>
-                  月度表现
-                </h3>
-              </div>
-              <div class="card-content">
-                <div class="monthly-list">
-                  @for (month of monthlyStats; track month.month) {
-                    <div class="monthly-item">
-                      <div class="monthly-header">
-                        <span class="monthly-label">{{ formatMonth(month.month) }}</span>
-                        <span class="monthly-value">{{ month.totalProjects }} 个项目</span>
-                      </div>
-                      <div class="monthly-details">
-                        <span class="detail-item">
-                          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="16" height="16">
-                            <path d="M448 256c0-106-86-192-192-192S64 150 64 256s86 192 192 192 192-86 192-192z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/>
-                            <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M352 176L217.6 336 160 272"/>
-                          </svg>
-                          已完成 {{ month.completedProjects }}
-                        </span>
-                        <span class="detail-item">
-                          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="16" height="16">
-                            <path d="M448 400H64a16 16 0 010-32h384a16 16 0 010 32z"/>
-                            <path d="M416 221.25V144a48 48 0 00-48-48H144a48 48 0 00-48 48v77.25M256 160v128M208 208v88M304 224v64M144 384V288M368 384V288"/>
-                          </svg>
-                          {{ formatCurrency(month.revenue) }}
-                        </span>
-                      </div>
-                    </div>
-                  }
-                </div>
-              </div>
-            </div>
-          }
-        </div>
-      }
-
-      <!-- 技能选项卡 -->
-      @if (activeTab === 'skills') {
-        <div class="tab-content">
-          <div class="card">
-            <div class="card-header">
-              <h3 class="card-title">
-                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-                  <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M256 64C132.3 64 32 164.2 32 287.9a223.18 223.18 0 0056.3 148.5c1.1 1.2 2.1 2.4 3.2 3.5a25.19 25.19 0 0037.1-.1 173.13 173.13 0 01254.8 0 25.19 25.19 0 0037.1.1l3.2-3.5A223.18 223.18 0 00480 287.9C480 164.2 379.7 64 256 64z"/>
-                </svg>
-                技能评分
-              </h3>
-              <button class="btn-icon" (click)="showSkillEditor = true">
-                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-                  <path d="M384 224v184a40 40 0 01-40 40H104a40 40 0 01-40-40V168a40 40 0 0140-40h167.48"/>
-                  <path d="M459.94 53.25a16.06 16.06 0 00-23.22-.56L424.35 65a8 8 0 000 11.31l11.34 11.32a8 8 0 0011.34 0l12.06-12c6.1-6.09 6.67-16.01.85-22.38zM399.34 90L218.82 270.2a9 9 0 00-2.31 3.93L208.16 299a3.91 3.91 0 004.86 4.86l24.85-8.35a9 9 0 003.93-2.31L422 112.66a9 9 0 000-12.66l-9.95-10a9 9 0 00-12.71 0z"/>
-                </svg>
-              </button>
-            </div>
-            <div class="card-content">
-              <!-- 按类别分组显示技能 -->
-              @for (category of ['设计能力', '沟通能力', '技术能力', '项目管理']; track category) {
-                @if (filterSkillsByCategory(category).length > 0) {
-                  <div class="skill-category">
-                    <h4 class="category-title">{{ category }}</h4>
-                    @for (skill of filterSkillsByCategory(category); track skill.name) {
-                      <div class="skill-item">
-                        <div class="skill-header">
-                          <span class="skill-name">{{ skill.name }}</span>
-                          <span class="skill-score" [ngClass]="getScoreColor(skill.currentScore)">
-                            {{ skill.currentScore }}
-                          </span>
-                        </div>
-                        <div class="skill-progress">
-                          <div class="progress-bar">
-                            <div class="progress-fill" [style.width.%]="getScoreProgress(skill.currentScore, skill.targetScore)"></div>
-                          </div>
-                          <span class="target-label">目标: {{ skill.targetScore }}</span>
-                        </div>
-                      </div>
-                    }
-                  </div>
-                }
-              }
-
-              @if (skillRatings.length === 0) {
-                <div class="empty-state">
-                  <p class="text-muted">暂无技能评分数据</p>
-                  <button class="btn btn-primary" (click)="showSkillEditor = true">添加技能评分</button>
-                </div>
-              }
-            </div>
-          </div>
-        </div>
-      }
-
-      <!-- 案例选项卡 -->
-      @if (activeTab === 'cases') {
-        <div class="tab-content">
-          <div class="card">
-            <div class="card-header">
-              <h3 class="card-title">
-                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-                  <rect x="48" y="80" width="416" height="352" rx="48" ry="48" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/>
-                  <circle cx="336" cy="176" r="32"/>
-                  <path d="M304 335.79l-90.66-90.49a32 32 0 00-43.87-1.3L48 352M224 432l123.34-123.34a32 32 0 0143.11-2L464 368"/>
-                </svg>
-                案例作品集
-              </h3>
-              <button class="btn-icon" (click)="openCaseSelector()">
-                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-                  <path d="M448 256c0-106-86-192-192-192S64 150 64 256s86 192 192 192 192-86 192-192z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/>
-                  <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M256 176v160M336 256H176"/>
-                </svg>
-              </button>
-            </div>
-            <div class="card-content">
-              @if (caseWorks.length > 0) {
-                <div class="cases-grid">
-                  @for (case of caseWorks; track case.id) {
-                    <div class="case-card">
-                      <div class="case-image" [style.background-image]="'url(' + case.coverImage + ')'">
-                        @if (case.totalPrice) {
-                          <div class="case-price">{{ formatCurrency(case.totalPrice) }}</div>
-                        }
-                      </div>
-                      <div class="case-info">
-                        <h4 class="case-title">{{ case.projectTitle }}</h4>
-                        <p class="case-meta">
-                          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="14" height="14">
-                            <path d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48z"/>
-                          </svg>
-                          {{ case.customerName }}
-                        </p>
-                        @if (case.tags && case.tags.length > 0) {
-                          <div class="case-tags">
-                            @for (tag of case.tags.slice(0, 3); track tag) {
-                              <span class="tag tag-sm">{{ tag }}</span>
-                            }
-                          </div>
-                        }
-                        <p class="case-date">{{ formatDate(case.completionDate) }}</p>
-                      </div>
-                    </div>
-                  }
-                </div>
-              } @else {
-                <div class="empty-state">
-                  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="64" height="64">
-                    <rect x="48" y="80" width="416" height="352" rx="48" ry="48" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/>
-                    <circle cx="336" cy="176" r="32"/>
-                    <path d="M304 335.79l-90.66-90.49a32 32 0 00-43.87-1.3L48 352M224 432l123.34-123.34a32 32 0 0143.11-2L464 368"/>
-                  </svg>
-                  <p class="text-muted">暂无案例作品</p>
-                  <p class="text-muted small">从已完成项目中选择您的优秀作品</p>
-                  <button class="btn btn-primary" (click)="openCaseSelector()">选择案例</button>
-                </div>
-              }
-            </div>
-          </div>
-        </div>
-      }
-
-      <!-- 统计选项卡 -->
-      @if (activeTab === 'stats') {
-        <div class="tab-content">
-          <div class="card">
-            <div class="card-header">
-              <h3 class="card-title">
-                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-                  <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M64 400V96h32v304M96 432h320"/>
-                  <path d="M224 208v192h-64V208zM288 160v240h64V160zM160 272v128H96V272zM416 144v256h-64V144z"/>
-                </svg>
-                数据统计
-              </h3>
-            </div>
-            <div class="card-content">
-              <!-- 综合统计 -->
-              <div class="stats-summary">
-                <div class="summary-item">
-                  <div class="summary-label">完成率</div>
-                  <div class="summary-value">{{ totalProjects > 0 ? ((completedProjects / totalProjects * 100).toFixed(1)) : 0 }}%</div>
-                </div>
-                <div class="summary-item">
-                  <div class="summary-label">月均项目</div>
-                  <div class="summary-value">{{ monthlyStats.length > 0 ? (totalProjects / monthlyStats.length).toFixed(1) : 0 }}</div>
-                </div>
-              </div>
-
-              <!-- 月度趋势图 -->
-              @if (monthlyStats.length > 0) {
-                <div class="chart-container">
-                  <h4 class="chart-title">月度项目趋势</h4>
-                  <div class="bar-chart">
-                    @for (month of monthlyStats.slice().reverse(); track month.month) {
-                      <div class="bar-item">
-                        <div class="bar-wrapper">
-                          <div class="bar" [style.height.%]="(month.totalProjects / getMaxMonthlyProjects()) * 100">
-                            <span class="bar-label">{{ month.totalProjects }}</span>
-                          </div>
-                        </div>
-                        <span class="bar-month">{{ month.month.split('-')[1] }}月</span>
-                      </div>
-                    }
-                  </div>
-                </div>
-              }
-            </div>
-          </div>
-        </div>
-      }
-    </div>
-  }
-
-  <!-- 编辑自我评价弹窗 -->
-  @if (showEditEvaluation && editingEvaluation) {
-    <div class="modal-overlay" (click)="showEditEvaluation = false">
-      <div class="modal-content" (click)="$event.stopPropagation()">
-        <div class="modal-header">
-          <h3 class="modal-title">编辑自我评价</h3>
-          <button class="btn-close" (click)="showEditEvaluation = false">
-            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-              <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M368 368L144 144M368 144L144 368"/>
-            </svg>
-          </button>
-        </div>
-        <div class="modal-body">
-          <div class="form-group">
-            <label>个人陈述</label>
-            <textarea class="form-textarea" [(ngModel)]="editingEvaluation.personalStatement" rows="4" placeholder="介绍您的专业背景和职业愿景..."></textarea>
-          </div>
-
-          <div class="form-group">
-            <label>我的优势(用逗号分隔)</label>
-            <input type="text" class="form-input" [value]="editingEvaluation.strengths.join(', ')" (input)="updateStrengths($any($event.target).value)" placeholder="例如: 专业扎实, 责任心强, 沟通能力好">
-          </div>
-
-          <div class="form-group">
-            <label>待提升项(用逗号分隔)</label>
-            <input type="text" class="form-input" [value]="editingEvaluation.improvements.join(', ')" (input)="updateImprovements($any($event.target).value)" placeholder="例如: 时间管理, 技术深度">
-          </div>
-        </div>
-        <div class="modal-footer">
-          <button class="btn btn-secondary" (click)="showEditEvaluation = false">取消</button>
-          <button class="btn btn-primary" (click)="saveEvaluation()">保存</button>
-        </div>
-      </div>
-    </div>
-  }
-
-  <!-- 案例选择器弹窗 -->
-  @if (showCaseSelector) {
-    <div class="modal-overlay" (click)="showCaseSelector = false">
-      <div class="modal-content modal-large" (click)="$event.stopPropagation()">
-        <div class="modal-header">
-          <h3 class="modal-title">选择案例作品 ({{ selectedProjectIds.length }}/12)</h3>
-          <button class="btn-close" (click)="showCaseSelector = false">
-            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-              <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M368 368L144 144M368 144L144 368"/>
-            </svg>
-          </button>
-        </div>
-        <div class="modal-body">
-          @if (availableProjects.length > 0) {
-            <div class="project-selector-grid">
-              @for (project of availableProjects; track project.id) {
-                <div class="project-selector-item" [class.selected]="selectedProjectIds.includes(project.id)" (click)="toggleProjectSelection(project.id)">
-                  <div class="selector-checkbox">
-                    @if (selectedProjectIds.includes(project.id)) {
-                      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-                        <path d="M448 256c0-106-86-192-192-192S64 150 64 256s86 192 192 192 192-86 192-192z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/>
-                        <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M352 176L217.6 336 160 272"/>
-                      </svg>
-                    }
-                  </div>
-                  <div class="selector-content">
-                    <h4 class="selector-title">{{ project.get('title') }}</h4>
-                    <p class="selector-meta">{{ project.get('contact')?.get('name') || '客户' }} · {{ formatDate(project.get('updatedAt')) }}</p>
-                  </div>
-                </div>
-              }
-            </div>
-          } @else {
-            <div class="empty-state">
-              <p class="text-muted">暂无已完成项目</p>
-            </div>
-          }
-        </div>
-        <div class="modal-footer">
-          <button class="btn btn-secondary" (click)="showCaseSelector = false">取消</button>
-          <button class="btn btn-primary" (click)="saveCaseSelection()">保存选择</button>
-        </div>
-      </div>
-    </div>
-  }
-
-  <!-- 技能编辑器弹窗 -->
-  @if (showSkillEditor) {
-    <div class="modal-overlay" (click)="showSkillEditor = false">
-      <div class="modal-content" (click)="$event.stopPropagation()">
-        <div class="modal-header">
-          <h3 class="modal-title">编辑技能评分</h3>
-          <button class="btn-close" (click)="showSkillEditor = false">
-            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
-              <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M368 368L144 144M368 144L144 368"/>
-            </svg>
-          </button>
-        </div>
-        <div class="modal-body">
-          @for (skill of skillRatings; track skill.name) {
-            <div class="skill-editor-item">
-              <label class="skill-editor-label">{{ skill.name }}</label>
-              <div class="skill-editor-controls">
-                <div class="slider-group">
-                  <label>当前分数</label>
-                  <input type="range" min="0" max="100" step="5" [(ngModel)]="skill.currentScore" class="slider">
-                  <span class="slider-value">{{ skill.currentScore }}</span>
-                </div>
-                <div class="slider-group">
-                  <label>目标分数</label>
-                  <input type="range" min="0" max="100" step="5" [(ngModel)]="skill.targetScore" class="slider">
-                  <span class="slider-value">{{ skill.targetScore }}</span>
-                </div>
-              </div>
-            </div>
-          }
-        </div>
-        <div class="modal-footer">
-          <button class="btn btn-secondary" (click)="showSkillEditor = false">取消</button>
-          <button class="btn btn-primary" (click)="saveSkillRatings()">保存</button>
-        </div>
-      </div>
-    </div>
-  }
-
-  <!-- 群聊创建项目引导(保留原有功能) -->
+  <!-- 创建项目引导 -->
   @if (showCreateGuide && !loading && !error) {
     <div class="create-guide-container">
-      <!-- 原有创建项目引导内容 -->
+      <!-- 群聊信息卡片 -->
       <div class="card group-info-card">
         <div class="card-header">
           <h3 class="card-title">{{ groupChat?.get('name') }}</h3>
@@ -555,6 +58,7 @@
         </div>
       </div>
 
+      <!-- 创建新项目 -->
       <div class="card create-project-card">
         <div class="card-header">
           <h3 class="card-title">
@@ -568,10 +72,19 @@
         <div class="card-content">
           <div class="form-group">
             <label for="projectName">项目名称</label>
-            <input id="projectName" type="text" class="form-input" [(ngModel)]="projectName" placeholder="输入项目名称" [disabled]="creating">
-          </div>
-
-          <button class="btn btn-primary btn-block" (click)="createProject()" [disabled]="creating || !projectName.trim()">
+            <input
+              id="projectName"
+              type="text"
+              class="form-input"
+              [(ngModel)]="projectName"
+              placeholder="输入项目名称"
+              [disabled]="creating">
+          </div>
+
+          <button
+            class="btn btn-primary btn-block"
+            (click)="createProject()"
+            [disabled]="creating || !projectName.trim()">
             @if (creating) {
               <div class="btn-spinner"></div>
               <span>创建中...</span>
@@ -586,6 +99,7 @@
         </div>
       </div>
 
+      <!-- 历史项目列表 -->
       @if (historyProjects.length > 0) {
         <div class="card history-projects-card">
           <div class="card-header">
@@ -605,10 +119,14 @@
                   <div class="list-item-content">
                     <h4 class="list-item-title">{{ proj.get('title') }}</h4>
                     <div class="list-item-meta">
-                      <span class="badge" [ngClass]="getProjectStatusClass(proj.get('status'))">{{ proj.get('status') }}</span>
+                      <span class="badge" [ngClass]="getProjectStatusClass(proj.get('status'))">
+                        {{ proj.get('status') }}
+                      </span>
                       <span class="list-item-stage">{{ proj.get('currentStage') }}</span>
                     </div>
-                    <p class="list-item-date">创建时间: {{ formatDate(proj.get('createdAt')) }}</p>
+                    <p class="list-item-date">
+                      创建时间: {{ formatDate(proj.get('createdAt')) }}
+                    </p>
                   </div>
                   <div class="list-item-arrow">
                     <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
@@ -621,6 +139,17 @@
           </div>
         </div>
       }
+
+      <!-- 用户信息底部 -->
+      @if (currentUser) {
+        <div class="user-info-footer">
+          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
+            <path d="M258.9 48C141.92 46.42 46.42 141.92 48 258.9c1.56 112.19 92.91 203.54 205.1 205.1 117 1.6 212.48-93.9 210.88-210.88C462.44 140.91 371.09 49.56 258.9 48zM385.32 375.25a4 4 0 01-6.14-.32 124.27 124.27 0 00-32.35-29.59C321.37 329 289.11 320 256 320s-65.37 9-90.83 25.34a124.24 124.24 0 00-32.35 29.58 4 4 0 01-6.14.32A175.32 175.32 0 0180 259c-1.63-97.31 78.22-178.76 175.57-179S432 158.81 432 256a175.32 175.32 0 01-46.68 119.25z"/>
+            <path d="M256 144c-19.72 0-37.55 7.39-50.22 20.82s-19 32-17.57 51.93C191.11 256 221.52 288 256 288s64.83-32 67.79-71.24c1.48-19.74-4.8-38.14-17.68-51.82C293.39 151.44 275.59 144 256 144z"/>
+          </svg>
+          <span>当前用户: {{ getCurrentUserName() }} ({{ getCurrentUserRole() }})</span>
+        </div>
+      }
     </div>
   }
 </div>

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 165 - 1052
src/modules/project/pages/project-loader/project-loader.component.scss


+ 175 - 561
src/modules/project/pages/project-loader/project-loader.component.ts

@@ -16,46 +16,6 @@ interface WxworkCurrentChat {
   [key: string]: any;
 }
 
-// 个人技能评分
-interface SkillRating {
-  name: string;
-  currentScore: number;
-  targetScore: number;
-  category: '设计能力' | '沟通能力' | '技术能力' | '项目管理';
-}
-
-// 案例作品
-interface CaseWork {
-  id: string;
-  projectId: string;
-  projectTitle: string;
-  coverImage: string;
-  description: string;
-  tags: string[];
-  completionDate: Date;
-  customerName: string;
-  status: string;
-  totalPrice?: number;
-  roomType?: string;
-}
-
-// 月度统计
-interface MonthlyStats {
-  month: string;
-  totalProjects: number;
-  completedProjects: number;
-  revenue: number;
-  avgScore: number;
-}
-
-// 自我评价
-interface SelfEvaluation {
-  strengths: string[];        // 优势
-  improvements: string[];     // 待提升
-  personalStatement: string;  // 个人陈述
-  lastUpdated: Date;
-}
-
 function wxdebug(...params:any[]){
   console.log(params)
 }
@@ -63,16 +23,18 @@ function wxdebug(...params:any[]){
 const Parse = FmodeParse.with('nova');
 
 /**
- * 个人看板页面(重构自项目预加载页面
+ * 项目预加载页面
  *
  * 功能:
- * 1. 展示个人信息和自我评价
- * 2. 技能评分和发展目标
- * 3. 案例作品集(从完成项目选择)
- * 4. 月度接单量统计
- * 5. 支持编辑个人资料和案例
+ * 1. 从企微会话获取上下文(群聊或联系人)
+ * 2. 获取当前登录用户(Profile)
+ * 3. 根据场景跳转到对应页面
+ *    - 群聊 → 项目详情 或 创建项目引导
+ *    - 联系人 → 客户画像
  *
  * 路由:/wxwork/:cid/project-loader
+ *
+ * 参考实现:nova-admin/projects/nova-crm/src/modules/chat/page-chat-context
  */
 @Component({
   selector: 'app-project-loader',
@@ -96,46 +58,20 @@ 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' | 'personal' = 'personal';
+  chatType: 'group' | 'contact' | 'none' = 'none';
   groupChat: FmodeObject | null = null;     // GroupChat
   contact: FmodeObject | null = null;       // ContactInfo
   project: FmodeObject | null = null;       // Project
 
-  // 个人看板数据
-  skillRatings: SkillRating[] = [];
-  caseWorks: CaseWork[] = [];
-  monthlyStats: MonthlyStats[] = [];
-  selfEvaluation: SelfEvaluation = {
-    strengths: [],
-    improvements: [],
-    personalStatement: '',
-    lastUpdated: new Date()
-  };
-
-  // UI状态
-  activeTab: 'overview' | 'cases' | 'stats' | 'skills' = 'overview';
-  showEditEvaluation: boolean = false;
-  showCaseSelector: boolean = false;
-  showSkillEditor: boolean = false;
-
-  // 编辑状态
-  editingEvaluation: SelfEvaluation | null = null;
-  availableProjects: FmodeObject[] = [];
-  selectedProjectIds: string[] = [];
-
-  // 统计数据
-  totalProjects: number = 0;
-  completedProjects: number = 0;
-  currentMonthProjects: number = 0;
-  avgCustomerRating: number = 0;
-
-  // 创建项目引导(保留原有功能)
+  // 创建项目引导
   showCreateGuide: boolean = false;
   defaultProjectName: string = '';
   projectName: string = '';
   creating: boolean = false;
+
+  // 历史项目(当前群聊无项目时展示)
   historyProjects: FmodeObject[] = [];
 
   constructor(
@@ -161,7 +97,7 @@ export class ProjectLoaderComponent implements OnInit {
   }
 
   /**
-   * 加载数据主流程
+   * 加载数据主流程(参考 page-chat-context 实现)
    */
   async loadData() {
     try {
@@ -176,13 +112,14 @@ export class ProjectLoaderComponent implements OnInit {
 
       wxdebug('1. SDK初始化完成', { cid: this.cid, appId: this.appId });
 
-      // 2️⃣ 加载当前登录员工信息
+      // 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('获取用户信息失败,请重试');
       }
 
@@ -196,26 +133,60 @@ export class ProjectLoaderComponent implements OnInit {
         wxdebug('3. getCurrentChat失败', err);
       }
 
-      // 4️⃣ 根据场景处理
+      // 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.chatType = 'personal';
-        await this.loadPersonalBoard();
+        // 未检测到有效场景
+        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
       });
 
@@ -228,446 +199,61 @@ export class ProjectLoaderComponent implements OnInit {
   }
 
   /**
-   * 加载个人看板数据
-   */
-  async loadPersonalBoard() {
-    if (!this.currentUser) {
-      throw new Error('用户信息不存在');
-    }
-
-    this.loadingMessage = '加载个人信息...';
-
-    try {
-      // 并行加载所有数据
-      await Promise.all([
-        this.loadProfileData(),
-        this.loadSkillRatings(),
-        this.loadCaseWorks(),
-        this.loadMonthlyStats(),
-        this.loadSelfEvaluation()
-      ]);
-
-      console.log('✅ 个人看板数据加载完成');
-    } catch (err) {
-      console.error('加载个人看板数据失败:', err);
-      throw err;
-    }
-  }
-
-  /**
-   * 加载个人资料数据
-   */
-  async loadProfileData() {
-    try {
-      // 从Profile表获取最新数据
-      const query = new Parse.Query('Profile');
-      const profile = await query.get(this.currentUser!.id);
-      this.currentUser = profile;
-
-      const data = profile.get('data') || {};
-      
-      // 计算统计数据
-      await this.calculateStatistics();
-    } catch (err) {
-      console.error('加载个人资料失败:', err);
-    }
-  }
-
-  /**
-   * 加载技能评分
+   * 处理群聊场景
    */
-  async loadSkillRatings() {
-    try {
-      const data = this.currentUser!.get('data') || {};
-      const skills = data.skillRatings || [];
-
-      // 如果没有技能评分,创建默认值
-      if (skills.length === 0) {
-        this.skillRatings = this.getDefaultSkillRatings();
-      } else {
-        this.skillRatings = skills;
-      }
-    } catch (err) {
-      console.error('加载技能评分失败:', err);
-      this.skillRatings = this.getDefaultSkillRatings();
-    }
-  }
-
-  /**
-   * 加载案例作品
-   */
-  async loadCaseWorks() {
-    try {
-      const data = this.currentUser!.get('data') || {};
-      const caseProjectIds = data.caseWorks || [];
-
-      if (caseProjectIds.length === 0) {
-        this.caseWorks = [];
-        return;
-      }
-
-      // 查询案例对应的项目
-      const query = new Parse.Query('Project');
-      query.containedIn('objectId', caseProjectIds);
-      query.equalTo('currentStage', '售后归档');
-      query.notEqualTo('isDeleted', true);
-      query.include('contact');
-      query.descending('updatedAt');
-      query.limit(20);
-
-      const projects = await query.find();
-
-      this.caseWorks = projects.map(p => this.transformProjectToCase(p));
-      console.log(`✅ 加载了 ${this.caseWorks.length} 个案例作品`);
-    } catch (err) {
-      console.error('加载案例作品失败:', err);
-      this.caseWorks = [];
-    }
-  }
-
-  /**
-   * 加载月度统计
-   */
-  async loadMonthlyStats() {
-    try {
-      // 查询最近6个月的项目
-      const sixMonthsAgo = new Date();
-      sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6);
-
-      const query = new Parse.Query('Project');
-      query.equalTo('assignee', this.currentUser!.toPointer());
-      query.greaterThanOrEqualTo('createdAt', sixMonthsAgo);
-      query.notEqualTo('isDeleted', true);
-      query.limit(1000);
-
-      const projects = await query.find();
-
-      // 按月分组统计
-      const monthlyMap = new Map<string, MonthlyStats>();
-
-      projects.forEach(p => {
-        const date = p.get('createdAt');
-        const monthKey = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
-        
-        if (!monthlyMap.has(monthKey)) {
-          monthlyMap.set(monthKey, {
-            month: monthKey,
-            totalProjects: 0,
-            completedProjects: 0,
-            revenue: 0,
-            avgScore: 0
-          });
-        }
-
-        const stats = monthlyMap.get(monthKey)!;
-        stats.totalProjects++;
-
-        if (p.get('currentStage') === '售后归档' || p.get('status') === '已完成') {
-          stats.completedProjects++;
-          
-          // 计算收入
-          const pricing = p.get('data')?.pricing || {};
-          const totalPrice = pricing.totalAmount || pricing.total || pricing.finalPrice || 0;
-          stats.revenue += totalPrice;
-        }
-      });
-
-      // 转换为数组并排序
-      this.monthlyStats = Array.from(monthlyMap.values())
-        .sort((a, b) => b.month.localeCompare(a.month))
-        .slice(0, 6);
-
-      console.log(`✅ 加载了 ${this.monthlyStats.length} 个月的统计数据`);
-    } catch (err) {
-      console.error('加载月度统计失败:', err);
-      this.monthlyStats = [];
-    }
-  }
-
-  /**
-   * 加载自我评价
-   */
-  async loadSelfEvaluation() {
-    try {
-      const data = this.currentUser!.get('data') || {};
-      const evaluation = data.selfEvaluation;
-
-      if (evaluation) {
-        this.selfEvaluation = {
-          strengths: evaluation.strengths || [],
-          improvements: evaluation.improvements || [],
-          personalStatement: evaluation.personalStatement || '',
-          lastUpdated: evaluation.lastUpdated ? new Date(evaluation.lastUpdated) : new Date()
-        };
-      } else {
-        // 默认值
-        this.selfEvaluation = {
-          strengths: ['专业扎实', '责任心强'],
-          improvements: ['沟通效率', '时间管理'],
-          personalStatement: '我是一名热爱设计的专业人士,致力于为客户提供优质的服务。',
-          lastUpdated: new Date()
-        };
-      }
-    } catch (err) {
-      console.error('加载自我评价失败:', err);
-    }
-  }
-
-  /**
-   * 计算统计数据
-   */
-  async calculateStatistics() {
-    try {
-      const profilePointer = this.currentUser!.toPointer();
-
-      // 查询总项目数
-      const totalQuery = new Parse.Query('Project');
-      totalQuery.equalTo('assignee', profilePointer);
-      totalQuery.notEqualTo('isDeleted', true);
-      this.totalProjects = await totalQuery.count();
-
-      // 查询已完成项目数
-      const completedQuery = new Parse.Query('Project');
-      completedQuery.equalTo('assignee', profilePointer);
-      completedQuery.equalTo('currentStage', '售后归档');
-      completedQuery.notEqualTo('isDeleted', true);
-      this.completedProjects = await completedQuery.count();
-
-      // 查询本月项目数
-      const currentMonth = new Date();
-      currentMonth.setDate(1);
-      currentMonth.setHours(0, 0, 0, 0);
-
-      const monthQuery = new Parse.Query('Project');
-      monthQuery.equalTo('assignee', profilePointer);
-      monthQuery.greaterThanOrEqualTo('createdAt', currentMonth);
-      monthQuery.notEqualTo('isDeleted', true);
-      this.currentMonthProjects = await monthQuery.count();
-
-      console.log(`✅ 统计数据:总项目=${this.totalProjects}, 已完成=${this.completedProjects}, 本月=${this.currentMonthProjects}`);
-    } catch (err) {
-      console.error('计算统计数据失败:', err);
-    }
-  }
-
-  /**
-   * 将项目转换为案例
-   */
-  transformProjectToCase(project: FmodeObject): CaseWork {
-    const data = project.get('data') || {};
-    const pricing = data.pricing || {};
-    const contact = project.get('contact');
-
-    // 获取封面图片
-    let coverImage = '/assets/images/default-project.jpg';
-    if (data.referenceImages && data.referenceImages.length > 0) {
-      coverImage = data.referenceImages[0];
-    } else if (data.deliverables && data.deliverables.length > 0) {
-      const firstDeliverable = data.deliverables[0];
-      if (firstDeliverable.files && firstDeliverable.files.length > 0) {
-        coverImage = firstDeliverable.files[0];
-      }
-    }
-
-    return {
-      id: project.id,
-      projectId: project.id,
-      projectTitle: project.get('title') || '未命名项目',
-      coverImage: coverImage,
-      description: data.description || project.get('title') || '',
-      tags: data.tags || data.stylePreferences || [],
-      completionDate: project.get('updatedAt') || new Date(),
-      customerName: contact?.get('name') || '客户',
-      status: project.get('status') || '已完成',
-      totalPrice: pricing.totalAmount || pricing.total || pricing.finalPrice,
-      roomType: data.roomType || data.spaceType
-    };
-  }
-
-  /**
-   * 获取默认技能评分
-   */
-  getDefaultSkillRatings(): SkillRating[] {
-    const role = this.currentUser?.get('roleName') || '组员';
-
-    if (role === '组员' || role === '设计师') {
-      return [
-        { name: '空间设计', currentScore: 70, targetScore: 90, category: '设计能力' },
-        { name: '色彩搭配', currentScore: 65, targetScore: 85, category: '设计能力' },
-        { name: '软装搭配', currentScore: 75, targetScore: 90, category: '设计能力' },
-        { name: '客户沟通', currentScore: 60, targetScore: 80, category: '沟通能力' },
-        { name: '需求分析', currentScore: 65, targetScore: 85, category: '沟通能力' },
-        { name: '3D建模', currentScore: 70, targetScore: 85, category: '技术能力' },
-        { name: '效果图渲染', currentScore: 75, targetScore: 90, category: '技术能力' },
-        { name: '项目管理', currentScore: 60, targetScore: 80, category: '项目管理' }
-      ];
-    } else if (role === '客服') {
-      return [
-        { name: '客户接待', currentScore: 80, targetScore: 95, category: '沟通能力' },
-        { name: '需求挖掘', currentScore: 75, targetScore: 90, category: '沟通能力' },
-        { name: '订单管理', currentScore: 70, targetScore: 85, category: '项目管理' },
-        { name: '售后服务', currentScore: 75, targetScore: 90, category: '沟通能力' },
-        { name: '问题解决', currentScore: 65, targetScore: 85, category: '项目管理' }
-      ];
-    }
-
-    return [];
-  }
-
-  // ==================== 编辑功能 ====================
-
-  /**
-   * 打开编辑自我评价
-   */
-  openEditEvaluation() {
-    this.editingEvaluation = JSON.parse(JSON.stringify(this.selfEvaluation));
-    this.showEditEvaluation = true;
-  }
-
-  /**
-   * 保存自我评价
-   */
-  async saveEvaluation() {
-    if (!this.editingEvaluation) return;
-
-    try {
-      this.editingEvaluation.lastUpdated = new Date();
-
-      const data = this.currentUser!.get('data') || {};
-      data.selfEvaluation = this.editingEvaluation;
-
-      this.currentUser!.set('data', data);
-      await this.currentUser!.save();
-
-      this.selfEvaluation = this.editingEvaluation;
-      this.showEditEvaluation = false;
-      this.editingEvaluation = null;
-
-      window?.fmode?.alert('保存成功!');
-    } catch (err: any) {
-      console.error('保存自我评价失败:', err);
-      window?.fmode?.alert('保存失败: ' + (err.message || '未知错误'));
-    }
-  }
-
-  /**
-   * 打开案例选择器
-   */
-  async openCaseSelector() {
-    try {
-      this.loadingMessage = '加载可选项目...';
-      this.loading = true;
-
-      // 查询已完成的项目
-      const query = new Parse.Query('Project');
-      query.equalTo('assignee', this.currentUser!.toPointer());
-      query.equalTo('currentStage', '售后归档');
-      query.notEqualTo('isDeleted', true);
-      query.include('contact');
-      query.descending('updatedAt');
-      query.limit(100);
-
-      this.availableProjects = await query.find();
-      this.selectedProjectIds = this.caseWorks.map(c => c.projectId);
-      
-      this.showCaseSelector = true;
-      console.log(`✅ 找到 ${this.availableProjects.length} 个可选项目`);
-    } catch (err) {
-      console.error('加载可选项目失败:', err);
-      window?.fmode?.alert('加载失败,请重试');
-    } finally {
-      this.loading = false;
-    }
-  }
-
-  /**
-   * 切换项目选择
-   */
-  toggleProjectSelection(projectId: string) {
-    const index = this.selectedProjectIds.indexOf(projectId);
-    if (index > -1) {
-      this.selectedProjectIds.splice(index, 1);
-    } else {
-      if (this.selectedProjectIds.length >= 12) {
-        window?.fmode?.alert('最多选择12个案例');
-        return;
-      }
-      this.selectedProjectIds.push(projectId);
-    }
-  }
-
-  /**
-   * 保存案例选择
-   */
-  async saveCaseSelection() {
-    try {
-      const data = this.currentUser!.get('data') || {};
-      data.caseWorks = this.selectedProjectIds;
-
-      this.currentUser!.set('data', data);
-      await this.currentUser!.save();
-
-      // 重新加载案例
-      await this.loadCaseWorks();
-
-      this.showCaseSelector = false;
-      window?.fmode?.alert('保存成功!');
-    } catch (err: any) {
-      console.error('保存案例选择失败:', err);
-      window?.fmode?.alert('保存失败: ' + (err.message || '未知错误'));
-    }
-  }
-
-  /**
-   * 保存技能评分
-   */
-  async saveSkillRatings() {
-    try {
-      const data = this.currentUser!.get('data') || {};
-      data.skillRatings = this.skillRatings;
-
-      this.currentUser!.set('data', data);
-      await this.currentUser!.save();
-
-      this.showSkillEditor = false;
-      window?.fmode?.alert('保存成功!');
-    } catch (err: any) {
-      console.error('保存技能评分失败:', err);
-      window?.fmode?.alert('保存失败: ' + (err.message || '未知错误'));
-    }
-  }
-
-  // ==================== 原有群聊/联系人场景功能(保留) ====================
-
   async handleGroupChatScene() {
     this.loadingMessage = '查询项目信息...';
+
+    // 查询群聊关联的项目
     const projectPointer = this.groupChat!.get('project');
 
     if (projectPointer) {
+      // 有项目,加载项目详情
       let pid = projectPointer.id || projectPointer.objectId
       try {
         const query = new Parse.Query('Project');
         query.include('contact', 'assignee');
         this.project = await query.get(pid);
+
+        wxdebug('找到项目', this.project.toJSON());
+
+        // 跳转项目详情
         await this.navigateToProjectDetail();
       } catch (err) {
         console.error('加载项目失败:', err);
+        wxdebug('加载项目失败', err);
         this.error = '项目已删除或无权访问';
       }
     } else {
+      // 无项目,查询历史项目并显示创建引导
       await this.loadHistoryProjects();
       this.showCreateProjectGuide();
     }
   }
 
+  /**
+   * 处理联系人场景
+   */
   async handleContactScene() {
+    wxdebug('联系人场景,跳转客户画像', {
+      contactId: this.contact!.id,
+      contactName: this.contact!.get('name')
+    });
+
+    // 跳转客户画像页面
     await this.router.navigate(['/wxwork', this.cid, 'contact', this.contact!.id], {
-      queryParams: { profileId: this.currentUser!.id }
+      queryParams: {
+        profileId: this.currentUser!.id
+      }
     });
   }
 
+  /**
+   * 加载历史项目(当前群聊相关的其他项目)
+   */
   async loadHistoryProjects() {
     try {
+      // 通过 ProjectGroup 查询该群聊的所有项目
       const pgQuery = new Parse.Query('ProjectGroup');
       pgQuery.equalTo('groupChat', this.groupChat!.toPointer());
       pgQuery.include('project');
@@ -677,32 +263,53 @@ export class ProjectLoaderComponent implements OnInit {
       this.historyProjects = projectGroups
         .map((pg: any) => pg.get('project'))
         .filter((p: any) => p && !p.get('isDeleted'));
+
+      wxdebug('找到历史项目', { count: this.historyProjects.length });
     } catch (err) {
       console.error('加载历史项目失败:', err);
+      wxdebug('加载历史项目失败', err);
     }
   }
 
+  /**
+   * 显示创建项目引导
+   */
   showCreateProjectGuide() {
     this.showCreateGuide = true;
     this.defaultProjectName = this.groupChat!.get('name') || '新项目';
     this.projectName = this.defaultProjectName;
+    wxdebug('显示创建项目引导', {
+      groupName: this.groupChat!.get('name'),
+      historyProjectsCount: this.historyProjects.length
+    });
   }
 
+  /**
+   * 创建项目
+   */
   async createProject() {
     if (!this.projectName.trim()) {
-      window?.fmode?.alert('请输入项目名称');
+     window?.fmode?.alert('请输入项目名称');
       return;
     }
 
+    // 权限检查
     const role = this.currentUser!.get('roleName');
     if (!['客服', '组长', '管理员'].includes(role)) {
-      window?.fmode?.alert('您没有权限创建项目');
+     window?.fmode?.alert('您没有权限创建项目');
       return;
     }
 
     try {
       this.creating = true;
+      wxdebug('开始创建项目', {
+        projectName: this.projectName,
+        groupChatId: this.groupChat!.id,
+        currentUserId: this.currentUser!.id,
+        role: role
+      });
 
+      // 1. 创建项目
       const Project = Parse.Object.extend('Project');
       const project = new Project();
 
@@ -717,10 +324,14 @@ export class ProjectLoaderComponent implements OnInit {
       });
 
       await project.save();
+      wxdebug('项目创建成功', { projectId: project.id });
 
+      // 2. 关联群聊
       this.groupChat!.set('project', project.toPointer());
       await this.groupChat!.save();
+      wxdebug('群聊关联项目成功');
 
+      // 3. 创建 ProjectGroup 关联(支持多项目多群)
       const ProjectGroup = Parse.Object.extend('ProjectGroup');
       const pg = new ProjectGroup();
       pg.set('project', project.toPointer());
@@ -728,48 +339,78 @@ export class ProjectLoaderComponent implements OnInit {
       pg.set('isPrimary', true);
       pg.set('company', this.currentUser!.get('company'));
       await pg.save();
+      wxdebug('ProjectGroup关联创建成功');
 
-      await this.activityLogService.logActivity({
-        actorId: this.currentUser!.id,
-        actorName: this.currentUser!.get('name') || '系统',
-        actorRole: role,
-        actionType: 'create',
-        module: 'project',
-        entityType: 'Project',
-        entityId: project.id,
-        entityName: this.projectName.trim(),
-        description: '创建了新项目',
-        metadata: {
-          createdFrom: 'wxwork_groupchat',
-          groupChatId: this.groupChat!.id,
-          status: '待分配',
-          stage: '订单分配'
-        }
-      });
+      // 4. 记录活动日志
+      try {
+        await this.activityLogService.logActivity({
+          actorId: this.currentUser!.id,
+          actorName: this.currentUser!.get('name') || '系统',
+          actorRole: role,
+          actionType: 'create',
+          module: 'project',
+          entityType: 'Project',
+          entityId: project.id,
+          entityName: this.projectName.trim(),
+          description: '创建了新项目',
+          metadata: {
+            createdFrom: 'wxwork_groupchat',
+            groupChatId: this.groupChat!.id,
+            status: '待分配',
+            stage: '订单分配'
+          }
+        });
+        wxdebug('活动日志记录成功');
+      } catch (logError) {
+        console.error('记录活动日志失败:', logError);
+        // 活动日志失败不影响主流程
+      }
 
+      // 5. 跳转项目详情
       this.project = project;
       await this.navigateToProjectDetail();
     } catch (err: any) {
       console.error('创建项目失败:', err);
-      window?.fmode?.alert('创建失败: ' + (err.message || '未知错误'));
+      wxdebug('创建项目失败', err);
+     window?.fmode?.alert('创建失败: ' + (err.message || '未知错误'));
     } finally {
       this.creating = false;
     }
   }
 
+  /**
+   * 选择历史项目
+   */
   async selectHistoryProject(project: FmodeObject) {
     try {
+      wxdebug('选择历史项目', {
+        projectId: project.id,
+        projectTitle: project.get('title')
+      });
+
+      // 更新群聊的当前项目
       this.groupChat!.set('project', project.toPointer());
       await this.groupChat!.save();
+
+      // 跳转项目详情
       this.project = project;
       await this.navigateToProjectDetail();
     } catch (err: any) {
       console.error('关联项目失败:', err);
-      window?.fmode?.alert('关联失败: ' + (err.message || '未知错误'));
+     window?.fmode?.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,
@@ -778,26 +419,36 @@ export class ProjectLoaderComponent implements OnInit {
     });
   }
 
-  // ==================== 工具方法 ====================
-
+  /**
+   * 重新加载
+   */
   async reload() {
     this.error = null;
     this.showCreateGuide = false;
     this.historyProjects = [];
-    this.chatType = 'personal';
+    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('roleName') || '未知';
   }
 
+  /**
+   * 获取项目状态的显示样式类
+   */
   getProjectStatusClass(status: string): string {
     const classMap: any = {
       '待分配': 'status-pending',
@@ -809,49 +460,12 @@ export class ProjectLoaderComponent implements OnInit {
     return classMap[status] || 'status-default';
   }
 
-  formatDate(date: Date | string): string {
+  /**
+   * 格式化日期
+   */
+  formatDate(date: Date): string {
     if (!date) return '';
     const d = new Date(date);
     return `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}`;
   }
-
-  formatMonth(monthStr: string): string {
-    const [year, month] = monthStr.split('-');
-    return `${year}年${month}月`;
-  }
-
-  formatCurrency(amount: number): string {
-    if (!amount) return '¥0';
-    return `¥${amount.toLocaleString()}`;
-  }
-
-  getScoreColor(score: number): string {
-    if (score >= 80) return 'score-high';
-    if (score >= 60) return 'score-medium';
-    return 'score-low';
-  }
-
-  getScoreProgress(current: number, target: number): number {
-    if (target === 0) return 0;
-    return Math.min((current / target) * 100, 100);
-  }
-
-  filterSkillsByCategory(category: string): SkillRating[] {
-    return this.skillRatings.filter(s => s.category === category);
-  }
-
-  getMaxMonthlyProjects(): number {
-    if (this.monthlyStats.length === 0) return 1;
-    return Math.max(...this.monthlyStats.map(m => m.totalProjects));
-  }
-
-  updateStrengths(value: string) {
-    if (!this.editingEvaluation) return;
-    this.editingEvaluation.strengths = value.split(',').map(s => s.trim()).filter(s => s.length > 0);
-  }
-
-  updateImprovements(value: string) {
-    if (!this.editingEvaluation) return;
-    this.editingEvaluation.improvements = value.split(',').map(s => s.trim()).filter(s => s.length > 0);
-  }
 }

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно