uniapp (微信小程序 ,h5) 工作日历 周计划日报 修改等提报和状态展示功能

101 阅读7分钟

Work-calendar

介绍

基于uni-calendar做的定制化开发,主要功能为工作日历展示和提报组件

1.支持周计划日报状态展示且可配置

2.支持农历展示配置,回到当日,月份切换

3.日历,周报,日报等点击事件封装

4.支持休假展示

Uniapp 插件市场连接

screenshot_2025-09-12_08-58-20.png

Screenshot_20250911_172303 - 副本.jpg

使用说明

1.下载插件到工程中,并在业务代码中引入

import Calendar from '@/components/calendar-zhikuany/calendar.vue'

2.布局中引入插件,并配置所需要的展示信息

<template>
    <view>
        <calendar ref="calendar" :date="date" :selected="selected" @monthSwitch="monthSwitch" @change="handleSelect"
            @weekPlanClick="weekPlanClick" @datePlanClick="datePlanClick" lunar :showDay="prop.showDay"
            :showPlan="prop.showPlan" :showMonth="prop.showMonth" />
    </view>
</template>
​
/**
     * Calendar 日历
     * @property {String} date 自定义当前时间,默认为今天
     * @property {String} text.size 文字大小
     * @property {String} text.color 文字颜色
     * @property {Boolean} lunar 显示农历
     * @property {Boolean} showPlan 展示周计划
     * @property {Boolean} showDay 展示日报
     * @property {String} startDate 日期选择范围-开始日期
     * @property {String} endDate 日期选择范围-结束日期
     * @property {Boolean} range 范围选择
     * @property {Array} selected 
     * @property {Boolean} showMonth 是否选择月份为背景
	 * @property {Boolean} needState 周计划日报是否需要审核
     * @event {Function} change 日期改变,
     * @event {Function} monthSwitch 切换月份时触发
     */
​

3.设置本月周报日报假期数据

    /**
     * 设置数据
     */
    const setDate = (year : number, month : number) => {
        // 获取当月第一天和最后一天
        // const firstDay = new Date(year, month, 1);
        // const lastDay = new Date(year, month + 1, 0); // 下个月第0= 本月最后一天
        uni.showLoading({
            title: ''
        })
        //仿照调用接口 设置工作日历数据
        setTimeout(() => {
            uni.hideLoading()
            //测试周报和日报数据 为 912号
            date.value = '2025-09-12'
            calendar.value.setPlanList(planList)
        }, 1000)
​
    }

4.核心数据设置逻辑

