5 Commits 49653c8852 ... d1d32b9cc5

Author SHA1 Message Date
  0235713 d1d32b9cc5 fax mine 2 days ago
  0235713 77780affa8 Merge branch 'master' of http://git.fmode.cn:3000/0235713/intelligent-interview 2 days ago
  0235713 ad6fad0563 Merge branch 'master' of http://git.fmode.cn:3000/0235713/intelligent-interview 3 days ago
  0235713 7cfb7e4179 Merge branch 'master' of http://git.fmode.cn:3000/0235713/intelligent-interview 3 days ago
  0235702 338c1bda36 feat demo 3 days ago

+ 80 - 0
demo/PPT.html

@@ -0,0 +1,80 @@
+1. 首页
+   ├─ VR企业展厅
+   │   ├─ 3D环境漫游
+   │   ├─ 岗位信息浮窗
+   │   └─ 面试快速入口
+   ├─ 热门岗位推荐
+   │   ├─ 智能匹配岗位
+   │   ├─ 薪资范围筛选
+   │   └─ 企业VR导览
+   └─ 面试历史入口
+       ├─ 进度追踪
+       ├─ 录像回放
+       └─ 报告查看
+
+2. 面试准备中心
+   ├─ 简历管理
+   │   ├─ 智能解析
+   │   ├─ 重点强化
+   │   └─ 一键投递
+   ├─ 设备检测
+   │   ├─ 麦克风测试
+   │   │   ├─ 灵敏度调节
+   │   │   └─ 降噪设置
+   │   └─ 摄像头校准
+   │       ├─ 取景框调整
+   │       └─ 光线检测
+   └─ 模拟训练
+       ├─ 常见问题库
+       │   ├─ 分类训练
+       │   └─ 智能评分
+       └─ 专项突破
+           ├─ 技术题库
+           └─ 压力测试
+
+3. 核心面试模块
+   ├─ 数字人区域
+   │   ├─ 表情反馈系统
+   │   │   ├─ 微表情识别
+   │   │   └─ 注视方向提示
+   │   └─ 唇形同步引擎
+   │       ├─ 语音驱动
+   │       └─ 延迟优化
+   ├─ 交互控制区
+   │   ├─ 作品提交入口
+   │   │   ├─ 文件上传
+   │   │   └─ GitHub绑定
+   │   ├─ 问题跳过按钮
+   │   │   ├─ 技术问题
+   │   │   └─ 情景题
+   │   └─ 紧急暂停键
+   │       ├─ 临时静音
+   │       └─ 技术中断
+   └─ 实时辅助
+       ├─ 关键词提示
+       │   ├─ 岗位JD匹配
+       │   └─ 简历关联
+       ├─ 计时进度条
+       │   ├─ 分段计时
+       │   └─ 剩余提醒
+       └─ 情绪波动监测
+           ├─ 心率检测
+           └─ 语速分析
+
+4. 报告分析中心
+   ├─ 能力雷达图
+   │   ├─ 五维评估
+   │   └─ 行业对比
+   ├─ 追问点分析
+   │   ├─ 漏洞标记
+   │   └─ 深度追问
+   ├─ 改进计划
+   │   ├─ 学习资源推荐
+   │   │   ├─ 针对性课程
+   │   │   └─ 书单推荐
+   │   └─ 训练方案
+   │       ├─ 模拟面试
+   │       └─ 专项练习
+   └─ 企业匹配建议
+       ├─ 文化契合度
+       └─ 团队适配度

+ 20 - 0
interview-web/package-lock.json

@@ -18,6 +18,7 @@
         "@fortawesome/fontawesome-svg-core": "^6.7.2",
         "@fortawesome/fontawesome-svg-core": "^6.7.2",
         "@fortawesome/free-solid-svg-icons": "^6.7.2",
         "@fortawesome/free-solid-svg-icons": "^6.7.2",
         "rxjs": "~7.8.0",
         "rxjs": "~7.8.0",
+        "swiper": "^11.2.10",
         "tslib": "^2.3.0",
         "tslib": "^2.3.0",
         "zone.js": "~0.15.0"
         "zone.js": "~0.15.0"
       },
       },
@@ -8139,6 +8140,25 @@
         "url": "https://github.com/sponsors/ljharb"
         "url": "https://github.com/sponsors/ljharb"
       }
       }
     },
     },
