当前位置: 首页 > news >正文

Java全栈项目 - 智能考勤管理系统

项目介绍

智能考勤管理系统是一个基于 Java 全栈技术开发的现代化企业考勤解决方案。该系统采用前后端分离架构,实现了员工考勤、请假管理、统计分析等核心功能,旨在帮助企业提高人力资源管理效率。

技术栈

后端技术

  • Spring Boot 2.6.x
  • Spring Security
  • MyBatis-Plus
  • MySQL 8.0
  • Redis
  • JWT

前端技术

  • Vue 3
  • Element Plus
  • Axios
  • Echarts
  • Vite

核心功能

1. 考勤管理

  • 上下班打卡
  • 加班申请
  • 外出登记
  • 考勤规则设置
  • 异常考勤处理

2. 请假管理

  • 请假申请
  • 请假审批
  • 请假类型配置
  • 假期余额查询

3. 统计分析

  • 考勤统计报表
  • 部门出勤率分析
  • 加班统计
  • 请假趋势分析

4. 系统管理

  • 用户管理
  • 角色权限
  • 部门管理
  • 系统配置

系统架构

├── smart-attendance-system
│   ├── attendance-admin        # 后台管理服务
│   ├── attendance-api         # 接口服务
│   ├── attendance-common      # 公共模块
│   ├── attendance-model       # 数据模型
│   └── attendance-web         # 前端项目

数据库设计

核心表结构

-- 员工表
CREATE TABLE sys_employee (id BIGINT PRIMARY KEY,emp_no VARCHAR(32),name VARCHAR(50),department_id BIGINT,position VARCHAR(50),status TINYINT,create_time DATETIME
);-- 考勤记录表
CREATE TABLE attendance_record (id BIGINT PRIMARY KEY,emp_id BIGINT,check_in_time DATETIME,check_out_time DATETIME,status TINYINT,type TINYINT,remark VARCHAR(255)
);-- 请假记录表
CREATE TABLE leave_record (id BIGINT PRIMARY KEY,emp_id BIGINT,leave_type TINYINT,start_time DATETIME,end_time DATETIME,reason VARCHAR(255),status TINYINT
);

项目亮点

1. 人脸识别打卡

  • 集成人脸识别SDK
  • 活体检测
  • 高精度识别算法

2. 智能定位打卡

  • 基于地理围栏技术
  • 支持移动端GPS定位
  • 异地打卡预警

3. 灵活的考勤规则

  • 多班次管理
  • 弹性工时
  • 节假日智能排班
  • 加班规则配置

4. 数据可视化

  • 直观的统计图表
  • 多维度数据分析
  • 自定义报表导出

性能优化

1. 缓存优化

@Cacheable(value = "attendance", key = "#empId")
public AttendanceDTO getAttendanceInfo(Long empId) {// 获取考勤信息逻辑
}

2. SQL优化

@Select("SELECT DATE_FORMAT(check_in_time,'%Y-%m-%d') as date, " +"COUNT(*) as count FROM attendance_record " +"WHERE emp_id = #{empId} " +"GROUP BY DATE_FORMAT(check_in_time,'%Y-%m-%d')")
List<StatisticsDTO> getAttendanceStatistics(Long empId);

3. 接口性能

  • 接口响应时间控制在200ms以内
  • 使用线程池处理异步任务
  • 批量操作优化

安全性设计