/**
	 * 获取每周数据
	 * @param {Object} dateData
	 */
	_getWeek(dateData) {
		const {
			year,
			month
		} = this.getDate(dateData)

		let firstDay = new Date(year, month - 1, 1).getDay()
		// 调整为周一作为第一天(0=周一,6=周日)
		let adjustedFirstDay = firstDay === 0 ? 6 : firstDay - 1;
		let currentDay = new Date(year, month, 0).getDate()
		let dates = {
			lastMonthDays: this._getLastMonthDays(adjustedFirstDay, this.getDate(dateData)), // 上个月末尾几天
			currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
			nextMonthDays: [], // 下个月开始几天
			weeks: []
		}

		let canlender = []
		const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
		dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
		canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
		this.canlender = canlender
		let weekTemp = {}
		let weekplan = {} //每周的周计划
		// 拼接数组  上个月开始几天 + 本月天数+ 下个月开始几天
		for (let i = 0; i < canlender.length; i++) {
			//获取本周的周计划数据
			if (i % 7 === 0) {
				//本周开始日期
				const weekBeginDate = canlender[i].fullDate
				// console.log('开始',weekBeginDate)
				//获取计划状态
				weekplan = {}
				for (let i = 0; i < this.planList.length; i++) {
					if (this.planList[i]) {
						const item = this.planList[i]
						// console.log(item.monday)
						if (item.beginDate == weekBeginDate) {
							weekplan = item
							// console.log('weekplan', weekplan)
							break
						}
					}

				}
				let weekDataState = 0 //周计划状态K
				if (this.needSate) {
					weekDataState = weekplan.dataState //周计划 状态
				} else {
					weekDataState = this.isEmpty(weekplan.dataState) ? weekplan.dataState : 1 //状态不用审核
				}
				weekTemp[parseInt(i / 7)] = {
					weeks: new Array(7),
					planCode: weekplan.planCode,
					planId: weekplan.planId,
					dataState: weekDataState,
					attachIds: weekplan.attachIds,
					// fileUrl: weekplan.fileUrl,
					weekWorkPlan: weekplan.weekWorkPlan,
					workSummary: weekplan.workSummary,
					coordinateHelp: weekplan.coordinateHelp,

				}
			}
			//每天的计划状态
			var dayPlan = {}

			switch (i % 7) {
				case 0: //周一
					if (this.needSate) {
						dayPlan.dayStatus = weekplan.mondayStatus
					} else {
						dayPlan.dayStatus = this.isEmptyWithZero(weekplan.mondayStatus) ? weekplan.mondayStatus : 2
					}
					dayPlan.isHoliday = weekplan.mondayIsHoliday
					break;
				case 1:
					if (this.needSate) {
						dayPlan.dayStatus = weekplan.tuesdayStatus
					} else {
						dayPlan.dayStatus = this.isEmptyWithZero(weekplan.tuesdayStatus) ? weekplan.tuesdayStatus :
							2
					}
					dayPlan.isHoliday = weekplan.tuesdayIsHoliday
					break;
				case 2:
					if (this.needSate) {
						dayPlan.dayStatus = weekplan.wednesdayStatus
					} else {
						dayPlan.dayStatus = this.isEmptyWithZero(weekplan.wednesdayStatus) ? weekplan
							.wednesdayStatus : 2
					}

					dayPlan.isHoliday = weekplan.wednesdayIsHoliday
					break;
				case 3:
					if (this.needSate) {
						dayPlan.dayStatus = weekplan.thursdayStatus
					} else {
						dayPlan.dayStatus = this.isEmptyWithZero(weekplan.thursdayStatus) ? weekplan
							.thursdayStatus : 2
					}
					dayPlan.isHoliday = weekplan.thursdayIsHoliday
					break;
				case 4:
					if (this.needSate) {
						dayPlan.dayStatus = weekplan.fridayStatus
					} else {
						dayPlan.dayStatus = this.isEmptyWithZero(weekplan.fridayStatus) ? weekplan.fridayStatus : 2
					}
					dayPlan.isHoliday = weekplan.fridayIsHoliday
					break;
				case 5:
					if (this.needSate) {
						dayPlan.dayStatus = weekplan.saturdayStatus
					} else {
						dayPlan.dayStatus = this.isEmptyWithZero(weekplan.saturdayStatus) ? weekplan
							.saturdayStatus : 2
					}
					dayPlan.isHoliday = weekplan.saturdayIsHoliday
					break;
				case 6:
					if (this.needSate) {
						dayPlan.dayStatus = weekplan.sundayStatus
					} else {
						dayPlan.dayStatus = this.isEmptyWithZero(weekplan.sundayStatus) ? weekplan.sundayStatus : 2
					}

					dayPlan.isHoliday = weekplan.sundayIsHoliday
					break;
			}

			// console.log('swich',dayPlan)
			weekTemp[parseInt(i / 7)].weeks[i % 7] = {
				...canlender[i],
				...dayPlan
			}
		}

		this.weeks = weekTemp
		// console.log(this.weeks)
	}

完整示例

<template>
	<view>
		<calendar ref="calendar" :date="date" @monthSwitch="monthSwitch" @change="handleSelect"
			@weekPlanClick="weekPlanClick" @datePlanClick="datePlanClick" lunar :showDay="prop.showDay"
			:showPlan="prop.showPlan" :showMonth="prop.showMonth" :needState="prop.needState" />
	</view>
</template>

