瀏覽代碼

feat: enhance employee calendar with month navigation and improved styling

- Added buttons for navigating between months in the employee calendar, enhancing user interaction.
- Updated the calendar month header layout to use flexbox for better alignment and spacing.
- Improved button styles with hover and active effects for a more engaging user experience.
- Refactored routing for project details to ensure consistency across the application.
0235711 2 天之前
父節點
當前提交
67de6da356

+ 328 - 0
docs/feature/组长端设计师负载日历月份切换功能.md

@@ -0,0 +1,328 @@
+# 组长端设计师负载日历月份切换功能
+
+## 功能概述
+
+为组长端的设计师详情面板中的负载详细日历添加上月/下月切换按钮,允许组长查看设计师在不同月份的工作负载情况。
+
+## 实现日期
+
+2025年11月3日
+
+## 修改的文件
+
+### 1. `src/app/pages/team-leader/dashboard/dashboard.html`
+
+**修改位置**:第441-462行(日历月份标题部分)
+
+**修改内容**:
+- 在月份标题左侧添加"上月"按钮
+- 在月份标题右侧添加"下月"按钮
+- 使用SVG图标展示箭头
+- 绑定点击事件到 `changeEmployeeCalendarMonth()` 方法
+
+**代码片段**:
+```html
+<div class="calendar-month-header">
+  <button class="btn-prev-month" 
+          (click)="changeEmployeeCalendarMonth(-1)"
+          title="上月">
+    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+      <polyline points="15 18 9 12 15 6"></polyline>
+    </svg>
+  </button>
+  <span class="month-title">
+    {{ selectedEmployeeDetail.calendarData.currentMonth | date:'yyyy年M月' }}
+  </span>
+  <button class="btn-next-month" 
+          (click)="changeEmployeeCalendarMonth(1)"
+          title="下月">
+    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+      <polyline points="9 18 15 12 9 6"></polyline>
+    </svg>
+  </button>
+</div>
+```
+
+### 2. `src/app/pages/team-leader/dashboard/dashboard.ts`
+
+#### 修改1:添加员工日历相关数据属性(第207-209行)
+
+**目的**:保存当前员工信息和项目数据,用于月份切换时重新生成日历
+
+```typescript
+// 当前员工日历相关数据(用于切换月份)
+private currentEmployeeName: string = '';
+private currentEmployeeProjects: any[] = [];
+```
+
+#### 修改2:修改 `generateEmployeeDetail` 方法(第2694-2699行)
+
+**目的**:在生成员工详情时保存员工信息和项目数据
+
+```typescript
+// 保存当前员工信息和项目数据(用于切换月份)
+this.currentEmployeeName = employeeName;
+this.currentEmployeeProjects = employeeProjects;
+
+// 生成日历数据
+const calendarData = this.generateEmployeeCalendar(employeeName, employeeProjects);
+```
+
+#### 修改3:修改 `generateEmployeeCalendar` 方法签名(第2771行)
+
+**目的**:支持传入指定月份参数
+
+**修改前**:
+```typescript
+private generateEmployeeCalendar(employeeName: string, employeeProjects: any[]): EmployeeCalendarData {
+  const currentMonth = new Date();
+```
+
+**修改后**:
+```typescript
+private generateEmployeeCalendar(employeeName: string, employeeProjects: any[], targetMonth?: Date): EmployeeCalendarData {
+  const currentMonth = targetMonth || new Date();
+```
+
+#### 修改4:添加 `changeEmployeeCalendarMonth` 方法(第2920-2945行)
+
+**目的**:实现月份切换逻辑
+
+```typescript
+/**
+ * 切换员工日历月份
+ * @param direction -1=上月, 1=下月
+ */
+changeEmployeeCalendarMonth(direction: number): void {
+  if (!this.selectedEmployeeDetail?.calendarData) {
+    return;
+  }
+  
+  const currentMonth = this.selectedEmployeeDetail.calendarData.currentMonth;
+  const newMonth = new Date(currentMonth);
+  newMonth.setMonth(newMonth.getMonth() + direction);
+  
+  // 重新生成日历数据
+  const newCalendarData = this.generateEmployeeCalendar(
+    this.currentEmployeeName, 
+    this.currentEmployeeProjects, 
+    newMonth
+  );
+  
+  // 更新员工详情中的日历数据
+  this.selectedEmployeeDetail = {
+    ...this.selectedEmployeeDetail,
+    calendarData: newCalendarData
+  };
+}
+```
+
+### 3. `src/app/pages/team-leader/dashboard/dashboard-calendar.scss`
+
+**修改位置**:第9-60行(日历月份标题样式)
+
+**修改内容**:
+- 将 `calendar-month-header` 改为 flex 布局,支持左右布局
+- 为月份标题设置 flex: 1 居中显示
+- 添加 `.btn-prev-month` 和 `.btn-next-month` 按钮样式
+- 添加悬停效果:渐变背景、图标颜色变化、缩放动画
+- 添加点击效果:缩小动画
+
+**关键样式**:
+```scss
+.calendar-month-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  
+  .month-title {
+    flex: 1;
+    text-align: center;
+  }
+  
+  .btn-prev-month,
+  .btn-next-month {
+    background: transparent;
+    border: 1px solid #e2e8f0;
+    border-radius: 8px;
+    width: 32px;
+    height: 32px;
+    cursor: pointer;
+    transition: all 0.2s ease;
+    
+    &:hover {
+      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+      border-color: #667eea;
+      transform: scale(1.05);
+      
+      svg {
+        stroke: white;
+      }
+    }
+    
+    &:active {
+      transform: scale(0.95);
+    }
+  }
+}
+```
+
+## 功能特性
+
+### 1. 月份导航
+- ✅ 左侧按钮:切换到上一个月
+- ✅ 右侧按钮:切换到下一个月
+- ✅ 中间显示:当前月份(格式:yyyy年M月)
+
+### 2. 数据同步
+- ✅ 切换月份时自动重新生成该月的日历数据
+- ✅ 保留员工信息和项目数据,确保数据一致性
+- ✅ 正确计算每天的项目数量和项目列表
+
+### 3. 视觉效果
+- ✅ 按钮使用简洁的左右箭头图标
+- ✅ 悬停时按钮显示渐变紫色背景
+- ✅ 图标颜色从灰色变为白色
+- ✅ 缩放动画提供视觉反馈
+- ✅ 点击时有缩小效果,增强交互感
+
+### 4. 日历数据处理
+- ✅ 自动补齐月初和月末的日期(确保从周日开始)
+- ✅ 正确标记"今天"(相对于系统当前日期)
+- ✅ 区分当前月和其他月的日期(其他月半透明显示)
+- ✅ 计算每天的项目数量
+- ✅ 高负载标记(2个及以上项目)
+
+## 用户使用场景
+
+### 场景1:查看历史负载
+组长想要查看设计师上个月的工作负载情况:
+1. 点击某个设计师,打开详情面板
+2. 查看负载详细日历
+3. 点击左侧"上月"按钮
+4. 日历显示上个月的数据
+
+### 场景2:查看未来负载
+组长想要查看设计师下个月的工作安排:
+1. 在详情面板中查看日历
+2. 点击右侧"下月"按钮
+3. 日历显示下个月的数据
+4. 查看每天的项目安排
+
+### 场景3:跨月对比
+组长想要对比不同月份的负载情况:
+1. 查看当前月份
+2. 点击"上月"查看上月数据
+3. 点击"下月"返回当前月
+4. 继续点击"下月"查看下月数据
+
+## 技术亮点
+
+### 1. 灵活的参数设计
+`generateEmployeeCalendar` 方法使用可选的 `targetMonth` 参数:
+- 不传参数:默认生成当前月份
+- 传入日期:生成指定月份
+
+### 2. 数据缓存优化
+使用 `currentEmployeeName` 和 `currentEmployeeProjects` 缓存当前员工数据:
+- 避免重复查询数据库
+- 快速切换月份
+- 保持数据一致性
+
+### 3. 不可变数据更新
+使用对象展开运算符更新 `selectedEmployeeDetail`:
+```typescript
+this.selectedEmployeeDetail = {
+  ...this.selectedEmployeeDetail,
+  calendarData: newCalendarData
+};
+```
+- 符合 Angular 的变更检测机制
+- 确保UI正确更新
+
+### 4. 防御性编程
+在 `changeEmployeeCalendarMonth` 中进行空值检查:
+```typescript
+if (!this.selectedEmployeeDetail?.calendarData) {
+  return;
+}
+```
+- 避免空指针错误
+- 提高代码健壮性
+
+## 后续优化建议
+
+### 1. 快速跳转
+可以添加月份选择器,允许直接跳转到指定月份:
+```html
+<select (change)="jumpToMonth($event)">
+  <option>2024年10月</option>
+  <option selected>2024年11月</option>
+  <option>2024年12月</option>
+</select>
+```
+
+### 2. 年份切换
+当前只能切换月份,可以添加年份切换按钮:
+```html
+<button (click)="changeYear(-1)">上一年</button>
+<button (click)="changeYear(1)">下一年</button>
+```
+
+### 3. 键盘导航
+支持键盘快捷键:
+- 左箭头键:上月
+- 右箭头键:下月
+- Home键:回到当前月
+
+### 4. 加载状态
+切换月份时显示加载动画,提升用户体验:
+```typescript
+isLoadingCalendar: boolean = false;
+
+changeEmployeeCalendarMonth(direction: number): void {
+  this.isLoadingCalendar = true;
+  // ... 生成日历 ...
+  this.isLoadingCalendar = false;
+}
+```
+
+### 5. 数据预加载
+预加载前后一个月的数据,实现无缝切换:
+```typescript
+// 缓存前后3个月的日历数据
+private calendarCache: Map<string, EmployeeCalendarData> = new Map();
+```
+
+## 测试建议
+
+### 功能测试
+- [ ] 点击"上月"按钮,日历显示上个月
+- [ ] 点击"下月"按钮,日历显示下个月
+- [ ] 连续点击可以跨年切换(如:2024年12月 → 2025年1月)
+- [ ] 切换月份后项目数量和项目列表正确
+- [ ] "今天"标记在非当前月份时不显示
+
+### UI测试
+- [ ] 按钮悬停时显示紫色渐变背景
+- [ ] 按钮点击时有缩放动画
+- [ ] 月份标题居中显示
+- [ ] 按钮大小和图标大小适中
+- [ ] 在不同屏幕尺寸下布局正常
+
+### 边界测试
+- [ ] 未打开员工详情面板时点击按钮不报错
+- [ ] 员工没有项目时切换月份不报错
+- [ ] 从12月切换到1月,年份正确增加
+- [ ] 从1月切换到12月,年份正确减少
+
+## 总结
+
+此功能为组长端的设计师负载管理增加了重要的时间维度导航能力,使组长能够:
+- 📅 查看历史工作负载
+- 📈 预测未来工作安排
+- 📊 对比不同时期的负载情况
+- 🎯 更科学地进行任务分配
+
+通过简洁的UI设计和流畅的交互动画,提升了用户体验,使负载管理更加高效便捷。
+

