vue3 日历打卡如何实现?

 我先把官网弄来吧
官网链接: 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>


 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3 打卡日历是一个基于 Vue3 开发的日历组件,可以方便地展示月视图和周视图,并支持日历签到功能。 首先,在你的 Vue3 项目中安装 `vue3-calendar`: ``` npm i vue3-calendar ``` 然后在需要使用日历组件的地方引入: ```html <template> <div> <Calendar :events="events" :signed="signed" @event-click="onEventClick" @date-click="onDateClick" /> </div> </template> <script> import Calendar from 'vue3-calendar' export default { components: { Calendar }, data () { return { events: [ { title: 'Event 1', date: '2022-01-01' }, { title: 'Event 2', date: '2022-01-15' }, { title: 'Event 3', date: '2022-01-20' } ], signed: ['2022-01-01', '2022-01-15'] } }, methods: { onEventClick (event) { console.log(event) }, onDateClick (date) { console.log(date) } } } </script> ``` 在上面的代码中,我们将 `vue3-calendar` 引入并注册为 `Calendar` 组件。然后在模板中使用 `<Calendar>` 标签,并传入两个属性: - `events`:用于指定日历上显示的事件列表,每个事件包含 `title` 和 `date` 两个属性; - `signed`:用于指定哪些日期已经签到。 `<Calendar>` 组件还提供了两个事件: - `event-click`:当用户点击某个事件时触发,可以通过 `$event` 参数获取被点击的事件信息; - `date-click`:当用户点击某个日期时触发,可以通过 `$event` 参数获取被点击的日期信息。 最后,你需要在样式中引入日历组件的 CSS 文件: ```html <style> @import 'vue3-calendar/dist/vue3-calendar.css'; </style> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值