【免费】SpringBoot4+Vue3企业人事(人力资源)HR管理系统 适合java毕业设计 java课程设计

大家好,我是Java1234_小锋老师,分享一套锋哥原创的SpringBoot4+Vue3企业人事(人力资源)HR管理系统。

项目介绍

随着企业组织规模扩大和用工形式多样化,传统依赖电子表格与纸质单据的人事管理方式已难以满足考勤统计、请假审批、薪资核算和员工信息集中维护等业务要求。针对中小企业人力资源信息化建设的实际需求,本文设计并实现了一套基于 B/S 架构的企业人事(人力资源)HR 管理系统。

系统采用前后端分离开发模式。后端以 Java 17 为编程语言,基于 Spring Boot 4 构建 RESTful 服务,使用 MyBatis-Plus 完成对象关系映射与分页查询,数据持久化于 MySQL 8 数据库 db_hr_system;前端采用 Vue 3、Vite、Element Plus 与 ECharts,实现管理端与员工端一体化界面。身份认证采用 JWT 令牌机制,接口返回统一封装为 R 对象,日期在界面中按 yyyy-MM-dd、日期时间按 yyyy-MM-dd HH:mm:ss 格式展示。

系统面向管理员与员工两类角色。管理员可完成首页数据统计、部门与职位维护、员工档案管理、考勤查询、请假审批、薪资核算发放、公告发布、账号管理及个人中心操作;员工可进行上下班打卡、提交请假、查看本人考勤与薪资、阅读公告,并维护头像、个人资料和登录密码。测试结果表明,系统功能完整、流程清晰,能够支撑中小企业日常人事管理工作,对同类毕业设计与信息化实践具有参考价值。

源码下载

链接: https://pan.baidu.com/s/1fXAS1OBFTCfjHe2F5tlJIA?pwd=1234
提取码: 1234

系统展示

核心代码

package com.java1234.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.java1234.common.R;
import com.java1234.entity.Department;
import com.java1234.entity.Employee;
import com.java1234.service.DepartmentService;
import com.java1234.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 部门控制器
 */
@RestController
@RequestMapping("/department")
public class DepartmentController {

    @Autowired
    private DepartmentService departmentService;

    @Autowired
    private EmployeeService employeeService;

    /**
     * 分页查询部门
     *
     * @param pageNum  页码
     * @param pageSize 每页条数
     * @param deptName 部门名称
     * @param deptNo   部门编号
     * @return 分页数据
     */
    @GetMapping("/page")
    public R page(@RequestParam(defaultValue = "1") Integer pageNum,
                  @RequestParam(defaultValue = "10") Integer pageSize,
                  String deptName, String deptNo) {
        Page<Department> page = departmentService.page(new Page<>(pageNum, pageSize),
                new LambdaQueryWrapper<Department>()
                        .like(StringUtils.hasText(deptName), Department::getDeptName, deptName)
                        .like(StringUtils.hasText(deptNo), Department::getDeptNo, deptNo)
                        .orderByAsc(Department::getSortNum)
                        .orderByDesc(Department::getId));
        Map<String, Object> data = new HashMap<>();
        data.put("total", page.getTotal());
        data.put("records", page.getRecords());
        return R.ok(data);
    }

    /**
     * 查询全部部门(下拉框使用)
     *
     * @return 部门列表
     */
    @GetMapping("/list")
    public R list() {
        return R.ok(departmentService.list(new LambdaQueryWrapper<Department>()
                .orderByAsc(Department::getSortNum)));
    }

    /**
     * 新增部门
     *
     * @param department 部门信息
     * @return 操作结果
     */
    @PostMapping
    public R add(@RequestBody Department department) {
        long count = departmentService.count(new LambdaQueryWrapper<Department>()
                .eq(Department::getDeptNo, department.getDeptNo()));
        if (count > 0) {
            return R.error("部门编号已存在");
        }
        department.setCreateTime(LocalDateTime.now());
        departmentService.save(department);
        return R.ok();
    }

    /**
     * 修改部门
     *
     * @param department 部门信息
     * @return 操作结果
     */
    @PutMapping
    public R update(@RequestBody Department department) {
        departmentService.updateById(department);
        return R.ok();
    }

