Browse Source

feat: new home page

0235711 4 days ago
parent
commit
2a4ac8760f
26 changed files with 2045 additions and 248 deletions
  1. 4 1
      manager-web/angular.json
  2. 65 0
      manager-web/package-lock.json
  3. 3 0
      manager-web/package.json
  4. 4 2
      manager-web/src/app/app.config.ts
  5. 1 1
      manager-web/src/modules/manager/mobile/mobile.routes.ts
  6. 2 2
      manager-web/src/modules/manager/mobile/nav-mobile-tabs/nav-mobile-tabs.html
  7. 1 0
      manager-web/src/modules/manager/mobile/page-home/components/header/header.html
  8. 0 0
      manager-web/src/modules/manager/mobile/page-home/components/header/header.scss
  9. 23 0
      manager-web/src/modules/manager/mobile/page-home/components/header/header.spec.ts
  10. 82 0
      manager-web/src/modules/manager/mobile/page-home/components/header/header.ts
  11. 1 0
      manager-web/src/modules/manager/mobile/page-home/components/permission-modal/permission-modal.html
  12. 0 0
      manager-web/src/modules/manager/mobile/page-home/components/permission-modal/permission-modal.scss
  13. 23 0
      manager-web/src/modules/manager/mobile/page-home/components/permission-modal/permission-modal.spec.ts
  14. 219 0
      manager-web/src/modules/manager/mobile/page-home/components/permission-modal/permission-modal.ts
  15. 1 0
      manager-web/src/modules/manager/mobile/page-home/components/sales-card/sales-card.html
  16. 0 0
      manager-web/src/modules/manager/mobile/page-home/components/sales-card/sales-card.scss
  17. 23 0
      manager-web/src/modules/manager/mobile/page-home/components/sales-card/sales-card.spec.ts
  18. 215 0
      manager-web/src/modules/manager/mobile/page-home/components/sales-card/sales-card.ts
  19. 1 0
      manager-web/src/modules/manager/mobile/page-home/components/sidebar/sidebar.html
  20. 0 0
      manager-web/src/modules/manager/mobile/page-home/components/sidebar/sidebar.scss
  21. 23 0
      manager-web/src/modules/manager/mobile/page-home/components/sidebar/sidebar.spec.ts
  22. 145 0
      manager-web/src/modules/manager/mobile/page-home/components/sidebar/sidebar.ts
  23. 281 234
      manager-web/src/modules/manager/mobile/page-home/page-home.html
  24. 704 0
      manager-web/src/modules/manager/mobile/page-home/page-home.scss
  25. 222 7
      manager-web/src/modules/manager/mobile/page-home/page-home.ts
  26. 2 1
      manager-web/src/modules/manager/mobile/page-mine/page-mine.ts

+ 4 - 1
manager-web/angular.json

@@ -88,7 +88,8 @@
               }
             ],
             "styles": [
-              "src/styles.scss"
+              "src/styles.scss",
+              "node_modules/@fortawesome/fontawesome-free/css/all.css"
             ]
           }
         }
@@ -96,3 +97,5 @@
     }
   }
 }
+
+

+ 65 - 0
manager-web/package-lock.json

@@ -14,6 +14,9 @@
         "@angular/forms": "^20.0.0",
         "@angular/platform-browser": "^20.0.0",
         "@angular/router": "^20.0.0",
+        "chart.js": "^4.5.0",
+        "echarts": "^5.6.0",
+        "ngx-echarts": "^20.0.1",
         "rxjs": "~7.8.0",
         "tslib": "^2.3.0",
         "zone.js": "~0.15.0"
@@ -1653,6 +1656,12 @@
         "@jridgewell/sourcemap-codec": "^1.4.14"
       }
     },
+    "node_modules/@kurkle/color": {
+      "version": "0.3.4",
+      "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
+      "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
+      "license": "MIT"
+    },
     "node_modules/@listr2/prompt-adapter-inquirer": {
       "version": "2.0.22",
       "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.22.tgz",
@@ -3811,6 +3820,18 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/chart.js": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/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": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
@@ -4334,6 +4355,22 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/echarts": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz",
+      "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "tslib": "2.3.0",
+        "zrender": "5.6.1"
+      }
+    },
+    "node_modules/echarts/node_modules/tslib": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
+      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
+      "license": "0BSD"
+    },
     "node_modules/ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -6582,6 +6619,19 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/ngx-echarts": {
+      "version": "20.0.1",
+      "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-20.0.1.tgz",
+      "integrity": "sha512-SpMj8jX4qVle1ZEA3ob4AlTXduhsUeMQdyILu7UWcNr/zRqR3dPgiiahIepdOIel+5PJDl3qtJGUiYhuIyUUMA==",
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.3.0"
+      },
+      "peerDependencies": {
+        "@angular/core": ">=20.0.0",
+        "echarts": ">=5.0.0"
+      }
+    },
     "node_modules/node-addon-api": {
       "version": "6.1.0",
       "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz",
@@ -8902,6 +8952,21 @@
       "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz",
       "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==",
       "license": "MIT"
+    },
+    "node_modules/zrender": {
+      "version": "5.6.1",
+      "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz",
+      "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==",
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "tslib": "2.3.0"
+      }
+    },
+    "node_modules/zrender/node_modules/tslib": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
+      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
+      "license": "0BSD"
     }
   }
 }

+ 3 - 0
manager-web/package.json

@@ -26,6 +26,9 @@
     "@angular/forms": "^20.0.0",
     "@angular/platform-browser": "^20.0.0",
     "@angular/router": "^20.0.0",
+    "chart.js": "^4.5.0",
+    "echarts": "^5.6.0",
+    "ngx-echarts": "^20.0.1",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",
     "zone.js": "~0.15.0"

+ 4 - 2
manager-web/src/app/app.config.ts