+ 424 - 0
docs/fix/组长端项目路由修复.md

@@ -0,0 +1,424 @@
+# 组长端项目路由修复
+
+> **修复时间**:2025年11月2日  
+> **状态**:✅ 已完成
+
+---
+
+## 🎯 问题描述
+
+在**组长端项目大盘**中,点击项目卡片或"查看详情"按钮时,**无法正确跳转**到项目详情页。
+
+**原因**:使用了错误的路由格式。
+
+---
+
+## 🔍 问题分析
+
+### 错误的路由 ❌
+```typescript
+/team-leader/project-detail/:projectId
+```
+
+**问题**:
+- ❌ 这个路由在 `app.routes.ts` 中**不存在**
+- ❌ 没有企微认证保护
+- ❌ 没有公司 ID (cid) 参数
+- ❌ 导致 404 错误或跳转失败
+
+### 正确的路由 ✅
+```typescript
+/wxwork/:cid/project/:projectId
+```
+
+**优势**:
+- ✅ 在 `app.routes.ts` 中**已定义**
+- ✅ 包含企微认证保护 (`CustomWxworkAuthGuard`)
+- ✅ 支持多租户(通过 `cid` 区分公司)
+- ✅ 与设计师端、管理端路由一致
+
+---
+
+## 📝 修改内容
+
+### 修改的文件
+
+| 文件 | 修改位置 | 方法名 |
+|------|---------|--------|
+| `dashboard.ts` | 第 2535-2545 行 | `viewProjectDetails()` |
+| `dashboard.ts` | 第 2367-2372 行 | `selectProject()` |
+| `dashboard.ts` | 第 2575-2579 行 | `quickAssignProject()` |
+| `dashboard.ts` | 第 2622-2632 行 | `openWorkloadEstimator()` |
+| `team-management.ts` | 第 391-396 行 | `viewProjectDetails()` |
+| `workload-calendar.ts` | 第 217-223 行 | `navigateToProject()` |
+
+### 修改总数
+- ✅ **3 个文件**
+- ✅ **6 个方法**
+- ✅ **0 个 Linter 错误**
+
+---
+
+## 🔧 详细修改
+
+### 1. dashboard.ts - viewProjectDetails()
+
+**文件位置**:`src/app/pages/team-leader/dashboard/dashboard.ts`  
+**行号**:2535-2545
+
+**修改前** ❌
+```typescript
+viewProjectDetails(projectId: string): void {
+  if (!projectId) {
+    return;
+  }
+  
+  // 获取公司ID
+  const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
+  
+  // 跳转到组长端项目详情页(包含审批功能)
+  this.router.navigate(['/wxwork', cid, 'team-leader', 'project-detail', projectId]);
+}
+```
+
+**修改后** ✅
+```typescript
+viewProjectDetails(projectId: string): void {
+  if (!projectId) {
+    return;
+  }
+  
+  // 获取公司ID
+  const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
+  
+  // 跳转到企微认证项目详情页(正确路由)
+  this.router.navigate(['/wxwork', cid, 'project', projectId]);
+}
+```
+
+**影响范围**:
+- ✅ 项目大盘中的项目卡片点击
+- ✅ 项目列表中的查看详情按钮
+
+---
+
+### 2. dashboard.ts - selectProject()
+
+**文件位置**:`src/app/pages/team-leader/dashboard/dashboard.ts`  
+**行号**:2367-2372
+
+**修改前** ❌
+```typescript
+selectProject(): void {
+  if (this.selectedProjectId) {
+    this.router.navigate(['/team-leader/project-detail', this.selectedProjectId]);
+  }
+}
+```
+
+**修改后** ✅
+```typescript
+selectProject(): void {
+  if (this.selectedProjectId) {
+    const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
+    this.router.navigate(['/wxwork', cid, 'project', this.selectedProjectId]);
+  }
+}
+```
+
+**影响范围**:
+- ✅ 项目选择器中的项目选择
+
+---
+
+### 3. dashboard.ts - quickAssignProject()
+
+**文件位置**:`src/app/pages/team-leader/dashboard/dashboard.ts`  
+**行号**:2575-2579
+
+**修改前** ❌
+```typescript
+// 无推荐或用户取消,跳转到详细分配页面
+// 改为跳转到复用详情(组长视图),通过 query 参数标记 assign 模式
+this.router.navigate(['/team-leader/project-detail', projectId], { queryParams: { mode: 'assign' } });
+```
+
+**修改后** ✅
+```typescript
+// 无推荐或用户取消,跳转到详细分配页面
+// 跳转到项目详情页
+const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
+this.router.navigate(['/wxwork', cid, 'project', projectId]);
+```
+
+**影响范围**:
+- ✅ 快速分配项目功能
+- ✅ 智能推荐后的手动分配
+
+---
+
+### 4. dashboard.ts - openWorkloadEstimator()
+
+**文件位置**:`src/app/pages/team-leader/dashboard/dashboard.ts`  
+**行号**:2622-2632
+
+**修改前** ❌
+```typescript
+openWorkloadEstimator(): void {
+  // 工具迁移至详情页:引导前往当前选中项目详情
+  if (this.selectedProjectId) {
+    this.router.navigate(['/team-leader/project-detail', this.selectedProjectId], { queryParams: { tool: 'estimator' } });
+  } else {
+    this.router.navigate(['/team-leader/dashboard']);
+  }
+  window?.fmode?.alert('工作量预估工具已迁移至项目详情页...');
+}
+```
+
+**修改后** ✅
+```typescript
+openWorkloadEstimator(): void {
+  // 工具迁移至详情页:引导前往当前选中项目详情
+  const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
+  if (this.selectedProjectId) {
+    this.router.navigate(['/wxwork', cid, 'project', this.selectedProjectId]);
+  } else {
+    this.router.navigate(['/wxwork', cid, 'team-leader']);
+  }
+  window?.fmode?.alert('工作量预估工具已迁移至项目详情页...');
+}
+```
+
+**影响范围**:
+- ✅ 工作量预估工具的跳转
+
+---
+
+### 5. team-management.ts - viewProjectDetails()
+
+**文件位置**:`src/app/pages/team-leader/team-management/team-management.ts`  
+**行号**:391-396
+
+**修改前** ❌
+```typescript
+viewProjectDetails(projectId: string): void {
+  // 改为复用设计师项目详情(组长上下文),具备审核/同步权限
+  this.router.navigate(['/team-leader/project-detail', projectId]);
+}
+```
+
+**修改后** ✅
+```typescript
+viewProjectDetails(projectId: string): void {
+  // 跳转到企微认证项目详情页(正确路由)
+  const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
+  this.router.navigate(['/wxwork', cid, 'project', projectId]);
+}
+```
+
+**影响范围**:
+- ✅ 团队管理页面中的项目详情查看
+
+---
+
+### 6. workload-calendar.ts - navigateToProject()
+
+**文件位置**:`src/app/pages/team-leader/workload-calendar/workload-calendar.ts`  
+**行号**:217-223
+
+**修改前** ❌
+```typescript
+navigateToProject(t: Task, ev?: Event): void {
+  if (ev) { ev.stopPropagation(); ev.preventDefault?.(); }
+  if (!t || !t.projectId) return;
+  // 复用设计师端项目详情页面(通过 URL 上下文赋予组长审核权限)
+  this.router.navigate(['/team-leader/project-detail', t.projectId]);
+}
+```
+
+**修改后** ✅
+```typescript
+navigateToProject(t: Task, ev?: Event): void {
+  if (ev) { ev.stopPropagation(); ev.preventDefault?.(); }
+  if (!t || !t.projectId) return;
+  // 跳转到企微认证项目详情页(正确路由)
+  const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
+  this.router.navigate(['/wxwork', cid, 'project', t.projectId]);
+}
+```
+
+**影响范围**:
+- ✅ 负载日历中的项目跳转
+
+---
+
+## 📊 修改总结
+
+### 核心改动
+所有方法都进行了相同的修改:
+
+**从** ❌
+```typescript
+this.router.navigate(['/team-leader/project-detail', projectId]);
+```
+
+**改为** ✅
+```typescript
+const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
+this.router.navigate(['/wxwork', cid, 'project', projectId]);
+```
+
+### 关键点
+1. ✅ 添加 `cid` 参数(从 localStorage 获取)
+2. ✅ 使用正确的路由路径:`/wxwork/:cid/project/:projectId`
+3. ✅ 移除错误的路由片段:`team-leader/project-detail`
+
+---
+
+## 🎯 影响的功能
+
+### 组长端 Dashboard
+- ✅ 项目大盘中的项目卡片点击
+- ✅ 项目列表查看详情按钮
+- ✅ 项目选择器的项目选择
+- ✅ 快速分配项目功能
+- ✅ 智能推荐后的手动分配
+- ✅ 工作量预估工具跳转
+
+### 团队管理页面
+- ✅ 项目详情查看
+
+### 负载日历页面
+- ✅ 任务/项目跳转
+
+---
+
+## 🧪 测试清单
+
+### 测试步骤
+
+1️⃣ **项目大盘测试**
+   - [ ] 访问组长端 Dashboard
+   - [ ] 点击任意项目卡片
+   - [ ] 确认跳转到项目详情页(不是 404)
+   - [ ] 验证 URL 格式为:`/wxwork/:cid/project/:projectId`
+
+2️⃣ **项目列表测试**
+   - [ ] 在项目列表中点击"查看详情"
+   - [ ] 确认正确跳转
+
+3️⃣ **快速分配测试**
+   - [ ] 点击"手动分配"按钮
+   - [ ] 确认跳转到项目详情页
+
+4️⃣ **团队管理测试**
+   - [ ] 访问团队管理页面
+   - [ ] 点击项目详情链接
+   - [ ] 确认正确跳转
+
+5️⃣ **负载日历测试**
+   - [ ] 访问负载日历页面
+   - [ ] 点击任务/项目
+   - [ ] 确认正确跳转
+
+### 预期结果 ✅
+
+所有跳转都应该:
+- ✅ 成功跳转到项目详情页
+- ✅ URL 格式正确:`http://localhost:4200/wxwork/cDL6R1hgSi/project/:projectId`
+- ✅ 页面正常显示项目信息
+- ✅ 无 404 或路由错误
+- ✅ 包含企微认证保护
+
+---
+
+## 🔄 路由对比
+
+### 错误路由 ❌
+```
+/team-leader/project-detail/B2xcbHfFR8
+```
+**问题**:
+- ❌ 路由不存在
+- ❌ 无企微认证
+- ❌ 无公司 ID
+- ❌ 404 错误
+
+### 正确路由 ✅
+```
+/wxwork/cDL6R1hgSi/project/B2xcbHfFR8
+```
+**优势**:
+- ✅ 路由已定义在 `app.routes.ts`
+- ✅ 有企微认证保护
+- ✅ 包含公司 ID(多租户)
+- ✅ 与设计师端一致
+
+---
+
+## 🎨 路由架构
+
+### 当前正确的路由结构
+```
+/wxwork/:cid
+  ├─ activation          (身份激活)
+  ├─ survey/profile      (员工问卷)
+  ├─ survey/project/:id  (项目问卷)
+  ├─ designer            (设计师工作台)
+  ├─ team-leader         (组长工作台) ✅
+  ├─ project/:id         (项目详情) ✅ 统一入口
+  │   ├─ order           (订单分配)
+  │   ├─ design          (方案设计)
+  │   ├─ modeling        (建模渲染)
+  │   └─ delivery        (交付验收)
+  └─ contact/:id         (客户联系人)
+```
+
+### 关键特性
+- ✅ **统一入口**:所有角色(组长、设计师、客户)访问同一项目详情路由
+- ✅ **权限控制**:通过企微认证判断用户角色和权限
+- ✅ **多租户**:通过 `cid` 参数区分不同公司
+- ✅ **子路由**:项目详情包含 4 个阶段子路由
+
+---
+
+## 📱 用户体验提升
+
+### 修复前 ❌
+```
+组长点击项目 → 404 错误 → 无法查看详情
+```
+
+### 修复后 ✅
+```
+组长点击项目 → 正确跳转 → 查看项目详情 → 可以审批/操作
+```
+
+---
+
+## 🎉 总结
+
+### 已完成的工作 ✅
+- ✅ 修复了 **6 个方法**中的路由错误
+- ✅ 涉及 **3 个文件**(dashboard、team-management、workload-calendar)
+- ✅ 所有跳转现在使用**正确的企微认证路由**
+- ✅ 支持**多租户**(通过 cid 参数)
+- ✅ **无 Linter 错误**
+
+### 影响范围 📊
+- ✅ 组长端 Dashboard(项目大盘、快速分配、工作量预估等)
+- ✅ 团队管理页面
+- ✅ 负载日历页面
+- ✅ 所有涉及项目详情跳转的功能
+
+### 预期效果 🚀
+- ✅ 组长可以**正常查看**项目详情
+- ✅ 项目跳转**不再 404**
+- ✅ 路由格式**统一规范**
+- ✅ 支持**企微认证**和**权限控制**
+
+---
+
+**修复完成!** ✅ 现在组长端所有项目跳转都使用正确的路由格式。
+
+

