239 lines
6.2 KiB
Vue
239 lines
6.2 KiB
Vue
|
|
<template>
|
|||
|
|
<!-- 外层容器:占用 30% 宽度,可根据需要自行调样式 -->
|
|||
|
|
<div class="mini-calendar" style="">
|
|||
|
|
<!-- 日历头部,显示“YYYY年M月” -->
|
|||
|
|
<div class="calendar-header">
|
|||
|
|
<div>个人日历</div>
|
|||
|
|
<div>{{ currentMonthYear }}</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- 日历主体:使用 table 简易排版,每周 7 列,只显示当前月的日期 -->
|
|||
|
|
<table class="calendar-body">
|
|||
|
|
<thead>
|
|||
|
|
<tr>
|
|||
|
|
<th v-for="(day, index) in weekDays" :key="index">{{ day }}</th>
|
|||
|
|
</tr>
|
|||
|
|
</thead>
|
|||
|
|
<tbody>
|
|||
|
|
<tr v-for="(row, rowIndex) in calendarRows" :key="rowIndex">
|
|||
|
|
<td
|
|||
|
|
v-for="(cell, cellIndex) in row"
|
|||
|
|
:key="cellIndex"
|
|||
|
|
:class="getDayClass(cell.type)"
|
|||
|
|
>
|
|||
|
|
<!-- 只显示数字,不含任何额外文本 -->
|
|||
|
|
<span>{{ cell.dayNum }}</span>
|
|||
|
|
</td>
|
|||
|
|
</tr>
|
|||
|
|
</tbody>
|
|||
|
|
</table>
|
|||
|
|
|
|||
|
|
<!-- legend 区域:展示不同 type 的色块与说明 -->
|
|||
|
|
<div class="calendar-legend">
|
|||
|
|
<div class="legend-item" v-for="legend in legends" :key="legend.type">
|
|||
|
|
<span
|
|||
|
|
class="color-box"
|
|||
|
|
:style="{ backgroundColor: legend.color }"
|
|||
|
|
></span>
|
|||
|
|
<span class="legend-text">{{ legend.label }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
export default {
|
|||
|
|
name: "MiniCalendar",
|
|||
|
|
/**
|
|||
|
|
* 父组件可以通过 :daysData 传入当前月的具体日期和 type。
|
|||
|
|
* 示例:[{ date: '2025-03-01', type: 1 }, { date: '2025-03-02', type: 2 }, ...]
|
|||
|
|
*/
|
|||
|
|
props: {
|
|||
|
|
daysData: {
|
|||
|
|
type: Array,
|
|||
|
|
default: () => []
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
// 星期栏
|
|||
|
|
weekDays: ["日", "一", "二", "三", "四", "五", "六"],
|
|||
|
|
// legend 配置:type对应的背景色 + 说明
|
|||
|
|
legends: [
|
|||
|
|
{ type: 1, label: "休息日", color: "#d3f6f3" },
|
|||
|
|
{ type: 2, label: "节假日", color: "#ffe7ba" },
|
|||
|
|
{ type: 3, label: "调休", color: "#ffdede" },
|
|||
|
|
{ type: 4, label: "出差", color: "#fa18bc" },
|
|||
|
|
{ type: 5, label: "请假", color: "#c4c4eb" }
|
|||
|
|
]
|
|||
|
|
};
|
|||
|
|
},
|
|||
|
|
computed: {
|
|||
|
|
/**
|
|||
|
|
* 当前日期对象(默认为今天,也可自行改成其它月份)
|
|||
|
|
*/
|
|||
|
|
currentDate() {
|
|||
|
|
return new Date();
|
|||
|
|
},
|
|||
|
|
currentMonth() {
|
|||
|
|
return this.currentDate.getMonth(); // 0-11
|
|||
|
|
},
|
|||
|
|
currentYear() {
|
|||
|
|
return this.currentDate.getFullYear();
|
|||
|
|
},
|
|||
|
|
// 用于在日历头部显示“YYYY年M月”
|
|||
|
|
currentMonthYear() {
|
|||
|
|
return `${this.currentYear}年${this.currentMonth + 1}月`;
|
|||
|
|
},
|
|||
|
|
/**
|
|||
|
|
* 生成一个二维数组,每一行代表一周,单元格中有 { dayNum, dateStr, type }。
|
|||
|
|
* 只显示当月的日期,如果第一天不是周日,前面会插入空格。
|
|||
|
|
*/
|
|||
|
|
calendarRows() {
|
|||
|
|
// 当前月1号
|
|||
|
|
const firstDayOfMonth = new Date(this.currentYear, this.currentMonth, 1);
|
|||
|
|
const firstDayIndex = firstDayOfMonth.getDay(); // 0=周日,1=周一, ...
|
|||
|
|
|
|||
|
|
// 本月总天数
|
|||
|
|
const daysInMonth = new Date(this.currentYear, this.currentMonth + 1, 0).getDate();
|
|||
|
|
|
|||
|
|
// 准备一个空数组,往里放 dayNum 和 type
|
|||
|
|
const cells = [];
|
|||
|
|
// 1) 填充本月第一天前面的空白单元格
|
|||
|
|
for (let i = 0; i < firstDayIndex; i++) {
|
|||
|
|
cells.push({ dayNum: "", dateStr: "", type: null });
|
|||
|
|
}
|
|||
|
|
// 2) 填充本月每一天
|
|||
|
|
for (let day = 1; day <= daysInMonth; day++) {
|
|||
|
|
const dateObj = new Date(this.currentYear, this.currentMonth, day);
|
|||
|
|
const dateStr = this.formatDate(dateObj); // YYYY-MM-DD
|
|||
|
|
// 根据 daysData 查找 type
|
|||
|
|
const dayType = this.findDayType(dateStr);
|
|||
|
|
cells.push({
|
|||
|
|
dayNum: day,
|
|||
|
|
dateStr,
|
|||
|
|
type: dayType
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3) 将 cells 拆分成多行,每行7列
|
|||
|
|
const rows = [];
|
|||
|
|
for (let i = 0; i < cells.length; i += 7) {
|
|||
|
|
rows.push(cells.slice(i, i + 7));
|
|||
|
|
}
|
|||
|
|
return rows;
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
methods: {
|
|||
|
|
/**
|
|||
|
|
* 格式化 Date => "YYYY-MM-DD"
|
|||
|
|
*/
|
|||
|
|
formatDate(d) {
|
|||
|
|
const year = d.getFullYear();
|
|||
|
|
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|||
|
|
const day = String(d.getDate()).padStart(2, "0");
|
|||
|
|
return `${year}-${month}-${day}`;
|
|||
|
|
},
|
|||
|
|
/**
|
|||
|
|
* 在 daysData 中找对应日期的 type,找不到就默认为 0(工作日)
|
|||
|
|
*/
|
|||
|
|
findDayType(dateStr) {
|
|||
|
|
const item = this.daysData.find((day) => day.date === dateStr);
|
|||
|
|
return item ? item.type : 0; // 默认工作日(0)
|
|||
|
|
},
|
|||
|
|
/**
|
|||
|
|
* 返回一个 class 用于设置对应背景色
|
|||
|
|
*/
|
|||
|
|
getDayClass(type) {
|
|||
|
|
switch (type) {
|
|||
|
|
case 0: return "type-workday"; // 工作日
|
|||
|
|
case 1: return "type-rest"; // 休息日
|
|||
|
|
case 2: return "type-holiday"; // 节假日
|
|||
|
|
case 3: return "type-adjust"; // 调休
|
|||
|
|
case 4: return "type-trip"; // 出差
|
|||
|
|
case 5: return "type-leave"; // 请假
|
|||
|
|
default: return "";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
.mini-calendar {
|
|||
|
|
border: 1px solid #ccc;
|
|||
|
|
padding: 10px;
|
|||
|
|
background-color: white;
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
/* 若需要更细节的布局控制,可以加上 float 或 display 属性,比如 float: left; */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 日历头部 */
|
|||
|
|
.calendar-header {
|
|||
|
|
text-align: center;
|
|||
|
|
font-size: 16px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
margin-bottom: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 日历主体样式 */
|
|||
|
|
.calendar-body {
|
|||
|
|
width: 100%;
|
|||
|
|
border-collapse: collapse;
|
|||
|
|
margin-bottom: 8px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.calendar-body th,
|
|||
|
|
.calendar-body td {
|
|||
|
|
width: 14.28%; /* 7天 */
|
|||
|
|
height: 40px;
|
|||
|
|
text-align: center;
|
|||
|
|
vertical-align: middle;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 不同 type 的背景色 */
|
|||
|
|
.type-workday {
|
|||
|
|
background-color: transparent;
|
|||
|
|
}
|
|||
|
|
.type-rest {
|
|||
|
|
background-color: #d3f6f3;
|
|||
|
|
}
|
|||
|
|
.type-holiday {
|
|||
|
|
background-color: #ffe7ba;
|
|||
|
|
}
|
|||
|
|
.type-adjust {
|
|||
|
|
background-color: #ffdede;
|
|||
|
|
}
|
|||
|
|
.type-trip {
|
|||
|
|
background-color: #c6ebf5;
|
|||
|
|
}
|
|||
|
|
.type-leave {
|
|||
|
|
background-color: #c4c4eb;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* legend 部分:展示各类型色块和说明 */
|
|||
|
|
.calendar-legend {
|
|||
|
|
margin-top: 12px;
|
|||
|
|
display: flex;
|
|||
|
|
flex-wrap: wrap;
|
|||
|
|
gap: 10px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.legend-item {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.color-box {
|
|||
|
|
display: inline-block;
|
|||
|
|
width: 14px;
|
|||
|
|
height: 14px;
|
|||
|
|
margin-right: 4px;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.legend-text {
|
|||
|
|
font-size: 12px;
|
|||
|
|
}
|
|||
|
|
</style>
|