    /**
     * 删除部门
     *
     * @param id 主键ID
     * @return 操作结果
     */
    @DeleteMapping("/{id}")
    public R delete(@PathVariable Integer id) {
        long empCount = employeeService.count(new LambdaQueryWrapper<Employee>().eq(Employee::getDeptId, id));
        if (empCount > 0) {
            return R.error("该部门下存在员工,无法删除");
        }
        departmentService.removeById(id);
        return R.ok();
    }
}
<template>
  <div class="page-card">
    <div class="search-bar">
      <el-select v-model="query.employeeId" placeholder="员工" clearable filterable style="width: 160px">
        <el-option v-for="e in emps" :key="e.id" :label="e.empName" :value="e.id" />
      </el-select>
      <el-select v-model="query.status" placeholder="状态" clearable style="width: 120px">
        <el-option v-for="s in ['正常','迟到','早退','缺勤','请假']" :key="s" :label="s" :value="s" />
      </el-select>
      <el-date-picker v-model="query.beginDate" value-format="YYYY-MM-DD" placeholder="开始日期" />
      <el-date-picker v-model="query.endDate" value-format="YYYY-MM-DD" placeholder="结束日期" />
      <el-button type="primary" @click="load">查询</el-button>
      <el-button type="success" @click="open()">新增</el-button>
    </div>
    <el-table :data="table" stripe border style="width: 100%">
      <el-table-column prop="empNo" label="工号" min-width="110" />
      <el-table-column prop="empName" label="姓名" min-width="90" />
      <el-table-column prop="attendanceDate" label="考勤日期" min-width="120" />
      <el-table-column prop="checkInTime" label="上班打卡" min-width="170" />
      <el-table-column prop="checkOutTime" label="下班打卡" min-width="170" />
      <el-table-column prop="status" label="状态" min-width="90" />
      <el-table-column prop="remark" label="备注" min-width="140" show-overflow-tooltip />
      <el-table-column label="操作" min-width="140" fixed="right">
        <template #default="{ row }">
          <el-button link type="primary" @click="open(row)">编辑</el-button>
          <el-button link type="danger" @click="remove(row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <div class="pager"><el-pagination background layout="total, prev, pager, next" :total="total" v-model:current-page="query.pageNum" @current-change="load" /></div>
    <el-dialog v-model="visible" :title="form.id ? '编辑考勤' : '新增考勤'" width="520px">
      <el-form :model="form" label-width="90px">
        <el-form-item label="员工">
          <el-select v-model="form.employeeId" style="width:100%" filterable>
            <el-option v-for="e in emps" :key="e.id" :label="e.empName" :value="e.id" />
          </el-select>
        </el-form-item>
        <el-form-item label="考勤日期"><el-date-picker v-model="form.attendanceDate" value-format="YYYY-MM-DD" style="width:100%" /></el-form-item>
        <el-form-item label="上班打卡"><el-date-picker v-model="form.checkInTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" style="width:100%" /></el-form-item>
        <el-form-item label="下班打卡"><el-date-picker v-model="form.checkOutTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" style="width:100%" /></el-form-item>
        <el-form-item label="状态">
          <el-select v-model="form.status" style="width:100%">
            <el-option v-for="s in ['正常','迟到','早退','缺勤','请假']" :key="s" :label="s" :value="s" />
          </el-select>
        </el-form-item>
        <el-form-item label="备注"><el-input v-model="form.remark" /></el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="visible=false">取消</el-button>
        <el-button type="primary" @click="save">保存</el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { attendancePage, attendanceAdd, attendanceUpdate, attendanceDelete, empList } from '../../api'
const query = reactive({ pageNum: 1, pageSize: 10, employeeId: null, status: '', beginDate: '', endDate: '' })
const table = ref([]); const total = ref(0); const visible = ref(false); const emps = ref([]); const form = reactive({})
const load = async () => { const res = await attendancePage(query); table.value = res.data.records; total.value = res.data.total }
const open = (row) => { Object.keys(form).forEach(k => delete form[k]); Object.assign(form, row ? { ...row } : { status: '正常' }); visible.value = true }
const save = async () => { form.id ? await attendanceUpdate(form) : await attendanceAdd(form); ElMessage.success('保存成功'); visible.value=false; load() }
const remove = (row) => { ElMessageBox.confirm('确认删除?').then(async () => { await attendanceDelete(row.id); ElMessage.success('删除成功'); load() }) }
onMounted(async () => { emps.value = (await empList()).data || []; load() })
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值