+ 41 - 1
src/app/pages/team-leader/dashboard/dashboard-calendar.scss

@@ -7,7 +7,9 @@
     padding: 20px;
     
     .calendar-month-header {
-      text-align: center;
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
       margin-bottom: 16px;
       padding-bottom: 12px;
       border-bottom: 2px solid #e2e8f0;
@@ -16,6 +18,44 @@
         font-size: 16px;
         font-weight: 600;
         color: #1e293b;
+        flex: 1;
+        text-align: center;
+      }
+      
+      .btn-prev-month,
+      .btn-next-month {
+        background: transparent;
+        border: 1px solid #e2e8f0;
+        border-radius: 8px;
+        width: 32px;
+        height: 32px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        cursor: pointer;
+        transition: all 0.2s ease;
+        padding: 0;
+        
+        svg {
+          width: 18px;
+          height: 18px;
+          stroke: #64748b;
+          transition: stroke 0.2s ease;
+        }
+        
+        &:hover {
+          background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+          border-color: #667eea;
+          transform: scale(1.05);
+          
+          svg {
+            stroke: white;
+          }
+        }
+        
+        &:active {
+          transform: scale(0.95);
+        }
       }
     }
     

+ 14 - 0
src/app/pages/team-leader/dashboard/dashboard.html

