# 管理后台首页日历Skill ## 适用场景 需要在管理后台首页展示日历视图,用于: - 工作日志录入情况概览 - 考勤打卡情况展示 - 日程安排查看 ## 功能特性 - 按月份展示日历 - 日期状态标识(已录入/未录入) - 管理员可选择人员查看 - 点击日期查看详情 ## 实现方案 ### 后端接口 ```java // LogController.java @GetMapping("/calendar") public Result> getCalendarData( @RequestParam Integer year, @RequestParam Integer month, @RequestParam(required = false) String userId) { return Result.success(logService.getLogDatesByMonth(year, month, userId)); } // LogService.java List getLogDatesByMonth(Integer year, Integer month, String userId); ``` ### 前端实现 #### 1. 日历组件结构 ```vue ``` #### 2. 核心逻辑 ```typescript import { ref, computed, onMounted, watch } from 'vue' import { useUserStore } from '@/store/user' import { getCalendarData, getLogByDate } from '@/api/log' import { listEnabledUsers } from '@/api/user' const userStore = useUserStore() const isAdmin = computed(() => userStore.isAdmin()) const today = new Date() const currentYear = ref(today.getFullYear()) const currentMonth = ref(today.getMonth() + 1) const calendarDate = ref(today) const logDates = ref>(new Set()) const userList = ref([]) const selectedUserId = ref('') // 加载日历数据 async function loadCalendarData() { const dates = await getCalendarData(currentYear.value, currentMonth.value, selectedUserId.value || undefined) logDates.value = new Set(dates) } // 月份切换 function prevMonth() { if (currentMonth.value === 1) { currentYear.value-- currentMonth.value = 12 } else { currentMonth.value-- } updateCalendarDate() loadCalendarData() } function nextMonth() { if (currentMonth.value === 12) { currentYear.value++ currentMonth.value = 1 } else { currentMonth.value++ } updateCalendarDate() loadCalendarData() } // 判断日期样式 function getDayClass(dateStr: string): string { if (!isCurrentMonth(dateStr)) return 'other-month' if (logDates.value.has(dateStr)) return 'has-log' return 'no-log' } // 监听日历组件月份变化 watch(calendarDate, (newDate) => { const year = newDate.getFullYear() const month = newDate.getMonth() + 1 if (year !== currentYear.value || month !== currentMonth.value) { currentYear.value = year currentMonth.value = month loadCalendarData() } }) ``` #### 3. 样式规范 ```css /* 日期样式 - 已记录显示蓝色 */ .has-log .day-number, .has-log .log-indicator { color: #409eff; font-weight: 500; } /* 日期样式 - 未记录显示红色 */ .no-log .day-number, .no-log .log-indicator { color: #f56c6c; } /* 非当月日期 */ .other-month .day-number { color: #c0c4cc; } .other-month .log-indicator { display: none; } /* 日历格子 */ .calendar-day { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; border-radius: 4px; } .calendar-day:hover { background-color: #f5f7fa; } ``` ## API接口定义 ### 获取日历数据 ```typescript // api/log.ts export function getCalendarData(year: number, month: number, userId?: string): Promise { const params: Record = { year, month } if (userId) params.userId = userId return request.get('/log/calendar', { params }) } ``` ### 获取日志详情 ```typescript export function getLogByDate(date: string, userId?: string): Promise { const params: Record = { date } if (userId) params.userId = userId return request.get('/log/byDate', { params }) } ``` ## 管理员权限扩展 ### 后端扩展 ```java // UserService.java List listEnabledUsers(); // UserServiceImpl.java @Override public List listEnabledUsers() { return userMapper.selectList( new LambdaQueryWrapper() .eq(User::getStatus, 1) .orderByAsc(User::getCreatedTime) ); } // LogService.java List getLogDatesByMonth(Integer year, Integer month, String userId); // LogServiceImpl.java @Override public List getLogDatesByMonth(Integer year, Integer month, String userId) { String targetUserId = StringUtils.hasText(userId) ? userId : getCurrentUserId(); // 查询该用户当月的日志日期列表 return logMapper.selectDatesByMonth(year, month, targetUserId); } ``` ### 前端权限判断 ```typescript import { useUserStore } from '@/store/user' const userStore = useUserStore() const isAdmin = computed(() => userStore.isAdmin()) ``` ## 状态颜色规范 | 状态 | 颜色 | 说明 | |------|------|------| | 已记录 | #409eff (蓝色) | 当月日期有日志记录 | | 未记录 | #f56c6c (红色) | 当月日期无日志记录 | | 非当月 | #c0c4cc (灰色) | 不属于当前显示月份 | ## 注意事项 1. **日期格式**:统一使用 `YYYY-MM-DD` 格式 2. **时区处理**:注意前后端时区一致性 3. **权限控制**:非管理员只能查看自己的日志 4. **性能优化**:日历数据按月加载,避免一次性请求过多