Browse Source

Merge branch 'master' of http://git.fmode.cn:3000/18307996893/ai-manager

StarJie-Xu 2 days ago
parent
commit
a1f2282303

+ 15 - 0
.hintrc

@@ -0,0 +1,15 @@
+{
+  "extends": [
+    "development"
+  ],
+  "hints": {
+    "compat-api/css": [
+      "default",
+      {
+        "ignore": [
+          "backdrop-filter"
+        ]
+      }
+    ]
+  }
+}

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

@@ -1,27 +1,34 @@
 <router-outlet></router-outlet>
 
+<!-- 科技感移动导航栏 -->
+<nav class="tech-nav">
+    <div class="nav-indicator"></div>
     
-    <!-- 移动导航栏 -->
-    <nav class="nav-mobile-tabs">
-        <div class="indicator"></div>
-        
-        <a routerLink="/mobile/home" class="nav-tab active">
+    <a routerLink="/mobile/home" class="nav-item active" aria-label="首页">
+        <div class="nav-icon">
             <i class="fas fa-home"></i>
-            <span>首页</span>
-        </a>
-        
-        <a routerLink="/mobile/cart" class="nav-tab">
-            <i class="fas fa-shopping-cart"></i>
-            <span>销售数据</span>
-        </a>
-        
-        <a routerLink="/mobile/mine" class="nav-tab">
-            <i class="fas fa-chart-line"></i>
-            <span>场馆日历</span>
-        </a>
-        
-        <a href="#" class="nav-tab">
+        </div>
+        <span class="nav-label">首页</span>
+    </a>
+    
+    <a routerLink="/mobile/cart" class="nav-item" aria-label="销售数据">
+        <div class="nav-icon">
+            <i class="fas fa-chart-bar"></i>
+        </div>
+        <span class="nav-label">销售数据</span>
+    </a>
+    
+    <a routerLink="/mobile/mine" class="nav-item" aria-label="场馆日历">
+        <div class="nav-icon">
+            <i class="fas fa-calendar-alt"></i>
+        </div>
+        <span class="nav-label">场馆日历</span>
+    </a>
+    
+    <a routerLink="/mobile/settings" class="nav-item" aria-label="设置">
+        <div class="nav-icon">
             <i class="fas fa-cog"></i>
-            <span>设置</span>
-        </a>
-    </nav>
+        </div>
+        <span class="nav-label">设置</span>
+    </a>
+</nav>

+ 135 - 72
manager-web/src/modules/manager/mobile/nav-mobile-tabs/nav-mobile-tabs.scss

@@ -1,73 +1,136 @@
+:root {
+  --nav-height: 72px;
+  --primary-bg: #0f172a; // 深蓝底色
+  --glass-bg: rgba(15, 23, 42, 0.85);
+  --accent-color: #3b82f6; // 科技蓝
+  --accent-glow: 0 0 10px rgba(59, 130, 246, 0.7);
+  --text-primary: #e2e8f0;
+  --text-secondary: #94a3b8;
+  --transition-speed: 0.25s;
+}
 
