6 Commits 4e06cbc8d3 ... 1d142916a6

Author SHA1 Message Date
  0235701 1d142916a6 Merge branch 'master' of http://git.fmode.cn:3000/18879694722/AI-Salesperson-Assistant 2 days ago
  0235701 9f2b6539f5 update:page-crm-image 2 days ago
  0235701 02ede558d7 update;page-crm-training 2 days ago
  0235701 45ea96e764 update:login.componet and resigter.component 2 days ago
  0235701 f3a86636ff update:home ,trainingweb.optimize app.routes.ts 3 days ago
  0235701 33af2c7488 updata:refact home,training,image web 4 days ago
32 changed files with 11701 additions and 46 deletions
  1. 35 0
      .hintrc
  2. 16 1
      ai-assisant/angular.json
  3. 1232 0
      ai-assisant/demo/Data.html
  4. 1077 0
      ai-assisant/demo/assistant.html
  5. 1068 0
      ai-assisant/demo/first.html
  6. 570 0
      ai-assisant/demo/photo.html
  7. 1333 0
      ai-assisant/demo/training.html
  8. 126 2
      ai-assisant/package-lock.json
  9. 9 0
      ai-assisant/package.json
  10. 1 1
      ai-assisant/src/app/app.html
  11. 11 2
      ai-assisant/src/app/app.routes.ts
  12. 20 2
      ai-assisant/src/app/app.ts
  13. 4 0
      ai-assisant/src/index.html
  14. 487 0
      ai-assisant/src/lib/ncloud.ts
  15. 477 0
      ai-assisant/src/modules/crm/mobile/page-crm-home/login.component.ts
  16. 268 1
      ai-assisant/src/modules/crm/mobile/page-crm-home/page-crm-home.html
  17. 983 0
      ai-assisant/src/modules/crm/mobile/page-crm-home/page-crm-home.scss
  18. 123 18
      ai-assisant/src/modules/crm/mobile/page-crm-home/page-crm-home.spec.ts
  19. 338 5
      ai-assisant/src/modules/crm/mobile/page-crm-home/page-crm-home.ts
  20. 522 0
      ai-assisant/src/modules/crm/mobile/page-crm-home/register.component.ts
  21. 175 0
      ai-assisant/src/modules/crm/mobile/page-crm-image/cloud-service.ts
  22. 176 0
      ai-assisant/src/modules/crm/mobile/page-crm-image/crm-service.ts
  23. 266 1
      ai-assisant/src/modules/crm/mobile/page-crm-image/page-crm-image.html
  24. 734 0
      ai-assisant/src/modules/crm/mobile/page-crm-image/page-crm-image.scss
  25. 427 6
      ai-assisant/src/modules/crm/mobile/page-crm-image/page-crm-image.ts
  26. 108 1
      ai-assisant/src/modules/crm/mobile/page-crm-training/page-crm-training.html
  27. 422 0
      ai-assisant/src/modules/crm/mobile/page-crm-training/page-crm-training.scss
  28. 207 6
      ai-assisant/src/modules/crm/mobile/page-crm-training/page-crm-training.ts
  29. 284 0
      ai-assisant/src/modules/crm/mobile/page-crm-training/report-viewer.component.ts
  30. 40 0
      ai-assisant/src/modules/crm/mobile/page-crm-training/report.interface.ts
  31. 159 0
      ai-assisant/src/modules/crm/mobile/page-crm-training/training.service.ts
  32. 3 0
      ai-assisant/src/styles.scss

+ 35 - 0
.hintrc

@@ -0,0 +1,35 @@
+{
+  "extends": [
+    "development"
+  ],
+  "hints": {
+    "axe/name-role-value": [
+      "default",
+      {
+        "button-name": "off"
+      }
+    ],
+    "compat-api/css": [
+      "default",
+      {
+        "ignore": [
+          "backdrop-filter"
+        ]
+      }
+    ],
+    "meta-viewport": "off",
+    "axe/forms": [
+      "default",
+      {
+        "select-name": "off"
+      }
+    ],
+    "axe/aria": [
+      "default",
+      {
+        "aria-allowed-attr": "off",
+        "aria-required-parent": "off"
+      }
+    ]
+  }
+}

+ 16 - 1
ai-assisant/angular.json

@@ -30,6 +30,7 @@
               }
               }
             ],
             ],
             "styles": [
             "styles": [
+              "@angular/material/prebuilt-themes/azure-blue.css",
               "src/styles.scss"
               "src/styles.scss"
             ]
             ]
           },
           },
@@ -88,7 +89,21 @@
               }
               }
             ],
             ],
             "styles": [
             "styles": [
-              "src/styles.scss"
+              "@angular/material/prebuilt-themes/azure-blue.css",
+              "src/styles.scss",
+              {
+                "input": "https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap",
+                "inject": true,
+                "bundleName": "inter-font"
+              }
+            ],
+            "styles": [
+              "src/styles.scss",
+            {
+            "input": "https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap",
+             "inject": true,
+               "bundleName": "inter-font"
+            }
             ]
             ]
           }
           }
         }
         }

+ 1232 - 0
ai-assisant/demo/Data.html

@@ -0,0 +1,1232 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>AI实验室 - 数据训练中心</title>
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
+    <style>
+        :root {
+            --primary: #4285f4;
+            --primary-light: rgba(66, 133, 244, 0.1);
+            --primary-dark: #3367d6;
+            --text-dark: #0a192f;
+            --text-medium: #333333;
+            --text-light: #8898aa;
+            --background: #ffffff;
+            --card-bg: #f8f9fa;
+            --border: #e6e9ed;
+            --success: #34a853;
+            --warning: #fbbc05;
+            --error: #ea4335;
+            --shadow: 0 8px 24px rgba(0, 0, 0, 0.05);
+        }
+        
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+            font-family: 'Segoe UI', 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;
+        }
+        
+        body {
+            background-color: #f5f8ff;
+            background-image: linear-gradient(135deg, #f5f8ff 0%, #e8ecff 100%);
+            color: var(--text-medium);
+            line-height: 1.6;
+            padding: 16px;
+            max-width: 500px;
+            margin: 0 auto;
+            position: relative;
+            min-height: 100vh;
+            overflow-x: hidden;
+        }
+        
+        /* 头部导航 */
+        .header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 16px 0;
+            margin-bottom: 20px;
+            position: sticky;
+            top: 0;
+            background: transparent;
+            z-index: 100;
+        }
+        
+        .back-btn {
+            width: 40px;
+            height: 40px;
+            border-radius: 50%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            background: var(--background);
+            border: none;
+            color: var(--text-dark);
+            font-size: 18px;
+            cursor: pointer;
+            transition: all 0.3s ease;
+            box-shadow: var(--shadow);
+        }
+        
+        .back-btn:hover {
+            background: var(--primary-light);
+            color: var(--primary);
+        }
+        
+        .title {
+            font-size: 24px;
+            font-weight: 700;
+            color: var(--text-dark);
+            text-align: center;
+            flex-grow: 1;
+            text-shadow: 0 2px 4px rgba(0,0,0,0.05);
+        }
+        
+        /* 卡片样式 */
+        .card {
+            background: var(--background);
+            border-radius: 20px;
+            padding: 24px;
+            margin-bottom: 20px;
+            box-shadow: var(--shadow);
+            position: relative;
+            overflow: hidden;
+            border: 1px solid rgba(66, 133, 244, 0.1);
+            transition: transform 0.3s ease, box-shadow 0.3s ease;
+        }
+        
+        .card:hover {
+            transform: translateY(-5px);
+            box-shadow: 0 12px 30px rgba(66, 133, 244, 0.15);
+        }
+        
+        .card-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 20px;
+        }
+        
+        .card-title {
+            font-size: 18px;
+            font-weight: 700;
+            color: var(--text-dark);
+        }
+        
+        .card-subtitle {
+            font-size: 14px;
+            color: var(--text-light);
+            margin-top: 4px;
+        }
+        
+        /* 上传控制台 */
+        .upload-console {
+            position: relative;
+            min-height: 220px;
+        }
+        
+        .source-tags {
+            display: flex;
+            gap: 10px;
+            margin-top: 20px;
+            flex-wrap: wrap;
+        }
+        
+        .source-tag {
+            background: #f0f4f8;
+            padding: 8px 16px;
+            border-radius: 20px;
+            font-size: 14px;
+            color: var(--text-dark);
+            transition: all 0.2s ease;
+            border: 1px solid transparent;
+            cursor: pointer;
+            box-shadow: 0 2px 5px rgba(0,0,0,0.05);
+        }
+        
+        .source-tag.active {
+            border-color: var(--primary);
+            box-shadow: 0 0 0 2px rgba(66, 133, 244, 0.3);
+            color: var(--primary);
+            font-weight: 600;
+            background: rgba(66, 133, 244, 0.08);
+        }
+        
+        /* 自定义标签区域 */
+        .custom-tag-form {
+            display: flex;
+            margin-top: 25px;
+            gap: 10px;
+            align-items: center;
+        }
+        
+        .custom-tag-input {
+            flex: 1;
+            padding: 12px 18px;
+            border-radius: 20px;
+            border: 1px solid var(--border);
+            outline: none;
+            font-size: 14px;
+            transition: border-color 0.3s;
+            background: var(--card-bg);
+            box-shadow: inset 0 2px 4px rgba(0,0,0,0.03);
+        }
+        
+        .custom-tag-input:focus {
+            border-color: var(--primary);
+            box-shadow: 0 0 0 2px rgba(66, 133, 244, 0.2);
+        }
+        
+        .add-tag-btn {
+            background: var(--primary);
+            color: white;
+            border: none;
+            border-radius: 20px;
+            padding: 12px 24px;
+            font-size: 14px;
+            font-weight: 600;
+            cursor: pointer;
+            transition: background 0.3s;
+            display: flex;
+            align-items: center;
+            gap: 8px;
+            box-shadow: 0 4px 10px rgba(66, 133, 244, 0.3);
+        }
+        
+        .add-tag-btn:hover {
+            background: var(--primary-dark);
+            transform: translateY(-2px);
+            box-shadow: 0 6px 15px rgba(66, 133, 244, 0.4);
+        }
+        
+        /* 数据看板 */
+        .stats-container {
+            display: flex;
+            justify-content: space-between;
+            gap: 15px;
+            margin-top: 15px;
+        }
+        
+        .stat-item {
+            flex: 1;
+            text-align: center;
+            padding: 15px;
+            border-radius: 16px;
+            background: var(--background);
+            position: relative;
+            box-shadow: 0 4px 10px rgba(0,0,0,0.03);
+            border: 1px solid rgba(66, 133, 244, 0.08);
+        }
+        
+        .stat-value {
+            font-size: 24px;
+            font-weight: 700;
+            color: var(--text-dark);
+            margin: 10px 0;
+        }
+        
+        .stat-label {
+            font-size: 13px;
+            color: var(--text-light);
+        }
+        
+        .progress-ring {
+            position: relative;
+            width: 80px;
+            height: 80px;
+            margin: 0 auto;
+        }
+        
+        .progress-bg {
+            width: 100%;
+            height: 100%;
+            border-radius: 50%;
+            background: conic-gradient(var(--primary) 0% 75%, var(--border) 75% 100%);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+        
+        .progress-inner {
+            width: 70px;
+            height: 70px;
+            border-radius: 50%;
+            background: var(--card-bg);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 18px;
+            font-weight: 700;
+            color: var(--text-dark);
+        }
+        
+        .quality-bar {
+            height: 8px;
+            background: var(--border);
+            border-radius: 4px;
+            margin-top: 15px;
+            overflow: hidden;
+            position: relative;
+        }
+        
+        .quality-fill {
+            height: 100%;
+            width: 85%;
+            background: linear-gradient(90deg, var(--primary), var(--primary-dark));
+            border-radius: 4px;
+            position: relative;
+        }
+        
+        .quality-fill::after {
+            content: '';
+            position: absolute;
+            top: 0;
+            left: 0;
+            right: 0;
+            bottom: 0;
+            background: linear-gradient(90deg, 
+                transparent, 
+                rgba(255, 255, 255, 0.5),
+                transparent);
+            animation: wave 2s linear infinite;
+        }
+        
+        @keyframes wave {
+            0% { transform: translateX(-100%); }
+            100% { transform: translateX(100%); }
+        }
+        
+        .alert-badge {
+            position: absolute;
+            top: -8px;
+            right: -8px;
+            width: 24px;
+            height: 24px;
+            border-radius: 50%;
+            background: var(--error);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            color: white;
+            font-size: 12px;
+            font-weight: bold;
+            animation: pulse 1.5s infinite;
+        }
+        
+        @keyframes pulse {
+            0% { box-shadow: 0 0 0 0 rgba(234, 67, 53, 0.7); }
+            70% { box-shadow: 0 0 0 8px rgba(234, 67, 53, 0); }
+            100% { box-shadow: 0 0 0 0 rgba(234, 67, 53, 0); }
+        }
+        
+        /* 训练结果展示 */
+        .training-results {
+            margin-top: 25px;
+        }
+        
+        .result-item {
+            display: flex;
+            align-items: center;
+            padding: 15px 0;
+            border-bottom: 1px solid var(--border);
+            transition: all 0.2s ease;
+        }
+        
+        .result-item:hover {
+            background: rgba(66, 133, 244, 0.03);
+            border-radius: 12px;
+            padding: 15px;
+        }
+        
+        .result-item:last-child {
+            border-bottom: none;
+        }
+        
+        .result-icon {
+            width: 40px;
+            height: 40px;
+            border-radius: 12px;
+            background: var(--primary-light);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            color: var(--primary);
+            margin-right: 15px;
+            font-size: 18px;
+        }
+        
+        .result-content {
+            flex: 1;
+        }
+        
+        .result-title {
+            font-weight: 600;
+            color: var(--text-dark);
+            margin-bottom: 4px;
+        }
+        
+        .result-meta {
+            display: flex;
+            font-size: 13px;
+            color: var(--text-light);
+            flex-wrap: wrap;
+            gap: 10px;
+        }
+        
+        .result-date {
+            display: flex;
+            align-items: center;
+            gap: 5px;
+        }
+        
+        .result-status {
+            padding: 4px 10px;
+            border-radius: 20px;
+            font-size: 12px;
+            font-weight: 600;
+        }
+        
+        .status-completed {
+            background: rgba(52, 168, 83, 0.1);
+            color: var(--success);
+        }
+        
+        .status-training {
+            background: rgba(251, 188, 5, 0.1);
+            color: var(--warning);
+        }
+        
+        .status-error {
+            background: rgba(234, 67, 53, 0.1);
+            color: var(--error);
+        }
+        
+        /* 数据记录部分 */
+        .data-record {
+            margin-top: 25px;
+        }
+        
+        .record-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 15px;
+        }
+        
+        .view-all {
+            color: var(--primary);
+            font-size: 14px;
+            text-decoration: none;
+            cursor: pointer;
+            display: flex;
+            align-items: center;
+            gap: 5px;
+        }
+        
+        .record-list {
+            display: grid;
+            grid-template-columns: repeat(2, 1fr);
+            gap: 15px;
+        }
+        
+        .record-item {
+            background: var(--card-bg);
+            border-radius: 16px;
+            padding: 15px;
+            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.03);
+            border: 1px solid rgba(66, 133, 244, 0.08);
+            transition: all 0.3s ease;
+        }
+        
+        .record-item:hover {
+            transform: translateY(-3px);
+            box-shadow: 0 6px 15px rgba(66, 133, 244, 0.15);
+        }
+        
+        .record-title {
+            font-size: 14px;
+            font-weight: 600;
+            color: var(--text-dark);
+            margin-bottom: 10px;
+            display: flex;
+            align-items: center;
+            gap: 5px;
+        }
+        
+        .record-value {
+            font-size: 22px;
+            font-weight: 700;
+            color: var(--primary);
+        }
+        
+        .record-trend {
+            display: flex;
+            align-items: center;
+            font-size: 12px;
+            margin-top: 5px;
+        }
+        
+        .trend-up {
+            color: var(--success);
+        }
+        
+        .trend-down {
+            color: var(--error);
+        }
+        
+        .trend-icon {
+            margin-right: 4px;
+        }
+        
+        /* 历史数据记录 */
+        .history-list {
+            max-height: 200px;
+            overflow-y: auto;
+            padding-right: 8px;
+        }
+        
+        .history-item {
+            display: flex;
+            align-items: center;
+            padding: 12px 0;
+            border-bottom: 1px solid var(--border);
+            transition: all 0.2s ease;
+        }
+        
+        .history-item:hover {
+            background: rgba(66, 133, 244, 0.03);
+            border-radius: 12px;
+            padding: 12px;
+        }
+        
+        .history-icon {
+            width: 36px;
+            height: 36px;
+            border-radius: 10px;
+            background: var(--primary-light);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            color: var(--primary);
+            margin-right: 12px;
+            font-size: 16px;
+        }
+        
+        .history-content {
+            flex: 1;
+        }
+        
+        .history-name {
+            font-weight: 500;
+            margin-bottom: 4px;
+        }
+        
+        .history-meta {
+            display: flex;
+            font-size: 12px;
+            color: var(--text-light);
+            gap: 15px;
+        }
+        
+        .history-size {
+            display: flex;
+            align-items: center;
+            gap: 3px;
+        }
+        
+        .history-date {
+            color: var(--text-medium);
+            display: flex;
+            align-items: center;
+            gap: 3px;
+        }
+        
+        /* 页面标题装饰 */
+        .page-header {
+            text-align: center;
+            margin-bottom: 25px;
+        }
+        
+        .page-title {
+            font-size: 28px;
+            font-weight: 800;
+            color: var(--text-dark);
+            margin-bottom: 8px;
+            background: linear-gradient(90deg, #3367d6, #4285f4);
+            -webkit-background-clip: text;
+            -webkit-text-fill-color: transparent;
+            position: relative;
+            display: inline-block;
+        }
+        
+        .page-subtitle {
+            color: var(--text-light);
+            font-size: 16px;
+            max-width: 300px;
+            margin: 0 auto;
+        }
+        
+        /* 装饰元素 */
+        .decor-circle {
+            position: absolute;
+            width: 200px;
+            height: 200px;
+            border-radius: 50%;
+            background: linear-gradient(135deg, rgba(66, 133, 244, 0.1) 0%, rgba(66, 133, 244, 0.05) 100%);
+            z-index: -1;
+        }
+        
+        .circle-1 {
+            top: 10%;
+            left: -50px;
+        }
+        
+        .circle-2 {
+            bottom: 10%;
+            right: -50px;
+        }
+        
+        /* 新增搜索框样式 */
+        .search-container {
+            margin-bottom: 20px;
+            position: relative;
+        }
+        
+        .search-box {
+            display: flex;
+            align-items: center;
+            background: var(--card-bg);
+            border-radius: 30px;
+            padding: 8px 16px;
+            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+            border: 1px solid var(--border);
+        }
+        
+        .search-box i {
+            color: var(--text-light);
+            margin-right: 10px;
+            font-size: 18px;
+        }
+        
+        .search-input {
+            flex: 1;
+            border: none;
+            background: transparent;
+            padding: 10px 0;
+            font-size: 15px;
+            color: var(--text-dark);
+            outline: none;
+        }
+        
+        .search-input::placeholder {
+            color: var(--text-light);
+        }
+        
+        /* 上传控制台新样式 */
+        .upload-method-selector {
+            margin: 25px 0;
+        }
+        
+        .method-title {
+            font-size: 16px;
+            font-weight: 600;
+            margin-bottom: 12px;
+            color: var(--text-dark);
+        }
+        
+        .method-options {
+            display: flex;
+            gap: 15px;
+            flex-wrap: wrap;
+        }
+        
+        .method-option {
+            flex: 1;
+            min-width: 100px;
+            padding: 15px;
+            background: var(--card-bg);
+            border-radius: 16px;
+            text-align: center;
+            cursor: pointer;
+            transition: all 0.3s ease;
+            border: 1px solid var(--border);
+        }
+        
+        .method-option:hover {
+            transform: translateY(-3px);
+            box-shadow: 0 6px 15px rgba(66, 133, 244, 0.1);
+        }
+        
+        .method-option.active {
+            border-color: var(--primary);
+            background: var(--primary-light);
+            color: var(--primary);
+            font-weight: 600;
+        }
+        
+        .method-icon {
+            font-size: 24px;
+            margin-bottom: 10px;
+            color: var(--primary);
+        }
+        
+        .upload-action {
+            display: flex;
+            justify-content: center;
+            margin-top: 15px;
+        }
+        
+        .upload-button {
+            background: var(--primary);
+            color: white;
+            border: none;
+            border-radius: 30px;
+            padding: 15px 40px;
+            font-size: 16px;
+            font-weight: 600;
+            cursor: pointer;
+            transition: all 0.3s ease;
+            display: flex;
+            align-items: center;
+            gap: 10px;
+            box-shadow: 0 6px 15px rgba(66, 133, 244, 0.3);
+        }
+        
+        .upload-button:hover {
+            background: var(--primary-dark);
+            transform: translateY(-2px);
+            box-shadow: 0 8px 20px rgba(66, 133, 244, 0.4);
+        }
+        
+        .upload-button:active {
+            transform: translateY(0);
+        }
+        
+        /* 上传状态指示器 */
+        .upload-status {
+            margin-top: 20px;
+            padding: 15px;
+            border-radius: 16px;
+            background: rgba(52, 168, 83, 0.1);
+            color: var(--success);
+            text-align: center;
+            display: none;
+        }
+        
+        .upload-status.error {
+            background: rgba(234, 67, 53, 0.1);
+            color: var(--error);
+        }
+        
+        .upload-progress {
+            height: 6px;
+            background: var(--border);
+            border-radius: 3px;
+            margin-top: 10px;
+            overflow: hidden;
+        }
+        
+        .progress-bar {
+            height: 100%;
+            width: 0%;
+            background: linear-gradient(90deg, var(--primary), var(--primary-dark));
+            border-radius: 3px;
+            transition: width 0.3s ease;
+        }
+    </style>
+</head>
+<body>
+    <div class="decor-circle circle-1"></div>
+    <div class="decor-circle circle-2"></div>
+    
+    <!-- 顶部导航 -->
+    <div class="header">
+        <button class="back-btn">
+            <i class="fas fa-arrow-left"></i>
+        </button>
+        <h1 class="title">数据训练中心</h1>
+    </div>
+    
+    <div class="page-header">
+        <h1 class="page-title">AI数据训练中心</h1>
+        <p class="page-subtitle">上传数据、训练模型、优化结果</p>
+    </div>
+    
+    <!-- 上传控制台 -->
+    <div class="card upload-console">
+        <div class="card-header">
+            <div>
+                <div class="card-title">上传控制台</div>
+                <div class="card-subtitle">选择数据类型和输入方式</div>
+            </div>
+        </div>
+        
+        <div class="source-tags" id="sourceTags">
+            <div class="source-tag active">会议记录</div>
+            <div class="source-tag">客户合同</div>
+            <div class="source-tag">反馈表</div>
+            <div class="source-tag">培训资料</div>
+        </div>
+        
+        <div class="custom-tag-form">
+            <input type="text" class="custom-tag-input" id="customTagInput" placeholder="输入新数据类型...">
+            <button class="add-tag-btn" id="addTagBtn">
+                添加标签
+            </button>
+        </div>
+        
+        <div class="upload-method-selector">
+            <div class="method-title">选择输入方式</div>
+            <div class="method-options" id="methodOptions">
+                <div class="method-option" data-method="camera">
+                    <div class="method-icon">
+                        <i class="fas fa-camera"></i>
+                    </div>
+                    <div>拍照</div>
+                </div>
+                <div class="method-option" data-method="file">
+                    <div class="method-icon">
+                        <i class="fas fa-file"></i>
+                    </div>
+                    <div>文件</div>
+                </div>
+                <div class="method-option" data-method="mic">
+                    <div class="method-icon">
+                        <i class="fas fa-microphone"></i>
+                    </div>
+                    <div>录音</div>
+                </div>
+                <div class="method-option" data-method="text">
+                    <div class="method-icon">
+                        <i class="fas fa-keyboard"></i>
+                    </div>
+                    <div>文本</div>
+                </div>
+            </div>
+        </div>
+        
+        <div class="upload-action">
+            <button class="upload-button" id="uploadButton">
+                <i class="fas fa-cloud-upload-alt"></i> 上传数据
+            </button>
+        </div>
+        
+        <div class="upload-status" id="uploadStatus">
+            <div>数据上传中...</div>
+            <div class="upload-progress">
+                <div class="progress-bar" id="progressBar"></div>
+            </div>
+        </div>
+    </div>
+    
+    <!-- 数据看板 -->
+    <div class="card">
+        <div class="card-header">
+            <div>
+                <div class="card-title">数据看板</div>
+                <div class="card-subtitle">今日处理状态</div>
+            </div>
+            <div class="alert-badge">3</div>
+        </div>
+        
+        <div class="stats-container">
+            <div class="stat-item">
+                <div class="progress-ring">
+                    <div class="progress-bg">
+                        <div class="progress-inner">128</div>
+                    </div>
+                </div>
+                <div class="stat-label">处理量</div>
+            </div>
+            
+            <div class="stat-item">
+                <div class="stat-value">85%</div>
+                <div class="stat-label">质量评分</div>
+                <div class="quality-bar">
+                    <div class="quality-fill"></div>
+                </div>
+            </div>
+        </div>
+        
+        <!-- 每日数据记录 -->
+        <div class="data-record">
+            <div class="record-header">
+                <div class="card-title">每日数据记录</div>
+                <a class="view-all">
+                    查看全部 <i class="fas fa-arrow-right"></i>
+                </a>
+            </div>
+            
+            <div class="record-list">
+                <div class="record-item">
+                    <div class="record-title"><i class="fas fa-file-medical"></i> 新增数据</div>
+                    <div class="record-value">42</div>
+                    <div class="record-trend trend-up">
+                        <i class="fas fa-arrow-up trend-icon"></i> 12%
+                    </div>
+                </div>
+                
+                <div class="record-item">
+                    <div class="record-title"><i class="fas fa-cogs"></i> 处理中</div>
+                    <div class="record-value">18</div>
+                    <div class="record-trend trend-down">
+                        <i class="fas fa-arrow-down trend-icon"></i> 5%
+                    </div>
+                </div>
+                
+                <div class="record-item">
+                    <div class="record-title"><i class="fas fa-clock"></i> 训练时间</div>
+                    <div class="record-value">1.8h</div>
+                    <div class="record-trend trend-up">
+                        <i class="fas fa-arrow-up trend-icon"></i> 23%
+                    </div>
+                </div>
+                
+                <div class="record-item">
+                    <div class="record-title"><i class="fas fa-check-circle"></i> 完成率</div>
+                    <div class="record-value">76%</div>
+                    <div class="record-trend trend-up">
+                        <i class="fas fa-arrow-up trend-icon"></i> 8%
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    
+    <!-- 历史数据上传记录 -->
+    <div class="card">
+        <div class="card-header">
+            <div>
+                <div class="card-title">历史数据上传记录</div>
+                <div class="card-subtitle">最近上传的文件</div>
+            </div>
+        </div>
+        
+        <!-- 搜索区域 -->
+        <div class="search-container">
+            <div class="search-box">
+                <i class="fas fa-search"></i>
+                <input type="text" class="search-input" id="searchInput" placeholder="搜索文件名、类型或日期...">
+            </div>
+        </div>
+        
+        <div class="history-list" id="historyList">
+            <div class="history-item">
+                <div class="history-icon">
+                    <i class="fas fa-file-pdf"></i>
+                </div>
+                <div class="history-content">
+                    <div class="history-name">Q3销售报告.pdf</div>
+                    <div class="history-meta">
+                        <div class="history-size">
+                            <i class="fas fa-database"></i> 4.2MB
+                        </div>
+                        <div class="history-date">
+                            <i class="far fa-calendar"></i> 2023-10-15
+                        </div>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="history-item">
+                <div class="history-icon">
+                    <i class="fas fa-file-excel"></i>
+                </div>
+                <div class="history-content">
+                    <div class="history-name">客户数据.xlsx</div>
+                    <div class="history-meta">
+                        <div class="history-size">
+                            <i class="fas fa-database"></i> 3.1MB
+                        </div>
+                        <div class="history-date">
+                            <i class="far fa-calendar"></i> 2023-10-14
+                        </div>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="history-item">
+                <div class="history-icon">
+                    <i class="fas fa-file-word"></i>
+                </div>
+                <div class="history-content">
+                    <div class="history-name">会议纪要.docx</div>
+                    <div class="history-meta">
+                        <div class="history-size">
+                            <i class="fas fa-database"></i> 1.7MB
+                        </div>
+                        <div class="history-date">
+                            <i class="far fa-calendar"></i> 2023-10-13
+                        </div>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="history-item">
+                <div class="history-icon">
+                    <i class="fas fa-file-csv"></i>
+                </div>
+                <div class="history-content">
+                    <div class="history-name">用户反馈.csv</div>
+                    <div class="history-meta">
+                        <div class="history-size">
+                            <i class="fas fa-database"></i> 2.3MB
+                        </div>
+                        <div class="history-date">
+                            <i class="far fa-calendar"></i> 2023-10-12
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    
+    <!-- 训练结果展示 -->
+    <div class="card">
+        <div class="card-header">
+            <div>
+                <div class="card-title">训练结果展示</div>
+                <div class="card-subtitle">模型训练状态与结果</div>
+            </div>
+        </div>
+        
+        <div class="training-results">
+            <div class="result-item">
+                <div class="result-icon">
+                    <i class="fas fa-brain"></i>
+                </div>
+                <div class="result-content">
+                    <div class="result-title">销售预测模型</div>
+                    <div class="result-meta">
+                        <div class="result-date">
+                            <i class="far fa-clock"></i> 训练时间: 2.3小时
+                        </div>
+                        <div class="result-status status-completed">已完成</div>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="result-item">
+                <div class="result-icon">
+                    <i class="fas fa-comments"></i>
+                </div>
+                <div class="result-content">
+                    <div class="result-title">情感分析模型</div>
+                    <div class="result-meta">
+                        <div class="result-date">
+                            <i class="far fa-clock"></i> 训练时间: 1.5小时
+                        </div>
+                        <div class="result-status status-training">训练中</div>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="result-item">
+                <div class="result-icon">
+                    <i class="fas fa-chart-line"></i>
+                </div>
+                <div class="result-content">
+                    <div class="result-title">趋势预测模型</div>
+                    <div class="result-meta">
+                        <div class="result-date">
+                            <i class="far fa-clock"></i> 训练时间: 3.1小时
+                        </div>
+                        <div class="result-status status-completed">已完成</div>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="result-item">
+                <div class="result-icon">
+                    <i class="fas fa-robot"></i>
+                </div>
+                <div class="result-content">
+                    <div class="result-title">客户服务模型</div>
+                    <div class="result-meta">
+                        <div class="result-date">
+                            <i class="far fa-clock"></i> 训练时间: 4.2小时
+                        </div>
+                        <div class="result-status status-error">失败</div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <script>
+        // 标签选择交互
+        const tags = document.querySelectorAll('.source-tag');
+        tags.forEach(tag => {
+            tag.addEventListener('click', function() {
+                tags.forEach(t => t.classList.remove('active'));
+                this.classList.add('active');
+            });
+        });
+        
+        // 添加自定义标签
+        const addTagBtn = document.getElementById('addTagBtn');
+        const customTagInput = document.getElementById('customTagInput');
+        const sourceTags = document.getElementById('sourceTags');
+        
+        addTagBtn.addEventListener('click', function() {
+            const tagText = customTagInput.value.trim();
+            if (tagText) {
+                const newTag = document.createElement('div');
+                newTag.className = 'source-tag';
+                newTag.textContent = tagText;
+                
+                // 添加点击事件
+                newTag.addEventListener('click', function() {
+                    tags.forEach(t => t.classList.remove('active'));
+                    this.classList.add('active');
+                });
+                
+                sourceTags.appendChild(newTag);
+                customTagInput.value = '';
+                
+                // 添加动画效果
+                newTag.style.opacity = '0';
+                newTag.style.transform = 'scale(0.8)';
+                setTimeout(() => {
+                    newTag.style.transition = 'all 0.3s ease';
+                    newTag.style.opacity = '1';
+                    newTag.style.transform = 'scale(1)';
+                }, 10);
+            }
+        });
+        
+        // 按Enter键添加标签
+        customTagInput.addEventListener('keypress', function(e) {
+            if (e.key === 'Enter') {
+                addTagBtn.click();
+            }
+        });
+        
+        // 输入方式选择
+        const methodOptions = document.querySelectorAll('.method-option');
+        methodOptions.forEach(option => {
+            option.addEventListener('click', function() {
+                methodOptions.forEach(opt => opt.classList.remove('active'));
+                this.classList.add('active');
+            });
+        });
+        
+        // 上传按钮功能
+        const uploadButton = document.getElementById('uploadButton');
+        const uploadStatus = document.getElementById('uploadStatus');
+        const progressBar = document.getElementById('progressBar');
+        
+        uploadButton.addEventListener('click', function() {
+            // 获取选中的标签
+            const selectedTag = document.querySelector('.source-tag.active').textContent;
+            
+            // 获取选中的输入方式
+            const selectedMethod = document.querySelector('.method-option.active');
+            const methodName = selectedMethod ? selectedMethod.querySelector('div:last-child').textContent : '未选择';
+            
+            // 显示上传状态
+            uploadStatus.style.display = 'block';
+            uploadStatus.innerHTML = `<div>正在上传: ${selectedTag} (方式: ${methodName})</div>
+                                       <div class="upload-progress">
+                                         <div class="progress-bar" id="progressBar"></div>
+                                       </div>`;
+            
+            // 模拟上传进度
+            let progress = 0;
+            const interval = setInterval(() => {
+                progress += Math.floor(Math.random() * 10);
+                if (progress >= 100) {
+                    progress = 100;
+                    clearInterval(interval);
+                    
+                    // 上传完成
+                    setTimeout(() => {
+                        uploadStatus.innerHTML = `<div><i class="fas fa-check-circle"></i> 上传成功: ${selectedTag} (方式: ${methodName})</div>`;
+                        
+                        // 添加新项目到历史记录
+                        const historyList = document.getElementById('historyList');
+                        const newItem = document.createElement('div');
+                        newItem.className = 'history-item';
+                        newItem.innerHTML = `
+                            <div class="history-icon">
+                                <i class="fas fa-file-alt"></i>
+                            </div>
+                            <div class="history-content">
+                                <div class="history-name">${selectedTag}.${getFileExtension(methodName)}</div>
+                                <div class="history-meta">
+                                    <div class="history-size">
+                                        <i class="fas fa-database"></i> ${(Math.random() * 5).toFixed(1)}MB
+                                    </div>
+                                    <div class="history-date">
+                                        <i class="far fa-calendar"></i> ${getCurrentDate()}
+                                    </div>
+                                </div>
+                            </div>
+                        `;
+                        historyList.insertBefore(newItem, historyList.firstChild);
+                        
+                        // 3秒后隐藏状态
+                        setTimeout(() => {
+                            uploadStatus.style.display = 'none';
+                        }, 3000);
+                    }, 500);
+                }
+                
+                // 更新进度条
+                progressBar.style.width = `${progress}%`;
+            }, 200);
+        });
+        
+        // 获取文件扩展名
+        function getFileExtension(method) {
+            switch(method) {
+                case '拍照': return 'jpg';
+                case '文件': return 'pdf';
+                case '录音': return 'mp3';
+                case '文本': return 'txt';
+                default: return 'dat';
+            }
+        }
+        
+        // 获取当前日期
+        function getCurrentDate() {
+            const now = new Date();
+            const year = now.getFullYear();
+            const month = String(now.getMonth() + 1).padStart(2, '0');
+            const day = String(now.getDate()).padStart(2, '0');
+            return `${year}-${month}-${day}`;
+        }
+        
+        // 历史记录搜索功能
+        const searchInput = document.getElementById('searchInput');
+        const historyItems = document.querySelectorAll('.history-item');
+        
+        searchInput.addEventListener('input', function() {
+            const searchTerm = this.value.toLowerCase();
+            
+            historyItems.forEach(item => {
+                const fileName = item.querySelector('.history-name').textContent.toLowerCase();
+                if (fileName.includes(searchTerm)) {
+                    item.style.display = 'flex';
+                } else {
+                    item.style.display = 'none';
+                }
+            });
+        });
+        
+        // 模拟每日数据更新
+        setInterval(() => {
+            const valueElements = document.querySelectorAll('.record-value');
+            valueElements.forEach(el => {
+                const currentValue = parseInt(el.textContent) || 0;
+                const change = Math.floor(Math.random() * 5) - 2; // -2 到 2 之间的随机数
+                const newValue = Math.max(0, currentValue + change);
+                el.textContent = newValue;
+            });
+        }, 5000);
+    </script>
+</body>
+</html>

+ 1077 - 0
ai-assisant/demo/assistant.html

@@ -0,0 +1,1077 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>话术决策助手 - AI实验室</title>
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
+    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
+    <style>
+        :root {
+            --primary: #64a0ff;
+            --primary-light: rgba(100, 160, 255, 0.1);
+            --dark: #0a192f;
+            --dark-light: #112240;
+            --gray: #8892b0;
+            --light-gray: #f8f9fa;
+            --white: #ffffff;
+            --blue: #64a0ff;
+            --blue-light: rgba(100, 160, 255, 0.15);
+            --yellow: #ffd43b;
+            --orange: #ff922b;
+            --purple: #9c36b5;
+            --shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
+            --shadow-primary: 0 4px 20px rgba(100, 160, 255, 0.2);
+        }
+        
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+            font-family: 'Segoe UI', 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;
+        }
+        
+        body {
+            background-color: #f0f5ff;
+            color: var(--dark);
+            line-height: 1.6;
+            overflow-x: hidden;
+            background: linear-gradient(135deg, #e6f0ff 0%, #f5f9ff 100%);
+            min-height: 100vh;
+            padding: 20px 0;
+        }
+        
+        .container {
+            max-width: 480px;
+            margin: 0 auto;
+            padding: 0 16px 30px;
+            position: relative;
+        }
+        
+        /* 顶部导航 */
+        .app-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 15px 0;
+            margin-bottom: 15px;
+            border-bottom: 1px solid rgba(10, 25, 47, 0.05);
+        }
+        
+        .header-title {
+            font-size: 22px;
+            font-weight: 700;
+            color: var(--dark);
+            display: flex;
+            align-items: center;
+            gap: 10px;
+        }
+        
+        .header-title i {
+            color: var(--primary);
+            background: var(--primary-light);
+            width: 36px;
+            height: 36px;
+            border-radius: 10px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+        
+        /* 场景选择 */
+        .scene-selector {
+            background: var(--white);
+            border-radius: 20px;
+            padding: 20px;
+            margin-bottom: 20px;
+            box-shadow: var(--shadow);
+            position: relative;
+            overflow: hidden;
+            border: 1px solid rgba(100, 160, 255, 0.2);
+        }
+        
+        .scene-options {
+            display: flex;
+            gap: 15px;
+            margin-top: 10px;
+        }
+        
+        .scene-option {
+            flex: 1;
+            padding: 15px;
+            border-radius: 15px;
+            background: var(--light-gray);
+            text-align: center;
+            cursor: pointer;
+            transition: all 0.3s ease;
+            border: 1px solid rgba(100, 160, 255, 0.1);
+        }
+        
+        .scene-option.active {
+            background: var(--primary-light);
+            border-color: var(--primary);
+            box-shadow: var(--shadow-primary);
+        }
+        
+        .scene-option i {
+            font-size: 28px;
+            margin-bottom: 10px;
+            color: var(--primary);
+        }
+        
+        .scene-option h3 {
+            font-size: 16px;
+            margin-bottom: 5px;
+        }
+        
+        .scene-option p {
+            font-size: 13px;
+            color: var(--gray);
+        }
+        
+        /* 对话聊天区 */
+        .chat-area {
+            background: var(--white);
+            border-radius: 20px;
+            padding: 20px;
+            margin-bottom: 20px;
+            box-shadow: var(--shadow);
+            height: 350px;
+            overflow-y: auto;
+            display: flex;
+            flex-direction: column;
+            gap: 15px;
+            border: 1px solid rgba(100, 160, 255, 0.2);
+        }
+        
+        .chat-title {
+            font-size: 18px;
+            font-weight: 600;
+            margin-bottom: 15px;
+            color: var(--dark);
+            display: flex;
+            align-items: center;
+            gap: 10px;
+            padding-bottom: 10px;
+            border-bottom: 1px solid rgba(100, 160, 255, 0.1);
+        }
+        
+        .chat-title i {
+            color: var(--primary);
+        }
+        
+        .chat-message {
+            max-width: 85%;
+            padding: 14px 18px;
+            border-radius: 18px;
+            position: relative;
+            animation: fadeIn 0.3s ease;
+            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+        }
+        
+        @keyframes fadeIn {
+            from { opacity: 0; transform: translateY(10px); }
+            to { opacity: 1; transform: translateY(0); }
+        }
+        
+        .customer-message {
+            background: linear-gradient(135deg, #e6f0ff, #ebf2ff);
+            align-self: flex-start;
+            border-bottom-left-radius: 5px;
+            border-left: 3px solid var(--blue);
+        }
+        
+        .assistant-message {
+            background: linear-gradient(135deg, #e6f7ff, #ebf9ff);
+            border: 1px solid rgba(100, 160, 255, 0.3);
+            align-self: flex-end;
+            border-bottom-right-radius: 5px;
+            border-right: 3px solid var(--primary);
+        }
+        
+        .message-header {
+            display: flex;
+            align-items: center;
+            gap: 8px;
+            margin-bottom: 8px;
+            font-weight: 600;
+        }
+        
+        .customer-header .icon {
+            background: var(--blue-light);
+            color: var(--blue);
+        }
+        
+        .assistant-header .icon {
+            background: var(--primary-light);
+            color: var(--primary);
+        }
+        
+        .message-header .icon {
+            width: 28px;
+            height: 28px;
+            border-radius: 8px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 14px;
+        }
+        
+        .message-content {
+            line-height: 1.5;
+        }
+        
+        .message-time {
+            font-size: 11px;
+            color: var(--gray);
+            margin-top: 8px;
+            text-align: right;
+        }
+        
+        /* 客户标签编辑区 */
+        .tags-area {
+            background: var(--light-gray);
+            border-radius: 15px;
+            padding: 15px;
+            margin-top: 10px;
+            border: 1px solid rgba(100, 160, 255, 0.1);
+        }
+        
+        .tags-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 10px;
+        }
+        
+        .tags-title {
+            font-size: 14px;
+            font-weight: 600;
+            color: var(--dark);
+        }
+        
+        .input-tags {
+            display: flex;
+            gap: 8px;
+            flex-wrap: wrap;
+        }
+        
+        .tag {
+            background: var(--primary-light);
+            color: var(--primary);
+            padding: 6px 12px 6px 8px;
+            border-radius: 20px;
+            font-size: 13px;
+            display: flex;
+            align-items: center;
+            gap: 5px;
+            cursor: pointer;
+            transition: all 0.2s ease;
+            border: 1px solid rgba(100, 160, 255, 0.2);
+        }
+        
+        .tag:hover {
+            background: rgba(100, 160, 255, 0.3);
+        }
+        
+        .tag .delete {
+            font-size: 12px;
+            margin-left: 5px;
+            opacity: 0.7;
+        }
+        
+        .tag .delete:hover {
+            opacity: 1;
+        }
+        
+        .add-tag {
+            background: rgba(136, 146, 176, 0.1);
+            color: var(--gray);
+            padding: 6px 12px;
+            border-radius: 20px;
+            font-size: 13px;
+            display: flex;
+            align-items: center;
+            gap: 5px;
+            cursor: pointer;
+            transition: all 0.2s ease;
+        }
+        
+        .add-tag:hover {
+            background: rgba(136, 146, 176, 0.2);
+        }
+        
+        /* 输入工作区 */
+        .input-area {
+            background: var(--white);
+            border-radius: 20px;
+            padding: 20px;
+            margin-bottom: 20px;
+            box-shadow: var(--shadow);
+            border: 1px solid rgba(100, 160, 255, 0.2);
+        }
+        
+        .input-title {
+            font-size: 18px;
+            font-weight: 600;
+            margin-bottom: 15px;
+            color: var(--dark);
+            display: flex;
+            align-items: center;
+            gap: 10px;
+            padding-bottom: 10px;
+            border-bottom: 1px solid rgba(100, 160, 255, 0.1);
+        }
+        
+        .input-title i {
+            color: var(--primary);
+        }
+        
+        .role-selector {
+            display: flex;
+            background: var(--light-gray);
+            border-radius: 12px;
+            padding: 4px;
+            margin-bottom: 15px;
+        }
+        
+        .role-btn {
+            flex: 1;
+            padding: 10px;
+            text-align: center;
+            border-radius: 10px;
+            cursor: pointer;
+            transition: all 0.3s ease;
+            font-weight: 500;
+        }
+        
+        .role-btn.active {
+            background: var(--white);
+            box-shadow: var(--shadow);
+            color: var(--primary);
+        }
+        
+        .input-field {
+            position: relative;
+        }
+        
+        .text-input {
+            width: 100%;
+            height: 120px;
+            padding: 15px;
+            border-radius: 15px;
+            border: 1px solid rgba(136, 146, 176, 0.2);
+            background: var(--light-gray);
+            resize: none;
+            font-size: 16px;
+            color: var(--dark);
+            transition: all 0.3s ease;
+        }
+        
+        .text-input:focus {
+            outline: none;
+            border-color: var(--primary);
+            box-shadow: 0 0 0 2px rgba(100, 160, 255, 0.2);
+        }
+        
+        /* 策略卡片组 */
+        .strategy-area {
+            margin-bottom: 25px;
+        }
+        
+        .strategy-title {
+            font-size: 18px;
+            font-weight: 600;
+            margin-bottom: 15px;
+            color: var(--dark);
+            display: flex;
+            align-items: center;
+            gap: 10px;
+            padding-bottom: 10px;
+            border-bottom: 1px solid rgba(100, 160, 255, 0.1);
+        }
+        
+        .strategy-title i {
+            color: var(--primary);
+        }
+        
+        .cards-container {
+            position: relative;
+            height: 320px;
+            perspective: 1000px;
+        }
+        
+        .strategy-card {
+            position: absolute;
+            width: 100%;
+            height: 280px;
+            border-radius: 20px;
+            padding: 25px;
+            box-shadow: var(--shadow);
+            display: flex;
+            flex-direction: column;
+            transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1), 
+                        opacity 0.4s ease, 
+                        box-shadow 0.3s ease;
+            backface-visibility: hidden;
+            cursor: pointer;
+            border: 1px solid rgba(100, 160, 255, 0.2);
+        }
+        
+        .card-aggressive {
+            background: linear-gradient(135deg, #eef6ff, #f0f8ff);
+            border-top: 4px solid var(--blue);
+            z-index: 30;
+        }
+        
+        .card-neutral {
+            background: linear-gradient(135deg, #fff9e6, #fffbf0);
+            border-top: 4px solid var(--yellow);
+            transform: translateY(20px) scale(0.95);
+            z-index: 20;
+        }
+        
+        .card-conservative {
+            background: linear-gradient(135deg, #f9f0ff, #fdf5ff);
+            border-top: 4px solid var(--purple);
+            transform: translateY(40px) scale(0.9);
+            z-index: 10;
+        }
+        
+        .card-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 20px;
+        }
+        
+        .card-title {
+            font-size: 18px;
+            font-weight: 700;
+        }
+        
+        .card-icon {
+            width: 40px;
+            height: 40px;
+            border-radius: 12px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 18px;
+        }
+        
+        .card-content {
+            flex: 1;
+            overflow-y: auto;
+            padding-right: 10px;
+        }
+        
+        .card-content p {
+            margin-bottom: 15px;
+            line-height: 1.7;
+            color: #333;
+        }
+        
+        .card-highlight {
+            background: rgba(10, 25, 47, 0.05);
+            padding: 12px 15px;
+            border-radius: 12px;
+            border-left: 3px solid var(--primary);
+            margin: 15px 0;
+            font-weight: 500;
+            line-height: 1.6;
+        }
+        
+        .card-footer {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-top: 15px;
+            padding-top: 15px;
+            border-top: 1px solid rgba(136, 146, 176, 0.1);
+        }
+        
+        .card-hint {
+            font-size: 14px;
+            color: var(--gray);
+        }
+        
+        /* 卡片导航点 */
+        .card-navigation {
+            display: flex;
+            justify-content: center;
+            gap: 10px;
+            margin-top: 15px;
+        }
+        
+        .card-nav-btn {
+            width: 12px;
+            height: 12px;
+            border-radius: 50%;
+            background: var(--light-gray);
+            cursor: pointer;
+            transition: all 0.2s ease;
+        }
+        
+        .card-nav-btn.active {
+            background: var(--primary);
+            transform: scale(1.2);
+        }
+        
+        /* 操作按钮 */
+        .action-buttons {
+            display: flex;
+            gap: 15px;
+            margin-top: 25px;
+        }
+        
+        .action-btn {
+            flex: 1;
+            height: 50px;
+            border-radius: 15px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            gap: 10px;
+            font-weight: 600;
+            cursor: pointer;
+            transition: all 0.3s ease;
+        }
+        
+        .save-btn {
+            background: var(--primary);
+            color: var(--dark);
+            border: none;
+            box-shadow: 0 4px 15px rgba(100, 160, 255, 0.3);
+        }
+        
+        .save-btn:hover {
+            transform: translateY(-2px);
+            box-shadow: 0 6px 20px rgba(100, 160, 255, 0.4);
+        }
+        
+        .history-btn {
+            background: var(--white);
+            color: var(--dark);
+            border: 2px solid var(--primary);
+            box-shadow: 0 4px 15px rgba(100, 160, 255, 0.1);
+        }
+        
+        .history-btn:hover {
+            transform: translateY(-2px);
+            box-shadow: 0 6px 20px rgba(100, 160, 255, 0.2);
+        }
+        
+        /* 响应式调整 */
+        @media (max-width: 380px) {
+            .container {
+                padding: 0 12px 25px;
+            }
+            
+            .scene-options {
+                flex-direction: column;
+            }
+            
+            .cards-container {
+                height: 300px;
+            }
+            
+            .strategy-card {
+                height: 260px;
+                padding: 20px;
+            }
+            
+            .chat-area {
+                height: 320px;
+            }
+        }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <!-- 顶部导航 -->
+        <header class="app-header">
+            <div class="header-title">
+                <i class="fas fa-robot"></i>
+                <h1>话术决策助手</h1>
+            </div>
+        </header>
+        
+        <!-- 场景选择 -->
+        <section class="scene-selector">
+            <h2 class="input-title">
+                <i class="fas fa-dharmachakra"></i>
+                选择对话场景
+            </h2>
+            <div class="scene-options">
+                <div class="scene-option active" data-scene="first-contact">
+                    <i class="fas fa-handshake"></i>
+                    <h3>首次接触</h3>
+                    <p>初次沟通建立信任</p>
+                </div>
+                <div class="scene-option" data-scene="deep-talk">
+                    <i class="fas fa-comments"></i>
+                    <h3>深度交流</h3>
+                    <p>深入挖掘客户需求</p>
+                </div>
+            </div>
+        </section>
+        
+        <!-- 客户对话分析 -->
+        <section class="input-area">
+            <h2 class="chat-title">
+                <i class="fas fa-comments"></i>
+                客户对话分析
+            </h2>
+            <div class="chat-area" id="chatContainer">
+                <div class="chat-message customer-message">
+                    <div class="message-header customer-header">
+                        <div class="icon"><i class="fas fa-user"></i></div>
+                        <div>客户</div>
+                    </div>
+                    <div class="message-content">您好,我对贵酒店的豪华套房很感兴趣,但觉得价格偏高,能否提供一些优惠?</div>
+                    <div class="message-time">10:25 AM</div>
+                </div>
+                <div class="chat-message assistant-message">
+                    <div class="message-header assistant-header">
+                        <div class="icon"><i class="fas fa-headset"></i></div>
+                        <div>销售顾问</div>
+                    </div>
+                    <div class="message-content">感谢您对我们豪华套房的关注!我们的套房拥有全景海景和私人管家服务,目前预订可享8折优惠,您觉得如何?</div>
+                    <div class="message-time">10:26 AM</div>
+                </div>
+                <div class="chat-message customer-message">
+                    <div class="message-header customer-header">
+                        <div class="icon"><i class="fas fa-user"></i></div>
+                        <div>客户</div>
+                    </div>
+                    <div class="message-content">8折还是有点高,我看到其他酒店类似房型有更优惠的价格。</div>
+                    <div class="message-time">10:27 AM</div>
+                </div>
+                <div class="chat-message assistant-message">
+                    <div class="message-header assistant-header">
+                        <div class="icon"><i class="fas fa-headset"></i></div>
+                        <div>销售顾问</div>
+                    </div>
+                    <div class="message-content">我理解您的考虑。我们的套房包含双人早餐和免费SPA体验,这些增值服务能让您的住宿体验更加完美。</div>
+                    <div class="message-time">10:28 AM</div>
+                </div>
+                <div class="chat-message customer-message">
+                    <div class="message-header customer-header">
+                        <div class="icon"><i class="fas fa-user"></i></div>
+                        <div>客户</div>
+                    </div>
+                    <div class="message-content">这个听起来不错,我考虑一下。</div>
+                    <div class="message-time">10:29 AM</div>
+                </div>
+                <div class="chat-message assistant-message">
+                    <div class="message-header assistant-header">
+                        <div class="icon"><i class="fas fa-headset"></i></div>
+                        <div>销售顾问</div>
+                    </div>
+                    <div class="message-content">好的,如果您今天预订,我们还可以额外赠送您一次下午茶体验。</div>
+                    <div class="message-time">10:30 AM</div>
+                </div>
+            </div>
+            
+            <!-- 客户标签编辑区 -->
+            <div class="tags-area">
+                <div class="tags-header">
+                    <div class="tags-title">客户标签</div>
+                    <div class="add-tag" id="addTagBtn">
+                        <i class="fas fa-plus"></i>
+                        <span>添加标签</span>
+                    </div>
+                </div>
+                <div class="input-tags" id="tagsContainer">
+                    <div class="tag" style="background: rgba(100, 160, 255, 0.15); color: #64a0ff;">
+                        <i class="fas fa-user"></i>
+                        <span>VIP客户</span>
+                        <span class="delete"><i class="fas fa-times"></i></span>
+                    </div>
+                    <div class="tag" style="background: rgba(255, 212, 59, 0.15); color: #ffd43b;">
+                        <i class="fas fa-calendar"></i>
+                        <span>旺季时段</span>
+                        <span class="delete"><i class="fas fa-times"></i></span>
+                    </div>
+                    <div class="tag" style="background: rgba(156, 54, 181, 0.15); color: #9c36b5;">
+                        <i class="fas fa-percent"></i>
+                        <span>价格敏感</span>
+                        <span class="delete"><i class="fas fa-times"></i></span>
+                    </div>
+                </div>
+            </div>
+        </section>
+        
+        <!-- 输入工作区 -->
+        <section class="input-area">
+            <h2 class="input-title">
+                <i class="fas fa-comment-dots"></i>
+                输入对话内容
+            </h2>
+            
+            <div class="role-selector">
+                <div class="role-btn active" id="customerRoleBtn">客户消息</div>
+                <div class="role-btn" id="assistantRoleBtn">销售回复</div>
+            </div>
+            
+            <div class="input-field">
+                <textarea class="text-input" placeholder="输入对话内容..." id="messageInput"></textarea>
+            </div>
+            
+            <div class="action-buttons">
+                <div class="action-btn save-btn" onclick="sendMessage()">
+                    <i class="fas fa-paper-plane"></i>
+                    <span>发送消息</span>
+                </div>
+            </div>
+        </section>
+        
+        <!-- 策略卡片组 -->
+        <section class="strategy-area">
+            <h2 class="strategy-title">
+                <i class="fas fa-cards"></i>
+                推荐应对策略
+            </h2>
+            <div class="cards-container">
+                <div class="strategy-card card-aggressive" onclick="activateCard(0)">
+                    <div class="card-header">
+                        <div class="card-title">主动型策略</div>
+                        <div class="card-icon" style="background: var(--blue-light); color: var(--blue);">
+                            <i class="fas fa-bolt"></i>
+                        </div>
+                    </div>
+                    <div class="card-content">
+                        <p>直接强调酒店独特价值,限量优惠制造紧迫感:</p>
+                        <div class="card-highlight">
+                            "我们的豪华套房拥有全景海景和私人管家服务,目前仅剩3间,现在预订可享8折限时优惠!"
+                        </div>
+                        <p><strong>适用场景:</strong>客户表现出明确兴趣,决策周期短</p>
+                        <p><strong>优势:</strong>快速成交,提升单笔订单价值</p>
+                    </div>
+                    <div class="card-footer">
+                        <div class="card-hint">成功率: 68%</div>
+                        <div class="card-hint"><i class="fas fa-clock"></i> 推荐指数: ⭐⭐⭐⭐</div>
+                    </div>
+                </div>
+                
+                <div class="strategy-card card-neutral" onclick="activateCard(1)">
+                    <div class="card-header">
+                        <div class="card-title">平衡型策略</div>
+                        <div class="card-icon" style="background: rgba(255, 212, 59, 0.15); color: var(--yellow);">
+                            <i class="fas fa-balance-scale"></i>
+                        </div>
+                    </div>
+                    <div class="card-content">
+                        <p>提供阶梯式优惠,引导客户选择:</p>
+                        <div class="card-highlight">
+                            "如果您连住3晚以上,我们可以提供免费升级和早餐。另外,会员可额外享受9折优惠,现在注册立享福利!"
+                        </div>
+                        <p><strong>适用场景:</strong>客户在多个选项间犹豫</p>
+                        <p><strong>优势:</strong>平衡双方利益,建立长期关系</p>
+                    </div>
+                    <div class="card-footer">
+                        <div class="card-hint">成功率: 82%</div>
+                        <div class="card-hint"><i class="fas fa-clock"></i> 推荐指数: ⭐⭐⭐⭐⭐</div>
+                    </div>
+                </div>
+                
+                <div class="strategy-card card-conservative" onclick="activateCard(2)">
+                    <div class="card-header">
+                        <div class="card-title">保守型策略</div>
+                        <div class="card-icon" style="background: rgba(156, 54, 181, 0.15); color: var(--purple);">
+                            <i class="fas fa-shield-alt"></i>
+                        </div>
+                    </div>
+                    <div class="card-content">
+                        <p>提供灵活方案,降低决策风险:</p>
+                        <div class="card-highlight">
+                            "我们提供24小时免费取消政策,现在预订可锁定当前价格。如果您对入住体验有任何不满意,我们将提供额外补偿。"
+                        </div>
+                        <p><strong>适用场景:</strong>客户犹豫不决,决策周期长</p>
+                        <p><strong>优势:</strong>降低客户风险感知,提高转化率</p>
+                    </div>
+                    <div class="card-footer">
+                        <div class="card-hint">成功率: 75%</div>
+                        <div class="card-hint"><i class="fas fa-clock"></i> 推荐指数: ⭐⭐⭐⭐</div>
+                    </div>
+                </div>
+            </div>
+            
+            <!-- 卡片导航点 -->
+            <div class="card-navigation">
+                <div class="card-nav-btn active" onclick="activateCard(0)"></div>
+                <div class="card-nav-btn" onclick="activateCard(1)"></div>
+                <div class="card-nav-btn" onclick="activateCard(2)"></div>
+            </div>
+            
+            <!-- 操作按钮 -->
+            <div class="action-buttons">
+                <div class="action-btn save-btn" onclick="saveRecord()">
+                    <i class="fas fa-save"></i>
+                    <span>保存记录</span>
+                </div>
+                <div class="action-btn history-btn" onclick="viewHistory()">
+                    <i class="fas fa-history"></i>
+                    <span>查看历史</span>
+                </div>
+            </div>
+        </section>
+    </div>
+
+    <script>
+        // 初始化变量
+        let selectedColor = '#64a0ff';
+        
+        // 场景选择功能
+        document.querySelectorAll('.scene-option').forEach(item => {
+            item.addEventListener('click', function() {
+                document.querySelectorAll('.scene-option').forEach(i => i.classList.remove('active'));
+                this.classList.add('active');
+                
+                // 更新策略内容
+                const scene = this.getAttribute('data-scene');
+                updateStrategies(scene);
+            });
+        });
+        
+        // 更新策略内容
+        function updateStrategies(scene) {
+            const strategies = {
+                "first-contact": {
+                    aggressive: "主动介绍酒店特色和限时优惠,强调独特卖点",
+                    neutral: "提供套餐选择,引导客户了解不同房型",
+                    conservative: "邀请客户参观虚拟酒店,提供详细资料"
+                },
+                "deep-talk": {
+                    aggressive: "深度挖掘客户需求,提供定制化解决方案",
+                    neutral: "建立信任关系,分享成功案例和客户评价",
+                    conservative: "提供专业建议,解答客户深层疑问"
+                }
+            };
+            
+            const sceneTitles = {
+                "first-contact": "首次接触",
+                "deep-talk": "深度交流"
+            };
+            
+            const sceneTitle = sceneTitles[scene] || "当前场景";
+            
+            // 更新策略内容
+            document.querySelector('.card-aggressive .card-highlight').textContent = 
+                strategies[scene].aggressive;
+            document.querySelector('.card-neutral .card-highlight').textContent = 
+                strategies[scene].neutral;
+            document.querySelector('.card-conservative .card-highlight').textContent = 
+                strategies[scene].conservative;
+                
+            // 更新策略标题
+            document.querySelector('.strategy-title').innerHTML = 
+                `<i class="fas fa-cards"></i> ${sceneTitle} - 推荐应对策略`;
+        }
+        
+        // 激活卡片功能
+        function activateCard(index) {
+            const cards = document.querySelectorAll('.strategy-card');
+            const navBtns = document.querySelectorAll('.card-nav-btn');
+            
+            cards.forEach((c, i) => {
+                if (i === index) {
+                    c.style.transform = 'translateY(0) scale(1)';
+                    c.style.zIndex = '30';
+                } else if (Math.abs(i - index) === 1) {
+                    c.style.transform = `translateY(${20 * Math.abs(i - index)}px) scale(${1 - 0.05 * Math.abs(i - index)})`;
+                    c.style.zIndex = '20';
+                } else {
+                    c.style.transform = `translateY(${40 * Math.abs(i - index)}px) scale(${1 - 0.1 * Math.abs(i - index)})`;
+                    c.style.zIndex = '10';
+                }
+            });
+            
+            navBtns.forEach((btn, i) => {
+                if (i === index) {
+                    btn.classList.add('active');
+                } else {
+                    btn.classList.remove('active');
+                }
+            });
+        }
+        
+        // 角色切换功能
+        const customerRoleBtn = document.getElementById('customerRoleBtn');
+        const assistantRoleBtn = document.getElementById('assistantRoleBtn');
+        
+        customerRoleBtn.addEventListener('click', function() {
+            customerRoleBtn.classList.add('active');
+            assistantRoleBtn.classList.remove('active');
+        });
+        
+        assistantRoleBtn.addEventListener('click', function() {
+            assistantRoleBtn.classList.add('active');
+            customerRoleBtn.classList.remove('active');
+        });
+        
+        // 标签删除功能
+        function setupTagDeletion() {
+            document.querySelectorAll('.tag .delete').forEach(deleteBtn => {
+                deleteBtn.addEventListener('click', function(e) {
+                    e.stopPropagation();
+                    this.closest('.tag').remove();
+                });
+            });
+        }
+        
+        // 初始化标签删除功能
+        setupTagDeletion();
+        
+        // 添加新标签功能
+        const addTagBtn = document.getElementById('addTagBtn');
+        const tagsContainer = document.getElementById('tagsContainer');
+        
+        addTagBtn.addEventListener('click', function() {
+            const newTag = document.createElement('div');
+            newTag.className = 'tag';
+            newTag.style.background = 'rgba(100, 160, 255, 0.15)';
+            newTag.style.color = '#64a0ff';
+            newTag.innerHTML = `
+                <i class="fas fa-tag"></i>
+                <span>新标签</span>
+                <span class="delete"><i class="fas fa-times"></i></span>
+            `;
+            
+            // 添加删除事件
+            newTag.querySelector('.delete').addEventListener('click', function(e) {
+                e.stopPropagation();
+                this.closest('.tag').remove();
+            });
+            
+            tagsContainer.appendChild(newTag);
+        });
+        
+        // 发送消息功能
+        const messageInput = document.getElementById('messageInput');
+        const chatContainer = document.getElementById('chatContainer');
+        
+        function sendMessage() {
+            const message = messageInput.value.trim();
+            if (message) {
+                // 确定消息角色
+                const isCustomer = customerRoleBtn.classList.contains('active');
+                const role = isCustomer ? 'customer' : 'assistant';
+                
+                // 创建新消息元素
+                const newMessage = document.createElement('div');
+                newMessage.className = `chat-message ${role}-message`;
+                
+                // 获取当前时间
+                const now = new Date();
+                const timeString = `${now.getHours()}:${now.getMinutes().toString().padStart(2, '0')}`;
+                
+                // 消息头部
+                let headerHtml = '';
+                if (isCustomer) {
+                    headerHtml = `
+                        <div class="message-header customer-header">
+                            <div class="icon"><i class="fas fa-user"></i></div>
+                            <div>客户</div>
+                        </div>
+                    `;
+                } else {
+                    headerHtml = `
+                        <div class="message-header assistant-header">
+                            <div class="icon"><i class="fas fa-headset"></i></div>
+                            <div>销售顾问</div>
+                        </div>
+                    `;
+                }
+                
+                newMessage.innerHTML = `
+                    ${headerHtml}
+                    <div class="message-content">${message}</div>
+                    <div class="message-time">${timeString}</div>
+                `;
+                
+                // 添加到聊天容器
+                chatContainer.appendChild(newMessage);
+                
+                // 清空输入框
+                messageInput.value = '';
+                
+                // 滚动到底部
+                chatContainer.scrollTop = chatContainer.scrollHeight;
+                
+                // 如果是销售发送消息,模拟客户回复
+                if (!isCustomer) {
+                    setTimeout(() => {
+                        const customerReply = document.createElement('div');
+                        customerReply.className = 'chat-message customer-message';
+                        
+                        // 模拟回复内容
+                        const replies = [
+                            "这个优惠包含早餐吗?",
+                            "我需要和家人商量一下",
+                            "能否提供免费接机服务?",
+                            "价格还是有点高,能再优惠些吗?",
+                            "你们的取消政策是怎样的?",
+                            "如果我今天预订,还有额外优惠吗?",
+                            "套餐包含哪些服务?",
+                            "有更经济的房型推荐吗?"
+                        ];
+                        const randomReply = replies[Math.floor(Math.random() * replies.length)];
+                        
+                        customerReply.innerHTML = `
+                            <div class="message-header customer-header">
+                                <div class="icon"><i class="fas fa-user"></i></div>
+                                <div>客户</div>
+                            </div>
+                            <div class="message-content">${randomReply}</div>
+                            <div class="message-time">${now.getHours()}:${(now.getMinutes() + 1).toString().padStart(2, '0')}</div>
+                        `;
+                        
+                        chatContainer.appendChild(customerReply);
+                        chatContainer.scrollTop = chatContainer.scrollHeight;
+                    }, 1500);
+                }
+                
+                // 重新聚焦输入框
+                messageInput.focus();
+            }
+        }
+        
+        // 支持按Enter发送消息(Shift+Enter换行)
+        messageInput.addEventListener('keydown', function(e) {
+            if (e.key === 'Enter' && !e.shiftKey) {
+                e.preventDefault();
+                sendMessage();
+            }
+        });
+        
+        // 保存记录功能
+        function saveRecord() {
+            // 创建动画效果
+            const saveBtn = document.querySelector('.save-btn');
+            saveBtn.innerHTML = '<i class="fas fa-check"></i> 已保存';
+            saveBtn.style.background = '#4da3ff';
+            
+            setTimeout(() => {
+                saveBtn.innerHTML = '<i class="fas fa-save"></i> 保存记录';
+                saveBtn.style.background = '';
+            }, 2000);
+        }
+        
+        // 查看历史功能
+        function viewHistory() {
+            alert('历史记录功能即将开放,正在开发中...');
+        }
+        
+        // 初始化
+        document.addEventListener('DOMContentLoaded', function() {
+            // 初始化卡片位置
+            activateCard(0);
+            
+            // 滚动到聊天底部
+            chatContainer.scrollTop = chatContainer.scrollHeight;
+        });
+    </script>
+</body>
+</html>

+ 1068 - 0
ai-assisant/demo/first.html

@@ -0,0 +1,1068 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>AI实验室 - 酒店销售智能平台</title>
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
+    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+            font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
+        }
+        
+        :root {
+            --primary-blue: #2563eb;
+            --accent-teal: #0d9488;
+            --accent-purple: #7b4bff;
+            --light-gray: #f3f4f6;
+            --text-dark: #1f2937;
+            --text-light: #6b7280;
+            --card-bg: #ffffff;
+            --border-color: #e5e7eb;
+            --transition: all 0.3s ease;
+            --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.05);
+            --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
+            --shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.1);
+        }
+        
+        body {
+            background-color: #ffffff;
+            color: var(--text-dark);
+            min-height: 100vh;
+            padding: 20px 16px 40px;
+            position: relative;
+            overflow-x: hidden;
+        }
+        
+        /* 头部导航 */
+        .header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 12px 0 20px;
+            margin-bottom: 10px;
+            position: relative;
+        }
+        
+        .logo {
+            display: flex;
+            align-items: center;
+            gap: 12px;
+        }
+        
+        .logo-icon {
+            width: 40px;
+            height: 40px;
+            background: linear-gradient(135deg, var(--primary-blue), #3b82f6);
+            border-radius: 12px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            box-shadow: var(--shadow-sm);
+        }
+        
+        .logo-icon i {
+            font-size: 20px;
+            color: white;
+        }
+        
+        .logo-text {
+            font-size: 22px;
+            font-weight: 700;
+            color: var(--text-dark);
+            letter-spacing: -0.5px;
+        }
+        
+        .logo-subtext {
+            font-size: 12px;
+            color: var(--primary-blue);
+            font-weight: 500;
+            margin-top: -5px;
+            letter-spacing: 0.5px;
+        }
+        
+        .user-actions {
+            display: flex;
+            gap: 16px;
+        }
+        
+        .action-btn {
+            background: var(--light-gray);
+            border-radius: 10px;
+            width: 40px;
+            height: 40px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            color: var(--text-dark);
+            font-size: 18px;
+            cursor: pointer;
+            transition: var(--transition);
+            border: 1px solid var(--border-color);
+            position: relative;
+        }
+        
+        .action-btn:hover {
+            background: #e5e7eb;
+            transform: translateY(-2px);
+            box-shadow: var(--shadow-sm);
+        }
+        
+        .badge {
+            position: absolute;
+            top: -5px;
+            right: -5px;
+            width: 20px;
+            height: 20px;
+            background: #ef4444;
+            color: white;
+            border-radius: 50%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 11px;
+            font-weight: 600;
+        }
+        
+        /* 欢迎区域 */
+        .welcome-section {
+            margin: 15px 0 25px;
+            padding: 0 5px;
+            text-align: center;
+        }
+        
+        .greeting {
+            font-size: 26px;
+            font-weight: 700;
+            margin-bottom: 8px;
+            line-height: 1.3;
+        }
+        
+        .greeting span {
+            color: var(--primary-blue);
+            position: relative;
+        }
+        
+        .greeting span::after {
+            content: '';
+            position: absolute;
+            bottom: 2px;
+            left: 0;
+            width: 100%;
+            height: 6px;
+            background: rgba(37, 99, 235, 0.15);
+            border-radius: 3px;
+            z-index: -1;
+        }
+        
+        .motivational-text {
+            font-size: 18px;
+            color: var(--primary-blue);
+            font-weight: 600;
+            line-height: 1.6;
+            max-width: 90%;
+            margin: 20px auto;
+            padding: 15px;
+            border-radius: 16px;
+            background: rgba(37, 99, 235, 0.05);
+            border-left: 4px solid var(--primary-blue);
+            position: relative;
+        }
+        
+        .motivational-text::before {
+            content: """;
+            position: absolute;
+            top: -15px;
+            left: 10px;
+            font-size: 60px;
+            color: rgba(37, 99, 235, 0.1);
+            font-family: Georgia, serif;
+        }
+        
+        /* 功能卡片网格 */
+        .features-grid {
+            display: grid;
+            grid-template-columns: repeat(2, 1fr);
+            gap: 18px;
+            margin-top: 25px;
+        }
+        
+        .feature-card {
+            background: var(--card-bg);
+            border-radius: 20px;
+            padding: 25px 20px;
+            position: relative;
+            overflow: hidden;
+            transition: var(--transition);
+            border: 1px solid var(--border-color);
+            box-shadow: var(--shadow-md);
+            cursor: pointer;
+            height: 180px;
+            display: flex;
+            flex-direction: column;
+        }
+        
+        .feature-card:hover {
+            transform: translateY(-5px);
+            box-shadow: var(--shadow-lg);
+            border-color: #d1d5db;
+        }
+        
+        .card-icon {
+            width: 50px;
+            height: 50px;
+            background: var(--light-gray);
+            border-radius: 14px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            margin-bottom: 18px;
+            font-size: 22px;
+            color: var(--primary-blue);
+        }
+        
+        .card-title {
+            font-size: 18px;
+            font-weight: 600;
+            margin-bottom: 8px;
+            color: var(--text-dark);
+        }
+        
+        .card-desc {
+            font-size: 14px;
+            color: var(--text-light);
+            line-height: 1.5;
+            flex-grow: 1;
+        }
+        
+        .card-stats {
+            display: flex;
+            justify-content: space-between;
+            margin-top: 15px;
+            font-size: 12px;
+            color: var(--primary-blue);
+            font-weight: 500;
+        }
+        
+        /* 数据统计卡片 */
+        .stats-card {
+            background: var(--card-bg);
+            border-radius: 20px;
+            padding: 20px;
+            margin: 25px 0 15px;
+            border: 1px solid var(--border-color);
+            box-shadow: var(--shadow-sm);
+            position: relative;
+            overflow: hidden;
+        }
+        
+        .stats-card::before {
+            content: '';
+            position: absolute;
+            top: 0;
+            left: 0;
+            right: 0;
+            height: 4px;
+            background: linear-gradient(90deg, var(--primary-blue), #0d9488);
+        }
+        
+        .stats-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 20px;
+        }
+        
+        .stats-title {
+            font-size: 18px;
+            font-weight: 600;
+            color: var(--text-dark);
+        }
+        
+        .stats-container {
+            display: grid;
+            grid-template-columns: repeat(3, 1fr);
+            gap: 15px;
+        }
+        
+        .stat-item {
+            text-align: center;
+            padding: 10px;
+            background: var(--light-gray);
+            border-radius: 14px;
+            transition: var(--transition);
+        }
+        
+        .stat-item:hover {
+            transform: translateY(-3px);
+            box-shadow: var(--shadow-sm);
+        }
+        
+        .stat-value {
+            font-size: 22px;
+            font-weight: 700;
+            color: var(--primary-blue);
+            margin-bottom: 5px;
+        }
+        
+        .stat-label {
+            font-size: 13px;
+            color: var(--text-light);
+        }
+        
+        /* 激励区域 */
+        .inspiration-section {
+            background: linear-gradient(135deg, #f0f9ff, #e0f2fe);
+            border-radius: 20px;
+            padding: 25px;
+            margin: 30px 0;
+            text-align: center;
+            border: 1px solid #dbeafe;
+            position: relative;
+            overflow: hidden;
+        }
+        
+        .inspiration-title {
+            font-size: 22px;
+            font-weight: 700;
+            color: var(--primary-blue);
+            margin-bottom: 15px;
+        }
+        
+        .inspiration-content {
+            font-size: 16px;
+            color: var(--text-dark);
+            line-height: 1.7;
+            max-width: 600px;
+            margin: 0 auto;
+        }
+        
+        .inspiration-icon {
+            position: absolute;
+            top: 20px;
+            right: 20px;
+            font-size: 60px;
+            color: rgba(37, 99, 235, 0.1);
+        }
+        
+        /* 消息弹窗 */
+        .popup-overlay {
+            position: fixed;
+            top: 0;
+            left: 0;
+            right: 0;
+            bottom: 0;
+            background: rgba(0, 0, 0, 0.5);
+            backdrop-filter: blur(5px);
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            z-index: 1000;
+            opacity: 0;
+            visibility: hidden;
+            transition: var(--transition);
+        }
+        
+        .popup-overlay.active {
+            opacity: 1;
+            visibility: visible;
+        }
+        
+        .message-popup {
+            background: white;
+            border-radius: 20px;
+            width: 90%;
+            max-width: 400px;
+            max-height: 80vh;
+            overflow: hidden;
+            box-shadow: 0 25px 50px rgba(0, 0, 0, 0.2);
+            transform: translateY(20px);
+            transition: transform 0.4s ease;
+        }
+        
+        .popup-overlay.active .message-popup {
+            transform: translateY(0);
+        }
+        
+        .popup-header {
+            padding: 20px;
+            background: var(--primary-blue);
+            color: white;
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+        }
+        
+        .popup-title {
+            font-size: 20px;
+            font-weight: 600;
+        }
+        
+        .close-btn {
+            background: rgba(255, 255, 255, 0.2);
+            width: 36px;
+            height: 36px;
+            border-radius: 50%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            cursor: pointer;
+            transition: var(--transition);
+        }
+        
+        .close-btn:hover {
+            background: rgba(255, 255, 255, 0.3);
+            transform: rotate(90deg);
+        }
+        
+        .popup-content {
+            padding: 0;
+            max-height: 60vh;
+            overflow-y: auto;
+        }
+        
+        .message-list {
+            list-style: none;
+        }
+        
+        .message-item {
+            padding: 18px 20px;
+            border-bottom: 1px solid var(--border-color);
+            cursor: pointer;
+            transition: var(--transition);
+        }
+        
+        .message-item:hover {
+            background: var(--light-gray);
+        }
+        
+        .message-item.unread {
+            background: rgba(37, 99, 235, 0.05);
+        }
+        
+        .message-title {
+            font-weight: 600;
+            margin-bottom: 5px;
+            display: flex;
+            align-items: center;
+        }
+        
+        .message-title .unread-badge {
+            width: 8px;
+            height: 8px;
+            background: var(--primary-blue);
+            border-radius: 50%;
+            margin-right: 10px;
+        }
+        
+        .message-preview {
+            color: var(--text-light);
+            font-size: 14px;
+            line-height: 1.5;
+            display: -webkit-box;
+            -webkit-line-clamp: 2;
+            -webkit-box-orient: vertical;
+            overflow: hidden;
+        }
+        
+        .message-time {
+            font-size: 12px;
+            color: var(--text-light);
+            margin-top: 8px;
+            text-align: right;
+        }
+        
+        /* 个人中心弹窗 */
+        .profile-popup {
+            background: white;
+            border-radius: 20px;
+            width: 90%;
+            max-width: 400px;
+            max-height: 90vh;
+            overflow: hidden;
+            box-shadow: 0 25px 50px rgba(0, 0, 0, 0.2);
+            transform: translateY(20px);
+            transition: transform 0.4s ease;
+        }
+        
+        .popup-overlay.active .profile-popup {
+            transform: translateY(0);
+        }
+        
+        .user-info {
+            padding: 30px 20px;
+            background: linear-gradient(135deg, var(--primary-blue), #3b82f6);
+            color: white;
+            text-align: center;
+            position: relative;
+        }
+        
+        .user-avatar {
+            width: 80px;
+            height: 80px;
+            border-radius: 50%;
+            background: white;
+            margin: 0 auto 15px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 36px;
+            color: var(--primary-blue);
+            border: 3px solid white;
+            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
+        }
+        
+        .user-name {
+            font-size: 22px;
+            font-weight: 700;
+            margin-bottom: 5px;
+        }
+        
+        .user-role {
+            font-size: 14px;
+            background: rgba(255, 255, 255, 0.2);
+            padding: 4px 12px;
+            border-radius: 20px;
+            display: inline-block;
+        }
+        
+        .training-section {
+            padding: 20px;
+        }
+        
+        .section-title {
+            font-size: 18px;
+            font-weight: 600;
+            margin-bottom: 20px;
+            padding-bottom: 10px;
+            border-bottom: 2px solid var(--light-gray);
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+        }
+        
+        .training-list {
+            list-style: none;
+        }
+        
+        .training-item {
+            padding: 15px;
+            border-radius: 14px;
+            border: 1px solid var(--border-color);
+            margin-bottom: 15px;
+            transition: var(--transition);
+            cursor: pointer;
+        }
+        
+        .training-item:hover {
+            transform: translateY(-3px);
+            box-shadow: var(--shadow-md);
+            border-color: var(--primary-blue);
+        }
+        
+        .training-header {
+            display: flex;
+            justify-content: space-between;
+            margin-bottom: 10px;
+        }
+        
+        .training-title {
+            font-weight: 600;
+            color: var(--text-dark);
+        }
+        
+        .training-date {
+            font-size: 12px;
+            color: var(--text-light);
+        }
+        
+        .training-stats {
+            display: flex;
+            justify-content: space-between;
+            font-size: 14px;
+            color: var(--text-light);
+        }
+        
+        .training-score {
+            color: var(--primary-blue);
+            font-weight: 600;
+        }
+        
+        .progress-bar {
+            height: 6px;
+            background: var(--light-gray);
+            border-radius: 3px;
+            margin-top: 10px;
+            overflow: hidden;
+        }
+        
+        .progress-fill {
+            height: 100%;
+            background: var(--primary-blue);
+            border-radius: 3px;
+            width: 75%; /* 示例值 */
+        }
+        
+        /* 功能区颜色 */
+        .feature-card:nth-child(1) .card-icon {
+            color: #0d9488;
+            background: rgba(13, 148, 136, 0.1);
+        }
+        
+        .feature-card:nth-child(1):hover .card-icon {
+            background: rgba(13, 148, 136, 0.15);
+        }
+        
+        .feature-card:nth-child(2) .card-icon {
+            color: #7b4bff;
+            background: rgba(123, 75, 255, 0.1);
+        }
+        
+        .feature-card:nth-child(2):hover .card-icon {
+            background: rgba(123, 75, 255, 0.15);
+        }
+        
+        .feature-card:nth-child(3) .card-icon {
+            color: #ec4899;
+            background: rgba(236, 72, 153, 0.1);
+        }
+        
+        .feature-card:nth-child(3):hover .card-icon {
+            background: rgba(236, 72, 153, 0.15);
+        }
+        
+        .feature-card:nth-child(4) .card-icon {
+            color: #f59e0b;
+            background: rgba(245, 158, 11, 0.1);
+        }
+        
+        .feature-card:nth-child(4):hover .card-icon {
+            background: rgba(245, 158, 11, 0.15);
+        }
+        
+        /* 微交互效果 */
+        .feature-card:hover .card-icon {
+            transform: rotate(5deg) scale(1.1);
+            transition: transform 0.3s ease;
+            background: rgba(37, 99, 235, 0.1);
+        }
+        
+        .pulse {
+            position: absolute;
+            top: 10px;
+            right: 10px;
+            width: 8px;
+            height: 8px;
+            background: #ef4444;
+            border-radius: 50%;
+        }
+        
+        /* 响应式设计 */
+        @media (max-width: 480px) {
+            .features-grid {
+                gap: 15px;
+            }
+            
+            .feature-card {
+                padding: 20px 16px;
+                height: 170px;
+            }
+            
+            .card-icon {
+                width: 45px;
+                height: 45px;
+                font-size: 20px;
+            }
+            
+            .card-title {
+                font-size: 17px;
+            }
+            
+            .card-desc {
+                font-size: 13px;
+            }
+            
+            .greeting {
+                font-size: 24px;
+            }
+            
+            .stats-card {
+                padding: 18px;
+            }
+            
+            .stat-value {
+                font-size: 20px;
+            }
+            
+            .motivational-text {
+                font-size: 16px;
+                padding: 12px;
+            }
+        }
+    </style>
+</head>
+<body>
+    <!-- 头部导航 -->
+    <div class="header">
+        <div class="logo">
+            <div class="logo-icon">
+                <i class="fas fa-brain"></i>
+            </div>
+            <div>
+                <div class="logo-text">AI实验室</div>
+                <div class="logo-subtext">酒店销售智能平台</div>
+            </div>
+        </div>
+        <div class="user-actions">
+            <div class="action-btn" id="message-btn">
+                <i class="fas fa-bell"></i>
+                <div class="badge">3</div>
+            </div>
+            <div class="action-btn" id="profile-btn">
+                <i class="fas fa-user"></i>
+            </div>
+        </div>
+    </div>
+    
+    <!-- 欢迎区域 -->
+    <div class="welcome-section">
+        <h1 class="greeting">你好,<span>销售精英</span> 👋</h1>
+        
+        <div class="motivational-text">
+            每一次对话都是展现专业的机会,每一次练习都在提升成功的概率!今天,让AI成为您最强大的销售伙伴
+        </div>
+    </div>
+    
+    <!-- 激励区域 -->
+    <div class="inspiration-section">
+        <div class="inspiration-icon">
+            <i class="fas fa-bullhorn"></i>
+        </div>
+        <h2 class="inspiration-title">今日激励</h2>
+        <p class="inspiration-content">
+            卓越的销售不是天生的,而是通过每一次精心准备的对话和持续训练铸就的。您今天的努力,将成就明天签约的喜悦!
+        </p>
+    </div>
+    
+    <!-- 数据统计卡片 -->
+    <div class="stats-card">
+        <div class="stats-header">
+            <div class="stats-title">团队今日战绩</div>
+            <div class="action-btn">
+                <i class="fas fa-arrow-right"></i>
+            </div>
+        </div>
+        <div class="stats-container">
+            <div class="stat-item">
+                <div class="stat-value">42</div>
+                <div class="stat-label">陪练次数</div>
+            </div>
+            <div class="stat-item">
+                <div class="stat-value">28</div>
+                <div class="stat-label">策略生成</div>
+            </div>
+            <div class="stat-item">
+                <div class="stat-value">96%</div>
+                <div class="stat-label">满意度</div>
+            </div>
+        </div>
+    </div>
+    
+    <!-- 功能卡片网格 -->
+    <div class="features-grid">
+        <!-- 虚拟陪练 -->
+        <div class="feature-card">
+            <div class="pulse"></div>
+            <div class="card-icon">
+                <i class="fas fa-robot"></i>
+            </div>
+            <h3 class="card-title">虚拟陪练</h3>
+            <p class="card-desc">与AI客户进行真实销售对话练习,提升沟通技巧</p>
+            <div class="card-stats">
+                <span><i class="fas fa-history"></i> 12次练习</span>
+                <span>85%得分</span>
+            </div>
+        </div>
+        
+        <!-- 话术决策 -->
+        <div class="feature-card">
+            <div class="card-icon">
+                <i class="fas fa-comments"></i>
+            </div>
+            <h3 class="card-title">话术决策</h3>
+            <p class="card-desc">智能生成最佳沟通策略,应对各种销售场景</p>
+            <div class="card-stats">
+                <span><i class="fas fa-star"></i> 8个策略</span>
+                <span>92%有效</span>
+            </div>
+        </div>
+        
+        <!-- 数据训练 -->
+        <div class="feature-card">
+            <div class="card-icon">
+                <i class="fas fa-database"></i>
+            </div>
+            <h3 class="card-title">数据训练</h3>
+            <p class="card-desc">上传销售数据训练AI模型,优化决策能力</p>
+            <div class="card-stats">
+                <span><i class="fas fa-chart-line"></i> 3.2TB</span>
+                <span>98%准确</span>
+            </div>
+        </div>
+        
+        <!-- 客户画像 -->
+        <div class="feature-card">
+            <div class="card-icon">
+                <i class="fas fa-user-tie"></i>
+            </div>
+            <h3 class="card-title">客户画像</h3>
+            <p class="card-desc">生成详细客户分析报告,洞察客户需求</p>
+            <div class="card-stats">
+                <span><i class="fas fa-file-alt"></i> 24份</span>
+                <span>更新中</span>
+            </div>
+        </div>
+    </div>
+    
+    <!-- 激励话语 -->
+    <div class="inspiration-section" style="margin-top: 30px;">
+        <h2 class="inspiration-title">成功源于持续精进</h2>
+        <p class="inspiration-content">
+            您已经完成了<span style="color: var(--primary-blue); font-weight: 600;">12次</span>虚拟陪练,
+            击败了<span style="color: var(--primary-blue); font-weight: 600;">86%</span>的同级销售。
+            继续保持,下一个销售冠军就是您!
+        </p>
+    </div>
+    
+    <!-- 消息提醒弹窗 -->
+    <div class="popup-overlay" id="message-popup">
+        <div class="message-popup">
+            <div class="popup-header">
+                <div class="popup-title">消息提醒</div>
+                <div class="close-btn" id="close-message">
+                    <i class="fas fa-times"></i>
+                </div>
+            </div>
+            <div class="popup-content">
+                <ul class="message-list">
+                    <li class="message-item unread">
+                        <div class="message-title">
+                            <span class="unread-badge"></span>
+                            新的陪练挑战
+                        </div>
+                        <div class="message-preview">
+                            您有一个新的虚拟陪练挑战等待完成,主题:高端客户价格谈判
+                        </div>
+                        <div class="message-time">10分钟前</div>
+                    </li>
+                    <li class="message-item unread">
+                        <div class="message-title">
+                            <span class="unread-badge"></span>
+                            话术策略更新
+                        </div>
+                        <div class="message-preview">
+                            您收藏的"投诉处理"话术策略已更新至3.2版本
+                        </div>
+                        <div class="message-time">1小时前</div>
+                    </li>
+                    <li class="message-item">
+                        <div class="message-title">
+                            陪练成绩通知
+                        </div>
+                        <div class="message-preview">
+                            您最近的虚拟陪练成绩为92分,超过89%的销售同事
+                        </div>
+                        <div class="message-time">昨天</div>
+                    </li>
+                    <li class="message-item">
+                        <div class="message-title">
+                            团队周报
+                        </div>
+                        <div class="message-preview">
+                            本周团队陪练报告已生成,点击查看详细分析
+                        </div>
+                        <div class="message-time">2天前</div>
+                    </li>
+                    <li class="message-item">
+                        <div class="message-title">
+                            系统维护通知
+                        </div>
+                        <div class="message-preview">
+                            系统将于本周六凌晨2:00-4:00进行维护升级
+                        </div>
+                        <div class="message-time">3天前</div>
+                    </li>
+                </ul>
+            </div>
+        </div>
+    </div>
+    
+    <!-- 个人中心弹窗 -->
+    <div class="popup-overlay" id="profile-popup">
+        <div class="profile-popup">
+            <div class="user-info">
+                <div class="close-btn" id="close-profile">
+                    <i class="fas fa-times"></i>
+                </div>
+                <div class="user-avatar">
+                    <i class="fas fa-user"></i>
+                </div>
+                <div class="user-name">张明</div>
+                <div class="user-role">高级销售经理</div>
+            </div>
+            
+            <div class="training-section">
+                <div class="section-title">
+                    <span>我的训练记录</span>
+                    <span>总计: 12次</span>
+                </div>
+                
+                <ul class="training-list">
+                    <li class="training-item">
+                        <div class="training-header">
+                            <div class="training-title">高端客户价格谈判</div>
+                            <div class="training-date">2023-10-15</div>
+                        </div>
+                        <div class="training-stats">
+                            <div>难度: <span class="training-score">⭐⭐⭐</span></div>
+                            <div>得分: <span class="training-score">92分</span></div>
+                        </div>
+                        <div class="progress-bar">
+                            <div class="progress-fill" style="width: 92%"></div>
+                        </div>
+                    </li>
+                    <li class="training-item">
+                        <div class="training-header">
+                            <div class="training-title">首次接触技巧</div>
+                            <div class="training-date">2023-10-12</div>
+                        </div>
+                        <div class="training-stats">
+                            <div>难度: <span class="training-score">⭐⭐</span></div>
+                            <div>得分: <span class="training-score">85分</span></div>
+                        </div>
+                        <div class="progress-bar">
+                            <div class="progress-fill" style="width: 85%"></div>
+                        </div>
+                    </li>
+                    <li class="training-item">
+                        <div class="training-header">
+                            <div class="training-title">投诉处理模拟</div>
+                            <div class="training-date">2023-10-08</div>
+                        </div>
+                        <div class="training-stats">
+                            <div>难度: <span class="training-score">⭐⭐⭐</span></div>
+                            <div>得分: <span class="training-score">88分</span></div>
+                        </div>
+                        <div class="progress-bar">
+                            <div class="progress-fill" style="width: 88%"></div>
+                        </div>
+                    </li>
+                    <li class="training-item">
+                        <div class="training-header">
+                            <div class="training-title">长期合作谈判</div>
+                            <div class="training-date">2023-10-02</div>
+                        </div>
+                        <div class="training-stats">
+                            <div>难度: <span class="training-score">⭐⭐⭐⭐</span></div>
+                            <div>得分: <span class="training-score">78分</span></div>
+                        </div>
+                        <div class="progress-bar">
+                            <div class="progress-fill" style="width: 78%"></div>
+                        </div>
+                    </li>
+                </ul>
+            </div>
+        </div>
+    </div>
+    
+    <script>
+        // 获取DOM元素
+        const messageBtn = document.getElementById('message-btn');
+        const profileBtn = document.getElementById('profile-btn');
+        const messagePopup = document.getElementById('message-popup');
+        const profilePopup = document.getElementById('profile-popup');
+        const closeMessage = document.getElementById('close-message');
+        const closeProfile = document.getElementById('close-profile');
+        
+        // 消息弹窗控制
+        messageBtn.addEventListener('click', () => {
+            messagePopup.classList.add('active');
+        });
+        
+        closeMessage.addEventListener('click', () => {
+            messagePopup.classList.remove('active');
+        });
+        
+        // 个人中心弹窗控制
+        profileBtn.addEventListener('click', () => {
+            profilePopup.classList.add('active');
+        });
+        
+        closeProfile.addEventListener('click', () => {
+            profilePopup.classList.remove('active');
+        });
+        
+        // 点击弹窗外部关闭
+        [messagePopup, profilePopup].forEach(popup => {
+            popup.addEventListener('click', (e) => {
+                if (e.target === popup) {
+                    popup.classList.remove('active');
+                }
+            });
+        });
+        
+        // 卡片悬停效果增强
+        document.querySelectorAll('.feature-card').forEach(card => {
+            card.addEventListener('mouseenter', () => {
+                card.style.transform = 'translateY(-8px)';
+                card.style.boxShadow = '0 15px 30px rgba(0, 0, 0, 0.12)';
+            });
+            
+            card.addEventListener('mouseleave', () => {
+                card.style.transform = 'translateY(0)';
+                card.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.08)';
+            });
+            
+            card.addEventListener('click', () => {
+                card.style.transform = 'scale(0.97)';
+                setTimeout(() => {
+                    card.style.transform = '';
+                    // 实际项目中这里会有页面跳转逻辑
+                    alert('进入' + card.querySelector('.card-title').textContent + '功能');
+                }, 200);
+            });
+        });
+        
+        // 模拟数据更新
+        setInterval(() => {
+            const stats = document.querySelectorAll('.stat-value');
+            stats[0].textContent = Math.floor(Math.random() * 20 + 35);
+            stats[1].textContent = Math.floor(Math.random() * 15 + 20);
+        }, 5000);
+        
+        // 随机激励语句
+        const motivationalPhrases = [
+            "每一次拒绝都是离成功更近一步!",
+            "卓越的销售不是推销产品,而是解决问题!",
+            "今天的练习,明天的签约!",
+            "客户的需求是您成功的地图,AI是您的导航仪!",
+            "专业来自准备,成功源于坚持!",
+            "您不是一个人在战斗,AI是您最强大的后援!"
+        ];
+        
+        // 随机选择激励语句
+        function updateMotivationalText() {
+            const textElement = document.querySelector('.motivational-text');
+            const randomIndex = Math.floor(Math.random() * motivationalPhrases.length);
+            textElement.textContent = motivationalPhrases[randomIndex];
+        }
+        
+        // 每10秒更新一次激励语句
+        setInterval(updateMotivationalText, 10000);
+    </script>
+</body>
+</html>

+ 570 - 0
ai-assisant/demo/photo.html

@@ -0,0 +1,570 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>客户画像分析 - AI实验室</title>
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+            font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
+        }
+
+        :root {
+            --primary: #4a8fe7;
+            --primary-dark: #0a192f;
+            --secondary: #5e72e4;
+            --accent: #ff6b6b;
+            --text-dark: #1a1a1a;
+            --text-medium: #4a4a4a;
+            --text-light: #8a8f9c;
+            --bg-white: #ffffff;
+            --bg-light: #f5f7fa;
+            --card-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
+            --border-radius: 12px;
+            --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
+        }
+
+        body {
+            background-color: var(--bg-white);
+            color: var(--text-medium);
+            padding: 0;
+            max-width: 480px;
+            margin: 0 auto;
+            min-height: 100vh;
+            position: relative;
+            overflow-x: hidden;
+            background: linear-gradient(to bottom, #f5f9ff 0%, #ffffff 100px);
+        }
+
+        .app-container {
+            padding: 0 16px 40px;
+            position: relative;
+        }
+
+        /* 头部导航 */
+        .header {
+            padding: 20px 0;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            position: sticky;
+            top: 0;
+            background: var(--bg-white);
+            z-index: 100;
+            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.03);
+        }
+
+        .header-title {
+            font-size: 22px;
+            font-weight: 700;
+            color: var(--text-dark);
+            display: flex;
+            align-items: center;
+            gap: 10px;
+        }
+
+        .header-title i {
+            color: var(--primary);
+            font-size: 24px;
+            background: rgba(74, 143, 231, 0.1);
+            width: 40px;
+            height: 40px;
+            border-radius: 12px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+
+        /* 分析输入区 */
+        .analysis-input {
+            background: var(--bg-white);
+            border-radius: var(--border-radius);
+            box-shadow: var(--card-shadow);
+            padding: 20px;
+            margin-bottom: 24px;
+            border: 1px solid rgba(0, 0, 0, 0.03);
+        }
+
+        .input-group {
+            margin-bottom: 16px;
+        }
+
+        .input-group label {
+            display: block;
+            margin-bottom: 8px;
+            font-weight: 600;
+            color: var(--text-dark);
+            font-size: 14px;
+        }
+
+        .input-group input,
+        .input-group textarea {
+            width: 100%;
+            padding: 12px 16px;
+            border-radius: var(--border-radius);
+            border: 1px solid #e0e4e8;
+            font-size: 14px;
+            transition: var(--transition);
+        }
+
+        .input-group input:focus,
+        .input-group textarea:focus {
+            outline: none;
+            border-color: var(--primary);
+            box-shadow: 0 0 0 3px rgba(74, 143, 231, 0.2);
+        }
+
+        .input-group textarea {
+            min-height: 120px;
+            resize: vertical;
+        }
+
+        .action-buttons {
+            display: flex;
+            gap: 12px;
+            margin-top: 20px;
+        }
+
+        .btn {
+            padding: 12px 20px;
+            border-radius: var(--border-radius);
+            font-size: 14px;
+            font-weight: 600;
+            border: none;
+            cursor: pointer;
+            transition: var(--transition);
+            flex: 1;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            gap: 8px;
+        }
+
+        .btn-primary {
+            background: var(--primary);
+            color: white;
+            box-shadow: 0 4px 8px rgba(74, 143, 231, 0.2);
+        }
+
+        .btn-primary:hover {
+            background: #3a7bd5;
+            transform: translateY(-2px);
+            box-shadow: 0 6px 12px rgba(74, 143, 231, 0.3);
+        }
+
+        .btn-secondary {
+            background: var(--bg-light);
+            color: var(--text-medium);
+        }
+
+        .btn-secondary:hover {
+            background: #e1ebfa;
+            transform: translateY(-2px);
+        }
+
+        /* 客户列表区 */
+        .client-list-section {
+            margin-bottom: 24px;
+        }
+
+        .section-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 16px;
+        }
+
+        .section-title {
+            font-size: 18px;
+            font-weight: 700;
+            color: var(--text-dark);
+            position: relative;
+            padding-left: 12px;
+        }
+
+        .section-title:before {
+            content: '';
+            position: absolute;
+            left: 0;
+            top: 4px;
+            height: 16px;
+            width: 4px;
+            background: var(--primary);
+            border-radius: 2px;
+        }
+
+        .search-box {
+            position: relative;
+            margin-bottom: 16px;
+        }
+
+        .search-box input {
+            width: 100%;
+            padding: 12px 16px 12px 42px;
+            border-radius: var(--border-radius);
+            border: 1px solid #e0e4e8;
+            font-size: 14px;
+            transition: var(--transition);
+        }
+
+        .search-box input:focus {
+            outline: none;
+            border-color: var(--primary);
+            box-shadow: 0 0 0 3px rgba(74, 143, 231, 0.2);
+        }
+
+        .search-box i {
+            position: absolute;
+            left: 16px;
+            top: 50%;
+            transform: translateY(-50%);
+            color: var(--text-light);
+        }
+
+        .client-list {
+            background: var(--bg-white);
+            border-radius: var(--border-radius);
+            box-shadow: var(--card-shadow);
+            overflow: hidden;
+            border: 1px solid rgba(0, 0, 0, 0.03);
+        }
+
+        .client-item {
+            padding: 16px;
+            border-bottom: 1px solid #f0f2f5;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            transition: var(--transition);
+            cursor: pointer;
+        }
+
+        .client-item:last-child {
+            border-bottom: none;
+        }
+
+        .client-item:hover {
+            background: #f9fbfe;
+        }
+
+        .client-info {
+            display: flex;
+            align-items: center;
+            gap: 12px;
+        }
+
+        .client-avatar {
+            width: 40px;
+            height: 40px;
+            border-radius: 50%;
+            background: linear-gradient(135deg, #4a8fe7, #5e72e4);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            color: white;
+            font-weight: bold;
+            font-size: 16px;
+        }
+
+        .client-name {
+            font-weight: 600;
+            color: var(--text-dark);
+            margin-bottom: 2px;
+        }
+
+        .client-meta {
+            font-size: 12px;
+            color: var(--text-light);
+        }
+
+        .client-date {
+            font-size: 12px;
+            color: var(--text-light);
+        }
+
+        /* 智能推荐区 */
+        .recommendation-section {
+            margin-top: 24px;
+        }
+
+        .recommendation-cards {
+            display: flex;
+            flex-direction: column;
+            gap: 16px;
+        }
+
+        .recommendation-card {
+            background: var(--bg-white);
+            border-radius: var(--border-radius);
+            box-shadow: var(--card-shadow);
+            padding: 20px;
+            position: relative;
+            border: 1px solid rgba(0, 0, 0, 0.03);
+        }
+
+        .card-header {
+            display: flex;
+            align-items: center;
+            gap: 12px;
+            margin-bottom: 16px;
+        }
+
+        .card-icon {
+            width: 42px;
+            height: 42px;
+            border-radius: 12px;
+            background: rgba(74, 143, 231, 0.15);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            color: var(--primary);
+            font-size: 20px;
+        }
+
+        .card-title {
+            font-size: 16px;
+            font-weight: 700;
+            color: var(--text-dark);
+        }
+
+        .recommendation-content {
+            color: var(--text-medium);
+            font-size: 14px;
+            line-height: 1.6;
+            margin-bottom: 16px;
+        }
+
+        .recommendation-action {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+        }
+
+        .tag {
+            padding: 6px 12px;
+            border-radius: 20px;
+            background: var(--bg-light);
+            font-size: 12px;
+            color: var(--text-medium);
+            font-weight: 500;
+        }
+
+        .action-btn {
+            padding: 8px 16px;
+            border-radius: 30px;
+            background: var(--primary);
+            color: white;
+            font-size: 14px;
+            font-weight: 600;
+            border: none;
+            cursor: pointer;
+            transition: var(--transition);
+            box-shadow: 0 4px 8px rgba(74, 143, 231, 0.2);
+        }
+
+        .action-btn:hover {
+            background: #3a7bd5;
+            transform: translateY(-2px);
+            box-shadow: 0 6px 12px rgba(74, 143, 231, 0.3);
+        }
+
+        /* 动画效果 */
+        @keyframes fadeIn {
+            from { opacity: 0; transform: translateY(20px); }
+            to { opacity: 1; transform: translateY(0); }
+        }
+
+        .animated-card {
+            animation: fadeIn 0.6s cubic-bezier(0.22, 1, 0.36, 1) forwards;
+        }
+    </style>
+</head>
+<body>
+    <div class="app-container">
+        <!-- 头部导航 -->
+        <div class="header">
+            <div class="header-title">
+                <i class="fas fa-user-tag"></i>
+                <h1>客户画像分析</h1>
+            </div>
+        </div>
+
+        <!-- 第一部分:分析输入区 -->
+        <div class="analysis-input animated-card">
+            <div class="input-group">
+                <label for="client-id">客户编号</label>
+                <input type="text" id="client-id" placeholder="请输入客户编号">
+            </div>
+            
+            <div class="input-group">
+                <label for="client-name">客户名称</label>
+                <input type="text" id="client-name" placeholder="请输入客户名称">
+            </div>
+            
+            <div class="input-group">
+                <label for="chat-data">聊天记录文本</label>
+                <textarea id="chat-data" placeholder="请粘贴或输入聊天记录文本..."></textarea>
+            </div>
+            
+            <div class="action-buttons">
+                <button class="btn btn-secondary">
+                    <i class="fas fa-save"></i> 保存
+                </button>
+                <button class="btn btn-primary">
+                    <i class="fas fa-play"></i> 开始分析
+                </button>
+            </div>
+        </div>
+
+        <!-- 第二部分:客户分析列表 -->
+        <div class="client-list-section">
+            <div class="section-header">
+                <h2 class="section-title">客户分析列表</h2>
+            </div>
+            
+            <div class="search-box">
+                <i class="fas fa-search"></i>
+                <input type="text" placeholder="搜索客户名称或编号...">
+            </div>
+            
+            <div class="client-list">
+                <!-- 客户项 1 -->
+                <div class="client-item animated-card">
+                    <div class="client-info">
+                        <div class="client-avatar">张</div>
+                        <div>
+                            <div class="client-name">张明远</div>
+                            <div class="client-meta">企业客户 · ID: C1001</div>
+                        </div>
+                    </div>
+                    <div class="client-date">06-28</div>
+                </div>
+                
+                <!-- 客户项 2 -->
+                <div class="client-item animated-card">
+                    <div class="client-info">
+                        <div class="client-avatar">李</div>
+                        <div>
+                            <div class="client-name">李思琪</div>
+                            <div class="client-meta">个人客户 · ID: P2003</div>
+                        </div>
+                    </div>
+                    <div class="client-date">06-27</div>
+                </div>
+                
+                <!-- 客户项 3 -->
+                <div class="client-item animated-card">
+                    <div class="client-info">
+                        <div class="client-avatar">王</div>
+                        <div>
+                            <div class="client-name">王建国</div>
+                            <div class="client-meta">企业客户 · ID: C1002</div>
+                        </div>
+                    </div>
+                    <div class="client-date">06-25</div>
+                </div>
+                
+                <!-- 客户项 4 -->
+                <div class="client-item animated-card">
+                    <div class="client-info">
+                        <div class="client-avatar">陈</div>
+                        <div>
+                            <div class="client-name">陈晓薇</div>
+                            <div class="client-meta">个人客户 · ID: P2004</div>
+                        </div>
+                    </div>
+                    <div class="client-date">06-24</div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 第三部分:智能推荐区 -->
+        <div class="recommendation-section">
+            <div class="section-header">
+                <h2 class="section-title">智能推荐</h2>
+            </div>
+            
+            <div class="recommendation-cards">
+                <!-- 推荐卡片 1 -->
+                <div class="recommendation-card animated-card">
+                    <div class="card-header">
+                        <div class="card-icon">
+                            <i class="fas fa-user-friends"></i>
+                        </div>
+                        <h3 class="card-title">相似客户推荐</h3>
+                    </div>
+                    <p class="recommendation-content">
+                        根据张明远的画像特征,发现3位相似客户,沟通策略可复用率85%
+                    </p>
+                    <div class="recommendation-action">
+                        <span class="tag">高匹配度</span>
+                        <button class="action-btn">查看客户</button>
+                    </div>
+                </div>
+
+                <!-- 推荐卡片 2 -->
+                <div class="recommendation-card animated-card">
+                    <div class="card-header">
+                        <div class="card-icon" style="background: rgba(94, 114, 228, 0.15); color: #5e72e4;">
+                            <i class="fas fa-clock"></i>
+                        </div>
+                        <h3 class="card-title">最佳接触时机</h3>
+                    </div>
+                    <p class="recommendation-content">
+                        李思琪的下次最佳联系时间:明天上午10:00-11:30,接通率预测92%
+                    </p>
+                    <div class="recommendation-action">
+                        <span class="tag">高接通率</span>
+                        <button class="action-btn">加入日程</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <script>
+        // 模拟交互效果
+        document.querySelectorAll('.client-item').forEach(item => {
+            item.addEventListener('click', function() {
+                this.style.transform = 'scale(0.98)';
+                setTimeout(() => {
+                    this.style.transform = '';
+                    alert('进入客户详情页:' + this.querySelector('.client-name').textContent);
+                }, 200);
+            });
+        });
+        
+        // 分析按钮点击事件
+        document.querySelector('.btn-primary').addEventListener('click', function() {
+            const clientId = document.getElementById('client-id').value;
+            const clientName = document.getElementById('client-name').value;
+            const chatData = document.getElementById('chat-data').value;
+            
+            if(!clientId || !clientName || !chatData) {
+                alert('请填写完整的客户信息和聊天记录');
+                return;
+            }
+            
+            alert(`开始分析客户 ${clientName} (${clientId}) 的聊天记录...`);
+        });
+        
+        // 保存按钮点击事件
+        document.querySelector('.btn-secondary').addEventListener('click', function() {
+            const clientId = document.getElementById('client-id').value;
+            const clientName = document.getElementById('client-name').value;
+            const chatData = document.getElementById('chat-data').value;
+            
+            if(!clientId || !clientName || !chatData) {
+                alert('请填写完整的客户信息和聊天记录');
+                return;
+            }
+            
+            alert(`已保存客户 ${clientName} (${clientId}) 的信息和聊天记录`);
+        });
+    </script>
+</body>
+</html>

+ 1333 - 0
ai-assisant/demo/training.html

@@ -0,0 +1,1333 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>虚拟陪练舱 - 酒店全员移动工作平台</title>
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
+    <style>
+        :root {
+            --primary: #4285f4;
+            --primary-light: #8ab4f8;
+            --primary-dark: #0a192f;
+            --text-dark: #333333;
+            --text-light: #f8f9fa;
+            --card-bg: #ffffff;
+            --border-color: #eaeaea;
+            --shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+            --success: #34a853;
+            --warning: #f9ab00;
+            --danger: #ea4335;
+            --info: #4285f4;
+        }
+        
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+            font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
+        }
+        
+        body {
+            background-color: #f8fafc;
+            color: var(--text-dark);
+            line-height: 1.6;
+            padding-bottom: 40px;
+        }
+        
+        .container {
+            max-width: 480px;
+            margin: 0 auto;
+            padding: 0 16px;
+        }
+        
+        /* 头部导航 */
+        .header {
+            position: sticky;
+            top: 0;
+            background: rgba(255, 255, 255, 0.95);
+            backdrop-filter: blur(10px);
+            z-index: 100;
+            padding: 16px 0;
+            border-bottom: 1px solid var(--border-color);
+        }
+        
+        .nav-top {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+        }
+        
+        .back-btn {
+            background: none;
+            border: none;
+            font-size: 20px;
+            color: var(--text-dark);
+            cursor: pointer;
+        }
+        
+        .page-title {
+            font-size: 18px;
+            font-weight: 700;
+            color: var(--primary-dark);
+        }
+        
+        /* 场景选择卡 */
+        .section-title {
+            font-size: 16px;
+            font-weight: 600;
+            margin: 24px 0 12px;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+        }
+        
+        .section-title i {
+            margin-right: 8px;
+            color: var(--primary);
+        }
+        
+        .section-title .edit-btn {
+            background: none;
+            border: none;
+            color: var(--primary-dark);
+            font-size: 14px;
+            cursor: pointer;
+            display: flex;
+            align-items: center;
+            gap: 4px;
+        }
+        
+        .difficulty-tabs {
+            display: flex;
+            gap: 12px;
+            overflow-x: auto;
+            padding: 8px 0 16px;
+            -ms-overflow-style: none;
+            scrollbar-width: none;
+        }
+        
+        .difficulty-tabs::-webkit-scrollbar {
+            display: none;
+        }
+        
+        .tab {
+            flex: 0 0 auto;
+            padding: 8px 16px;
+            border-radius: 20px;
+            background-color: var(--card-bg);
+            border: 1px solid var(--border-color);
+            box-shadow: var(--shadow);
+            font-size: 14px;
+            cursor: pointer;
+            transition: all 0.3s ease;
+        }
+        
+        .tab.active {
+            background-color: var(--primary);
+            color: white;
+            border-color: var(--primary);
+            font-weight: 600;
+        }
+        
+        .customer-bubbles {
+            display: flex;
+            flex-wrap: wrap;
+            gap: 12px;
+            margin-top: 8px;
+        }
+        
+        .bubble {
+            padding: 10px 16px;
+            border-radius: 20px;
+            background-color: var(--card-bg);
+            border: 1px solid var(--border-color);
+            box-shadow: var(--shadow);
+            font-size: 14px;
+            cursor: pointer;
+            transition: all 0.2s ease;
+            position: relative;
+            display: flex;
+            align-items: center;
+            gap: 6px;
+        }
+        
+        .bubble.active {
+            background-color: var(--primary-dark);
+            color: white;
+            border-color: var(--primary-dark);
+        }
+        
+        .bubble .delete-btn {
+            display: none;
+            background: none;
+            border: none;
+            color: rgba(255, 255, 255, 0.7);
+            font-size: 12px;
+            cursor: pointer;
+        }
+        
+        .bubble.active .delete-btn {
+            display: block;
+        }
+        
+        .add-bubble {
+            padding: 10px 16px;
+            border-radius: 20px;
+            background-color: var(--card-bg);
+            border: 1px dashed var(--border-color);
+            font-size: 14px;
+            cursor: pointer;
+            display: flex;
+            align-items: center;
+            gap: 6px;
+            color: #94a3b8;
+        }
+        
+        /* 对话主界面 - 修改部分 */
+        .avatar-container {
+            display: flex;
+            justify-content: center;
+            margin: 20px 0;
+        }
+        
+        /* 客户头像缩小到100px */
+        .customer-avatar {
+            width: 100px;
+            height: 100px;
+            border-radius: 50%;
+            background: linear-gradient(135deg, var(--primary), var(--primary-dark));
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            position: relative;
+            overflow: hidden;
+            box-shadow: var(--shadow);
+            transition: all 0.3s ease;
+        }
+        
+        .customer-avatar::before {
+            content: "";
+            position: absolute;
+            width: 140px;
+            height: 140px;
+            background: radial-gradient(circle, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0) 70%);
+            border-radius: 50%;
+        }
+        
+        /* 头像图标缩小到36px */
+        .customer-avatar i {
+            font-size: 36px;
+            color: white;
+        }
+        
+        /* 聊天框高度增加到320px */
+        .conversation-container {
+            background-color: var(--card-bg);
+            border-radius: 20px;
+            box-shadow: var(--shadow);
+            padding: 16px;
+            margin: 16px 0;
+            height: 320px; /* 修改此处 */
+            overflow-y: auto;
+        }
+        
+        .message {
+            max-width: 80%;
+            padding: 12px;
+            margin-bottom: 16px;
+            border-radius: 18px;
+            position: relative;
+            animation: fadeIn 0.3s ease;
+        }
+        
+        @keyframes fadeIn {
+            from { opacity: 0; transform: translateY(10px); }
+            to { opacity: 1; transform: translateY(0); }
+        }
+        
+        .customer-message {
+            background-color: #f1f5f9;
+            border-bottom-left-radius: 4px;
+            align-self: flex-start;
+        }
+        
+        .user-message {
+            background-color: var(--primary);
+            color: white;
+            border-bottom-right-radius: 4px;
+            margin-left: auto;
+        }
+        
+        .input-area {
+            display: flex;
+            gap: 12px;
+            align-items: center;
+            background-color: var(--card-bg);
+            border-radius: 30px;
+            padding: 12px 20px;
+            box-shadow: var(--shadow);
+            margin-top: 16px;
+        }
+        
+        .voice-btn {
+            width: 48px;
+            height: 48px;
+            border-radius: 50%;
+            background-color: var(--primary);
+            color: white;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            cursor: pointer;
+            border: none;
+            font-size: 20px;
+            transition: all 0.3s ease;
+        }
+        
+        .voice-btn.active {
+            background-color: var(--danger);
+            color: white;
+            animation: pulse 1.5s infinite;
+        }
+        
+        @keyframes pulse {
+            0% { transform: scale(1); }
+            50% { transform: scale(1.05); }
+            100% { transform: scale(1); }
+        }
+        
+        .text-input {
+            flex: 1;
+            padding: 12px 16px;
+            border: 1px solid var(--border-color);
+            border-radius: 24px;
+            font-size: 16px;
+            outline: none;
+            transition: border-color 0.3s;
+        }
+        
+        .text-input:focus {
+            border-color: var(--primary);
+        }
+        
+        .send-btn {
+            width: 48px;
+            height: 48px;
+            border-radius: 50%;
+            background-color: var(--primary-dark);
+            color: white;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            cursor: pointer;
+            border: none;
+            font-size: 20px;
+        }
+        
+        /* 能力仪表盘 */
+        .dashboard {
+            background-color: var(--card-bg);
+            border-radius: 20px;
+            box-shadow: var(--shadow);
+            padding: 24px;
+            margin: 24px 0;
+            text-align: center;
+        }
+        
+        .progress-container {
+            position: relative;
+            width: 180px;
+            height: 180px;
+            margin: 0 auto 20px;
+        }
+        
+        .progress-circle {
+            width: 100%;
+            height: 100%;
+        }
+        
+        .progress-value {
+            position: absolute;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            font-size: 32px;
+            font-weight: 700;
+            color: var(--primary-dark);
+        }
+        
+        .skills-container {
+            display: flex;
+            flex-wrap: wrap;
+            justify-content: center;
+            gap: 16px;
+            margin-top: 20px;
+        }
+        
+        .skill {
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+        }
+        
+        .skill-progress {
+            width: 80px;
+            height: 6px;
+            background-color: #e2e8f0;
+            border-radius: 3px;
+            margin-top: 8px;
+            overflow: hidden;
+        }
+        
+        .skill-progress-fill {
+            height: 100%;
+            background-color: var(--primary);
+            border-radius: 3px;
+        }
+        
+        .skill-name {
+            font-size: 12px;
+            color: var(--text-dark);
+            margin-top: 4px;
+        }
+        
+        /* 存档面板 */
+        .report-card {
+            background-color: var(--card-bg);
+            border-radius: 20px;
+            box-shadow: var(--shadow);
+            padding: 20px;
+            margin-top: 24px;
+        }
+        
+        .report-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 16px;
+        }
+        
+        .report-title {
+            font-size: 18px;
+            font-weight: 700;
+            color: var(--primary-dark);
+        }
+        
+        .comparison {
+            display: flex;
+            align-items: center;
+            font-size: 14px;
+            color: var(--success);
+        }
+        
+        .comparison.down {
+            color: var(--danger);
+        }
+        
+        .comparison i {
+            margin-right: 4px;
+        }
+        
+        .report-summary {
+            font-size: 14px;
+            line-height: 1.7;
+            margin-bottom: 20px;
+        }
+        
+        .tags-container {
+            display: flex;
+            flex-wrap: wrap;
+            gap: 8px;
+            margin-bottom: 20px;
+        }
+        
+        .tag {
+            padding: 6px 12px;
+            background-color: #e2e8f0;
+            border-radius: 16px;
+            font-size: 12px;
+        }
+        
+        .actions {
+            display: flex;
+            gap: 12px;
+        }
+        
+        .action-btn {
+            flex: 1;
+            padding: 12px;
+            border-radius: 12px;
+            border: none;
+            font-weight: 600;
+            cursor: pointer;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            gap: 8px;
+            transition: all 0.3s ease;
+        }
+        
+        .view-btn {
+            background-color: var(--primary);
+            color: white;
+        }
+        
+        .history-btn {
+            background-color: var(--primary-dark);
+            color: white;
+        }
+        
+        /* 弹窗样式 */
+        .modal-overlay {
+            position: fixed;
+            top: 0;
+            left: 0;
+            right: 0;
+            bottom: 0;
+            background-color: rgba(0, 0, 0, 0.5);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            z-index: 1000;
+            opacity: 0;
+            pointer-events: none;
+            transition: opacity 0.3s ease;
+        }
+        
+        .modal-overlay.active {
+            opacity: 1;
+            pointer-events: all;
+        }
+        
+        .modal {
+            background-color: white;
+            border-radius: 16px;
+            width: 90%;
+            max-width: 500px;
+            max-height: 90vh;
+            overflow-y: auto;
+            padding: 24px;
+            box-shadow: var(--shadow);
+            transform: translateY(20px);
+            transition: transform 0.3s ease;
+        }
+        
+        .modal-overlay.active .modal {
+            transform: translateY(0);
+        }
+        
+        .modal-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 20px;
+            padding-bottom: 16px;
+            border-bottom: 1px solid var(--border-color);
+        }
+        
+        .modal-title {
+            font-size: 18px;
+            font-weight: 700;
+            color: var(--primary-dark);
+        }
+        
+        .close-modal {
+            background: none;
+            border: none;
+            font-size: 20px;
+            cursor: pointer;
+            color: #94a3b8;
+        }
+        
+        .modal-content {
+            margin-bottom: 24px;
+        }
+        
+        .report-detail {
+            background-color: white;
+            padding: 20px;
+            border-radius: 16px;
+        }
+        
+        .report-info {
+            display: flex;
+            justify-content: space-between;
+            margin-bottom: 20px;
+            padding-bottom: 15px;
+            border-bottom: 1px solid var(--border-color);
+        }
+        
+        .info-item {
+            display: flex;
+            flex-direction: column;
+        }
+        
+        .info-label {
+            font-size: 12px;
+            color: #64748b;
+            margin-bottom: 4px;
+        }
+        
+        .info-value {
+            font-size: 14px;
+            font-weight: 600;
+            color: var(--text-dark);
+        }
+        
+        .section {
+            margin-bottom: 24px;
+        }
+        
+        .section-title {
+            font-size: 16px;
+            font-weight: 600;
+            margin-bottom: 12px;
+            color: var(--primary-dark);
+            display: flex;
+            align-items: center;
+            gap: 8px;
+        }
+        
+        .section-title i {
+            color: var(--primary);
+        }
+        
+        .conversation-history {
+            background-color: #f8fafc;
+            border-radius: 12px;
+            padding: 16px;
+            max-height: 300px;
+            overflow-y: auto;
+        }
+        
+        .message-history {
+            padding: 10px 12px;
+            margin-bottom: 12px;
+            border-radius: 12px;
+            font-size: 14px;
+        }
+        
+        .customer-message-history {
+            background-color: #e2e8f0;
+            align-self: flex-start;
+            max-width: 80%;
+        }
+        
+        .user-message-history {
+            background-color: var(--primary-light);
+            color: var(--text-dark);
+            margin-left: auto;
+            max-width: 80%;
+        }
+        
+        .evaluation-content {
+            background-color: #f8fafc;
+            border-radius: 12px;
+            padding: 16px;
+            font-size: 14px;
+            line-height: 1.6;
+        }
+        
+        .summary-content {
+            background-color: #f8fafc;
+            border-radius: 12px;
+            padding: 16px;
+            font-size: 14px;
+            line-height: 1.6;
+        }
+        
+        .tag-list {
+            display: flex;
+            flex-wrap: wrap;
+            gap: 8px;
+            margin-top: 12px;
+        }
+        
+        .history-list {
+            background-color: #f8fafc;
+            border-radius: 12px;
+            padding: 16px;
+            max-height: 400px;
+            overflow-y: auto;
+        }
+        
+        .history-item {
+            padding: 12px;
+            background-color: white;
+            border-radius: 12px;
+            margin-bottom: 12px;
+            box-shadow: var(--shadow);
+            cursor: pointer;
+            transition: all 0.2s ease;
+        }
+        
+        .history-item:hover {
+            transform: translateY(-2px);
+            box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
+        }
+        
+        .history-header {
+            display: flex;
+            justify-content: space-between;
+            margin-bottom: 8px;
+        }
+        
+        .history-date {
+            font-weight: 600;
+            color: var(--primary-dark);
+        }
+        
+        .history-type {
+            background-color: var(--primary);
+            color: white;
+            padding: 2px 8px;
+            border-radius: 10px;
+            font-size: 12px;
+        }
+        
+        .history-summary {
+            font-size: 14px;
+            color: #64748b;
+            display: -webkit-box;
+            -webkit-line-clamp: 2;
+            -webkit-box-orient: vertical;
+            overflow: hidden;
+        }
+        
+        .no-history {
+            text-align: center;
+            padding: 20px;
+            color: #94a3b8;
+        }
+        
+        /* 评分标签 */
+        .score-tag {
+            display: inline-block;
+            padding: 4px 8px;
+            border-radius: 12px;
+            font-size: 12px;
+            font-weight: 600;
+            margin-top: 8px;
+        }
+        
+        .high-score {
+            background-color: #d1fae5;
+            color: #065f46;
+        }
+        
+        .medium-score {
+            background-color: #fef3c7;
+            color: #92400e;
+        }
+        
+        .low-score {
+            background-color: #fee2e2;
+            color: #b91c1c;
+        }
+        
+        /* 新增:修改说明 */
+        .modification-notice {
+            position: fixed;
+            bottom: 20px;
+            right: 20px;
+            background: var(--primary);
+            color: white;
+            padding: 10px 20px;
+            border-radius: 30px;
+            font-size: 14px;
+            box-shadow: 0 4px 15px rgba(0,0,0,0.2);
+            z-index: 1000;
+            animation: slideIn 0.5s ease-out;
+        }
+        
+        @keyframes slideIn {
+            from { transform: translateY(100px); opacity: 0; }
+            to { transform: translateY(0); opacity: 1; }
+        }
+    </style>
+</head>
+<body>
+    <div class="container">
+        <!-- 头部导航 -->
+        <header class="header">
+            <div class="nav-top">
+                <button class="back-btn">
+                    <i class="fas fa-arrow-left"></i>
+                </button>
+                <h1 class="page-title">虚拟陪练舱</h1>
+                <div></div> <!-- 占位元素 -->
+            </div>
+        </header>
+        
+        <!-- 场景选择卡 -->
+        <section>
+            <div class="section-title">
+                <div>
+                    <i class="fas fa-layer-group"></i>
+                    选择陪练场景
+                </div>
+                <button class="edit-btn" id="editCustomerBtn">
+                    <i class="fas fa-edit"></i>
+                    编辑分类
+                </button>
+            </div>
+            <div class="difficulty-tabs">
+                <div class="tab active">⭐ 初级</div>
+                <div class="tab">⭐⭐ 中级</div>
+                <div class="tab">⭐⭐⭐ 高级</div>
+                <div class="tab">专家挑战</div>
+            </div>
+            
+            <div class="customer-bubbles" id="customerBubbles">
+                <div class="bubble active">
+                    商务客户
+                    <button class="delete-btn">
+                        <i class="fas fa-times"></i>
+                    </button>
+                </div>
+                <div class="bubble">
+                    家庭客户
+                    <button class="delete-btn">
+                        <i class="fas fa-times"></i>
+                    </button>
+                </div>
+                <div class="bubble">
+                    VIP客户
+                    <button class="delete-btn">
+                        <i class="fas fa-times"></i>
+                    </button>
+                </div>
+                <div class="bubble">
+                    投诉客户
+                    <button class="delete-btn">
+                        <i class="fas fa-times"></i>
+                    </button>
+                </div>
+                <div class="bubble">
+                    团体客户
+                    <button class="delete-btn">
+                        <i class="fas fa-times"></i>
+                    </button>
+                </div>
+                <div class="add-bubble" id="addCustomerBtn">
+                    <i class="fas fa-plus"></i>
+                    添加类型
+                </div>
+            </div>
+        </section>
+        
+        <!-- 对话主界面 -->
+        <section>
+            <div class="avatar-container">
+                <div class="customer-avatar">
+                    <i class="fas fa-user-tie"></i>
+                </div>
+            </div>
+            
+            <div class="conversation-container" id="conversation">
+                <div class="message customer-message">
+                    您好,我想预订下周五的商务套房,你们有什么优惠吗?
+                </div>
+                <div class="message user-message">
+                    感谢您的咨询!我们目前有商务套餐优惠,包含早餐和会议室使用,您需要了解详情吗?
+                </div>
+                <div class="message customer-message">
+                    会议室可以容纳多少人?另外我需要延迟退房到下午4点。
+                </div>
+                <div class="message user-message">
+                    我们的商务套房会议室最多可容纳20人,延迟退房到下午4点需要额外支付50%的房费。
+                </div>
+                <div class="message customer-message">
+                    50%的费用太高了,我是贵酒店的黄金会员,能否提供免费延迟退房?
+                </div>
+                <div class="message user-message">
+                    感谢您的会员支持!根据黄金会员权益,我们可以提供免费延迟退房到下午2点,或者您可以选择支付额外费用延长到4点。
+                </div>
+                <div class="message customer-message">
+                    下午2点可能不太够,我下午3点有个重要会议。有没有折中方案?
+                </div>
+                <div class="message user-message">
+                    我理解您的情况。我们可以为您提供下午3点的延迟退房,只需额外支付25%的房费,这样您看可以接受吗?
+                </div>
+            </div>
+            
+            <div class="input-area">
+                <button class="voice-btn" id="voiceBtn">
+                    <i class="fas fa-microphone"></i>
+                </button>
+                <input type="text" class="text-input" placeholder="输入回复内容...">
+                <button class="send-btn">
+                    <i class="fas fa-paper-plane"></i>
+                </button>
+            </div>
+        </section>
+        
+        <!-- 能力仪表盘 -->
+        <section class="dashboard">
+            <h2 class="section-title">
+                <i class="fas fa-chart-line"></i>
+                能力评估
+            </h2>
+            
+            <div class="progress-container">
+                <svg class="progress-circle" viewBox="0 0 180 180">
+                    <circle cx="90" cy="90" r="80" stroke="#e2e8f0" stroke-width="10" fill="none" />
+                    <circle cx="90" cy="90" r="80" stroke="#4285f4" stroke-width="10" fill="none" 
+                            stroke-dasharray="502" stroke-dashoffset="150" stroke-linecap="round" />
+                </svg>
+                <div class="progress-value">86</div>
+            </div>
+            
+            <div class="skills-container">
+                <div class="skill">
+                    <div class="skill-name">反应力</div>
+                    <div class="skill-progress">
+                        <div class="skill-progress-fill" style="width: 90%"></div>
+                    </div>
+                </div>
+                <div class="skill">
+                    <div class="skill-name">话术</div>
+                    <div class="skill-progress">
+                        <div class="skill-progress-fill" style="width: 85%"></div>
+                    </div>
+                </div>
+                <div class="skill">
+                    <div class="skill-name">说服力</div>
+                    <div class="skill-progress">
+                        <div class="skill-progress-fill" style="width: 75%"></div>
+                    </div>
+                </div>
+                <div class="skill">
+                    <div class="skill-name">专业度</div>
+                    <div class="skill-progress">
+                        <div class="skill-progress-fill" style="width: 92%"></div>
+                    </div>
+                </div>
+            </div>
+        </section>
+        
+        <!-- 存档面板 -->
+        <section class="report-card">
+            <div class="report-header">
+                <h3 class="report-title">本次陪练报告</h3>
+                <div class="comparison">
+                    <i class="fas fa-arrow-up"></i>
+                    <span>12%</span>
+                </div>
+            </div>
+            
+            <p class="report-summary">
+                本次与商务客户的对话中,您展现了优秀的专业知识和反应能力。建议在价格谈判环节采用更积极的策略,成功率可提升15%。
+            </p>
+            
+            <div class="tags-container">
+                <div class="tag">商务场景</div>
+                <div class="tag">价格谈判</div>
+                <div class="tag">提升空间</div>
+            </div>
+            
+            <div class="actions">
+                <button class="action-btn view-btn" id="viewReportBtn">
+                    <i class="fas fa-file-alt"></i>
+                    查看完整报告
+                </button>
+                <button class="action-btn history-btn" id="historyReportBtn">
+                    <i class="fas fa-history"></i>
+                    历史报告
+                </button>
+            </div>
+        </section>
+    </div>
+    
+    <!-- 添加客户类型弹窗 -->
+    <div class="modal-overlay" id="addCustomerModal">
+        <div class="modal">
+            <div class="modal-header">
+                <h3 class="modal-title">添加客户类型</h3>
+                <button class="close-modal">
+                    <i class="fas fa-times"></i>
+                </button>
+            </div>
+            <div class="modal-content">
+                <div class="form-group">
+                    <label for="customerType">客户类型名称</label>
+                    <input type="text" id="customerType" placeholder="例如:新婚客户">
+                </div>
+            </div>
+            <div class="modal-actions">
+                <button class="modal-btn cancel-btn">取消</button>
+                <button class="modal-btn save-btn">保存</button>
+            </div>
+        </div>
+    </div>
+    
+    <!-- 完整报告弹窗 -->
+    <div class="modal-overlay" id="fullReportModal">
+        <div class="modal">
+            <div class="modal-header">
+                <h3 class="modal-title">陪练报告详情</h3>
+                <button class="close-modal">
+                    <i class="fas fa-times"></i>
+                </button>
+            </div>
+            <div class="modal-content">
+                <div class="report-detail">
+                    <div class="report-info">
+                        <div class="info-item">
+                            <span class="info-label">日期</span>
+                            <span class="info-value">2023年10月15日</span>
+                        </div>
+                        <div class="info-item">
+                            <span class="info-label">客户类型</span>
+                            <span class="info-value">商务客户</span>
+                        </div>
+                        <div class="info-item">
+                            <span class="info-label">难度</span>
+                            <span class="info-value">⭐⭐ 中级</span>
+                        </div>
+                    </div>
+                    
+                    <div class="section">
+                        <div class="section-title">
+                            <i class="fas fa-comments"></i>
+                            对话内容
+                        </div>
+                        <div class="conversation-history">
+                            <div class="message-history customer-message-history">
+                                您好,我想预订下周五的商务套房,你们有什么优惠吗?
+                            </div>
+                            <div class="message-history user-message-history">
+                                感谢您的咨询!我们目前有商务套餐优惠,包含早餐和会议室使用,您需要了解详情吗?
+                            </div>
+                            <div class="message-history customer-message-history">
+                                会议室可以容纳多少人?另外我需要延迟退房到下午4点。
+                            </div>
+                            <div class="message-history user-message-history">
+                                我们的商务套房会议室最多可容纳20人,延迟退房到下午4点需要额外支付50%的房费。
+                            </div>
+                            <div class="message-history customer-message-history">
+                                50%的费用太高了,我是贵酒店的黄金会员,能否提供免费延迟退房?
+                            </div>
+                        </div>
+                    </div>
+                    
+                    <div class="section">
+                        <div class="section-title">
+                            <i class="fas fa-star"></i>
+                            能力评价
+                        </div>
+                        <div class="evaluation-content">
+                            <p>您在本轮陪练中展现了出色的专业素养和服务意识:</p>
+                            <ul style="margin-top: 12px; padding-left: 20px;">
+                                <li>反应速度优秀,对客户需求理解准确</li>
+                                <li>专业知识扎实,准确提供了会议室容量信息</li>
+                                <li>会员政策运用得当,但未能灵活处理客户特殊需求</li>
+                                <li>建议提升价格谈判技巧,提供更多替代方案</li>
+                            </ul>
+                            <div class="score-tag high-score">综合评分: 86/100</div>
+                        </div>
+                    </div>
+                    
+                    <div class="section">
+                        <div class="section-title">
+                            <i class="fas fa-lightbulb"></i>
+                            总结方法
+                        </div>
+                        <div class="summary-content">
+                            <p>针对商务客户的价格敏感需求,建议采用以下策略:</p>
+                            <ol style="margin-top: 12px; padding-left: 20px;">
+                                <li>强调会员权益价值,提供阶梯式延迟退房方案</li>
+                                <li>捆绑销售会议室与客房服务,提高整体收益</li>
+                                <li>准备2-3个替代方案,满足不同预算需求</li>
+                                <li>主动提供增值服务(如免费打印、咖啡服务)提升客户体验</li>
+                            </ol>
+                            <div class="tag-list">
+                                <div class="tag">商务谈判</div>
+                                <div class="tag">会员权益</div>
+                                <div class="tag">价格策略</div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    
+    <!-- 历史报告弹窗 -->
+    <div class="modal-overlay" id="historyReportModal">
+        <div class="modal">
+            <div class="modal-header">
+                <h3 class="modal-title">历史陪练报告</h3>
+                <button class="close-modal">
+                    <i class="fas fa-times"></i>
+                </button>
+            </div>
+            <div class="modal-content">
+                <div class="history-list">
+                    <div class="history-item" data-id="1">
+                        <div class="history-header">
+                            <span class="history-date">2023年10月15日 14:30</span>
+                            <span class="history-type">商务客户</span>
+                        </div>
+                        <div class="history-summary">
+                            本次与商务客户的对话中,您展现了优秀的专业知识和反应能力。建议在价格谈判环节采用更积极的策略。
+                        </div>
+                    </div>
+                    <div class="history-item" data-id="2">
+                        <div class="history-header">
+                            <span class="history-date">2023年10月12日 10:15</span>
+                            <span class="history-type">投诉客户</span>
+                        </div>
+                        <div class="history-summary">
+                            处理客户投诉时展现了良好的同理心,但解决方案不够全面,建议加强问题解决能力训练。
+                        </div>
+                    </div>
+                    <div class="history-item" data-id="3">
+                        <div class="history-header">
+                            <span class="history-date">2023年10月10日 16:45</span>
+                            <span class="history-type">VIP客户</span>
+                        </div>
+                        <div class="history-summary">
+                            为VIP客户提供了个性化服务方案,展现了出色的服务意识,但在附加服务推荐上略显保守。
+                        </div>
+                    </div>
+                    <div class="history-item" data-id="4">
+                        <div class="history-header">
+                            <span class="history-date">2023年10月8日 09:30</span>
+                            <span class="history-type">家庭客户</span>
+                        </div>
+                        <div class="history-summary">
+                            为家庭客户推荐了亲子套餐,但未能有效突出套餐价值,建议加强销售话术训练。
+                        </div>
+                    </div>
+                    <div class="history-item" data-id="5">
+                        <div class="history-header">
+                            <span class="history-date">2023年10月5日 11:20</span>
+                            <span class="history-type">团体客户</span>
+                        </div>
+                        <div class="history-summary">
+                            处理团体预订时展现了良好的组织能力,但在协调不同需求方面还有提升空间。
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    
+    <!-- 修改说明 -->
+    <div class="modification-notice" id="modNotice">
+        已优化:聊天框高度增加,客户头像缩小
+    </div>
+    
+    <script>
+        // 语音按钮交互
+        const voiceBtn = document.getElementById('voiceBtn');
+        voiceBtn.addEventListener('click', function() {
+            this.classList.toggle('active');
+            
+            if (this.classList.contains('active')) {
+                this.innerHTML = '<i class="fas fa-square"></i>';
+            } else {
+                this.innerHTML = '<i class="fas fa-microphone"></i>';
+            }
+        });
+        
+        // 模拟对话
+        const conversation = document.getElementById('conversation');
+        
+        // 添加新消息的函数
+        function addMessage(text, isCustomer = false) {
+            const message = document.createElement('div');
+            message.classList.add('message');
+            message.classList.add(isCustomer ? 'customer-message' : 'user-message');
+            message.textContent = text;
+            
+            conversation.appendChild(message);
+            conversation.scrollTop = conversation.scrollHeight;
+        }
+        
+        // 模拟回复
+        document.querySelector('.send-btn').addEventListener('click', function() {
+            const input = document.querySelector('.text-input');
+            if (input.value.trim() !== '') {
+                addMessage(input.value);
+                input.value = '';
+                
+                // 模拟AI回复
+                setTimeout(() => {
+                    addMessage("听起来不错,我会考虑这个方案。能提供一份详细报价吗?", true);
+                }, 1000);
+            }
+        });
+        
+        // 按Enter键发送消息
+        document.querySelector('.text-input').addEventListener('keypress', function(e) {
+            if (e.key === 'Enter') {
+                document.querySelector('.send-btn').click();
+            }
+        });
+        
+        // 气泡选择效果
+        document.querySelectorAll('.bubble').forEach(bubble => {
+            bubble.addEventListener('click', function(e) {
+                if (e.target.classList.contains('delete-btn')) return;
+                
+                document.querySelectorAll('.bubble').forEach(b => b.classList.remove('active'));
+                this.classList.add('active');
+            });
+        });
+        
+        // 难度标签选择效果
+        document.querySelectorAll('.tab').forEach(tab => {
+            tab.addEventListener('click', function() {
+                document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
+                this.classList.add('active');
+            });
+        });
+        
+        // 客户类型编辑功能
+        const editBtn = document.getElementById('editCustomerBtn');
+        const addBtn = document.getElementById('addCustomerBtn');
+        const modal = document.getElementById('addCustomerModal');
+        const closeModal = document.querySelector('.close-modal');
+        const cancelBtn = document.querySelector('.cancel-btn');
+        const saveBtn = document.querySelector('.save-btn');
+        const bubblesContainer = document.getElementById('customerBubbles');
+        
+        // 显示编辑模式
+        editBtn.addEventListener('click', function() {
+            const isEditing = this.classList.toggle('editing');
+            
+            if (isEditing) {
+                this.innerHTML = '<i class="fas fa-check"></i> 完成编辑';
+                document.querySelectorAll('.delete-btn').forEach(btn => {
+                    btn.style.display = 'block';
+                });
+            } else {
+                this.innerHTML = '<i class="fas fa-edit"></i> 编辑分类';
+                document.querySelectorAll('.delete-btn').forEach(btn => {
+                    btn.style.display = 'none';
+                });
+            }
+        });
+        
+        // 删除客户类型
+        document.querySelectorAll('.delete-btn').forEach(btn => {
+            btn.addEventListener('click', function(e) {
+                e.stopPropagation();
+                const bubble = this.parentElement;
+                if (document.querySelectorAll('.bubble').length > 1) {
+                    bubble.remove();
+                } else {
+                    alert('至少需要保留一个客户类型');
+                }
+            });
+        });
+        
+        // 打开添加客户类型弹窗
+        addBtn.addEventListener('click', function() {
+            modal.classList.add('active');
+        });
+        
+        // 关闭弹窗
+        function closeModalFunc() {
+            modal.classList.remove('active');
+            document.getElementById('customerType').value = '';
+        }
+        
+        closeModal.addEventListener('click', closeModalFunc);
+        cancelBtn.addEventListener('click', closeModalFunc);
+        
+        // 保存新客户类型
+        saveBtn.addEventListener('click', function() {
+            const typeName = document.getElementById('customerType').value.trim();
+            if (typeName) {
+                const newBubble = document.createElement('div');
+                newBubble.className = 'bubble';
+                newBubble.innerHTML = `
+                    ${typeName}
+                    <button class="delete-btn">
+                        <i class="fas fa-times"></i>
+                    </button>
+                `;
+                
+                bubblesContainer.insertBefore(newBubble, addBtn);
+                
+                // 为新气泡添加事件
+                newBubble.addEventListener('click', function(e) {
+                    if (e.target.classList.contains('delete-btn')) return;
+                    
+                    document.querySelectorAll('.bubble').forEach(b => b.classList.remove('active'));
+                    this.classList.add('active');
+                });
+                
+                // 为新删除按钮添加事件
+                newBubble.querySelector('.delete-btn').addEventListener('click', function(e) {
+                    e.stopPropagation();
+                    const bubble = this.parentElement;
+                    if (document.querySelectorAll('.bubble').length > 1) {
+                        bubble.remove();
+                    } else {
+                        alert('至少需要保留一个客户类型');
+                    }
+                });
+                
+                closeModalFunc();
+            } else {
+                alert('请输入客户类型名称');
+            }
+        });
+        
+        // 报告弹窗功能
+        const viewReportBtn = document.getElementById('viewReportBtn');
+        const historyReportBtn = document.getElementById('historyReportBtn');
+        const fullReportModal = document.getElementById('fullReportModal');
+        const historyReportModal = document.getElementById('historyReportModal');
+        
+        // 打开完整报告
+        viewReportBtn.addEventListener('click', function() {
+            fullReportModal.classList.add('active');
+        });
+        
+        // 打开历史报告
+        historyReportBtn.addEventListener('click', function() {
+            historyReportModal.classList.add('active');
+        });
+        
+        // 关闭报告弹窗
+        document.querySelectorAll('.close-modal').forEach(btn => {
+            btn.addEventListener('click', function() {
+                this.closest('.modal-overlay').classList.remove('active');
+            });
+        });
+        
+        // 点击历史报告项显示详情
+        document.querySelectorAll('.history-item').forEach(item => {
+            item.addEventListener('click', function() {
+                const reportId = this.getAttribute('data-id');
+                historyReportModal.classList.remove('active');
+                
+                // 模拟加载报告详情
+                setTimeout(() => {
+                    fullReportModal.classList.add('active');
+                }, 300);
+            });
+        });
+        
+        // 点击模态框外部关闭弹窗
+        document.querySelectorAll('.modal-overlay').forEach(overlay => {
+            overlay.addEventListener('click', function(e) {
+                if (e.target === this) {
+                    this.classList.remove('active');
+                }
+            });
+        });
+        
+        // 显示修改通知
+        setTimeout(() => {
+            document.getElementById('modNotice').style.display = 'none';
+        }, 3000);
+    </script>
+</body>
+</html>

+ 126 - 2
ai-assisant/package-lock.json

@@ -8,12 +8,21 @@
       "name": "ai-assisant",
       "name": "ai-assisant",
       "version": "0.0.0",
       "version": "0.0.0",
       "dependencies": {
       "dependencies": {
+        "@angular/cdk": "^20.0.4",
         "@angular/common": "^20.0.0",
         "@angular/common": "^20.0.0",
         "@angular/compiler": "^20.0.0",
         "@angular/compiler": "^20.0.0",
         "@angular/core": "^20.0.0",
         "@angular/core": "^20.0.0",
         "@angular/forms": "^20.0.0",
         "@angular/forms": "^20.0.0",
+        "@angular/material": "^20.0.4",
         "@angular/platform-browser": "^20.0.0",
         "@angular/platform-browser": "^20.0.0",
         "@angular/router": "^20.0.0",
         "@angular/router": "^20.0.0",
+        "@fortawesome/angular-fontawesome": "^2.0.1",
+        "@fortawesome/fontawesome-free": "^6.7.2",
+        "@fortawesome/fontawesome-svg-core": "^6.7.2",
+        "@fortawesome/free-solid-svg-icons": "^6.7.2",
+        "animate.css": "^4.1.1",
+        "chart.js": "^4.5.0",
+        "modern-css-reset": "^1.4.0",
         "rxjs": "~7.8.0",
         "rxjs": "~7.8.0",
         "tslib": "^2.3.0",
         "tslib": "^2.3.0",
         "zone.js": "~0.15.0"
         "zone.js": "~0.15.0"
@@ -208,6 +217,21 @@
         }
         }
       }
       }
     },
     },
+    "node_modules/@angular/cdk": {
+      "version": "20.0.4",
+      "resolved": "https://registry.npmmirror.com/@angular/cdk/-/cdk-20.0.4.tgz",
+      "integrity": "sha512-NCUuw0qQXwawLsT14JHApNB9or3XGs7D1pWXlOIix/fKqzHVfi4un9xHmpjH2Q1uCiwonuak7fDof8B+IXhbug==",
+      "license": "MIT",
+      "dependencies": {
+        "parse5": "^7.1.2",
+        "tslib": "^2.3.0"
+      },
+      "peerDependencies": {
+        "@angular/common": "^20.0.0 || ^21.0.0",
+        "@angular/core": "^20.0.0 || ^21.0.0",
+        "rxjs": "^6.5.3 || ^7.4.0"
+      }
+    },
     "node_modules/@angular/cli": {
     "node_modules/@angular/cli": {
       "version": "20.0.4",
       "version": "20.0.4",
       "resolved": "https://registry.npmmirror.com/@angular/cli/-/cli-20.0.4.tgz",
       "resolved": "https://registry.npmmirror.com/@angular/cli/-/cli-20.0.4.tgz",
@@ -454,6 +478,23 @@
         "rxjs": "^6.5.3 || ^7.4.0"
         "rxjs": "^6.5.3 || ^7.4.0"
       }
       }
     },
     },
+    "node_modules/@angular/material": {
+      "version": "20.0.4",
+      "resolved": "https://registry.npmmirror.com/@angular/material/-/material-20.0.4.tgz",
+      "integrity": "sha512-ET+znnyOVjBezHsjy7U42/88JPl9Mhumvf01gMBN8mNcaoSpeM4cc2uKBg30/3YzykKIsjXtvUJj/PaTujmJAQ==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "peerDependencies": {
+        "@angular/cdk": "20.0.4",
+        "@angular/common": "^20.0.0 || ^21.0.0",
+        "@angular/core": "^20.0.0 || ^21.0.0",
+        "@angular/forms": "^20.0.0 || ^21.0.0",
+        "@angular/platform-browser": "^20.0.0 || ^21.0.0",
+        "rxjs": "^6.5.3 || ^7.4.0"
+      }
+    },
     "node_modules/@angular/platform-browser": {
     "node_modules/@angular/platform-browser": {
       "version": "20.0.5",
       "version": "20.0.5",
       "resolved": "https://registry.npmmirror.com/@angular/platform-browser/-/platform-browser-20.0.5.tgz",
       "resolved": "https://registry.npmmirror.com/@angular/platform-browser/-/platform-browser-20.0.5.tgz",
@@ -1212,6 +1253,61 @@
         "node": ">=18"
         "node": ">=18"
       }
       }
     },
     },
+    "node_modules/@fortawesome/angular-fontawesome": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/@fortawesome/angular-fontawesome/-/angular-fontawesome-2.0.1.tgz",
+      "integrity": "sha512-IdklZkuw+WS2GQWhFnr1EX/tOALnrKaj4YGnUmPaUg2Uf+Amj8Xi+M/qDrr915YJ5MaDxd9tZ1kqOHRcvQqq2A==",
+      "license": "MIT",
+      "dependencies": {
+        "@fortawesome/fontawesome-svg-core": "^6.7.2",
+        "tslib": "^2.8.1"
+      },
+      "peerDependencies": {
+        "@angular/core": "^20.0.0"
+      }
+    },
+    "node_modules/@fortawesome/fontawesome-common-types": {
+      "version": "6.7.2",
+      "resolved": "https://registry.npmmirror.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz",
+      "integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@fortawesome/fontawesome-free": {
+      "version": "6.7.2",
+      "resolved": "https://registry.npmmirror.com/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz",
+      "integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==",
+      "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@fortawesome/fontawesome-svg-core": {
+      "version": "6.7.2",
+      "resolved": "https://registry.npmmirror.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz",
+      "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==",
+      "license": "MIT",
+      "dependencies": {
+        "@fortawesome/fontawesome-common-types": "6.7.2"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@fortawesome/free-solid-svg-icons": {
+      "version": "6.7.2",
+      "resolved": "https://registry.npmmirror.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz",
+      "integrity": "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==",
+      "license": "(CC-BY-4.0 AND MIT)",
+      "dependencies": {
+        "@fortawesome/fontawesome-common-types": "6.7.2"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/@inquirer/checkbox": {
     "node_modules/@inquirer/checkbox": {
       "version": "4.1.8",
       "version": "4.1.8",
       "resolved": "https://registry.npmmirror.com/@inquirer/checkbox/-/checkbox-4.1.8.tgz",
       "resolved": "https://registry.npmmirror.com/@inquirer/checkbox/-/checkbox-4.1.8.tgz",
@@ -1653,6 +1749,12 @@
         "@jridgewell/sourcemap-codec": "^1.4.14"
         "@jridgewell/sourcemap-codec": "^1.4.14"
       }
       }
     },
     },
+    "node_modules/@kurkle/color": {
+      "version": "0.3.4",
+      "resolved": "https://registry.npmmirror.com/@kurkle/color/-/color-0.3.4.tgz",
+      "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
+      "license": "MIT"
+    },
     "node_modules/@listr2/prompt-adapter-inquirer": {
     "node_modules/@listr2/prompt-adapter-inquirer": {
       "version": "2.0.22",
       "version": "2.0.22",
       "resolved": "https://registry.npmmirror.com/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.22.tgz",
       "resolved": "https://registry.npmmirror.com/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.22.tgz",
@@ -3365,6 +3467,12 @@
         }
         }
       }
       }
     },
     },
+    "node_modules/animate.css": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmmirror.com/animate.css/-/animate.css-4.1.1.tgz",
+      "integrity": "sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ==",
+      "license": "MIT"
+    },
     "node_modules/ansi-escapes": {
     "node_modules/ansi-escapes": {
       "version": "4.3.2",
       "version": "4.3.2",
       "resolved": "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
       "resolved": "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
@@ -3811,6 +3919,18 @@
       "dev": true,
       "dev": true,
       "license": "MIT"
       "license": "MIT"
     },
     },
+    "node_modules/chart.js": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmmirror.com/chart.js/-/chart.js-4.5.0.tgz",
+      "integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@kurkle/color": "^0.3.0"
+      },
+      "engines": {
+        "pnpm": ">=8"
+      }
+    },
     "node_modules/chokidar": {
     "node_modules/chokidar": {
       "version": "4.0.3",
       "version": "4.0.3",
       "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz",
       "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz",
@@ -6492,6 +6612,12 @@
         "mkdirp": "bin/cmd.js"
         "mkdirp": "bin/cmd.js"
       }
       }
     },
     },
+    "node_modules/modern-css-reset": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmmirror.com/modern-css-reset/-/modern-css-reset-1.4.0.tgz",
+      "integrity": "sha512-0crZmSFmrxkI7159rvQWjpDhy0u4+Awg/iOycJdlVn0RSeft/a+6BrQHR3IqvmdK25sqt0o6Z5Ap7cWgUee2rw==",
+      "license": "MIT"
+    },
     "node_modules/mrmime": {
     "node_modules/mrmime": {
       "version": "2.0.1",
       "version": "2.0.1",
       "resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-2.0.1.tgz",
       "resolved": "https://registry.npmmirror.com/mrmime/-/mrmime-2.0.1.tgz",
@@ -7018,7 +7144,6 @@
       "version": "7.3.0",
       "version": "7.3.0",
       "resolved": "https://registry.npmmirror.com/parse5/-/parse5-7.3.0.tgz",
       "resolved": "https://registry.npmmirror.com/parse5/-/parse5-7.3.0.tgz",
       "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
       "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
-      "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "entities": "^6.0.0"
         "entities": "^6.0.0"
@@ -7072,7 +7197,6 @@
       "version": "6.0.1",
       "version": "6.0.1",
       "resolved": "https://registry.npmmirror.com/entities/-/entities-6.0.1.tgz",
       "resolved": "https://registry.npmmirror.com/entities/-/entities-6.0.1.tgz",
       "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
       "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
-      "dev": true,
       "license": "BSD-2-Clause",
       "license": "BSD-2-Clause",
       "engines": {
       "engines": {
         "node": ">=0.12"
         "node": ">=0.12"

+ 9 - 0
ai-assisant/package.json

@@ -20,12 +20,21 @@
   },
   },
   "private": true,
   "private": true,
   "dependencies": {
   "dependencies": {
+    "@angular/cdk": "^20.0.4",
     "@angular/common": "^20.0.0",
     "@angular/common": "^20.0.0",
     "@angular/compiler": "^20.0.0",
     "@angular/compiler": "^20.0.0",
     "@angular/core": "^20.0.0",
     "@angular/core": "^20.0.0",
     "@angular/forms": "^20.0.0",
     "@angular/forms": "^20.0.0",
+    "@angular/material": "^20.0.4",
     "@angular/platform-browser": "^20.0.0",
     "@angular/platform-browser": "^20.0.0",
     "@angular/router": "^20.0.0",
     "@angular/router": "^20.0.0",
+    "@fortawesome/angular-fontawesome": "^2.0.1",
+    "@fortawesome/fontawesome-free": "^6.7.2",
+    "@fortawesome/fontawesome-svg-core": "^6.7.2",
+    "@fortawesome/free-solid-svg-icons": "^6.7.2",
+    "animate.css": "^4.1.1",
+    "chart.js": "^4.5.0",
+    "modern-css-reset": "^1.4.0",
     "rxjs": "~7.8.0",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",
     "tslib": "^2.3.0",
     "zone.js": "~0.15.0"
     "zone.js": "~0.15.0"

+ 1 - 1
ai-assisant/src/app/app.html

@@ -10,4 +10,4 @@
 <button routerLink='/crm/mobile/image'>
 <button routerLink='/crm/mobile/image'>
     导航到数据训练
     导航到数据训练
 </button>
 </button>
-<router-outlet></router-outlet>
+<router-outlet></router-outlet>

+ 11 - 2
ai-assisant/src/app/app.routes.ts

@@ -1,8 +1,17 @@
 import { Routes } from '@angular/router';
 import { Routes } from '@angular/router';
 
 
 export const routes: Routes = [
 export const routes: Routes = [
-    {
+  {
     path: 'crm/mobile',
     path: 'crm/mobile',
     loadChildren: () => import('../modules/crm/mobile/mobile.routes').then(m => m.MOBILE_ROUTES)
     loadChildren: () => import('../modules/crm/mobile/mobile.routes').then(m => m.MOBILE_ROUTES)
+  },
+  {
+    path: '',
+    redirectTo: 'crm/mobile/home', // 默认重定向到 CRM 首页
+    pathMatch: 'full'
+  },
+  {
+    path: '**',
+    redirectTo: 'crm/mobile/home' // 处理 404 错误
   }
   }
-];
+];

+ 20 - 2
ai-assisant/src/app/app.ts

@@ -1,12 +1,30 @@
 import { Component } from '@angular/core';
 import { Component } from '@angular/core';
 import { RouterModule, RouterOutlet } from '@angular/router';
 import { RouterModule, RouterOutlet } from '@angular/router';
+ import { NgModule } from '@angular/core';
+ import { FormsModule } from '@angular/forms';
+
+ import { PageCrmTraining } from '../modules/crm/mobile/page-crm-training/page-crm-training';
+ import { TrainingReportsComponent } from '../modules/crm/mobile/page-crm-training/report-viewer.component';
 
 
 @Component({
 @Component({
   selector: 'app-root',
   selector: 'app-root',
-  imports: [RouterOutlet,RouterModule],
+  standalone: true,
+  imports: [RouterOutlet, RouterModule,],
   templateUrl: './app.html',
   templateUrl: './app.html',
   styleUrl: './app.scss'
   styleUrl: './app.scss'
 })
 })
 export class App {
 export class App {
-  protected title = 'ai-assisant';
+  protected title = 'ai-assistant';
 }
 }
+ @NgModule({
+  imports: [
+     FormsModule,
+    PageCrmTraining,
+     TrainingReportsComponent,
+    // 其他模块...
+  ],
+  declarations: [
+  ]
+
+})
+ export class CrmModule { }

+ 4 - 0
ai-assisant/src/index.html

@@ -6,7 +6,11 @@
   <base href="/">
   <base href="/">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
+  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
+  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
+  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
 </head>
 </head>
+<body class="mat-typography">
 <body>
 <body>
   <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.7.2/css/all.min.css">
   <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.7.2/css/all.min.css">
   <!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> -->
   <!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> -->

+ 487 - 0
ai-assisant/src/lib/ncloud.ts

@@ -0,0 +1,487 @@
+// CloudObject.ts
+
+let serverURL = `https://dev.fmode.cn/parse`;
+if (location.protocol == "http:") {
+    serverURL = `http://dev.fmode.cn:1337/parse`;
+}
+
+export class CloudObject {
+    className: string;
+    id: string | undefined = undefined;
+    createdAt: any;
+    updatedAt: any;
+    data: Record<string, any> = {};
+
+    constructor(className: string) {
+        this.className = className;
+    }
+
+    toPointer() {
+        return { "__type": "Pointer", "className": this.className, "objectId": this.id };
+    }
+
+    set(json: Record<string, any>) {
+        Object.keys(json).forEach(key => {
+            if (["objectId", "id", "createdAt", "updatedAt"].indexOf(key) > -1) {
+                return;
+            }
+            this.data[key] = json[key];
+        });
+    }
+
+    get(key: string) {
+        return this.data[key] || null;
+    }
+
+    async save() {
+        let method = "POST";
+        let url = serverURL + `/classes/${this.className}`;
+
+        // 更新
+        if (this.id) {
+            url += `/${this.id}`;
+            method = "PUT";
+        }
+
+        const body = JSON.stringify(this.data);
+        const response = await fetch(url, {
+            headers: {
+                "content-type": "application/json;charset=UTF-8",
+                "x-parse-application-id": "dev"
+            },
+            body: body,
+            method: method,
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+        }
+        if (result?.objectId) {
+            this.id = result?.objectId;
+        }
+        return this;
+    }
+
+    async destroy() {
+        if (!this.id) return;
+        const response = await fetch(serverURL + `/classes/${this.className}/${this.id}`, {
+            headers: {
+                "x-parse-application-id": "dev"
+            },
+            body: null,
+            method: "DELETE",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result) {
+            this.id = undefined;
+        }
+        return true;
+    }
+}
+
+// CloudQuery.ts
+export class CloudQuery {
+    className: string;
+    queryParams: Record<string, any> = { where: {} };
+
+    constructor(className: string) {
+        this.className = className;
+    }
+
+    include(...fileds: string[]) {
+        this.queryParams["include"] = fileds;
+    }
+    greaterThan(key: string, value: any) {
+        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
+        this.queryParams["where"][key]["$gt"] = value;
+    }
+
+    greaterThanAndEqualTo(key: string, value: any) {
+        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
+        this.queryParams["where"][key]["$gte"] = value;
+    }
+
+    lessThan(key: string, value: any) {
+        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
+        this.queryParams["where"][key]["$lt"] = value;
+    }
+
+    lessThanAndEqualTo(key: string, value: any) {
+        if (!this.queryParams["where"][key]) this.queryParams["where"][key] = {};
+        this.queryParams["where"][key]["$lte"] = value;
+    }
+
+    equalTo(key: string, value: any) {
+        if (!this.queryParams["where"]) this.queryParams["where"] = {};
+        this.queryParams["where"][key] = value;
+    }
+    //新增代码
+    skip(count: number) {
+        this.queryParams["skip"] = count;
+        return this;
+    }
+
+    limit(count: number) {
+        this.queryParams["limit"] = count;
+        return this;
+    }
+
+    orderBy(field: string, direction: 'asc' | 'desc' = 'asc') {
+        const prefix = direction === 'desc' ? '-' : '';
+        this.queryParams["order"] = `${prefix}${field}`;
+        return this;
+    }
+
+    async count(): Promise<number> {
+        const url = serverURL + `/classes/${this.className}?count=1&limit=0`;
+        
+        const response = await fetch(url, {
+            headers: {
+                "x-parse-application-id": "dev"
+            },
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const json = await response?.json();
+        return json?.count || 0;
+    }
+
+
+    //
+    async get(id: string) {
+        const url = serverURL + `/classes/${this.className}/${id}?`;
+
+        const response = await fetch(url, {
+            headers: {
+                "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+                "x-parse-application-id": "dev"
+            },
+            body: null,
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const json = await response?.json();
+        if (json) {
+            let existsObject = this.dataToObj(json)
+            return existsObject;
+        }
+        return null
+    }
+
+    async find(): Promise<Array<CloudObject>> {
+        let url = serverURL + `/classes/${this.className}?`;
+
+        let queryStr = ``
+        Object.keys(this.queryParams).forEach(key => {
+            let paramStr = JSON.stringify(this.queryParams[key]);
+            if (key == "include") {
+                paramStr = this.queryParams[key]?.join(",")
+            }
+            if (queryStr) {
+                url += `${key}=${paramStr}`;
+            } else {
+                url += `&${key}=${paramStr}`;
+            }
+        })
+        // if (Object.keys(this.queryParams["where"]).length) {
+
+        // }
+
+        const response = await fetch(url, {
+            headers: {
+                "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+                "x-parse-application-id": "dev"
+            },
+            body: null,
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const json = await response?.json();
+        let list = json?.results || []
+        let objList = list.map((item: any) => this.dataToObj(item))
+        return objList || [];
+    }
+
+
+    async first() {
+        let url = serverURL + `/classes/${this.className}?`;
+
+        if (Object.keys(this.queryParams["where"]).length) {
+            const whereStr = JSON.stringify(this.queryParams["where"]);
+            url += `where=${whereStr}&limit=1`;
+        }
+
+        const response = await fetch(url, {
+            headers: {
+                "if-none-match": "W/\"1f0-ghxH2EwTk6Blz0g89ivf2adBDKY\"",
+                "x-parse-application-id": "dev"
+            },
+            body: null,
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const json = await response?.json();
+        const exists = json?.results?.[0] || null;
+        if (exists) {
+            let existsObject = this.dataToObj(exists)
+            return existsObject;
+        }
+        return null
+    }
+
+    dataToObj(exists: any): CloudObject {
+        let existsObject = new CloudObject(this.className);
+        Object.keys(exists).forEach(key => {
+            if (exists[key]?.__type == "Object") {
+                exists[key] = this.dataToObj(exists[key])
+            }
+        })
+        existsObject.set(exists);
+        existsObject.id = exists.objectId;
+        existsObject.createdAt = exists.createdAt;
+        existsObject.updatedAt = exists.updatedAt;
+        return existsObject;
+    }
+}
+
+// CloudUser.ts
+export class CloudUser extends CloudObject {
+    constructor() {
+        super("_User"); // 假设用户类在Parse中是"_User"
+        // 读取用户缓存信息
+        let userCacheStr = localStorage.getItem("NCloud/dev/User")
+        if (userCacheStr) {
+            let userData = JSON.parse(userCacheStr)
+            // 设置用户信息
+            this.id = userData?.objectId;
+            this.sessionToken = userData?.sessionToken;
+            this.set(userData); // 保存用户数据
+        }
+    }
+
+    sessionToken: string | null = ""
+    /** 获取当前用户信息 */
+    async current() {
+        if (!this.sessionToken) {
+            console.error("用户未登录");
+            return null;
+        }
+        // 补充:从服务器拉取最新数据(可选,确保数据新鲜)
+           try {
+    const response = await fetch(serverURL + `/users/me`, {
+      headers: {
+        "x-parse-application-id": "dev",
+        "x-parse-session-token": this.sessionToken
+      },
+      method: "GET"
+    });
+
+    if (!response.ok) {
+      throw new Error("获取用户信息失败");
+    }
+
+    const result = await response.json();
+    this.set(result); // 接口成功时更新数据
+    return this;
+  } catch (error) {
+    console.error("current() 调用失败:", error);
+    this.clearUserCache(); // 出错时清除缓存,避免使用旧数据
+    return null;
+  }
+        return this;
+        // const response = await fetch(serverURL + `/users/me`, {
+        //     headers: {
+        //         "x-parse-application-id": "dev",
+        //         "x-parse-session-token": this.sessionToken // 使用sessionToken进行身份验证
+        //     },
+        //     method: "GET"
+        // });
+
+        // const result = await response?.json();
+        // if (result?.error) {
+        //     console.error(result?.error);
+        //     return null;
+        // }
+        // return result;
+    }
+
+    /** 登录 */
+    async login(username: string, password: string): Promise<CloudUser | null> {
+        const response = await fetch(serverURL + `/login`, {
+            headers: {
+                "x-parse-application-id": "dev",
+                "Content-Type": "application/json"
+            },
+            body: JSON.stringify({ username, password }),
+            method: "POST"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+            return null;
+        }
+
+        // 设置用户信息
+        this.id = result?.objectId;
+        this.sessionToken = result?.sessionToken;
+         this.set(result);  // 保存用户数据
+        // 缓存用户信息
+        console.log(result)
+        localStorage.setItem("NCloud/dev/User", JSON.stringify(result))
+        return this;
+    }
+
+    /** 登出 */
+    async logout() {
+        if (!this.sessionToken) {
+            console.error("用户未登录");
+            return;
+        }
+
+        const response = await fetch(serverURL + `/logout`, {
+            headers: {
+                "x-parse-application-id": "dev",
+                "x-parse-session-token": this.sessionToken
+            },
+            method: "POST"
+        });
+
+        let result = await response?.json();
+
+        if (result?.error) {
+            console.error(result?.error);
+            if (result?.error == "Invalid session token") {
+                this.clearUserCache()
+                return true;
+            }
+            return false;
+        }
+
+        this.clearUserCache()
+        return true;
+    }
+    clearUserCache() {
+        // 清除用户信息
+        localStorage.removeItem("NCloud/dev/User")
+        this.id = undefined;
+        this.sessionToken = null;
+        this.data = {};
+    }
+
+    /** 注册 */
+    async signUp(username: string, password: string, additionalData: Record<string, any> = {}) {
+        const userData = {
+            username,
+            password,
+            ...additionalData // 合并额外的用户数据
+        };
+
+        const response = await fetch(serverURL + `/users`, {
+            headers: {
+                "x-parse-application-id": "dev",
+                "Content-Type": "application/json"
+            },
+            body: JSON.stringify(userData),
+            method: "POST"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+            return null;
+        }
+
+        // 设置用户信息
+        // 缓存用户信息
+        console.log(result)
+        localStorage.setItem("NCloud/dev/User", JSON.stringify(result))
+        this.id = result?.objectId;
+        this.sessionToken = result?.sessionToken;
+        this.set(result); // 保存用户数据
+        return this;
+    }
+
+    override async save() {
+        let method = "POST";
+        let url = serverURL + `/users`;
+
+        // 更新用户信息
+        if (this.id) {
+            url += `/${this.id}`;
+            method = "PUT";
+        }
+
+        let data: any = JSON.parse(JSON.stringify(this.data))
+        delete data.createdAt
+        delete data.updatedAt
+        delete data.ACL
+        delete data.objectId
+        const body = JSON.stringify(data);
+        let headersOptions: any = {
+            "content-type": "application/json;charset=UTF-8",
+            "x-parse-application-id": "dev",
+            "x-parse-session-token": this.sessionToken, // 添加sessionToken以进行身份验证
+        }
+        const response = await fetch(url, {
+            headers: headersOptions,
+            body: body,
+            method: method,
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+        }
+        if (result?.objectId) {
+            this.id = result?.objectId;
+        }
+        localStorage.setItem("NCloud/dev/User", JSON.stringify(this.data))
+        return this;
+    }
+}
+
+export class CloudApi {
+    async fetch(path: string, body: any, options?: {
+        method: string
+        body: any
+    }) {
+
+        let reqOpts: any = {
+            headers: {
+                "x-parse-application-id": "dev",
+                "Content-Type": "application/json"
+            },
+            method: options?.method || "POST",
+            mode: "cors",
+            credentials: "omit"
+        }
+        if (body || options?.body) {
+            reqOpts.body = JSON.stringify(body || options?.body);
+            reqOpts.json = true;
+        }
+        let host = `https://dev.fmode.cn`
+        // host = `http://127.0.0.1:1337`
+        let url = `${host}/api/` + path
+        console.log(url, reqOpts)
+        const response = await fetch(url, reqOpts);
+        let json = await response.json();
+        return json
+    }
+}

+ 477 - 0
ai-assisant/src/modules/crm/mobile/page-crm-home/login.component.ts

@@ -0,0 +1,477 @@
+import { Component, Output, EventEmitter, Input, OnChanges, OnDestroy, AfterViewInit, ElementRef, HostListener } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
+import { CloudUser } from '../../../../lib/ncloud';
+
+@Component({
+  selector: 'app-login-modal',
+  standalone: true,
+  imports: [CommonModule, ReactiveFormsModule],
+  template: `
+    <div class="modal-overlay" *ngIf="visible" (click)="onClose($event)">
+      <div class="overlay-backdrop" (click)="onClose($event)"></div>
+      
+      <div class="modal-container" tabindex="-1" (click)="$event.stopPropagation()">
+        <div class="modal-content">
+          <div class="modal-header">
+            <h2>用户登录</h2>
+            <button class="close-btn" (click)="onClose($event)">&times;</button>
+          </div>
+          
+          <!-- 成功消息提示 -->
+          <div class="success-message" *ngIf="successMessage">
+            <div class="success-icon">
+              <i class="fas fa-check-circle"></i>
+            </div>
+            <div class="success-text">{{ successMessage }}</div>
+          </div>
+          
+          <form [formGroup]="loginForm" (ngSubmit)="onLogin($event)" *ngIf="!successMessage">
+            <div class="form-group">
+              <label for="username">用户名</label>
+              <input 
+                type="text" 
+                id="username" 
+                formControlName="username" 
+                placeholder="请输入用户名"
+                [ngClass]="{ 'error-border': username.touched && username.invalid }">
+              <div class="error-message" *ngIf="username.touched && username.hasError('required')">
+                用户名不能为空
+              </div>
+            </div>
+            
+            <div class="form-group">
+              <label for="password">密码</label>
+              <input 
+                type="password" 
+                id="password" 
+                formControlName="password" 
+                placeholder="请输入密码"
+                [ngClass]="{ 'error-border': password.touched && password.invalid }">
+              <div class="error-message" *ngIf="password.touched && password.hasError('required')">
+                密码不能为空
+              </div>
+            </div>
+            
+            <button 
+              type="submit" 
+              class="submit-btn" 
+              [disabled]="loginForm.invalid || isLoading">
+              {{ isLoading ? '登录中...' : '立即登录' }}
+            </button>
+            
+            <div class="switch-link">
+              还没有账号? 
+              <button type="button" class="register-link" (click)="onSwitchToRegister($event)">
+                立即注册
+              </button>
+            </div>
+          </form>
+          
+          <div class="global-error-message" *ngIf="errorMessage && !successMessage">
+            {{ errorMessage }}
+          </div>
+        </div>
+      </div>
+    </div>
+  `,
+  styles: [`
+    .modal-overlay {
+      position: fixed;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      background-color: rgba(0, 0, 0, 0.5);
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      z-index: 1000;
+      overflow-y: auto;
+      pointer-events: all;
+      user-select: none;
+      opacity: 0;
+      animation: fadeInOverlay 0.3s forwards;
+    }
+    
+    @keyframes fadeInOverlay {
+      to { opacity: 1; }
+    }
+    
+    .overlay-backdrop {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      background-color: rgba(0, 0, 0, 0.5);
+      z-index: 1;
+    }
+    
+    .modal-container {
+      position: relative;
+      z-index: 2;
+      width: 90%;
+      max-width: 400px;
+      background-color: white;
+      border-radius: 8px;
+      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+      margin: 20px;
+      outline: none;
+      pointer-events: all;
+      transform: scale(0.95);
+      opacity: 0;
+      animation: fadeInModal 0.3s forwards;
+    }
+    
+    @keyframes fadeInModal {
+      to {
+        transform: scale(1);
+        opacity: 1;
+      }
+    }
+    
+    .modal-header {
+      padding: 20px;
+      border-bottom: 1px solid #eee;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+    }
+    
+    .modal-header h2 {
+      margin: 0;
+      font-size: 1.2rem;
+      color: #333;
+    }
+    
+    .close-btn {
+      background: none;
+      border: none;
+      font-size: 1.5rem;
+      color: #999;
+      cursor: pointer;
+      transition: color 0.2s;
+    }
+    
+    .close-btn:hover {
+      color: #333;
+    }
+    
+    .modal-content {
+      padding: 20px;
+    }
+    
+    .success-message {
+      background-color: #e8f5e9;
+      color: #2e7d32;
+      padding: 15px;
+      border-radius: 4px;
+      margin-bottom: 20px;
+      display: flex;
+      align-items: center;
+    }
+    
+    .success-icon {
+      font-size: 1.5rem;
+      margin-right: 10px;
+    }
+    
+    .success-text {
+      flex: 1;
+    }
+    
+    .form-group {
+      margin-bottom: 15px;
+    }
+    
+    .form-group label {
+      display: block;
+      margin-bottom: 5px;
+      font-size: 0.9rem;
+      color: #555;
+    }
+    
+    .form-group input {
+      width: 100%;
+      padding: 10px;
+      border: 1px solid #ddd;
+      border-radius: 4px;
+      box-sizing: border-box;
+      font-size: 1rem;
+      transition: border-color 0.2s;
+    }
+    
+    .form-group input:focus {
+      outline: none;
+      border-color: #007bff;
+    }
+    
+    .error-border {
+      border-color: #dc3545 !important;
+    }
+    
+    .error-message {
+      color: #dc3545;
+      font-size: 0.8rem;
+      margin-top: 5px;
+    }
+    
+    .submit-btn {
+      width: 100%;
+      padding: 10px;
+      background-color: #007bff;
+      color: white;
+      border: none;
+      border-radius: 4px;
+      cursor: pointer;
+      font-size: 1rem;
+      transition: background-color 0.2s;
+      margin-top: 10px;
+      box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+    }
+    
+    .submit-btn:hover {
+      background-color: #0069d9;
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
+    }
+    
+    .submit-btn:disabled {
+      background-color: #6c757d;
+      cursor: not-allowed;
+      box-shadow: none;
+    }
+    
+    .switch-link {
+      text-align: center;
+      margin-top: 15px;
+      font-size: 0.9rem;
+      color: #555;
+    }
+    
+    .register-link {
+      background: none;
+      border: none;
+      color: #007bff;
+      cursor: pointer;
+      text-decoration: underline;
+      font-size: 0.9rem;
+    }
+    
+    .register-link:hover {
+      color: #0056b3;
+    }
+    
+    .global-error-message {
+      color: #dc3545;
+      font-size: 0.9rem;
+      text-align: center;
+      margin-top: 15px;
+      padding: 10px;
+      background-color: #f8d7da;
+      border-radius: 4px;
+      opacity: 0;
+      animation: fadeInError 0.3s forwards;
+    }
+    
+    @keyframes fadeInError {
+      to { opacity: 1; }
+    }
+  `]
+})
+export class LoginModalComponent implements OnChanges, AfterViewInit, OnDestroy {
+  @Input() visible: boolean = false;
+  @Output() close = new EventEmitter<void>();
+  @Output() switchToRegister = new EventEmitter<void>();
+  @Output() loginSuccess = new EventEmitter<void>();
+
+  loginForm: FormGroup;
+  errorMessage: string = '';
+  successMessage: string = '';
+  isLoading: boolean = false;
+  private modalElement!: HTMLElement;
+  private scrollTop: number = 0;
+  private successMessageTimeout: any;
+
+  constructor(private fb: FormBuilder, private elementRef: ElementRef) {
+    this.loginForm = this.fb.group({
+      username: ['', Validators.required],
+      password: ['', Validators.required]
+    });
+  }
+
+  ngAfterViewInit() {
+    this.modalElement = this.elementRef.nativeElement.querySelector('.modal-container');
+    if (this.visible) {
+      this.focusModal();
+    }
+  }
+
+  ngOnChanges() {
+    if (this.visible) {
+      this.disableBodyScroll();
+      
+      // 重置表单状态
+      this.resetForm();
+      
+      // 延迟聚焦以确保DOM已渲染
+      setTimeout(() => this.focusModal(), 100);
+    } else {
+      this.enableBodyScroll();
+      this.clearSuccessMessage();
+    }
+  }
+
+  ngOnDestroy() {
+    this.enableBodyScroll();
+    this.clearSuccessMessage();
+  }
+
+  // 重置表单状态
+  resetForm() {
+    this.loginForm.reset();
+    this.errorMessage = '';
+    this.successMessage = '';
+    this.isLoading = false;
+  }
+
+  // 显示成功消息
+  showSuccessMessage(message: string) {
+    this.clearSuccessMessage();
+    this.successMessage = message;
+    
+    // 3秒后自动清除成功消息
+    this.successMessageTimeout = setTimeout(() => {
+      this.successMessage = '';
+    }, 3000);
+  }
+
+  // 清除成功消息
+  clearSuccessMessage() {
+    if (this.successMessageTimeout) {
+      clearTimeout(this.successMessageTimeout);
+      this.successMessageTimeout = null;
+    }
+    this.successMessage = '';
+  }
+
+  private focusModal() {
+    if (this.modalElement) {
+      this.modalElement.focus();
+      
+      // 如果没有成功消息,聚焦第一个输入框
+      if (!this.successMessage) {
+        const firstInput = this.modalElement.querySelector('input');
+        if (firstInput) {
+          (firstInput as HTMLElement).focus();
+        }
+      }
+    }
+  }
+
+  @HostListener('keydown.tab', ['$event'])
+  onTabKey(event: Event) {
+    const keyboardEvent = event as KeyboardEvent;
+    
+    if (!this.modalElement) return;
+    
+    const focusableElements = this.modalElement.querySelectorAll(
+      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
+    );
+    
+    if (focusableElements.length === 0) return;
+    
+    const firstElement = focusableElements[0] as HTMLElement;
+    const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement;
+    
+    if (keyboardEvent.shiftKey) {
+      if (document.activeElement === firstElement) {
+        lastElement.focus();
+        keyboardEvent.preventDefault();
+      }
+    } else {
+      if (document.activeElement === lastElement) {
+        firstElement.focus();
+        keyboardEvent.preventDefault();
+      }
+    }
+  }
+
+  private disableBodyScroll() {
+    this.scrollTop = window.scrollY;
+    document.body.style.overflow = 'hidden';
+    document.body.style.position = 'fixed';
+    document.body.style.top = `-${this.scrollTop}px`;
+    document.body.style.width = '100%';
+  }
+
+  private enableBodyScroll() {
+    document.body.style.overflow = '';
+    document.body.style.position = '';
+    document.body.style.top = '';
+    document.body.style.width = '';
+    window.scrollTo(0, this.scrollTop);
+  }
+
+  onClose(event: Event) {
+    event.stopPropagation();
+    
+    // 添加关闭动画
+    this.modalElement.style.transform = 'scale(0.95)';
+    this.modalElement.style.opacity = '0';
+    
+    // 延迟关闭以完成动画
+    setTimeout(() => {
+      this.visible = false;
+      this.close.emit();
+    }, 200);
+  }
+
+  onSwitchToRegister(event: Event) {
+  event.stopPropagation();
+  console.log('触发了注册切换事件'); // 添加日志
+  
+  if (this.modalElement) {
+    this.modalElement.style.transform = 'scale(0.95)';
+    this.modalElement.style.opacity = '0';
+  }
+  
+  setTimeout(() => {
+    console.log('准备切换到注册页面'); // 添加日志
+    this.visible = false;
+    this.switchToRegister.emit();
+  }, 200);
+}
+
+  async onLogin(event: Event) {
+    event.preventDefault();
+    
+    if (this.loginForm.invalid || this.isLoading) {
+      return;
+    }
+
+    this.isLoading = true;
+    this.errorMessage = '';
+
+    try {
+      const { username, password } = this.loginForm.value;
+      const cloudUser = new CloudUser();
+      const user = await cloudUser.login(username, password);
+
+      if (user) {
+        this.loginSuccess.emit();
+        this.visible = false;
+      } else {
+        this.errorMessage = '用户名或密码错误';
+      }
+    } catch (error: any) {
+      this.errorMessage = error?.message || '登录失败,请检查网络连接';
+      console.error('登录错误:', error);
+    } finally {
+      this.isLoading = false;
+    }
+  }
+
+  get username() { return this.loginForm.get('username')!; }
+  get password() { return this.loginForm.get('password')!; }
+}

+ 268 - 1
ai-assisant/src/modules/crm/mobile/page-crm-home/page-crm-home.html

@@ -1 +1,268 @@
-<p>page-crm-home works!</p>
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>AI实验室 - 酒店销售智能平台</title>
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
+    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
+</head>
+<body>
+    <div class="dashboard-container">
+        <!-- 头部导航 -->
+        <div class="header">
+            <div class="logo">
+                <div class="logo-icon">
+                    <i class="fas fa-brain"></i>
+                </div>
+                <div>
+                    <div class="logo-text">AI实验室</div>
+                    <div class="logo-subtext">酒店销售智能平台</div>
+                </div>
+            </div>
+
+            <div class="user-actions">
+                <div *ngIf="!isLoggedIn">
+                    <button class="action-btn" (click)="openLoginModal()">
+                        <i class="fas fa-sign-in-alt"></i> 登录
+                    </button>
+                </div>
+                <div *ngIf="isLoggedIn">
+                    <div class="action-btn" (click)="toggleMessagePopup()">
+                        <i class="fas fa-bell"></i>
+                        <div class="badge" *ngIf="unreadMessagesCount > 0">{{ unreadMessagesCount }}</div>
+                    </div>
+                    <div class="action-btn" (click)="toggleProfilePopup()">
+                        <i class="fas fa-user"></i>
+                    </div>
+                </div>
+            </div>
+        </div>
+        
+        <!-- 欢迎区域 -->
+        <div class="welcome-section">
+  <h1 class="greeting">你好,<span>{{ '销售精英' }}</span> 👋</h1>
+            <div class="motivational-text">
+                {{ motivationalText }}
+            </div>
+        </div>
+        
+        <!-- 数据统计卡片 -->
+        <div class="stats-card">
+            <div class="stats-header">
+                <div class="stats-title">团队今日战绩</div>
+            </div>
+            <div class="stats-container">
+                <div class="stat-item">
+                    <div class="stat-value">128</div>
+                    <div class="stat-label">陪练次数</div>
+                </div>
+                <div class="stat-item">
+                    <div class="stat-value">42</div>
+                    <div class="stat-label">策略生成</div>
+                </div>
+                <div class="stat-item">
+                    <div class="stat-value">92%</div>
+                    <div class="stat-label">满意度</div>
+                </div>
+            </div>
+        </div>
+        
+        <!-- 功能卡片网格 -->
+        <div class="features-grid">
+            <div class="feature-card" *ngFor="let feature of features" (click)="navigateTo(feature.id)">
+                <div class="pulse" *ngIf="feature.hasNotification"></div>
+                <div class="card-icon">
+                    <i [class]="feature.icon"></i>
+                </div>
+                <h3 class="card-title">{{ feature.title }}</h3>
+                <p class="card-desc">{{ feature.description }}</p>
+                <div class="card-stats">
+                    <span><i [class]="feature.statIcon"></i> {{ feature.stat1 }}</span>
+                    <span>{{ feature.stat2 }}</span>
+                </div>
+            </div>
+        </div>
+        
+        <!-- 激励区域 -->
+        <div class="inspiration-section">
+            <div class="inspiration-icon">
+                <i class="fas fa-bullhorn"></i>
+            </div>
+            <h2 class="inspiration-title"><i class="fas fa-fire"></i> 今日激励</h2>
+            <p class="inspiration-content">
+                卓越的销售不是天生的,而是通过每一次精心准备的对话和持续训练铸就的。您今天的努力,将成就明天签约的喜悦!
+            </p>
+        </div>
+        
+        <!-- 用户统计区域 -->
+        <div class="inspiration-section">
+            <h2 class="inspiration-title"><i class="fas fa-trophy"></i> 成功源于持续精进</h2>
+            <p class="inspiration-content">
+                您已经完成了<span style="color: var(--primary-blue); font-weight: 700;">{{ user.trainingCount }}次</span>虚拟陪练,
+                击败了<span style="color: var(--primary-blue); font-weight: 700;">92%</span>的同级销售。
+                继续保持,下一个销售冠军就是您!
+            </p>
+        </div>
+        
+        <!-- 消息弹窗 -->
+        <div class="popup-overlay" *ngIf="showMessagePopup" (click)="toggleMessagePopup()">
+            <div class="popup-container" (click)="$event.stopPropagation()">
+                <div class="popup-header">
+                    <h3>消息通知 ({{ unreadMessagesCount }}未读)</h3>
+                    <div class="popup-actions">
+                        <button class="mark-all-read" (click)="markAllAsRead()" *ngIf="unreadMessagesCount > 0">
+                            <fa-icon [icon]="icons.faCheck"></fa-icon> 全部已读
+                        </button>
+                        <button (click)="toggleMessagePopup()"><fa-icon [icon]="icons.faTimes"></fa-icon></button>
+                    </div>
+                </div>
+                <div class="message-list-container">
+                    <div class="message-list">
+                        <div class="message-item" 
+                             *ngFor="let message of messages" 
+                             [class.unread]="message.unread"
+                             (click)="showMessageDetail(message, $event)">
+                            <div class="message-content">
+                                <div class="message-header">
+                                    <div class="message-title">{{ message.title }}</div>
+                                    <div class="message-time">{{ message.time }}</div>
+                                </div>
+                                <div class="message-preview">{{ message.content | slice:0:50 }}...</div>
+                            </div>
+                            <button class="read-btn" 
+                                    (click)="markMessageAsRead(message, $event)" 
+                                    *ngIf="message.unread">
+                                <fa-icon [icon]="icons.faCheck"></fa-icon>
+                            </button>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 消息详情弹窗 -->
+        <div class="popup-overlay" *ngIf="selectedMessage" (click)="closeMessageDetail()">
+            <div class="popup-container" (click)="$event.stopPropagation()">
+                <div class="popup-header">
+                    <h3>{{ selectedMessage.title }}</h3>
+                    <button (click)="closeMessageDetail()"><fa-icon [icon]="icons.faTimes"></fa-icon></button>
+                </div>
+                <div class="message-content-detail">
+                    <div class="message-meta">
+                        <span>{{ selectedMessage.time }}</span>
+                        <span class="unread-badge" *ngIf="selectedMessage.unread">未读</span>
+                    </div>
+                    <p>{{ selectedMessage.content }}</p>
+                    <div class="message-actions">
+                        <button class="btn-primary" 
+                                (click)="markAsRead(selectedMessage)" 
+                                *ngIf="selectedMessage.unread">
+                            <fa-icon [icon]="icons.faCheck"></fa-icon> 标记为已读
+                        </button>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+       <!-- 个人信息弹窗 -->
+<div class="popup-overlay" *ngIf="showProfilePopup" (click)="toggleProfilePopup()">
+  <div class="popup-container" (click)="$event.stopPropagation()">
+    <div class="popup-header">
+      <h3>个人信息</h3>
+      <button (click)="toggleProfilePopup()">
+        <fa-icon [icon]="icons.faTimes"></fa-icon>
+      </button>
+    </div>
+
+    <div class="profile-content">
+      <!-- 加载状态 -->
+      <div *ngIf="loadingProfile" class="loading">
+        <i class="fas fa-spinner fa-spin"></i> 加载中...
+      </div>
+
+      <!-- 未登录状态 -->
+      <div *ngIf="!loadingProfile && !isLoggedIn" class="not-logged-in">
+        请先登录查看个人信息
+      </div>
+
+      <!-- 已登录状态:显示完整信息 -->
+      <div *ngIf="!loadingProfile && isLoggedIn && currentUser" class="profile-info">
+        <div class="profile-avatar">
+          <fa-icon [icon]="icons.faUserCircle"></fa-icon>
+        </div>
+
+        <div class="profile-details">
+          <!-- 基础信息 -->
+          <div class="detail-item">
+            <span class="detail-label">用户名:</span>
+            <span class="detail-value">{{ currentUser.username || '未设置' }}</span>
+          </div>
+
+          <!-- 注册时填写的扩展字段 -->
+          
+
+          <div class="detail-item">
+            <span class="detail-label">年龄:</span>
+            <span class="detail-value">{{ currentUser.age || '未设置' }}</span>
+          </div>
+
+          <div class="detail-item">
+            <span class="detail-label">出生日期:</span>
+            <span class="detail-value">
+           {{ currentUser.data.birthDate ? (currentUser.birthDate | date:'yyyy-MM-dd') : '未设置' }} </span>
+          </div>
+
+          <div class="detail-item">
+            <span class="detail-label">职位:</span>
+            <span class="detail-value">{{ currentUser.data.position || '未设置' }}</span>
+          </div>
+
+          <!-- 系统自动记录的字段 -->
+          <div class="detail-item">
+            <span class="detail-label">角色:</span>
+            <span class="detail-value">{{ currentUser.data.role || '未设置' }}</span>
+          </div>
+
+          <div class="detail-item">
+            <span class="detail-label">训练次数:</span>
+            <span class="detail-value">{{ currentUser.data?.trainingCount || 0 }} 次</span>
+          </div>
+
+          <!-- 登出按钮 -->
+          <div class="detail-item action-item">
+            <button class="btn-danger" (click)="logout()">
+              <i class="fas fa-sign-out-alt"></i> 退出登录
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+        
+        <!-- 底部版权信息 -->
+        <div class="footer">
+            <p>© 2023 AI实验室 - 酒店销售智能平台 | 赋能销售精英,创造无限可能</p>
+        </div>
+    </div>
+
+    <!-- 登录和注册弹窗 -->
+    <app-login-modal 
+         [visible]="showLoginModal"
+            (close)="closeModals()"
+            (switchToRegister)="openRegisterModal()"
+            (loginSuccess)="handleLoginSuccess()">
+    </app-login-modal>
+
+    <app-register-modal 
+        [visible]="showRegisterModal"
+        (close)="closeModals()"
+        (switchToLogin)="openLoginModal()"
+        (registerSuccess)="handleRegisterSuccess()">
+         <div style="background: red; height: 200px; width: 200px;" *ngIf="showRegisterModal">
+    注册组件已渲染
+  </div>
+    </app-register-modal>
+</body>
+</html>

+ 983 - 0
ai-assisant/src/modules/crm/mobile/page-crm-home/page-crm-home.scss

@@ -0,0 +1,983 @@
+:root {
+            --primary-blue: #2563eb;
+            --accent-teal: #0d9488;
+            --accent-purple: #7b4bff;
+            --accent-pink: #ec4899;
+            --accent-amber: #f59e0b;
+            --accent-gradient: linear-gradient(135deg, #2563eb, #3b82f6);
+            --light-gray: #f8fafc;
+            --light-blue: #e0f2fe;
+            --text-dark: #1f2937;
+            --text-medium: #4b5563;
+            --text-light: #6b7280;
+            --card-bg: #ffffff;
+            --border-color: #e2e8f0;
+            --success: #10b981;
+            --warning: #f59e0b;
+            --danger: #ef4444;
+            --transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+            --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.05);
+            --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
+            --shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.1);
+            --border-radius: 16px;
+            --header-height: 70px;
+        }
+
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+            font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
+        }
+
+        body {
+            background: linear-gradient(135deg, #f8fafc, #e0f2fe);
+            color: var(--text-dark);
+            line-height: 1.6;
+            min-height: 100vh;
+            padding: 0;
+        }
+
+        .dashboard-container {
+            width: 100%;
+            max-width: 1200px;
+            margin: 0 auto;
+            padding: 20px 16px 40px;
+            position: relative;
+        }
+
+        /* 头部导航 - 响应式调整 */
+        .header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 12px 0 24px;
+            margin-bottom: 10px;
+            position: relative;
+            border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+            flex-wrap: wrap;
+        }
+
+        .logo {
+            display: flex;
+            align-items: center;
+            gap: 14px;
+            flex-shrink: 0;
+            margin-bottom: 10px;
+        }
+
+        .logo-icon {
+            width: 40px;
+            height: 40px;
+            background: var(--accent-gradient);
+            border-radius: 12px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            box-shadow: var(--shadow-md);
+            transition: var(--transition);
+            flex-shrink: 0;
+        }
+
+        .logo-icon i {
+            font-size: 18px;
+            color: white;
+            animation: pulse 2s infinite;
+        }
+
+        .logo-text {
+            font-size: 20px;
+            font-weight: 800;
+            color: var(--text-dark);
+            line-height: 1.2;
+            background: linear-gradient(90deg, var(--primary-blue), var(--accent-purple));
+            -webkit-background-clip: text;
+            -webkit-text-fill-color: transparent;
+        }
+
+        .logo-subtext {
+            font-size: 12px;
+            color: var(--primary-blue);
+            font-weight: 600;
+            letter-spacing: 0.5px;
+            text-transform: uppercase;
+        }
+
+        .user-actions {
+            display: flex;
+            gap: 15px;
+            flex-shrink: 0;
+        }
+
+        .action-btn {
+          flex: 1;
+          padding: 12px;
+          border-radius: 12px;
+          border: none;
+          font-weight: 600;
+          cursor: pointer;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          gap: 8px;
+          transition: all 0.3s ease;
+          color: white;
+          box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+        }
+
+
+        .action-btn:hover {
+            background: #f1f5f9;
+            transform: translateY(-3px);
+            box-shadow: var(--shadow-lg);
+            color: var(--primary-blue);
+        }
+
+        .badge {
+            position: absolute;
+            top: -6px;
+            right: -6px;
+            width: 18px;
+            height: 18px;
+            background: var(--danger);
+            color: white;
+            border-radius: 50%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 10px;
+            font-weight: 600;
+            animation: bounce 1.5s infinite;
+        }
+
+        /* 欢迎区域 - 响应式调整 */
+        .welcome-section {
+            margin: 20px 0 30px;
+            padding: 20px;
+            text-align: center;
+            background: var(--card-bg);
+            border-radius: var(--border-radius);
+            box-shadow: var(--shadow-md);
+            border: 1px solid var(--border-color);
+            position: relative;
+            overflow: hidden;
+        }
+
+        .welcome-section::before {
+            content: "";
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 4px;
+            background: var(--accent-gradient);
+        }
+
+        .greeting {
+            font-size: 24px;
+            font-weight: 800;
+            margin-bottom: 10px;
+            line-height: 1.3;
+            position: relative;
+            display: inline-block;
+        }
+
+        .greeting span {
+            color: var(--primary-blue);
+            position: relative;
+            z-index: 1;
+        }
+
+        .greeting span::after {
+            content: '';
+            position: absolute;
+            bottom: 2px;
+            left: 0;
+            width: 100%;
+            height: 8px;
+            background: rgba(37, 99, 235, 0.2);
+            border-radius: 4px;
+            z-index: -1;
+            transform: skewX(-15deg);
+        }
+
+        .motivational-text {
+            font-size: 16px;
+            color: var(--text-dark);
+            font-weight: 500;
+            line-height: 1.6;
+            margin: 20px auto 10px;
+            padding: 15px;
+            border-radius: 14px;
+            background: rgba(37, 99, 235, 0.03);
+            border-left: 4px solid var(--primary-blue);
+            position: relative;
+            box-shadow: var(--shadow-sm);
+        }
+
+        .motivational-text::before {
+            content: '"';
+            position: absolute;
+            top: -15px;
+            left: 8px;
+            font-size: 50px;
+            color: rgba(37, 99, 235, 0.1);
+            font-family: Georgia, serif;
+        }
+
+        /* 数据统计卡片 - 响应式调整 */
+        .stats-card {
+            background: var(--card-bg);
+            border-radius: var(--border-radius);
+            padding: 20px;
+            margin: 25px 0;
+            border: 1px solid var(--border-color);
+            box-shadow: var(--shadow-md);
+            position: relative;
+            overflow: hidden;
+            background-image: radial-gradient(circle at top right, rgba(37, 99, 235, 0.05) 0%, transparent 30%);
+        }
+
+        .stats-card::before {
+            content: '';
+            position: absolute;
+            top: 0;
+            left: 0;
+            right: 0;
+            height: 4px;
+            background: var(--accent-gradient);
+        }
+
+        .stats-header {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            margin-bottom: 15px;
+        }
+
+        .stats-title {
+            font-size: 18px;
+            font-weight: 700;
+            color: var(--text-dark);
+            display: flex;
+            align-items: center;
+            gap: 8px;
+        }
+
+        .stats-title::before {
+            content: "";
+            display: block;
+            width: 5px;
+            height: 20px;
+            background: #4f46e5; /* 修改为紫色,与虚拟陪练区分 */
+            border-radius: 4px;
+        }
+
+        .stats-container {
+            display: flex;
+            justify-content: space-between;
+            gap: 12px;
+            flex-wrap: wrap;
+        }
+
+        .stat-item {
+            text-align: center;
+            padding: 12px 8px;
+            background: var(--light-gray);
+            border-radius: 10px;
+            transition: var(--transition);
+            box-shadow: var(--shadow-sm);
+            position: relative;
+            overflow: hidden;
+            flex: 1 1 100px;
+            min-width: 0;
+        }
+
+        .stat-item:hover {
+            transform: translateY(-3px);
+            box-shadow: var(--shadow-md);
+            background: white;
+        }
+
+        .stat-value {
+            font-size: 20px;
+            font-weight: 800;
+            color: #4f46e5; /* 修改为紫色,与虚拟陪练区分 */
+            margin-bottom: 5px;
+            text-shadow: 0 2px 4px rgba(79, 70, 229, 0.1);
+        }
+
+        .stat-label {
+            font-size: 13px;
+            color: var(--text-light);
+            font-weight: 500;
+        }
+
+        /* 功能卡片网格 - 响应式调整 */
+        .features-grid {
+            display: grid;
+            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
+            gap: 16px;
+            margin: 25px 0;
+        }
+
+        .feature-card {
+            background: var(--card-bg);
+            border-radius: var(--border-radius);
+            padding: 18px;
+            position: relative;
+            overflow: hidden;
+            transition: var(--transition);
+            border: 1px solid var(--border-color);
+            box-shadow: var(--shadow-md);
+            cursor: pointer;
+            min-height: 180px;
+            display: flex;
+            flex-direction: column;
+            z-index: 1;
+        }
+
+        .feature-card::after {
+            content: "";
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 5px;
+            background: var(--accent-gradient);
+            opacity: 0;
+            transition: var(--transition);
+            z-index: -1;
+        }
+
+        .feature-card:hover {
+            transform: translateY(-5px);
+            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
+            border-color: transparent;
+        }
+
+        .feature-card:hover::after {
+            opacity: 1;
+            height: 100%;
+        }
+
+        .card-icon {
+            width: 45px;
+            height: 45px;
+            border-radius: 12px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            margin-bottom: 12px;
+            font-size: 22px;
+            transition: var(--transition);
+            position: relative;
+            z-index: 2;
+            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
+        }
+
+        .feature-card:hover .card-icon {
+            transform: translateY(-3px);
+        }
+
+        .card-title {
+            font-size: 17px;
+            font-weight: 700;
+            margin-bottom: 10px;
+            color: var(--text-dark);
+            position: relative;
+            z-index: 2;
+        }
+
+        .card-desc {
+            font-size: 14px;
+            color: var(--text-medium);
+            line-height: 1.5;
+            flex-grow: 1;
+            margin-bottom: 10px;
+            position: relative;
+            z-index: 2;
+        }
+
+        .card-stats {
+            display: flex;
+            justify-content: space-between;
+            margin-top: auto;
+            font-size: 12px;
+            font-weight: 500;
+            color: var(--text-light);
+            padding-top: 8px;
+            border-top: 1px solid rgba(0, 0, 0, 0.05);
+            position: relative;
+            z-index: 2;
+        }
+
+        .card-stats i {
+            margin-right: 5px;
+        }
+
+        /* 激励区域 - 响应式调整 */
+        .inspiration-section {
+            background: linear-gradient(135deg, #f0f9ff, var(--light-blue));
+            border-radius: var(--border-radius);
+            padding: 20px;
+            margin: 25px 0;
+            text-align: center;
+            border: 1px solid #dbeafe;
+            position: relative;
+            overflow: hidden;
+            box-shadow: var(--shadow-md);
+            border-top: 3px solid var(--primary-blue);
+        }
+
+        .inspiration-title {
+            font-size: 18px;
+            font-weight: 800;
+            color: var(--primary-blue);
+            margin-bottom: 12px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            gap: 8px;
+        }
+
+        .inspiration-content {
+            font-size: 15px;
+            color: var(--text-dark);
+            line-height: 1.6;
+            margin: 0 auto;
+            font-weight: 500;
+        }
+
+        .inspiration-icon {
+            position: absolute;
+            top: 10px;
+            right: 10px;
+            font-size: 50px;
+            color: rgba(37, 99, 235, 0.08);
+            z-index: 0;
+        }
+
+        /* 功能区颜色 */
+        .feature-card:nth-child(1) .card-icon {
+            color: var(--accent-teal);
+            background: rgba(13, 148, 136, 0.15);
+        }
+
+        .feature-card:nth-child(2) .card-icon {
+            color: var(--accent-purple);
+            background: rgba(123, 75, 255, 0.15);
+        }
+
+        .feature-card:nth-child(3) .card-icon {
+            color: var(--accent-pink);
+            background: rgba(236, 72, 153, 0.15);
+        }
+
+        .feature-card:nth-child(4) .card-icon {
+            color: var(--accent-amber);
+            background: rgba(245, 158, 11, 0.15);
+        }
+
+        /* 动画效果 */
+        @keyframes pulse {
+            0% { transform: scale(1); }
+            50% { transform: scale(1.1); }
+            100% { transform: scale(1); }
+        }
+
+        @keyframes bounce {
+            0%, 100% { transform: translateY(0); }
+            50% { transform: translateY(-5px); }
+        }
+
+        .pulse {
+            position: absolute;
+            top: 8px;
+            right: 8px;
+            width: 7px;
+            height: 7px;
+            background: var(--danger);
+            border-radius: 50%;
+            animation: pulse 1.5s infinite;
+            z-index: 3;
+        }
+
+        /* 底部版权信息 */
+        .footer {
+            text-align: center;
+            padding: 20px 0 10px;
+            color: var(--text-light);
+            font-size: 13px;
+            border-top: 1px solid rgba(0, 0, 0, 0.05);
+            margin-top: 20px;
+        }
+
+        /* 响应式调整 */
+        @media (max-width: 768px) {
+            .dashboard-container {
+                padding: 15px 12px 30px;
+            }
+            
+            .header {
+                padding: 10px 0 20px;
+            }
+            
+            .logo-icon {
+                width: 36px;
+                height: 36px;
+            }
+            
+            .logo-text {
+                font-size: 18px;
+            }
+            
+            .logo-subtext {
+                font-size: 11px;
+            }
+            
+            .action-btn {
+                width: 36px;
+                height: 36px;
+                font-size: 15px;
+            }
+            
+            .greeting {
+                font-size: 22px;
+            }
+            
+            .motivational-text {
+                font-size: 15px;
+                padding: 12px;
+            }
+            
+            .stats-title {
+                font-size: 16px;
+            }
+            
+            .stat-value {
+                font-size: 18px;
+            }
+            
+            .card-title {
+                font-size: 16px;
+            }
+            
+            .card-desc {
+                font-size: 13px;
+            }
+            
+            .inspiration-title {
+                font-size: 17px;
+            }
+            
+            .inspiration-content {
+                font-size: 14px;
+            }
+        }
+
+        @media (max-width: 480px) {
+            .features-grid {
+                grid-template-columns: 1fr;
+            }
+            
+            .stats-container {
+                flex-direction: column;
+                gap: 10px;
+            }
+            
+            .stat-item {
+                flex: 1 1 auto;
+            }
+        }
+        /* 弹窗样式 */
+.popup-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+  backdrop-filter: blur(5px);
+  animation: fadeIn 0.3s ease-out;
+}
+
+.popup-container {
+  background: white;
+  border-radius: var(--border-radius);
+  width: 90%;
+  max-width: 500px;
+  max-height: 80vh;
+  overflow: hidden;
+  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
+  display: flex;
+  flex-direction: column;
+  animation: slideUp 0.3s ease-out;
+}
+
+.popup-header {
+  padding: 16px 20px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  border-bottom: 1px solid var(--border-color);
+  background: var(--light-gray);
+  
+  h3 {
+    font-size: 18px;
+    font-weight: 700;
+    margin: 0;
+    color: var(--text-dark);
+  }
+  
+  button {
+    background: none;
+    border: none;
+    font-size: 18px;
+    color: var(--text-light);
+    cursor: pointer;
+    padding: 5px;
+    
+    &:hover {
+      color: var(--primary-blue);
+    }
+  }
+}
+
+.message-list {
+  overflow-y: auto;
+  flex-grow: 1;
+}
+
+.message-item {
+  padding: 16px 20px;
+  border-bottom: 1px solid var(--border-color);
+  cursor: pointer;
+  transition: var(--transition);
+  
+  &:hover {
+    background: var(--light-gray);
+  }
+  
+  &.unread {
+    background: rgba(37, 99, 235, 0.05);
+  }
+}
+
+.message-header {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 8px;
+}
+
+.message-title {
+  font-weight: 600;
+  color: var(--text-dark);
+}
+
+.message-time {
+  font-size: 12px;
+  color: var(--text-light);
+}
+
+.message-preview {
+  font-size: 14px;
+  color: var(--text-medium);
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.message-content {
+  padding: 20px;
+  overflow-y: auto;
+  
+  .message-meta {
+    font-size: 14px;
+    color: var(--text-light);
+    margin-bottom: 20px;
+  }
+  
+  p {
+    line-height: 1.6;
+    margin-bottom: 20px;
+  }
+}
+
+.message-actions {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.profile-content {
+  padding: 20px;
+  text-align: center;
+}
+
+.profile-avatar {
+  font-size: 60px;
+  color: var(--primary-blue);
+  margin-bottom: 20px;
+}
+
+.profile-details {
+  text-align: left;
+}
+
+.detail-item {
+  display: flex;
+  margin-bottom: 15px;
+  padding-bottom: 15px;
+  border-bottom: 1px solid var(--border-color);
+}
+
+.detail-label {
+  font-weight: 600;
+  color: var(--text-dark);
+  width: 100px;
+}
+
+.detail-value {
+  color: var(--text-medium);
+  flex-grow: 1;
+}
+
+.btn-primary {
+  background: var(--primary-blue);
+  color: white;
+  border: none;
+  padding: 8px 16px;
+  border-radius: 8px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: var(--transition);
+  
+  &:hover {
+    background: darken(#2563eb, 10%);
+  }
+}
+
+/* 动画 */
+@keyframes fadeIn {
+  from { 
+    opacity: 0;
+    transform: translateY(8px);
+  }
+  to { 
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+@keyframes slideUp {
+  from { 
+    transform: translateY(20px);
+    opacity: 0;
+  }
+  to { 
+    transform: translateY(0);
+    opacity: 1;
+  }
+}
+/* 消息列表容器 - 可滚动 */
+.message-list-container {
+  height: 60vh;
+  overflow-y: auto;
+  padding-right: 5px;
+  
+  /* 滚动条样式 */
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+  
+  &::-webkit-scrollbar-track {
+    background: #f1f1f1;
+    border-radius: 10px;
+  }
+  
+  &::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 10px;
+    
+    &:hover {
+      background: #a8a8a8;
+    }
+  }
+}
+
+/* 消息项样式 */
+.message-item {
+  display: flex;
+  align-items: center;
+  padding: 12px 16px;
+  border-bottom: 1px solid #e2e8f0;
+  transition: all 0.3s ease;
+  
+  &:hover {
+    background: #f8fafc;
+  }
+  
+  &.unread {
+    background: rgba(37, 99, 235, 0.05);
+  }
+}
+
+.message-content {
+  flex-grow: 1;
+  min-width: 0; /* 防止内容溢出 */
+  cursor: pointer;
+}
+
+/* 已读按钮样式 */
+.read-btn {
+  background: #e2e8f0;
+  border: none;
+  padding: 6px 12px;
+  border-radius: 16px;
+  font-size: 12px;
+  color: #4b5563;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  white-space: nowrap;
+  margin-left: 10px;
+  
+  &:hover {
+    background: #cbd5e1;
+    color: #1e40af;
+  }
+}
+
+/* 全部已读按钮 */
+.mark-all-read {
+  background: none;
+  border: none;
+  color: #2563eb;
+  font-size: 14px;
+  font-weight: 500;
+  cursor: pointer;
+  padding: 6px 12px;
+  margin-right: 10px;
+  
+  &:hover {
+    text-decoration: underline;
+  }
+}
+
+.popup-actions {
+  display: flex;
+  align-items: center;
+}
+
+/* 消息详情样式 */
+.message-content-detail {
+  padding: 20px;
+  
+  p {
+    white-space: pre-line;
+    line-height: 1.6;
+    margin: 20px 0;
+  }
+}
+
+/* 响应式调整 */
+@media (max-width: 768px) {
+  .message-list-container {
+    height: 50vh;
+  }
+  
+  .message-item {
+    flex-direction: column;
+    align-items: flex-start;
+  }
+  
+  .read-btn {
+    margin-left: 0;
+    margin-top: 8px;
+    align-self: flex-end;
+  }
+}
+app-login-modal {
+  display: block;
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  pointer-events: none; /* 允许点击穿透到下层 */
+  
+  .modal-overlay {
+    pointer-events: auto; /* 恢复弹窗区域的点击 */
+  }
+}
+
+.profile-content {
+  padding: 20px;
+}
+
+.loading {
+  text-align: center;
+  padding: 30px 0;
+  color: #666;
+}
+
+.not-logged-in {
+  text-align: center;
+  padding: 30px 0;
+  color: #666;
+  font-size: 14px;
+}
+
+.profile-info {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.profile-avatar {
+  margin-bottom: 20px;
+  font-size: 60px;
+  color: #007bff;
+}
+
+.detail-item {
+  width: 100%;
+  padding: 8px 0;
+  border-bottom: 1px solid #f0f0f0;
+  display: flex;
+  justify-content: space-between;
+}
+
+.detail-label {
+  color: #666;
+  font-weight: 500;
+}
+
+.detail-value {
+  color: #333;
+}
+
+.action-item {
+  margin-top: 15px;
+  border-bottom: none;
+  justify-content: center;
+}
+
+.btn-danger {
+  background-color: #dc3545;
+  color: white;
+  border: none;
+  padding: 6px 16px;
+  border-radius: 4px;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  gap: 5px;
+}
+
+.btn-danger:hover {
+  background-color: #bb2d3b;
+}

+ 123 - 18
ai-assisant/src/modules/crm/mobile/page-crm-home/page-crm-home.spec.ts

@@ -1,23 +1,128 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { RouterModule } from '@angular/router';
+import { Component, OnInit } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { MatDialog } from '@angular/material/dialog';
+import { MatButtonModule } from '@angular/material/button';
+import { MatListModule } from '@angular/material/list';
+import { MatIconModule } from '@angular/material/icon';
+import { MatBadgeModule } from '@angular/material/badge';
+import { MatCardModule } from '@angular/material/card';
+import { MatToolbarModule } from '@angular/material/toolbar';
 
 
-import { PageCrmHome } from './page-crm-home';
+@Component({
+  imports: [
+    RouterModule,
+    CommonModule,
+    MatButtonModule,
+    MatListModule,
+    MatIconModule,
+    MatBadgeModule,
+    MatCardModule,
+    MatToolbarModule
+  ],
+  templateUrl: './page-crm-home.html',
+  styleUrl: './page-crm-home.scss',
+  selector: 'page-crm-home',
+  standalone: true,
+})
+export class PageCrmHome implements OnInit {
+  constructor(private dialog: MatDialog) {}
 
 
-describe('PageCrmHome', () => {
-  let component: PageCrmHome;
-  let fixture: ComponentFixture<PageCrmHome>;
+  // Font Awesome 图标
+  icons = {
+    faBrain: 'brain', 
+    faBell: 'bell', 
+    faUser: 'user', 
+    faArrowRight: 'arrow-right', 
+    faRobot: 'robot', 
+    faComments: 'comments', 
+    faDatabase: 'database', 
+    faUserTie: 'user-tie', 
+    faTimes: 'times', 
+    faHistory: 'history', 
+    faStar: 'star', 
+    faChartLine: 'chart-line', 
+    faFileAlt: 'file-alt', 
+    faBullhorn: 'bullhorn'
+  };
 
 
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      imports: [PageCrmHome]
-    })
-    .compileComponents();
+  // 状态变量
+  unreadMessagesCount: number = 3;
 
 
-    fixture = TestBed.createComponent(PageCrmHome);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
+  // 数据
+  motivationalText: string = '每一次对话都是展现专业的机会,每一次练习都在提升成功的概率!今天,让AI成为您最强大的销售伙伴';
+  stats = {
+    practiceCount: 42,
+    strategyCount: 28,
+    satisfactionRate: 96
+  };
+  
+  features = {
+    virtualPractice: { count: 12, score: 85 },
+    speechStrategy: { count: 8, effectiveness: 92 },
+    dataTraining: { size: '3.2TB', accuracy: 98 },
+    customerProfile: { count: 24 }
+  };
+  
+  userStats = {
+    practiceCount: 12,
+    beatPercentage: 86
+  };
+  
+  user = {
+    name: '张明',
+    role: '高级销售经理'
+  };
+  
+  messages = [
+    { title: '新的陪练挑战', preview: '您有一个新的虚拟陪练挑战等待完成,主题:高端客户价格谈判', time: '10分钟前', unread: true },
+    { title: '话术策略更新', preview: '您收藏的"投诉处理"话术策略已更新至3.2版本', time: '1小时前', unread: true },
+    { title: '陪练成绩通知', preview: '您最近的虚拟陪练成绩为92分,超过89%的销售同事', time: '昨天', unread: false },
+    { title: '团队周报', preview: '本周团队陪练报告已生成,点击查看详细分析', time: '2天前', unread: false },
+    { title: '系统维护通知', preview: '系统将于本周六凌晨2:00-4:00进行维护升级', time: '3天前', unread: false }
+  ];
+  
+  trainings = [
+    { title: '高端客户价格谈判', date: '2023-10-15', difficulty: '⭐⭐⭐', score: 92 },
+    { title: '首次接触技巧', date: '2023-10-12', difficulty: '⭐⭐', score: 85 },
+    { title: '投诉处理模拟', date: '2023-10-08', difficulty: '⭐⭐⭐', score: 88 },
+    { title: '长期合作谈判', date: '2023-10-02', difficulty: '⭐⭐⭐⭐', score: 78 }
+  ];
 
 
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
+  motivationalPhrases = [
+    "每一次对话都是展现专业的机会,每一次练习都在提升成功的概率!今天,让AI成为您最强大的销售伙伴",
+    "每一次拒绝都是离成功更近一步!",
+    "卓越的销售不是推销产品,而是解决问题!",
+    "今天的练习,明天的签约!",
+    "客户的需求是您成功的地图,AI是您的导航仪!",
+    "专业来自准备,成功源于坚持!",
+    "您不是一个人在战斗,AI是您最强大的后援!"
+  ];
+
+  ngOnInit(): void {
+    this.updateMotivationalText();
+    setInterval(() => this.updateMotivationalText(), 10000);
+    setInterval(() => this.updateStats(), 5000);
+  }
+
+  updateMotivationalText(): void {
+    const randomIndex = Math.floor(Math.random() * this.motivationalPhrases.length);
+    this.motivationalText = this.motivationalPhrases[randomIndex];
+  }
+
+  updateStats(): void {
+    this.stats.practiceCount = Math.floor(Math.random() * 20 + 35);
+    this.stats.strategyCount = Math.floor(Math.random() * 15 + 20);
+    this.stats.satisfactionRate = Math.floor(Math.random() * 5 + 94);
+  }
+
+  
+   
+
+    
+  }
+
+ 
+  
+
+  

+ 338 - 5
ai-assisant/src/modules/crm/mobile/page-crm-home/page-crm-home.ts

@@ -1,12 +1,345 @@
-import { Component } from '@angular/core';
+import { Component, OnInit, ViewChild } from '@angular/core';
 import { RouterModule } from '@angular/router';
 import { RouterModule } from '@angular/router';
+import { CommonModule } from '@angular/common';
+import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
+import { LoginModalComponent } from './login.component';
+import { RegisterModalComponent } from './register.component';
+import { 
+  faBrain, faBell, faUser, faRobot, faComments, 
+  faDatabase, faUserTie, faTimes, faHistory, faStar, 
+  faChartLine, faFileAlt, faBullhorn, faUserCircle,
+  faFire, faTrophy, faCheck
+} from '@fortawesome/free-solid-svg-icons';
+import { CloudUser } from '../../../../lib/ncloud';
 
 
 @Component({
 @Component({
-  selector: 'app-page-crm-home',
-  imports: [RouterModule],
+  imports: [RouterModule, CommonModule, FontAwesomeModule, LoginModalComponent, RegisterModalComponent],
   templateUrl: './page-crm-home.html',
   templateUrl: './page-crm-home.html',
-  styleUrl: './page-crm-home.scss'
+  styleUrls: ['./page-crm-home.scss'],
+  selector: 'page-crm-home',
+  standalone: true,
 })
 })
-export class PageCrmHome {
+export class PageCrmHome implements OnInit {
+  // Font Awesome 图标
+  icons = {
+    faBrain, faBell, faUser, faRobot, faComments, 
+    faDatabase, faUserTie, faTimes, faHistory, faStar, 
+    faChartLine, faFileAlt, faBullhorn, faUserCircle,
+    faFire, faTrophy, faCheck
+  };
 
 
+  // 弹窗控制变量
+  showLoginModal: boolean = false;
+  showRegisterModal: boolean = false;
+  loginError: string = '';
+  registerError: string = '';
+
+  // 当前用户信息(包含扩展字段)
+  currentUser: any = null;
+  isLoggedIn: boolean = false;
+  loadingProfile: boolean = false; // 新增:加载状态
+
+  // 弹窗状态
+  showMessagePopup: boolean = false;
+  showProfilePopup: boolean = false;
+  selectedMessage: any = null;
+  unreadMessagesCount: number = 0;
+
+  // 数据
+  motivationalText: string = '每一次对话都是展现专业的机会,每一次练习都在提升成功的概率!今天,让AI成为您最强大的销售伙伴';
+  
+  features = [
+    {
+      id: 'virtual-practice',
+      title: '虚拟陪练',
+      description: '与AI客户进行真实销售对话练习,提升沟通技巧',
+      icon: 'fas fa-robot',
+      statIcon: 'fas fa-history',
+      stat1: '86次练习',
+      stat2: '92%得分',
+      hasNotification: true
+    },
+    {
+      id: 'speech-strategy',
+      title: '话术决策',
+      description: '智能生成最佳沟通策略,应对各种销售场景',
+      icon: 'fas fa-comments',
+      statIcon: 'fas fa-star',
+      stat1: '34个策略',
+      stat2: '89%有效'
+    },
+    {
+      id: 'data-training',
+      title: '数据训练',
+      description: '上传销售数据训练AI模型,优化决策能力',
+      icon: 'fas fa-database',
+      statIcon: 'fas fa-chart-line',
+      stat1: '1.2GB',
+      stat2: '95%准确'
+    },
+    {
+      id: 'customer-profile',
+      title: '客户画像',
+      description: '生成详细客户分析报告,洞察客户需求',
+      icon: 'fas fa-user-tie',
+      statIcon: 'fas fa-file-alt',
+      stat1: '28份',
+      stat2: '更新中'
+    }
+  ];
+
+  messages = [
+    { 
+      id: 1,
+      title: '新的陪练挑战', 
+      content: '您有一个新的虚拟陪练挑战等待完成,主题:高端客户价格谈判。请尽快完成以获得最佳学习效果。',
+      time: '10分钟前', 
+      unread: true 
+    },
+    { 
+      id: 2,
+      title: '话术策略更新', 
+      content: '您收藏的"投诉处理"话术策略已更新至3.2版本,包含了最新的客户反馈数据。',
+      time: '1小时前', 
+      unread: true 
+    },
+    { 
+      id: 3,
+      title: '系统维护通知', 
+      content: '系统将于本周六凌晨2:00-4:00进行维护升级,期间将无法使用服务。',
+      time: '昨天', 
+      unread: true 
+    },
+    { 
+      id: 4,
+      title: '陪练成绩通知', 
+      content: '您最近的虚拟陪练成绩为92分,超过89%的销售同事,继续保持!',
+      time: '2天前', 
+      unread: true 
+    },
+    { 
+      id: 5,
+      title: '团队周报', 
+      content: '本周团队陪练报告已生成,点击查看详细分析。',
+      time: '3天前', 
+      unread: true 
+    }
+  ];
+  
+  user = {
+    username: '张明',
+    role: '高级销售经理',
+    age: 32,
+    birthDate: '1991-05-15',
+    trainingCount: 86
+  };
+
+  motivationalPhrases = [
+    "每一次对话都是展现专业的机会,每一次练习都在提升成功的概率!今天,让AI成为您最强大的销售伙伴",
+    "每一次拒绝都是离成功更近一步!",
+    "卓越的销售不是推销产品,而是解决问题!",
+    "今天的练习,明天的签约!",
+    "客户的需求是您成功的地图,AI是您的导航仪!",
+    "专业来自准备,成功源于坚持!",
+    "您不是一个人在战斗,AI是您最强大的后援!"
+  ];
+
+  @ViewChild(LoginModalComponent) loginModal!: LoginModalComponent;
+  @ViewChild(RegisterModalComponent) registerModal!: RegisterModalComponent;
+
+// 在 PageCrmHome 类中添加(建议放在 logout 方法下方)
+async loadUserProfile() {
+  this.loadingProfile = true; // 开始加载
+  try {
+    const cloudUser = new CloudUser();
+    const currentUser = await cloudUser.current(); // 获取当前用户
+    
+    if (currentUser && currentUser.sessionToken) {
+      this.isLoggedIn = true;
+      // 绑定完整用户信息(包含注册时的扩展字段)
+      this.currentUser = {
+        username: currentUser.get('username') || '用户',
+        role: currentUser.get('role') || '销售',
+        // 扩展字段(注册时填写的信息)
+        age: currentUser.get('age') || '未设置',   // 年龄
+        birthDate: currentUser.get('birthDate') || '未设置', // 出生日期
+        position: currentUser.get('position') || '未设置',   // 职位
+        // 系统字段
+        trainingCount: currentUser.get('trainingCount') || 0
+      };
+      // 更新 user 对象,确保页面数据同步
+      this.user = {
+        username: this.currentUser.username,
+        role: this.currentUser.position,
+        age: this.currentUser.age,
+        birthDate: this.currentUser.birthDate,
+        trainingCount: this.currentUser.trainingCount
+      };
+    }
+  } catch (error) {
+    console.error('加载用户信息失败:', error);
+    this.currentUser = null;
+    this.isLoggedIn = false;
+  } finally {
+    this.loadingProfile = false; // 结束加载
+  }
 }
 }
+
+
+
+
+
+
+  private modalOpenCount = 0;
+  private modalCloseReason: string = '';
+
+  ngOnInit(): void {
+    this.updateUnreadCount();
+    this.updateMotivationalText();
+    this.loadUserProfile(); // 初始化加载用户信息
+    
+    setInterval(() => this.updateMotivationalText(), 10000);
+  }
+
+  updateMotivationalText(): void {
+    const randomIndex = Math.floor(Math.random() * this.motivationalPhrases.length);
+    this.motivationalText = this.motivationalPhrases[randomIndex];
+  }
+
+  async logout(): Promise<void> {
+    const cloudUser = new CloudUser();
+    await cloudUser.logout();
+    this.isLoggedIn = false;
+    this.currentUser = null;
+    this.user = {
+      username: '访客',
+      role: '未登录用户',
+      age: 0,
+      birthDate: '',
+      trainingCount: 0
+    };
+    this.toggleProfilePopup();
+  }
+
+  toggleMessagePopup(): void {
+    this.showMessagePopup = !this.showMessagePopup;
+    if (this.showMessagePopup) {
+      this.updateUnreadCount();
+    }
+  }
+
+  // 优化:打开个人信息弹窗时刷新数据
+  toggleProfilePopup(): void {
+    this.showProfilePopup = !this.showProfilePopup;
+    if (this.showProfilePopup && this.isLoggedIn) {
+      this.loadUserProfile(); // 重新加载最新信息
+    }
+  }
+
+  showMessageDetail(message: any, event?: Event): void {
+    if (event) event.stopPropagation();
+    this.selectedMessage = message;
+    if (message.unread) {
+      message.unread = false;
+      this.updateUnreadCount();
+    }
+  }
+
+  closeMessageDetail(): void {
+    this.selectedMessage = null;
+  }
+
+  markMessageAsRead(message: any, event: Event): void {
+    event.stopPropagation();
+    if (message.unread) {
+      message.unread = false;
+      this.updateUnreadCount();
+    }
+  }
+
+  markAllAsRead(): void {
+    this.messages.forEach(message => message.unread = false);
+    this.updateUnreadCount();
+  }
+
+  markAsRead(message: any): void {
+    if (message.unread) {
+      message.unread = false;
+      this.updateUnreadCount();
+    }
+  }
+
+  updateUnreadCount(): void {
+    this.unreadMessagesCount = this.messages.filter(m => m.unread).length;
+  }
+
+  navigateTo(featureId: string): void {
+    console.log('导航至:', featureId);
+  }
+
+  openLoginModal(): void {
+    this.showRegisterModal = false;
+    if (this.loginModal) {
+      this.loginModal.resetForm();
+    }
+    this.showLoginModal = true;
+    this.modalOpenCount++;
+    this.modalCloseReason = '';
+    document.body.classList.add('modal-open');
+  }
+
+  openRegisterModal(): void {
+    console.log('接收到注册模态框打开请求');
+    this.showLoginModal = false;
+    this.showRegisterModal = true;
+    if (this.registerModal) {
+      this.registerModal.resetForm();
+    }
+    console.log('打开注册模态框后状态:', {
+      showLoginModal: this.showLoginModal,
+      showRegisterModal: this.showRegisterModal
+    });
+    this.modalOpenCount++;
+    this.modalCloseReason = '';
+    document.body.classList.add('modal-open');
+  }
+
+  closeModals(reason: string = 'manual'): void {
+    this.modalCloseReason = reason;
+    if (this.showRegisterModal) {
+      this.showRegisterModal = false;
+      this.registerError = '';
+    }
+    if (this.showLoginModal) {
+      this.showLoginModal = false;
+      this.loginError = '';
+    }
+    this.modalOpenCount--;
+    if (this.modalOpenCount <= 0) {
+      this.modalOpenCount = 0;
+      document.body.classList.remove('modal-open');
+      setTimeout(() => {
+        window.scrollTo(0, 0);
+      }, 100);
+    }
+  }
+
+  // 优化:登录成功后重新加载用户信息
+  async handleLoginSuccess(): Promise<void> {
+    this.closeModals('login-success');
+    setTimeout(async () => {
+      await this.loadUserProfile(); // 加载最新用户信息
+      console.log('登录成功,用户信息:', this.currentUser);
+    }, 300);
+  }
+
+  handleRegisterSuccess(): void {
+    this.closeModals('register-success');
+    setTimeout(() => {
+      this.openLoginModal();
+      if (this.loginModal) {
+        this.loginModal.showSuccessMessage('注册成功,请登录');
+      }
+    }, 300);
+  }
+}

+ 522 - 0
ai-assisant/src/modules/crm/mobile/page-crm-home/register.component.ts

@@ -0,0 +1,522 @@
+import { Component, Output, EventEmitter, Input, OnChanges, OnDestroy, AfterViewInit, ElementRef, HostListener } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
+import { CloudUser } from '../../../../lib/ncloud';
+
+@Component({
+  selector: 'app-register-modal',
+  standalone: true,
+  imports: [CommonModule, ReactiveFormsModule],
+  template: `
+    <div class="modal-overlay" *ngIf="visible" (click)="onClose($event)">
+      <div class="overlay-backdrop" (click)="onClose($event)"></div>
+      
+      <div class="modal-container" tabindex="-1" (click)="$event.stopPropagation()">
+        <div class="modal-content">
+          <div class="modal-header">
+            <h2>注册账号</h2>
+            <button class="close-btn" (click)="onClose($event)">&times;</button>
+          </div>
+          
+          <form [formGroup]="registerForm" (ngSubmit)="onRegister($event)">
+            <div class="form-group">
+              <label for="username">用户名</label>
+              <input 
+                type="text" 
+                id="username" 
+                formControlName="username" 
+                placeholder="请输入用户名"
+                [ngClass]="{ 'error-border': username.touched && username.invalid }">
+              <div class="error-message" *ngIf="username.touched && username.hasError('required')">
+                用户名不能为空
+              </div>
+            </div>
+
+
+            <div class="form-group">
+                <label for="age">年龄</label>
+                <input 
+                  type="number" 
+                  id="age" 
+                  formControlName="age" 
+                  placeholder="请输入你的年龄"
+                  [ngClass]="{ 'error-border': age.touched && age.invalid }">
+                <div class="error-message" *ngIf="age.touched && age.hasError('required')">
+                  年龄不能为空
+                </div>
+                <div class="error-message" *ngIf="age.touched && (age.hasError('min') || age.hasError('max'))">
+                  年龄需在 1 - 150 之间
+                </div>
+              </div>
+            
+
+              <div class="form-group">
+                  <label for="birthDate">出生日期</label>
+                  <input 
+                    type="date" 
+                    id="birthDate" 
+                    formControlName="birthDate" 
+                    [ngClass]="{ 'error-border': birthDate.touched && birthDate.invalid }">
+                  <div class="error-message" *ngIf="birthDate.touched && birthDate.hasError('required')">
+                    出生日期不能为空
+                  </div>
+                </div>
+
+                <div class="form-group">
+                  <label for="position">职位</label>
+                  <input 
+                    type="text" 
+                    id="position" 
+                    formControlName="position" 
+                    placeholder="请输入你的职位"
+                    [ngClass]="{ 'error-border': position.touched && position.invalid }">
+                  <div class="error-message" *ngIf="position.touched && position.hasError('required')">
+                    职位不能为空
+                  </div>
+                </div>
+            <div class="form-group">
+              <label for="password">密码</label>
+              <input 
+                type="password" 
+                id="password" 
+                formControlName="password" 
+                placeholder="请输入密码(至少6位)"
+                [ngClass]="{ 'error-border': password.touched && password.invalid }">
+              <div class="error-message" *ngIf="password.touched && password.hasError('required')">
+                密码不能为空
+              </div>
+              <div class="error-message" *ngIf="password.touched && password.hasError('minlength')">
+                密码长度至少6位
+              </div>
+            </div>
+            
+            <div class="form-group">
+              <label for="confirmPassword">确认密码</label>
+              <input 
+                type="password" 
+                id="confirmPassword" 
+                formControlName="confirmPassword" 
+                placeholder="请再次输入密码"
+                [ngClass]="{ 'error-border': confirmPassword.touched && (confirmPassword.invalid || registerForm.hasError('passwordMismatch')) }">
+              <div class="error-message" *ngIf="confirmPassword.touched && confirmPassword.hasError('required')">
+                请确认密码
+              </div>
+              <div class="error-message" *ngIf="confirmPassword.touched && registerForm.hasError('passwordMismatch')">
+                两次输入的密码不一致
+              </div>
+            </div>
+            
+            <button 
+              type="submit" 
+              class="submit-btn" 
+              [disabled]="registerForm.invalid || isLoading">
+              {{ isLoading ? '注册中...' : '立即注册' }}
+            </button>
+            
+            <div class="switch-link">
+              已有账号? 
+              <button type="button" class="login-link" (click)="onSwitchToLogin($event)">
+                立即登录
+              </button>
+            </div>
+          </form>
+          
+          <div class="global-error-message" *ngIf="errorMessage">
+            {{ errorMessage }}
+          </div>
+        </div>
+      </div>
+      <<!-- 注册表单底部添加 -->
+<div style="color: red; margin-top: 10px;">
+  <!-- 表单级错误 -->
+  表单级错误:{{ registerForm.errors | json }}<br>
+  
+  <!-- 所有控件的错误 -->
+  用户名错误:{{ username.errors | json }}<br>
+  密码错误:{{ password.errors | json }}<br>
+  确认密码错误:{{ confirmPassword.errors | json }}<br>
+  年龄错误:{{ age.errors | json }}<br>
+  出生日期错误:{{ birthDate.errors | json }}<br>
+  职位错误:{{ position.errors | json }}<br>
+</div>
+    </div>
+  `,
+  styles: [`
+    .modal-overlay {
+      position: fixed;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      background-color: rgba(0, 0, 0, 0.5);
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      z-index: 1000;
+      overflow-y: auto;
+      pointer-events: all;
+      user-select: none;
+      opacity: 0;
+      animation: fadeInOverlay 0.3s forwards;
+    }
+    
+    @keyframes fadeInOverlay {
+      to { opacity: 1; }
+    }
+    
+    .overlay-backdrop {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      background-color: rgba(0, 0, 0, 0.5);
+      z-index: 1;
+    }
+    
+    .modal-container {
+      position: relative;
+      z-index: 2;
+      width: 90%;
+      max-width: 400px;
+      background-color: white;
+      border-radius: 8px;
+      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+      margin: 20px;
+      outline: none;
+      pointer-events: all;
+      transform: scale(0.95);
+      opacity: 0;
+      animation: fadeInModal 0.3s forwards;
+    }
+    
+    @keyframes fadeInModal {
+      to {
+        transform: scale(1);
+        opacity: 1;
+      }
+    }
+    
+    .modal-header {
+      padding: 20px;
+      border-bottom: 1px solid #eee;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+    }
+    
+    .modal-header h2 {
+      margin: 0;
+      font-size: 1.2rem;
+      color: #333;
+    }
+    
+    .close-btn {
+      background: none;
+      border: none;
+      font-size: 1.5rem;
+      color: #999;
+      cursor: pointer;
+      transition: color 0.2s;
+    }
+    
+    .close-btn:hover {
+      color: #333;
+    }
+    
+    .modal-content {
+      padding: 20px;
+    }
+    
+    .form-group {
+      margin-bottom: 15px;
+    }
+    
+    .form-group label {
+      display: block;
+      margin-bottom: 5px;
+      font-size: 0.9rem;
+      color: #555;
+    }
+    
+    .form-group input {
+      width: 100%;
+      padding: 10px;
+      border: 1px solid #ddd;
+      border-radius: 4px;
+      box-sizing: border-box;
+      font-size: 1rem;
+      transition: border-color 0.2s;
+    }
+    
+    .form-group input:focus {
+      outline: none;
+      border-color: #007bff;
+    }
+    
+    .error-border {
+      border-color: #dc3545 !important;
+    }
+    
+    .error-message {
+      color: #dc3545;
+      font-size: 0.8rem;
+      margin-top: 5px;
+    }
+    
+    .submit-btn {
+      width: 100%;
+      padding: 10px;
+      background-color: #007bff;
+      color: white;
+      border: none;
+      border-radius: 4px;
+      cursor: pointer;
+      font-size: 1rem;
+      transition: background-color 0.2s;
+      margin-top: 10px;
+      box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+    }
+    
+    .submit-btn:hover {
+      background-color: #0069d9;
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
+    }
+    
+    .submit-btn:disabled {
+      background-color: #6c757d;
+      cursor: not-allowed;
+      box-shadow: none;
+    }
+    
+    .switch-link {
+      text-align: center;
+      margin-top: 15px;
+      font-size: 0.9rem;
+      color: #555;
+    }
+    
+    .login-link {
+      background: none;
+      border: none;
+      color: #007bff;
+      cursor: pointer;
+      text-decoration: underline;
+      font-size: 0.9rem;
+    }
+    
+    .login-link:hover {
+      color: #0056b3;
+    }
+    
+    .global-error-message {
+      color: #dc3545;
+      font-size: 0.9rem;
+      text-align: center;
+      margin-top: 15px;
+      padding: 10px;
+      background-color: #f8d7da;
+      border-radius: 4px;
+      opacity: 0;
+      animation: fadeInError 0.3s forwards;
+    }
+    
+    @keyframes fadeInError {
+      to { opacity: 1; }
+    }
+  `]
+})
+export class RegisterModalComponent implements OnChanges, AfterViewInit, OnDestroy {
+  @Input() visible: boolean = false;
+  @Output() close = new EventEmitter<void>();
+  @Output() switchToLogin = new EventEmitter<void>();
+  @Output() registerSuccess = new EventEmitter<void>();
+
+  registerForm: FormGroup;
+  errorMessage: string = '';
+  isLoading: boolean = false;
+  private modalElement!: HTMLElement;
+  private scrollTop: number = 0;
+
+  constructor(private fb: FormBuilder, private elementRef: ElementRef) {
+    this.registerForm = this.fb.group({
+      username: ['', Validators.required],
+      password: ['', [Validators.required, Validators.minLength(6)]],
+      confirmPassword: ['', Validators.required],
+        age: [null, [Validators.required, Validators.min(1), Validators.max(150)]], // 年龄
+        birthDate: [null, Validators.required], // 出生日期
+        position: ['', Validators.required] // 职位
+    }, { validator: this.passwordMatchValidator });
+  }
+
+  ngAfterViewInit() {
+    this.modalElement = this.elementRef.nativeElement.querySelector('.modal-container');
+    if (this.visible) {
+      this.focusModal();
+    }
+  }
+
+  ngOnChanges() {
+    if (this.visible) {
+      this.disableBodyScroll();
+      this.resetForm();
+      setTimeout(() => this.focusModal(), 100);
+    } else {
+      this.enableBodyScroll();
+    }
+  }
+
+  ngOnDestroy() {
+    this.enableBodyScroll();
+  }
+
+  // 重置表单状态
+  resetForm() {
+    this.registerForm.reset();
+    this.errorMessage = '';
+    this.isLoading = false;
+  }
+
+  passwordMatchValidator(form: FormGroup) {
+    const password = form.get('password')?.value;
+    const confirmPassword = form.get('confirmPassword')?.value;
+    return password === confirmPassword ? null : { passwordMismatch: true };
+  }
+
+  private focusModal() {
+    if (this.modalElement) {
+      this.modalElement.focus();
+      const firstInput = this.modalElement.querySelector('input');
+      if (firstInput) {
+        (firstInput as HTMLElement).focus();
+      }
+    }
+  }
+
+  @HostListener('keydown.tab', ['$event'])
+  onTabKey(event: Event) {
+    const keyboardEvent = event as KeyboardEvent;
+    
+    if (!this.modalElement) return;
+    
+    const focusableElements = this.modalElement.querySelectorAll(
+      'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
+    );
+    
+    if (focusableElements.length === 0) return;
+    
+    const firstElement = focusableElements[0] as HTMLElement;
+    const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement;
+    
+    if (keyboardEvent.shiftKey) {
+      if (document.activeElement === firstElement) {
+        lastElement.focus();
+        keyboardEvent.preventDefault();
+      }
+    } else {
+      if (document.activeElement === lastElement) {
+        firstElement.focus();
+        keyboardEvent.preventDefault();
+      }
+    }
+  }
+
+  private disableBodyScroll() {
+    this.scrollTop = window.scrollY;
+    document.body.style.overflow = 'hidden';
+    document.body.style.position = 'fixed';
+    document.body.style.top = `-${this.scrollTop}px`;
+    document.body.style.width = '100%';
+  }
+
+  private enableBodyScroll() {
+    document.body.style.overflow = '';
+    document.body.style.position = '';
+    document.body.style.top = '';
+    document.body.style.width = '';
+    window.scrollTo(0, this.scrollTop);
+  }
+
+ onClose(event: Event) {
+  event.stopPropagation();
+  if (this.modalElement) { // 增加非空判断,避免 modalElement 为 null 时报错
+    this.modalElement.style.transform = 'scale(0.95)';
+    this.modalElement.style.opacity = '0';
+  }
+  setTimeout(() => {
+    this.visible = false;
+    this.close.emit();
+  }, 200);
+}
+
+
+  onSwitchToLogin(event: Event) {
+    event.stopPropagation();
+    
+    // 添加切换动画
+    this.modalElement.style.transform = 'scale(0.95)';
+    this.modalElement.style.opacity = '0';
+    
+    setTimeout(() => {
+      this.visible = false;
+      this.switchToLogin.emit();
+    }, 200);
+  }
+
+  async onRegister(event: Event) {
+  event.preventDefault();
+  if (this.registerForm.invalid || this.isLoading) {
+     // 表单无效时触发表单验证
+    Object.values(this.registerForm.controls).forEach(control => {
+      control.markAsTouched(); // 标记为已触碰,触发错误提示
+    });
+    return;
+  }
+
+  this.isLoading = true;
+  this.errorMessage = '';
+
+  try {
+    // 1. 获取表单中所有字段(包括新增的 name、age 等)
+    const { username, password,  age, birthDate, position } = this.registerForm.value;
+    const cloudUser = new CloudUser();
+    
+    // 2. 构造扩展数据(包含新增字段和原有字段)
+    const additionalData = {
+      role: 'sales',
+      trainingCount: 0,
+      age: Number(age), // 确保为数字类型
+      birthDate: new Date(birthDate),
+      position
+    };
+
+    // 3. 调用注册接口,传递所有数据
+    const user = await cloudUser.signUp(username, password, additionalData);
+
+    if (user) {
+      this.registerSuccess.emit();
+      this.visible = false;
+    } else {
+      this.errorMessage = '注册失败,请稍后重试';
+    }
+  } catch (error: any) {
+    // 错误处理
+    if (error.message.includes('username already exists')) {
+      this.errorMessage = '该用户名已被注册,请更换其他用户名';
+    } else {
+      this.errorMessage = error?.message || '注册失败,请检查网络连接';
+    }
+    console.error('注册错误:', error);
+  } finally {
+    this.isLoading = false;
+  }
+}
+
+  get username() { return this.registerForm.get('username')!; }
+  get password() { return this.registerForm.get('password')!; }
+  get confirmPassword() { return this.registerForm.get('confirmPassword')!; }
+  // 在类的末尾添加(与其他 getter 方法并列)
+  get age() { return this.registerForm.get('age')!; }         // 年龄控件
+  get birthDate() { return this.registerForm.get('birthDate')!; } // 出生日期控件
+  get position() { return this.registerForm.get('position')!; }   // 职位控件
+}

+ 175 - 0
ai-assisant/src/modules/crm/mobile/page-crm-image/cloud-service.ts

@@ -0,0 +1,175 @@
+// src/app/services/cloud-service.ts
+
+import { Injectable } from '@angular/core';
+
+// 定义服务器URL
+let serverURL = `https://dev.fmode.cn/parse`;
+if (location.protocol == "http:") {
+    serverURL = `http://dev.fmode.cn:1337/parse`;
+}
+
+// 基础云对象类
+export class CloudObject {
+    className: string;
+    id: string | undefined = undefined;
+    createdAt: any;
+    updatedAt: any;
+    data: Record<string, any> = {};
+
+    constructor(className: string) {
+        this.className = className;
+    }
+
+    toPointer() {
+        return { "__type": "Pointer", "className": this.className, "objectId": this.id };
+    }
+
+    set(json: Record<string, any>) {
+        Object.keys(json).forEach(key => {
+            if (["objectId", "id", "createdAt", "updatedAt"].indexOf(key) > -1) {
+                return;
+            }
+            this.data[key] = json[key];
+        });
+    }
+
+    get(key: string) {
+        return this.data[key] || null;
+    }
+
+    async save() {
+        let method = "POST";
+        let url = serverURL + `/classes/${this.className}`;
+
+        // 更新
+        if (this.id) {
+            url += `/${this.id}`;
+            method = "PUT";
+        }
+
+        const body = JSON.stringify(this.data);
+        const response = await fetch(url, {
+            headers: {
+                "content-type": "application/json;charset=UTF-8",
+                "x-parse-application-id": "dev"
+            },
+            body: body,
+            method: method,
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+        }
+        if (result?.objectId) {
+            this.id = result?.objectId;
+        }
+        return this;
+    }
+
+    async destroy() {
+        if (!this.id) return;
+        const response = await fetch(serverURL + `/classes/${this.className}/${this.id}`, {
+            headers: {
+                "x-parse-application-id": "dev"
+            },
+            body: null,
+            method: "DELETE",
+            mode: "cors",
+            credentials: "omit"
+        });
+
+        const result = await response?.json();
+        if (result) {
+            this.id = undefined;
+        }
+        return true;
+    }
+}
+
+// 查询类 - 实现了所有必要的查询方法
+export class CloudQuery {
+    className: string;
+    queryParams: Record<string, any> = { where: {} };
+
+    constructor(className: string) {
+        this.className = className;
+    }
+
+    // 查询条件方法
+    equalTo(key: string, value: any) {
+        this.queryParams['where'][key] = value;
+        return this;
+    }
+    
+    // 设置包含关联对象
+    include(...fields: string[]) {
+        this.queryParams["include"] = fields.join(',');
+        return this;
+    }
+    
+    // 设置查询结果数量限制
+    limit(limit: number) {
+        this.queryParams["limit"] = limit;
+        return this;
+    }
+    
+    // 设置查询结果排序
+    ascending(field: string) {
+        this.queryParams["order"] = field;
+        return this;
+    }
+    
+    // 获取查询的第一个结果
+    async first() {
+        this.limit(1);
+        const results = await this.find();
+        return results.length > 0 ? results[0] : null;
+    }
+    
+    // 执行查询并返回所有结果
+    async find() {
+        // 构建查询URL参数
+        const queryString = Object.keys(this.queryParams)
+            .map(key => `${key}=${encodeURIComponent(JSON.stringify(this.queryParams[key]))}`)
+            .join('&');
+            
+        const response = await fetch(serverURL + `/classes/${this.className}?${queryString}`, {
+            headers: {
+                "x-parse-application-id": "dev"
+            },
+            method: "GET",
+            mode: "cors",
+            credentials: "omit"
+        });
+        
+        const result = await response?.json();
+        if (result?.error) {
+            console.error(result?.error);
+            return [];
+        }
+        
+        // 将结果转换为CloudObject实例
+        return result?.results?.map((item: any) => {
+            const obj = new CloudObject(this.className);
+            obj.id = item.objectId;
+            obj.createdAt = item.createdAt;
+            obj.updatedAt = item.updatedAt;
+            obj.data = { ...item };
+            delete obj.data['objectId'];
+            delete obj.data['createdAt'];
+            delete obj.data['updatedAt'];
+            return obj;
+        }) || [];
+    }
+}
+
+// 云服务类
+@Injectable({
+    providedIn: 'root'
+})
+export class CloudService {
+    constructor() { }
+}

+ 176 - 0
ai-assisant/src/modules/crm/mobile/page-crm-image/crm-service.ts

@@ -0,0 +1,176 @@
+// src/app/services/crm-service.ts
+
+import { Injectable } from '@angular/core';
+import { CloudObject, CloudQuery } from './cloud-service';
+
+// 客户数据模型
+export class Client extends CloudObject {
+    constructor() {
+        super('Client'); // 对应后端的Client类
+    }
+    
+    // 设置客户属性的便捷方法
+    setClientData(data: {
+        clientId: string;
+        clientName: string;
+        clientType: string;
+        chatData: string;
+        date: string;
+    }) {
+        this.set({
+            clientId: data.clientId,
+            clientName: data.clientName,
+            clientType: data.clientType,
+            chatData: data.chatData,
+            date: data.date
+        });
+    }
+    
+    // 获取客户属性的便捷方法
+    getClientData() {
+        return {
+            clientId: this.get('clientId'),
+            clientName: this.get('clientName'),
+            clientType: this.get('clientType'),
+            chatData: this.get('chatData'),
+            date: this.get('date')
+        };
+    }
+}
+
+// 聊天消息数据模型 - 添加了必要的属性定义
+export class ChatMessage extends CloudObject {
+    constructor() {
+        super('ChatMessage'); // 对应后端的ChatMessage类
+    }
+    
+    // 设置消息属性
+    setMessageData(data: {
+        clientId: string;
+        time: string;
+        sender: string;
+        content: string;
+    }) {
+        this.set({
+            clientId: data.clientId,
+            time: data.time,
+            sender: data.sender,
+            content: data.content
+        });
+    }
+    
+    // 添加获取属性的方法
+    getTime() { return this.get('time'); }
+    getSender() { return this.get('sender'); }
+    getContent() { return this.get('content'); }
+    getClientId() { return this.get('clientId'); }
+}
+
+// CRM服务类 - 实现了所有必要的方法
+@Injectable({
+    providedIn: 'root'
+})
+export class CRMServices {
+    constructor() { }
+    
+    // 保存客户数据到后端
+    async saveClient(clientData: {
+        clientId: string;
+        clientName: string;
+        clientType: string;
+        chatData: string;
+        date: string;
+    }): Promise<Client> {
+        // 先检查是否已有该客户ID的记录
+        const query = new CloudQuery('Client');
+        query.equalTo('clientId', clientData.clientId);
+        const existingClient = await query.first();
+        
+        let client: Client;
+        
+        if (existingClient) {
+            // 如果存在,更新现有记录
+            client = new Client();
+            client.id = existingClient.id;
+            client.setClientData(clientData);
+        } else {
+            // 如果不存在,创建新记录
+            client = new Client();
+            client.setClientData(clientData);
+        }
+        
+        // 保存到后端
+        await client.save();
+        return client;
+    }
+    
+    // 获取所有客户
+    async getAllClients(): Promise<Client[]> {
+        const query = new CloudQuery('Client');
+        query.limit(1000); // 设置最大查询数量
+        const results = await query.find();
+        return results.map((result: { id: string | undefined; get: (arg0: string) => any; }) => {
+            const client = new Client();
+            client.id = result.id;
+            client.setClientData({
+                clientId: result.get('clientId'),
+                clientName: result.get('clientName'),
+                clientType: result.get('clientType'),
+                chatData: result.get('chatData'),
+                date: result.get('date')
+            });
+            return client;
+        });
+    }
+    
+    // 保存聊天消息
+    async saveChatMessages(clientId: string, messages: ChatMessage[]): Promise<void> {
+        for (const msg of messages) {
+            // 确保消息与客户关联
+            msg.set({ clientId });
+            await msg.save();
+        }
+    }
+    
+    // 获取客户的聊天消息
+    async getChatMessages(clientId: string): Promise<ChatMessage[]> {
+        const query = new CloudQuery('ChatMessage');
+        query.equalTo('clientId', clientId);
+        query.ascending('time'); // 按时间升序排列
+        const results = await query.find();
+        
+        return results.map((result: { id: string | undefined; get: (arg0: string) => any; }) => {
+            const msg = new ChatMessage();
+            msg.id = result.id;
+            msg.setMessageData({
+                clientId: result.get('clientId'),
+                time: result.get('time'),
+                sender: result.get('sender'),
+                content: result.get('content')
+            });
+            return msg;
+        });
+    }
+    
+    // 删除客户及其相关聊天记录
+    async deleteClient(clientId: string): Promise<void> {
+        // 先查找客户
+        const query = new CloudQuery('Client');
+        query.equalTo('clientId', clientId);
+        const clients = await query.find();
+        
+        if (clients.length > 0) {
+            // 删除客户
+            await clients[0].destroy();
+            
+            // 删除相关的聊天记录
+            const msgQuery = new CloudQuery('ChatMessage');
+            msgQuery.equalTo('clientId', clientId);
+            const messages = await msgQuery.find();
+            
+            for (const msg of messages) {
+                await msg.destroy();
+            }
+        }
+    }
+}

+ 266 - 1
ai-assisant/src/modules/crm/mobile/page-crm-image/page-crm-image.html

@@ -1 +1,266 @@
-<p>page-crm-image works!</p>
+<!-- page-crm-image.html - 修改后与后端服务集成的代码 -->
+<div class="app-container">
+  <!-- 头部导航 -->
+  <div class="header">
+    <div class="header-title">
+      <i class="fas fa-user-tag"></i>
+      <h1>客户画像分析</h1>
+    </div>
+  </div>
+
+  <!-- 分析输入区 -->
+  <div class="analysis-input">
+    <div class="input-group">
+      <label for="client-id">客户编号</label>
+      <input type="text" id="client-id" [(ngModel)]="clientId" placeholder="请输入客户编号">
+    </div>
+    
+    <div class="input-group">
+      <label for="client-name">客户名称</label>
+      <input type="text" id="client-name" [(ngModel)]="clientName" placeholder="请输入客户名称">
+    </div>
+    
+    <div class="input-group">
+      <label for="client-type">客户类型</label>
+      <select id="client-type" [(ngModel)]="clientType">
+        <option value="企业客户">企业客户</option>
+        <option value="个人客户">个人客户</option>
+        <option value="潜在客户">潜在客户</option>
+        <option value="VIP客户">VIP客户</option>
+      </select>
+    </div>
+    
+    <div class="input-group">
+      <label for="chat-data">聊天记录文本</label>
+      <textarea id="chat-data" [(ngModel)]="chatData" placeholder="请粘贴或输入聊天记录文本..."></textarea>
+    </div>
+    
+    <div class="action-buttons">
+      <button class="btn btn-blue" (click)="save()">
+        <i class="fas fa-save"></i> 保存
+      </button>
+      <button class="btn btn-blue" (click)="analyze()">
+        <i class="fas fa-play"></i> 开始分析
+      </button>
+    </div>
+  </div>
+
+  <!-- 客户分析列表 -->
+  <div class="client-list-section">
+    <div class="section-header">
+      <h2 class="section-title">客户分析列表</h2>
+      <div class="section-actions">
+        <button class="btn btn-sm btn-blue" (click)="refreshClients()">
+          <i class="fas fa-refresh"></i> 刷新
+        </button>
+        <button class="btn btn-sm btn-blue" (click)="clearAllClients()">
+          <i class="fas fa-trash"></i> 清空
+        </button>
+      </div>
+    </div>
+    
+    <div class="search-box">
+      <i class="fas fa-search"></i>
+      <input type="text" [(ngModel)]="searchTerm" placeholder="搜索客户名称或编号...">
+    </div>
+    
+    <div class="client-list">
+      <div class="client-item" *ngFor="let client of filteredClients" (click)="loadClient(client)">
+        <div class="client-info">
+          <div class="client-avatar">{{ client.get('clientName')?.charAt(0) || '?' }}</div>
+          <div>
+            <div class="client-name">{{ client.get('clientName') || '未命名' }}</div>
+            <div class="client-meta">{{ client.get('clientType') || '未知类型' }} · ID: {{ client.get('clientId') || '未知' }}</div>
+          </div>
+        </div>
+        <div class="client-date">{{ client.get('date') || '未知日期' }}</div>
+        <div class="client-actions">
+          <button class="btn btn-icon" (click)="deleteClient(client.get('clientId'), $event)">
+            <i class="fas fa-trash"></i>
+          </button>
+        </div>
+      </div>
+      <div *ngIf="clients.length === 0" class="empty-state">
+        <i class="fas fa-folder-open"></i>
+        <p>暂无客户分析记录</p>
+      </div>
+    </div>
+  </div>
+
+  <!-- 智能推荐区 -->
+  <div class="recommendation-section">
+    <div class="section-header">
+      <h2 class="section-title">智能推荐</h2>
+    </div>
+    
+    <div class="recommendation-cards">
+      <div class="recommendation-card" *ngFor="let rec of recommendations">
+        <div class="card-header">
+          <div class="card-icon" [style.background]="rec.iconColor" [style.color]="rec.iconTextColor">
+            <i [class]="rec.icon"></i>
+          </div>
+          <h3 class="card-title">{{ rec.title }}</h3>
+        </div>
+        <p class="recommendation-content">
+          {{ rec.content }}
+        </p>
+        <div class="recommendation-action">
+          <span class="tag">{{ rec.tag }}</span>
+          <button class="action-btn" (click)="handleRecommendationAction(rec)">
+            {{ rec.buttonText }}
+          </button>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <!-- 一级弹窗:基本信息 -->
+  <div class="report-modal" *ngIf="showBaseReportModal">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button class="close-btn" (click)="closeModal()">
+          <i class="fas fa-times"></i>
+        </button>
+        <h2>客户画像分析报告</h2>
+      </div>
+      <div class="modal-body">
+        <div class="form-group">
+          <label for="report-name">名称</label>
+          <input type="text" id="report-name" [(ngModel)]="reportName" placeholder="请输入报告名称">
+        </div>
+        
+        <div class="info-item">
+          <i class="fas fa-calendar-alt"></i>
+          <span>日期时间:{{ currentDate | date:'yyyy-MM-dd HH:mm' }}</span>
+        </div>
+        
+        <div class="info-item">
+          <i class="fas fa-user-tag"></i>
+          <span>客户类型:{{ clientType || '未设置' }}</span>
+        </div>
+        
+        <div class="clickable-item" (click)="openChatDetailModal()">
+          <i class="fas fa-comments"></i>
+          <span>聊天记录文本</span>
+          <i class="fas fa-chevron-right"></i>
+        </div>
+        
+        <div class="clickable-item" (click)="openAnalysisResultModal()">
+          <i class="fas fa-chart-pie"></i>
+          <span>分析结果</span>
+          <i class="fas fa-chevron-right"></i>
+        </div>
+        
+        <div class="clickable-item" (click)="openStrategyModal()">
+          <i class="fas fa-lightbulb"></i>
+          <span>推荐策略</span>
+          <i class="fas fa-chevron-right"></i>
+        </div>
+        
+        <div class="modal-actions">
+          <button class="btn btn-blue" (click)="exportReport()">
+            <i class="fas fa-download"></i> 导出报告
+          </button>
+        </div>
+      </div>
+      <div class="modal-footer">
+        <button class="btn btn-confirm" (click)="closeModal()">确定</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- 二级弹窗:聊天记录详情 -->
+  <div class="report-modal" *ngIf="showChatDetailModal">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button class="back-btn" (click)="backToBaseModal()">
+          <i class="fas fa-arrow-left"></i> 返回
+        </button>
+        <h2>聊天记录详情</h2>
+        <button class="close-btn" (click)="closeModal()">
+          <i class="fas fa-times"></i>
+        </button>
+      </div>
+      <div class="modal-body">
+        <div class="info-item">
+          <i class="fas fa-calendar-alt"></i>
+          <span>日期时间:{{ chatDetail.date || '未记录' }}</span>
+        </div>
+        <div class="chat-messages">
+          <div class="message" *ngFor="let msg of formattedChatMessages">
+            <div class="message-header">
+              <span class="sender">{{ msg.getSender() }}</span>
+              <span class="time">{{ msg.getTime() }}</span>
+            </div>
+            <div class="message-content">{{ msg.getContent() }}</div>
+          </div>
+          <div *ngIf="formattedChatMessages.length === 0" class="empty-chat">
+            暂无格式化聊天内容
+          </div>
+        </div>
+      </div>
+      <div class="modal-footer">
+        <button class="btn btn-confirm" (click)="closeModal()">确定</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- 二级弹窗:分析结果 -->
+  <div class="report-modal" *ngIf="showAnalysisResultModal">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button class="back-btn" (click)="backToBaseModal()">
+          <i class="fas fa-arrow-left"></i> 返回
+        </button>
+        <h2>分析结果</h2>
+        <button class="close-btn" (click)="closeModal()">
+          <i class="fas fa-times"></i>
+        </button>
+      </div>
+      <div class="modal-body">
+        <!-- 图表容器 -->
+        <div class="chart-container" style="position: relative; height:250px; margin-bottom: 20px;">
+          <canvas id="analysisChart"></canvas>
+        </div>
+        
+        <div class="analysis-grid">
+          <div class="analysis-item">
+            <i class="fas fa-venus-mars"></i>
+            <span>性别:{{ analysisResult.gender || '未知' }}</span>
+          </div>
+          <div class="analysis-item">
+            <i class="fas fa-birthday-cake"></i>
+            <span>年龄:{{ analysisResult.age || '未知' }}</span>
+          </div>
+          <div class="analysis-item">
+            <i class="fas fa-briefcase"></i>
+            <span>职业:{{ analysisResult.job || '未知' }}</span>
+          </div>
+          <div class="analysis-item">
+            <i class="fas fa-brain"></i>
+            <span>心理特征:{{ analysisResult.psychology || '未分析' }}</span>
+          </div>
+          <div class="analysis-item">
+            <i class="fas fa-shopping-cart"></i>
+            <span>消费习惯:{{ analysisResult.consumption || '未分析' }}</span>
+          </div>
+          <div class="analysis-item">
+            <i class="fas fa-lightbulb"></i>
+            <span>需求信息:{{ analysisResult.needs || '未分析' }}</span>
+          </div>
+        </div>
+      </div>
+      <div class="modal-footer">
+        <button class="btn btn-confirm" (click)="closeModal()">确定</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- 加载中弹窗 -->
+  <div class="loading-modal" *ngIf="isLoading">
+    <div class="loading-content">
+      <div class="spinner"></div>
+      <p>{{ loadingMessage || '处理中...' }}</p>
+    </div>
+  </div>
+</div>

+ 734 - 0
ai-assisant/src/modules/crm/mobile/page-crm-image/page-crm-image.scss

@@ -0,0 +1,734 @@
+/* page-crm-image.scss - 添加功能后的完整代码 */
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+  font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
+}
+
+:root {
+  --primary: #4a8fe7;
+  --primary-dark: #0a192f;
+  --secondary: #5e72e4;
+  --accent: #ff6b6b;
+  --text-dark: #1a1a1a;
+  --text-medium: #4a4a4a;
+  --text-light: #8a8f9c;
+  --bg-white: #ffffff;
+  --bg-light: #f5f7fa;
+  --card-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
+  --border-radius: 12px;
+}
+
+body {
+  background-color: var(--bg-white);
+  color: var(--text-medium);
+  padding: 0;
+  max-width: 480px;
+  margin: 0 auto;
+  min-height: 100vh;
+  position: relative;
+  overflow-x: hidden;
+  background: linear-gradient(to bottom, #f5f9ff 0%, #ffffff 100px);
+}
+
+.app-container {
+  padding: 0 16px 40px;
+  position: relative;
+}
+
+/* 头部导航 */
+.header {
+  padding: 20px 0;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.header-title {
+  font-size: 22px;
+  font-weight: 700;
+  color: var(--text-dark);
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.header-title i {
+  color: var(--primary);
+  font-size: 24px;
+  background: rgba(74, 143, 231, 0.1);
+  width: 40px;
+  height: 40px;
+  border-radius: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+/* 分析输入区 */
+.analysis-input {
+  background: var(--bg-white);
+  border-radius: var(--border-radius);
+  box-shadow: var(--card-shadow);
+  padding: 20px;
+  margin-bottom: 24px;
+  border: 1px solid rgba(0, 0, 0, 0.03);
+}
+
+.input-group {
+  margin-bottom: 16px;
+}
+
+.input-group label {
+  display: block;
+  margin-bottom: 8px;
+  font-weight: 600;
+  color: var(--text-dark);
+  font-size: 14px;
+}
+
+.input-group input,
+.input-group textarea,
+.input-group select {
+  width: 100%;
+  padding: 12px 16px;
+  border-radius: var(--border-radius);
+  border: 1px solid #e0e4e8;
+  font-size: 14px;
+}
+
+.input-group input:focus,
+.input-group textarea:focus,
+.input-group select:focus {
+  outline: none;
+  border-color: var(--primary);
+  box-shadow: 0 0 0 3px rgba(74, 143, 231, 0.2);
+}
+
+.input-group textarea {
+  min-height: 120px;
+  resize: vertical;
+}
+
+.action-buttons {
+  display: flex;
+  gap: 12px;
+  margin-top: 20px;
+}
+
+.btn {
+  padding: 12px 20px;
+  border-radius: var(--border-radius);
+  font-size: 14px;
+  font-weight: 600;
+  border: none;
+  cursor: pointer;
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+}
+
+.btn-blue {
+  background: var(--primary);
+  color: white;
+  
+  &:hover {
+    background: #3a7bd5;
+    box-shadow: 0 4px 8px rgba(74, 143, 231, 0.3);
+  }
+}
+
+.btn-sm {
+  padding: 8px 12px;
+  font-size: 12px;
+}
+
+.btn-icon {
+  padding: 6px 10px;
+  background: rgba(74, 143, 231, 0.1);
+  color: var(--primary);
+  border-radius: 8px;
+  
+  &:hover {
+    background: rgba(74, 143, 231, 0.2);
+  }
+}
+
+/* 客户列表区 */
+.client-list-section {
+  margin-bottom: 24px;
+}
+
+.section-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 16px;
+}
+
+.section-title {
+  font-size: 18px;
+  font-weight: 700;
+  color: var(--text-dark);
+  position: relative;
+  padding-left: 12px;
+}
+
+.section-title:before {
+  content: '';
+  position: absolute;
+  left: 0;
+  top: 4px;
+  height: 16px;
+  width: 4px;
+  background: var(--primary);
+  border-radius: 2px;
+}
+
+.section-actions {
+  display: flex;
+  gap: 8px;
+}
+
+.search-box {
+  position: relative;
+  margin-bottom: 16px;
+}
+
+.search-box input {
+  width: 100%;
+  padding: 12px 16px 12px 42px;
+  border-radius: var(--border-radius);
+  border: 1px solid #e0e4e8;
+  font-size: 14px;
+}
+
+.search-box input:focus {
+  outline: none;
+  border-color: var(--primary);
+  box-shadow: 0 0 0 3px rgba(74, 143, 231, 0.2);
+}
+
+.search-box i {
+  position: absolute;
+  left: 16px;
+  top: 50%;
+  transform: translateY(-50%);
+  color: var(--text-light);
+}
+
+.client-list {
+  background: var(--bg-white);
+  border-radius: var(--border-radius);
+  box-shadow: var(--card-shadow);
+  overflow: hidden;
+  border: 1px solid rgba(0, 0, 0, 0.03);
+}
+
+.client-item {
+  padding: 16px;
+  border-bottom: 1px solid #f0f2f5;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  cursor: pointer;
+  transition: all 0.2s ease;
+}
+
+.client-item:last-child {
+  border-bottom: none;
+}
+
+.client-item:hover {
+  background: #f9fbfe;
+  transform: translateX(4px);
+}
+
+.client-info {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.client-avatar {
+  width: 40px;
+  height: 40px;
+  border-radius: 50%;
+  background: linear-gradient(135deg, #4a8fe7, #5e72e4);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: white;
+  font-weight: bold;
+  font-size: 16px;
+}
+
+.client-name {
+  font-weight: 600;
+  color: var(--text-dark);
+  margin-bottom: 2px;
+}
+
+.client-meta {
+  font-size: 12px;
+  color: var(--text-light);
+}
+
+.client-date {
+  font-size: 12px;
+  color: var(--text-light);
+}
+
+.client-actions {
+  display: flex;
+  gap: 8px;
+}
+
+.empty-state {
+  padding: 40px 20px;
+  text-align: center;
+  color: var(--text-light);
+}
+
+.empty-state i {
+  font-size: 40px;
+  margin-bottom: 10px;
+  color: rgba(74, 143, 231, 0.3);
+}
+
+/* 智能推荐区 */
+.recommendation-section {
+  margin-top: 24px;
+}
+
+.recommendation-cards {
+  display: flex;
+  flex-direction: column;
+  gap: 16px;
+}
+
+.recommendation-card {
+  background: var(--bg-white);
+  border-radius: var(--border-radius);
+  box-shadow: var(--card-shadow);
+  padding: 20px;
+  position: relative;
+  border: 1px solid rgba(0, 0, 0, 0.03);
+  transition: all 0.2s ease;
+}
+
+.recommendation-card:hover {
+  transform: translateY(-4px);
+  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.12);
+}
+
+.card-header {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  margin-bottom: 16px;
+}
+
+.card-icon {
+  width: 42px;
+  height: 42px;
+  border-radius: 12px;
+  background: rgba(74, 143, 231, 0.15);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: var(--primary);
+  font-size: 20px;
+}
+
+.card-title {
+  font-size: 16px;
+  font-weight: 700;
+  color: var(--text-dark);
+}
+
+.recommendation-content {
+  color: var(--text-medium);
+  font-size: 14px;
+  line-height: 1.6;
+  margin-bottom: 16px;
+}
+
+.recommendation-action {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.tag {
+  padding: 6px 12px;
+  border-radius: 20px;
+  background: var(--bg-light);
+  font-size: 12px;
+  color: var(--text-medium);
+  font-weight: 500;
+}
+
+.action-btn {
+  padding: 8px 16px;
+  border-radius: 30px;
+  background: var(--primary);
+  color: white;
+  font-size: 14px;
+  font-weight: 600;
+  border: none;
+  cursor: pointer;
+  transition: all 0.2s ease;
+}
+
+.action-btn:hover {
+  background: #3a7bd5;
+  box-shadow: 0 4px 8px rgba(74, 143, 231, 0.3);
+}
+
+/* 弹窗样式 */
+.report-modal {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+  padding: 20px;
+  opacity: 0;
+  visibility: hidden;
+  transition: opacity 0.3s ease, visibility 0.3s ease;
+}
+
+.report-modal.active {
+  opacity: 1;
+  visibility: visible;
+}
+
+.modal-content {
+  background: white;
+  border-radius: var(--border-radius);
+  width: 100%;
+  max-width: 480px;
+  max-height: 90vh;
+  overflow-y: auto;
+  box-shadow: var(--card-shadow);
+  transform: scale(0.9);
+  transition: transform 0.3s ease;
+}
+
+.report-modal.active .modal-content {
+  transform: scale(1);
+}
+
+.modal-header {
+  padding: 20px;
+  border-bottom: 1px solid #eee;
+  text-align: center;
+  position: relative;
+}
+
+.modal-header h2 {
+  color: var(--primary);
+  font-size: 20px;
+  margin: 0;
+}
+
+.back-btn {
+  position: absolute;
+  left: 20px;
+  top: 50%;
+  transform: translateY(-50%);
+  background: none;
+  border: none;
+  font-size: 16px;
+  color: var(--primary);
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  gap: 5px;
+  padding: 5px 10px;
+  border-radius: 4px;
+  
+  &:hover {
+    background: rgba(74, 143, 231, 0.1);
+  }
+  
+  i {
+    font-size: 12px;
+  }
+}
+
+.close-btn {
+  position: absolute;
+  right: 20px;
+  top: 50%;
+  transform: translateY(-50%);
+  background: none;
+  border: none;
+  color: var(--text-light);
+  font-size: 16px;
+  cursor: pointer;
+  padding: 5px;
+  
+  &:hover {
+    color: var(--primary);
+  }
+}
+
+.modal-body {
+  padding: 20px;
+}
+
+.form-group {
+  margin-bottom: 20px;
+}
+
+.form-group label {
+  display: block;
+  margin-bottom: 8px;
+  font-weight: 600;
+  color: var(--text-dark);
+  font-size: 14px;
+}
+
+.form-group input {
+  width: 100%;
+  padding: 10px 12px;
+  border-radius: var(--border-radius);
+  border: 1px solid #e0e4e8;
+  font-size: 14px;
+}
+
+.info-item {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  padding: 12px 0;
+  border-bottom: 1px solid #f5f5f5;
+}
+
+.info-item i {
+  color: var(--primary);
+  width: 24px;
+  text-align: center;
+}
+
+.clickable-item {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 12px 0;
+  border-bottom: 1px solid #f5f5f5;
+  cursor: pointer;
+  transition: all 0.2s ease;
+}
+
+.clickable-item i:first-child {
+  color: var(--primary);
+  width: 24px;
+  text-align: center;
+}
+
+.clickable-item i.fa-chevron-right {
+  color: var(--text-light);
+}
+
+.clickable-item:hover {
+  background-color: #f9f9f9;
+  padding-left: 8px;
+}
+
+.text-content {
+  padding: 15px;
+  background: #f9f9f9;
+  border-radius: 8px;
+  margin-top: 15px;
+  line-height: 1.6;
+  white-space: pre-wrap;
+}
+
+.analysis-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 12px;
+  margin-top: 15px;
+}
+
+.analysis-item {
+  background: #f5f7fa;
+  padding: 12px;
+  border-radius: 8px;
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.analysis-item i {
+  color: var(--primary);
+}
+
+.modal-footer {
+  padding: 20px;
+  text-align: center;
+  border-top: 1px solid #eee;
+}
+
+.btn-confirm {
+  background: var(--primary);
+  color: white;
+  padding: 12px 24px;
+  border-radius: 30px;
+  border: none;
+  font-weight: 600;
+  cursor: pointer;
+}
+
+.modal-actions {
+  margin-top: 20px;
+  display: flex;
+  gap: 12px;
+}
+
+/* 聊天记录样式 */
+.chat-messages {
+  margin-top: 15px;
+}
+
+.message {
+  margin-bottom: 15px;
+}
+
+.message-header {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 5px;
+}
+
+.sender {
+  font-weight: 600;
+  color: var(--text-dark);
+}
+
+.time {
+  font-size: 12px;
+  color: var(--text-light);
+}
+
+.message-content {
+  padding: 10px 15px;
+  background: var(--bg-light);
+  border-radius: 8px;
+  line-height: 1.6;
+}
+
+.empty-chat {
+  padding: 20px;
+  text-align: center;
+  color: var(--text-light);
+  background: var(--bg-light);
+  border-radius: 8px;
+}
+
+/* 加载中样式 */
+.loading-modal {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.6);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 2000;
+}
+
+.loading-content {
+  background: white;
+  padding: 30px 40px;
+  border-radius: var(--border-radius);
+  text-align: center;
+  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
+}
+
+.spinner {
+  width: 40px;
+  height: 40px;
+  border: 4px solid rgba(74, 143, 231, 0.3);
+  border-radius: 50%;
+  border-top-color: var(--primary);
+  animation: spin 1s linear infinite;
+  margin: 0 auto 15px;
+}
+
+@keyframes spin {
+  to {
+    transform: rotate(360deg);
+  }
+}
+
+.loading-content p {
+  font-weight: 500;
+  color: var(--text-dark);
+}
+// src/app/pages/page-crm-image/page-crm-image.scss
+
+// 添加或修改以下样式
+
+.client-avatar {
+  width: 40px;
+  height: 40px;
+  background-color: #4a8fe7;
+  color: white;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-weight: bold;
+  margin-right: 15px;
+}
+
+.loading-modal {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+}
+
+.loading-content {
+  background-color: white;
+  padding: 20px;
+  border-radius: 8px;
+  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  text-align: center;
+}
+
+.spinner {
+  border: 4px solid rgba(0, 0, 0, 0.1);
+  border-left-color: #4a8fe7;
+  border-radius: 50%;
+  width: 30px;
+  height: 30px;
+  animation: spin 1s linear infinite;
+  margin: 0 auto 10px;
+}
+
+@keyframes spin {
+  to {
+    transform: rotate(360deg);
+  }
+}

+ 427 - 6
ai-assisant/src/modules/crm/mobile/page-crm-image/page-crm-image.ts

@@ -1,11 +1,432 @@
-import { Component } from '@angular/core';
+// src/app/pages/page-crm-image/page-crm-image.ts
+
+import { Component, AfterViewInit, ElementRef, ViewChild, OnInit } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import Chart from 'chart.js/auto';
+import { CRMServices, Client, ChatMessage } from './crm-service'; // 导入新的服务和模型
+
+// 定义推荐项类型
+interface Recommendation {
+  icon: string;
+  title: string;
+  content: string;
+  tag: string;
+  buttonText: string;
+  iconColor: string;
+  iconTextColor: string;
+}
+
+// 定义分析结果类型
+interface AnalysisResult {
+  gender?: string;
+  age?: string;
+  job?: string;
+  psychology?: string;
+  consumption?: string;
+  needs?: string;
+}
 
 
 @Component({
 @Component({
   selector: 'app-page-crm-image',
   selector: 'app-page-crm-image',
-  imports: [],
+  standalone: true,
+  imports: [CommonModule, FormsModule],
   templateUrl: './page-crm-image.html',
   templateUrl: './page-crm-image.html',
-  styleUrl: './page-crm-image.scss'
+  styleUrls: ['./page-crm-image.scss']
 })
 })
-export class PageCrmImage {
-
-}
+export class PageCrmImage implements AfterViewInit, OnInit {
+  // 表单数据
+  clientId = '';
+  clientName = '';
+  chatData = '';
+  searchTerm = '';
+  reportName = '';
+  clientType = '企业客户';
+  
+  // 弹窗控制
+  showBaseReportModal = false;
+  showChatDetailModal = false;
+  showAnalysisResultModal = false;
+  isLoading = false;
+  loadingMessage = '';
+  
+  // 当前日期
+  currentDate = new Date();
+  
+  // 聊天记录详情
+  chatDetail = {
+    date: '2023-07-15 14:30',
+    content: '客户表示对新产品很感兴趣,询问了价格和功能细节,希望下周能安排演示。'
+  };
+  
+  // 分析结果
+  analysisResult: AnalysisResult = {
+    gender: '男',
+    age: '35-40岁',
+    job: 'IT经理',
+    psychology: '理性决策型',
+    consumption: '注重性价比',
+    needs: '需要高效解决方案'
+  };
+  
+  // 图表数据
+  chartData = {
+    labels: ['理性决策', '价格敏感', '品牌忠诚', '冒险尝试', '社交导向'],
+    datasets: [{
+      label: '客户心理特征分析',
+      data: [75, 40, 30, 20, 55],
+      backgroundColor: [
+        'rgba(74, 143, 231, 0.7)',
+        'rgba(94, 114, 228, 0.7)',
+        'rgba(23, 162, 184, 0.7)',
+        'rgba(255, 99, 132, 0.7)',
+        'rgba(54, 162, 235, 0.7)'
+      ],
+      borderColor: [
+        'rgb(74, 143, 231)',
+        'rgb(94, 114, 228)',
+        'rgb(23, 162, 184)',
+        'rgb(255, 99, 132)',
+        'rgb(54, 162, 235)'
+      ],
+      borderWidth: 1
+    }]
+  };
+  
+  // 客户列表
+  clients: Client[] = [];
+  
+  // 推荐数据
+  recommendations: Recommendation[] = [
+    {
+      icon: 'fas fa-user-friends',
+      title: '相似客户推荐',
+      content: '根据张明远的画像特征,发现3位相似客户,沟通策略可复用率85%',
+      tag: '高匹配度',
+      buttonText: '查看客户',
+      iconColor: 'rgba(74, 143, 231, 0.15)',
+      iconTextColor: '#4a8fe7'
+    },
+    {
+      icon: 'fas fa-clock',
+      title: '最佳接触时机',
+      content: '李思琪的下次最佳联系时间:明天上午10:00-11:30,接通率预测92%',
+      tag: '高接通率',
+      buttonText: '加入日程',
+      iconColor: 'rgba(94, 114, 228, 0.15)',
+      iconTextColor: '#5e72e4'
+    }
+  ];
+  
+  // 格式化后的聊天消息
+  formattedChatMessages: ChatMessage[] = [];
+  
+  @ViewChild('analysisChart', { static: false }) analysisChartRef: ElementRef | undefined;
+  private analysisChart: Chart | undefined;
+  
+  constructor(private crmService: CRMServices) {
+    // 从后端加载客户数据
+    this.loadClientsFromBackend();
+  }
+  
+  ngOnInit() {
+    // 初始化时格式化聊天记录
+    this.formatChatMessages();
+  }
+  
+  ngAfterViewInit() {
+    this.createAnalysisChart();
+  }
+  
+  // 获取过滤后的客户列表
+  get filteredClients() {
+    if (!this.searchTerm) return this.clients;
+    
+    const term = this.searchTerm.toLowerCase();
+    return this.clients.filter(client => 
+      client.get('clientName')?.toLowerCase().includes(term) || 
+      client.get('clientId')?.toLowerCase().includes(term)
+    );
+  }
+  
+  // 从后端加载客户数据
+  async loadClientsFromBackend() {
+    this.showLoading('正在加载客户数据...');
+    
+    try {
+      const clients = await this.crmService.getAllClients();
+      this.clients = clients;
+    } catch (error) {
+      console.error('加载客户数据失败', error);
+      alert('加载客户数据失败,请稍后再试');
+    } finally {
+      this.hideLoading();
+    }
+  }
+  
+  // 格式化聊天记录
+  formatChatMessages() {
+    this.formattedChatMessages = [];
+    
+    if (!this.chatData) return;
+    
+    // 假设聊天记录格式为:[时间] 发送者: 消息内容
+    const chatRegex = /\[([^\]]+)\]\s*([^:]+):\s*(.+)/g;
+    let match;
+    
+    while ((match = chatRegex.exec(this.chatData)) !== null) {
+        const msg = new ChatMessage();
+        msg.setMessageData({
+            clientId: this.clientId,
+            time: match[1],
+            sender: match[2],
+            content: match[3]
+        });
+        this.formattedChatMessages.push(msg);
+    }
+    
+    // 如果没有匹配到特定格式,创建一个默认消息
+    if (this.formattedChatMessages.length === 0 && this.chatData.trim()) {
+        const msg = new ChatMessage();
+        msg.setMessageData({
+            clientId: this.clientId,
+            time: new Date().toLocaleTimeString(),
+            sender: '系统',
+            content: this.chatData
+        });
+        this.formattedChatMessages.push(msg);
+    }
+  }
+  
+  // 创建分析图表
+  createAnalysisChart() {
+    if (this.analysisChartRef) {
+      const ctx = this.analysisChartRef.nativeElement.getContext('2d');
+      if (ctx) {
+        this.analysisChart = new Chart(ctx, {
+          type: 'radar',
+          data: this.chartData,
+          options: {
+            scales: {
+              r: {
+                angleLines: {
+                  display: true
+                },
+                suggestedMin: 0,
+                suggestedMax: 100
+              }
+            }
+          }
+        });
+      }
+    }
+  }
+  
+  // 保存分析
+  async save() {
+    if (!this.clientId || !this.clientName || !this.chatData) {
+      alert('请填写完整的客户信息和聊天记录');
+      return;
+    }
+    
+    // 格式化聊天记录
+    this.formatChatMessages();
+    
+    // 保存到后端
+    this.showLoading('正在保存客户信息...');
+    
+    try {
+      // 保存客户数据
+      await this.crmService.saveClient({
+        clientId: this.clientId,
+        clientName: this.clientName,
+        clientType: this.clientType,
+        chatData: this.chatData,
+        date: new Date().toLocaleDateString()
+      });
+      
+      // 保存聊天消息
+      await this.crmService.saveChatMessages(this.clientId, this.formattedChatMessages);
+      
+      // 刷新客户列表
+      await this.loadClientsFromBackend();
+      
+      this.hideLoading();
+      this.showBaseReportModal = true;
+    } catch (error) {
+      console.error('保存客户数据失败', error);
+      alert('保存客户数据失败,请稍后再试');
+      this.hideLoading();
+    }
+  }
+  
+  // 开始分析
+  async analyze() {
+    if (!this.clientId || !this.clientName || !this.chatData) {
+      alert('请填写完整的客户信息和聊天记录');
+      return;
+    }
+    
+    // 格式化聊天记录
+    this.formatChatMessages();
+    
+    // 模拟分析过程
+    this.showLoading('正在分析客户数据...');
+    
+    setTimeout(() => {
+      // 模拟分析结果
+      this.analysisResult = {
+        gender: Math.random() > 0.5 ? '男' : '女',
+        age: `${Math.floor(Math.random() * 20) + 25}-${Math.floor(Math.random() * 5) + 30}岁`,
+        job: ['IT经理', '市场营销', '金融分析师', '教师', '医生'][Math.floor(Math.random() * 5)],
+        psychology: ['理性决策型', '冲动消费型', '品牌忠诚型', '社交导向型'][Math.floor(Math.random() * 4)],
+        consumption: ['注重性价比', '高端消费', '中等消费', '价格敏感型'][Math.floor(Math.random() * 4)],
+        needs: ['需要高效解决方案', '寻求价格优惠', '追求品质体验', '关注品牌价值'][Math.floor(Math.random() * 4)]
+      };
+      
+      // 更新图表数据
+      this.chartData.datasets[0].data = [
+        Math.floor(Math.random() * 40) + 60, // 理性决策
+        Math.floor(Math.random() * 80) + 20, // 价格敏感
+        Math.floor(Math.random() * 70) + 30, // 品牌忠诚
+        Math.floor(Math.random() * 50) + 10, // 冒险尝试
+        Math.floor(Math.random() * 70) + 30  // 社交导向
+      ];
+      
+      if (this.analysisChart) {
+        this.analysisChart.data = this.chartData;
+        this.analysisChart.update();
+      }
+      
+      this.hideLoading();
+      alert(`客户 ${this.clientName} (${this.clientId}) 分析完成!`);
+    }, 2000);
+  }
+  
+  // 导出报告
+  exportReport() {
+    this.showLoading('正在生成报告...');
+    
+    setTimeout(() => {
+      this.hideLoading();
+      alert('报告已成功导出!');
+    }, 1500);
+  }
+  
+  // 加载客户数据
+  async loadClient(client: Client) {
+    this.clientId = client.get('clientId');
+    this.clientName = client.get('clientName');
+    this.clientType = client.get('clientType');
+    this.chatData = client.get('chatData');
+    
+    // 从后端加载聊天记录
+    this.showLoading('正在加载客户数据...');
+    
+    try {
+      const messages = await this.crmService.getChatMessages(this.clientId);
+      this.formattedChatMessages = messages;
+      
+      this.hideLoading();
+      this.showBaseReportModal = true;
+    } catch (error) {
+      console.error('加载聊天记录失败', error);
+      alert('加载聊天记录失败,请稍后再试');
+      this.hideLoading();
+    }
+  }
+  
+  // 删除客户
+  async deleteClient(clientId: string, event: Event) {
+    event.stopPropagation(); // 阻止事件冒泡
+    
+    if (confirm('确定要删除这个客户记录吗?')) {
+      this.showLoading('正在删除客户数据...');
+      
+      try {
+        await this.crmService.deleteClient(clientId);
+        // 刷新客户列表
+        await this.loadClientsFromBackend();
+        this.hideLoading();
+      } catch (error) {
+        console.error('删除客户失败', error);
+        alert('删除客户失败,请稍后再试');
+        this.hideLoading();
+      }
+    }
+  }
+  
+  // 清空所有客户
+  async clearAllClients() {
+    if (confirm('确定要清空所有客户记录吗?此操作不可撤销!')) {
+      this.showLoading('正在清空客户数据...');
+      
+      try {
+        // 逐个删除客户
+        for (const client of this.clients) {
+          await this.crmService.deleteClient(client.get('clientId'));
+        }
+        
+        // 刷新客户列表
+        this.clients = [];
+        this.hideLoading();
+      } catch (error) {
+        console.error('清空客户数据失败', error);
+        alert('清空客户数据失败,请稍后再试');
+        this.hideLoading();
+      }
+    }
+  }
+  
+  // 刷新客户列表
+  async refreshClients() {
+    await this.loadClientsFromBackend();
+  }
+  
+  // 显示加载中状态
+  showLoading(message: string) {
+    this.loadingMessage = message;
+    this.isLoading = true;
+  }
+  
+  // 隐藏加载中状态
+  hideLoading() {
+    this.isLoading = false;
+  }
+  
+  // 关闭模态框
+  closeModal() {
+    this.showBaseReportModal = false;
+    this.showChatDetailModal = false;
+    this.showAnalysisResultModal = false;
+  }
+  
+  // 返回基础报告模态框
+  backToBaseModal() {
+    this.showChatDetailModal = false;
+    this.showAnalysisResultModal = false;
+    this.showBaseReportModal = true;
+  }
+  
+  // 打开聊天详情模态框
+  openChatDetailModal() {
+    this.showBaseReportModal = false;
+    this.showChatDetailModal = true;
+  }
+  
+  // 打开分析结果模态框
+  openAnalysisResultModal() {
+    this.showBaseReportModal = false;
+    this.showAnalysisResultModal = true;
+  }
+  
+  // 打开策略模态框(假设实现)
+  openStrategyModal() {
+    alert('推荐策略功能将在未来版本中实现');
+  }
+  
+  // 处理推荐项点击
+  handleRecommendationAction(recommendation: Recommendation) {
+    alert(`执行推荐操作: ${recommendation.title}`);
+  }
+}

+ 108 - 1
ai-assisant/src/modules/crm/mobile/page-crm-training/page-crm-training.html

@@ -1 +1,108 @@
-<p>page-crm-training works!</p>
+<div class="container">
+  <!-- 头部标题 -->
+  <div class="header">
+    <h1>虚拟训练功能</h1>
+  </div>
+
+  <!-- 主体内容 -->
+  <div class="main">
+    <!-- 陪练场景选择侧边栏 -->
+    <aside class="sidebar">
+      <h2>陪练场景选择</h2>
+      
+      <!-- 场景难度设置 -->
+      <div class="form-group">
+        <label for="sceneLevel">场景难度设置</label>
+        <select 
+          id="sceneLevel" 
+          [(ngModel)]="selectedLevel"
+          (change)="filterScenes()"
+        >
+          <option value="">全部难度</option>
+          <option *ngFor="let level of sceneLevels" [value]="level.value">
+            {{level.label}}
+          </option>
+        </select>
+      </div>
+
+      <!-- 客户角色设定 -->
+      <div class="form-group">
+        <label for="customerType">客户角色设定</label>
+        <select 
+          id="customerType" 
+          [(ngModel)]="selectedCustomerType"
+          (change)="filterScenes()"
+        >
+          <option value="">全部角色</option>
+          <option *ngFor="let customer of customerTypes" [value]="customer.value">
+            {{customer.label}}
+          </option>
+        </select>
+      </div>
+
+      <!-- 场景列表 -->
+      <div class="form-group scene-list-container">
+        <label>可选场景</label>
+        <div class="scene-list">
+          <div *ngIf="filteredScenes.length === 0" class="no-scene">
+            暂无符合条件的场景
+          </div>
+          <div *ngFor="let scene of filteredScenes" class="scene-item">
+            <div class="scene-info">
+              <div class="scene-name">{{scene.name}}</div>
+              <div class="scene-desc">{{scene.description}}</div>
+              <div class="scene-meta">
+                <span>难度: {{getLevelLabel(scene.level)}}</span>
+                <span>角色: {{getCustomerLabel(scene.customerType)}}</span>
+              </div>
+            </div>
+            <button 
+              class="select-scene-btn" 
+              (click)="selectScene(scene)"
+              [disabled]="selectedScene?.id === scene.id"
+            >
+              {{selectedScene?.id === scene.id ? '已选择' : '选择'}}
+            </button>
+          </div>
+        </div>
+      </div>
+    </aside>
+
+    <!-- 对话训练模拟区域 -->
+    <section class="chat-section">
+      <h2>对话训练模拟 - {{selectedScene?.name || '未选择场景'}}</h2>
+      
+      <div class="training-info" *ngIf="selectedScene">
+        <span>轮次: {{currentRound}}/{{maxRounds}}</span>
+        <span *ngIf="conversationScore !== null">当前得分: {{conversationScore}}</span>
+      </div>
+      
+      <div class="chat-messages" #chatMessagesContainer>
+        <p *ngIf="!selectedScene" class="system-message">请先从左侧选择训练场景</p>
+        <div *ngFor="let message of chatMessages" class="message" [class.user]="message.type === 'user'" [class.bot]="message.type === 'bot'">
+          <div class="message-content">{{message.content}}</div>
+          <div class="message-time">{{message.timestamp | date:'HH:mm'}}</div>
+        </div>
+      </div>
+      
+      <div class="chat-input" *ngIf="selectedScene">
+        <input 
+          type="text" 
+          [(ngModel)]="chatInput" 
+          placeholder="输入回复内容..."
+          (keyup.enter)="sendMessage()"
+        >
+        <button (click)="sendMessage()" [disabled]="!chatInput.trim()">发送</button>
+        <button (click)="resetConversation()" class="reset-btn">重置对话</button>
+      </div>
+    </section>
+
+    <!-- 训练报告区域 -->
+    <div class="eval-report">
+      <app-training-reports 
+        [reports]="generatedReports"
+        (reportSelected)="viewReport($event)"
+      ></app-training-reports>
+    </div>
+  </div>
+</div>

+ 422 - 0
ai-assisant/src/modules/crm/mobile/page-crm-training/page-crm-training.scss

@@ -0,0 +1,422 @@
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+  font-family: "Microsoft YaHei", sans-serif;
+}
+
+.container {
+  max-width: 1200px;
+  margin: 0 auto;
+  background-color: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+  overflow: hidden;
+  margin-top: 20px;
+}
+
+.header {
+  padding: 20px;
+  background-color: #f8f9fc;
+  border-bottom: 1px solid #e5e7eb;
+  
+  h1 {
+    font-size: 24px;
+    color: #333;
+    text-align: center;
+  }
+}
+
+.main {
+  display: flex;
+  flex-wrap: wrap;
+  padding: 20px;
+  gap: 20px;
+}
+
+/* 陪练场景选择侧边栏样式 */
+.sidebar {
+  width: 320px;
+  background-color: #f8f9fc;
+  border-radius: 8px;
+  padding: 20px;
+  border: 1px solid #e5e7eb;
+  height: fit-content;
+
+  h2 {
+    font-size: 18px;
+    color: #333;
+    margin-bottom: 20px;
+    border-left: 4px solid #007bff;
+    padding-left: 10px;
+  }
+}
+
+.form-group {
+  margin-bottom: 20px;
+  
+  label {
+    display: block;
+    margin-bottom: 8px;
+    color: #666;
+    font-weight: 500;
+  }
+  
+  select, input {
+    width: 100%;
+    padding: 10px;
+    border: 1px solid #ddd;
+    border-radius: 4px;
+    outline: none;
+    font-size: 14px;
+    transition: border-color 0.2s;
+    
+    &:focus {
+      border-color: #007bff;
+    }
+  }
+}
+
+.btn-add {
+  padding: 8px 15px;
+  background-color: #007bff;
+  color: #fff;
+  border: none;
+  border-radius: 4px;
+  cursor: pointer;
+  white-space: nowrap;
+  
+  &:hover {
+    background-color: #0056b3;
+  }
+}
+
+/* 场景列表样式 */
+.scene-list-container {
+  margin-top: 30px;
+}
+
+.scene-list {
+  border: 1px solid #e5e7eb;
+  border-radius: 4px;
+  padding: 10px;
+  max-height: 300px;
+  overflow-y: auto;
+  background-color: #fff;
+}
+
+.scene-category {
+  margin-bottom: 15px;
+  padding-bottom: 10px;
+  border-bottom: 1px dashed #e5e7eb;
+  
+  h4 {
+    font-size: 15px;
+    margin-bottom: 10px;
+    color: #2c3e50;
+  }
+}
+
+.scene-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 10px;
+  background-color: #f9f9f9;
+  border-radius: 4px;
+  margin-bottom: 10px;
+  cursor: pointer;
+  transition: background-color 0.2s;
+  
+  &:hover {
+    background-color: #f0f7ff;
+  }
+}
+
+.scene-info {
+  flex: 1;
+  margin-right: 10px;
+}
+
+.scene-name {
+  font-weight: 500;
+  color: #333;
+  margin-bottom: 3px;
+}
+
+.scene-desc {
+  font-size: 13px;
+  color: #666;
+  line-height: 1.4;
+}
+
+.select-scene-btn {
+  padding: 6px 12px;
+  background-color: #28a745;
+  color: white;
+  border: none;
+  border-radius: 4px;
+  font-size: 13px;
+  cursor: pointer;
+  transition: background-color 0.2s;
+  
+  &:hover {
+    background-color: #218838;
+  }
+}
+
+.no-scene {
+  color: #999;
+  text-align: center;
+  padding: 20px 0;
+  font-size: 14px;
+}
+
+/* 对话模拟区域 */
+.chat-section {
+  flex: 1;
+  min-width: 300px;
+  background-color: #fff;
+  border-radius: 8px;
+  padding: 20px;
+  border: 1px solid #e5e7eb;
+  height: fit-content;
+  min-height: 480px;
+
+  h2 {
+    font-size: 18px;
+    color: #333;
+    margin-bottom: 15px;
+    border-left: 4px solid #007bff;
+    padding-left: 10px;
+  }
+  
+  .chat-messages {
+    height: 320px;
+    overflow-y: auto;
+    margin-bottom: 15px;
+    border: 1px solid #e5e7eb;
+    border-radius: 4px;
+    padding: 15px;
+    background-color: #fafafa;
+    
+    .system-message {
+      color: #666;
+      text-align: center;
+      padding: 10px;
+      font-style: italic;
+    }
+    
+    p {
+      margin: 8px 0;
+      padding: 10px 12px;
+      border-radius: 6px;
+      max-width: 70%;
+      word-wrap: break-word;
+      line-height: 1.5;
+    }
+    
+    p.user {
+      background-color: #d1ecf1;
+      color: #0c5460;
+      margin-left: auto;
+      box-shadow: 0 1px 2px rgba(0,0,0,0.05);
+    }
+    
+    p.bot {
+      background-color: #f1f3f5;
+      color: #495057;
+      box-shadow: 0 1px 2px rgba(0,0,0,0.05);
+    }
+  }
+  
+  .chat-input {
+    display: flex;
+    gap: 10px;
+    
+    input {
+      flex: 1;
+      padding: 10px;
+      border: 1px solid #ddd;
+      border-radius: 4px;
+      outline: none;
+    }
+    
+    button {
+      padding: 0 20px;
+      background-color: #007bff;
+      color: #fff;
+      border: none;
+      border-radius: 4px;
+      cursor: pointer;
+      font-weight: 500;
+      
+      &:hover {
+        background-color: #0056b3;
+      }
+    }
+  }
+}
+
+/* 评估与报告区域 */
+.eval-report {
+  width: 100%;
+  display: flex;
+  gap: 20px;
+  margin-top: 10px;
+}
+
+.card {
+  flex: 1;
+  min-width: 250px;
+  background-color: #fff;
+  border-radius: 8px;
+  padding: 20px;
+  border: 1px solid #e5e7eb;
+  box-shadow: 0 1px 3px rgba(0,0,0,0.05);
+  
+  h3 {
+    font-size: 16px;
+    color: #333;
+    margin-bottom: 20px;
+    padding-bottom: 10px;
+    border-bottom: 1px solid #f1f3f5;
+  }
+}
+
+.score-circle {
+  width: 120px;
+  height: 120px;
+  border-radius: 50%;
+  background-color: #f3f4f6;
+  margin: 0 auto 20px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 28px;
+  color: #007bff;
+  font-weight: bold;
+  position: relative;
+  box-shadow: inset 0 0 0 12px #fff, inset 0 0 0 13px #e5e7eb;
+}
+
+.score-details {
+  display: flex;
+  justify-content: space-around;
+  color: #666;
+  flex-wrap: wrap;
+  gap: 10px;
+  text-align: center;
+  
+  span {
+    font-size: 14px;
+    padding: 5px 0;
+    flex: 1;
+    min-width: 80px;
+    border-bottom: 2px solid #f1f3f5;
+  }
+}
+
+.report-list {
+  list-style: none;
+  padding: 0;
+  
+  li {
+    padding: 12px 0;
+    border-bottom: 1px solid #f1f3f5;
+    color: #333;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    
+    span {
+      color: #666;
+      font-size: 14px;
+    }
+  }
+}
+
+.btn-report {
+  padding: 6px 12px;
+  background-color: #007bff;
+  color: #fff;
+  border: none;
+  border-radius: 4px;
+  cursor: pointer;
+  text-decoration: none;
+  font-size: 14px;
+  
+  &:hover {
+    background-color: #0056b3;
+  }
+}
+
+/* 响应式调整 */
+@media (max-width: 768px) {
+  .main {
+    flex-direction: column;
+  }
+  
+  .sidebar {
+    width: 100%;
+    margin-right: 0;
+  }
+  
+  .eval-report {
+    flex-direction: column;
+  }
+}
+// 新增轮次和评分样式
+.training-info {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 10px;
+  color: #666;
+  font-size: 14px;
+}
+/* page-crm-training.scss (新增) */
+
+.report-modal {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 100;
+}
+
+.modal-content {
+  background-color: white;
+  border-radius: 8px;
+  max-width: 600px;
+  width: 90%;
+  max-height: 80vh;
+  overflow: auto;
+}
+
+.modal-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 16px;
+  border-bottom: 1px solid #eee;
+}
+
+.modal-body {
+  padding: 16px;
+}
+
+.report-date {
+  color: #666;
+  margin-bottom: 16px;
+}
+
+.report-content pre {
+  white-space: pre-wrap;
+  font-family: inherit;
+  line-height: 1.6;
+}

+ 207 - 6
ai-assisant/src/modules/crm/mobile/page-crm-training/page-crm-training.ts

@@ -1,11 +1,212 @@
-import { Component } from '@angular/core';
+import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { TrainingReportsComponent } from './report-viewer.component';
+import { TrainingService } from './training.service';
+import { Report, Scene } from './report.interface';
 
 
 @Component({
 @Component({
-  selector: 'app-page-crm-training',
-  imports: [],
+  selector: 'page-crm-training',
+  standalone: true,
+  imports: [CommonModule, FormsModule, TrainingReportsComponent],
   templateUrl: './page-crm-training.html',
   templateUrl: './page-crm-training.html',
-  styleUrl: './page-crm-training.scss'
+  styleUrls: ['./page-crm-training.scss']
 })
 })
-export class PageCrmTraining {
+export class PageCrmTraining implements OnInit {
+  @ViewChild('chatMessagesContainer') chatMessagesContainer!: ElementRef;
 
 
-}
+  // 场景数据
+  sceneLevels: { value: string; label: string }[] = [];
+  customerTypes: { value: string; label: string }[] = [];
+  allScenes: Scene[] = [];
+  filteredScenes: Scene[] = [];
+  selectedLevel: string = '';
+  selectedCustomerType: string = '';
+  selectedScene: Scene | null = null;
+
+  // 对话数据
+  chatMessages: Array<{
+    type: 'user' | 'bot';
+    content: string;
+    timestamp: Date;
+  }> = [];
+  chatInput: string = '';
+  currentRound: number = 1;
+  maxRounds: number = 5;
+  conversationScore: number | null = null;
+
+  // 报告数据
+  generatedReports: Report[] = [];
+  selectedReport: Report | null = null;
+
+  constructor(private trainingService: TrainingService) {}
+
+  ngOnInit(): void {
+    this.loadInitialData();
+  }
+
+  private loadInitialData(): void {
+    this.trainingService.getSceneLevels().subscribe(levels => {
+      this.sceneLevels = levels;
+    });
+
+    this.trainingService.getCustomerTypes().subscribe(types => {
+      this.customerTypes = types;
+    });
+
+    this.trainingService.getAllScenes().subscribe(scenes => {
+      this.allScenes = scenes;
+      this.filteredScenes = [...scenes];
+    });
+  }
+
+  filterScenes(): void {
+    this.filteredScenes = this.allScenes.filter(scene => {
+      const levelMatch = !this.selectedLevel || scene.level === this.selectedLevel;
+      const typeMatch = !this.selectedCustomerType || scene.customerType === this.selectedCustomerType;
+      return levelMatch && typeMatch;
+    });
+  }
+
+  getLevelLabel(levelValue: string): string {
+    const level = this.sceneLevels.find(l => l.value === levelValue);
+    return level ? level.label : levelValue;
+  }
+
+  getCustomerLabel(typeValue: string): string {
+    const type = this.customerTypes.find(t => t.value === typeValue);
+    return type ? type.label : typeValue;
+  }
+
+  selectScene(scene: Scene): void {
+    this.selectedScene = scene;
+    this.currentRound = 1;
+    this.conversationScore = null;
+    this.chatMessages = [{
+      type: 'bot',
+      content: scene.initialMessage,
+      timestamp: new Date()
+    }];
+    this.scrollToBottom();
+  }
+
+  sendMessage(): void {
+    if (!this.chatInput.trim() || !this.selectedScene) return;
+
+    // 添加用户消息
+    const userMessage = {
+      type: 'user' as const,
+      content: this.chatInput,
+      timestamp: new Date()
+    };
+    this.chatMessages.push(userMessage);
+    this.chatInput = '';
+    this.scrollToBottom();
+
+    // 模拟AI回复
+    setTimeout(() => {
+      const botResponse = this.trainingService.generateResponse(
+        this.selectedScene!.id, 
+        userMessage.content
+      );
+      
+      this.chatMessages.push({
+        type: 'bot' as const,
+        content: botResponse,
+        timestamp: new Date()
+      });
+
+      // 更新轮次和评分
+      this.currentRound = Math.ceil(this.chatMessages.length / 2);
+      if (this.currentRound <= this.maxRounds) {
+        this.updateScore();
+      }
+
+      this.scrollToBottom();
+    }, 800);
+  }
+
+  private updateScore(): void {
+    const baseScore = 80;
+    const roundBonus = (this.currentRound - 1) * 5;
+    const randomVariation = Math.floor(Math.random() * 10);
+    
+    this.conversationScore = Math.min(baseScore + roundBonus + randomVariation, 100);
+
+    // 如果完成所有轮次,生成报告
+    if (this.currentRound === this.maxRounds) {
+      this.generateReport();
+    }
+  }
+
+  private generateReport(): void {
+    if (!this.selectedScene) return;
+
+    const newReport: Report = {
+      id: `report-${Date.now()}`,
+      name: this.selectedScene.name,
+      sceneId: this.selectedScene.id,
+      date: new Date().toISOString(),
+      difficulty: this.selectedScene.level,
+      customerRole: this.selectedScene.customerType,
+      score: this.conversationScore || 0,
+      evaluations: {
+        responsiveness: Math.min(this.conversationScore! + Math.floor(Math.random() * 10) - 5, 100),
+        话术: Math.min((this.conversationScore || 80) + Math.floor(Math.random() * 8) - 4, 100),
+        persuasion: Math.min((this.conversationScore || 75) + Math.floor(Math.random() * 12) - 6, 100),
+        professionalism: Math.min((this.conversationScore || 85) + Math.floor(Math.random() * 6) - 3, 100)
+      },
+      summary: this.generateSummaryText()
+    };
+
+    this.generatedReports.unshift(newReport);
+  }
+
+  private generateSummaryText(): string {
+    const strengths = [
+      '展现了出色的沟通技巧',
+      '对产品知识掌握扎实',
+      '能够有效处理客户异议',
+      '表现出了高度的专业性',
+      '对话流畅自然',
+      '反应迅速准确'
+    ];
+    
+    const improvements = [
+      '可以进一步提高反应速度',
+      '建议丰富案例说明',
+      '需要加强价格谈判技巧',
+      '可优化话术结构',
+      '应更关注客户需求',
+      '可增加数据支持论点'
+    ];
+
+    return `在${this.selectedScene?.name}场景训练中,${
+      strengths[Math.floor(Math.random() * strengths.length)]
+    },${improvements[Math.floor(Math.random() * improvements.length)]}。`;
+  }
+
+  resetConversation(): void {
+    if (this.selectedScene) {
+      this.selectScene(this.selectedScene);
+    }
+  }
+
+  viewReport(report: Report): void {
+    this.selectedReport = report;
+    console.log('查看完整报告:', report);
+  }
+
+  closeReport(): void {
+    this.selectedReport = null;
+  }
+
+  private scrollToBottom(): void {
+    setTimeout(() => {
+      if (this.chatMessagesContainer) {
+        this.chatMessagesContainer.nativeElement.scrollTop = 
+          this.chatMessagesContainer.nativeElement.scrollHeight;
+      }
+    }, 100);
+  }
+}

+ 284 - 0
ai-assisant/src/modules/crm/mobile/page-crm-training/report-viewer.component.ts

@@ -0,0 +1,284 @@
+import { Component, Input, Output, EventEmitter } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Report } from './report.interface';
+
+interface EvaluationItem {
+  label: string;
+  score: number;
+}
+
+@Component({
+  selector: 'app-training-reports',
+  standalone: true,
+  imports: [CommonModule],
+  template: `
+    <div class="training-reports">
+      <h2>训练报告</h2>
+      
+      <div class="report-list">
+        <div *ngFor="let report of reports" 
+             class="report-card"
+             (click)="selectReport(report)">
+          <div class="report-header">
+            <h3>{{report.name}}</h3>
+            <span>{{report.date | date:'yyyy-MM-dd HH:mm'}}</span>
+          </div>
+          <div class="report-meta">
+            <span>难度: {{getDifficultyLabel(report.difficulty)}}</span>
+            <span>角色: {{report.customerRole}}</span>
+            <span class="score-badge">得分: {{report.score || 0}}/100</span>
+          </div>
+        </div>
+      </div>
+
+      <div *ngIf="selectedReport" class="modal-overlay" (click)="closeReport($event)">
+        <div class="modal-content" (click)="$event.stopPropagation()">
+          <div class="report-detail">
+            <div class="detail-header">
+              <h2>{{selectedReport.name}}</h2>
+              <button class="close-btn" (click)="closeReport()">×</button>
+            </div>
+            <div class="detail-meta">
+              <span><strong>日期:</strong> {{selectedReport.date | date:'yyyy-MM-dd HH:mm'}}</span>
+              <span><strong>难度:</strong> {{getDifficultyLabel(selectedReport.difficulty)}}</span>
+              <span><strong>角色:</strong> {{selectedReport.customerRole}}</span>
+              <span><strong>总分:</strong> {{selectedReport.score || 0}}/100</span>
+            </div>
+            
+            <div class="detail-evaluations">
+              <h3>能力评估</h3>
+              <div class="eval-grid">
+                <div *ngFor="let eval of getEvaluations(selectedReport)" class="eval-card">
+                  <div class="eval-score">{{eval.score}}</div>
+                  <div class="eval-label">{{eval.label}}</div>
+                  <div class="progress-bar">
+                    <div class="progress-fill" [style.width.%]="eval.score"></div>
+                  </div>
+                </div>
+              </div>
+            </div>
+            
+            <div class="detail-summary">
+              <h3>训练总结</h3>
+              <p>{{selectedReport.summary}}</p>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  `,
+  styles: [`
+    .training-reports {
+      padding: 20px;
+      max-width: 1200px;
+      margin: 0 auto;
+    }
+    
+    .report-list {
+      display: grid;
+      gap: 15px;
+    }
+    
+    .report-card {
+      background: white;
+      border-radius: 8px;
+      padding: 15px;
+      cursor: pointer;
+      transition: all 0.2s ease;
+      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+      border-left: 4px solid #4CAF50;
+    }
+    
+    .report-card:hover {
+      transform: translateY(-2px);
+      box-shadow: 0 4px 8px rgba(0,0,0,0.15);
+    }
+    
+    .report-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 10px;
+    }
+    
+    .report-header h3 {
+      margin: 0;
+      color: #333;
+    }
+    
+    .report-meta {
+      display: flex;
+      gap: 15px;
+      color: #666;
+      font-size: 0.9rem;
+      flex-wrap: wrap;
+    }
+    
+    .score-badge {
+      background: #4CAF50;
+      color: white;
+      padding: 2px 8px;
+      border-radius: 12px;
+      font-size: 0.8rem;
+    }
+    
+    .modal-overlay {
+      position: fixed;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      background: rgba(0,0,0,0.5);
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      z-index: 1000;
+    }
+    
+    .modal-content {
+      background: white;
+      border-radius: 8px;
+      width: 90%;
+      max-width: 800px;
+      max-height: 90vh;
+      overflow: auto;
+      box-shadow: 0 4px 20px rgba(0,0,0,0.2);
+    }
+    
+    .report-detail {
+      padding: 25px;
+    }
+    
+    .detail-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 20px;
+      border-bottom: 1px solid #eee;
+      padding-bottom: 15px;
+    }
+    
+    .detail-header h2 {
+      margin: 0;
+      color: #333;
+    }
+    
+    .close-btn {
+      background: none;
+      border: none;
+      font-size: 24px;
+      cursor: pointer;
+      color: #666;
+    }
+    
+    .detail-meta {
+      display: flex;
+      flex-wrap: wrap;
+      gap: 15px;
+      margin-bottom: 20px;
+      color: #555;
+    }
+    
+    .detail-meta span {
+      display: flex;
+      align-items: center;
+      gap: 5px;
+    }
+    
+    .detail-meta strong {
+      color: #333;
+    }
+    
+    .eval-grid {
+      display: grid;
+      grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
+      gap: 15px;
+      margin-top: 15px;
+    }
+    
+    .eval-card {
+      background: #f8f9fa;
+      border-radius: 8px;
+      padding: 15px;
+      text-align: center;
+    }
+    
+    .eval-score {
+      font-size: 28px;
+      font-weight: bold;
+      color: #333;
+      margin-bottom: 5px;
+    }
+    
+    .eval-label {
+      color: #666;
+      font-size: 0.9rem;
+      margin-bottom: 10px;
+    }
+    
+    .progress-bar {
+      height: 6px;
+      background: #e0e0e0;
+      border-radius: 3px;
+      overflow: hidden;
+    }
+    
+    .progress-fill {
+      height: 100%;
+      background: #4CAF50;
+      transition: width 0.3s ease;
+    }
+    
+    .detail-summary {
+      margin-top: 25px;
+      padding-top: 20px;
+      border-top: 1px solid #eee;
+    }
+    
+    .detail-summary h3 {
+      color: #333;
+      margin-top: 0;
+    }
+    
+    .detail-summary p {
+      line-height: 1.6;
+      color: #444;
+    }
+  `]
+})
+export class TrainingReportsComponent {
+  @Input() reports: Report[] = [];
+  @Output() reportSelected = new EventEmitter<Report>();
+
+  selectedReport: Report | null = null;
+
+  getDifficultyLabel(difficulty: string): string {
+    const labels: Record<string, string> = {
+      'easy': '初级',
+      'medium': '中级',
+      'hard': '高级',
+      'expert': '专家级'
+    };
+    return labels[difficulty] || difficulty;
+  }
+
+  getEvaluations(report: Report): EvaluationItem[] {
+    return [
+      { label: '反应力', score: report.evaluations.responsiveness },
+      { label: '话术', score: report.evaluations.话术 },
+      { label: '说服力', score: report.evaluations.persuasion },
+      { label: '专业度', score: report.evaluations.professionalism }
+    ];
+  }
+
+  selectReport(report: Report): void {
+    this.selectedReport = report;
+    this.reportSelected.emit(report);
+  }
+
+  closeReport(event?: MouseEvent): void {
+    if (!event || (event.target as HTMLElement).classList.contains('modal-overlay')) {
+      this.selectedReport = null;
+    }
+  }
+}

+ 40 - 0
ai-assisant/src/modules/crm/mobile/page-crm-training/report.interface.ts

@@ -0,0 +1,40 @@
+// src/modules/crm/mobile/page-crm-training/report.interface.ts
+
+// 场景接口
+export interface Scene {
+  id: string;
+  name: string;
+  description: string;
+  level: string;          // 对应难度值:easy/medium/hard
+  customerType: string;   // 对应客户类型值
+  initialMessage: string; // 场景初始消息
+}
+
+// 报告接口
+export interface Report {
+  id: string;
+  name: string;               // 报告名称
+  sceneId?: string;           // 关联场景ID(可选)
+  date: string;               // 报告日期
+  difficulty: string;         // 难度级别
+  customerRole: string;       // 客户角色
+  score?: number;             // 总分(可选)
+  evaluations: {              // 各项评估分数
+    responsiveness: number;   // 反应力
+    话术: number;             // 话术
+    persuasion: number;       // 说服力
+    professionalism: number;  // 专业度
+  };
+  summary: string;            // 总结评语
+}
+
+// 可选:其他相关类型
+export interface SceneLevel {
+  value: string;  // easy/medium/hard
+  label: string;  // 初级/中级/高级
+}
+
+export interface CustomerType {
+  value: string;  // new/returning/vip 等
+  label: string;  // 新客户/回头客/VIP客户 等
+}

+ 159 - 0
ai-assisant/src/modules/crm/mobile/page-crm-training/training.service.ts

@@ -0,0 +1,159 @@
+import { Injectable } from '@angular/core';
+import { Observable, of } from 'rxjs';
+import { delay } from 'rxjs/operators';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class TrainingService {
+  // 模拟数据库
+  private sceneLevels: SceneLevel[] = [
+    { value: 'easy', label: '初级' },
+    { value: 'medium', label: '中级' },
+    { value: 'hard', label: '高级' }
+  ];
+
+  private customerTypes: CustomerType[] = [
+    { value: 'new', label: '新客户' },
+    { value: 'returning', label: '回头客' },
+    { value: 'vip', label: 'VIP客户' },
+    { value: 'complaining', label: '投诉客户' }
+  ];
+
+  private allScenes: Scene[] = [
+    {
+      id: 'scene-1',
+      name: '产品初次介绍',
+      description: '向新客户介绍公司主打产品',
+      level: 'easy',
+      customerType: 'new',
+      initialMessage: '您好,我对贵公司的产品很感兴趣,能简单介绍一下吗?'
+    },
+    {
+      id: 'scene-2',
+      name: '处理价格异议',
+      description: '应对客户对价格的质疑',
+      level: 'medium',
+      customerType: 'returning',
+      initialMessage: '你们的产品价格比竞争对手高不少,能解释下为什么吗?'
+    },
+    {
+      id: 'scene-3',
+      name: 'VIP客户维护',
+      description: '与重要客户保持良好关系',
+      level: 'medium',
+      customerType: 'vip',
+      initialMessage: '王总,感谢您一直以来的支持,最近使用我们的产品还满意吗?'
+    },
+    {
+      id: 'scene-4',
+      name: '处理严重投诉',
+      description: '解决客户重大不满问题',
+      level: 'hard',
+      customerType: 'complaining',
+      initialMessage: '你们的产品简直太差了!我要退货并要求赔偿!'
+    }
+  ];
+
+  private sampleReports: Report[] = [
+    {
+      id: 'report-1',
+      sceneId: 'scene-1',
+      sceneName: '产品初次介绍',
+      date: new Date('2023-06-15').toISOString(),
+      score: 88,
+      evaluations: {
+        responsiveness: 85,
+        话术: 82,
+        persuasion: 78,
+        professionalism: 90
+      },
+      summary: '产品介绍流畅,但未能有效突出产品独特卖点'
+    }
+  ];
+
+  constructor() { }
+
+  getSceneLevels(): Observable<SceneLevel[]> {
+    return of(this.sceneLevels).pipe(delay(300));
+  }
+
+  getCustomerTypes(): Observable<CustomerType[]> {
+    return of(this.customerTypes).pipe(delay(300));
+  }
+
+  getAllScenes(): Observable<Scene[]> {
+    return of(this.allScenes).pipe(delay(400));
+  }
+
+  getGeneratedReports(): Observable<Report[]> {
+    return of(this.sampleReports).pipe(delay(500));
+  }
+
+  generateResponse(sceneId: string, userInput: string): string {
+    const scene = this.allScenes.find(s => s.id === sceneId);
+    if (!scene) return '我不太明白您的意思';
+
+    // 根据场景和用户输入生成响应
+    if (sceneId === 'scene-1') {
+      if (userInput.includes('价格') || userInput.includes('多少钱')) {
+        return '我们的产品价格区间在X到Y之间,具体取决于配置。您对哪个型号感兴趣?';
+      }
+      return '这款产品的核心优势是A、B、C三个功能,能有效解决您面临的X问题。';
+    }
+    
+    if (sceneId === 'scene-4') {
+      if (userInput.includes('抱歉') || userInput.includes('对不起')) {
+        return '道歉是不够的!我需要你们立即解决问题!';
+      }
+      if (userInput.includes('方案') || userInput.includes('解决')) {
+        return '我们提供三种解决方案:1. 全额退款 2. 产品更换 3. 补偿优惠券,您倾向于哪种?';
+      }
+      return '我理解您的不满,请给我们一个改正的机会。';
+    }
+
+    // 默认回复逻辑
+    const responses = [
+      '这是一个很好的观点,我们可以详细讨论。',
+      '关于这个问题,我们的专业团队是这样建议的...',
+      '我理解您的担忧,实际上我们的产品是这样处理的...',
+      '根据大多数客户反馈,这个问题的解决方案是...'
+    ];
+    return responses[Math.floor(Math.random() * responses.length)];
+  }
+}
+
+// 数据模型
+export interface SceneLevel {
+  value: string;
+  label: string;
+}
+
+export interface CustomerType {
+  value: string;
+  label: string;
+}
+
+export interface Scene {
+  id: string;
+  name: string;
+  description: string;
+  level: string;
+  customerType: string;
+  initialMessage: string;
+}
+
+export interface Report {
+  id: string;
+  sceneId: string;
+  sceneName: string;
+  date: string;
+  score: number;
+  evaluations: {
+    responsiveness: number;
+    话术: number;
+    persuasion: number;
+    professionalism: number;
+  };
+  summary: string;
+}

+ 3 - 0
ai-assisant/src/styles.scss

@@ -1 +1,4 @@
 /* You can add global styles to this file, and also import other style files */
 /* You can add global styles to this file, and also import other style files */
+
+html, body { height: 100%; }
+body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }