前言
基于vue2+java的日历组件(后端需要引用hutool工具集),可以后台自定义放假日跟调休日
效果图
前端
vue页面代码
<template>
<!-- 源码地址 https://github.com/yj-liuzepeng/zp-calendar -->
<div id="calendar">
<!-- 年份 月份 -->
<div class="months">
<div class="year-month">{{ currentYear }}年{{ currentMonth }}月</div>
<div class="toggle-month">
<span class="lt" @click="preMonth()"><</span>
<span class="ct" @click="initData()">今天</span>
<span class="rt" @click="nextMonth()">></span>
</div>
</div>
<!-- 星期 -->
<ul class="weekdays">
<li v-for="item in (fromsun ? weekDaysFromSun : weekDays)" :key="item">{{ item }}</li>
</ul>
<!-- 日期 -->
<ul class="days">
<li v-for="(dayobject,i) in days" :key="i" @click="getClickDay(dayobject)">
<div
ref="cday"
class="cday"
:class="{
'other-month': dayobject.cmonth!= currentMonth,
'active': curDayMsg.date == dayobject.date
}"
>
<span>{{ dayobject.cday }}</span>
<span v-if="dayobject.isArder" class="isArder">休</span>
<span v-if="dayobject.isWork" class="isWork">班</span>
</div>
<!-- 优先展示节日,其次,如果农历初一,展示当前农历月份,否则展示农历日期 -->
<div
v-if="showlunar"
class="idaycn"
>
{{
dayobject.lunarFestival
? dayobject.lunarFestival
: dayobject.festival
? dayobject.festival
: dayobject.idayCn === "初一"
? dayobject.imonthCn
: dayobject.idayCn
}}
</div>
<slot></slot>
</li>
</ul>
</div>
</template>
<script>
import {getCalendar, getCalendarByDate} from "@/api/project/festival";
import {formatDate} from "@/utils/dateUtils";
export default {
name: 'Calendar',
props: {
showlunar: {
type: Boolean,
default: false,
},
lines: {
type: Number,
default: 5,
},
fromsun: {
type: Boolean,
default: true,
},
},
data() {
return {
currentDay: 1,
currentMonth: 1,
currentYear: 2023,
currentWeek: 1,
days: [], //当月日期集合
curDayMsg: [], //当天日历信息
weekDays: ['一', '二', '三', '四', '五', '六', '日'],
weekDaysFromSun: ['日', '一', '二', '三', '四', '五', '六'],
}
},
created() {
this.initData()
},
methods: {
// 初始化
initData(cur) {
this.days = []
//是否有指定时间
if (cur) {
this.currentYear = new Date(cur).getFullYear()
this.currentMonth = new Date(cur).getMonth() + 1
} else {
this.currentYear = new Date().getFullYear()
this.currentMonth = new Date().getMonth() + 1
}
let params = {
year: this.currentYear,
month: this.currentMonth
}
getCalendar(params).then(res => {
this.days = res.data
})
if (!cur) {
let date = formatDate(new Date(), "yyyy-MM-dd")
getCalendarByDate(date).then(res => {
this.curDayMsg = res.data
})
}
},
// 上一月
preMonth() {
this.currentMonth--
if (this.currentMonth === 0) {
this.currentMonth = 12
this.currentYear--
}
this.initData(this.formatDate(this.currentYear, this.currentMonth, 1))
},
// 下一月
nextMonth() {
this.currentMonth++
if (this.currentMonth === 13) {
this.currentMonth = 1
this.currentYear++
}
this.initData(this.formatDate(this.currentYear, this.currentMonth, 1))
},
// 点击日期
getClickDay(el) {
this.curDayMsg = el
this.$emit('dayMsg', this.curDayMsg)
},
// 格式化 -> 2020-11-20
formatDate(year, month, day) {
if (month < 10) month = '0' + month
if (day < 10) day = '0' + day
return year + '-' + month + '-' + day
},
},
}
</script>
<style>
ul li {
padding: 0;
margin: 0;
list-style-type: none;
}
#calendar {
width: 100%;
height: 100%;
margin: 0 auto;
overflow: hidden;
font-size: 0.75rem;
border: 1px solid #edeeee;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.1),
0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
.months {
display: flex;
justify-content: space-around;
margin-top: 3%;
margin-bottom: 3%;
}
.months .year-month {
margin-left: -10%;
font-size: 0.875rem;
}
.months .toggle-month {
width: 23%;
margin-right: -10%;
text-align: center;
cursor: pointer;
border: 1px solid #edeeee;
}
.months .toggle-month .lt,
.months .toggle-month .rt {
display: inline-block;
width: 24%;
color: #bebdbe;
text-align: center;
}
.months .toggle-month .ct {
display: inline-block;
width: 48%;
color: #000;
text-align: center;
border-right: 1px solid #edeeee;
border-left: 1px solid #edeeee;
}
.weekdays {
display: flex;
justify-content: space-around;
padding: 0;
color: #999;
}
.weekdays li {
display: inline-block;
width: 13.6%;
text-align: center;
}
.days {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
padding: 1% 0;
margin: 0;
}
.days li {
display: inline-block;
width: 14.2%;
padding-top: 2%;
padding-bottom: 5%;
color: #000;
text-align: center;
cursor: pointer;
}
.vishidden {
visibility: hidden;
}
.days li .active {
display: inline-block;
width: 1.5625rem;
height: 1.5625rem;
line-height: 1.5625rem;
text-align: center;
color: #fff;
background: #5cc18d !important;
border-radius: 50%;
}
.days li .other-month {
color: gainsboro;
}
.days li .cday {
display: inline-block;
width: 1.5625rem;
height: 1.5625rem;
line-height: 1.5625rem;
text-align: center;
position: relative;
}
.isWork {
position: absolute;
top: -6px;
left: 24px;
color: red;
font-size: 11px;
}
.isArder {
position: absolute;
top: -6px;
left: 24px;
color: #19ce19;
font-size: 11px;
}
.days li:hover .cday {
color: #fff;
background: #e1e1e1;
border-radius: 50%;
}
.recday {
display: inline-block;
width: 1.5625rem;
height: 1.5625rem;
line-height: 1.5625rem;
text-align: center;
color: #fff;
background: #e1e1e1;
border-radius: 50%;
}
.idaycn {
margin-top: 10%;
color: #999;
}
</style>
/**
* 格式化函数 , 给日期格式化
* date为 new Date()对象, fmt为 'yyyy-MM-dd hh:mm:ss'的格式
*/
export function formatDate(date, fmt) {
//获取年份
if (/(y+)/.test(fmt)) {
// 把数字变成字符串
let dateY = date.getFullYear() + "";
//RegExp.$1 在判断中出现过,且是括号括起来的,所以 RegExp.$1 就是 "yyyy"
fmt = fmt.replace(RegExp.$1, dateY.substr(4 - RegExp.$1.length));
}
//获取其他
let o = {
"M+": date.getMonth() + 1,
"d+": date.getDate(),
"h+": date.getHours(),
"m+": date.getMinutes(),
"s+": date.getSeconds(),
};
for (const k in o) {
if (new RegExp(`(${k})`).test(fmt)) {
let str = o[k] + "";
fmt = fmt.replace(
RegExp.$1,
RegExp.$1.length === 1 ? str : padLeftZero(str)
);
}
}
return fmt;
}
function padLeftZero(str) {
return ("00" + str).substr(str.length);
}
后端代码
业务代码
public QuickDFResponse getCalendar(String year, String month) {
ArrayList<Calendar> calendarList = new ArrayList<>();
//获取阳历指定月的集合
String curMonthStartDay = year + "-" + month + "-01"; //指定月份的第一天
Date curMonthStartDayDate = DateUtil.parse(curMonthStartDay, "yyyy-MM-dd");
int curMonthStartWeek = DateUtil.dayOfWeek(curMonthStartDayDate); //当前月第一天是周几 周天是1 周是2
Date curPageStartDay = DateUtil.offsetDay(curMonthStartDayDate, -curMonthStartWeek + 1);//日历当前页开始日期
//循环日历当月时间
for (int i = 0; i < lines * 7; i++) {
DateTime dateTime = DateUtil.offsetDay(curPageStartDay, i);
String dateStr = dateTime.toDateStr();
Calendar calendar = getCalendarByDate(dateStr);
calendarList.add(calendar);
}
return new QuickDFResponse().success().data(calendarList);
}
public Calendar getCalendarByDate(String date) {
Calendar calendar = new Calendar();
DateTime dateTime = DateUtil.parse(date);
String calendarDate = DateUtil.formatDate(dateTime); //阳历时间
ChineseDate chineseDate = new ChineseDate(dateTime); //农历时间
String festival = CalendarUtils.getFestival(dateTime); //阳历节日
String lfestival = CalendarUtils.getLfestival(chineseDate.toStringNormal()); //农历节日
String lDate = chineseDate.toStringNormal();//农历日期 数字写法
int lYear = chineseDate.getChineseYear(); //农历年 数字写法
int lMonth = chineseDate.getMonth(); //农历月 数字写法
int lDay = chineseDate.getDay();//农历日 数字写法
String chineseZodiac = DateUtil.getChineseZodiac(dateTime.year());//生肖
String IMonthCn = chineseDate.getChineseMonthName();//农历月 汉字写法
String IDayCn = chineseDate.getChineseDay();//农历日 汉字写法
int cYear = dateTime.year(); //阳历年
int cMonth = dateTime.monthStartFromOne(); //阳历月
int cDay = dateTime.dayOfMonth(); //阳历日
String gzDate = CalendarUtils.getGanzhiOfDate(cYear, cMonth, cDay); //日期的天干地支
String gzYear = CalendarUtils.getGanzhiOfYear(cYear); //年的天干地支
String gzMonth = CalendarUtils.getGanzhiOfMonth(cYear, cMonth, cDay);//月份的天干地支
String gzDay = CalendarUtils.getGanzhiOfDay(cYear, cMonth, cDay); //日的天干地支
boolean isToday = DateUtil.isSameDay(dateTime, new Date()); //判断是否是今天
boolean leapYear = DateUtil.isLeapYear(cYear); //是否闰年 阳历
boolean isLeap = chineseDate.isLeapMonth(); //是否闰月 阴历
int nWeek = CalendarUtils.nWeek(dateTime); //星期几 数字写法 1表示周一 7表示周天
String ncWeek = CalendarUtils.ncWeek(dateTime); //星期几 中文写法
String term = chineseDate.getTerm(); //节气
boolean isTerm = StringUtils.isNotEmpty(term); //是否是节气
String astro = DateUtil.getZodiac(dateTime.month(), cDay); //星座
calendar.setDate(calendarDate);
calendar.setLunarDate(chineseDate.toString());
calendar.setFestival(festival);
calendar.setLunarFestival(lfestival);
calendar.setLDate(lDate);
calendar.setLYear(lYear);
calendar.setLMonth(lMonth);
calendar.setLDay(lDay);
calendar.setAnimal(chineseZodiac);
calendar.setIMonthCn(IMonthCn);
calendar.setIDayCn(IDayCn);
calendar.setCYear(cYear);
calendar.setCMonth(cMonth);
calendar.setCDay(cDay);
calendar.setGzDate(gzDate);
calendar.setGzYear(gzYear);
calendar.setGzMonth(gzMonth);
calendar.setGzDay(gzDay);
calendar.setIsToday(isToday);
calendar.setIsLeapYear(leapYear);
calendar.setIsLeap(isLeap);
calendar.setNWeek(nWeek);
calendar.setNcWeek(ncWeek);
calendar.setIsTerm(isTerm);
calendar.setTerm(term);
calendar.setAstro(astro);
//是否休班 自定义维护
calendar.setIsArder(false);
calendar.setIsWork(true);
return calendar;
}
日历信息实体类
import lombok.Data;
@Data
public class Calendar {
/**
* 阳历日期
*/
private String Date;
/**
* 农历日期
*/
private String lunarDate;
/**
* 阳历节日
*/
private String festival;
/**
* 农历节日
*/
private String lunarFestival;
/**
* 农历日期 数字写法
*/
private String lDate;
/**
* 农历年 数字写法
*/
private int lYear;
/**
* 农历月 数字写法
*/
private int lMonth;
/**
* 农历日 数字写法
*/
private int lDay;
/**
* 生肖年份
*/
private String Animal;
/**
* 农历月 汉字写法
*/
private String IMonthCn;
/**
* 农历日 汉字写法
*/
private String IDayCn;
/**
* 阳历年
*/
private int cYear;
/**
* 阳历月
*/
private int cMonth;
/**
* 阳历日
*/
private int cDay;
/**
* 天干地支日期
*/
private String gzDate;
/**
* 年的天干地支
*/
private String gzYear;
/**
* 月的天干地支
*/
private String gzMonth;
/**
* 日的天干地支
*/
private String gzDay;
/**
* 是否今天
*/
private Boolean isToday;
/**
* 是否闰年 阳历
*/
private Boolean isLeapYear;
/**
* 是否闰月 农历
*/
private Boolean isLeap;
/**
* 星期几 数字
*/
private int nWeek;
/**
* 星期几 中文
*/
private String ncWeek;
/**
* 是否是跟节气有关
*/
private Boolean isTerm;
/**
* 节气
*/
private String Term;
/**
* 星座
*/
private String astro;
/**
* 是否休假
*/
private Boolean isArder;
/**
* 是否加班
*/
private Boolean isWork;
}
CalendarUtils工具
public class CalendarUtils {
/**
* 十天干:甲(jiǎ)、乙(yǐ)、丙(bǐng)、丁(dīng)、戊(wù)、己(jǐ)、庚(gēng)、辛(xīn)、壬(rén)、癸(guǐ)
* 十二地支:子(zǐ)、丑(chǒu)、寅(yín)、卯(mǎo)、辰(chén)、巳(sì)、午(wǔ)、未(wèi)、申(shēn)、酉(yǒu)、戌(xū)、亥(hài)
* 十二地支对应十二生肖:子-鼠,丑-牛,寅-虎,卯-兔,辰-龙,巳-蛇, 午-马,未-羊,申-猴,酉-鸡,戌-狗,亥-猪
*
* @see <a href="https://baike.baidu.com/item/%E5%A4%A9%E5%B9%B2%E5%9C%B0%E6%94%AF/278140">天干地支:简称,干支</a>
*/
private static final String[] GAN = new String[]{"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"};
private static final String[] ZHI = new String[]{"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"};
private static final TableMap<Pair<Integer, Integer>, String> L_FTV = new TableMap<>(16);
//自定义农历节日
static {
// 节日
L_FTV.put(new Pair<>(1, 1), "春节");
L_FTV.put(new Pair<>(1, 15), "元宵节");
// 二月
L_FTV.put(new Pair<>(2, 2), "龙抬头");
// 五月
L_FTV.put(new Pair<>(5, 5), "端午节");
// 六月
L_FTV.put(new Pair<>(6, 24), "彝族火把节");
// 七月
L_FTV.put(new Pair<>(7, 7), "七夕");
L_FTV.put(new Pair<>(7, 15), "中元节");
// 八月
L_FTV.put(new Pair<>(8, 15), "中秋节");
// 九月
L_FTV.put(new Pair<>(9, 9), "重阳节");
// 腊月
L_FTV.put(new Pair<>(12, 8), "腊八节");
L_FTV.put(new Pair<>(12, 23), "小年");
L_FTV.put(new Pair<>(12, 30), "除夕");
/*
` L_FTV.put(new Pair<>(1, 2), "犬日");
L_FTV.put(new Pair<>(1, 3), "猪日");
L_FTV.put(new Pair<>(1, 4), "羊日");
L_FTV.put(new Pair<>(1, 5), "牛日 破五日");
L_FTV.put(new Pair<>(1, 6), "马日 送穷日");
L_FTV.put(new Pair<>(1, 7), "人日 人胜节");
L_FTV.put(new Pair<>(1, 8), "谷日 八仙日");
L_FTV.put(new Pair<>(1, 9), "天日 九皇会");
L_FTV.put(new Pair<>(1, 10), "地日 石头生日");
L_FTV.put(new Pair<>(1, 12), "火日 老鼠娶媳妇日");
L_FTV.put(new Pair<>(1, 13), "上(试)灯日 关公升天日");
L_FTV.put(new Pair<>(1, 18), "落灯日");
// 二月
L_FTV.put(new Pair<>(2, 1), "中和节 太阳生日");
L_FTV.put(new Pair<>(2, 12), "花朝节");
L_FTV.put(new Pair<>(2, 19), "观世音圣诞");
// 三月
L_FTV.put(new Pair<>(3, 3), "上巳节");
// 四月
L_FTV.put(new Pair<>(4, 1), "祭雹神");
L_FTV.put(new Pair<>(4, 4), "文殊菩萨诞辰");
L_FTV.put(new Pair<>(4, 8), "佛诞节");
// 六月
L_FTV.put(new Pair<>(6, 6), "晒衣节 姑姑节");
L_FTV.put(new Pair<>(6, 6), "天贶节");
// 七月
L_FTV.put(new Pair<>(7, 14), "鬼节(南方)");
L_FTV.put(new Pair<>(7, 15), "盂兰盆节 中元节");
L_FTV.put(new Pair<>(7, 30), "地藏节");
// 十月
L_FTV.put(new Pair<>(10, 1), "祭祖节");
L_FTV.put(new Pair<>(10, 15), "下元节");
// 十一月
L_FTV.put(new Pair<>(11, 17), "阿弥陀佛圣诞");
// 腊月
L_FTV.put(new Pair<>(12, 16), "尾牙");
*/
}
/**
* 判断指定日期是否是阳历节日
*
* @param date
* @return
*/
public static String getFestival(DateTime date) {
String festival = "";
//获取指定日期的月份
int month = date.monthStartFromOne();
//获取指定日期的dd部分
int day = date.dayOfMonth();
String festivalDate = month + "-" + day;
switch (festivalDate) {
case "1-1":
festival = "元旦节";
break;
case "2-14":
festival = "情人节";
break;
case "3-8":
festival = "妇女节";
break;
case "3-12":
festival = "植树节";
break;
case "4-1":
festival = "愚人节";
break;
case "5-1":
festival = "劳动节";
break;
case "5-4":
festival = "青年节";
break;
case "5-12":
festival = "护士节";
break;
case "6-1":
festival = "儿童节";
break;
case "7-1":
festival = "建党节";
break;
case "8-1":
festival = "建军节";
break;
case "9-10":
festival = "教师节";
break;
case "10-1":
festival = "国庆节";
break;
case "12-24":
festival = "平安夜";
break;
case "12-25":
festival = "圣诞节";
break;
default:
festival = "";
}
return festival;
}
/**
* 获取农历节日
*
* @param dateTime
* @return
*/
public static String getLfestival(String dateTime) {
String lfestival = "";
DateTime chineseDate = DateUtil.parse(dateTime);
int year = chineseDate.year();
int month = chineseDate.monthStartFromOne();
int day = chineseDate.dayOfMonth();
List<String> festivalList = getFestivals(year, month, day);
lfestival = StrUtil.join(",", festivalList);
return lfestival;
}
/**
* 获得节日列表
*
* @param year 年
* @param month 月
* @param day 日
* @return 获得农历节日
* @since 5.4.5
*/
public static List<String> getFestivals(int year, int month, int day) {
// 春节判断,如果12月是小月,则29为除夕,否则30为除夕
if (12 == month && 29 == day) {
if (29 == LunarInfo.monthDays(year, month)) {
day++;
}
}
return getFestivals(month, day);
}
/**
* 获得节日列表,此方法无法判断月是否为大月或小月
*
* @param month 月
* @param day 日
* @return 获得农历节日
*/
public static List<String> getFestivals(int month, int day) {
return L_FTV.getValues(new Pair<>(month, day));
}
/**
* 这里同步处理年月日的天干地支信息
*
* @param year 公历年
* @param month 公历月,从1开始
* @param day 公历日
* @return 天干地支信息
*/
public static String getGanzhiOfDate(int year, int month, int day) {
return StrUtil.format("{}年{}月{}日",
GanZhi.getGanzhiOfYear(year),
GanZhi.getGanzhiOfMonth(year, month, day),
GanZhi.getGanzhiOfDay(year, month, day));
}
/**
* 传入年传回干支
*
* @param year 农历年
* @return 干支
* @since 5.4.7
*/
public static String getGanzhiOfYear(int year) {
// 1864年(1900 - 36)是甲子年,用于计算基准的干支年
return cyclicalm(year - LunarInfo.BASE_YEAR + 36);
}
/**
* 获取干支月
*
* @param year 公历年
* @param month 公历月,从1开始
* @param day 公历日
* @return 干支月
*/
public static String getGanzhiOfMonth(int year, int month, int day) {
//返回当月「节」为几日开始
int firstNode = SolarTerms.getTerm(year, (month * 2 - 1));
// 依据12节气修正干支月
int monthOffset = (year - LunarInfo.BASE_YEAR) * 12 + month + 11;
if (day >= firstNode) {
monthOffset++;
}
return cyclicalm(monthOffset);
}
/**
* 获取干支日
*
* @param year 公历年
* @param month 公历月,从1开始
* @param day 公历日
* @return 干支
* @since 5.4.7
*/
public static String getGanzhiOfDay(int year, int month, int day) {
// 与1970-01-01相差天数,不包括当天
final long days = LocalDate.of(year, month, day).toEpochDay() - 1;
//1899-12-21是农历1899年腊月甲子日 41:相差1900-01-31有41天
return cyclicalm((int) (days - LunarInfo.BASE_DAY + 41));
}
/**
* 传入 月日的offset 传回干支, 0=甲子
*
* @param num 月日的offset
* @return 干支
*/
public static String cyclicalm(int num) {
return (GAN[num % 10] + ZHI[num % 12]);
}
/**
* 获取指定日期是星期几 数字表达 星期一是1 星期日是 7
*
* @param dateTime
* @return
*/
public static int nWeek(DateTime dateTime) {
int nWeek = 1;
int i = dateTime.dayOfWeek();
switch (i) {
case 1:
nWeek = 7;
break;
case 2:
nWeek = 1;
break;
case 3:
nWeek = 2;
break;
case 4:
nWeek = 3;
break;
case 5:
nWeek = 4;
break;
case 6:
nWeek = 5;
break;
case 7:
nWeek = 6;
break;
default:
nWeek = 0;
}
return nWeek;
}
/**
* 获取指定日期是星期几 中文表达
*
* @param dateTime
* @return
*/
public static String ncWeek(DateTime dateTime) {
String ncWeek = "";
int i = dateTime.dayOfWeek();
switch (i) {
case 1:
ncWeek = "星期日";
break;
case 2:
ncWeek = "星期一";
break;
case 3:
ncWeek = "星期二";
break;
case 4:
ncWeek = "星期三";
break;
case 5:
ncWeek = "星期四";
break;
case 6:
ncWeek = "星期五";
break;
case 7:
ncWeek = "星期六";
break;
default:
ncWeek = "";
}
return ncWeek;
}
}