-        /* 移动导航栏样式 */
-        .nav-mobile-tabs {
-            position: fixed;
-            bottom: 0;
-            left: 0;
-            right: 0;
-            height: var(--nav-height);
-            background: rgba(15, 23, 42, 0.95);
-            backdrop-filter: blur(10px);
-            display: flex;
-            justify-content: space-around;
-            align-items: center;
-            border-top: 1px solid var(--glass-border);
-            z-index: 1000;
-            box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.2);
-        }
-        
-        .nav-tab {
-            display: flex;
-            flex-direction: column;
-            align-items: center;
-            justify-content: center;
-            width: 25%;
-            height: 100%;
-            color: #94a3b8;
-            text-decoration: none;
-            font-size: 12px;
-            transition: all 0.3s ease;
-            position: relative;
-        }
-        
-        .nav-tab i {
-            font-size: 20px;
-            margin-bottom: 4px;
-            transition: all 0.3s ease;
-        }
-        
-        .nav-tab.active {
-            color: white;
-        }
-        
-        .nav-tab.active i {
-            color: var(--accent);
-            transform: translateY(-5px);
-        }
-        
-        .nav-tab::after {
-            content: '';
-            position: absolute;
-            bottom: 0;
-            left: 50%;
-            transform: translateX(-50%);
-            width: 0;
-            height: 3px;
-            background: var(--accent);
-            border-radius: 3px 3px 0 0;
-            transition: all 0.3s ease;
-        }
-        
-        .nav-tab.active::after {
-            width: 60%;
-        }
-        
-        .nav-tab:hover {
-            color: white;
-            background: rgba(255, 255, 255, 0.05);
-        }
-        
-        .nav-tab:active {
-            transform: scale(0.95);
-        }
-        
+/* 科技感导航栏 */
+.tech-nav {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  height: var(--nav-height);
+  background: var(--glass-bg);
+  backdrop-filter: blur(12px) saturate(180%);
+  display: flex;
+  justify-content: space-around;
+  align-items: center;
+  border-top: 1px solid rgba(255, 255, 255, 0.08);
+  z-index: 1000;
+  box-shadow: 0 -2px 30px rgba(0, 0, 0, 0.3);
+  padding: 0 16px;
+}
+
+.nav-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  width: 25%;
+  height: 100%;
+  color: var(--text-secondary);
+  text-decoration: none;
+  position: relative;
+  transition: all var(--transition-speed) ease;
+  overflow: hidden;
+  
+  &::before {
+    content: '';
+    position: absolute;
+    top: -10px;
+    left: 50%;
+    transform: translateX(-50%);
+    width: 40px;
+    height: 40px;
+    background: var(--accent-color);
+    border-radius: 50%;
+    opacity: 0;
+    transition: all var(--transition-speed) ease;
+    filter: blur(8px);
+  }
+}
+
+.nav-icon {
+  font-size: 20px;
+  width: 44px;
+  height: 44px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border-radius: 12px;
+  margin-bottom: 4px;
+  transition: all var(--transition-speed) ease;
+  position: relative;
+  z-index: 1;
+  background: rgba(255, 255, 255, 0.05);
+}
+
+.nav-label {
+  font-size: 12px;
+  font-weight: 500;
+  transition: all var(--transition-speed) ease;
+  position: relative;
+  z-index: 1;
+}
+
+/* 活动状态样式 */
+.nav-item.active {
+  color: var(--text-primary);
+  
+  .nav-icon {
+    background: rgba(59, 130, 246, 0.2);
+    box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.3);
+    transform: translateY(-6px);
+    
+    i {
+      color: var(--accent-color);
+      text-shadow: var(--accent-glow);
+    }
+  }
+  
+  .nav-label {
+    transform: translateY(4px);
+    font-weight: 600;
+  }
+  
+  &::before {
+    opacity: 0.3;
+    top: -20px;
+  }
+}
+
+/* 导航指示器 */
+.nav-indicator {
+  position: absolute;
+  top: -12px;
+  left: 0;
+  height: 4px;
+  background: var(--accent-color);
+  border-radius: 2px;
+  transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
+  box-shadow: var(--accent-glow);
+  z-index: 2;
+}
+
+/* 悬停效果 */
+@media (hover: hover) {
+  .nav-item:hover:not(.active) {
+    color: var(--text-primary);
+    
+    .nav-icon {
+      transform: translateY(-2px);
+      background: rgba(255, 255, 255, 0.1);
+    }
+  }
+}
+
+/* 点击反馈 */
+.nav-item:active {
+  transform: scale(0.96);
+}

+ 6 - 5
manager-web/src/modules/manager/mobile/nav-mobile-tabs/nav-mobile-tabs.ts

@@ -2,11 +2,12 @@ import { Component } from '@angular/core';
 import { RouterModule } from '@angular/router';
 
 @Component({
-  selector: 'app-nav-mobile-tabs',
+  selector: 'app-tech-nav',
+  standalone: true,
   imports: [RouterModule],
-  templateUrl: './nav-mobile-tabs.html',
-  styleUrl: './nav-mobile-tabs.scss'
+  templateUrl: './tech-nav.component.html',
+  styleUrls: ['./tech-nav.component.scss']
 })
 export class NavMobileTabs {
-
-}
+  // 可以在这里添加导航逻辑,如跟踪活动标签等
+}

+ 15 - 18
manager-web/src/modules/manager/mobile/page-home/page-home.html

@@ -168,25 +168,22 @@
       </div>
       
       <div class="chart-container">
-        <div class="chart-header">
-          <div class="chart-title">
-            <i class="fas fa-chart-bar"></i>
-            <span>销售团队业绩分析</span>
-          </div>
-          <div class="chart-actions">
-            <button class="btn btn-outline" (click)="exportChart()">
-              <i class="fas fa-download"></i> 导出
-            </button>
-            <button class="btn btn-primary" (click)="refreshChart()">
-              <i class="fas fa-sync-alt"></i> 更新
-            </button>
-          </div>
-        </div>
-        <div class="chart-wrapper">
-          <div echarts [options]="chartOptions" class="echarts-chart"></div>
-        </div>
-      </div>
+  <div class="chart-header">
+    <div class="chart-title">
+      <i class="fas fa-chart-bar"></i>
+      <span>销售团队业绩分析</span>
     </div>
+    <div class="chart-actions">
+      <button class="btn btn-outline" (click)="exportChart()">
+        <i class="fas fa-download"></i> 导出
+      </button>
+      <button class="btn btn-primary" (click)="refreshChart()">
+        <i class="fas fa-sync-alt"></i> 更新
+      </button>
+    </div>
+  </div>
+  <div class="chart-wrapper">
+    <div echarts [options]="chartOptions" class="echarts-chart" style="height: 350px;"></div>
   </div>
 </div>
 

