Prechádzať zdrojové kódy

perf(work/edit): 关联时间(请假,加班)自动计算时间差

wangpx 1 rok pred
rodič
commit
98aca1f780
2 zmenil súbory, kde vykonal 137 pridanie a 11 odobranie
  1. 13 0
      api/work.js
  2. 124 11
      pages/work/edit/index.vue

+ 13 - 0
api/work.js

@@ -93,4 +93,17 @@ export function uploadFile(data) {
     name: data.name,
     filePath: data.filePath
   })
+}
+// 获取班次信息
+export function getAttendanceSegment(unitId) {
+	return request({
+		url: preUrl,
+		method: 'post',
+		data: {
+			serviceId: 'miniapp_getAttendanceSegment',
+			params: {
+				unitId
+			}
+		}
+	})
 }

+ 124 - 11
pages/work/edit/index.vue

@@ -111,7 +111,7 @@ import $modal from '@/plugins/modal.js'
 import $tab from '@/plugins/tab.js'
 import { convertToChineseCurrency } from '@/utils/ygoa.js'
 import { calCommonExp } from '@/utils/rpn.js'
-import { getProcessInfo, getProcessForm, submitProcessForm, uploadFile } from '@/api/work.js'
+import { getProcessInfo, getProcessForm, submitProcessForm, uploadFile, getAttendanceSegment } from '@/api/work.js'
 const fieldTypeDict = {
 	'0': 'text',
 	'1': 'number'
@@ -200,6 +200,15 @@ function bindTimeRangeData() {
 
 			// 只有找到 startName 和 endName 后,才检查 bindName
 			if (startIndex !== -1 && endIndex !== -1) {
+				formElements.value[startIndex].defaultValue = new Date(Date.now()).toLocaleString('zh-CN', {
+					year: 'numeric',
+					month: '2-digit',
+					day: '2-digit',
+					hour: '2-digit',
+					minute: '2-digit',
+					second: '2-digit',
+					hour12: false
+				}).replace(/\//g, '-').replace(/, /g, ' ');
 				if (bindName) {
 					const bindIndex = formElements.value.findIndex((item) => item.elementName === bindName);
 					if (bindIndex !== -1) {
@@ -210,6 +219,7 @@ function bindTimeRangeData() {
 							startIndex,
 							endIndex
 						};
+						setAttendanceSegment() // 获取班次信息
 					}
 				} else {
 					// 没有 bindName,仅保存 start 和 end 的索引
@@ -228,15 +238,17 @@ function calculateTimeDifference(item, form) {
 	const { startIndex, endIndex } = item.bindTimeRange;
 	const startTime = new Date(form[startIndex].defaultValue);
 	const endTime = new Date(form[endIndex].defaultValue);
-
+	
 	// 检查时间是否合法
 	if (isNaN(startTime.getTime()) || isNaN(endTime.getTime())) {
 		return item.defaultValue = 0
 	}
-
+	// 改为配置选择
+	const type = item.elementName == '多少小时'?'请假':'加班'
 	// 计算时间差
-	const timeDifferenceInMs = endTime - startTime;
-	let timeDifferenceInHours = (timeDifferenceInMs / (1000 * 60 * 60)).toFixed(1);
+	const timeDifferenceInHours = calculateWorkingHours(startTime, endTime, type);
+	// const timeDifferenceInMs = endTime - startTime;
+	// let timeDifferenceInHours = (timeDifferenceInMs / (1000 * 60 * 60)).toFixed(1);
 	// let timeDifferenceInHours = (timeDifferenceInMs / (1000 * 60 * 60))
 	// // 计算小数部分
 	// const decimalPart = timeDifferenceInHours - Math.floor(timeDifferenceInHours)
@@ -250,6 +262,106 @@ function calculateTimeDifference(item, form) {
 	// 保存到 defaultValue
 	return item.defaultValue = timeDifferenceInHours;
 }
+let workingPeriods = []
+let workDays = [] // 0为周日
+function setAttendanceSegment() {
+	getAttendanceSegment(userStore.user.unitId).then(({returnParams}) => {
+		const workTime = returnParams[0].work_time.split(';')
+		for (const time of workTime) {
+			if (time == '') continue
+			const times = time.split(',')
+			const obj = {
+				start: times[0],
+				end: times[1]
+			}
+			workingPeriods.push(obj)
+		}
+		if (workingPeriods.length == 0) {
+			workingPeriods = [
+				{ start: "09:00", end: "12:00" }, // 上午
+				{ start: "13:30", end: "17:30" }, // 下午
+			]
+		}
+		if (workDays.length == 0) {
+			workDays = [1,2,3,4,5,6] // 0为周日
+		}
+	})
+}
+function calculateWorkingHours(startTime, endTime, type) {
+	// 将时间字符串解析为分钟数
+	const formatTime = (timeString) => {
+		const [hours, minutes] = timeString.split(":").map(Number)
+		return hours * 60 + minutes
+	};
+	// 计算两个时间段的重叠部分
+	const calculateOverlap = (start1, end1, start2, end2) => {
+		const overlapStart = Math.max(start1, start2)
+		const overlapEnd = Math.min(end1, end2)
+		return Math.max(0, overlapEnd - overlapStart) // 如果无重叠返回 0
+	};
+	// 将 Date 转化为当天的分钟数
+	const dateToMinutes = (date) => date.getHours() * 60 + date.getMinutes()
+	// 判断日期是否是工作日
+	const isRestdays = (date) => !workDays.includes(date.getDay())
+	// 确保 startTime 和 endTime 是 Date 类型
+	if (!(startTime instanceof Date) || !(endTime instanceof Date)) {
+		throw new Error("startTime 和 endTime 必须是 Date 类型")
+	}
+
+	// 将时间范围分解为每天的计算
+	const startDate = new Date(startTime)
+	const endDate = new Date(endTime)
+	startDate.setHours(0, 0, 0, 0)
+	endDate.setHours(0, 0, 0, 0)
+
+	let totalMinutes = 0
+
+	// 遍历时间范围的每一天
+	      for (
+	        let currentDate = new Date(startDate);
+	        currentDate <= endDate;
+	        currentDate.setDate(currentDate.getDate() + 1)
+	      ) {
+	        // 如果当前日期不是工作日,跳过
+	        if (isRestdays(currentDate)) continue;
+	
+	        const isStartDay = currentDate.getTime() === startDate.getTime();
+	        const isEndDay = currentDate.getTime() === endDate.getTime();
+	
+	        // 当天的起始和结束时间
+	        const dayStart = isStartDay ? dateToMinutes(startTime) : 0;
+	        const dayEnd = isEndDay ? dateToMinutes(endTime) : 1440; // 1440 = 24 * 60
+					// TODO 改为配置选择
+	        if (type === "请假") {
+	          // 计算工作时间段内的时间
+	          workingPeriods.forEach((period) => {
+	            const periodStart = formatTime(period.start);
+	            const periodEnd = formatTime(period.end);
+	            totalMinutes += calculateOverlap(dayStart, dayEnd, periodStart, periodEnd);
+	          });
+	        } else if (type === "加班") {
+	          // 计算非工作时间段的时间
+	          let nonWorkingMinutes = 0;
+	          let current = dayStart;
+	          for (const period of workingPeriods) {
+	            const periodStart = formatTime(period.start);
+	            const periodEnd = formatTime(period.end);
+	
+	            if (current < periodStart) {
+	              nonWorkingMinutes += calculateOverlap(current, dayEnd, current, periodStart);
+	            }
+	            current = Math.max(current, periodEnd);
+	          }
+	          if (current < dayEnd) {
+	            nonWorkingMinutes += dayEnd - current;
+	          }
+	          totalMinutes += nonWorkingMinutes;
+	        }
+	      }
+	
+	      // 转换为小时
+	      return totalMinutes / 60;
+}
 
 function setTimeRange(e) {
 	// console.log('setTimeRange', e)
@@ -440,9 +552,10 @@ function getValidateRules() {
 					{
 						required: true,
 					},
-					{
-						formatTypeDict: formatTypeDict[elem.fieldType.value] || 'string',
-					}
+					// {
+						// 类型判断 数值型使用string会出错
+						// formatTypeDict: formatTypeDict[elem.fieldType.value] || 'string',
+					// }
 				],
 				label: elem.elementName.slice(3)
 			};
@@ -458,9 +571,9 @@ function getValidateRules() {
 					{
 						required: '1' == elem.noNull,
 					},
-					{
-						format: formatTypeDict[elem.fieldType] || 'string',
-					}
+					// {
+					// 	format: formatTypeDict[elem.fieldType] || 'string',
+					// }
 				],
 				label: elem.elementName
 			};