@@ -2,11 +2,13 @@ import { ApplicationConfig, provideBrowserGlobalErrorListeners, provideZoneChang
 import { provideRouter } from '@angular/router';
 
 import { routes } from './app.routes';
-
+import { provideEchartsCore } from 'ngx-echarts';
+import * as echarts from 'echarts/core';
 export const appConfig: ApplicationConfig = {
   providers: [
     provideBrowserGlobalErrorListeners(),
     provideZoneChangeDetection({ eventCoalescing: true }),
-    provideRouter(routes)
+    provideRouter(routes),
+    provideEchartsCore({echarts})
   ]
 };

+ 1 - 1
manager-web/src/modules/manager/mobile/mobile.routes.ts

@@ -8,7 +8,7 @@ export const MOBILE_ROUTES: Routes = [
     children: [
       {
         path: 'home',
-        loadComponent: () => import('./page-home/page-home').then(m => m.PageHome)
+        loadComponent: () => import('./page-home/page-home').then(m => m.PageHome) 
       },
       {
         path: 'cart',

+ 2 - 2
manager-web/src/modules/manager/mobile/nav-mobile-tabs/nav-mobile-tabs.html

@@ -15,9 +15,9 @@
             <span>销售数据</span>
         </a>
         
-        <a href="#" class="nav-tab">
+        <a routerLink="/mobile/mine" class="nav-tab">
             <i class="fas fa-chart-line"></i>
-            <span>业绩分析</span>
+            <span>场馆日历</span>
         </a>
         
         <a href="#" class="nav-tab">

+ 1 - 0
manager-web/src/modules/manager/mobile/page-home/components/header/header.html

@@ -0,0 +1 @@
+<p>header works!</p>

+ 0 - 0
manager-web/src/modules/manager/mobile/page-home/components/header/header.scss


+ 23 - 0
manager-web/src/modules/manager/mobile/page-home/components/header/header.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { Header } from './header';
+
+describe('Header', () => {
+  let component: Header;
+  let fixture: ComponentFixture<Header>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [Header]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(Header);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 82 - 0
manager-web/src/modules/manager/mobile/page-home/components/header/header.ts

@@ -0,0 +1,82 @@
+// header.component.ts
+import { Component } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+@Component({
+  selector: 'app-header',
+  standalone: true,
+  imports: [CommonModule],
+  template: `
+    <header>
+      <div class="logo">
+        <div class="logo-icon">
+          <i class="fas fa-crown"></i>
+        </div>
+        <div class="logo-text">
+          <h1>九州管理</h1>
+          <p>智能AI权限管理系统</p>
+        </div>
+      </div>
+      <div class="user-actions">
+        <button class="btn btn-outline">
+          <i class="fas fa-sync-alt"></i> 刷新数据
+        </button>
+        <button class="btn btn-primary" (click)="addSales()">
+          <i class="fas fa-plus"></i> 添加销售
+        </button>
+      </div>
+    </header>
+  `,
+  styles: [`
+    header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 20px 0;
+      margin-bottom: 30px;
+      border-bottom: 1px solid rgba(255, 255, 255, 0.2);
+    }
+    
+    .logo {
+      display: flex;
+      align-items: center;
+      gap: 15px;
+    }
+    
+    .logo-icon {
+      width: 50px;
+      height: 50px;
+      background: linear-gradient(135deg, #1a56db, #3b82f6);
+      border-radius: 12px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 24px;
+      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.15);
+    }
+    
+    .logo-text h1 {
+      font-size: 24px;
+      font-weight: 700;
+      background: linear-gradient(to right, #fbcfe8, #c7d2fe);
+      -webkit-background-clip: text;
+      -webkit-text-fill-color: transparent;
+    }
+    
+    .logo-text p {
+      font-size: 14px;
+      color: #cbd5e1;
+      letter-spacing: 1px;
+    }
+    
+    .user-actions {
+      display: flex;
+      gap: 15px;
+    }
+  `]
+})
+export class HeaderComponent {
+  addSales() {
+    // 实际逻辑在父组件处理
+  }
+}

+ 1 - 0
manager-web/src/modules/manager/mobile/page-home/components/permission-modal/permission-modal.html

@@ -0,0 +1 @@
+<p>permission-modal works!</p>

+ 0 - 0
manager-web/src/modules/manager/mobile/page-home/components/permission-modal/permission-modal.scss


+ 23 - 0
manager-web/src/modules/manager/mobile/page-home/components/permission-modal/permission-modal.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PermissionModal } from './permission-modal';
+
+describe('PermissionModal', () => {
+  let component: PermissionModal;
+  let fixture: ComponentFixture<PermissionModal>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [PermissionModal]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(PermissionModal);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 219 - 0
manager-web/src/modules/manager/mobile/page-home/components/permission-modal/permission-modal.ts

@@ -0,0 +1,219 @@
+// permission-modal.component.ts
+import { Component, Input, Output, EventEmitter } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+@Component({
+  selector: 'app-permission-modal',
+  standalone: true,
+  imports: [CommonModule],
+  template: `
+    <div class="permission-modal active" (click)="onBackdropClick($event)">
+      <div class="modal-content">
+        <div class="modal-header">
+          <h2>{{ currentSales?.name }} - 权限管理</h2>
+          <button class="close-btn" (click)="onClose()">&times;</button>
+        </div>
+        <div class="modal-body">
+          <div class="ai-recommendation">
+            <p><i class="fas fa-lightbulb"></i> {{ getAiRecommendation() }}</p>
+            <button class="btn btn-primary" (click)="onApplyAi()">
+              <i class="fas fa-check"></i> 应用AI建议
+            </button>
+          </div>
+          
+          <div class="permission-options">
+            <!-- 权限选项保持不变 -->
+          </div>
+        </div>
+        <div class="modal-footer">
+          <button class="btn btn-outline" (click)="onClose()">取消</button>
+          <button class="btn btn-primary" (click)="onSave()">保存设置</button>
+        </div>
+      </div>
+    </div>
+  `,
+  styles: [`
+    .permission-modal {
+      position: fixed;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      background: rgba(15, 23, 42, 0.9);
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      z-index: 1000;
+    }
+    
+    .modal-content {
+      background: rgba(255, 255, 255, 0.85);
+      width: 90%;
+      max-width: 600px;
+      border-radius: 20px;
+      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.15);
+      overflow: hidden;
+    }
+    
+    .modal-header {
+      padding: 20px;
+      background: linear-gradient(135deg, #1a56db, #3b82f6);
+      color: white;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+    }
+    
+    .modal-header h2 {
+      font-size: 22px;
+    }
+    
+    .close-btn {
+      background: transparent;
+      border: none;
+      color: white;
+      font-size: 24px;
+      cursor: pointer;
+    }
+    
+    .modal-body {
+      padding: 25px;
+      color: #0f172a;
+    }
+    
+    .ai-recommendation {
+      background: rgba(26, 86, 219, 0.1);
+      border-left: 4px solid #1a56db;
+      padding: 15px;
+      margin-bottom: 20px;
+      border-radius: 0 8px 8px 0;
+    }
+    
+    .ai-recommendation p {
+      margin-bottom: 10px;
+    }
+    
+    .permission-options {
+      display: flex;
+      flex-direction: column;
+      gap: 15px;
+    }
+    
+    .permission-option {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 12px 15px;
+      background: rgba(241, 245, 249, 0.5);
+      border-radius: 10px;
+    }
+    
+    .permission-info {
+      flex: 1;
+    }
+    
+    .permission-info h3 {
+      font-size: 16px;
+      margin-bottom: 5px;
+    }
+    
+    .permission-info p {
+      font-size: 13px;
+      color: #64748b;
+    }
+    
+    .switch {
+      position: relative;
+      display: inline-block;
+      width: 50px;
+      height: 24px;
+    }
+    
+    .switch input {
+      opacity: 0;
+      width: 0;
+      height: 0;
+    }
+    
+    .slider {
+      position: absolute;
+      cursor: pointer;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      background-color: #ccc;
+      transition: .4s;
+      border-radius: 24px;
+    }
+    
+    .slider:before {
+      position: absolute;
+      content: "";
+      height: 16px;
+      width: 16px;
+      left: 4px;
+      bottom: 4px;
+      background-color: white;
+      transition: .4s;
+      border-radius: 50%;
+    }
+    
+    input:checked + .slider {
+      background-color: #10b981;
+    }
+    
+    input:checked + .slider:before {
+      transform: translateX(26px);
+    }
+    
+    .modal-footer {
+      padding: 20px;
+      display: flex;
+      justify-content: flex-end;
+      gap: 15px;
+      border-top: 1px solid rgba(0, 0, 0, 0.1);
+    }
+  `]
+})
+export class PermissionModalComponent {
+  @Input() currentSales: any;
+  @Output() close = new EventEmitter<void>();
+  @Output() applyAi = new EventEmitter<void>();
+  @Output() save = new EventEmitter<void>();
+
+  onBackdropClick(event: MouseEvent) {
+    if ((event.target as HTMLElement).classList.contains('permission-modal')) {
+      this.onClose();
+    }
+  }
+
+  onClose() {
+    this.close.emit();
+  }
+
+  onApplyAi() {
+    this.applyAi.emit();
+  }
+
+  onSave() {
+    this.save.emit();
+  }
+
+  getAiRecommendation(): string {
+    if (!this.currentSales) return '';
+    
+    switch(this.currentSales.levelName) {
+      case '实习销售':
+        return 'AI建议:根据该销售表现,建议升级为<span class="ai-highlight">白银销售</span>权限级别';
+      case '白银销售':
+        return 'AI建议:根据该销售表现,建议升级为<span class="ai-highlight">黄金销售</span>权限级别';
+      case '黄金销售':
+        return 'AI建议:根据该销售表现,建议升级为<span class="ai-highlight">铂金销售</span>权限级别';
+      case '铂金销售':
+        return 'AI建议:根据该销售表现,建议升级为<span class="ai-highlight">钻石销售</span>权限级别';
+      default:
+        return 'AI建议:该销售已达到最高权限级别,表现优秀';
+    }
+  }
+}

+ 1 - 0
manager-web/src/modules/manager/mobile/page-home/components/sales-card/sales-card.html

@@ -0,0 +1 @@
+<p>sales-card works!</p>

+ 0 - 0
manager-web/src/modules/manager/mobile/page-home/components/sales-card/sales-card.scss


+ 23 - 0
manager-web/src/modules/manager/mobile/page-home/components/sales-card/sales-card.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SalesCard } from './sales-card';
+
+describe('SalesCard', () => {
+  let component: SalesCard;
+  let fixture: ComponentFixture<SalesCard>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [SalesCard]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(SalesCard);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 215 - 0
manager-web/src/modules/manager/mobile/page-home/components/sales-card/sales-card.ts

@@ -0,0 +1,215 @@
+// sales-card.component.ts
+import { Component, Input, Output, EventEmitter } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+@Component({
+  selector: 'app-sales-card',
+  standalone: true,
+  imports: [CommonModule],
+  template: `
+    <div class="card" [ngClass]="sales.level" (click)="selectCard()">
+      <!-- 其他内容保持不变 -->
+      <div class="card-footer">
+        <button class="permission-btn btn-edit" (click)="onEditPermission($event)">
+          <i class="fas fa-user-cog"></i> 权限管理
+        </button>
+        <button class="permission-btn btn-details">
+          <i class="fas fa-chart-bar"></i> 业绩详情
+        </button>
+      </div>
+    </div>
+  `,
+  styles: [`
+    .card {
+      background: rgba(255, 255, 255, 0.85);
+      backdrop-filter: blur(10px);
+      border-radius: 20px;
+      border: 1px solid rgba(255, 255, 255, 0.2);
+      overflow: hidden;
+      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.15);
+      transition: all 0.3s ease;
+      color: #0f172a;
+    }
+    
+    .card:hover {
+      transform: translateY(-5px);
+      box-shadow: 0 12px 20px rgba(31, 38, 135, 0.2);
+    }
+    
+    .card-header {
+      padding: 20px;
+      display: flex;
+      align-items: center;
+      gap: 15px;
+      border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+      position: relative;
+    }
+    
+    .card-header::before {
+      content: '';
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      height: 4px;
+    }
+    
+    .rookie .card-header::before { background: linear-gradient(90deg, #60a5fa, #3b82f6); }
+    .silver .card-header::before { background: linear-gradient(90deg, #cbd5e1, #94a3b8); }
+    .gold .card-header::before { background: linear-gradient(90deg, #fcd34d, #f59e0b); }
+    .platinum .card-header::before { background: linear-gradient(90deg, #a5b4fc, #818cf8); }
+    .diamond .card-header::before { background: linear-gradient(90deg, #67e8f9, #22d3ee); }
+    
+    .avatar {
+      width: 60px;
+      height: 60px;
+      border-radius: 50%;
+      overflow: hidden;
+      border: 3px solid white;
+      box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+    }
+    
+    .avatar img {
+      width: 100%;
+      height: 100%;
+      object-fit: cover;
+    }
+    
+    .user-info {
+      flex: 1;
+    }
+    
+    .user-info h3 {
+      font-size: 18px;
+      font-weight: 700;
+      margin-bottom: 5px;
+      color: #0f172a;
+    }
+    
+    .user-info p {
+      font-size: 14px;
+      color: #64748b;
+    }
+    
+    .user-tag {
+      padding: 4px 12px;
+      border-radius: 20px;
+      font-size: 12px;
+      font-weight: 600;
+      margin-top: 5px;
+      display: inline-block;
+    }
+    
+    .card-body {
+      padding: 20px;
+      display: flex;
+      flex-direction: column;
+      gap: 15px;
+    }
+    
+    .stats {
+      display: flex;
+      justify-content: space-between;
+      text-align: center;
+    }
+    
+    .stat {
+      flex: 1;
+    }
+    
+    .stat-value {
+      font-size: 20px;
+      font-weight: 700;
+      margin-bottom: 5px;
+    }
+    
+    .stat-label {
+      font-size: 12px;
+      color: #64748b;
+    }
+    
+    .progress-container {
+      margin-top: 5px;
+    }
+    
+    .progress-label {
+      display: flex;
+      justify-content: space-between;
+      font-size: 12px;
+      color: #64748b;
+      margin-bottom: 5px;
+    }
+    
+    .progress-bar {
+      height: 8px;
+      background: #e2e8f0;
+      border-radius: 10px;
+      overflow: hidden;
+    }
+    
+    .progress {
+      height: 100%;
+      border-radius: 10px;
+    }
+    
+    .card-footer {
+      padding: 15px 20px;
+      background: rgba(241, 245, 249, 0.7);
+      display: flex;
+      justify-content: space-between;
+      border-top: 1px solid rgba(0, 0, 0, 0.05);
+    }
+    
+    .permission-btn {
+      padding: 8px 15px;
+      border-radius: 8px;
+      font-size: 12px;
+      font-weight: 600;
+      cursor: pointer;
+      display: flex;
+      align-items: center;
+      gap: 5px;
+      border: none;
+      transition: all 0.2s ease;
+    }
+    
+    .permission-btn:hover {
+      transform: translateY(-2px);
+    }
+    
+    .btn-edit {
+      background: linear-gradient(135deg, #a5b4fc, #818cf8);
+      color: white;
+    }
+    
+    .btn-details {
+      background: rgba(203, 213, 225, 0.5);
+      color: #0f172a;
+    }
+  `]
+})
+export class SalesCardComponent {
+  @Input() sales: any;
+  @Input() data: any;
+  @Output() editPermission = new EventEmitter<void>();
+
+  selectCard() {
+    // 卡片选择逻辑
+  }
+
+  onEditPermission(event: Event) {
+    event.stopPropagation();
+    this.editPermission.emit();
+  }
+
+  getLevelColor(level: string): string {
+    const colors: { [key: string]: string } = {
+      'rookie': '#60a5fa',
+      'silver': '#94a3b8',
+      'gold': '#f59e0b',
+      'platinum': '#818cf8',
+      'diamond': '#22d3ee'
+    };
+    return colors[level] || '#60a5fa';
+  }
+}

+ 1 - 0
manager-web/src/modules/manager/mobile/page-home/components/sidebar/sidebar.html

@@ -0,0 +1 @@
+<p>sidebar works!</p>

+ 0 - 0
manager-web/src/modules/manager/mobile/page-home/components/sidebar/sidebar.scss


+ 23 - 0
manager-web/src/modules/manager/mobile/page-home/components/sidebar/sidebar.spec.ts

@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { Sidebar } from './sidebar';
+
+describe('Sidebar', () => {
+  let component: Sidebar;
+  let fixture: ComponentFixture<Sidebar>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [Sidebar]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(Sidebar);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});

+ 145 - 0
manager-web/src/modules/manager/mobile/page-home/components/sidebar/sidebar.ts

@@ -0,0 +1,145 @@
+// sidebar.component.ts
+import { Component, EventEmitter, Output } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+@Component({
+  selector: 'app-sidebar',
+  standalone: true,
+  imports: [CommonModule],
+  template: `
+    <div class="sidebar">
+      <!-- 其他内容保持不变 -->
+      <button class="btn btn-primary" style="margin-top: 15px;" (click)="onAiRecommend()">
+        <i class="fas fa-robot"></i> AI智能推荐
+      </button>
+    </div>
+  `,
+  styles: [`
+    .sidebar {
+      flex: 0 0 280px;
+      background: rgba(255, 255, 255, 0.1);
+      backdrop-filter: blur(10px);
+      border-radius: 20px;
+      border: 1px solid rgba(255, 255, 255, 0.2);
+      padding: 25px;
+      box-shadow: 0 8px 32px rgba(31, 38, 135, 0.15);
+      height: fit-content;
+    }
+    
+    .section-title {
+      font-size: 18px;
+      font-weight: 600;
+      margin-bottom: 20px;
+      display: flex;
+      align-items: center;
+      gap: 10px;
+      color: #e2e8f0;
+    }
+    
+    .section-title i {
+      color: #f59e0b;
+    }
+    
+    .filters {
+      display: flex;
+      flex-direction: column;
+      gap: 15px;
+    }
+    
+    .filter-group {
+      display: flex;
+      flex-direction: column;
+      gap: 8px;
+    }
+    
+    .filter-group label {
+      font-size: 14px;
+      color: #94a3b8;
+      font-weight: 500;
+    }
+    
+    .tag-filters {
+      display: flex;
+      flex-wrap: wrap;
+      gap: 10px;
+      margin-top: 5px;
+    }
+    
+    .tag {
+      padding: 5px 12px;
+      border-radius: 20px;
+      font-size: 12px;
+      font-weight: 500;
+      cursor: pointer;
+      transition: all 0.2s ease;
+    }
+    
+    .tag:hover {
+      transform: translateY(-2px);
+    }
+    
+    .tag.active {
+      box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+    }
+    
+    .tag-rookie {
+      background: linear-gradient(135deg, #60a5fa, #3b82f6);
+      color: white;
+    }
+    
+    .tag-silver {
+      background: linear-gradient(135deg, #cbd5e1, #94a3b8);
+      color: #0f172a;
+    }
+    
+    .tag-gold {
+      background: linear-gradient(135deg, #fcd34d, #f59e0b);
+      color: #0f172a;
+    }
+    
+    .tag-platinum {
+      background: linear-gradient(135deg, #a5b4fc, #818cf8);
+      color: white;
+    }
+    
+    .tag-diamond {
+      background: linear-gradient(135deg, #67e8f9, #22d3ee);
+      color: #0f172a;
+    }
+    
+    .stats-card {
+      background: rgba(255, 255, 255, 0.1);
+      backdrop-filter: blur(10px);
+      border-radius: 15px;
+      border: 1px solid rgba(255, 255, 255, 0.2);
+      padding: 15px;
+      margin-top: 20px;
+    }
+    
+    .stat-item {
+      display: flex;
+      justify-content: space-between;
+      padding: 10px 0;
+      border-bottom: 1px solid rgba(255, 255, 255, 0.05);
+    }
+    
+    .stat-item:last-child {
+      border-bottom: none;
+    }
+    
+    .stat-value {
+      font-weight: 700;
+      font-size: 18px;
+      background: linear-gradient(to right, #fbcfe8, #c7d2fe);
+      -webkit-background-clip: text;
+      -webkit-text-fill-color: transparent;
+    }
+  `]
+})
+export class SidebarComponent {
+  @Output() aiRecommend = new EventEmitter<void>();
+
+  onAiRecommend() {
+    this.aiRecommend.emit();
+  }
+}

+ 281 - 234
manager-web/src/modules/manager/mobile/page-home/page-home.html

@@ -1,249 +1,296 @@
-
-    <style>
-        * {
-            margin: 0;
-            padding: 0;
-            box-sizing: border-box;
-            font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
-        }
-        
-        :root {
-            --primary: #1a56db;
-            --secondary: #0e2a53;
-            --accent: #f59e0b;
-            --success: #10b981;
-            --danger: #ef4444;
-            --light: #f8fafc;
-            --dark: #0f172a;
-            --card-bg: rgba(255, 255, 255, 0.85);
-            --glass: rgba(255, 255, 255, 0.1);
-            --glass-border: rgba(255, 255, 255, 0.2);
-            --shadow: 0 8px 32px rgba(31, 38, 135, 0.15);
-            --nav-height: 65px;
-        }
-        
-        body {
-            background: linear-gradient(135deg, #0f172a, #1e293b);
-            color: var(--light);
-            min-height: 100vh;
-            padding: 20px;
-            position: relative;
-            overflow-x: hidden;
-            padding-bottom: calc(var(--nav-height) + 20px);
-        }
-        
-        body::before {
-            content: '';
-            position: absolute;
-            top: 0;
-            left: 0;
-            right: 0;
-            bottom: 0;
-            background: 
-                radial-gradient(circle at 10% 20%, rgba(26, 86, 219, 0.15) 0%, transparent 30%),
-                radial-gradient(circle at 90% 80%, rgba(245, 158, 11, 0.15) 0%, transparent 30%);
-            z-index: -1;
-        }
-        
-        .container {
-            max-width: 100%;
-            margin: 0 auto;
-            padding: 10px;
-        }
-        
-        .content {
-            background: var(--glass);
-            backdrop-filter: blur(10px);
-            border-radius: 20px;
-            border: 1px solid var(--glass-border);
-            padding: 25px;
-            box-shadow: var(--shadow);
-            margin-bottom: 20px;
-            color: #e2e8f0;
-            line-height: 1.6;
-        }
-        
-        h2 {
-            font-size: 22px;
-            margin-bottom: 15px;
-            background: linear-gradient(to right, #fbcfe8, #c7d2fe);
-            -webkit-background-clip: text;
-            -webkit-text-fill-color: transparent;
-        }
-        
-        .stats {
-            display: flex;
-            justify-content: space-around;
-            margin: 25px 0;
-            text-align: center;
-        }
-        
-        .stat-item {
-            display: flex;
-            flex-direction: column;
-            align-items: center;
-        }
-        
-        .stat-value {
-            font-size: 24px;
-            font-weight: 700;
-            margin-bottom: 5px;
-        }
-        
-        .stat-label {
-            font-size: 14px;
-            color: #94a3b8;
-        }
-        
-        .indicator {
-            position: absolute;
-            top: -10px;
-            width: 50px;
-            height: 50px;
-            background: linear-gradient(135deg, var(--primary), #3b82f6);
-            border-radius: 50%;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            font-size: 24px;
-            box-shadow: 0 4px 15px rgba(26, 86, 219, 0.4);
-            transition: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
-            color: white;
-            z-index: -1;
-        }
-        
-        .page-title {
-            text-align: center;
-            margin: 20px 0 30px;
-        }
-        
-        .page-title h1 {
-            font-size: 24px;
-            font-weight: 700;
-            background: linear-gradient(to right, #fde68a, #fcd34d);
-            -webkit-background-clip: text;
-            -webkit-text-fill-color: transparent;
-            margin-bottom: 10px;
-        }
+<!-- page-home.component.html -->
+<div class="container">
+  <header>
+    <div class="logo">
+      <div class="logo-icon">
+        <i class="fas fa-crown"></i>
+      </div>
+      <div class="logo-text">
+        <h1>九州管理</h1>
+        <p>智能AI权限管理系统</p>
+      </div>
+    </div>
+    <div class="user-actions">
+      <button class="btn btn-outline">
+        <i class="fas fa-sync-alt"></i> 刷新数据
+      </button>
+      <button class="btn btn-primary" (click)="addSales()">
+        <i class="fas fa-plus"></i> 添加销售
+      </button>
+    </div>
+  </header>
+  
+  <div class="dashboard">
+    <div class="sidebar">
+      <div class="section-title">
+        <i class="fas fa-filter"></i>
+        <span>智能筛选</span>
+      </div>
+      <div class="filters">
+        <div class="filter-group">
+          <label>销售等级</label>
+          <div class="tag-filters">
+            <div class="tag tag-rookie active">实习销售</div>
+            <div class="tag tag-silver">白银销售</div>
+            <div class="tag tag-gold">黄金销售</div>
+            <div class="tag tag-platinum">铂金销售</div>
+            <div class="tag tag-diamond">钻石销售</div>
+          </div>
+        </div>
         
-        .page-title p {
-            color: #cbd5e1;
-            font-size: 14px;
-        }
+        <div class="filter-group">
+          <label>业绩范围</label>
+          <input type="range" min="0" max="100" value="50" class="slider">
+        </div>
         
-        /* 动画效果 */
-        @keyframes pulse {
-            0% { transform: scale(1); }
-            50% { transform: scale(1.05); }
-            100% { transform: scale(1); }
-        }
+        <div class="filter-group">
+          <label>权限级别</label>
+          <select class="select">
+            <option>全部权限</option>
+            <option>基础权限</option>
+            <option>高级权限</option>
+            <option>管理员权限</option>
+          </select>
+        </div>
         
-        .pulse {
-            animation: pulse 2s infinite;
-        }
+        <button class="btn btn-primary" style="margin-top: 15px;" (click)="aiRecommend()">
+          <i class="fas fa-robot"></i> AI智能推荐
+        </button>
+      </div>
+      
+      <div class="stats-card">
+        <div class="section-title">
+          <i class="fas fa-chart-line"></i>
+          <span>团队统计</span>
+        </div>
         
-        /* 响应式调整 */
-        @media (max-width: 480px) {
-            .content {
-                padding: 15px;
-            }
+        <div class="stat-item">
+          <div>团队成员</div>
+          <div class="stat-value">24人</div>
+        </div>
+        <div class="stat-item">
+          <div>平均业绩</div>
+          <div class="stat-value">¥86,540</div>
+        </div>
+        <div class="stat-item">
+          <div>本月成交率</div>
+          <div class="stat-value">72.5%</div>
+        </div>
+        <div class="stat-item">
+          <div>AI标签准确率</div>
+          <div class="stat-value">94.8%</div>
+        </div>
+      </div>
+    </div>
+    
+    <div class="main-content">
+      <div class="ai-header">
+        <div>
+          <div class="ai-title">AI智能权限管理系统</div>
+          <div class="ai-subtitle">基于深度学习的销售行为分析,<span class="ai-highlight">自动生成销售标签</span>,智能分配权限级别,动态优化团队结构,提升整体销售业绩</div>
+        </div>
+        <div class="ai-power">
+          <i class="fas fa-brain"></i>
+        </div>
+      </div>
+      
+      <div class="cards-container">
+        <!-- 使用 *ngFor 循环生成销售卡片 -->
+        <div class="card {{sales.level}}" *ngFor="let sales of sales" (click)="openPermissionModal(sales)">
+          <div class="card-header">
+            <div class="avatar">
+              <img [src]="sales.avatar" alt="销售头像">
+            </div>
+            <div class="user-info">
+              <h3>{{sales.name}}</h3>
+              <p>入职时间: {{sales.joinDate}}</p>
+              <span class="user-tag tag-{{sales.level}}">{{sales.levelName}}</span>
+            </div>
+          </div>
+          <div class="card-body">
+            <div class="stats">
+              <div class="stat">
+                <div class="stat-value">{{sales.performance}}</div>
+                <div class="stat-label">本月业绩</div>
+              </div>
+              <div class="stat">
+                <div class="stat-value">{{sales.successRate}}</div>
+                <div class="stat-label">成交率</div>
+              </div>
+              <div class="stat">
+                <div class="stat-value">{{sales.clients}}</div>
+                <div class="stat-label">客户数</div>
+              </div>
+            </div>
             
-            .stats {
-                flex-wrap: wrap;
-            }
+            <div class="progress-container" *ngIf="sales.trainingProgress !== undefined">
+              <div class="progress-label">
+                <span>培训进度</span>
+                <span>{{sales.trainingProgress}}%</span>
+              </div>
+              <div class="progress-bar">
+                <div class="progress" [style.width.%]="sales.trainingProgress" [style.background]="getProgressColor(sales.level)"></div>
+              </div>
+            </div>
             
-            .stat-item {
-                width: 50%;
-                margin-bottom: 15px;
-            }
+            <div class="progress-container" *ngIf="sales.satisfaction !== undefined">
+              <div class="progress-label">
+                <span>客户满意度</span>
+                <span>{{sales.satisfaction}}%</span>
+              </div>
+              <div class="progress-bar">
+                <div class="progress" [style.width.%]="sales.satisfaction" [style.background]="getProgressColor(sales.level)"></div>
+              </div>
+            </div>
+            
+            <div class="progress-container" *ngIf="sales.vipClients !== undefined">
+              <div class="progress-label">
+                <span>大客户占比</span>
+                <span>{{sales.vipClients}}%</span>
+              </div>
+              <div class="progress-bar">
+                <div class="progress" [style.width.%]="sales.vipClients" [style.background]="getProgressColor(sales.level)"></div>
+              </div>
+            </div>
+            
+            <div class="progress-container" *ngIf="sales.avgPrice !== undefined">
+              <div class="progress-label">
+                <span>客单价</span>
+                <span>¥11,711</span>
+              </div>
+              <div class="progress-bar">
+                <div class="progress" [style.width.%]="sales.avgPrice" [style.background]="getProgressColor(sales.level)"></div>
+              </div>
+            </div>
+            
+            <div class="progress-container" *ngIf="sales.repurchaseRate !== undefined">
+              <div class="progress-label">
+                <span>复购率</span>
+                <span>{{sales.repurchaseRate}}%</span>
+              </div>
+              <div class="progress-bar">
+                <div class="progress" [style.width.%]="sales.repurchaseRate" [style.background]="getProgressColor(sales.level)"></div>
+              </div>
+            </div>
             
-            .nav-tab span {
-                font-size: 11px;
+            <div class="progress-container">
+              <div class="progress-label">
+                <span>AI能力评估</span>
+                <span>{{sales.aiAssessment}}%</span>
+              </div>
+              <div class="progress-bar">
+                <div class="progress" [style.width.%]="sales.aiAssessment" [style.background]="getProgressColor(sales.level)"></div>
+              </div>
+            </div>
+          </div>
+          <div class="card-footer">
+            <button class="permission-btn btn-edit" (click)="openPermissionModal(sales); $event.stopPropagation()">
+              <i class="fas fa-user-cog"></i> 权限管理
+            </button>
+            <button class="permission-btn btn-details">
+              <i class="fas fa-chart-bar"></i> 业绩详情
+            </button>
+          </div>
+        </div>
+      </div>
+      
+      <div class="chart-container">
+        <div class="chart-header">
+          <div class="chart-title">销售团队业绩分析</div>
+          <div class="chart-actions">
+            <button class="btn btn-outline">
+              <i class="fas fa-download"></i> 导出
+            </button>
+            <button class="btn btn-primary">
+              <i class="fas fa-sync-alt"></i> 更新
+            </button>
+          </div>
+        </div>
+        <div class="chart-wrapper">
+            @if(chartOptions){
+                <div echarts [options]="chartOptions"  class="echarts-chart"></div>
             }
-        }
-    </style>
-
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
 
-    <div class="container">
-        <div class="page-title">
-            <h1>九州管理平台</h1>
-            <p>智能AI权限管理系统 - 移动端</p>
+<!-- AI权限管理面板 -->
+<div class="permission-modal" [class.active]="showModal" (click)="showModal && $event.target === $event.currentTarget && closeModal()">
+  <div class="modal-content" [class.active]="showModal">
+    <div class="modal-header">
+      <h2>{{currentSales.name}} - 权限管理</h2>
+      <button class="close-btn" (click)="closeModal()">&times;</button>
+    </div>
+    <div class="modal-body">
+      <div class="ai-recommendation">
+        <p [innerHTML]="getAiRecommendation(currentSales.level)"></p>
+        <button class="btn btn-primary">
+          <i class="fas fa-check"></i> 应用AI建议
+        </button>
+      </div>
+      
+      <div class="permission-options">
+        <div class="permission-option">
+          <div class="permission-info">
+            <h3>客户数据访问</h3>
+            <p>允许查看和编辑客户信息</p>
+          </div>
+          <label class="switch">
+            <input type="checkbox" checked>
+            <span class="slider"></span>
+          </label>
         </div>
         
-        <div class="content">
-            <h2>欢迎使用移动端管理平台</h2>
-            <p>基于深度学习的销售行为分析,<span style="color: var(--accent); font-weight: 500;">自动生成销售标签</span>,智能分配权限级别,动态优化团队结构,提升整体销售业绩。</p>
-            
-            <div class="stats">
-                <div class="stat-item">
-                    <div class="stat-value">24</div>
-                    <div class="stat-label">团队成员</div>
-                </div>
-                <div class="stat-item">
-                    <div class="stat-value">86,540</div>
-                    <div class="stat-label">平均业绩</div>
-                </div>
-                <div class="stat-item">
-                    <div class="stat-value">72.5%</div>
-                    <div class="stat-label">成交率</div>
-                </div>
-                <div class="stat-item">
-                    <div class="stat-value">94.8%</div>
-                    <div class="stat-label">AI准确率</div>
-                </div>
-            </div>
-            
-            <p>使用底部导航栏在不同功能模块之间快速切换,随时随地管理您的销售团队和权限设置。</p>
+        <div class="permission-option">
+          <div class="permission-info">
+            <h3>报价修改权限</h3>
+            <p>允许修改套餐价格和优惠</p>
+          </div>
+          <label class="switch">
+            <input type="checkbox">
+            <span class="slider"></span>
+          </label>
+        </div>
+        
+        <div class="permission-option">
+          <div class="permission-info">
+            <h3>AI陪练系统</h3>
+            <p>使用AI虚拟陪练功能</p>
+          </div>
+          <label class="switch">
+            <input type="checkbox" checked>
+            <span class="slider"></span>
+          </label>
         </div>
         
-        <div class="content">
-            <h2>智能功能</h2>
-            <p>• AI销售行为分析</p>
-            <p>• 智能权限分配</p>
-            <p>• 实时业绩追踪</p>
-            <p>• 团队结构优化</p>
-            <p>• 销售能力评估</p>
+        <div class="permission-option">
+          <div class="permission-info">
+            <h3>高级分析报告</h3>
+            <p>访问详细客户分析报告</p>
+          </div>
+          <label class="switch">
+            <input type="checkbox">
+            <span class="slider"></span>
+          </label>
         </div>
+        
+        <div class="permission-option">
+          <div class="permission-info">
+            <h3>跨区域客户</h3>
+            <p>访问和分配跨区域客户</p>
+          </div>
+          <label class="switch">
+            <input type="checkbox" checked>
+            <span class="slider"></span>
+          </label>
+        </div>
+      </div>
     </div>
-
-    <script>
-        document.addEventListener('DOMContentLoaded', function() {
-            const tabs = document.querySelectorAll('.nav-tab');
-            const indicator = document.querySelector('.indicator');
-            
-            // 初始位置设置
-            const activeTab = document.querySelector('.nav-tab.active');
-            if (activeTab) {
-                const tabRect = activeTab.getBoundingClientRect();
-                const containerRect = activeTab.parentElement.getBoundingClientRect();
-                
-                const left = tabRect.left - containerRect.left + tabRect.width/2;
-                indicator.style.left = `${left}px`;
-            }
-            
-            // 添加点击事件
-            tabs.forEach(tab => {
-                tab.addEventListener('click', function(e) {
-                    // 移除所有active类
-                    tabs.forEach(t => t.classList.remove('active'));
-                    
-                    // 添加active类到当前标签
-                    this.classList.add('active');
-                    
-                    // 更新指示器位置
-                    const tabRect = this.getBoundingClientRect();
-                    const containerRect = this.parentElement.getBoundingClientRect();
-                    
-                    const left = tabRect.left - containerRect.left + tabRect.width/2;
-                    indicator.style.left = `${left}px`;
-                    
-                    // 添加动画效果
-                    indicator.classList.remove('pulse');
-                    void indicator.offsetWidth; // 触发重绘
-                    indicator.classList.add('pulse');
-                    
-                });
-            });
-        });
-    </script>
-    
+    <div class="modal-footer">
+      <button class="btn btn-outline" (click)="closeModal()">取消</button>
+      <button class="btn btn-primary" (click)="saveSettings()">保存设置</button>
+    </div>
+  </div>
+</div>

+ 704 - 0
manager-web/src/modules/manager/mobile/page-home/page-home.scss

@@ -0,0 +1,704 @@
+// page-home.component.scss
+:host {
+  --primary: #1a56db;
+  --secondary: #0e2a53;
+  --accent: #f59e0b;
+  --success: #10b981;
+  --danger: #ef4444;
+  --light: #f8fafc;
+  --dark: #0f172a;
+  --card-bg: rgba(255, 255, 255, 0.85);
+  --glass: rgba(255, 255, 255, 0.1);
+  --glass-border: rgba(255, 255, 255, 0.2);
+  --shadow: 0 8px 32px rgba(31, 38, 135, 0.15);
+}
+
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+  font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
+}
+
+body {
+  background: linear-gradient(135deg, #0f172a, #1e293b);
+  color: var(--light);
+  min-height: 100vh;
+  padding: 20px;
+  position: relative;
+  overflow-x: hidden;
+}
+
+body::before {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: 
+    radial-gradient(circle at 10% 20%, rgba(26, 86, 219, 0.15) 0%, transparent 30%),
+    radial-gradient(circle at 90% 80%, rgba(245, 158, 11, 0.15) 0%, transparent 30%);
+  z-index: -1;
+}
+
+.container {
+  max-width: 1200px;
+  margin: 0 auto;
+}
+
+/* 头部样式 */
+header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 20px 0;
+  margin-bottom: 30px;
+  border-bottom: 1px solid var(--glass-border);
+}
+
+.logo {
+  display: flex;
+  align-items: center;
+  gap: 15px;
+}
+
+.logo-icon {
+  width: 50px;
+  height: 50px;
+  background: linear-gradient(135deg, var(--primary), #3b82f6);
+  border-radius: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 24px;
+  box-shadow: var(--shadow);
+}
+
+.logo-text h1 {
+  font-size: 24px;
+  font-weight: 700;
+  background: linear-gradient(to right, #fbcfe8, #c7d2fe);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+}
+
+.logo-text p {
+  font-size: 14px;
+  color: #cbd5e1;
+  letter-spacing: 1px;
+}
+
+.user-actions {
+  display: flex;
+  gap: 15px;
+}
+
+.btn {
+  padding: 10px 20px;
+  border-radius: 10px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  border: none;
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+.btn-primary {
+  background: linear-gradient(135deg, var(--primary), #3b82f6);
+  color: white;
+  box-shadow: 0 4px 6px rgba(26, 86, 219, 0.3);
+}
+
+.btn-primary:hover {
+  transform: translateY(-2px);
+  box-shadow: 0 6px 12px rgba(26, 86, 219, 0.4);
+}
+
+.btn-outline {
+  background: transparent;
+  border: 1px solid var(--glass-border);
+  color: #e2e8f0;
+}
+
+.btn-outline:hover {
+  background: rgba(255, 255, 255, 0.1);
+}
+
+/* 主内容区 */
+.dashboard {
+  display: flex;
+  gap: 25px;
+  margin-bottom: 30px;
+}
+
+/* 左侧面板 */
+.sidebar {
+  flex: 0 0 280px;
+  background: var(--glass);
+  backdrop-filter: blur(10px);
+  border-radius: 20px;
+  border: 1px solid var(--glass-border);
+  padding: 25px;
+  box-shadow: var(--shadow);
+  height: fit-content;
+}
+
+.section-title {
+  font-size: 18px;
+  font-weight: 600;
+  margin-bottom: 20px;
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  color: #e2e8f0;
+}
+
+.section-title i {
+  color: var(--accent);
+}
+
+.filters {
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+}
+
+.filter-group {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+
+.filter-group label {
+  font-size: 14px;
+  color: #94a3b8;
+  font-weight: 500;
+}
+
+.tag-filters {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 10px;
+  margin-top: 5px;
+}
+
+.tag {
+  padding: 5px 12px;
+  border-radius: 20px;
+  font-size: 12px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: all 0.2s ease;
+}
+
+.tag:hover {
+  transform: translateY(-2px);
+}
+
+.tag.active {
+  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+}
+
+.tag-rookie {
+  background: linear-gradient(135deg, #60a5fa, #3b82f6);
+  color: white;
+}
+
+.tag-silver {
+  background: linear-gradient(135deg, #cbd5e1, #94a3b8);
+  color: var(--dark);
+}
+
+.tag-gold {
+  background: linear-gradient(135deg, #fcd34d, #f59e0b);
+  color: var(--dark);
+}
+
+.tag-platinum {
+  background: linear-gradient(135deg, #a5b4fc, #818cf8);
+  color: white;
+}
+
+.tag-diamond {
+  background: linear-gradient(135deg, #67e8f9, #22d3ee);
+  color: var(--dark);
+}
+
+.stats-card {
+  background: var(--glass);
+  backdrop-filter: blur(10px);
+  border-radius: 15px;
+  border: 1px solid var(--glass-border);
+  padding: 15px;
+  margin-top: 20px;
+}
+
+.stat-item {
+  display: flex;
+  justify-content: space-between;
+  padding: 10px 0;
+  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
+}
+
+.stat-item:last-child {
+  border-bottom: none;
+}
+
+.stat-value {
+  font-weight: 700;
+  font-size: 18px;
+  background: linear-gradient(to right, #fbcfe8, #c7d2fe);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+}
+
+/* 主面板 */
+.main-content {
+  flex: 1;
+  display: flex;
+  flex-direction: column;
+  gap: 25px;
+}
+
+.ai-header {
+  background: var(--glass);
+  backdrop-filter: blur(10px);
+  border-radius: 20px;
+  border: 1px solid var(--glass-border);
+  padding: 25px;
+  box-shadow: var(--shadow);
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.ai-title {
+  font-size: 24px;
+  font-weight: 700;
+  margin-bottom: 10px;
+  background: linear-gradient(to right, #fde68a, #fcd34d);
+  -webkit-background-clip: text;
+  -webkit-text-fill-color: transparent;
+}
+
+.ai-subtitle {
+  color: #cbd5e1;
+  max-width: 600px;
+  line-height: 1.6;
+}
+
+.ai-highlight {
+  color: var(--accent);
+  font-weight: 600;
+}
+
+.ai-power {
+  font-size: 48px;
+  color: var(--accent);
+  opacity: 0.7;
+}
+
+.cards-container {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+  gap: 20px;
+  margin-bottom: 30px;
+}
+
+.card {
+  background: var(--card-bg);
+  backdrop-filter: blur(10px);
+  border-radius: 20px;
+  border: 1px solid rgba(255, 255, 255, 0.2);
+  overflow: hidden;
+  box-shadow: var(--shadow);
+  transition: all 0.3s ease;
+  color: var(--dark);
+}
+
+.card:hover {
+  transform: translateY(-5px);
+  box-shadow: 0 12px 20px rgba(31, 38, 135, 0.2);
+}
+
+.card-header {
+  padding: 20px;
+  display: flex;
+  align-items: center;
+  gap: 15px;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+  position: relative;
+}
+
+.card-header::before {
+  content: '';
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 4px;
+}
+
+.rookie .card-header::before { background: linear-gradient(90deg, #60a5fa, #3b82f6); }
+.silver .card-header::before { background: linear-gradient(90deg, #cbd5e1, #94a3b8); }
+.gold .card-header::before { background: linear-gradient(90deg, #fcd34d, #f59e0b); }
+.platinum .card-header::before { background: linear-gradient(90deg, #a5b4fc, #818cf8); }
+.diamond .card-header::before { background: linear-gradient(90deg, #67e8f9, #22d3ee); }
+
+.avatar {
+  width: 60px;
+  height: 60px;
+  border-radius: 50%;
+  overflow: hidden;
+  border: 3px solid white;
+  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+}
+
+.avatar img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+}
+
+.user-info {
+  flex: 1;
+}
+
+.user-info h3 {
+  font-size: 18px;
+  font-weight: 700;
+  margin-bottom: 5px;
+  color: var(--dark);
+}
+
+.user-info p {
+  font-size: 14px;
+  color: #64748b;
+}
+
+.user-tag {
+  padding: 4px 12px;
+  border-radius: 20px;
+  font-size: 12px;
+  font-weight: 600;
+  margin-top: 5px;
+  display: inline-block;
+}
+
+.card-body {
+  padding: 20px;
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+}
+
+.stats {
+  display: flex;
+  justify-content: space-between;
+  text-align: center;
+}
+
+.stat {
+  flex: 1;
+}
+
+.stat-value {
+  font-size: 20px;
+  font-weight: 700;
+  margin-bottom: 5px;
+}
+
+.stat-label {
+  font-size: 12px;
+  color: #64748b;
+}
+
+.progress-container {
+  margin-top: 5px;
+}
+
+.progress-label {
+  display: flex;
+  justify-content: space-between;
+  font-size: 12px;
+  color: #64748b;
+  margin-bottom: 5px;
+}
+
+.progress-bar {
+  height: 8px;
+  background: #e2e8f0;
+  border-radius: 10px;
+  overflow: hidden;
+}
+
+.progress {
+  height: 100%;
+  border-radius: 10px;
+}
+
+.card-footer {
+  padding: 15px 20px;
+  background: rgba(241, 245, 249, 0.7);
+  display: flex;
+  justify-content: space-between;
+  border-top: 1px solid rgba(0, 0, 0, 0.05);
+}
+
+.permission-btn {
+  padding: 8px 15px;
+  border-radius: 8px;
+  font-size: 12px;
+  font-weight: 600;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  gap: 5px;
+  border: none;
+  transition: all 0.2s ease;
+}
+
+.permission-btn:hover {
+  transform: translateY(-2px);
+}
+
+.btn-edit {
+  background: linear-gradient(135deg, #a5b4fc, #818cf8);
+  color: white;
+}
+
+.btn-details {
+  background: rgba(203, 213, 225, 0.5);
+  color: var(--dark);
+}
+
+/* 图表容器 */
+.chart-container {
+  background: var(--card-bg);
+  backdrop-filter: blur(10px);
+  border-radius: 20px;
+  border: 1px solid rgba(255, 255, 255, 0.2);
+  padding: 25px;
+  box-shadow: var(--shadow);
+  margin-bottom: 30px;
+}
+
+.chart-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+}
+
+.chart-title {
+  font-size: 20px;
+  font-weight: 600;
+  color: var(--dark);
+}
+
+.chart-actions {
+  display: flex;
+  gap: 10px;
+}
+
+.chart-wrapper {
+  height: 300px;
+  position: relative;
+}
+
+.echarts-chart {
+  width: 100%;
+  height: 100%;
+}
+
+/* AI权限管理面板 */
+.permission-modal {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(15, 23, 42, 0.9);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+  opacity: 0;
+  visibility: hidden;
+  transition: all 0.3s ease;
+}
+
+.permission-modal.active {
+  opacity: 1;
+  visibility: visible;
+}
+
+.modal-content {
+  background: var(--card-bg);
+  width: 90%;
+  max-width: 600px;
+  border-radius: 20px;
+  box-shadow: var(--shadow);
+  overflow: hidden;
+  transform: translateY(20px);
+  transition: transform 0.3s ease;
+}
+
+.permission-modal.active .modal-content {
+  transform: translateY(0);
+}
+
+.modal-header {
+  padding: 20px;
+  background: linear-gradient(135deg, var(--primary), #3b82f6);
+  color: white;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.modal-header h2 {
+  font-size: 22px;
+}
+
+.close-btn {
+  background: transparent;
+  border: none;
+  color: white;
+  font-size: 24px;
+  cursor: pointer;
+}
+
+.modal-body {
+  padding: 25px;
+  color: var(--dark);
+}
+
+.ai-recommendation {
+  background: rgba(26, 86, 219, 0.1);
+  border-left: 4px solid var(--primary);
+  padding: 15px;
+  margin-bottom: 20px;
+  border-radius: 0 8px 8px 0;
+}
+
+.ai-recommendation p {
+  margin-bottom: 10px;
+}
+
+.ai-recommendation .btn {
+  margin-top: 10px;
+}
+
+.permission-options {
+  display: flex;
+  flex-direction: column;
+  gap: 15px;
+}
+
+.permission-option {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 12px 15px;
+  background: rgba(241, 245, 249, 0.5);
+  border-radius: 10px;
+}
+
+.permission-info {
+  flex: 1;
+}
+
+.permission-info h3 {
+  font-size: 16px;
+  margin-bottom: 5px;
+}
+
+.permission-info p {
+  font-size: 13px;
+  color: #64748b;
+}
+
+.switch {
+  position: relative;
+  display: inline-block;
+  width: 50px;
+  height: 24px;
+}
+
+.switch input {
+  opacity: 0;
+  width: 0;
+  height: 0;
+}
+
+.slider {
+  position: absolute;
+  cursor: pointer;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: #ccc;
+  transition: .4s;
+  border-radius: 24px;
+}
+
+.slider:before {
+  position: absolute;
+  content: "";
+  height: 16px;
+  width: 16px;
+  left: 4px;
+  bottom: 4px;
+  background-color: white;
+  transition: .4s;
+  border-radius: 50%;
+}
+
+input:checked + .slider {
+  background-color: var(--success);
+}
+
+input:checked + .slider:before {
+  transform: translateX(26px);
+}
+
+.modal-footer {
+  padding: 20px;
+  display: flex;
+  justify-content: flex-end;
+  gap: 15px;
+  border-top: 1px solid rgba(0, 0, 0, 0.1);
+}
+
+/* 响应式调整 */
+@media (max-width: 992px) {
+  .dashboard {
+    flex-direction: column;
+  }
+  
+  .sidebar {
+    width: 100%;
+  }
+}
+
+@media (max-width: 576px) {
+  .cards-container {
+    grid-template-columns: 1fr;
+  }
+  
+  .ai-header {
+    flex-direction: column;
+    text-align: center;
+    gap: 20px;
+  }
+  
+  .user-actions {
+    flex-wrap: wrap;
+    justify-content: center;
+  }
+}

+ 222 - 7
manager-web/src/modules/manager/mobile/page-home/page-home.ts

@@ -1,12 +1,227 @@
-import { Component } from '@angular/core';
-import { RouterModule } from '@angular/router';
-
+// page-home.component.ts
+import { Component, OnInit } from '@angular/core';
+import { NgxEchartsModule } from 'ngx-echarts';
+import { CommonModule } from '@angular/common';
+import * as echarts from 'echarts';
 @Component({
   selector: 'app-page-home',
-  imports: [RouterModule],
+  standalone: true,
+  imports: [
+    CommonModule,
+    NgxEchartsModule
+  ],
   templateUrl: './page-home.html',
-  styleUrl: './page-home.scss'
+  styleUrls: ['./page-home.scss']
 })
-export class PageHome {
+export class PageHome implements OnInit {
+  chartOptions: any;
+  showModal = false;
+  currentSales: any = {};
+  
+  ngOnInit() {
+    this.initChart();
+  }
+
+  initChart() {
+    this.chartOptions = {
+      tooltip: {
+        trigger: 'axis',
+        axisPointer: {
+          type: 'shadow'
+        },
+        backgroundColor: 'rgba(15, 23, 42, 0.9)',
+        borderColor: 'rgba(255, 255, 255, 0.1)',
+        borderWidth: 1,
+        textStyle: {
+          color: '#e2e8f0'
+        }
+      },
+      grid: {
+        left: '3%',
+        right: '4%',
+        bottom: '3%',
+        containLabel: true
+      },
+      xAxis: {
+        type: 'value',
+        axisLine: {
+          lineStyle: {
+            color: 'rgba(255, 255, 255, 0.1)'
+          }
+        },
+        axisLabel: {
+          color: '#64748b'
+        },
+        splitLine: {
+          lineStyle: {
+            color: 'rgba(255, 255, 255, 0.1)'
+          }
+        }
+      },
+      yAxis: {
+        type: 'category',
+        data: ['实习销售', '白银销售', '黄金销售', '铂金销售', '钻石销售'],
+        axisLine: {
+          lineStyle: {
+            color: 'rgba(255, 255, 255, 0.1)'
+          }
+        },
+        axisLabel: {
+          color: '#64748b'
+        }
+      },
+      series: [
+        {
+          name: '平均月业绩 (万元)',
+          type: 'bar',
+          data: [8.2, 22.5, 45.8, 78.3, 125.6],
+          itemStyle: {
+            color: (params: any) => {
+              const colors = [
+                'rgba(59, 130, 246, 0.7)',
+                'rgba(148, 163, 184, 0.7)',
+                'rgba(245, 158, 11, 0.7)',
+                'rgba(129, 140, 248, 0.7)',
+                'rgba(34, 211, 238, 0.7)'
+              ];
+              return colors[params.dataIndex];
+            },
+            borderColor: (params: any) => {
+              const colors = [
+                'rgb(59, 130, 246)',
+                'rgb(148, 163, 184)',
+                'rgb(245, 158, 11)',
+                'rgb(129, 140, 248)',
+                'rgb(34, 211, 238)'
+              ];
+              return colors[params.dataIndex];
+            },
+            borderWidth: 2,
+            borderRadius: [4, 4, 0, 0]
+          },
+          label: {
+            show: true,
+            position: 'right',
+            color: '#64748b'
+          }
+        }
+      ]
+    };
+  }
+
+  openPermissionModal(sales: any) {
+    this.currentSales = sales;
+    this.showModal = true;
+  }
+
+  closeModal() {
+    this.showModal = false;
+  }
+
+  saveSettings() {
+    this.closeModal();
+    alert('权限设置已保存!');
+  }
+
+  aiRecommend() {
+    alert('AI正在分析团队数据,推荐最优权限配置...\n\n结果:建议将3名白银销售升级为黄金销售权限');
+  }
+
+  addSales() {
+    alert('添加新销售功能已打开,请填写销售信息');
+  }
+
+  getAiRecommendation(level: string) {
+    switch(level) {
+      case 'rookie':
+        return 'AI建议:根据该销售表现,建议升级为<span class="ai-highlight">白银销售</span>权限级别';
+      case 'silver':
+        return 'AI建议:根据该销售表现,建议升级为<span class="ai-highlight">黄金销售</span>权限级别';
+      case 'gold':
+        return 'AI建议:根据该销售表现,建议升级为<span class="ai-highlight">铂金销售</span>权限级别';
+      case 'platinum':
+        return 'AI建议:根据该销售表现,建议升级为<span class="ai-highlight">钻石销售</span>权限级别';
+      default:
+        return 'AI建议:该销售已达到最高权限级别,表现优秀';
+    }
+  }
+
+  getProgressColor(level: string) {
+    switch(level) {
+      case 'rookie': return '#3b82f6';
+      case 'silver': return '#94a3b8';
+      case 'gold': return '#f59e0b';
+      case 'platinum': return '#818cf8';
+      case 'diamond': return '#22d3ee';
+      default: return '#3b82f6';
+    }
+  }
 
-}
+  sales = [
+    {
+      id: 1,
+      name: '张雨欣',
+      joinDate: '2023-08-15',
+      level: 'rookie',
+      levelName: '实习销售',
+      avatar: 'https://randomuser.me/api/portraits/women/44.jpg',
+      performance: '¥24,500',
+      successRate: '58%',
+      clients: '12',
+      trainingProgress: 65,
+      aiAssessment: 42
+    },
+    {
+      id: 2,
+      name: '王建国',
+      joinDate: '2022-11-03',
+      level: 'silver',
+      levelName: '白银销售',
+      avatar: 'https://randomuser.me/api/portraits/men/32.jpg',
+      performance: '¥68,200',
+      successRate: '76%',
+      clients: '21',
+      satisfaction: 88,
+      aiAssessment: 78
+    },
+    {
+      id: 3,
+      name: '李思琪',
+      joinDate: '2021-05-22',
+      level: 'gold',
+      levelName: '黄金销售',
+      avatar: 'https://randomuser.me/api/portraits/women/68.jpg',
+      performance: '¥128,400',
+      successRate: '84%',
+      clients: '29',
+      vipClients: 42,
+      aiAssessment: 92
+    },
+    {
+      id: 4,
+      name: '陈志强',
+      joinDate: '2020-03-14',
+      level: 'platinum',
+      levelName: '铂金销售',
+      avatar: 'https://randomuser.me/api/portraits/men/75.jpg',
+      performance: '¥210,800',
+      successRate: '91%',
+      clients: '18',
+      avgPrice: 85,
+      aiAssessment: 97
+    },
+    {
+      id: 5,
+      name: '赵雅芝',
+      joinDate: '2019-08-07',
+      level: 'diamond',
+      levelName: '钻石销售',
+      avatar: 'https://randomuser.me/api/portraits/women/26.jpg',
+      performance: '¥356,700',
+      successRate: '96%',
+      clients: '15',
+      repurchaseRate: 63,
+      aiAssessment: 99
+    }
+  ];
+}

+ 2 - 1
manager-web/src/modules/manager/mobile/page-mine/page-mine.ts

@@ -1,8 +1,9 @@
 import { Component } from '@angular/core';
+import { RouterModule } from '@angular/router';
 
 @Component({
   selector: 'app-page-mine',
-  imports: [],
+  imports: [RouterModule],
   templateUrl: './page-mine.html',
   styleUrl: './page-mine.scss'
 })