+ 15 - 4
manager-web/src/modules/manager/mobile/page-home/page-home.scss

@@ -661,6 +661,11 @@ header {
   padding: 25px;
   box-shadow: var(--shadow);
   margin-bottom: 30px;
+  transition: var(--transition);
+  
+  &:hover {
+    box-shadow: var(--shadow-hover);
+  }
 }
 
 .chart-header {
@@ -677,10 +682,10 @@ header {
   display: flex;
   align-items: center;
   gap: 10px;
-}
-
-.chart-title i {
-  color: var(--primary);
+  
+  i {
+    color: var(--primary);
+  }
 }
 
 .chart-actions {
@@ -691,11 +696,17 @@ header {
 .chart-wrapper {
   height: 350px;
   position: relative;
+  transition: var(--transition);
+  
+  &:hover {
+    transform: translateY(-2px);
+  }
 }
 
 .echarts-chart {
   width: 100%;
   height: 100%;
+  transition: var(--transition);
 }
 
 /* AI权限管理面板 */

+ 116 - 79
manager-web/src/modules/manager/mobile/page-home/page-home.ts

@@ -1,17 +1,23 @@
 import { Component, OnInit } from '@angular/core';
-import { NgxEchartsModule } from 'ngx-echarts';
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
+import { NgxEchartsDirective, provideEchartsCore } from 'ngx-echarts';
 import * as echarts from 'echarts';
 
+
 @Component({
   selector: 'app-page-home',
   standalone: true,
   imports: [
     CommonModule,
-    NgxEchartsModule,
-    FormsModule
+    FormsModule,
+    NgxEchartsDirective // 使用指令而不是模块
   ],
+  providers: [
+  provideEchartsCore({
+    echarts: () => import('echarts')
+  })
+],
   templateUrl: './page-home.html',
   styleUrls: ['./page-home.scss']
 })
@@ -85,92 +91,123 @@ applyAiRecommendation() {
   }
 
   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'
+  this.chartOptions = {
+    backgroundColor: 'transparent',
+    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'
+      },
+      formatter: '{b}: {c}万元'
+    },
+    grid: {
+      left: '3%',
+      right: '4%',
+      bottom: '3%',
+      top: '10%',
+      containLabel: true
+    },
+    xAxis: {
+      type: 'value',
+      axisLine: {
+        lineStyle: {
+          color: 'rgba(0, 0, 0, 0.1)'
         }
       },
-      grid: {
-        left: '3%',
-        right: '4%',
-        bottom: '3%',
-        containLabel: true
+      axisLabel: {
+        color: '#64748b',
+        formatter: '{value}万'
       },
-      xAxis: {
-        type: 'value',
-        axisLine: {
-          lineStyle: {
-            color: 'rgba(0, 0, 0, 0.1)'
-          }
-        },
-        axisLabel: {
-          color: '#64748b'
-        },
-        splitLine: {
-          lineStyle: {
-            color: 'rgba(0, 0, 0, 0.05)'
-          }
+      splitLine: {
+        lineStyle: {
+          color: 'rgba(0, 0, 0, 0.05)'
         }
       },
-      yAxis: {
-        type: 'category',
-        data: ['实习销售', '白银销售', '黄金销售', '铂金销售', '钻石销售'],
-        axisLine: {
-          lineStyle: {
-            color: 'rgba(0, 0, 0, 0.1)'
-          }
-        },
-        axisLabel: {
-          color: '#64748b'
+      name: '平均月业绩',
+      nameTextStyle: {
+        color: '#64748b',
+        padding: [0, 0, 0, 40]
+      }
+    },
+    yAxis: {
+      type: 'category',
+      data: ['实习销售', '白银销售', '黄金销售', '铂金销售', '钻石销售'],
+      axisLine: {
+        lineStyle: {
+          color: 'rgba(0, 0, 0, 0.1)'
         }
       },
-      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]
+      axisLabel: {
+        color: '#64748b',
+        fontWeight: 'bold'
+      },
+      axisTick: {
+        show: false
+      }
+    },
+    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.8)',
+              'rgba(148, 163, 184, 0.8)',
+              'rgba(245, 158, 11, 0.8)',
+              'rgba(129, 140, 248, 0.8)',
+              'rgba(34, 211, 238, 0.8)'
+            ];
+            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];
           },
-          label: {
-            show: true,
-            position: 'right',
-            color: '#64748b',
-            formatter: '{c}万'
+          borderWidth: 2,
+          borderRadius: [4, 4, 0, 0],
+          shadowColor: 'rgba(0, 0, 0, 0.1)',
+          shadowBlur: 5,
+          shadowOffsetY: 2
+        },
+        label: {
+          show: true,
+          position: 'right',
+          color: '#64748b',
+          formatter: '{c}万',
+          fontWeight: 'bold'
+        },
+        barWidth: '40%',
+        emphasis: {
+          itemStyle: {
+            shadowColor: 'rgba(0, 0, 0, 0.2)',
+            shadowBlur: 10,
+            shadowOffsetY: 3
           }
+        },
+        animationType: 'scale',
+        animationEasing: 'elasticOut',
+        animationDelay: function (idx: number) {
+          return idx * 100;
         }
-      ]
-    };
-  }
+      }
+    ],
+    animationDuration: 1000
+  };
+}
 
   setFilter(level: string) {
     this.activeFilter = this.activeFilter === level ? null : level;

+ 165 - 1
manager-web/src/modules/manager/mobile/page-mine/page-mine.html

@@ -1 +1,165 @@
-<p>page-mine works!</p>
+<div class="calendar-container">
+  <!-- 头部区域 -->
+  <div class="header">
+    <h1><i class="fas fa-calendar-alt"></i> 婚庆AI全周期管理系统 - 场馆日历</h1>
+    <div class="user-info">
+      <button class="btn"><i class="fas fa-user"></i> 管理员</button>
+    </div>
+  </div>
+
+  <!-- 统计卡片 -->
+  <div class="stats">
+    <div class="stat-card">
+      <div class="stat-icon">
+        <i class="fas fa-calendar-day fa-2x"></i>
+      </div>
+      <div class="stat-value">{{ stats.totalEvents }}</div>
+      <div class="stat-title">本月预订</div>
+    </div>
+    <div class="stat-card">
+      <div class="stat-icon">
+        <i class="fas fa-heart fa-2x"></i>
+      </div>
+      <div class="stat-value">{{ stats.weddings }}</div>
+      <div class="stat-title">婚礼预订</div>
+    </div>
+    <div class="stat-card">
+      <div class="stat-icon">
+        <i class="fas fa-utensils fa-2x"></i>
+      </div>
+      <div class="stat-value">{{ stats.banquets }}</div>
+      <div class="stat-title">宴会预订</div>
+    </div>
+    <div class="stat-card">
+      <div class="stat-icon">
+        <i class="fas fa-users fa-2x"></i>
+      </div>
+      <div class="stat-value">{{ stats.meetings }}</div>
+      <div class="stat-title">会议预订</div>
+    </div>
+  </div>
+
+  <!-- 控制区域 -->
+  <div class="controls">
+    <div class="date-controls">
+      <button class="btn" (click)="changeMonth(-1)">
+        <i class="fas fa-chevron-left"></i>
+      </button>
+      <div class="date-display">{{ currentYear }}年{{ currentMonth + 1 }}月</div>
+      <button class="btn" (click)="changeMonth(1)">
+        <i class="fas fa-chevron-right"></i>
+      </button>
+      <button class="btn btn-outline" (click)="goToToday()">今天</button>
+    </div>
+    
+    <div class="view-controls">
+      <button 
+        class="view-btn" 
+        [class.active]="viewMode === 'month'"
+        (click)="viewMode = 'month'"
+      >
+        月视图
+      </button>
+      <button 
+        class="view-btn" 
+        [class.active]="viewMode === 'week'"
+        (click)="viewMode = 'week'"
+      >
+        周视图
+      </button>
+    </div>
+  </div>
+
+  <!-- 筛选器 -->
+  <div class="filters">
+    <div 
+      class="filter-item" 
+      [class.active]="activeFilter === 'all'"
+      (click)="setFilter('all')"
+    >
+      <div class="filter-color wedding"></div>
+      <span>全部活动</span>
+    </div>
+    <div 
+      class="filter-item" 
+      [class.active]="activeFilter === 'wedding'"
+      (click)="setFilter('wedding')"
+    >
+      <div class="filter-color wedding"></div>
+      <span>婚礼</span>
+    </div>
+    <div 
+      class="filter-item" 
+      [class.active]="activeFilter === 'banquet'"
+      (click)="setFilter('banquet')"
+    >
+      <div class="filter-color banquet"></div>
+      <span>宴会</span>
+    </div>
+    <div 
+      class="filter-item" 
+      [class.active]="activeFilter === 'meeting'"
+      (click)="setFilter('meeting')"
+    >
+      <div class="filter-color meeting"></div>
+      <span>会议</span>
+    </div>
+    <div 
+      class="filter-item" 
+      [class.active]="activeFilter === 'other'"
+      (click)="setFilter('other')"
+    >
+      <div class="filter-color other"></div>
+      <span>其他</span>
+    </div>
+  </div>
+
+  <!-- 日历区域 -->
+  <div class="calendar">
+    <!-- 月视图 -->
+    <div class="month-view" *ngIf="viewMode === 'month'">
+      <div class="day-header" *ngFor="let day of weekDays">{{ day }}</div>
+      
+      <div 
+        class="calendar-day" 
+        [class.other-month]="!day.isCurrentMonth"
+        [class.today]="day.isToday"
+        *ngFor="let day of monthDays"
+      >
+        <div class="day-number">{{ day.date }}</div>
+        <div class="events">
+          <div 
+            class="event" 
+            [class]="event.type" 
+            *ngFor="let event of day.events"
+          >
+            <div>{{ event.title }}</div>
+            <small>{{ event.time }} | {{ event.venue }}</small>
+          </div>
+        </div>
+      </div>
+    </div>
+    
+    <!-- 周视图 -->
+    <div class="week-view" *ngIf="viewMode === 'week'">
+      <div class="week-grid">
+        <div class="time-slot" *ngFor="let hour of hours">
+          <div class="time-label">{{ hour }}:00</div>
+        </div>
+        
+        <div class="day-column" *ngFor="let day of weekDays; let i = index">
+          <div class="day-header">{{ day }}</div>
+          <div class="time-slot" *ngFor="let hour of hours">
+            <div 
+              class="week-event {{ event.type }}" 
+              *ngFor="let event of getEventsForDayAndHour(i, hour)"
+            >
+              <strong>{{ event.title }}</strong>
+              <div>{{ event.time }} | {{ event.venue }}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>

+ 438 - 0
manager-web/src/modules/manager/mobile/page-mine/page-mine.scss

@@ -0,0 +1,438 @@
+@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap');
+
+$primary: #9c27b0;
+$primary-light: #e1bee7;
+$primary-dark: #7b1fa2;
+$secondary: #ff9800;
+$accent: #4caf50;
+$text: #333;
+$text-light: #666;
+$bg: #f9f9f9;
+$bg-card: #fff;
+$border: #e0e0e0;
+$shadow: rgba(0, 0, 0, 0.1);
+
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+  font-family: 'Noto Sans SC', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+}
+
+.calendar-container {
+  max-width: 1400px;
+  margin: 0 auto;
+  padding: 20px;
+  background-color: $bg;
+  min-height: 100vh;
+}
+
+/* 顶部标题和功能区 */
+.header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 30px;
+  padding-bottom: 20px;
+  border-bottom: 1px solid $border;
+
+  h1 {
+    color: $primary;
+    font-size: 28px;
+    display: flex;
+    align-items: center;
+    gap: 12px;
+    
+    i {
+      background: linear-gradient(135deg, $primary, $primary-dark);
+      -webkit-background-clip: text;
+      background-clip: text;
+      -webkit-text-fill-color: transparent;
+    }
+  }
+}
+
+/* 控制栏 */
+.controls {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+  background: $bg-card;
+  padding: 15px 20px;
+  border-radius: 12px;
+  box-shadow: 0 4px 12px $shadow;
+}
+
+.date-controls {
+  display: flex;
+  align-items: center;
+  gap: 15px;
+}
+
+.date-display {
+  font-size: 22px;
+  font-weight: 600;
+  min-width: 220px;
+  text-align: center;
+}
+
+.btn {
+  background: $primary;
+  color: white;
+  border: none;
+  padding: 10px 18px;
+  border-radius: 8px;
+  cursor: pointer;
+  font-weight: 600;
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  transition: all 0.3s ease;
+  
+  &:hover {
+    background: $primary-dark;
+    transform: translateY(-2px);
+  }
+  
+  &-outline {
+    background: transparent;
+    border: 2px solid $primary;
+    color: $primary;
+    
+    &:hover {
+      background: $primary-light;
+    }
+  }
+}
+
+.view-controls {
+  display: flex;
+  gap: 10px;
+}
+
+.view-btn {
+  padding: 8px 16px;
+  border-radius: 8px;
+  background: transparent;
+  border: 2px solid $border;
+  cursor: pointer;
+  font-weight: 600;
+  transition: all 0.2s;
+  
+  &.active {
+    background: $primary;
+    color: white;
+    border-color: $primary;
+  }
+  
+  &:hover:not(.active) {
+    background: #f0f0f0;
+  }
+}
+
+/* 筛选区域 */
+.filters {
+  display: flex;
+  gap: 15px;
+  margin-bottom: 20px;
+  flex-wrap: wrap;
+}
+
+.filter-item {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  background: $bg-card;
+  padding: 10px 15px;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px $shadow;
+  cursor: pointer;
+  transition: all 0.2s;
+  
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 4px 12px $shadow;
+  }
+  
+  &.active {
+    background: $primary;
+    color: white;
+  }
+}
+
+.filter-color {
+  width: 16px;
+  height: 16px;
+  border-radius: 50%;
+  
+  &.wedding {
+    background: linear-gradient(135deg, #e91e63, #9c27b0);
+  }
+  
+  &.banquet {
+    background: linear-gradient(135deg, #4caf50, #8bc34a);
+  }
+  
+  &.meeting {
+    background: linear-gradient(135deg, #2196f3, #03a9f4);
+  }
+  
+  &.other {
+    background: linear-gradient(135deg, #ff9800, #ffc107);
+  }
+}
+
+/* 日历区域 */
+.calendar {
+  background: $bg-card;
+  border-radius: 12px;
+  overflow: hidden;
+  box-shadow: 0 8px 30px $shadow;
+}
+
+/* 月视图 */
+.month-view {
+  display: grid;
+  grid-template-columns: repeat(7, 1fr);
+  width: 100%;
+}
+
+.day-header {
+  padding: 15px 10px;
+  text-align: center;
+  font-weight: 600;
+  background: $primary;
+  color: white;
+}
+
+.calendar-day {
+  min-height: 120px;
+  border: 1px solid $border;
+  padding: 10px;
+  position: relative;
+  transition: all 0.3s ease;
+  
+  &:hover {
+    background: #fafafa;
+    transform: scale(1.02);
+    z-index: 2;
+    box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+  }
+}
+
+.day-number {
+  font-size: 18px;
+  font-weight: 700;
+  margin-bottom: 8px;
+}
+
+.other-month {
+  background: #fafafa;
+  color: #aaa;
+}
+
+.today .day-number {
+  display: inline-block;
+  background: $primary;
+  color: white;
+  width: 30px;
+  height: 30px;
+  line-height: 30px;
+  text-align: center;
+  border-radius: 50%;
+}
+
+/* 事件样式 */
+.events {
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+  margin-top: 5px;
+}
+
+.event {
+  padding: 6px 8px;
+  border-radius: 6px;
+  font-size: 13px;
+  color: white;
+  cursor: pointer;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  transition: all 0.2s;
+  
+  &:hover {
+    transform: translateX(3px);
+  }
+  
+  &.wedding {
+    background: linear-gradient(90deg, #e91e63, #9c27b0);
+  }
+  
+  &.banquet {
+    background: linear-gradient(90deg, #4caf50, #8bc34a);
+  }
+  
+  &.meeting {
+    background: linear-gradient(90deg, #2196f3, #03a9f4);
+  }
+  
+  &.other {
+    background: linear-gradient(90deg, #ff9800, #ffc107);
+  }
+}
+
+/* 周视图 */
+.week-view {
+  .week-grid {
+    display: grid;
+    grid-template-columns: 100px repeat(7, 1fr);
+  }
+  
+  .time-slot {
+    height: 80px;
+    border: 1px solid $border;
+    padding: 5px;
+    position: relative;
+  }
+  
+  .time-label {
+    position: absolute;
+    top: -10px;
+    left: 5px;
+    font-size: 12px;
+    color: $text-light;
+  }
+  
+  .week-event {
+    position: absolute;
+    border-radius: 6px;
+    padding: 5px;
+    color: white;
+    font-size: 12px;
+    overflow: hidden;
+    cursor: pointer;
+    width: 95%;
+    height: 70px;
+    
+    &.wedding {
+      background: linear-gradient(90deg, #e91e63, #9c27b0);
+    }
+    
+    &.banquet {
+      background: linear-gradient(90deg, #4caf50, #8bc34a);
+    }
+    
+    &.meeting {
+      background: linear-gradient(90deg, #2196f3, #03a9f4);
+    }
+    
+    &.other {
+      background: linear-gradient(90deg, #ff9800, #ffc107);
+    }
+  }
+}
+
+/* 统计数据 */
+.stats {
+  display: flex;
+  gap: 20px;
+  margin: 20px 0;
+  flex-wrap: wrap;
+}
+
+.stat-card {
+  flex: 1;
+  min-width: 200px;
+  background: $bg-card;
+  padding: 20px;
+  border-radius: 12px;
+  box-shadow: 0 4px 12px $shadow;
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+  
+  .stat-value {
+    font-size: 32px;
+    font-weight: 700;
+    color: $primary;
+  }
+  
+  .stat-title {
+    color: $text-light;
+    font-weight: 600;
+  }
+  
+  .stat-icon {
+    width: 50px;
+    height: 50px;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-bottom: 10px;
+  }
+  
+  &:nth-child(1) .stat-icon {
+    background: rgba(156, 39, 176, 0.1);
+    color: $primary;
+  }
+  
+  &:nth-child(2) .stat-icon {
+    background: rgba(76, 175, 80, 0.1);
+    color: $accent;
+  }
+  
+  &:nth-child(3) .stat-icon {
+    background: rgba(33, 150, 243, 0.1);
+    color: #2196f3;
+  }
+  
+  &:nth-child(4) .stat-icon {
+    background: rgba(255, 152, 0, 0.1);
+    color: $secondary;
+  }
+}
+
+/* 响应式设计 */
+@media (max-width: 992px) {
+  .controls {
+    flex-direction: column;
+    gap: 15px;
+    align-items: flex-start;
+  }
+  
+  .view-controls {
+    align-self: flex-end;
+  }
+}
+
+@media (max-width: 768px) {
+  .month-view {
+    grid-template-columns: repeat(1, 1fr);
+  }
+  
+  .day-header {
+    display: none;
+  }
+  
+  .calendar-day {
+    min-height: auto;
+  }
+  
+  .header {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 15px;
+  }
+  
+  .week-grid {
+    grid-template-columns: 60px repeat(1, 1fr);
+    overflow-x: auto;
+  }
+  
+  .stats {
+    flex-direction: column;
+  }
+}

+ 4 - 4
manager-web/src/modules/manager/mobile/page-mine/page-mine.spec.ts

@@ -3,16 +3,16 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { PageMine } from './page-mine';
 
 describe('PageMine', () => {
-  let component: PageMine;
-  let fixture: ComponentFixture<PageMine>;
+  let component: PageMine ;
+  let fixture: ComponentFixture<PageMine >;
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      imports: [PageMine]
+      imports: [PageMine ]
     })
     .compileComponents();
 
-    fixture = TestBed.createComponent(PageMine);
+    fixture = TestBed.createComponent(PageMine );
     component = fixture.componentInstance;
     fixture.detectChanges();
   });

+ 205 - 6
manager-web/src/modules/manager/mobile/page-mine/page-mine.ts

@@ -1,12 +1,211 @@
-import { Component } from '@angular/core';
-import { RouterModule } from '@angular/router';
+import { CommonModule } from '@angular/common';
+import { Component, OnInit } from '@angular/core';
+
+interface CalendarDay {
+  date: number;
+  isCurrentMonth: boolean;
+  isToday: boolean;
+  events: any[];
+}
+
+interface Event {
+  id: number;
+  date: Date;
+  title: string;
+  type: string;
+  time: string;
+  venue: string;
+}
 
 @Component({
   selector: 'app-page-mine',
-  imports: [RouterModule],
   templateUrl: './page-mine.html',
-  styleUrl: './page-mine.scss'
+  styleUrls: ['./page-mine.scss'],
+  standalone:true,
+  imports:[
+    CommonModule
+  ]
 })
-export class PageMine {
+export class PageMine implements OnInit {
+  weekDays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
+  hours = Array.from({length: 24}, (_, i) => i); // 0-23小时
+  currentDate: Date = new Date(); // 初始化当前日期
+  currentMonth: number = this.currentDate.getMonth(); // 初始化当前月份
+  currentYear: number = this.currentDate.getFullYear(); // 初始化当前年份
+  viewMode: 'month' | 'week' = 'month';
+  activeFilter: string = 'all';
+  
+  monthDays: CalendarDay[] = [];
+  events: Event[] = [];
+  
+  stats = {
+    totalEvents: 0,
+    weddings: 0,
+    banquets: 0,
+    meetings: 0
+  };
 
-}
+  ngOnInit() {
+    // 不需要再次初始化,因为已经在声明时初始化
+    this.initializeEvents();
+    this.generateCalendar();
+    this.calculateStats();
+  }
+
+  initializeEvents() {
+    this.events = [
+      { id: 1, date: new Date(this.currentYear, this.currentMonth, 5), title: '张先生 & 李女士婚礼', type: 'wedding', time: '10:00-14:00', venue: '玫瑰厅' },
+      { id: 2, date: new Date(this.currentYear, this.currentMonth, 8), title: '公司年度晚宴', type: 'banquet', time: '18:00-21:00', venue: '宴会A厅' },
+      { id: 3, date: new Date(this.currentYear, this.currentMonth, 12), title: '王先生 & 赵女士婚礼', type: 'wedding', time: '11:00-15:00', venue: '百合厅' },
+      { id: 4, date: new Date(this.currentYear, this.currentMonth, 15), title: '产品发布会', type: 'meeting', time: '14:00-16:00', venue: '会议中心' },
+      { id: 5, date: new Date(this.currentYear, this.currentMonth, 18), title: '陈先生 & 刘女士婚礼', type: 'wedding', time: '09:30-13:30', venue: '牡丹厅' },
+      { id: 6, date: new Date(this.currentYear, this.currentMonth, 20), title: '生日宴会', type: 'banquet', time: '19:00-22:00', venue: '宴会B厅' },
+      { id: 7, date: new Date(this.currentYear, this.currentMonth, 25), title: '婚庆行业交流会', type: 'meeting', time: '10:00-12:00', venue: '会议中心' },
+      { id: 8, date: new Date(this.currentYear, this.currentMonth, 28), title: '周先生 & 吴女士婚礼', type: 'wedding', time: '10:30-14:30', venue: '玫瑰厅' },
+      { id: 9, date: new Date(this.currentYear, this.currentMonth, 30), title: '公司团建活动', type: 'other', time: '全天', venue: '户外场地' }
+    ];
+  }
+
+  generateCalendar() {
+    this.monthDays = [];
+    
+    // 获取当月第一天
+    const firstDay = new Date(this.currentYear, this.currentMonth, 1);
+    // 获取当月最后一天
+    const lastDay = new Date(this.currentYear, this.currentMonth + 1, 0);
+    // 获取当月第一天是星期几(0为周日,6为周六)
+    const firstDayIndex = firstDay.getDay() === 0 ? 6 : firstDay.getDay() - 1;
+    // 获取当月最后一天是星期几
+    const lastDayIndex = lastDay.getDay();
+    
+    // 上个月最后一天
+    const prevLastDay = new Date(this.currentYear, this.currentMonth, 0).getDate();
+    const today = new Date();
+    
+    // 添加上个月日期
+    for (let i = firstDayIndex; i > 0; i--) {
+      const day = prevLastDay - i + 1;
+      this.monthDays.push({
+        date: day,
+        isCurrentMonth: false,
+        isToday: false,
+        events: []
+      });
+    }
+    
+    // 添加当月日期
+    for (let i = 1; i <= lastDay.getDate(); i++) {
+      const dayDate = new Date(this.currentYear, this.currentMonth, i);
+      const isToday = dayDate.toDateString() === today.toDateString();
+      
+      // 获取当天的活动(根据筛选条件)
+      const dayEvents = this.events.filter(event => 
+        event.date.getDate() === i && 
+        event.date.getMonth() === this.currentMonth && 
+        event.date.getFullYear() === this.currentYear &&
+        (this.activeFilter === 'all' || event.type === this.activeFilter)
+      );
+      
+      this.monthDays.push({
+        date: i,
+        isCurrentMonth: true,
+        isToday: isToday,
+        events: dayEvents
+      });
+    }
+    
+    // 添加下个月日期
+    const daysNeeded = 42 - (firstDayIndex + lastDay.getDate()); // 42是6行7列的格子总数
+    for (let i = 1; i <= daysNeeded; i++) {
+      this.monthDays.push({
+        date: i,
+        isCurrentMonth: false,
+        isToday: false,
+        events: []
+      });
+    }
+  }
+
+  getEventsForDayAndHour(dayIndex: number, hour: number): Event[] {
+    const dayOfWeek = dayIndex; // 0-6对应周一到周日
+    const currentDate = new Date(this.currentYear, this.currentMonth, 1);
+    
+    // 计算当前月份第一天是星期几
+    const firstDayOfWeek = currentDate.getDay() === 0 ? 7 : currentDate.getDay();
+    
+    // 计算目标日期
+    const targetDate = new Date(
+      this.currentYear, 
+      this.currentMonth, 
+      1 + (dayOfWeek - firstDayOfWeek + 7) % 7
+    );
+    
+    // 过滤事件
+    return this.events.filter(event => {
+      const eventDate = event.date;
+      
+      // 检查日期是否匹配
+      const sameDate = 
+        eventDate.getDate() === targetDate.getDate() &&
+        eventDate.getMonth() === targetDate.getMonth() &&
+        eventDate.getFullYear() === targetDate.getFullYear();
+      
+      if (!sameDate) return false;
+      
+      // 检查时间是否匹配
+      if (event.time === '全天') return true;
+      
+      const [startTime] = event.time.split('-');
+      const eventHour = parseInt(startTime.split(':')[0]);
+      
+      return eventHour === hour;
+    });
+  }
+
+  changeMonth(offset: number) {
+    this.currentMonth += offset;
+    
+    if (this.currentMonth < 0) {
+      this.currentMonth = 11;
+      this.currentYear--;
+    } else if (this.currentMonth > 11) {
+      this.currentMonth = 0;
+      this.currentYear++;
+    }
+    
+    this.initializeEvents();
+    this.generateCalendar();
+    this.calculateStats();
+  }
+
+  goToToday() {
+    const today = new Date();
+    this.currentDate = today;
+    this.currentMonth = today.getMonth();
+    this.currentYear = today.getFullYear();
+    
+    this.initializeEvents();
+    this.generateCalendar();
+    this.calculateStats();
+  }
+
+  setFilter(filter: string) {
+    this.activeFilter = filter;
+    this.generateCalendar();
+    this.calculateStats();
+  }
+
+  calculateStats() {
+    const currentMonthEvents = this.events.filter(event => 
+      event.date.getMonth() === this.currentMonth && 
+      event.date.getFullYear() === this.currentYear
+    );
+    
+    this.stats = {
+      totalEvents: currentMonthEvents.length,
+      weddings: currentMonthEvents.filter(e => e.type === 'wedding').length,
+      banquets: currentMonthEvents.filter(e => e.type === 'banquet').length,
+      meetings: currentMonthEvents.filter(e => e.type === 'meeting').length
+    };
+  }
+}