1. 身份认证

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/api/auth/**").permitAll().anyRequest().authenticated().and().addFilter(new JwtAuthenticationFilter(authenticationManager()));}
}

2. 数据安全

  • 敏感数据加密
  • SQL注入防护
  • XSS防御

部署方案

1. 容器化部署

version: '3'
services:attendance-api:image: attendance-api:latestports:- "8080:8080"environment:- SPRING_PROFILES_ACTIVE=prod

2. 高可用方案

  • 服务器集群
  • 负载均衡
  • 数据库主从复制

项目总结

智能考勤管理系统采用现代化的技术栈和架构设计,实现了企业考勤管理的智能化和自动化。系统具有良好的可扩展性和维护性,为企业提供了一个高效、可靠的考勤解决方案。

未来展望

  • 引入机器学习算法,实现考勤预测
  • 集成企业微信等第三方平台
  • 开发移动端应用
  • 支持多租户架构

智能考勤系统 - 考勤与请假管理模块详解

一、考勤管理模块

1. 上下班打卡

1.1 打卡记录表设计
CREATE TABLE attendance_record (id BIGINT PRIMARY KEY,emp_id BIGINT COMMENT '员工ID',check_type TINYINT COMMENT '打卡类型:1-上班,2-下班',check_time DATETIME COMMENT '打卡时间',check_location VARCHAR(255) COMMENT '打卡地点',device_info VARCHAR(100) COMMENT '设备信息',face_image VARCHAR(255) COMMENT '人脸照片URL',status TINYINT COMMENT '状态:1-正常,2-迟到,3-早退',remark VARCHAR(255) COMMENT '备注',create_time DATETIME,FOREIGN KEY (emp_id) REFERENCES sys_employee(id)
);
1.2 打卡服务实现
@Service
@Slf4j
public class CheckInService {@Autowiredprivate AttendanceRuleService ruleService;@Autowiredprivate FaceRecognitionService faceService;@Autowiredprivate LocationService locationService;@Transactionalpublic CheckInResult doCheckIn(CheckInDTO checkInDTO) {// 1. 人脸识别验证boolean faceValid = faceService.verify(checkInDTO.getEmpId(), checkInDTO.getFaceImage());if (!faceValid) {throw new BusinessException("人脸识别失败");}// 2. 位置验证boolean locationValid = locationService.verifyLocation(checkInDTO.getLocation(),checkInDTO.getEmpId());if (!locationValid) {throw new BusinessException("不在打卡范围内");}// 3. 判断打卡类型和状态AttendanceRule rule = ruleService.getEmployeeRule(checkInDTO.getEmpId());CheckInStatus status = calculateStatus(checkInDTO.getCheckTime(), rule);// 4. 保存打卡记录AttendanceRecord record = new AttendanceRecord();record.setEmpId(checkInDTO.getEmpId());record.setCheckType(checkInDTO.getCheckType());record.setCheckTime(checkInDTO.getCheckTime());record.setStatus(status.getCode());attendanceMapper.insert(record);// 5. 返回打卡结果return new CheckInResult(status, record.getId());}private CheckInStatus calculateStatus(LocalDateTime checkTime, AttendanceRule rule) {LocalTime time = checkTime.toLocalTime();if (isCheckIn) {if (time.isAfter(rule.getLateTime())) {return CheckInStatus.LATE;}} else {if (time.isBefore(rule.getEarlyLeaveTime())) {return CheckInStatus.EARLY_LEAVE;}}return CheckInStatus.NORMAL;}
}
1.3 打卡界面实现
<template><div class="check-in-container"><div class="camera-container"><video ref="video" class="camera-preview"></video><canvas ref="canvas" style="display: none;"></canvas></div><div class="check-in-info"><div class="time-display">{{ currentTime }}</div><el-button type="primary" size="large" @click="handleCheckIn":loading="checking">{{ checkType === 1 ? '上班打卡' : '下班打卡' }}</el-button><div class="location-info">当前位置:{{ location }}</div></div><!-- 打卡结果弹窗 --><el-dialogtitle="打卡结果":visible.sync="showResult"width="300px"center><div class="check-result"><i :class="resultIcon"></i><span>{{ resultMessage }}</span><div class="check-time">{{ checkTime }}</div></div></el-dialog></div>
</template><script>
export default {data() {return {checking: false,currentTime: '',location: '',checkType: this.getCheckType(),showResult: false,resultMessage: '',stream: null}},methods: {async initCamera() {try {this.stream = await navigator.mediaDevices.getUserMedia({video: true});this.$refs.video.srcObject = this.stream;} catch (error) {this.$message.error('摄像头启动失败');}},getCheckType() {const now = new Date();const hour = now.getHours();return hour < 12 ? 1 : 2; // 12点前为上班打卡},async handleCheckIn() {try {this.checking = true;// 1. 获取人脸图片const faceImage = this.captureFace();// 2. 获取位置信息const location = await this.getCurrentLocation();// 3. 提交打卡const result = await this.$api.attendance.checkIn({checkType: this.checkType,faceImage,location,checkTime: new Date()});// 4. 显示结果this.showCheckResult(result);} catch (error) {this.$message.error(error.message);} finally {this.checking = false;}},captureFace() {const canvas = this.$refs.canvas;const video = this.$refs.video;const context = canvas.getContext('2d');canvas.width = video.videoWidth;canvas.height = video.videoHeight;context.drawImage(video, 0, 0);return canvas.toDataURL('image/jpeg');}},mounted() {this.initCamera();// 更新当前时间setInterval(() => {this.currentTime = new Date().toLocaleTimeString();}, 1000);},beforeDestroy() {// 关闭摄像头if (this.stream) {this.stream.getTracks().forEach(track => track.stop());}}
}
</script>

2. 加班申请

2.1 加班申请表
CREATE TABLE overtime_application (id BIGINT PRIMARY KEY,emp_id BIGINT,start_time DATETIME,end_time DATETIME,overtime_type TINYINT COMMENT '加班类型:1-工作日,2-周末,3-节假日',reason VARCHAR(500),status TINYINT COMMENT '状态:0-待审批,1-已通过,2-已拒绝',approver_id BIGINT,approve_time DATETIME,approve_remark VARCHAR(255),create_time DATETIME
);
2.2 加班服务实现
@Service
public class OvertimeService {@Autowiredprivate WorkflowService workflowService;public void applyOvertime(OvertimeDTO overtimeDTO) {// 1. 验证加班时长validateOvertimeHours(overtimeDTO);// 2. 创建加班申请OvertimeApplication application = new OvertimeApplication();BeanUtils.copyProperties(overtimeDTO, application);application.setStatus(ApprovalStatus.PENDING.getCode());overtimeMapper.insert(application);// 3. 发起工作流workflowService.startProcess("overtime_process",application.getId(),overtimeDTO.getEmpId());}private void validateOvertimeHours(OvertimeDTO overtime) {// 计算加班时长long hours = ChronoUnit.HOURS.between(overtime.getStartTime(), overtime.getEndTime());// 获取员工当月已加班时长int monthlyHours = overtimeMapper.getMonthlyHours(overtime.getEmpId(),overtime.getStartTime());// 验证是否超过月度限制if (monthlyHours + hours > MAX_MONTHLY_HOURS) {throw new BusinessException("超过月度加班时长限制");}}
}

3. 外出登记

3.1 外出登记表
CREATE TABLE business_trip (id BIGINT PRIMARY KEY,emp_id BIGINT,start_time DATETIME,end_time DATETIME,destination VARCHAR(255),purpose VARCHAR(500),status TINYINT,contact_info VARCHAR(100),create_time DATETIME
);
3.2 外出服务实现
@Service
public class BusinessTripService {public void register(BusinessTripDTO tripDTO) {// 1. 检查是否有重叠的外出记录boolean hasOverlap = checkTimeOverlap(tripDTO.getEmpId(),tripDTO.getStartTime(),tripDTO.getEndTime());if (hasOverlap) {throw new BusinessException("当前时间段已有外出记录");}// 2. 保存外出记录BusinessTrip trip = new BusinessTrip();BeanUtils.copyProperties(tripDTO, trip);tripMapper.insert(trip);// 3. 更新考勤规则attendanceRuleService.addException(tripDTO.getEmpId(),tripDTO.getStartTime(),tripDTO.getEndTime(),AttendanceExceptionType.BUSINESS_TRIP);}
}

4. 考勤规则设置

4.1 考勤规则表
CREATE TABLE attendance_rule (id BIGINT PRIMARY KEY,rule_name VARCHAR(50),work_start_time TIME,work_end_time TIME,late_minutes INT COMMENT '迟到判定分钟数',early_leave_minutes INT COMMENT '早退判定分钟数',work_hours DECIMAL(4,1) COMMENT '每日工时',flexible_time INT COMMENT '弹性工作时间(分钟)',dept_id BIGINT COMMENT '适用部门',status TINYINT,create_time DATETIME
);
4.2 规则配置服务
@Service
public class AttendanceRuleService {@Cacheable(value = "attendance_rule", key = "#deptId")public AttendanceRule getDeptRule(Long deptId) {return ruleMapper.selectByDeptId(deptId);}@CacheEvict(value = "attendance_rule", key = "#rule.deptId")public void updateRule(AttendanceRule rule) {validateRule(rule);ruleMapper.updateById(rule);}private void validateRule(AttendanceRule rule) {// 验证工作时间设置if (rule.getWorkEndTime().isBefore(rule.getWorkStartTime())) {throw new BusinessException("下班时间不能早于上班时间");}// 验证弹性工作时间if (rule.getFlexibleTime() != null && rule.getFlexibleTime() > MAX_FLEXIBLE_TIME) {throw new BusinessException("弹性工作时间超出限制");}}
}

5. 异常考勤处理

5.1 异常考勤表
CREATE TABLE attendance_exception (id BIGINT PRIMARY KEY,emp_id BIGINT,exception_date DATE,exception_type TINYINT COMMENT '异常类型:1-漏打卡,2-迟到,3-早退',handle_status TINYINT COMMENT '处理状态',handle_result VARCHAR(255),handle_time DATETIME,handler_id BIGINT,create_time DATETIME
);
5.2 异常处理服务
@Service
public class ExceptionHandleService {@Asyncpublic void handleException(AttendanceException exception) {// 1. 判断异常类型switch (exception.getExceptionType()) {case MISSING_CHECK:handleMissingCheck(exception);break;case LATE:handleLate(exception);break;case EARLY_LEAVE:handleEarlyLeave(exception);break;}// 2. 发送通知notificationService.sendExceptionNotice(exception);// 3. 更新处理状态exceptionMapper.updateStatus(exception.getId(),ExceptionStatus.HANDLED);}private void handleMissingCheck(AttendanceException exception) {// 检查是否有相关的请假或外出记录List<LeaveRecord> leaveRecords = leaveMapper.findByEmpAndDate(exception.getEmpId(), exception.getExceptionDate());if (!leaveRecords.isEmpty()) {// 有请假记录,标记为已确认exception.setHandleResult("已确认请假");return;}// 发起补卡申请createSupplementaryApplication(exception);}
}

二、请假管理模块

1. 请假申请

1.1 请假记录表
CREATE TABLE leave_record (id BIGINT PRIMARY KEY,emp_id BIGINT,leave_type TINYINT COMMENT '请假类型',start_time DATETIME,end_time DATETIME,duration DECIMAL(5,1) COMMENT '请假时长(天)',reason VARCHAR(500),status TINYINT COMMENT '状态:0-待审批,1-已通过,2-已拒绝',approver_id BIGINT,approve_time DATETIME,approve_remark VARCHAR(255),attachment_url VARCHAR(255) COMMENT '附件URL',create_time DATETIME
);
1.2 请假服务实现
@Service
public class LeaveService {@Autowiredprivate LeaveBalanceService balanceService;@Autowiredprivate WorkflowService workflowService;@Transactionalpublic void applyLeave(LeaveApplicationDTO leaveDTO) {// 1. 校验请假时长validateLeaveDuration(leaveDTO);// 2. 检查假期余额checkLeaveBalance(leaveDTO.getEmpId(),leaveDTO.getLeaveType(),leaveDTO.getDuration());// 3. 创建请假记录LeaveRecord record = new LeaveRecord();BeanUtils.copyProperties(leaveDTO, record);record.setStatus(ApprovalStatus.PENDING.getCode());leaveMapper.insert(record);// 4. 发起工作流workflowService.startProcess("leave_process",record.getId(),leaveDTO.getEmpId());}private void checkLeaveBalance(Long empId, LeaveType leaveType, BigDecimal duration) {LeaveBalance balance = balanceService.getBalance(empId, leaveType);if (balance.getRemaining().compareTo(duration) < 0) {throw new BusinessException(leaveType.getName() + "假期余额不足");}}
}

2. 请假审批

2.1 审批流程配置
@Configuration
public class LeaveWorkflowConfig {@Autowiredprivate RuntimeService runtimeService;@Beanpublic ProcessEngineConfiguration leaveProcess() {return ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration().setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE).setJdbcUrl("jdbc:mysql://localhost:3306/workflow").setJdbcDriver("com.mysql.cj.jdbc.Driver").setJdbcUsername("root").setJdbcPassword("password").setActivityFontName("宋体").setLabelFontName("宋体").setAnnotationFontName("宋体");}
}
2.2 审批服务实现
@Service
public class LeaveApprovalService {@Autowiredprivate TaskService taskService;@Autowiredprivate LeaveBalanceService balanceService;@Transactionalpublic void approve(ApprovalDTO approvalDTO) {// 1. 获取请假记录LeaveRecord record = leaveMapper.selectById(approvalDTO.getRecordId());if (record == null) {throw new BusinessException("请假记录不存在");}// 2. 更新审批状态record.setStatus(approvalDTO.getApproved() ? ApprovalStatus.APPROVED.getCode(): ApprovalStatus.REJECTED.getCode());record.setApproveRemark(approvalDTO.getRemark());record.setApproveTime(LocalDateTime.now());record.setApproverId(approvalDTO.getApproverId());leaveMapper.updateById(record);// 3. 如果审批通过,扣减假期余额if (approvalDTO.getApproved()) {balanceService.deductBalance(record.getEmpId(),record.getLeaveType(),record.getDuration());}// 4. 完成工作流任务taskService.complete(approvalDTO.getTaskId());// 5. 发送通知notificationService.sendApprovalResult(record);}
}

3. 请假类型配置

3.1 请假类型表
CREATE TABLE leave_type (id BIGINT PRIMARY KEY,type_name VARCHAR(50),type_code VARCHAR(50),paid TINYINT COMMENT '是否带薪',max_duration INT COMMENT '最大请假天数',min_unit DECIMAL(2,1) COMMENT '最小请假单位(天)',need_attachment TINYINT COMMENT '是否需要附件',status TINYINT,create_time DATETIME
);
3.2 类型配置服务
@Service
public class LeaveTypeService {@Cacheable(value = "leave_type", key = "#typeId")public LeaveType getLeaveType(Long typeId) {return typeMapper.selectById(typeId);}@CacheEvict(value = "leave_type", allEntries = true)public void updateLeaveType(LeaveType leaveType) {validateLeaveType(leaveType);typeMapper.updateById(leaveType);}private void validateLeaveType(LeaveType type) {// 验证最大请假天数if (type.getMaxDuration() <= 0) {throw new BusinessException("最大请假天数必须大于0");}// 验证最小请假单位if (type.getMinUnit().compareTo(BigDecimal.ZERO) <= 0) {throw new BusinessException("最小请假单位必须大于0");}}
}

4. 假期余额查询

4.1 假期余额表
CREATE TABLE leave_balance (id BIGINT PRIMARY KEY,emp_id BIGINT,leave_type TINYINT,year INT,total_days DECIMAL(5,1),used_days DECIMAL(5,1),remaining_days DECIMAL(5,1),update_time DATETIME
);
4.2 余额查询服务
@Service
public class LeaveBalanceService {@Cacheable(value = "leave_balance", key = "#empId + ':' + #leaveType")public LeaveBalance getBalance(Long empId, LeaveType leaveType) {return balanceMapper.selectByEmpAndType(empId, leaveType);}@Transactional@CacheEvict(value = "leave_balance", key = "#empId + ':' + #leaveType")public void deductBalance(Long empId, LeaveType leaveType, BigDecimal days) {LeaveBalance balance = getBalance(empId, leaveType);if (balance == null) {throw new BusinessException("假期余额记录不存在");}// 检查余额是否足够if (balance.getRemainingDays().compareTo(days) < 0) {throw new BusinessException("假期余额不足");}// 更新已使用和剩余天数balance.setUsedDays(balance.getUsedDays().add(days));balance.setRemainingDays(balance.getRemainingDays().subtract(days));balanceMapper.updateById(balance);}// 年度假期初始化@Scheduled(cron = "0 0 0 1 1 ?")  // 每年1月1日执行public void initializeYearlyBalance() {int year = LocalDate.now().getYear();// 获取所有在职员工List<Employee> employees = employeeMapper.selectAllActive();for (Employee emp : employees) {// 初始化各类假期余额initializeBalance(emp.getId(), year);}}
}
4.3 余额查询界面
<template><div class="leave-balance"><el-card class="balance-card"><div slot="header"><span>假期余额</span><el-button type="text" @click="refreshBalance"style="float: right;">刷新</el-button></div><el-table :data="balanceList" border><el-table-column prop="typeName" label="假期类型"/><el-table-column prop="totalDays" label="总天数"/><el-table-column prop="usedDays" label="已用天数"/><el-table-column prop="remainingDays" label="剩余天数"><template slot-scope="scope"><span :class="{'warning': scope.row.remainingDays < 5,'danger': scope.row.remainingDays <= 0}">{{ scope.row.remainingDays }}</span></template></el-table-column></el-table></el-card><!-- 假期使用记录 --><el-card class="usage-card"><div slot="header"><span>假期使用记录</span></div><el-table :data="usageRecords" border><el-table-column prop="leaveType" label="假期类型"/><el-table-column prop="startTime" label="开始时间"/><el-table-column prop="endTime" label="结束时间"/><el-table-column prop="duration" label="请假天数"/><el-table-column prop="status" label="状态"><template slot-scope="scope"><el-tag :type="getStatusType(scope.row.status)">{{ getStatusText(scope.row.status) }}</el-tag></template></el-table-column></el-table></el-card></div>
</template><script>
export default {data() {return {balanceList: [],usageRecords: []}},methods: {async refreshBalance() {try {const response = await this.$api.leave.getBalance(this.userId);this.balanceList = response.data;} catch (error) {this.$message.error('获取假期余额失败');}},getStatusType(status) {const typeMap = {0: 'info',1: 'success',2: 'danger'};return typeMap[status] || 'info';},getStatusText(status) {const textMap = {0: '待审批',1: '已通过',2: '已拒绝'};return textMap[status] || '未知';}},created() {this.refreshBalance();}
}
</script><style scoped>
.leave-balance {padding: 20px;
}.balance-card {margin-bottom: 20px;
}.warning {color: #E6A23C;
}.danger {color: #F56C6C;
}
</style>

这些模块的实现涵盖了:

  • 数据库表设计
  • 业务逻辑实现
  • 工作流集成
  • 缓存管理
  • 定时任务
  • 前端界面开发
  • 权限控制
  • 数据验证

通过这些功能的实现,可以为企业提供完整的考勤和请假管理解决方案。

智能考勤系统 - 统计分析与系统管理模块详解

一、统计分析模块

1. 考勤统计报表

1.1 数据维度
-- 考勤统计视图
CREATE VIEW v_attendance_statistics AS
SELECT e.department_id,e.emp_no,e.name,DATE_FORMAT(ar.check_in_time, '%Y-%m') as month,COUNT(DISTINCT DATE(ar.check_in_time)) as work_days,COUNT(CASE WHEN ar.status = 1 THEN 1 END) as normal_days,COUNT(CASE WHEN ar.status = 2 THEN 1 END) as late_days,COUNT(CASE WHEN ar.status = 3 THEN 1 END) as early_leave_days,COUNT(CASE WHEN ar.status = 4 THEN 1 END) as absent_days
FROM sys_employee e
LEFT JOIN attendance_record ar ON e.id = ar.emp_id
GROUP BY e.id, DATE_FORMAT(ar.check_in_time, '%Y-%m');
1.2 报表类型
  • 月度考勤汇总表
  • 个人考勤明细表
  • 部门考勤对比表
  • 异常考勤分析表
1.3 数据展示
@Service
public class AttendanceReportService {@Autowiredprivate AttendanceMapper attendanceMapper;public List<AttendanceReportDTO> generateMonthlyReport(String month) {return attendanceMapper.getMonthlyStatistics(month);}// 支持多种导出格式public void exportReport(String format, String month) {List<AttendanceReportDTO> data = generateMonthlyReport(month);switch(format.toLowerCase()) {case "excel":exportToExcel(data);break;case "pdf":exportToPDF(data);break;case "csv":exportToCSV(data);break;}}
}

2. 部门出勤率分析

2.1 核心指标
  • 部门整体出勤率
  • 迟到率
  • 早退率
  • 缺勤率
  • 加班时长
2.2 可视化展示
<template><div class="department-analysis"><!-- 部门出勤率图表 --><div class="chart-container"><v-chart :option="chartOption" /></div><!-- 部门排名列表 --><el-table :data="departmentRanking"><el-table-column prop="deptName" label="部门" /><el-table-column prop="attendanceRate" label="出勤率"><template #default="scope"><el-progress :percentage="scope.row.attendanceRate" :color="getColorByRate(scope.row.attendanceRate)"/></template></el-table-column></el-table></div>
</template><script>
export default {data() {return {chartOption: {title: { text: '部门出勤率分析' },series: [{type: 'pie',data: [{ value: 95, name: '研发部' },{ value: 92, name: '市场部' },{ value: 88, name: '运营部' }]}]}}}
}
</script>

3. 加班统计

3.1 加班类型统计
public enum OvertimeType {WORKDAY(1, "工作日加班"),WEEKEND(2, "周末加班"),HOLIDAY(3, "节假日加班");private int code;private String desc;
}@Service
public class OvertimeStatisticsService {public Map<String, Object> calculateOvertimeHours(Long empId, String month) {Map<String, Object> statistics = new HashMap<>();// 计算不同类型加班时长statistics.put("workdayHours", calculateByType(empId, month, OvertimeType.WORKDAY));statistics.put("weekendHours", calculateByType(empId, month, OvertimeType.WEEKEND));statistics.put("holidayHours", calculateByType(empId, month, OvertimeType.HOLIDAY));// 计算加班费statistics.put("overtimePay", calculateOvertimePay(statistics));return statistics;}
}

4. 请假趋势分析

4.1 请假类型分布
SELECT leave_type,COUNT(*) as count,SUM(TIMESTAMPDIFF(HOUR, start_time, end_time)) as total_hours
FROM leave_record
WHERE DATE_FORMAT(start_time, '%Y-%m') = #{month}
GROUP BY leave_type;
4.2 趋势图表配置
const leaveAnalysisChart = {xAxis: {type: 'category',data: ['1月', '2月', '3月', '4月', '5月', '6月']},yAxis: {type: 'value'},series: [{name: '病假',type: 'line',data: [10, 8, 12, 6, 9, 7]},{name: '事假',type: 'line',data: [5, 7, 4, 8, 6, 9]},{name: '年假',type: 'line',data: [2, 4, 6, 8, 3, 5]}]
}

二、系统管理模块

1. 用户管理

1.1 用户表设计
CREATE TABLE sys_user (id BIGINT PRIMARY KEY,username VARCHAR(50) NOT NULL UNIQUE,password VARCHAR(100) NOT NULL,real_name VARCHAR(50),email VARCHAR(100),mobile VARCHAR(20),status TINYINT DEFAULT 1,create_time DATETIME,update_time DATETIME,last_login_time DATETIME,remark VARCHAR(255)
);
1.2 用户服务实现
@Service
public class UserService {@Autowiredprivate PasswordEncoder passwordEncoder;public void createUser(UserDTO userDTO) {// 密码加密String encodedPassword = passwordEncoder.encode(userDTO.getPassword());SysUser user = new SysUser();user.setUsername(userDTO.getUsername());user.setPassword(encodedPassword);// ... 设置其他属性userMapper.insert(user);}public void updateUserStatus(Long userId, Integer status) {userMapper.updateStatus(userId, status);}
}

2. 角色权限

2.1 RBAC权限模型
-- 角色表
CREATE TABLE sys_role (id BIGINT PRIMARY KEY,role_name VARCHAR(50),role_code VARCHAR(50),status TINYINT,create_time DATETIME
);-- 权限表
CREATE TABLE sys_permission (id BIGINT PRIMARY KEY,parent_id BIGINT,name VARCHAR(50),type TINYINT,permission_code VARCHAR(50),path VARCHAR(200),component VARCHAR(100),icon VARCHAR(50),sort INT
);-- 角色权限关联表
CREATE TABLE sys_role_permission (role_id BIGINT,permission_id BIGINT,PRIMARY KEY(role_id, permission_id)
);
2.2 权限控制实现
@PreAuthorize("hasRole('ADMIN') or hasPermission(#id, 'attendance:view')")
@GetMapping("/attendance/{id}")
public AttendanceDTO getAttendanceDetail(@PathVariable Long id) {return attendanceService.getById(id);
}@Service
public class CustomPermissionEvaluator implements PermissionEvaluator {@Overridepublic boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {// 权限判断逻辑return checkPermission(authentication, permission.toString());}
}

3. 部门管理

3.1 部门树形结构
@Data
public class DepartmentTree {private Long id;private String name;private Long parentId;private List<DepartmentTree> children;private String leader;private Integer employeeCount;
}@Service
public class DepartmentService {public List<DepartmentTree> buildDepartmentTree() {List<Department> allDepts = departmentMapper.selectAll();return buildTree(allDepts, 0L);}private List<DepartmentTree> buildTree(List<Department> depts, Long parentId) {return depts.stream().filter(dept -> dept.getParentId().equals(parentId)).map(dept -> {DepartmentTree node = new DepartmentTree();node.setId(dept.getId());node.setName(dept.getName());node.setChildren(buildTree(depts, dept.getId()));return node;}).collect(Collectors.toList());}
}

4. 系统配置

4.1 配置管理
@Configuration
@ConfigurationProperties(prefix = "system")
@Data
public class SystemConfig {private AttendanceConfig attendance;private SecurityConfig security;private NotificationConfig notification;@Datapublic static class AttendanceConfig {private String workStartTime;private String workEndTime;private Integer lateMinutes;private Integer earlyLeaveMinutes;}
}
4.2 动态配置实现
@Service
public class ConfigService {@Autowiredprivate StringRedisTemplate redisTemplate;public void updateConfig(String key, String value) {// 更新数据库configMapper.updateValue(key, value);// 更新缓存redisTemplate.opsForValue().set("system:config:" + key, value, 1, TimeUnit.DAYS);}public String getConfig(String key) {// 先从缓存获取String value = redisTemplate.opsForValue().get("system:config:" + key);if (value == null) {// 缓存未命中,从数据库获取value = configMapper.selectByKey(key);if (value != null) {redisTemplate.opsForValue().set("system:config:" + key, value, 1, TimeUnit.DAYS);}}return value;}
}
4.3 配置页面
<template><div class="system-config"><el-form :model="configForm" label-width="120px"><el-tabs v-model="activeTab"><!-- 考勤配置 --><el-tab-pane label="考勤配置" name="attendance"><el-form-item label="上班时间"><el-time-picker v-model="configForm.workStartTime" /></el-form-item><el-form-item label="下班时间"><el-time-picker v-model="configForm.workEndTime" /></el-form-item></el-tab-pane><!-- 系统配置 --><el-tab-pane label="系统配置" name="system"><el-form-item label="系统名称"><el-input v-model="configForm.systemName" /></el-form-item><el-form-item label="Logo"><el-uploadaction="/api/system/upload":show-file-list="false":on-success="handleLogoSuccess"><img v-if="configForm.logo" :src="configForm.logo" class="logo"><el-button v-else>上传Logo</el-button></el-upload></el-form-item></el-tab-pane></el-tabs><el-form-item><el-button type="primary" @click="saveConfig">保存配置</el-button></el-form-item></el-form></div>
</template><script>
export default {data() {return {activeTab: 'attendance',configForm: {workStartTime: '',workEndTime: '',systemName: '',logo: ''}}},methods: {async saveConfig() {try {await this.$api.system.updateConfig(this.configForm)this.$message.success('配置保存成功')} catch (error) {this.$message.error('配置保存失败')}}}
}
</script>

这些模块的实现涉及到了前后端的完整开发流程,包括:

  • 数据库表设计
  • 后端服务实现
  • 权限控制
  • 缓存优化
  • 前端界面开发
  • 数据可视化

通过这些功能的实现,可以为企业提供完整的考勤管理解决方案。

相关文章:

Java全栈项目 - 智能考勤管理系统

项目介绍 智能考勤管理系统是一个基于 Java 全栈技术开发的现代化企业考勤解决方案。该系统采用前后端分离架构&#xff0c;实现了员工考勤、请假管理、统计分析等核心功能&#xff0c;旨在帮助企业提高人力资源管理效率。 技术栈 后端技术 Spring Boot 2.6.xSpring Securi…...

Linux Shell : Process Substitution

注&#xff1a;本文为 “Process Substitution” 相关文章合辑。 英文引文机翻&#xff0c;未校。 Process Substitution. 进程替换允许使用文件名引用进程的输入或输出。它采取以下形式 <(list)or >(list)进程 list 异步运行&#xff0c;其输入或输出显示为文件名。…...

JOGL 从入门到精通:开启 Java 3D 图形编程之旅

一、引言 Java 作为一门广泛应用的编程语言&#xff0c;在图形编程领域也有着强大的工具和库。JOGL&#xff08;Java OpenGL&#xff09;便是其中之一&#xff0c;它为 Java 开发者提供了访问 OpenGL&#xff08;Open Graphics Library&#xff09;功能的接口&#xff0c;使得…...

汽车网络安全基线安全研究报告

一、引言 随着汽车行业朝着智能网联方向飞速发展&#xff0c;汽车网络安全已成为保障用户安全和行业健康发展的关键要素。本报告将深入探讨汽车网络安全相关内容&#xff0c;以及国际、国内重要的汽车网络安全标准基线和相应防护措施等内容。 二、汽车网络安全的重要性 &…...

Eclipse 修改项目栏字体大小

1、菜单栏选择window->preference&#xff0c;然后选择General->Appearance->Colors and Fonts&#xff0c;在搜索栏输入"tree"&#xff0c;点击"Edit"修改字体。 2、修改字体&#xff0c;选择"四号字体"&#xff0c;点击"确定&qu…...

【PCIe 总线及设备入门学习专栏 5.1 -- PCIe 引脚 PRSNT 与热插拔】

文章目录 OverviewPRSNT 与热插拔PRSNT 硬件设计 Overview Spec 定义的热插拔是把一个PCIe卡&#xff08;设备&#xff09;从一个正在运行的背板或者系统中插入/或者移除。这个过程需要不影响系统的其他功能。插入的新的设备可以正确工作。 显然&#xff0c;这里面需要考虑的问…...

【YOLO】YOLOv5原理

概述 YOLOv5的主要架构 Backbone&#xff08;主干网络&#xff09;&#xff1a;负责提取输入图像的多层次特征 Neck&#xff08;颈部网络&#xff09;&#xff1a;进行特征融合和多尺度特征处理&#xff0c;通常包含FPN&#xff08;特征金字塔网络&#xff09;和PAN&#xff0…...

uniapp中wx.getFuzzyLocation报错如何解决

一、用wx.getLocation接口审核不通过 用uniapp开发小程序时难免需要获取当前地理位置。 代码如下&#xff1a; uni.getLocation({type: wgs84,success: function (res) {console.log(当前位置的经度&#xff1a; res.longitude);console.log(当前位置的纬度&#xff1a; r…...

opencv图像直方图

【欢迎关注编码小哥&#xff0c;学习更多实用的编程方法和技巧】 1、基本直方图计算 // 灰度图直方图 cv::Mat calculateGrayscaleHistogram(const cv::Mat& image) {cv::Mat histogram;int histSize 256; // 灰度级别float range[] {0, 256};const float* histRange …...

OpenCV计算机视觉 03 椒盐噪声的添加与常见的平滑处理方式(均值、方框、高斯、中值)

上一篇文章&#xff1a;OpenCV计算机视觉 02 图片修改 图像运算 边缘填充 阈值处理 目录 添加椒盐噪声 图像平滑常见处理方式 均值滤波 (blur) 方框滤波 (boxFilter) ​高斯滤波 (GaussianBlur) 中值滤波 (medianBlur) 添加椒盐噪声 def add_peppersalt_noise(image, n…...

【嵌入式C语言】内存分布

内存分布 内存分布图内存的属性&#xff1a;只读空间只读空间的特点编程注意事项 栈空间栈的工作原理栈的特点栈溢出与堆的区别 堆空间堆的特点内存分配函数内存泄漏总结 内存分布图 内存的属性&#xff1a; 在C语言中&#xff0c;内存的属性主要取决于它是如何分配的以及它在…...

【brainpan靶场渗透】

文章目录 一、基础信息 二、信息收集 三、反弹shell 四、提权 一、基础信息 Kali IP&#xff1a;192.168.20.146 靶机 IP&#xff1a;192.168.20.155 二、信息收集 似乎开放了9999&#xff0c;10000端口&#xff0c;访问页面没有太多内容&#xff0c;扫描一下目录 dirs…...

Java实现观察者模式

一、前言 观察者模式&#xff0c;又称为发布订阅模式&#xff0c;是一种行为设置模式&#xff0c;允许对象之间建立一对多的依赖关系&#xff0c;这样当一个对象状态改变时&#xff0c;它的所有依赖者&#xff08;观察者&#xff09;都会收到通知并自动更新。 二、具体实现 …...

通过百度api处理交通数据

通过百度api处理交通数据 1、读取excel获取道路数据 //道路名称Data EqualsAndHashCode public class RoadName {ExcelProperty("Name")private String name; }/*** 获取excel中的道路名称*/private static List<String> getRoadName() {// 定义文件路径&…...

探索CSDN博客数据:使用Python爬虫技术

探索CSDN博客数据&#xff1a;使用Python爬虫技术 在数字化的浪潮中&#xff0c;数据的获取与分析变得日益关键。CSDN作为中国领先的IT社区和服务平台&#xff0c;汇聚了海量的技术博客与文章&#xff0c;成为一座蕴藏丰富的数据宝库。本文将引领您穿梭于Python的requests和py…...

b站ip属地评论和主页不一样怎么回事

在浏览B站时&#xff0c;细心的用户可能会发现一个有趣的现象&#xff1a;某些用户的评论IP属地与主页显示的IP属地并不一致。这种差异引发了用户的好奇和猜测&#xff0c;究竟是什么原因导致了这种情况的发生呢&#xff1f;本文将对此进行深入解析&#xff0c;帮助大家揭开这一…...

如何查看服务器内存占用情况?

如何查看服务器的内存占用情况&#xff1f;你知道内存使用情况对服务器性能的重要性吗&#xff1f;内存是服务器运行的核心资源之一&#xff0c;了解内存的占用情况可以帮助你优化系统性能。 要查看服务器的内存占用情况&#xff0c;首先需要确定你使用的是哪种操作系统。不同…...

流架构的读书笔记(2)

流架构的读书笔记&#xff08;2&#xff09; 一、建模工具之一沃德利地图 推测技术的发展,交流和辩论思想的最有力的方法是沃德利地图 沃德利地图的制作步骤 1确定范围和用户需求 2确定满足用户需求所需的组件 3在一条范围从全新到被人们接受的演进轴上评估这些组成 部分的演…...

E6 中的 扩展运算符(Spread) 和 剩余运算符(Rest)

时间&#xff1a;2024.12.29 之前看到 Es6 中的 三点运算符&#xff0c;有如下的几种写法&#xff0c;有时候三点运算符放在左边&#xff0c;有时候三点运算符放在右边&#xff0c;老是混淆。今天记录下&#xff0c;加强理解。 先看一个问题 最近在看 《ECMAScript 6 入门》关于…...

Python的简单爬虫框架

爬虫为网络爬虫&#xff08;又称为网页蜘蛛&#xff0c;网络机器人&#xff0c;在FOAF社区中间&#xff0c;更经常的称为网页追逐者&#xff09;&#xff0c;是一种按照一定的规则&#xff0c;自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、…...

使用 uni-app 开发的微信小程序中,如何在从 B 页面回来时,重新拉取数据?

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的全栈工程师 欢迎分享 / 收藏 / 赞 / 在看…...

Windows API Set:那些“只存在但不被使用“的DLL

API Set 是什么&#xff1f; 想象一下&#xff0c;Windows就像一个大型图书馆&#xff0c;而API Set就是这个图书馆的索引系统。但这个索引系统非常特别&#xff1a;它是直接内置在Windows加载器中的"虚拟目录"。 // 一个典型的API Set映射示例 api-ms-win-core-mem…...

黑神话悟空鼠标光标分享

效果图&#xff1a; 鼠标光标特点 这套鼠标光标的设计灵感来源于《黑神话&#xff1a;悟空》游戏中的角色和元素&#xff0c;具有以下特点&#xff1a; • 主题鲜明&#xff1a;光标设计紧扣游戏主题&#xff0c;采用了游戏中的元素&#xff0c;让玩家在使用电脑时也能感受到…...

编写一个简单的引导加载程序(bootloader)

编写一个简单的引导加载程序&#xff08;bootloader&#xff09;通常用于嵌入式系统或自定义操作系统。这里&#xff0c;我将为你提供一个基于x86架构的简单汇编语言 bootloader 示例。这个 bootloader 将会在启动时打印一条消息到屏幕上。 使用 NASM 汇编器来编写这个 bootlo…...

【Linux基础】进程(上) —— 概念、状态、优先级与环境变量

目录 一、进程的概念 1. 什么是进程 PCB进程控制块的理解 2. 查看进程的方式 ps ajx 指令 getpid系统调用 3. 另外一种查看进程的方式(了解) 4. 进程的常见调用 fork 创建子进程 现象说明 二、进程的状态 1. 操作系统层面的进程状态 ① 运行状态 ② 阻塞状态 ③…...

Rust: enum 和 i32 的区别和互换

在Rust编程语言中&#xff0c;enum&#xff08;枚举&#xff09;和i32是两种不同类型的数据结构&#xff0c;它们各自有不同的用途和特性。 i32 i32是一个32位的有符号整数类型。它用于存储整数值&#xff0c;范围从-2,147,483,648到2,147,483,647。i32是Rust中的基本数据类型…...

2024年终回顾

前言 很久没有更新博客&#xff0c;因为工作内容主要是内场开发&#xff0c;后来有点和互联网脱轨&#xff0c;断断续续上来看一下。这个总结应该也很简单&#xff0c;涉及以下的几个内容进行逐一说明 一、就业问题 这个问题可能很尖锐&#xff0c;从大环境来说&#xff0c;去…...

RGB、HSV颜色模型及MATLAB互换应用实例

一、前言 RGB和HSV模型是数字图像处理中颜色空间中的两种重要表示方式&#xff0c;RGB和HSV都是描述颜色的数学模型&#xff0c;可以用于表示和处理图像中的颜色信息。 RGB模型是一种基于光的颜色模型&#xff0c;由红&#xff08;Red&#xff09;、绿&#xff08;Green&#x…...

# 【超全面了解鸿蒙生命周期】-生命周期补充

【超全面了解鸿蒙生命周期】-生命周期补充 鸿蒙所有的生命周期函数梳理 文章目录 【超全面了解鸿蒙生命周期】-生命周期补充前言一、AbilityStage的生命周期二、ExtensionAbility卡片生命周期三、Web组件常用生命周期 前言 本文是继之前写的生命周期函数梳理的进一步补充&…...

黑神话悟空游戏鼠标光标使用教程与下载

效果图&#xff1a; 鼠标光标特点 这套鼠标光标的设计灵感来源于《黑神话&#xff1a;悟空》游戏中的角色和元素&#xff0c;具有以下特点&#xff1a; • 主题鲜明&#xff1a;光标设计紧扣游戏主题&#xff0c;采用了游戏中的元素&#xff0c;让玩家在使用电脑时也能感受到…...