@@ -442,9 +442,23 @@
             <div class="employee-calendar">
               <!-- 月份标题 -->
               <div class="calendar-month-header">
+                <button class="btn-prev-month" 
+                        (click)="changeEmployeeCalendarMonth(-1)"
+                        title="上月">
+                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                    <polyline points="15 18 9 12 15 6"></polyline>
+                  </svg>
+                </button>
                 <span class="month-title">
                   {{ selectedEmployeeDetail.calendarData.currentMonth | date:'yyyy年M月' }}
                 </span>
+                <button class="btn-next-month" 
+                        (click)="changeEmployeeCalendarMonth(1)"
+                        title="下月">
+                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+                    <polyline points="9 18 15 12 9 6"></polyline>
+                  </svg>
+                </button>
               </div>
               
               <!-- 星期标题 -->

+ 48 - 10
src/app/pages/team-leader/dashboard/dashboard.ts

@@ -204,6 +204,10 @@ export class Dashboard implements OnInit, OnDestroy {
   selectedDayProjects: Array<{ id: string; name: string; deadline?: Date }> = [];
   selectedDate: Date | null = null;
   
+  // 当前员工日历相关数据(用于切换月份)
+  private currentEmployeeName: string = '';
+  private currentEmployeeProjects: any[] = [];
+  
   // 员工请假数据(模拟数据)
   private leaveRecords: LeaveRecord[] = [
     { id: '1', employeeName: '张三', date: '2024-01-20', isLeave: true, leaveType: 'personal', reason: '事假' },
@@ -2366,7 +2370,8 @@ export class Dashboard implements OnInit, OnDestroy {
   // 选择单个项目
   selectProject(): void {
     if (this.selectedProjectId) {
-      this.router.navigate(['/team-leader/project-detail', this.selectedProjectId]);
+      const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
+      this.router.navigate(['/wxwork', cid, 'project', this.selectedProjectId]);
     }
   }
 
@@ -2540,8 +2545,8 @@ export class Dashboard implements OnInit, OnDestroy {
     // 获取公司ID
     const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
     
-    // 跳转到组长端项目详情页(包含审批功能
-    this.router.navigate(['/wxwork', cid, 'team-leader', 'project-detail', projectId]);
+    // 跳转到企微认证项目详情页(正确路由
+    this.router.navigate(['/wxwork', cid, 'project', projectId]);
   }
 
   // 快速分配项目(增强:加入智能推荐)
@@ -2572,8 +2577,9 @@ export class Dashboard implements OnInit, OnDestroy {
       }
     }
     // 无推荐或用户取消,跳转到详细分配页面
-    // 改为跳转到复用详情(组长视图),通过 query 参数标记 assign 模式
-    this.router.navigate(['/team-leader/project-detail', projectId], { queryParams: { mode: 'assign' } });
+    // 跳转到项目详情页
+    const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
+    this.router.navigate(['/wxwork', cid, 'project', projectId]);
     }
 
   // 导航到待办任务
@@ -2620,10 +2626,11 @@ export class Dashboard implements OnInit, OnDestroy {
   // 打开工作量预估工具(已迁移)
   openWorkloadEstimator(): void {
     // 工具迁移至详情页:引导前往当前选中项目详情
+    const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
     if (this.selectedProjectId) {
-      this.router.navigate(['/team-leader/project-detail', this.selectedProjectId], { queryParams: { tool: 'estimator' } });
+      this.router.navigate(['/wxwork', cid, 'project', this.selectedProjectId]);
     } else {
-      this.router.navigate(['/team-leader/dashboard']);
+      this.router.navigate(['/wxwork', cid, 'team-leader']);
     }
    window?.fmode?.alert('工作量预估工具已迁移至项目详情页,您可以在建模阶段之前使用该工具进行工作量计算。');
   }
@@ -2684,6 +2691,10 @@ export class Dashboard implements OnInit, OnDestroy {
     // 生成红色标记说明
     const redMarkExplanation = this.generateRedMarkExplanation(employeeName, employeeLeaveRecords, currentProjects);
     
+    // 保存当前员工信息和项目数据(用于切换月份)
+    this.currentEmployeeName = employeeName;
+    this.currentEmployeeProjects = employeeProjects;
+    
     // 生成日历数据
     const calendarData = this.generateEmployeeCalendar(employeeName, employeeProjects);
     
@@ -2763,10 +2774,10 @@ export class Dashboard implements OnInit, OnDestroy {
   }
   
   /**
-   * 生成员工日历数据(当前月份)
+   * 生成员工日历数据(支持指定月份)
    */
-  private generateEmployeeCalendar(employeeName: string, employeeProjects: any[]): EmployeeCalendarData {
-    const currentMonth = new Date();
+  private generateEmployeeCalendar(employeeName: string, employeeProjects: any[], targetMonth?: Date): EmployeeCalendarData {
+    const currentMonth = targetMonth || new Date();
     const year = currentMonth.getFullYear();
     const month = currentMonth.getMonth();
     
@@ -2906,6 +2917,33 @@ export class Dashboard implements OnInit, OnDestroy {
     this.showCalendarProjectList = true;
   }
   
+  /**
+   * 切换员工日历月份
+   * @param direction -1=上月, 1=下月
+   */
+  changeEmployeeCalendarMonth(direction: number): void {
+    if (!this.selectedEmployeeDetail?.calendarData) {
+      return;
+    }
+    
+    const currentMonth = this.selectedEmployeeDetail.calendarData.currentMonth;
+    const newMonth = new Date(currentMonth);
+    newMonth.setMonth(newMonth.getMonth() + direction);
+    
+    // 重新生成日历数据
+    const newCalendarData = this.generateEmployeeCalendar(
+      this.currentEmployeeName, 
+      this.currentEmployeeProjects, 
+      newMonth
+    );
+    
+    // 更新员工详情中的日历数据
+    this.selectedEmployeeDetail = {
+      ...this.selectedEmployeeDetail,
+      calendarData: newCalendarData
+    };
+  }
+  
   /**
    * 关闭项目列表弹窗
    */

+ 3 - 2
src/app/pages/team-leader/team-management/team-management.ts

@@ -390,8 +390,9 @@ export class TeamManagementComponent implements OnInit {
 
   // 查看项目详情
   viewProjectDetails(projectId: string): void {
-    // 改为复用设计师项目详情(组长上下文),具备审核/同步权限
-    this.router.navigate(['/team-leader/project-detail', projectId]);
+    // 跳转到企微认证项目详情页(正确路由)
+    const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
+    this.router.navigate(['/wxwork', cid, 'project', projectId]);
   }
 
   // 调整任务优先级

+ 3 - 2
src/app/pages/team-leader/workload-calendar/workload-calendar.ts

@@ -217,8 +217,9 @@ export class WorkloadCalendarComponent implements OnInit, OnDestroy {
   navigateToProject(t: Task, ev?: Event): void {
     if (ev) { ev.stopPropagation(); ev.preventDefault?.(); }
     if (!t || !t.projectId) return;
-    // 复用设计师端项目详情页面(通过 URL 上下文赋予组长审核权限)
-    this.router.navigate(['/team-leader/project-detail', t.projectId]);
+    // 跳转到企微认证项目详情页(正确路由)
+    const cid = localStorage.getItem('company') || 'cDL6R1hgSi';
+    this.router.navigate(['/wxwork', cid, 'project', t.projectId]);
   }
 
   // 新增:按设计师快速筛选(保持当前日期与视图)