Files
maintenance_system/src/views/integratedManage/attendManage/components/rightBox/calendar.vue
re-JZzzz 07c5dcde11 1.新增排班时间管理页面及其对接接口
2.对接排班人员列表接口
3.修改部分样式
2025-09-22 20:47:13 +08:00

336 lines
8.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="box">
<div class="chart-header">
<TitleComponent title="日历" :font-level="2" />
</div>
<div class="calendar-container">
<div class="calendar-header">
<el-button size="small" type="text" @click="prevMonth">
<el-icon><ArrowLeft /></el-icon>
</el-button>
<span class="current-month">{{ currentYear }} {{ currentMonthName }}</span>
<el-button size="small" type="text" @click="nextMonth">
<el-icon><ArrowRight /></el-icon>
</el-button>
</div>
<div class="calendar-weekdays">
<span v-for="day in weekdays" :key="day" class="weekday">{{ day }}</span>
</div>
<div class="calendar-days">
<!-- 上月剩余天数 -->
<div v-for="(day, index) in prevMonthDays" :key="'prev-' + index" class="day prev-month-day">
{{ day }}
</div>
<!-- 当月天数 -->
<div
v-for="day in currentMonthDays"
:key="day"
class="day current-month-day"
:class="{
'current-day': isCurrentDay(day),
'selected-day': isSelectedDay(day)
}"
@click="selectDay(day)"
>
{{ day }}
<!-- 今天有红点标记 -->
<span v-if="isToday(day)" class="today-marker"></span>
<!-- 考勤状态标记 -->
<span v-if="getAttendanceStatus(day)" class="attendance-marker" :class="getAttendanceStatus(day)"></span>
</div>
<!-- 下月开始天数 -->
<div v-for="(day, index) in nextMonthDays" :key="'next-' + index" class="day next-month-day">
{{ day }}
</div>
</div>
</div>
</div>
</template>
<script setup>
import TitleComponent from '@/components/TitleComponent/index.vue';
import { ArrowLeft, ArrowRight } from '@element-plus/icons-vue';
import { ref, computed } from 'vue';
import { ElMessage } from 'element-plus';
// 接收从父组件传入的数据
const props = defineProps({
calendarData: {
type: Object,
default: () => ({
// 初始化当前日期
today: new Date(),
currentDate: new Date(2025, 8, 27), // 2025年9月27日截图中显示的日期
selectedDate: new Date(2025, 8, 27),
// 模拟考勤数据
attendanceData: {
2025: {
9: {
1: 'normal',
4: 'late',
8: 'absent',
10: 'leave',
15: 'normal',
20: 'normal',
25: 'late',
27: 'normal'
}
}
}
})
}
});
// 初始化当前日期
const today = ref(props.calendarData.today);
const currentDate = ref(props.calendarData.currentDate);
const selectedDate = ref(props.calendarData.selectedDate);
// 模拟考勤数据
const attendanceData = ref(props.calendarData.attendanceData);
// 星期几的显示
const weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
// 计算属性
const currentYear = computed(() => currentDate.value.getFullYear());
const currentMonth = computed(() => currentDate.value.getMonth());
const currentMonthName = computed(() => monthNames[currentMonth.value]);
// 获取当月的天数
const currentMonthDays = computed(() => {
return new Date(currentYear.value, currentMonth.value + 1, 0).getDate();
});
// 获取当月第一天是星期几0-60是星期日
const firstDayOfMonth = computed(() => {
return new Date(currentYear.value, currentMonth.value, 1).getDay();
});
// 获取上月剩余天数
const prevMonthDays = computed(() => {
const days = [];
const prevMonth = new Date(currentYear.value, currentMonth.value, 0).getDate(); // 上月最后一天
for (let i = firstDayOfMonth.value - 1; i >= 0; i--) {
days.push(prevMonth - i);
}
return days;
});
// 获取下月开始天数
const nextMonthDays = computed(() => {
const days = [];
const totalDays = prevMonthDays.value.length + currentMonthDays.value;
const nextDays = 35 - totalDays; // 显示5周共35天
for (let i = 1; i <= nextDays; i++) {
days.push(i);
}
return days;
});
// 方法
const prevMonth = () => {
currentDate.value = new Date(currentYear.value, currentMonth.value - 1, 1);
};
const nextMonth = () => {
currentDate.value = new Date(currentYear.value, currentMonth.value + 1, 1);
};
const selectDay = (day) => {
selectedDate.value = new Date(currentYear.value, currentMonth.value, day);
// 显示选择的日期和考勤状态
let message = `Selected: ${currentMonthName.value} ${day}, ${currentYear.value}`;
const status = getAttendanceStatus(day);
if (status) {
const statusMap = {
normal: '正常',
late: '迟到',
absent: '缺勤',
leave: '请假'
};
message += ` - 考勤状态: ${statusMap[status] || '未知'}`;
}
ElMessage.success(message);
};
// 获取考勤状态
const getAttendanceStatus = (day) => {
if (attendanceData.value[currentYear.value] &&
attendanceData.value[currentYear.value][currentMonth.value + 1] &&
attendanceData.value[currentYear.value][currentMonth.value + 1][day]) {
return attendanceData.value[currentYear.value][currentMonth.value + 1][day];
}
return null;
};
const isToday = (day) => {
return day === today.value.getDate() &&
currentMonth.value === today.value.getMonth() &&
currentYear.value === today.value.getFullYear();
};
const isCurrentDay = (day) => {
return day === today.value.getDate() &&
currentMonth.value === today.value.getMonth() &&
currentYear.value === today.value.getFullYear();
};
const isSelectedDay = (day) => {
return day === selectedDate.value.getDate() &&
currentMonth.value === selectedDate.value.getMonth() &&
currentYear.value === selectedDate.value.getFullYear();
};
</script>
<style scoped lang="scss">
.chart-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.chart-header h3 {
margin: 0;
font-size: 16px;
font-weight: 500;
color: #333;
}
.chart-header span {
color: #186DF5;
font-size: 14px;
cursor: pointer;
}
.calendar-container {
background: white;
border-radius: 8px;
padding: 16px;
// border: 1px solid #F2F3F5;
}
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding: 8px 0;
}
.current-month {
font-size: 16px;
font-weight: 500;
color: #333;
}
.calendar-weekdays {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 8px;
margin-bottom: 8px;
}
.weekday {
text-align: center;
font-size: 14px;
color: #666;
font-weight: 500;
padding: 8px 0;
}
.calendar-days {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 8px;
height: 350px;
}
.day {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 40px;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
}
.prev-month-day,
.next-month-day {
color: #C0C4CC;
}
.current-month-day {
color: #333;
}
.current-month-day:hover {
background-color: #ECF5FF;
color: #186DF5;
}
.current-day {
position: relative;
}
.today-marker {
position: absolute;
bottom: 4px;
width: 4px;
height: 4px;
border-radius: 50%;
background-color: #FF6B3B;
}
.selected-day {
background-color: #186DF5;
color: white !important;
font-weight: 500;
}
.selected-day:hover {
background-color: #4096ff;
color: white !important;
}
// 考勤状态标记样式
.attendance-marker {
position: absolute;
bottom: 2px;
width: 6px;
height: 6px;
border-radius: 50%;
}
.attendance-marker.normal {
background-color: #52c41a;
}
.attendance-marker.late {
background-color: #faad14;
}
.attendance-marker.absent {
background-color: #f5222d;
}
.attendance-marker.leave {
background-color: #1890ff;
}
</style>