| | |
| | | const getAttendanceTagType = (status) => { |
| | | const tagMap = { |
| | | normal: 'success', |
| | | late: 'warning', |
| | | late: 'warning', |
| | | early: 'warning', |
| | | absent: 'danger' |
| | | } |
| | |
| | | const labelMap = { |
| | | normal: '正常', |
| | | late: '迟到', |
| | | early: '早退', |
| | | early: '早退', |
| | | absent: '缺勤' |
| | | } |
| | | return labelMap[status] || status |
| | |
| | | // 打卡记录过滤功能 |
| | | 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 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: '' |
| | | // 尝试从localStorage读取已缓存的数据 |
| | | const cachedData = localStorage.getItem('attendanceMockData') |
| | | const cacheDate = localStorage.getItem('attendanceMockDataDate') |
| | | |
| | | // 如果有缓存数据且是当天生成的,直接使用 |
| | | const today = new Date().toISOString().split('T')[0] |
| | | if (cachedData && cacheDate === today) { |
| | | try { |
| | | attendanceData.value = JSON.parse(cachedData) |
| | | filteredAttendanceData.value = attendanceData.value |
| | | console.log('使用缓存的考勤数据') |
| | | return |
| | | } catch (e) { |
| | | console.warn('缓存数据解析失败,重新生成') |
| | | } |
| | | } |
| | | |
| | | // 员工列表 |
| | | const employees = [ |
| | | { name: '朱倩倩', department: '技术部' }, |
| | | { name: '苏阳', department: '市场部' }, |
| | | { name: '林小梅', department: '人事部' }, |
| | | { name: '范海飞', department: '财务部' }, |
| | | { name: '严故培', department: '技术部' }, |
| | | { name: '汪转梅', department: '运营部' }, |
| | | { name: '张坤', department: '设计部' }, |
| | | { name: '张君', department: '销售部' }, |
| | | { name: '杨虎', department: '行政部' }, |
| | | { name: '拜天乐', department: '客服部' } |
| | | ] |
| | | |
| | | |
| | | // 2025年法定节假日 |
| | | const holidays = [ |
| | | // 元旦 |
| | | '2025-01-01', |
| | | // 春节 (1月28日-2月4日) |
| | | '2025-01-28', '2025-01-29', '2025-01-30', '2025-01-31', |
| | | '2025-02-01', '2025-02-02', '2025-02-03', '2025-02-04', |
| | | // 清明节 (4月4日-6日) |
| | | '2025-04-04', '2025-04-05', '2025-04-06', |
| | | // 劳动节 (5月1日-5日) |
| | | '2025-05-01', '2025-05-02', '2025-05-03', '2025-05-04', '2025-05-05', |
| | | // 端午节 (5月31日-6月2日) |
| | | '2025-05-31' |
| | | ] |
| | | |
| | | const holidaySet = new Set(holidays) |
| | | |
| | | // 判断是否为工作日(单休,周日休息) |
| | | const isWorkday = (dateStr) => { |
| | | if (holidaySet.has(dateStr)) return false |
| | | const date = new Date(dateStr) |
| | | const dayOfWeek = date.getDay() |
| | | return dayOfWeek !== 0 // 周日休息 |
| | | } |
| | | |
| | | // 生成日期范围内的所有工作日 |
| | | const startDate = new Date('2025-01-01') |
| | | const endDate = new Date('2025-05-25') |
| | | const workdays = [] |
| | | |
| | | for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) { |
| | | const dateStr = d.toISOString().split('T')[0] |
| | | if (isWorkday(dateStr)) { |
| | | workdays.push(dateStr) |
| | | } |
| | | } |
| | | |
| | | // 生成打卡记录 |
| | | const mockData = [] |
| | | let id = 1 |
| | | |
| | | // 随机生成打卡时间(全部正常) |
| | | const generateClockTime = (isClockIn) => { |
| | | if (isClockIn) { |
| | | // 上班打卡:8:50-9:00之间(全部正常) |
| | | const minutes = Math.floor(Math.random() * 11) + 50 // 50-60分钟 |
| | | const hour = 8 |
| | | const min = minutes |
| | | return `${hour.toString().padStart(2, '0')}:${min.toString().padStart(2, '0')}:00` |
| | | } else { |
| | | // 下班打卡:18:00-18:30之间(全部正常) |
| | | const minutes = Math.floor(Math.random() * 31) // 0-30分钟 |
| | | const hour = 18 |
| | | return `${hour.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:00` |
| | | } |
| | | } |
| | | |
| | | // 计算工作时长 |
| | | const calculateWorkHours = (clockIn, clockOut) => { |
| | | if (!clockIn || !clockOut) return '0h' |
| | | const [inH, inM] = clockIn.split(':').map(Number) |
| | | const [outH, outM] = clockOut.split(':').map(Number) |
| | | const inMinutes = inH * 60 + inM |
| | | const outMinutes = outH * 60 + outM |
| | | const diff = outMinutes - inMinutes |
| | | const hours = Math.floor(diff / 60) |
| | | const mins = diff % 60 |
| | | return `${hours}.${Math.round(mins / 6)}h` |
| | | } |
| | | |
| | | // 为每个员工的每个工作日生成打卡记录 |
| | | employees.forEach(employee => { |
| | | workdays.forEach(date => { |
| | | // 随机决定是否请假(1%概率)或加班(10%概率) |
| | | const random = Math.random() |
| | | let clockInTime = '' |
| | | let clockOutTime = '' |
| | | let status = 'normal' |
| | | let remark = '' |
| | | |
| | | if (random < 0.01) { |
| | | // 请假(1%概率) |
| | | remark = Math.random() < 0.5 ? '请病假' : '请事假' |
| | | status = 'absent' |
| | | } else { |
| | | clockInTime = generateClockTime(true) |
| | | clockOutTime = generateClockTime(false) |
| | | status = 'normal' |
| | | |
| | | // 加班备注(10%概率) |
| | | if (Math.random() < 0.1) { |
| | | remark = '加班' |
| | | } |
| | | } |
| | | |
| | | mockData.push({ |
| | | id: id++, |
| | | employeeName: employee.name, |
| | | department: employee.department, |
| | | date: date, |
| | | clockInTime: clockInTime, |
| | | clockOutTime: clockOutTime, |
| | | workHours: calculateWorkHours(clockInTime, clockOutTime), |
| | | status: status, |
| | | location: '公司总部', |
| | | remark: remark |
| | | }) |
| | | }) |
| | | }) |
| | | |
| | | // 按日期排序 |
| | | mockData.sort((a, b) => { |
| | | if (a.date !== b.date) return a.date.localeCompare(b.date) |
| | | return a.id - b.id |
| | | }) |
| | | |
| | | // 缓存数据到localStorage |
| | | localStorage.setItem('attendanceMockData', JSON.stringify(mockData)) |
| | | localStorage.setItem('attendanceMockDataDate', today) |
| | | |
| | | attendanceData.value = mockData |
| | | filteredAttendanceData.value = mockData |
| | | console.log('生成新的考勤数据并缓存') |
| | | } |
| | | |
| | | // 删除项目 |