From 1f55a1dc8273985685b79604dc9d60b908319934 Mon Sep 17 00:00:00 2001 From: gaoluyang <2820782392@qq.com> Date: 星期二, 16 九月 2025 16:21:08 +0800 Subject: [PATCH] 打卡记录页面 --- src/views/collaborativeApproval/attendanceManagement/index.vue | 401 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 361 insertions(+), 40 deletions(-) diff --git a/src/views/collaborativeApproval/attendanceManagement/index.vue b/src/views/collaborativeApproval/attendanceManagement/index.vue index 245d3b5..f6a3e3c 100644 --- a/src/views/collaborativeApproval/attendanceManagement/index.vue +++ b/src/views/collaborativeApproval/attendanceManagement/index.vue @@ -5,7 +5,7 @@ <el-tab-pane label="鍋囨湡璁剧疆" name="holiday"> <div class="tab-content"> <el-button type="primary" @click="openDialog('holiday', 'add')">鏂板鍋囨湡</el-button> - + <el-table :data="holidayData" border style="width: 100%; margin-top: 20px;"> <el-table-column prop="name" label="鍋囨湡鍚嶇О" /> <el-table-column prop="type" label="鍋囨湡绫诲瀷"> @@ -37,7 +37,7 @@ <el-tab-pane label="骞村亣璁剧疆" name="annual"> <div class="tab-content"> <el-button type="primary" @click="openDialog('annual', 'add')">鏂板骞村亣瑙勫垯</el-button> - + <el-table :data="annualData" border style="width: 100%; margin-top: 20px;"> <el-table-column prop="employeeType" label="鍛樺伐绫诲瀷"> <template #default="scope"> @@ -68,7 +68,7 @@ <el-tab-pane label="鍔犵彮璁剧疆" name="overtime"> <div class="tab-content"> <el-button type="primary" @click="openDialog('overtime', 'add')">鏂板鍔犵彮瑙勫垯</el-button> - + <el-table :data="overtimeData" border style="width: 100%; margin-top: 20px;"> <el-table-column prop="name" label="瑙勫垯鍚嶇О" /> <el-table-column prop="type" label="鍔犵彮绫诲瀷" > @@ -100,7 +100,7 @@ <el-tab-pane label="涓婄彮鏃堕棿璁剧疆" name="worktime"> <div class="tab-content"> <el-button type="primary" @click="openDialog('worktime', 'add')">鏂板鏃堕棿娈�</el-button> - + <el-table :data="worktimeData" border style="width: 100%; margin-top: 20px;"> <el-table-column prop="name" label="鏃堕棿娈靛悕绉�" /> <el-table-column prop="startTime" label="涓婄彮鏃堕棿"/> @@ -129,6 +129,52 @@ </el-table> </div> </el-tab-pane> + + <!-- 鎵撳崱璁板綍 --> + <el-tab-pane label="鎵撳崱璁板綍" name="attendance"> + <div class="tab-content"> + <div style="margin-bottom: 20px;"> + <el-date-picker + v-model="attendanceDate" + type="date" + placeholder="閫夋嫨鏃ユ湡" + format="YYYY-MM-DD" + value-format="YYYY-MM-DD" + style="margin-right: 10px;" + @change="filterAttendanceData" + /> + <el-select + v-model="attendanceStatus" + placeholder="閫夋嫨鐘舵��" + style="width: 120px; margin-right: 10px;" + @change="filterAttendanceData" + > + <el-option label="鍏ㄩ儴" value="" /> + <el-option label="姝e父" value="normal" /> + <el-option label="杩熷埌" value="late" /> + <el-option label="鏃╅��" value="early" /> + <el-option label="缂哄嫟" value="absent" /> + </el-select> + <el-button type="primary" @click="exportAttendance">瀵煎嚭璁板綍</el-button> + </div> + + <el-table :data="filteredAttendanceData" border style="width: 100%;"> + <el-table-column prop="employeeName" label="鍛樺伐濮撳悕" width="120" /> + <el-table-column prop="department" label="閮ㄩ棬" width="120" /> + <el-table-column prop="date" label="鏃ユ湡" width="120" /> + <el-table-column prop="clockInTime" label="涓婄彮鎵撳崱" width="120" /> + <el-table-column prop="clockOutTime" label="涓嬬彮鎵撳崱" width="120" /> + <el-table-column prop="workHours" label="宸ヤ綔鏃堕暱" width="100" align="center" /> + <el-table-column prop="status" label="鐘舵��" width="100" align="center"> + <template #default="scope"> + <el-tag :type="getAttendanceTagType(scope.row.status)">{{ getAttendanceStatusLabel(scope.row.status) }}</el-tag> + </template> + </el-table-column> + <el-table-column prop="location" label="鎵撳崱鍦扮偣" width="150" /> + <el-table-column prop="remark" label="澶囨敞" min-width="150" /> + </el-table> + </div> + </el-tab-pane> </el-tabs> <!-- 閫氱敤寮圭獥 --> @@ -137,14 +183,14 @@ <el-form-item label="鍚嶇О" prop="name" v-if="currentType !== 'annual'"> <el-input v-model="form.name" placeholder="璇疯緭鍏ュ悕绉�" /> </el-form-item> - + <el-form-item label="绫诲瀷" prop="type" v-if="currentType === 'holiday' || currentType === 'overtime'"> <el-select v-model="form.type" placeholder="璇烽�夋嫨绫诲瀷" style="width: 100%"> - <el-option - v-for="option in getTypeOptions()" - :key="option.value" - :label="option.label" - :value="option.value" + <el-option + v-for="option in getTypeOptions()" + :key="option.value" + :label="option.label" + :value="option.value" /> </el-select> </el-form-item> @@ -154,11 +200,11 @@ <!-- <el-option label="姝e紡鍛樺伐" value="regular" /> <el-option label="璇曠敤鏈熷憳宸�" value="probation" /> <el-option label="瀹炰範鐢�" value="intern" /> --> - <el-option - v-for="option in getTypeOptions()" - :key="option.value" - :label="option.label" - :value="option.value" + <el-option + v-for="option in getTypeOptions()" + :key="option.value" + :label="option.label" + :value="option.value" /> </el-select> </el-form-item> @@ -201,7 +247,7 @@ @change="validateTimeField('startTime')" /> </el-form-item> - + <el-form-item label="缁撴潫鏃堕棿" prop="endTime" v-if="currentType === 'overtime'"> <el-time-picker v-model="form.endTime" @@ -254,7 +300,7 @@ </el-radio-group> </el-form-item> </el-form> - + <template #footer> <span class="dialog-footer"> <el-button @click="dialogVisible = false">鍙栨秷</el-button> @@ -290,6 +336,12 @@ const overtimeData = ref([]) const worktimeData = ref([]) +// 鎵撳崱璁板綍鐩稿叧鏁版嵁 +const attendanceData = ref([]) +const filteredAttendanceData = ref([]) +const attendanceDate = ref('') +const attendanceStatus = ref('') + // 琛ㄥ崟鏁版嵁 const form = reactive({ name: '', @@ -322,9 +374,9 @@ workYears: [{ required: true, message: '璇疯緭鍏ュ伐浣滃勾闄�', trigger: 'blur' }], annualDays: [{ required: true, message: '璇疯緭鍏ュ勾鍋囧ぉ鏁�', trigger: 'blur' }], maxCarryOver: [{ required: true, message: '璇疯緭鍏ユ渶澶х粨杞ぉ鏁�', trigger: 'blur' }], - startTime: [{ - required: true, - message: '璇烽�夋嫨寮�濮嬫椂闂�', + startTime: [{ + required: true, + message: '璇烽�夋嫨寮�濮嬫椂闂�', trigger: 'change', validator: (rule, value, callback) => { if (!value) { @@ -334,9 +386,9 @@ } } }], - endTime: [{ - required: true, - message: '璇烽�夋嫨缁撴潫鏃堕棿', + endTime: [{ + required: true, + message: '璇烽�夋嫨缁撴潫鏃堕棿', trigger: 'change', validator: (rule, value, callback) => { if (!value) { @@ -346,9 +398,9 @@ } } }], - workStartTime: [{ - required: true, - message: '璇烽�夋嫨涓婄彮鏃堕棿', + workStartTime: [{ + required: true, + message: '璇烽�夋嫨涓婄彮鏃堕棿', trigger: 'change', validator: (rule, value, callback) => { if (!value) { @@ -358,9 +410,9 @@ } } }], - workEndTime: [{ - required: true, - message: '璇烽�夋嫨涓嬬彮鏃堕棿', + workEndTime: [{ + required: true, + message: '璇烽�夋嫨涓嬬彮鏃堕棿', trigger: 'change', validator: (rule, value, callback) => { if (!value) { @@ -389,6 +441,27 @@ regular: '姝e紡鍛樺伐', probation: '璇曠敤鏈熷憳宸�', intern: '瀹炰範鐢�' } return labelMap[type] || type +} + +// 鎵撳崱璁板綍鐩稿叧宸ュ叿鍑芥暟 +const getAttendanceTagType = (status) => { + const tagMap = { + normal: 'success', + late: 'warning', + early: 'warning', + absent: 'danger' + } + return tagMap[status] || 'info' +} + +const getAttendanceStatusLabel = (status) => { + const labelMap = { + normal: '姝e父', + late: '杩熷埌', + early: '鏃╅��', + absent: '缂哄嫟' + } + return labelMap[status] || status } const getTypeOptions = () => { @@ -424,12 +497,12 @@ const end = new Date(form.dateRange[1]) form.startDate = start.toISOString().split('T')[0] form.endDate = end.toISOString().split('T')[0] - + if (isNaN(start.getTime()) || isNaN(end.getTime())) { console.warn('鏃犳晥鐨勬棩鏈熸牸寮�') return } - + const diffTime = Math.abs(end - start) const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1 form.days = diffDays @@ -470,7 +543,7 @@ try { currentType.value = type currentAction.value = action - + if (action === 'add') { dialogTitle.value = `鏂板${getTypeName(type)}` currentEditId.value = '' @@ -480,7 +553,7 @@ currentEditId.value = row.id fillForm(row) } - + dialogVisible.value = true } catch (error) { console.error('鎵撳紑寮圭獥澶辫触:', error) @@ -568,15 +641,15 @@ ElMessage.error('琛ㄥ崟寮曠敤涓嶅瓨鍦�') return } - + await formRef.value.validate() - + if (currentAction.value === 'add') { addItem() } else if (currentAction.value === 'edit') { editItem() } - + dialogVisible.value = false ElMessage.success('鎿嶄綔鎴愬姛') } catch (error) { @@ -670,7 +743,7 @@ const editItem = () => { let dataArray let index - + if (currentType.value === 'holiday') { const params = { id: currentEditId.value, @@ -729,7 +802,7 @@ // dataArray = overtimeData.value // index = dataArray.findIndex(item => item.id === currentEditId.value) // if (index > -1) { - // dataArray[index] = { + // dataArray[index] = { // ...dataArray[index], // name: form.name, // type: form.type, @@ -760,7 +833,7 @@ // dataArray = worktimeData.value // index = dataArray.findIndex(item => item.id === currentEditId.value) // if (index > -1) { - // dataArray[index] = { + // dataArray[index] = { // ...dataArray[index], // name: form.name, // startTime: form.workStartTime || '', @@ -771,6 +844,253 @@ // } // } } +} + +// 鎵撳崱璁板綍杩囨护鍔熻兘 +const filterAttendanceData = () => { + let filtered = attendanceData.value + + // 鎸夋棩鏈熻繃婊� + if (attendanceDate.value) { + filtered = filtered.filter(item => item.date === attendanceDate.value) + } + + // 鎸夌姸鎬佽繃婊� + if (attendanceStatus.value) { + filtered = filtered.filter(item => item.status === attendanceStatus.value) + } + + filteredAttendanceData.value = filtered +} + +// 瀵煎嚭鎵撳崱璁板綍 +const exportAttendance = () => { + ElMessage.success('瀵煎嚭鍔熻兘寮�鍙戜腑...') +} + +// 鍒濆鍖栨墦鍗¤褰曞亣鏁版嵁 +const initAttendanceData = () => { + const mockData = [ + { + id: 1, + employeeName: '闄堝織寮�', + department: '鎶�鏈儴', + date: '2025-08-15', + clockInTime: '09:00:00', + clockOutTime: '18:00:00', + workHours: '8.0h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 2, + employeeName: '鏉庨洩姊�', + department: '甯傚満閮�', + date: '2025-08-16', + clockInTime: '08:58:00', + clockOutTime: '18:05:00', + workHours: '8.12h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 3, + employeeName: '鐜嬪缓鍗�', + department: '浜轰簨閮�', + date: '2025-08-16', + clockInTime: '09:02:00', + clockOutTime: '18:00:00', + workHours: '7.97h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 4, + employeeName: '璧垫檽涓�', + department: '璐㈠姟閮�', + date: '2025-09-02', + clockInTime: '08:55:00', + clockOutTime: '18:10:00', + workHours: '8.25h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 5, + employeeName: '寮犲浗搴�', + department: '鎶�鏈儴', + date: '2025-09-02', + clockInTime: '09:00:00', + clockOutTime: '18:30:00', + workHours: '8.5h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '鍔犵彮' + }, + { + id: 6, + employeeName: '鍒樻槑杈�', + department: '杩愯惀閮�', + date: '2025-09-03', + clockInTime: '09:05:00', + clockOutTime: '18:00:00', + workHours: '7.92h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 7, + employeeName: '瀛欎附鍗�', + department: '璁捐閮�', + date: '2025-09-03', + clockInTime: '08:59:00', + clockOutTime: '18:02:00', + workHours: '8.05h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 8, + employeeName: '鍛ㄥ缓鍐�', + department: '閿�鍞儴', + date: '2025-09-04', + clockInTime: '09:15:00', + clockOutTime: '18:00:00', + workHours: '7.75h', + status: 'late', + location: '鍏徃鎬婚儴', + remark: '浜ら�氬牭濉�' + }, + { + id: 9, + employeeName: '鍚村皬鑺�', + department: '瀹㈡湇閮�', + date: '2025-09-04', + clockInTime: '09:01:00', + clockOutTime: '18:00:00', + workHours: '7.98h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 10, + employeeName: '椹枃鏉�', + department: '鎶�鏈儴', + date: '2025-09-05', + clockInTime: '08:57:00', + clockOutTime: '17:30:00', + workHours: '7.55h', + status: 'early', + location: '鍏徃鎬婚儴', + remark: '鏈夋�ヤ簨鎻愬墠绂诲紑' + }, + { + id: 11, + employeeName: '鏋楁檽涓�', + department: '琛屾斂閮�', + date: '2025-09-05', + clockInTime: '09:03:00', + clockOutTime: '18:08:00', + workHours: '8.08h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 12, + employeeName: '榛勭編鐜�', + department: '璐㈠姟閮�', + date: '2025-09-06', + clockInTime: '', + clockOutTime: '', + workHours: '0h', + status: 'absent', + location: '', + remark: '璇风梾鍋�' + }, + { + id: 13, + employeeName: '閮戞捣娑�', + department: '甯傚満閮�', + date: '2025-08-14', + clockInTime: '09:00:00', + clockOutTime: '18:00:00', + workHours: '8.0h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 14, + employeeName: '璋附濞�', + department: '浜轰簨閮�', + date: '2025-08-20', + clockInTime: '08:58:00', + clockOutTime: '18:03:00', + workHours: '8.08h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 15, + employeeName: '浣曞織浼�', + department: '鎶�鏈儴', + date: '2025-08-21', + clockInTime: '09:10:00', + clockOutTime: '18:00:00', + workHours: '7.83h', + status: 'late', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 16, + employeeName: '璁搁泤鑺�', + department: '璁捐閮�', + date: '2025-08-22', + clockInTime: '09:01:00', + clockOutTime: '18:00:00', + workHours: '7.98h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 17, + employeeName: '閭撳缓骞�', + department: '杩愯惀閮�', + date: '2025-09-10', + clockInTime: '08:59:00', + clockOutTime: '18:05:00', + workHours: '8.1h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + }, + { + id: 18, + employeeName: '鏇惧皬绾�', + department: '瀹㈡湇閮�', + date: '2025-09-11', + clockInTime: '09:02:00', + clockOutTime: '18:00:00', + workHours: '7.97h', + status: 'normal', + location: '鍏徃鎬婚儴', + remark: '' + } + ] + + attendanceData.value = mockData + filteredAttendanceData.value = mockData } // 鍒犻櫎椤圭洰 @@ -830,7 +1150,7 @@ ElMessage.error(err.msg); }) } - + // const index = dataArray.findIndex(item => item.id === row.id) // if (index > -1) { // dataArray.splice(index, 1) @@ -888,6 +1208,7 @@ getAnnualLeaveSettingList() getOvertimeSettingList() getWorkingHoursSettingList() + initAttendanceData() console.log('鑰冨嫟绠$悊椤甸潰鍔犺浇瀹屾垚') }) -- Gitblit v1.9.3