+    "node_modules/swiper": {
+      "version": "11.2.10",
+      "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.10.tgz",
+      "integrity": "sha512-RMeVUUjTQH+6N3ckimK93oxz6Sn5la4aDlgPzB+rBrG/smPdCTicXyhxa+woIpopz+jewEloiEE3lKo1h9w2YQ==",
+      "funding": [
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/swiperjs"
+        },
+        {
+          "type": "open_collective",
+          "url": "http://opencollective.com/swiper"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4.7.0"
+      }
+    },
     "node_modules/tar": {
     "node_modules/tar": {
       "version": "6.2.1",
       "version": "6.2.1",
       "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
       "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",

+ 1 - 0
interview-web/package.json

@@ -30,6 +30,7 @@
     "@fortawesome/fontawesome-svg-core": "^6.7.2",
     "@fortawesome/fontawesome-svg-core": "^6.7.2",
     "@fortawesome/free-solid-svg-icons": "^6.7.2",
     "@fortawesome/free-solid-svg-icons": "^6.7.2",
     "rxjs": "~7.8.0",
     "rxjs": "~7.8.0",
+    "swiper": "^11.2.10",
     "tslib": "^2.3.0",
     "tslib": "^2.3.0",
     "zone.js": "~0.15.0"
     "zone.js": "~0.15.0"
   },
   },

+ 12 - 1
interview-web/src/app/app.html

@@ -1 +1,12 @@
-<router-outlet />
+<div class="container">
+  <!-- 顶部导航 -->
+  
+  
+  <!-- 主内容区 -->
+  <main>
+    <router-outlet></router-outlet>
+  </main>
+  
+  <!-- 底部导航 -->
+  <app-nav-mobile-tabs></app-nav-mobile-tabs>
+</div>

+ 7 - 2
interview-web/src/app/app.ts

@@ -1,12 +1,17 @@
 import { Component } from '@angular/core';
 import { Component } from '@angular/core';
 import { RouterOutlet } from '@angular/router';
 import { RouterOutlet } from '@angular/router';
+import { NavMobileTabs } from '../modules/interview/mobile/nav-mobile-tabs/nav-mobile-tabs';
+import { faUser } from '@fortawesome/free-solid-svg-icons';
 
 
 @Component({
 @Component({
   selector: 'app-root',
   selector: 'app-root',
-  imports: [RouterOutlet],
+  imports: [RouterOutlet, NavMobileTabs,],
   templateUrl: './app.html',
   templateUrl: './app.html',
   styleUrl: './app.scss'
   styleUrl: './app.scss'
 })
 })
 export class App {
 export class App {
   protected title = 'interview-web';
   protected title = 'interview-web';
-}
+  icons = {
+    user: faUser
+  };
+}

+ 13 - 0
interview-web/src/modules/interview/mobile/nav-mobile-tabs/nav-mobile-tabs.html

@@ -1 +1,14 @@
 <p>nav-mobile-tabs works!</p>
 <p>nav-mobile-tabs works!</p>
+<nav class="bottom-nav">
+  <div class="nav-container">
+    <div 
+      *ngFor="let item of navItems" 
+      class="nav-item" 
+      [class.active]="item.active"
+      (click)="navigateTo(item.route)"
+    >
+      <fa-icon [icon]="item.icon" class="nav-icon"></fa-icon>
+      <span class="nav-label">{{item.label}}</span>
+    </div>
+  </div>
+</nav>

+ 68 - 0
interview-web/src/modules/interview/mobile/nav-mobile-tabs/nav-mobile-tabs.scss

@@ -0,0 +1,68 @@
+.bottom-nav {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background: white;
+  box-shadow: 0 -2px 10px rgba(0,0,0,0.05);
+  z-index: 1000;
+  padding: 8px 0;
+  
+  .nav-container {
+    display: flex;
+    justify-content: space-around;
+    max-width: 800px;
+    margin: 0 auto;
+  }
+  
+  .nav-item {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding: 5px 10px;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    opacity: 0.6;
+    
+    &.active {
+      opacity: 1;
+      
+      .nav-icon {
+        color: var(--primary-blue);
+      }
+      
+      .nav-label {
+        color: var(--primary-blue);
+        font-weight: 500;
+      }
+    }
+  }
+  
+  .nav-icon {
+    font-size: 20px;
+    margin-bottom: 4px;
+    color: var(--text-dark);
+    transition: all 0.3s ease;
+  }
+  
+  .nav-label {
+    font-size: 12px;
+    color: var(--text-dark);
+    transition: all 0.3s ease;
+  }
+}
+
+// 响应式调整
+@media (max-width: 600px) {
+  .bottom-nav {
+    padding: 5px 0;
+    
+    .nav-icon {
+      font-size: 18px;
+    }
+    
+    .nav-label {
+      font-size: 10px;
+    }
+  }
+}