<script setup lang="ts">
	import { ref, onMounted } from 'vue'
	import { onLoad, onShow } from '@dcloudio/uni-app'
	import { planList } from './data.js'
	import Calendar from '@/components/calendar-zhikuany/calendar.vue'
	/**
	 * 本组件是基于uni-calendar(V1.5.5)之上增加了一些个性化功能点,如打卡日历,日历日程,日历排班,打卡排班等功能
	 * 小点的位置 point.position [1, 2, 3, 4, 5, 6] 红点位置,[左上角, 右上角, 右下角, 左下角, 上中间, 下中间]
	 * 小点的颜色  point.color 如 #000 #fff
	 * 日期数字下方的自定义文本  info
	 * text.size 自定义文本字体大小 如 12 14 16
	 * text.color 自定义文本颜色 如 #000 #fff
	 */
	const calendar = ref({})
	const date = ref('')
	const query = defineProps<{ prop : string }>()
	const prop : any = ref({})

	//页面加载
	onLoad(() => {
		//解析配置参数
		prop.value = JSON.parse(query.prop)

	})
	onShow(() => {
		initDate()
	})
	//获取当月所有日期的数组 初始化数据
	const initDate = () => {
		const now = new Date();
		const year = now.getFullYear();
		const month = now.getMonth() + 1; // 月份从 0 开始(0=1月)
		setDate(year, month);

	}
	/**
	 * 设置数据
	 */
	const setDate = (year : number, month : number) => {
		// 获取当月第一天和最后一天
		// const firstDay = new Date(year, month, 1);
		// const lastDay = new Date(year, month + 1, 0); // 下个月第0天 = 本月最后一天
		uni.showLoading({
			title: ''
		})
		//仿照调用接口 设置工作日历数据
		setTimeout(() => {
			uni.hideLoading()
			//测试周报和日报数据 为 9月12号
			date.value = '2025-09-12'
			calendar.value.setPlanList(planList)
		}, 1000)

	}


	/**
	 * 选中
	 */
	const handleSelect = (e : any) => {
		console.log(e)
		if (e.extraInfo.date) {
			// do something
		}
	}
	//周计划点击
	const weekPlanClick = (item : any) => {
		console.log(item)
		if (item.dataState == 1 || item.dataState == 0) {//审核中或者审核通过
			uni.showToast({
				title: JSON.stringify(item),
				icon: 'none',
				duration: 2000
			})

		} else {
			if (!checkWeekRange(item.beginDate, item.endDate)) {
				uni.showToast({
					title: '只能提交当本周或下周的周计划',
					icon: 'none'
				})
				return
			}
			uni.showToast({
				title: '跳转周计划填报页面',
				icon: 'none',
				duration: 2000
			})

		}

	}
	/**
	 * 判断给定的日期范围是否属于本周或下周
	 * @param {string} beginDate - 开始日期,格式为 "YYYY-MM-DD"
	 * @param {string} endDate - 结束日期,格式为 "YYYY-MM-DD"
	 * @returns {string} - 返回 "本周"、"下周" 或 "不在本周或下周"
	 */
	function checkWeekRange(beginDate : any, endDate : any) : Boolean {
		// 将字符串日期转换为Date对象
		const begin = new Date(beginDate);
		const end = new Date(endDate);
		begin.setHours(0, 0, 0, 0)
		end.setHours(0, 0, 0, 0)
		console.log(begin + '  ' + end)

		// 获取当前日期
		const today = new Date();
		today.setHours(0, 0, 0, 0); // 清除时间部分

		// 计算当前周的起始和结束日期(周一至周日)
		const currentWeekStart = new Date(today);
		const dayOfWeek = today.getDay(); // 0是周日,1是周一,...,6是周六
		const diffToMonday = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; // 调整为周一作为一周的第一天
		currentWeekStart.setDate(today.getDate() + diffToMonday);
		currentWeekStart.setHours(0, 0, 0, 0);

		const currentWeekEnd = new Date(currentWeekStart);
		currentWeekEnd.setDate(currentWeekStart.getDate() + 6);

		// 计算下周的起始和结束日期
		const nextWeekStart = new Date(currentWeekStart);
		nextWeekStart.setDate(currentWeekStart.getDate() + 7);

		const nextWeekEnd = new Date(currentWeekEnd);
		nextWeekEnd.setDate(currentWeekEnd.getDate() + 7);
		console.log(currentWeekStart + '  ' + currentWeekEnd)
		// 检查日期范围是否完全在本周内
		const isCurrentWeek = begin >= currentWeekStart && end <= currentWeekEnd;

		console.log(nextWeekStart + '  ' + nextWeekEnd)
		// 检查日期范围是否完全在下周内
		const isNextWeek = begin >= nextWeekStart && end <= nextWeekEnd;

		// 检查日期范围是否跨越本周和下周(部分在本周,部分在下周)
		const isOverlapping = (begin <= currentWeekEnd && end >= nextWeekStart);

		if (isCurrentWeek) {
			console.log('本周')
			return true;
		} else if (isNextWeek || isOverlapping) {
			console.log('下周')
			return true;
		} else {
			console.log('非本周或下周')
			return false;
		}
	}

	//是否属于当前周
	const isInRange = (bengin : any, end : any) => {
		const benginDate = new Date(bengin)
		const endDate = new Date(end)
		const currentDate = new Date()
		return currentDate >= benginDate && currentDate <= endDate
	}
	//日报点击
	const datePlanClick = (item : any) => {
		console.log(item)
		//展示周计划的时候需要校验周计划状态
		if (prop.showPlan) {
			if (item.dataState == null || item.dataState == 'undefined') {
				uni.showToast({
					title: '请先提交周计划',
					icon: 'none'
				})
				return
			}
			if (item.dataState == 0) {
				uni.showToast({
					title: '周计划审核中...',
					icon: 'none'
				})
				return
			}
		}

		//审批中 已通过
		if (item.dayStatus == 1 || item.dayStatus == 2) {
			uni.showToast({
				title: '跳转日报详情页面',
				icon: 'none',
				duration: 2000
			})
		} else {//未提交或者驳回
			if (!isDateInCurrentWeek(item.fullDate)) {
				uni.showToast({
					title: '只能提交本周内的日报',
					icon: 'none'
				})
				return
			}
			uni.showToast({
				title: '跳转日报填写页面',
				icon: 'none',
				duration: 2000
			})
		}

	}

	/**
	 * 判断某个日期是否属于本周
	 * @param {Date|string} targetDate - 目标日期(Date 对象或 "YYYY-MM-DD" 字符串)
	 * @returns {boolean} - 是否属于本周
	 */
	function isDateInCurrentWeek(targetDate : any) : Boolean {
		// 如果传入的是字符串,转换为 Date 对象
		const date = typeof targetDate === 'string' ? new Date(targetDate) : new Date(targetDate);

		// 获取当前日期
		const today = new Date();

		// 计算本周一的日期(以周一作为一周的第一天)
		const currentWeekMonday = new Date(today);
		currentWeekMonday.setDate(today.getDate() - today.getDay() + 1); // getDay() 周日是 0,周一是 1,...,周六是 6
		currentWeekMonday.setHours(0, 0, 0, 0); // 清除时间部分,确保比较的是日期

		// 计算本周日的日期
		const currentWeekSunday = new Date(currentWeekMonday);
		currentWeekSunday.setDate(currentWeekMonday.getDate() + 6);
		currentWeekSunday.setHours(23, 59, 59, 999); // 设置为周日最后一刻

		// 判断目标日期是否在本周范围内
		return date >= currentWeekMonday && date <= currentWeekSunday;
	}


	//月份切换
	const monthSwitch = (e : any) => {
		console.log(e)
		setDate(e.year, e.month)
	}
	//日期转字符串格式
	const dateToStr = (date : any) => {
		var year = date.getFullYear() //年
		var month = date.getMonth() //月
		var day = date.getDate() //日
		var hours = date.getHours() //时
		var min = date.getMinutes() //分
		var second = date.getSeconds() //秒
		return year + "-" +
			((month + 1) > 9 ? (month + 1) : "0" + (month + 1)) + "-" +
			(day > 9 ? day : ("0" + day)) + " " +
			(hours > 9 ? hours : ("0" + hours)) + ":" +
			(min > 9 ? min : ("0" + min))
	}
	//字符串转日期
	const strToDate = (str : string) => {
		var date = new Date(str)
		return date.getTime()

	}
