我先把官网弄来吧
官网链接: FullCalendar - JavaScript Event Calendar
我的这一篇日历打卡 代码不怎么需要改 想要快速实现
第一步 安装@fullCalendar这些 具体我也不是很明白 都先安装吧 我的这些不具体 可以进官网地址 里面安装@full这些
npm install @fullcalendar/core
npm install @fullcalendar/vue3
vue文件中引用
import FullCalendar from "@fullcalendar/vue3"
必须安装一个:
npm install @fullcalendar/daygrid
npm install @fullcalendar/multimonth
npm install @fullcalendar/timegrid
下面是全部代码
<!-- 功能太复杂,阅读时请配合文章后面的注意事项和文档 -->
<!-- 功能太复杂,阅读时请配合文章后面的注意事项和文档 -->
<template>
<div style="background-color: white;">
<h4 style="margin: 5px;">打卡任务</h4>
<div class="fullcalendar-content">
<!-- 自定义工具组 -->
<!-- <button @click="switchToView('dayGridMonth')">月视图</button>
<button @click="switchToView('timeGridWeek')">周视图</button>
<button @click="switchToView('listDay')">日视图</button> -->
<div
style="display: flex;align-items: center;justify-content: space-between;width: 98%;margin: auto;padding-top: 20px;">
<div>
<el-button color="black" style="width: 30px;height: 30px;" @click="pageTurning('prev')">
<el-icon>
<ArrowLeft />
</el-icon>
</el-button>
</div>
<div>
<el-button style="width: 30px;height: 30px;" @click="toToday()" color="#76818D">今天</el-button>
<el-button color="black" style="width: 30px;height: 30px;" @click="pageTurning('next')">
<el-icon>
<ArrowRight />
</el-icon>
</el-button>
</div>
</div>
<!-- 新增弹出框 -->
<el-dialog v-model="dialogTableVisible" @close="close(ruleFormRef)" :title="sta" width="55vw">
<el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" status-icon :rules="rules"
label-width="auto" class="demo-ruleForm">
<el-form-item label="任务标题" prop="tel">
<el-input v-model="ruleForm.tel" style="width: 100%" placeholder="请输入任务标题" autocomplete="off" />
</el-form-item>
<el-form-item label="任务介绍" prop="bjclass">
<el-input v-model="ruleForm.bjclass" style="width: 100%" placeholder="请输入任务介绍"
autocomplete="off" />
</el-form-item>
<el-form-item label="积分奖励" prop="intr">
<el-input v-model="ruleForm.intr" style="width: 100%" placeholder="请输入积分奖励"
autocomplete="off" />
</el-form-item>
<!-- 出生日期 -->
<el-form-item prop="date" label="开始日期" style="margin-left: 2px; margin-top: 15px">
<el-date-picker style="height: 35px;width: 100%" v-model="ruleForm.date" type="date"
format="YYYY-MM-DD" placeholder="开始日期" date-format="YYYY/MM/DD" time-format="A hh:mm:ss"
value-format="YYYY-MM-DD" />
</el-form-item>
<el-form-item prop="date" label="结束日期" style="margin-left: 2px; margin-top: 15px">
<el-date-picker style="height: 35px;width: 100%" v-model="ruleForm.dates" type="date"
format="YYYY-MM-DD" placeholder="结束日期" date-format="YYYY/MM/DD" time-format="A hh:mm:ss"
value-format="YYYY-MM-DD" />
</el-form-item>
<el-form-item prop="password" label="学生" style="margin-left: 2px; margin-top: 15px">
<el-tree style="max-width: 800px" :data="treeData" show-checkbox node-key="id"
@check-change="tree_id" ref="treeRef" :default-checked-keys="student_id" :props="defaultProps" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm(ruleFormRef)">确认</el-button>
<el-button @click="closes(ruleFormRef)">取消</el-button>
</div>
</template>
</el-dialog>
<!-- 日历组件 -->
<FullCalendar ref="FullCalendar_ref" @click="ls()" :options='_data.calendarOptions' />
<!-- 动态插入数据 -->
<!-- <button @click="getMatter()">接口获取列表</button>
<button @click="addMatter()">[新增]动态插入事项</button>
<button @click="getViewsData()">获取当前日历视图数据</button>
<button @click="clearAllList()">重置清空日历</button> -->
</div>
</div>
</template>
<script setup lang="ts">
// vue
import { ref, reactive, onMounted } from 'vue'
import FullCalendar from '@fullcalendar/vue3'//核心基础包
import locale from '@fullcalendar/core/locales/zh-cn'//汉化包
import dayGridPlugin from '@fullcalendar/daygrid'//视图-月
import timeGridPlugin from '@fullcalendar/timegrid'//视图-周
import listPlugin from '@fullcalendar/list'//视图-日
import { task_list, task_add,task_edit } from '../../api/task/index'
import { Plus, Search, ArrowLeft, ArrowRight } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { render } from 'nprogress';
import axios from 'axios';
const treeRef = ref();
// 选择checkboxid
const SelectArr = ref([])
const All_Delete = ref([])
const treeId = ref([])
const tree_id = (val) => {
// console.log(val);
treeId.value=[]
treeId.value.push(val.id)
All_Delete.value = []
SelectArr.value = val
for (let i = 0; i < SelectArr.value.length; i++) {
console.log(SelectArr.value[i],'每一项');
// All_Delete.value.push(SelectArr.value[i].id)
}
console.log(All_Delete.value);
ruleForm.password=treeId.value.join(',')
}
const defaultProps = {
children: 'children',
label: 'title',
}
const tacks = ref([])
// 新增打卡和编辑打卡
const disableds = ref(false)
const tokens = JSON.parse(localStorage.getItem('tokens'));
renders()
const task = ref([])
const tasks = ref([])
const copytacks = ref([])
const treeData = ref([])
function renders() {
task_list({
token: tokens.token,
id: tokens.id
}, {
role: tokens.role
}).then(res => {
console.log(res);
task.value = res.data.list
_data.calendarOptions.events = res.data.list
treeData.value = res.data.squad
})
}
const statusAdd = ref('')
const dialogTableVisible = ref(false)
const status = ref('')
const infos = ref([])
const ls = () => {
sta.value = '打卡任务'
console.log(infos.value);
status.value = '1'
statusAdd.value = '1'
dialogTableVisible.value = true
disableds.value = true
}
// 关闭新增
const closes = (formEl) => {
if (!formEl) return;
formEl.resetFields();
dialogTableVisible.value = false;
infos.value = []
// All_Delete.value=[]
infos.value = []
ruleForm.name = '';
ruleForm.tel = ''
ruleForm.name = ''
ruleForm.date = ''
ruleForm.dates = ''
ruleForm.radio = ''
ruleForm.intr = ''
ruleForm.bjclass = ''
ruleForm.password = ''
ruleForm.img = ''
student_id.value=[]
};
// 关闭新增
const close = (formEl) => {
if (!formEl) return;
formEl.resetFields();
const allKeys = treeRef.value.getCheckedKeys();
treeRef.value.setCheckedKeys([]);
student_id.value=[]
infos.value = []
ruleForm.name = '';
ruleForm.tel = ''
ruleForm.name = ''
ruleForm.date = ''
ruleForm.dates = ''
ruleForm.radio = ''
ruleForm.intr = ''
ruleForm.bjclass = ''
ruleForm.password = ''
ruleForm.img = ''
};
// 表单效验集合
const ruleFormRef = ref < FormInstance > ();
const validatePass = (rule: any, value: any, callback: any) => {
if (value === '') {
callback(new Error('Please input the password'));
} else {
if (ruleForm.checkPass !== '') {
if (!ruleFormRef.value) return;
ruleFormRef.value.validateField('checkPass', () => null);
}
callback();
}
};
// 新增输入框响应值
const ruleForm = reactive({
bjclass: '',
name: '',
intr: '',
img: '',
tel: '',
password: '',
radio: '',
date: '',
dates: ''
});
// 新增输入框判断效验
const rules = reactive({
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
// tel: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
tel: [
{ required: true, message: '请输入任务标题', trigger: 'blur' }
],
password: [{ required: true, message: '请选择学生', trigger: 'blur' }],
bjclass: [{ required: true, message: '请输入任务介绍', trigger: 'blur' }],
intr: [{ required: true, message: '请输入积分奖励', trigger: 'blur' }],
radio: [{ required: true, message: '请选择性别', trigger: 'blur' }],
img: [{ required: true, message: '请上传图片', trigger: 'blur' }],
date: [{ required: true, message: '请选择开始日期', trigger: 'blur' }],
dates: [{ required: true, message: '请选择结束日期', trigger: 'blur' }],
});
// 点击新增确认
const statuss = ref('')
const submitForm = (formEl: FormInstance | undefined) => {
console.log(ruleForm);
if (!formEl) return;
formEl.validate((valid) => {
if (valid) {
if (infos.value == '') {
task_add({
token: tokens.token,
id: tokens.id
}, {
title: ruleForm.tel,
desc: ruleForm.bjclass,
score: ruleForm.intr,
start_time: ruleForm.date,
end_time: ruleForm.dates,
user_id: tokens.id,
student_id: treeId.value.join(',')
}).then(res => {
console.log(res);
if (res.code == 1) {
renders()
ElMessage({
message: '新增成功',
type: 'success',
})
setTimeout(() => {
dialogTableVisible.value = false;
ruleForm.tel = ''
ruleForm.bjclass = ''
ruleForm.intr = ''
ruleForm.date = ''
ruleForm.dates = ''
}, 1300);
} else if (res.code == 0) {
ElMessage({
message: res.msg,
type: 'warning',
})
}
})
} else if (infos.value != '') {
console.log(All_Delete.value.join(','));
task_add({
token: tokens.token,
id: tokens.id
}, {
id:stu_id.value,
title: ruleForm.tel,
desc: ruleForm.bjclass,
score: ruleForm.intr,
start_time: ruleForm.date,
end_time: ruleForm.dates,
user_id: tokens.id,
student_id: treeId.value.join(',')
}).then(res => {
console.log(res);
if (res.code == 1) {
renders()
ElMessage({
message: '编辑成功',
type: 'success',
})
setTimeout(() => {
dialogTableVisible.value = false;
ruleForm.tel = ''
ruleForm.bjclass = ''
ruleForm.intr = ''
ruleForm.date = ''
ruleForm.dates = ''
}, 1300);
} else if (res.code == 0) {
ElMessage({
message: res.msg,
type: 'warning',
})
}
})
}
// 效验通过执行
console.log("通过");
} else {
console.log('error submit!');
return false;
}
});
}
// refs
const FullCalendar_ref = ref()//日历插件
let sta = ref('')
const student_id = ref([])
const stu_id=ref('')
// data
const _data = reactive({
// 插件配置(https://fullcalendar.io/docs#toc)
calendarOptions: {
locale: locale,//语言包
plugins: [dayGridPlugin, timeGridPlugin, listPlugin],//插件
initialView: 'dayGridMonth',//日历加载时的初始视图(我这里用月份)
weekends: true,//是否在日历中包含星期六/星期天列
// 日历头部按钮功能及位置
// 这里只用到了标题,其他的全部自定义了,没用它原来的样式太丑了
headerToolbar: { left: '', center: 'title', right: '' },
// 事项集合(会根据键值对的start开始时间确定在日历的哪个日期上显示)
// 更多属性请访问:https://fullcalendar.io/docs/event-object
events: [],
// 点击事项触发
eventClick: (info) => {
// console.log('啥都有:', info)
infos.value = info
sta.value = '编辑打卡任务'
status.value = '2'
if (infos.value != "") {
disableds.value = false
}
console.log(infos.value);
// ruleForm.bjclass = info.event.title
ruleForm.tel = info.event.title
ruleForm.bjclass = info.event.extendedProps.desc
ruleForm.intr = info.event.extendedProps.score
ruleForm.date = info.event.startStr
ruleForm.dates = info.event.extendedProps.end_time
student_id.value = info.event.extendedProps.student_id
treeId.value.push(info.event.extendedProps.student_id)
ruleForm.password=info.event.extendedProps.student_id
stu_id.value=info.event.id
console.log(treeId.value);
// alert(`您点击了【${info.event._def.defId}】,处理逻辑...`)
},
// 对事项做展示样式、逻辑等处理(最终必须return返回,否则不渲染!)
// https://fullcalendar.io/docs/content-injection
eventContent: (info) => {
// 这块根据逻辑来,api非常灵活,也比较复杂
// 可以返回html,携带class样式类等等
// 比如,这个事件是否逾期,如果逾期则标红的需求!
// -----------------------------------------
// console.log('啥都有:', info)
// 获取是否逾期标识
let isSlippage = info.event.extendedProps.isSlippage
// 根据逾期标识,决定是否加入 "标红的class: fullcalendar-highlight"
// fullcalendar-items: 这个样式是由于覆盖了原来的容器,所以里面的内容和样式全需要自己写了!
let className = isSlippage ? 'fullcalendar-items fullcalendar-highlight' : 'fullcalendar-items'
// 利用info里的数据,自己组合要显示什么信息和html!当然组件库的也可以用!
// info.timeText:即事项的开始时间 | info.event.title:即事项的标题
// 根据业务来即可,需要注意各日月周视图模式下的显示即可!
return {
html:
`<span class="${className}" title="${info.event.title}">
${info.timeText} ${info.event.title}
</span>`
}
},
// 监听月周日视图切换
viewDidMount: (info) => {
console.log('您切换了视图', info)
},
// 更多配置...
}
})
// onMounted
onMounted(() => {
// 初始模拟请求接口
// setTimeout(() => {
// getMatter()
// }, 3000)
})
// 动态插入事项数据(新增事项)
// https://fullcalendar.io/docs/Calendar-addEvent
const addMatter = () => {
FullCalendar_ref.value.getApi().addEvent(
{
id: 99,//唯一标识
title: '动态新增事项',//事项名称
start: new Date(),//开始时间
allDay: false,//是否全天(不限时间,无需开始和结束时间)
isSlippage: false,//[自己的额外业务数据]是否逾期
}
)
}
// 切换日历视图(mode模式名称)
const switchToView = (mode) => {
FullCalendar_ref.value.getApi().changeView(mode)
}
// 定位到今天
const toToday = () => {
FullCalendar_ref.value.getApi().today()
}
// 日历翻页/左右箭头(mode模式名称)
const pageTurning = (mode) => {
if (mode == 'prev') {
FullCalendar_ref.value.getApi().prev();
} else {
FullCalendar_ref.value.getApi().next();
}
}
// 重置清空日历列表事项
const clearAllList = () => {
_data.calendarOptions.events = []
}
// 获取当前日历视图数据(啥都有)
const getViewsData = () => {
let ff = FullCalendar_ref.value.getApi().view
console.log('当前日历标题(可赋值变量,放到任何位置):', ff.getCurrentData().viewTitle)
console.log('更多日历实例', ff.getCurrentData())
}
// 模拟接口获取日历列表事项
// const getMatter = () => {
// 假设ajax已获取到了数据
// }
</script>
<style>
/* 根节点 */
.fullcalendar-content {
width: 1000px;
margin: 0 auto;
cursor: pointer;
text-align: center;
}
/* 头部弹性布局 */
.fullcalendar-header {
display: flex;
justify-content: space-between;
margin-bottom: -25px;
}
/* 每个待办事项容器的样式 */
.fullcalendar-items {
/* 文本溢出后显示... */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
}
/* 逾期事项的样式 */
.fullcalendar-highlight {
color: red
}
/* ----------- 下方为覆盖组件原样式的代码 ---------------- */
/* ----------- 下方为覆盖组件原样式的代码 ---------------- */
/* ----------- 下方为覆盖组件原样式的代码 ---------------- */
/* 年月标题 */
.fc .fc-toolbar-title {
/* background: red; */
font-size: 20px;
vertical-align: middle;
}
/* 列头单元格(周日~周六) */
.fc .fc-col-header-cell-cushion {
/* background: red; */
display: block;
text-align: center;
background: white;
/* color: #333; */
}
/* 日期数字样式 */
.fc .fc-daygrid-day-number {
font-size: 13px;
}
</style>