<template>
<div class="attendance-statistics">
<div class="calendar-container">
<div class="calendar-header">
<a-button type="primary" @click="handleAdd()">新增</a-button>
<div class="calendar-nav">
<button @click="prevMonth">〈</button>
<span>{{ currentDate.format('YYYY-MM') }}</span>
<button @click="nextMonth">〉</button>
</div>
</div>
<div class="calendar-table">
<!-- 星期标题行 -->
<div class="week-header" style="height: 40px">
<div v-for="(day, index) in weekDays" :key="index" class="week-day">
{{ day }}
</div>
</div>
<!-- 日期网格 -->
<div class="date-grid">
<div v-for="(date, index) in datesInMonth" :key="index" class="date-cell" :class="{
'today': isToday(date),
'other-month': !isSameMonth(date)
}">
<!-- 日期显示 -->
<div class="date-display">
<div>{{ date.date() }}</div>
<div style="color: #878C9A;">{{ chineseDays[parseInt(moment(date).lunar().format('DD'), 10) - 1] }}</div>
</div>
<!-- 班次信息 -->
<div class="shift-info">
<div v-for="(shift, shiftIndex) in getShiftsForDate(date)" :key="shiftIndex" class="shift-item"
:class="getShiftClass(shift.type)">
<div class="shift-time">{{ shift.startTime }}</div>
<div class="shift-name">{{ shift.name }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import moment from 'moment'
import 'moment-lunar';
export default {
name: 'shiftConfiguration',
components: { },
data() {
return {
url: {
list: '/clockSchedule/scheduleList',
// exportXlsUrl: '/clock/exportList',
},
currentDate: moment(),
weekDays: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
chineseDays: ['初一', '初二', '初三', '初四', '初五', '初六',
'初七', '初八', '初九', '初十', '十一', '十二',
'十三', '十四', '十五', '十六', '十七', '十八',
'十九', '二十', '廿一', '廿二', '廿三', '廿四',
'廿五', '廿六', '廿七', '廿八', '廿九', '三十'],
shifts: [
{ date: '2025-6-5', time: '早班08:00-14:59', name: '章三,里斯', type: 'normal' },
{ date: '2025-6-1', time: '中班08:00-14:59', name: '章三', type: 'normal' },
{ date: '2024-11-30', time: '晚班08:00-14:59', name: '章三', type: 'normal' },
],
}
},
mounted() {
// this.getList()
},
computed: {
datesInMonth() {
const startOfMonth = this.currentDate.clone().startOf('month');
const endOfMonth = this.currentDate.clone().endOf('month');
const dates = [];
let current = startOfMonth.clone();
// 添加前一个月的几天(为了显示完整的星期)
while (current.day() !== 0) {
current.subtract(1, 'day');
}
// 添加整个月份的日期
while (current <= endOfMonth) {
dates.push(current.clone());
current.add(1, 'day');
}
return dates;
}
},
methods: {
moment,
prevMonth() {
this.currentDate = this.currentDate.clone().subtract(1, 'month');
},
nextMonth() {
this.currentDate = this.currentDate.clone().add(1, 'month');
},
isToday(date) {
return date.isSame(moment(), 'day');
},
isSameMonth(date) {
return date.isSame(this.currentDate, 'month');
},
getShiftsForDate(date) {
return this.shifts.filter(shift =>
moment(shift.scheduleDate).isSame(date, 'day')
);
},
getShiftClass(type) {
const classes = {
正常: 'shift-normal',
异常: 'shift-abnormal',
缺卡: 'shift-missing',
未来: 'shift-future'
};
return classes[type] || '';
},
// 获取班次列表
getList() {
getAction(this.url.list).then((res) => {
if (res.success) {
this.shifts = res.data
} else {
this.$message.error(res.message)
}
})
},
openClassConfigModal() {
this.$refs.classConfigModal.add()
this.$refs.classConfigModal.title = '班别配置'
this.$refs.classConfigModal.disableSubmit = false
},
openCheckMethodModal(record) {
this.$refs.checkMethodModal.add()
this.$refs.checkMethodModal.title = '打卡方式'
this.$refs.checkMethodModal.disableSubmit = false
},
},
}
</script>
<style lang="less" scoped>
.attendance-statistics {
height: calc(100% - 60px - 116px);
background: #ffffff;
box-shadow: 0px 3px 6px 1px rgba(51, 97, 250, 0.1);
border-radius: 8px;
padding: 14px;
flex: 1;
overflow: hidden;
overflow-y: auto;
.calendar-container {
.calendar-header {
margin-bottom: 16px;
display: flex;
.calendar-nav {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.calendar-nav button {
background: none;
border: none;
font-size: 16px;
cursor: pointer;
}
}
.calendar-table {
border: 1px solid #EFF0F2;
border-radius: 4px;
overflow: hidden;
.week-header {
display: grid;
grid-template-columns: repeat(7, 1fr);
background: #F2F5FF;
border-bottom: 1px solid #EFF0F2;
font-weight: 500;
font-size: 14px;
color: #212633;
font-family: @fontMedium;
.week-day {
padding: 10px;
text-align: center;
font-weight: bold;
border-right: 1px solid #EFF0F2;
}
.week-day:last-child {
border-right: none;
}
}
}
}
.date-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
.date-cell {
padding: 8px 12px;
border-right: 1px solid #EFF0F2;
border-bottom: 1px solid #EFF0F2;
min-height: 132px;
}
.date-cell.other-month {
background-color: #fafafa;
color: #ccc;
}
.date-cell.today .date-display {
color: #1890ff;
font-weight: bold;
}
.date-display {
margin-bottom: 6px;
display: flex;
align-items: center;
justify-content: space-between;
font-weight: 500;
font-size: 14px;
color: #212633;
}
}
.shift-info {
margin-bottom: 8px;
}
.shift-item {
padding: 4px;
margin-bottom: 4px;
border-radius: 4px;
font-size: 12px;
}
.shift-normal {
background-color: #c0d2fd;
}
.shift-abnormal {
background-color: #fae7b3;
}
.shift-missing {
background-color: #f8bebe;
}
.shift-future {
background-color: #e4e5e9;
}
.shift-time {
font-size: 11px;
color: #666;
}
.shift-name {
font-weight: bold;
}
}
</style>