</script>

<style>

</style>
周计划日报数据示例

含用户信息 ,周计划信息和状态,日报信息和状态,是否休假

const planList = [{
    //计划编码和id
    "planId": 58,
    "planCode": "1015297758478274563",
    //本周开始 截止时间
    "beginDate": "2025-09-08",
    "endDate": "2025-09-14",
    "planPeriod": "2025-09-08~2025-09-14",
    //用户信息
    "userCode": "1009761934881456147",
    "username": "员工001",
    "departCode": "951784785749401608",
    "departName": "xxx总公司",
    //周一到周日状态信息
    "monday": "2025-09-08",
    "mondayStatus": 0,
    "tuesday": "2025-09-09",
    "tuesdayStatus": 1,
    "wednesday": "2025-09-10",
    "wednesdayStatus": 1,
    "thursday": "2025-09-11",
    "thursdayStatus": 0,
    "friday": "2025-09-12",
    "fridayStatus": 0,
    "saturday": "2025-09-13",
    "saturdayStatus": 0,
    "sunday": "2025-09-14",
    "sundayStatus": 0,
    //
    "weekWorkPlan": "工作计划",
    "workSummary": '跟最后工作总结',
    "coordinateHelp": "需要协调需帮助",
    //附件列表 字符串 逗号分隔
    "attachIds": "",
    //创建更新时间
    "gmtCreate": "2025-09-03 08:27:25",
    "gmtModified": "2025-09-03 08:27:25",
    //周计划状态 
    "dataState": 0,
    //是否请假 周一到周五
    "mondayIsHoliday": null,
    "tuesdayIsHoliday": 1,
    "wednesdayIsHoliday": 0,
    "thursdayIsHoliday": null,
    "fridayIsHoliday": null,
    "saturdayIsHoliday": null,
    "sundayIsHoliday": null
}]
​
​
​