+ 62 - 3
interview-web/src/modules/interview/mobile/nav-mobile-tabs/nav-mobile-tabs.ts

@@ -1,11 +1,70 @@
 import { Component } from '@angular/core';
 import { Component } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Router, RouterModule } from '@angular/router';
+import { FaIconComponent, FontAwesomeModule } from '@fortawesome/angular-fontawesome';
+import { 
+  faHome,
+  faSearch,
+  faComments,
+  faUser
+} from '@fortawesome/free-solid-svg-icons';
 
 
 @Component({
 @Component({
   selector: 'app-nav-mobile-tabs',
   selector: 'app-nav-mobile-tabs',
-  imports: [],
+  standalone: true,
+  imports: [CommonModule, RouterModule, FontAwesomeModule, FaIconComponent],
   templateUrl: './nav-mobile-tabs.html',
   templateUrl: './nav-mobile-tabs.html',
-  styleUrl: './nav-mobile-tabs.scss'
+  styleUrls: ['./nav-mobile-tabs.scss']
 })
 })
 export class NavMobileTabs {
 export class NavMobileTabs {
+  // 导航图标
+  icons = {
+    home: faHome,
+    search: faSearch,
+    interview: faComments,
+    mine: faUser
+  };
 
 
-}
+  // 导航项配置
+  navItems = [
+    {
+      icon: this.icons.home,
+      label: '首页',
+      route: '/home',
+      active: false
+    },
+    {
+      icon: this.icons.search,
+      label: '职位',
+      route: '/interview/mobile/page-job-hunting',
+      active: false
+    },
+    {
+      icon: this.icons.interview,
+      label: '面试',
+      route: '/interview/mobile/page-interview',
+      active: false
+    },
+    {
+      icon: this.icons.mine,
+      label: '我的',
+      route: '/interview/mobile/page-mine',
+      active: false
+    }
+  ];
+
+  constructor(private router: Router) {
+    // 监听路由变化更新活动状态
+    this.router.events.subscribe(() => {
+      const currentRoute = this.router.url;
+      this.navItems.forEach(item => {
+        item.active = currentRoute.startsWith(item.route);
+      });
+    });
+  }
+
+  // 导航到指定路由
+  navigateTo(route: string) {
+    this.router.navigate([route]);
+  }
+}

+ 1 - 1
interview-web/src/modules/interview/mobile/page-home/page-home.html

@@ -59,7 +59,7 @@
     <h2 class="section-title">快速开始</h2>
     <h2 class="section-title">快速开始</h2>
     
     
     <div class="quick-actions">
     <div class="quick-actions">
-      <div class="action-card" *ngFor="let action of quickActions" (click)="handleCardClick()" [routerLink]="action.RouterLink">
+      <div class="action-card" *ngFor="let action of quickActions" [routerLink]="action.RouterLink">
         <div class="action-icon" [style.background]="action.gradient">
         <div class="action-icon" [style.background]="action.gradient">
           <fa-icon [icon]="action.icon"></fa-icon>
           <fa-icon [icon]="action.icon"></fa-icon>
         </div>
         </div>

+ 53 - 1
interview-web/src/modules/interview/mobile/page-mine/page-mine.html

@@ -1 +1,53 @@
-<p>page-mine works!</p>
+<div class="mine-container">
+  <!-- 用户信息卡片 -->
+  <div class="user-card">
+    <div class="user-avatar">{{user.avatar}}</div>
+    <div class="user-info">
+      <h2 class="user-name">{{user.name}}</h2>
+      <p class="user-stats">
+        <span>已完成面试: {{user.completedInterviews}}次</span>
+        <span>平均匹配度: {{user.matchRate}}%</span>
+      </p>
+    </div>
+  </div>
+
+  <!-- 主要功能区域 -->
+  <div class="section">
+    <h3 class="section-title">我的工具</h3>
+    <div class="features-grid">
+      <div class="feature-card" *ngFor="let feature of mainFeatures" [routerLink]="feature.route">
+        <div class="feature-icon">
+          <fa-icon [icon]="feature.icon"></fa-icon>
+        </div>
+        <div class="feature-content">
+          <h4 class="feature-title">{{feature.title}}</h4>
+          <p class="feature-desc">{{feature.description}}</p>
+        </div>
+        <fa-icon [icon]="icons.arrowRight" class="feature-arrow"></fa-icon>
+      </div>
+    </div>
+  </div>
+
+  <!-- 其他功能区域 -->
+  <div class="section">
+    <h3 class="section-title">其他</h3>
+    <div class="features-grid">
+      <div class="feature-card" *ngFor="let feature of otherFeatures" [routerLink]="feature.route">
+        <div class="feature-icon">
+          <fa-icon [icon]="feature.icon"></fa-icon>
+        </div>
+        <div class="feature-content">
+          <h4 class="feature-title">{{feature.title}}</h4>
+          <p class="feature-desc">{{feature.description}}</p>
+        </div>
+        <fa-icon [icon]="icons.arrowRight" class="feature-arrow"></fa-icon>
+      </div>
+    </div>
+  </div>
+
+  <!-- 退出登录按钮 -->
+  <button class="logout-btn" (click)="handleLogout()">
+    <fa-icon [icon]="icons.logout"></fa-icon>
+    <span>退出登录</span>
+  </button>
+</div>

