|
@@ -662,6 +662,7 @@
|
|
|
|
|
|
<!-- 新增:客户信息右侧 2x2 售后模块布局 -->
|
|
|
@if (expandedSection === 'aftercare') {
|
|
|
+ <!-- 上方 2x2 网格:前4个模块 -->
|
|
|
<div class="aftercare-grid">
|
|
|
|
|
|
<!-- 1/4:尾款结算 -->
|
|
@@ -847,187 +848,514 @@
|
|
|
}
|
|
|
</div>
|
|
|
</div>
|
|
|
-
|
|
|
- <!-- 5/5:项目复盘 -->
|
|
|
- <div class="aftercare-module review-module card">
|
|
|
- <div class="module-header">
|
|
|
- <h2>📊 项目复盘</h2>
|
|
|
- <p class="module-description">基于SOP执行数据和经验总结,自动生成复盘报告</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 下方横向展示:项目复盘模块 -->
|
|
|
+ <div class="project-review-section">
|
|
|
+ <div class="review-section-header">
|
|
|
+ <div class="header-left">
|
|
|
+ <h2 class="section-title">📊 项目复盘</h2>
|
|
|
+ <p class="section-subtitle">基于SOP执行数据和经验总结,自动生成复盘报告</p>
|
|
|
</div>
|
|
|
- <div class="review-management-enhanced">
|
|
|
- <div class="review-features">
|
|
|
- <div class="feature-card">
|
|
|
- <div class="feature-icon">📈</div>
|
|
|
- <div class="feature-content">
|
|
|
- <h4>SOP执行分析</h4>
|
|
|
- <p>自动分析各阶段SOP执行情况和时效</p>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="feature-card">
|
|
|
- <div class="feature-icon">💡</div>
|
|
|
- <div class="feature-content">
|
|
|
- <h4>经验总结</h4>
|
|
|
- <p>提取项目亮点和改进建议</p>
|
|
|
+ <div class="header-right">
|
|
|
+ @if (canEditSection('aftercare')) {
|
|
|
+ <button class="generate-review-btn" (click)="generateReviewReport()" [disabled]="isGeneratingReview">
|
|
|
+ @if (isGeneratingReview) {
|
|
|
+ <span class="loading-spinner"></span>
|
|
|
+ 生成中...
|
|
|
+ } @else {
|
|
|
+ 📊 生成复盘报告
|
|
|
+ }
|
|
|
+ </button>
|
|
|
+ @if (projectReview) {
|
|
|
+ <button class="export-review-btn" (click)="exportReviewReport()">
|
|
|
+ 📤 导出报告
|
|
|
+ </button>
|
|
|
+ }
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Tab切换导航 -->
|
|
|
+ <div class="review-tabs">
|
|
|
+ <button
|
|
|
+ class="review-tab"
|
|
|
+ [class.active]="activeReviewTab === 'sop'"
|
|
|
+ (click)="activeReviewTab = 'sop'">
|
|
|
+ <span class="tab-icon">📈</span>
|
|
|
+ <span class="tab-label">SOP执行数据</span>
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ class="review-tab"
|
|
|
+ [class.active]="activeReviewTab === 'experience'"
|
|
|
+ (click)="activeReviewTab = 'experience'">
|
|
|
+ <span class="tab-icon">💡</span>
|
|
|
+ <span class="tab-label">经验复盘</span>
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ class="review-tab"
|
|
|
+ [class.active]="activeReviewTab === 'suggestions'"
|
|
|
+ (click)="activeReviewTab = 'suggestions'">
|
|
|
+ <span class="tab-icon">🔧</span>
|
|
|
+ <span class="tab-label">优化建议</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- Tab内容区域 -->
|
|
|
+ <div class="review-content-area">
|
|
|
+ <!-- SOP执行数据 -->
|
|
|
+ @if (activeReviewTab === 'sop') {
|
|
|
+ <div class="sop-data-content">
|
|
|
+ <div class="sop-metrics-grid">
|
|
|
+ <!-- 关键指标卡片 -->
|
|
|
+ <div class="metric-card">
|
|
|
+ <div class="metric-header">
|
|
|
+ <span class="metric-icon">💬</span>
|
|
|
+ <h4 class="metric-title">需求沟通次数</h4>
|
|
|
+ </div>
|
|
|
+ <div class="metric-value-large">{{ sopMetrics?.communicationCount || 0 }}</div>
|
|
|
+ <div class="metric-footer">
|
|
|
+ <span class="metric-label">平均水平:</span>
|
|
|
+ <span class="metric-benchmark">{{ sopMetrics?.avgCommunication || 5 }}次</span>
|
|
|
+ <span class="metric-status" [class.good]="(sopMetrics?.communicationCount || 0) <= (sopMetrics?.avgCommunication || 5)" [class.warning]="(sopMetrics?.communicationCount || 0) > (sopMetrics?.avgCommunication || 5)">
|
|
|
+ {{ (sopMetrics?.communicationCount || 0) <= (sopMetrics?.avgCommunication || 5) ? '✓ 良好' : '⚠ 超标' }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <div class="feature-card">
|
|
|
- <div class="feature-icon">📋</div>
|
|
|
- <div class="feature-content">
|
|
|
- <h4>智能报告</h4>
|
|
|
- <p>自动生成结构化复盘报告</p>
|
|
|
+
|
|
|
+ <div class="metric-card">
|
|
|
+ <div class="metric-header">
|
|
|
+ <span class="metric-icon">🔄</span>
|
|
|
+ <h4 class="metric-title">改图次数</h4>
|
|
|
+ </div>
|
|
|
+ <div class="metric-value-large">{{ sopMetrics?.revisionCount || 0 }}</div>
|
|
|
+ <div class="metric-footer">
|
|
|
+ <span class="metric-label">平均水平:</span>
|
|
|
+ <span class="metric-benchmark">{{ sopMetrics?.avgRevision || 2 }}次</span>
|
|
|
+ <span class="metric-status" [class.good]="(sopMetrics?.revisionCount || 0) <= (sopMetrics?.avgRevision || 2)" [class.warning]="(sopMetrics?.revisionCount || 0) > (sopMetrics?.avgRevision || 2)">
|
|
|
+ {{ (sopMetrics?.revisionCount || 0) <= (sopMetrics?.avgRevision || 2) ? '✓ 良好' : '⚠ 超标' }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <div class="feature-card">
|
|
|
- <div class="feature-icon">🔄</div>
|
|
|
- <div class="feature-content">
|
|
|
- <h4>持续优化</h4>
|
|
|
- <p>为后续项目提供参考和改进方向</p>
|
|
|
+
|
|
|
+ <div class="metric-card">
|
|
|
+ <div class="metric-header">
|
|
|
+ <span class="metric-icon">⏱️</span>
|
|
|
+ <h4 class="metric-title">交付周期</h4>
|
|
|
+ </div>
|
|
|
+ <div class="metric-value-large">{{ sopMetrics?.deliveryCycle || 0 }}<span class="unit">天</span></div>
|
|
|
+ <div class="metric-footer">
|
|
|
+ <span class="metric-label">标准周期:</span>
|
|
|
+ <span class="metric-benchmark">{{ sopMetrics?.standardCycle || 15 }}天</span>
|
|
|
+ <span class="metric-status" [class.good]="(sopMetrics?.deliveryCycle || 0) <= (sopMetrics?.standardCycle || 15)" [class.warning]="(sopMetrics?.deliveryCycle || 0) > (sopMetrics?.standardCycle || 15)">
|
|
|
+ {{ (sopMetrics?.deliveryCycle || 0) <= (sopMetrics?.standardCycle || 15) ? '✓ 达标' : '⚠ 延期' }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 复盘状态显示 -->
|
|
|
- <div class="review-status-card">
|
|
|
- <div class="status-header">
|
|
|
- <h4>复盘状态</h4>
|
|
|
- <span class="status-badge" [class]="getReviewStatus()">
|
|
|
- {{ getReviewStatusText() }}
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- <div class="status-content">
|
|
|
- @if (projectReview) {
|
|
|
- <div class="review-summary">
|
|
|
- <div class="summary-item">
|
|
|
- <label>生成时间:</label>
|
|
|
- <span>{{ formatDateTime(projectReview.generatedAt) }}</span>
|
|
|
- </div>
|
|
|
- <div class="summary-item">
|
|
|
- <label>项目评分:</label>
|
|
|
- <span class="score">{{ projectReview.overallScore }}/100</span>
|
|
|
- </div>
|
|
|
- <div class="summary-item">
|
|
|
- <label>关键亮点:</label>
|
|
|
- <span>{{ projectReview.keyHighlights.join('、') || '暂无' }}</span>
|
|
|
+
|
|
|
+ <div class="metric-card">
|
|
|
+ <div class="metric-header">
|
|
|
+ <span class="metric-icon">⭐</span>
|
|
|
+ <h4 class="metric-title">客户满意度</h4>
|
|
|
+ </div>
|
|
|
+ <div class="metric-value-large">{{ sopMetrics?.customerSatisfaction || 0 }}<span class="unit">/5</span></div>
|
|
|
+ <div class="metric-footer">
|
|
|
+ <div class="satisfaction-stars">
|
|
|
+ @for (star of [1,2,3,4,5]; track star) {
|
|
|
+ <span class="star" [class.filled]="star <= (sopMetrics?.customerSatisfaction || 0)">★</span>
|
|
|
+ }
|
|
|
</div>
|
|
|
</div>
|
|
|
- } @else {
|
|
|
- <p class="no-review-text">项目完成后将自动生成复盘报告</p>
|
|
|
- }
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
- <!-- 复盘报告详情 -->
|
|
|
- @if (projectReview) {
|
|
|
- <div class="review-report-card">
|
|
|
- <div class="report-header">
|
|
|
- <h4>📊 复盘报告详情</h4>
|
|
|
- <button class="export-btn" (click)="exportReviewReport()">
|
|
|
- 📤 导出报告
|
|
|
- </button>
|
|
|
- </div>
|
|
|
- <div class="report-content">
|
|
|
- <!-- SOP执行分析 -->
|
|
|
- <div class="report-section">
|
|
|
- <h5>SOP执行分析</h5>
|
|
|
- <div class="sop-analysis">
|
|
|
- @for (stage of projectReview.sopAnalysis; track stage.stageName) {
|
|
|
- <div class="stage-analysis">
|
|
|
- <div class="stage-info">
|
|
|
- <span class="stage-name">{{ stage.stageName }}</span>
|
|
|
- <span class="stage-score" [class]="getScoreClass(stage.score)">
|
|
|
- {{ stage.score }}/100
|
|
|
- </span>
|
|
|
+ <!-- 阶段执行详情 -->
|
|
|
+ <div class="sop-stages-section">
|
|
|
+ <h3 class="subsection-title">各阶段执行详情</h3>
|
|
|
+ <div class="stages-timeline">
|
|
|
+ @for (stage of sopStagesData; track stage.name) {
|
|
|
+ <div class="stage-timeline-item" [class.completed]="stage.status === 'completed'" [class.ongoing]="stage.status === 'ongoing'" [class.delayed]="stage.isDelayed">
|
|
|
+ <div class="stage-indicator">
|
|
|
+ <div class="stage-dot"></div>
|
|
|
+ @if (!$last) {
|
|
|
+ <div class="stage-line"></div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ <div class="stage-content-card">
|
|
|
+ <div class="stage-card-header">
|
|
|
+ <h4 class="stage-name">{{ stage.name }}</h4>
|
|
|
+ <span class="stage-status-badge" [class]="stage.status">
|
|
|
+ {{ stage.statusText }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="stage-metrics">
|
|
|
+ <div class="stage-metric-item">
|
|
|
+ <span class="label">计划时长:</span>
|
|
|
+ <span class="value">{{ stage.plannedDuration }}天</span>
|
|
|
</div>
|
|
|
- <div class="stage-details">
|
|
|
- <div class="detail-item">
|
|
|
- <label>计划时长:</label>
|
|
|
- <span>{{ stage.plannedDuration }}天</span>
|
|
|
- </div>
|
|
|
- <div class="detail-item">
|
|
|
- <label>实际时长:</label>
|
|
|
- <span>{{ stage.actualDuration }}天</span>
|
|
|
- </div>
|
|
|
- <div class="detail-item">
|
|
|
- <label>执行状态:</label>
|
|
|
- <span class="status" [class]="stage.executionStatus">
|
|
|
- {{ getExecutionStatusText(stage.executionStatus) }}
|
|
|
- </span>
|
|
|
- </div>
|
|
|
+ <div class="stage-metric-item">
|
|
|
+ <span class="label">实际时长:</span>
|
|
|
+ <span class="value" [class.warning]="stage.actualDuration > stage.plannedDuration">{{ stage.actualDuration }}天</span>
|
|
|
+ </div>
|
|
|
+ <div class="stage-metric-item">
|
|
|
+ <span class="label">执行评分:</span>
|
|
|
+ <span class="value score" [class]="getScoreClass(stage.score)">{{ stage.score }}/100</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- }
|
|
|
+ @if (stage.issues && stage.issues.length > 0) {
|
|
|
+ <div class="stage-issues">
|
|
|
+ <span class="issues-label">⚠️ 问题:</span>
|
|
|
+ <span class="issues-text">{{ stage.issues.join('、') }}</span>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
|
|
|
- <!-- 经验总结 -->
|
|
|
- <div class="report-section">
|
|
|
- <h5>经验总结</h5>
|
|
|
- <div class="experience-summary">
|
|
|
- <div class="highlights">
|
|
|
- <h6>✨ 项目亮点</h6>
|
|
|
- <ul>
|
|
|
- @for (highlight of projectReview.keyHighlights; track highlight) {
|
|
|
- <li>{{ highlight }}</li>
|
|
|
- }
|
|
|
- </ul>
|
|
|
+ <!-- 数据图表展示 -->
|
|
|
+ <div class="sop-charts-section">
|
|
|
+ <h3 class="subsection-title">数据分析图表</h3>
|
|
|
+ <div class="charts-grid">
|
|
|
+ <div class="chart-card">
|
|
|
+ <h4 class="chart-title">阶段耗时对比</h4>
|
|
|
+ <div class="chart-placeholder">
|
|
|
+ <div class="bar-chart">
|
|
|
+ @for (stage of sopStagesData; track stage.name) {
|
|
|
+ <div class="bar-group">
|
|
|
+ <div class="bar-label">{{ stage.name }}</div>
|
|
|
+ <div class="bars">
|
|
|
+ <div class="bar planned" [style.height.%]="(stage.plannedDuration / getMaxDuration()) * 100">
|
|
|
+ <span class="bar-value">{{ stage.plannedDuration }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="bar actual" [style.height.%]="(stage.actualDuration / getMaxDuration()) * 100">
|
|
|
+ <span class="bar-value">{{ stage.actualDuration }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
</div>
|
|
|
- <div class="improvements">
|
|
|
- <h6>🔧 改进建议</h6>
|
|
|
- <ul>
|
|
|
- @for (improvement of projectReview.improvementSuggestions; track improvement) {
|
|
|
- <li>{{ improvement }}</li>
|
|
|
- }
|
|
|
- </ul>
|
|
|
+ <div class="chart-legend">
|
|
|
+ <span class="legend-item"><span class="legend-color planned"></span>计划时长</span>
|
|
|
+ <span class="legend-item"><span class="legend-color actual"></span>实际时长</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 客户满意度 -->
|
|
|
- <div class="report-section">
|
|
|
- <h5>客户满意度</h5>
|
|
|
- <div class="satisfaction-metrics">
|
|
|
- <div class="metric-item">
|
|
|
- <label>整体满意度:</label>
|
|
|
- <div class="rating">
|
|
|
- @for (star of [1,2,3,4,5]; track star) {
|
|
|
- <span class="star" [class.filled]="star <= projectReview.customerSatisfaction.overallRating">⭐</span>
|
|
|
+ <div class="chart-card">
|
|
|
+ <h4 class="chart-title">执行评分雷达图</h4>
|
|
|
+ <div class="chart-placeholder radar-chart">
|
|
|
+ <div class="radar-info">
|
|
|
+ <p>各阶段平均得分:<strong>{{ getAverageScore() }}/100</strong></p>
|
|
|
+ <div class="score-items">
|
|
|
+ @for (stage of sopStagesData.slice(0, 5); track stage.name) {
|
|
|
+ <div class="score-item">
|
|
|
+ <span class="stage-label">{{ stage.name }}:</span>
|
|
|
+ <span class="stage-score" [class]="getScoreClass(stage.score)">{{ stage.score }}</span>
|
|
|
+ </div>
|
|
|
}
|
|
|
- <span class="rating-text">({{ projectReview.customerSatisfaction.overallRating }}/5)</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- @if (projectReview.customerSatisfaction.feedback) {
|
|
|
- <div class="feedback">
|
|
|
- <label>客户反馈:</label>
|
|
|
- <p>"{{ projectReview.customerSatisfaction.feedback }}"</p>
|
|
|
- </div>
|
|
|
- }
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- }
|
|
|
+ </div>
|
|
|
+ }
|
|
|
|
|
|
- @if (canEditSection('aftercare')) {
|
|
|
- <div class="review-actions">
|
|
|
- <button class="primary-btn" (click)="generateReviewReport()" [disabled]="isGeneratingReview">
|
|
|
- @if (isGeneratingReview) {
|
|
|
- <span class="loading-spinner"></span>
|
|
|
- 生成中...
|
|
|
+ <!-- 经验复盘 -->
|
|
|
+ @if (activeReviewTab === 'experience') {
|
|
|
+ <div class="experience-content">
|
|
|
+ <div class="experience-intro">
|
|
|
+ <p class="intro-text">基于企业微信沟通记录智能提取关键信息,全面复盘项目过程</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="experience-grid">
|
|
|
+ <!-- 客户需求 -->
|
|
|
+ <div class="experience-card needs-card">
|
|
|
+ <div class="card-header-custom">
|
|
|
+ <span class="card-icon">📝</span>
|
|
|
+ <h3 class="card-title-custom">客户需求</h3>
|
|
|
+ <span class="count-badge">{{ experienceData?.customerNeeds?.length || 0 }}项</span>
|
|
|
+ </div>
|
|
|
+ <div class="card-content-scrollable">
|
|
|
+ @if (experienceData?.customerNeeds && experienceData.customerNeeds.length > 0) {
|
|
|
+ <ul class="experience-list">
|
|
|
+ @for (need of experienceData.customerNeeds; track $index) {
|
|
|
+ <li class="experience-item">
|
|
|
+ <span class="item-bullet">•</span>
|
|
|
+ <div class="item-content">
|
|
|
+ <p class="item-text">{{ need.text }}</p>
|
|
|
+ <div class="item-meta">
|
|
|
+ <span class="meta-time">{{ need.timestamp }}</span>
|
|
|
+ <span class="meta-source">来源:{{ need.source }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ }
|
|
|
+ </ul>
|
|
|
+ } @else {
|
|
|
+ <div class="empty-state-small">暂无客户需求记录</div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 客户顾虑 -->
|
|
|
+ <div class="experience-card concerns-card">
|
|
|
+ <div class="card-header-custom">
|
|
|
+ <span class="card-icon">🤔</span>
|
|
|
+ <h3 class="card-title-custom">客户顾虑</h3>
|
|
|
+ <span class="count-badge">{{ experienceData?.customerConcerns?.length || 0 }}项</span>
|
|
|
+ </div>
|
|
|
+ <div class="card-content-scrollable">
|
|
|
+ @if (experienceData?.customerConcerns && experienceData.customerConcerns.length > 0) {
|
|
|
+ <ul class="experience-list">
|
|
|
+ @for (concern of experienceData.customerConcerns; track $index) {
|
|
|
+ <li class="experience-item concern">
|
|
|
+ <span class="item-bullet">⚠️</span>
|
|
|
+ <div class="item-content">
|
|
|
+ <p class="item-text">{{ concern.text }}</p>
|
|
|
+ <div class="item-meta">
|
|
|
+ <span class="meta-time">{{ concern.timestamp }}</span>
|
|
|
+ @if (concern.resolved) {
|
|
|
+ <span class="meta-resolved">✓ 已解决</span>
|
|
|
+ } @else {
|
|
|
+ <span class="meta-unresolved">待处理</span>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ }
|
|
|
+ </ul>
|
|
|
+ } @else {
|
|
|
+ <div class="empty-state-small">暂无客户顾虑记录</div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 投诉点 -->
|
|
|
+ <div class="experience-card complaints-card">
|
|
|
+ <div class="card-header-custom">
|
|
|
+ <span class="card-icon">📢</span>
|
|
|
+ <h3 class="card-title-custom">投诉点</h3>
|
|
|
+ <span class="count-badge warning">{{ experienceData?.complaintPoints?.length || 0 }}项</span>
|
|
|
+ </div>
|
|
|
+ <div class="card-content-scrollable">
|
|
|
+ @if (experienceData?.complaintPoints && experienceData.complaintPoints.length > 0) {
|
|
|
+ <ul class="experience-list">
|
|
|
+ @for (complaint of experienceData.complaintPoints; track $index) {
|
|
|
+ <li class="experience-item complaint">
|
|
|
+ <span class="item-bullet">❗</span>
|
|
|
+ <div class="item-content">
|
|
|
+ <p class="item-text">{{ complaint.text }}</p>
|
|
|
+ <div class="item-meta">
|
|
|
+ <span class="meta-time">{{ complaint.timestamp }}</span>
|
|
|
+ <span class="meta-severity" [class]="complaint.severity">{{ complaint.severityText }}</span>
|
|
|
+ </div>
|
|
|
+ @if (complaint.resolution) {
|
|
|
+ <div class="item-resolution">
|
|
|
+ <span class="resolution-label">解决方案:</span>
|
|
|
+ <span class="resolution-text">{{ complaint.resolution }}</span>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ }
|
|
|
+ </ul>
|
|
|
+ } @else {
|
|
|
+ <div class="empty-state-small">✓ 暂无投诉记录</div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 项目亮点 -->
|
|
|
+ <div class="experience-card highlights-card">
|
|
|
+ <div class="card-header-custom">
|
|
|
+ <span class="card-icon">✨</span>
|
|
|
+ <h3 class="card-title-custom">项目亮点</h3>
|
|
|
+ <span class="count-badge success">{{ experienceData?.projectHighlights?.length || 0 }}项</span>
|
|
|
+ </div>
|
|
|
+ <div class="card-content-scrollable">
|
|
|
+ @if (experienceData?.projectHighlights && experienceData.projectHighlights.length > 0) {
|
|
|
+ <ul class="experience-list">
|
|
|
+ @for (highlight of experienceData.projectHighlights; track $index) {
|
|
|
+ <li class="experience-item highlight">
|
|
|
+ <span class="item-bullet">⭐</span>
|
|
|
+ <div class="item-content">
|
|
|
+ <p class="item-text">{{ highlight.text }}</p>
|
|
|
+ <div class="item-meta">
|
|
|
+ <span class="meta-category">{{ highlight.category }}</span>
|
|
|
+ @if (highlight.praised) {
|
|
|
+ <span class="meta-praised">👍 客户点赞</span>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ }
|
|
|
+ </ul>
|
|
|
+ } @else {
|
|
|
+ <div class="empty-state-small">暂无项目亮点记录</div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 沟通记录摘要 -->
|
|
|
+ <div class="communication-summary">
|
|
|
+ <h3 class="subsection-title">关键沟通记录</h3>
|
|
|
+ <div class="communication-timeline">
|
|
|
+ @if (experienceData?.communications && experienceData.communications.length > 0) {
|
|
|
+ @for (comm of experienceData.communications; track $index) {
|
|
|
+ <div class="communication-item">
|
|
|
+ <div class="comm-time">{{ comm.timestamp }}</div>
|
|
|
+ <div class="comm-content">
|
|
|
+ <div class="comm-header">
|
|
|
+ <span class="comm-participant">{{ comm.participant }}</span>
|
|
|
+ <span class="comm-type" [class]="comm.type">{{ comm.typeText }}</span>
|
|
|
+ </div>
|
|
|
+ <p class="comm-message">{{ comm.message }}</p>
|
|
|
+ @if (comm.attachments && comm.attachments.length > 0) {
|
|
|
+ <div class="comm-attachments">
|
|
|
+ <span class="attachment-icon">📎</span>
|
|
|
+ <span class="attachment-count">{{ comm.attachments.length }}个附件</span>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
} @else {
|
|
|
- 📊 生成复盘报告
|
|
|
+ <div class="empty-state-small">暂无沟通记录</div>
|
|
|
}
|
|
|
- </button>
|
|
|
- @if (projectReview) {
|
|
|
- <button class="secondary-btn" (click)="regenerateReviewReport()">
|
|
|
- 🔄 重新生成
|
|
|
- </button>
|
|
|
- <button class="primary-btn" (click)="shareReviewReport()">
|
|
|
- 📤 分享报告
|
|
|
- </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+
|
|
|
+ <!-- 优化建议 -->
|
|
|
+ @if (activeReviewTab === 'suggestions') {
|
|
|
+ <div class="suggestions-content">
|
|
|
+ <div class="suggestions-intro">
|
|
|
+ <div class="intro-card">
|
|
|
+ <h3 class="intro-title">智能分析与建议</h3>
|
|
|
+ <p class="intro-desc">基于项目执行数据和历史经验,为您提供具体可操作的优化建议</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="suggestions-list">
|
|
|
+ @if (optimizationSuggestions && optimizationSuggestions.length > 0) {
|
|
|
+ @for (suggestion of optimizationSuggestions; track $index) {
|
|
|
+ <div class="suggestion-card" [class]="suggestion.priority">
|
|
|
+ <div class="suggestion-header">
|
|
|
+ <div class="header-left-content">
|
|
|
+ <span class="suggestion-priority-badge" [class]="suggestion.priority">
|
|
|
+ {{ suggestion.priorityText }}
|
|
|
+ </span>
|
|
|
+ <span class="suggestion-category">{{ suggestion.category }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="header-right-content">
|
|
|
+ <span class="suggestion-impact">预期提升:<strong>{{ suggestion.expectedImprovement }}</strong></span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="suggestion-body">
|
|
|
+ <div class="suggestion-problem">
|
|
|
+ <h4 class="problem-title">🔍 问题分析</h4>
|
|
|
+ <p class="problem-text">{{ suggestion.problem }}</p>
|
|
|
+ <div class="problem-data">
|
|
|
+ @for (data of suggestion.dataPoints; track $index) {
|
|
|
+ <div class="data-point">
|
|
|
+ <span class="data-label">{{ data.label }}:</span>
|
|
|
+ <span class="data-value" [class.warning]="data.isWarning">{{ data.value }}</span>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="suggestion-solution">
|
|
|
+ <h4 class="solution-title">💡 优化建议</h4>
|
|
|
+ <p class="solution-text">{{ suggestion.solution }}</p>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="suggestion-actions-plan">
|
|
|
+ <h4 class="actions-title">📋 行动计划</h4>
|
|
|
+ <ul class="actions-list">
|
|
|
+ @for (action of suggestion.actionPlan; track $index) {
|
|
|
+ <li class="action-item">
|
|
|
+ <span class="action-step">{{ $index + 1 }}.</span>
|
|
|
+ <span class="action-text">{{ action }}</span>
|
|
|
+ </li>
|
|
|
+ }
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ @if (suggestion.references && suggestion.references.length > 0) {
|
|
|
+ <div class="suggestion-references">
|
|
|
+ <span class="references-label">📚 参考案例:</span>
|
|
|
+ @for (ref of suggestion.references; track $index) {
|
|
|
+ <span class="reference-tag">{{ ref }}</span>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="suggestion-footer">
|
|
|
+ <button class="action-btn accept" (click)="acceptSuggestion(suggestion)">
|
|
|
+ ✓ 采纳建议
|
|
|
+ </button>
|
|
|
+ <button class="action-btn detail" (click)="viewSuggestionDetail(suggestion)">
|
|
|
+ 查看详情
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ } @else {
|
|
|
+ <div class="empty-state-large">
|
|
|
+ <div class="empty-icon">📊</div>
|
|
|
+ <h3 class="empty-title">暂无优化建议</h3>
|
|
|
+ <p class="empty-desc">项目数据收集完成后将自动生成智能优化建议</p>
|
|
|
+ </div>
|
|
|
}
|
|
|
</div>
|
|
|
- }
|
|
|
- </div>
|
|
|
+
|
|
|
+ <!-- 建议统计 -->
|
|
|
+ @if (optimizationSuggestions && optimizationSuggestions.length > 0) {
|
|
|
+ <div class="suggestions-stats">
|
|
|
+ <h3 class="subsection-title">建议统计</h3>
|
|
|
+ <div class="stats-grid">
|
|
|
+ <div class="stat-card">
|
|
|
+ <div class="stat-icon">🔴</div>
|
|
|
+ <div class="stat-content">
|
|
|
+ <div class="stat-value">{{ getSuggestionCountByPriority('high') }}</div>
|
|
|
+ <div class="stat-label">高优先级</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="stat-card">
|
|
|
+ <div class="stat-icon">🟡</div>
|
|
|
+ <div class="stat-content">
|
|
|
+ <div class="stat-value">{{ getSuggestionCountByPriority('medium') }}</div>
|
|
|
+ <div class="stat-label">中优先级</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="stat-card">
|
|
|
+ <div class="stat-icon">🟢</div>
|
|
|
+ <div class="stat-content">
|
|
|
+ <div class="stat-value">{{ getSuggestionCountByPriority('low') }}</div>
|
|
|
+ <div class="stat-label">低优先级</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="stat-card">
|
|
|
+ <div class="stat-icon">📈</div>
|
|
|
+ <div class="stat-content">
|
|
|
+ <div class="stat-value">{{ getAverageImprovementPercent() }}%</div>
|
|
|
+ <div class="stat-label">平均预期提升</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ }
|
|
|
+ </div>
|
|
|
+ }
|
|
|
</div>
|
|
|
</div>
|
|
|
}
|