1、实现简单维护日程事件,以及显示农历,显示节假日,一切简单实现功能,没有做的很完美。开发效果图如下:
2、Fullcalendar6.1.15得资料地址
- 查阅一些CSDN等资料,都是早期版本,一些API都已经不一样了,使用了最新6.1.15
- 官网地址Demos | FullCalendar
- GitHub - fullcalendar/fullcalendar: Full-sized drag & drop event calendar in JavaScript
- Vue3参考地址GitHub - fullcalendar/fullcalendar-vue: The official Vue 3 component for FullCalendar
- 建议看官网就可以,有问题直接debugger找Api
3、前端使用Vue3,Vben2.8,Antd3+,WindCss
- 引入:
pnpm install @fullcalendar/vue3 @fullcalendar/core @fullcalendar/daygrid - 引入农历,
pnpm install js-calendar-converter; 资料地址js-calendar-converter - npm (npmjs.com) - 长话短说,短话不说,直接看代码
<template>
<div id="fullCalendar222">
<div class="dotGroup">
<span>
<i class="dayDot"></i>
值班
</span>
<span>
<i class="shareDot"></i>
休息
</span>
</div>
<div class="btnAdd">
<span>{{ oneDateDetail }}</span>
<a-button
type="primary"
class="addSch"
:disabled="addEventBtn"
@click="openModal(true, { startDate: selectedStartDate, endDate: selectedEndDate })"
>新建日程</a-button
>
</div>
<FullCalendar ref="fullCalendarRef" :options="calendarOptions" class="demo-app-calendar" />
<AddEventModal
@register="registerModal"
@success="handleAddSuccess"
@updates="handlerUpdateSuccess"
@deletes="handlerDeleteSuccess"
/></div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue';
import FullCalendar from '@fullcalendar/vue3';
import dayGridPlugin from '@fullcalendar/daygrid';
import timeGridPlugin from '@fullcalendar/timegrid';
import interactionPlugin from '@fullcalendar/interaction';
import zhCnLocale from '@fullcalendar/core/locales/zh-cn';
import { getBaseWorkDutyListApi, getBaseWorkDutyOneApi } from '/@/api/workDuty';
import dayjs from 'dayjs';
import { useModal } from '/@/components/Modal';
import AddEventModal from './components/addEventModal.vue';
import calendar from 'js-calendar-converter';
const [registerModal, { openModal }] = useModal();
const selectedStartDate = ref('');
const selectedEndDate = ref('');
const addEventBtn = ref(true);
let fullCalendarRef = ref<any>({});
let calendarEvents = <any>[];
const oneDateDetail = ref('');
//下个月,上个月渲染
async function getCalendarEvents(info, successCallback, failureCallback) {
const { data } = await getBaseWorkDutyListApi({
startDateFrom: dayjs(info.start).format('YYYY-MM-DD'),
startDateTo: dayjs(info.end).format('YYYY-MM-DD'),
});
calendarEvents = [];
data.forEach((item) => {
calendarEvents.push(packageEventinfo(item));
});
successCallback(calendarEvents);
}
async function handleEventClick(info) {
//日程点击事件
const { data } = await getBaseWorkDutyOneApi({ id: info.event.id });
data.endDate = dayjs(data.endDate).subtract(1).format('YYYY-MM-DD');
openModal(true, data);
}
function handleDateClick(info) {
//日期方格点击事件
// console.log(arg);
}
function handleDateSelect(startDate, endDate, allDay, jsEvent, view) {
//选中日期事件
// console.log(startDate.startStr);
selectedStartDate.value = startDate.startStr;
selectedEndDate.value = dayjs(startDate.end).subtract(1).format('YYYY-MM-DD');
addEventBtn.value = false;
if (selectedStartDate.value === selectedEndDate.value) {
const nowDate = dayjs(selectedStartDate.value);
debugger
let _dateF = calendar.solar2lunar(nowDate.year(), nowDate.month()+1, nowDate.date());
oneDateDetail.value =
_dateF.cYear +
'-' +
_dateF.cMonth +
'-' +
_dateF.cDay +
' ' +
_dateF.IMonthCn +
'-' +
_dateF.IDayCn;
}else{
oneDateDetail.value ='';
}
}
function handleDateUnSelect(view, jsEvent) {
//取消选中日程事件
selectedStartDate.value = '';
selectedEndDate.value = '';
addEventBtn.value = true;
}
/**日程创建成功回调 */
function handleAddSuccess(item) {
// console.log(addInfo);
let calendarApi = fullCalendarRef.value.getApi();
calendarApi.addEvent(packageEventinfo(item));
}
function handlerUpdateSuccess(item) {
let calendarApi = fullCalendarRef.value.getApi();
const now = calendarApi.getEventById(item.id);
now.remove();
calendarApi.addEvent(packageEventinfo(item));
// calendarApi.refetchEvents();
}
function handlerDeleteSuccess(item) {
let calendarApi = fullCalendarRef.value.getApi();
const now = calendarApi.getEventById(item.id);
now.remove();
// calendarApi.refetchEvents();
}
function packageEventinfo(item) {
let obj = {
soureData: item,
id: item.id,
title: item.remark,
start: item.startDate,
end: item.endDate,
allDay: true,
// display: 'background',
textColor: 'black',
backgroundColor: item.hasHoliday ? '#FF0000' : '#00CD00',
};
return obj;
}
const calendarOptions = {
plugins: [
// 加载插件,V5采用插件模块方式加入
dayGridPlugin,
timeGridPlugin,
interactionPlugin, // needed for dateClick
],
themeSystem: 'Cerulean',
height: 'auto', //日历高度 auto自适应 parent父级别容器 数值表示固定
aspectRatio: 1.6, // 日历格的宽高比
width: 600,
fixedWeekCount: false, //true显示1个月6周,false按照当前月周显示
headerToolbar: {
// 头部toolba
left: 'dayGridMonth,today,prev,next',
center: 'title',
right: '',
},
buttonText: {
today: '今天',
month: '月',
week: '周',
day: '天',
list: '列表',
},
handleWindowResize: true, //随浏览器窗口变化
initialView: 'dayGridMonth', // 初始化插件显示
unselectAuto: false,
selectable: true,
views: {
dayGridMonth: {
//转农历
dayCellContent(item) {
let mark = sessionStorage.getItem('joinholiday');
let _date = new Date(item.date).toLocaleDateString().split('/');
let _dateF = calendar.solar2lunar(_date[0], _date[1], _date[2]);
if (item.dayNumberText == mark + '日') {
return {
html: `<h3 id='selectedHolidy'><label>${_dateF.cDay}</label></h3><h3><span>${
_dateF.IDayCn === '初一' ? _dateF.IMonthCn : _dateF.IDayCn
}</span></h3>`,
};
} else
return {
html: `<h3><label>${_dateF.cDay}</label></h3><h3><span>${
_dateF.IDayCn === '初一' ? _dateF.IMonthCn : _dateF.IDayCn
}</span></h3>`,
};
},
},
},
select: handleDateSelect,
unselect: handleDateUnSelect,
dateClick: handleDateClick, //日期方格点击事件
eventClick: handleEventClick, //日程点击事件
locale: zhCnLocale,
weekMode: 'fixed',
weekNumbers: false,
nextDayThreshold: '01:00:00',
events: getCalendarEvents,
};
onMounted(async () => {
// getFcList();
});
</script>
<style lang="less" scoped>
#fullCalendar222 {
position: relative;
padding: 10px;
// height: 100%;
.btnAdd {
position: absolute;
right: 20px;
top: 20px;
.addSch {
height: 28px;
line-height: 28px;
padding: 0 10px;
}
}
.dotGroup {
position: absolute;
left: 250px;
top: 23px;
display: flex;
align-items: center;
span {
margin-right: 20px;
display: flex;
align-items: center;
i {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 8px;
}
.dayDot {
background: #00cd00;
}
.shareDot {
background: #ff0000;
}
}
}
.fc .fc-toolbar.fc-header-toolbar .fc-center > div {
display: flex;
align-items: center;
}
}
</style>
- 细节说明:
- fullCalenDar得选中日期区间,结尾日期endDate是多一天得,比如7月25-到8月1号,endDate值:08-02。使用过程需要注意;
- 假期来源于后端数据提供
- 每年得节假日如何获取
参考这边博客,感谢大大。调用免费API查询全年工作日、周末、法定节假日、节假日调休补班数据 - huanzi-qch - 博客园 (cnblogs.com)
- 废话不说,直接上代码,照抄。
@Slf4j
@Component
@AllArgsConstructor
public class HolidayTimer {
private BaseWorkDutyService workDutyService;
/**
* 发送get请求
*/
private String get(String url) {
StringBuilder inputLine = new StringBuilder();
String read;
try {
HttpURLConnection urlConnection = (HttpURLConnection)new URL(url).openConnection();
urlConnection.setReadTimeout(50 * 1000);
urlConnection.setConnectTimeout(50 * 1000);
urlConnection.setRequestProperty("Charset", "UTF-8");
urlConnection.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36)");
BufferedReader in =
new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), StandardCharsets.UTF_8));
while ((read = in.readLine()) != null) {
inputLine.append(read);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
return inputLine.toString();
}
@Scheduled(cron = "0 0 20 12 12 ?")
public void handlerHoliday() throws JsonProcessingException {
LocalDate localDate = LocalDate.now();
LocalDate nextYear = localDate.plusYears(1);
String response = get("https://timor.tech/api/holiday/year/" + nextYear.getYear() + "/");
Map holidayMap = ObjectMapperUtil.instanceDefault().readValue(response, Map.class);
Integer code = (Integer)holidayMap.get("code");
if (code != null && !code.equals(0)) {
log.error("查询下一年度的假期错误,接口返回失败");
return;
}
LinkedHashMap holidayList = (LinkedHashMap)holidayMap.get("holiday");
List<BaseWorkDutyModel> saveModels = new ArrayList<>();
holidayList.forEach((key, value) -> {
BaseWorkDutyModel holidayVo = new BaseWorkDutyModel();
Map value1 = (Map)value;
holidayVo.setYear(nextYear.getYear());
String dateTime = value1.get("date").toString();
holidayVo.setStartDate(LocalDate.parse(dateTime));
holidayVo.setEndDate(LocalDate.parse(dateTime));
String name = value1.get("name").toString();
boolean holiday = Boolean.valueOf(value1.get("holiday").toString());
if (holiday) {
holidayVo.setHasHoliday(true);
holidayVo.setRemark(name);
} else {
holidayVo.setHasHoliday(false);
holidayVo.setRemark(name);
}
saveModels.add(holidayVo);
});
// saveModels按照selectDate升序排序
List<BaseWorkDutyModel> sortModels = saveModels.stream()
.sorted(Comparator.comparing(BaseWorkDutyModel::getStartDate)).collect(Collectors.toList());
if (ObjectUtil.isNotEmpty(sortModels)) {
log.info("已经保存{}年共{}条假期数据数据", nextYear.getYear(), sortModels.size());
workDutyService.saveAndRedis(nextYear.getYear(), sortModels);
}
}
}
- 其他得业务各位朋友自行补充,暂时先做到这够用了。