+ 221 - 0
interview-web/src/modules/interview/mobile/page-mine/page-mine.scss

@@ -0,0 +1,221 @@
+// =============================================
+// 本地变量定义(确保所有变量都有定义)
+// =============================================
+
+// 主色
+$primary-blue: #2A5CAA !default;
+$accent-orange: #FF6B35 !default;
+
+// 背景与文字
+$bg-light: #F5F7FA !default;
+$text-dark: #2D3748 !default;
+
+// 状态色
+$success-green: #48BB78 !default;
+
+// 阴影
+$card-shadow: 0 10px 20px rgba(0,0,0,0.08) !default;
+
+// CSS变量(兼容性定义)
+:root {
+  --primary-blue: #{$primary-blue};
+  --accent-orange: #{$accent-orange};
+  --bg-light: #{$bg-light};
+  --text-dark: #{$text-dark};
+  --success-green: #{$success-green};
+}
+
+// =============================================
+// 主样式
+// =============================================
+
+.mine-container {
+  padding: 20px;
+  padding-bottom: 100px; // 为底部导航留空间
+
+  /* 用户信息卡片 */
+  .user-card {
+    background: white;
+    border-radius: 16px;
+    padding: 20px;
+    display: flex;
+    align-items: center;
+    margin-bottom: 25px;
+    box-shadow: $card-shadow; // 使用本地定义的变量
+    
+    .user-avatar {
+      width: 60px;
+      height: 60px;
+      border-radius: 50%;
+      background: linear-gradient(135deg, $primary-blue, #3A7BD5);
+      color: white;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      font-size: 24px;
+      font-weight: bold;
+      margin-right: 20px;
+    }
+    
+    .user-info {
+      flex: 1;
+      
+      .user-name {
+        font-size: 20px;
+        margin-bottom: 5px;
+        color: $text-dark;
+      }
+      
+      .user-stats {
+        display: flex;
+        gap: 15px;
+        font-size: 14px;
+        color: #718096;
+        
+        span {
+          display: flex;
+          align-items: center;
+          
+          &::before {
+            content: "•";
+            margin-right: 5px;
+            color: $primary-blue;
+          }
+        }
+      }
+    }
+  }
+
+  /* 功能区 */
+  .section {
+    margin-bottom: 25px;
+    
+    .section-title {
+      font-size: 16px;
+      color: $text-dark;
+      margin-bottom: 15px;
+      padding-left: 10px;
+      position: relative;
+      
+      &::before {
+        content: "";
+        position: absolute;
+        left: 0;
+        top: 50%;
+        transform: translateY(-50%);
+        height: 16px;
+        width: 4px;
+        background: $primary-blue;
+        border-radius: 2px;
+      }
+    }
+  }
+
+  /* 功能卡片 */
+  .features-grid {
+    display: grid;
+    gap: 12px;
+  }
+
+  .feature-card {
+    background: white;
+    border-radius: 12px;
+    padding: 15px;
+    display: flex;
+    align-items: center;
+    box-shadow: $card-shadow;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    
+    &:hover {
+      transform: translateY(-3px);
+      box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+    }
+    
+    .feature-icon {
+      width: 40px;
+      height: 40px;
+      border-radius: 10px;
+      background: rgba($primary-blue, 0.1);
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      margin-right: 15px;
+      color: $primary-blue;
+      font-size: 18px;
+    }
+    
+    .feature-content {
+      flex: 1;
+      
+      .feature-title {
+        font-size: 16px;
+        color: $text-dark;
+        margin-bottom: 3px;
+      }
+      
+      .feature-desc {
+        font-size: 12px;
+        color: #718096;
+      }
+    }
+    
+    .feature-arrow {
+      color: #CBD5E0;
+      font-size: 14px;
+    }
+  }
+
+  /* 退出登录按钮 */
+  .logout-btn {
+    width: 100%;
+    padding: 12px;
+    background: white;
+    border: 1px solid #E2E8F0;
+    border-radius: 8px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    gap: 8px;
+    color: #E53E3E;
+    font-size: 14px;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    margin-top: 20px;
+    
+    &:hover {
+      background: #FFF5F5;
+      border-color: #FEB2B2;
+    }
+    
+    fa-icon {
+      font-size: 16px;
+    }
+  }
+}
+
+/* 响应式调整 */
+@media (max-width: 600px) {
+  .mine-container {
+    padding: 15px;
+    padding-bottom: 100px;
+  }
+  
+  .user-card {
+    padding: 15px;
+    
+    .user-avatar {
+      width: 50px;
+      height: 50px;
+      font-size: 20px;
+    }
+    
+    .user-name {
+      font-size: 18px;
+    }
+  }
+  
+  .feature-card {
+    padding: 12px;
+  }
+}

+ 79 - 3
interview-web/src/modules/interview/mobile/page-mine/page-mine.ts

@@ -1,11 +1,87 @@
 import { Component } from '@angular/core';
 import { Component } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+import { FaIconComponent } from '@fortawesome/angular-fontawesome';
+import { 
+  faUserCircle,
+  faFileAlt,
+  faCog,
+  faChartBar,
+  faQuestionCircle,
+  faInfoCircle,
+  faSignOutAlt,
+  faArrowRight
+} from '@fortawesome/free-solid-svg-icons';
 
 
 @Component({
 @Component({
   selector: 'app-page-mine',
   selector: 'app-page-mine',
-  imports: [],
+  standalone: true,
+  imports: [CommonModule, RouterModule, FaIconComponent],
   templateUrl: './page-mine.html',
   templateUrl: './page-mine.html',
-  styleUrl: './page-mine.scss'
+  styleUrls: ['./page-mine.scss']
 })
 })
 export class PageMine {
 export class PageMine {
+  // Font Awesome 图标
+  icons = {
+    user: faUserCircle,
+    resume: faFileAlt,
+    settings: faCog,
+    report: faChartBar,
+    help: faQuestionCircle,
+    about: faInfoCircle,
+    logout: faSignOutAlt,
+    arrowRight: faArrowRight
+  };
 
 
-}
+  // 用户信息
+  user = {
+    name: '李华',
+    avatar: 'LH',
+    completedInterviews: 5,
+    matchRate: 82
+  };
+
+  // 主要功能列表
+  mainFeatures = [
+    {
+      icon: this.icons.resume,
+      title: '简历编辑',
+      description: '完善您的个人简历信息',
+      route: '/mine/resume'
+    },
+    {
+      icon: this.icons.settings,
+      title: '账号设置',
+      description: '修改个人信息和安全设置',
+      route: '/mine/settings'
+    },
+    {
+      icon: this.icons.report,
+      title: '分析报告',
+      description: '查看历史面试表现分析',
+      route: '/mine/reports'
+    }
+  ];
+
+  // 其他功能列表
+  otherFeatures = [
+    {
+      icon: this.icons.help,
+      title: '帮助中心',
+      description: '常见问题与使用指南',
+      route: '/mine/help'
+    },
+    {
+      icon: this.icons.about,
+      title: '关于我们',
+      description: '了解AI面试官',
+      route: '/mine/about'
+    }
+  ];
+
+  // 处理退出登录
+  handleLogout() {
+    console.log('用户退出登录');
+    // 实际项目中这里会有退出登录的逻辑
+  }
+}

+ 22 - 0
interview-web/src/styles/variables.scss

@@ -0,0 +1,22 @@
+// 主色
+$primary-blue: #2A5CAA;
+$accent-orange: #FF6B35;
+
+// 背景与文字
+$bg-light: #F5F7FA;
+$text-dark: #2D3748;
+
+// 状态色
+$success-green: #48BB78;
+
+// 阴影
+$card-shadow: 0 10px 20px rgba(0,0,0,0.08);
+
+// CSS变量(与Sass变量同时定义)
+:root {
+  --primary-blue: #2A5CAA;
+  --accent-orange: #FF6B35;
+  --bg-light: #F5F7FA;
+  --text-dark: #2D3748;
+  --success-green: #48BB78;
+}