最近一位老哥让我给他的公司开发一套人力资源管理系统,并详细描述了这个系统的一些功能,我也查找了一些人力资源的资料。因为跟老哥关系不错,就答应了他。大家都知道,人力资源管理就是管人的,从给公司开始投递简历到从公司离职,员工的方方面面都要受控,那么我们来根据这个前提,看看系统的整体规划:

  • 简历管理模块
  • 员工管理模块
  • 员工异动管理模块
  • 员工考勤管理模块
  • 薪酬管理模块
  • 合同管理模块
  • 系统管理模块

提示:开发该系统前,先掌握后端Java语言及SpringBoot基本原理和Html语言及Vue框架和AntDesignVUE组件的基本操作方法,并掌握基本SQL语句的编写。
如果不太会,也可参考本文查漏补缺。

一、简历管理模块

我们先看一下最终的效果:

老哥的需求是:人们通过手机扫码填报简历,hr筛选留下合格简历入库,并保留合适的简历作为备用资源。所以将该模块分为4个菜单(新投简历、暂存简历、简历库、回收站)和一个手机页面(填写简历)。开发前先进行一些准备工作:

1、搭建开发环境

我们使用开源的jeecg框架和mysql数据库进行开发,需安装7个基础程序: jdk、node.js、mysql、 redis、webstorm、idea、navicat,具体的安装过程网络上有很多。我们将 jeecg源码解压后,用webstorm打开前端源码,运行yarn安装依赖包及配置运行环境;用idea打开后端源码,在application-dev.yml配置文件内配好数据库及redis密码。用navicat新建数据库并导入源码内提供的初始化jeecg-boot.sql文件。前后端成功运行后点击webstorm控制台提示的浏览地址,能成功打开登录页面并刷出验证码表明运行成功。正式进入模块开发环节。

2、数据字段设计

我们根据需求,对字段进行初期设计。简历包含人员基础信息、工作经历、评取职称、考取证书、获得荣誉等内容,因为一个人会有多个工作经历,多个证书荣誉,所以数据库表设计是标准的一对多设计。详细的字段如下。

tb_resume_list[人员简历表] 因为由Jeecg生成,所以没有加ID主键,可以参考Jeecg官方的[online表单]开发说明

字段名 字段类型 注释 字典
resume_name varchar 姓名
resume_pic varchar 照片
resume_sfz varchar 身份证号码
resume_sex varchar 性别
resume_minzu tinyint 民族
resume_age varchar 年龄
resume_birthday datetime 出生日期
resume_tel varchar 电话
resume_address varchar 家庭住址
resume_qqwx varchar QQ或者微信号
resume_email varchar 电子邮箱
resume_party tinyint 政治面貌
resume_edu_college varchar 毕业院校
resume_edu_major varchar 主修专业
resume_edu_end_date datetime 毕业时间
resume_edu_background tinyint 学历
resume_edu_degree tinyint 学位
resume_memo varchar 备注
resume_is_read tinyint 已读未读
resume_is_passed tinyint 是否通过
resume_is_del tinyint 是否删除
resume_is_employee tinyint 是否入职

tb_career_info[人员工作经历表]

字段名 字段类型 注释
id int ID
person_id varchar 对应人员ID
career_date varchar 前工作日期
career_unit varchar 前工作单位
career_post varchar 前工作职务
career_leave_reason varchar 离职原因

tb_certificate_info[人员考取证书表]

字段名 字段类型 注释
id int ID
person_id varchar 对应人员ID
certificate varchar 资格证书名称

tb_honour_info[人员获得荣誉表]

字段名 字段类型 注释
id int ID
person_id varchar 对应人员ID
honour varchar 荣誉名称

tb_professional_info[人员取得的职称表]

字段名 字段类型 注释
id int ID
person_id varchar 对应人员ID
professional varchar 职称名称

3、代码开发

增加字典数据

根据设计好的字段添加字典数据。登录系统后打开[数据字典]菜单增加稍后用到的字典。先增加字典名称

再点击[字典配置],添加字典项

在线表单设计

打开online表单设计菜单,填入对应的字段名称,


同步数据库及代码生成
点击同步数据库,系统会自动在数据库中将表建好。点击代码生成按钮,填入对应的参数,系统自动生成前后端分离的代码。

代码拷贝
方便我们快速开发。紧接着,我们在后端Java代码的modules文件夹及前端Vue代码的view文件夹内新建hr文件夹,并在此文件夹内各自新建resume文件夹,代表这是人资管理系统的简历管理模块。将 controller、entity、mapper、service文件夹拷入后端resume文件夹内,vue文件夹内的所有文件拷入前端resume文件夹内,这时,树形结构为这样。

增加菜单
重启程序进入系统,点击菜单管理,增加简历管理及它的下级新投简历两个菜单,填入相应信息。组件就是*.vue这个文件的路径,路径名从 view开始填写。

二级菜单路径和组件都为[/modules/hr/resume/TbResumeNewList]

增加授权
打开角色管理菜单内admin角色的授权按钮后,选中新增的菜单后刷新页面
增加成功
菜单出现了,点击后能看到对应的空表格。

4、手机端填写简历页面开发

手机端我们使用vant2作为组件库,安装及引用方法参考官网。

https://vant-contrib.gitee.io/vant/v2/#/zh-CN/quickstart

由于应聘者的不确定性,无法让其登录系统后再填报,所以填报页面设计为不登录填报,需要在前端添加免登录白名单。

1)添加页面
在前端modules文件夹内,添加与hr平级的mobile文件夹及子文件夹resume。并新增两个vue组件:NewResumeByPhone.vue及OK.vue

页面效果:

->NewResumeByPhone.vue
该页面用到了<van-notice-bar> <van-form> <van-field> <van-button> 以及我封装的两个日期选择picker组件 <ZDatePicker> <ZDateRangePicker>、一个字典选择picker组件<ZDictPicker> 和一个照片上传组件<ZVantUploader>

<van-field v-model="resumeName" name="resumeName" label="姓名" placeholder="请填入姓名" :required="required" :rules="rule" />
<ZDatePicker v-model="resumeBirthday" name="resumeBirthday" type="date" label="出生日期" placeholder="请选择出生日期" :minDate="new Date(new Date().getFullYear()-100, 0, 1)" :maxDate="new Date()" :required="required" :rules="rule"/>
<ZDateRangePicker v-model="careerInfos[index].career_date" :name="'career_date_'+index" label="任期范围" type="date" placeholder="请选择任期的时间范围" :required="required" :rules="careerRule"n:index="index" :minDate="new Date(new Date().getFullYear()-60, 0, 1)" :maxDate="new Date()" @confirm="rangeDataConfirm" @confirmToNow="rangeDataConfirmToNow"/>
<ZDictPicker v-model="resumeEduDegree" name="resumeEduDegree" label="学位" placeholder="请选择学位" dictCode="edu_degree" />
<ZVantUploader v-model="resumePic" name="resumePic" label="照片" :maxCount="1" :maxSize="1024*1024"/>

页面需要添加验证码,以防止机器填报

<van-field v-model="inputCode" name="inputCode" label="验证码" placeholder="请输入验证码" :required="required" :rules="rule" ><template #extra ><img v-if="requestCodeSuccess" style="height:24px;" :src="randCodeImage" @click="handleChangeCheckCode"/><img v-else style="height:24px;" src="../../../../assets/checkcode.png" @click="handleChangeCheckCode"/></template>
</van-field>

在提交时,需要将一对多的地段合并成一个表单项,用逗号分段

//javascript
onSubmit(values) {if(this.haveCareer){for(let i=0;i<this.careerInfos.length;i++){let careerDate = values["career_date_"+i];let careerUnit = this.careerInfos[i].career_unit;let careerPost = this.careerInfos[i].career_post;let careerLeaveReason = this.careerInfos[i].career_leave_reason;values["career_"+i] = careerDate + ","  + careerUnit + "," + careerPost + "," + careerLeaveReason;delete values["career_date_"+i];delete values["career_unit_"+i];delete values["career_post_"+i];delete values["career_leave_reason_"+i];}}
}

->OK.vue
该页面为提交后的结果页面,很简单。

<template><div class="main"><van-icon name="passed" size="100" color="green"/><div><span class="hint_title">提报成功</span></div><div><span class="hint_sub_title">请等待工作人员的审核</span></div></div>
</template>

2)添加路径
在前端src/config/router.config.js文件内的constantRouterMap内增加/mobile/newResume及/mobile/newResumeOK的访问路径。

//javascript
export const constantRouterMap = [{path: '/mobile/newResume',component: () => import('@/views/modules/mobile/resume/NewResumeByPhone')},{path: '/mobile/newResumeOK',component: () => import('@/views/modules/mobile/resume/OK')},
]

3)添加白名单
在src/premission.js文件内增加此路径至白名单。

//javascript
const whiteList = ['/user/login', '/user/register', '/user/register-result','/user/alteration', '/mobile/newResume', '/mobile/newResumeOK']

5、后台交互逻辑代码

页面写好后,要提交数据至后台入库了。
在后端controller、mapper、service文件夹内新增对应的方法。需要注意的是,我们需要将工作经历、证书、荣誉、职称等内容在后端拆分后再分别录入到自己的数据表中。

->TbResumeListController.java

//Java代码块
/**
*   添加手机端数据
*
* @param pageMap
* @return
*/
@AutoLog(value = "简历表-添加")
@ApiOperation(value="简历表-添加", notes="简历表-添加")
@PostMapping(value = "/addNewResumeByPhone")
public Result<?> addNewResumeByPhone(@RequestBody Map<String, String> pageMap) {if(pageMap.size() > 0){//循环遍历Map然后,对不同的信息,放入到不同的数据表中.//判断验证码String captcha = pageMap.get("inputCode");if(captcha==null){return Result.error("验证码无效");}String lowerCaseCaptcha = captcha.toLowerCase();String realKey = MD5Util.MD5Encode(lowerCaseCaptcha+pageMap.get("currDatetime"), "utf-8");Object checkCode = redisUtil.get(realKey);if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {return Result.error("验证码错误");}//验证码判断完成//获得主键IDString id = SnowflakeIdUtils.getNextSnowflakeId()+"";Map<String, String> dbMap = new HashMap<>();for (Map.Entry<String, String> entry : pageMap.entrySet()) {System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());String val = entry.getValue();if(!"".equals(val.trim())) {if(entry.getKey().contains("professional")){tbResumeListService.insertProfessionalData(id, val);}else if(entry.getKey().contains("career")){String[] tempStr = val.split(",", -1);           //参数-1是为了保留逗号后面的空值String careerDate = CommFun.nvl(tempStr[0], "");String careerUnit = CommFun.nvl(tempStr[1], "");String careerPost = CommFun.nvl(tempStr[2], "");String careerLevelReason = CommFun.nvl(tempStr[3], "暂未离职");tbResumeListService.insertCareerData(id, careerDate, careerUnit, careerPost, careerLevelReason);}else if(entry.getKey().contains("certificate")){tbResumeListService.insertCertificateData(id, val);}else if(entry.getKey().contains("honour")){tbResumeListService.insertHonourData(id, val);}else{dbMap.put(entry.getKey(), val);}}}dbMap.put("id",id);dbMap.put("resume_is_passed","1");TbResumeList tbResumeList = JSON.parseObject(JSON.toJSONString(dbMap), TbResumeList.class);tbResumeListService.save(tbResumeList);return Result.OK("操作成功!");}else{return Result.OK("添加失败!");}
}

->ITbResumeListService.java

public interface ITbResumeListService extends IService<TbResumeList> {int insertCareerData(String personID, String careerDate, String careerUnit, String careerPost, String careerLevelReason);int insertProfessionalData(String personID, String professional);int insertCertificateData(String personID, String certificate);int insertHonourData(String personID, String honour);
}

->TbResumeListServiceImpl.java

@Service
public class TbResumeListServiceImpl extends ServiceImpl<TbResumeListMapper, TbResumeList> implements ITbResumeListService {@Autowiredprivate TbResumeListMapper tbResumeListMapper;@Overridepublic int insertCareerData(String personID, String careerDate, String careerUnit, String careerPost, String careerLevelReason) {return tbResumeListMapper.insertCareerData(personID, careerDate, careerUnit, careerPost, careerLevelReason);}@Overridepublic int insertProfessionalData(String personID, String professional) {return tbResumeListMapper.insertProfessionalData(personID, professional);}@Overridepublic int insertCertificateData(String personID, String certificate) {return tbResumeListMapper.insertCertificateData(personID, certificate);}@Overridepublic int insertHonourData(String personID, String honour) {return tbResumeListMapper.insertHonourData(personID, honour);}
}

->TbResumeListMapper.java

public interface TbResumeListMapper extends BaseMapper<TbResumeList> {int insertProfessionalData(String personID, String professional);int insertCareerData(String personID, String careerDate, String careerUnit, String careerPost, String careerLevelReason);int insertCertificateData(String personID, String certificate);int insertHonourData(String personID, String honour);
}

还要在xml中添加SQL语句
->TbResumeListMapper.xml

<mapper namespace="org.jeecg.modules.hr.resume.mapper.TbResumeListMapper"><!-- SQL语句 --><insert id="insertCareerData" parameterType="String">INSERT INTO tb_career_info( `person_id` , `career_date` , `career_unit` , `career_post` , `career_leave_reason` )VALUES( #{personID}, #{careerDate}, #{careerUnit}, #{careerPost}, #{careerLevelReason} )</insert><insert id="insertProfessionalData" parameterType="String">INSERT INTO tb_professional_info( `person_id` , `professional`)VALUES( #{personID}, #{professional})</insert><insert id="insertCertificateData" parameterType="String">INSERT INTO tb_certificate_info( `person_id` , `certificate` )VALUES( #{personID}, #{certificate} )</insert><insert id="insertHonourData" parameterType="String">INSERT INTO tb_honour_info( `person_id` , `honour` )VALUES( #{personID}, #{honour} )</insert>
</mapper>

通过以上操作,我们重新运行前后端代码后,登录系统就能看到数据了。比如这样

但目前表格信息里面还没有工作经历、获得荣誉、取得证书等等信息,怎么办?继续。

6、前端电脑页面显示工作经历信息

1)增加实体类(Entity)字段
在entity文件夹内打开TbResumeList.java文件,在private int resumeIsEmployee字段后再增加4个字段:

//Java代码
/**上一单位名称*/
@Excel(name = "上一单位名称", width = 15)
@ApiModelProperty(value = "上一单位名称")
private String career;
/**已获职称*/
@Excel(name = "已获职称", width = 15)
@ApiModelProperty(value = "已获职称")
private String professional;
/**资格证书*/
@Excel(name = "资格证书ID", width = 15)
@ApiModelProperty(value = "资格证书")
private String certificate;
/**曾获荣誉*/
@Excel(name = "曾获荣誉", width = 15)
@ApiModelProperty(value = "曾获荣誉")
private String honour;

2)编写多表查询SQL语句
由于是多表查询,单靠mybatis-plus提供的查询接口已经不能满足要求,所以需要自己单独编写代码。由于后面会用到对简历状态字段的查询(resumeStatusList)以及判断是否加入回收站的条件(delValue),所以在查询条件中,改成了动态拼写的SQL语句。

<!-- SQL代码 -->
<select id="getResumeData" resultType="org.jeecg.modules.hr.resume.entity.TbResumeList">SELECTa.id, a.resume_name, a.resume_pic, a.resume_sfz, a.resume_sex, a.resume_minzu, a.resume_age, a.resume_birthday, a.resume_tel, a.resume_address, a.resume_qqwx,a.resume_email, a.resume_party, a.resume_edu_college, a.resume_edu_major, a.resume_edu_end_date, a.resume_edu_background, a.resume_edu_degree, a.resume_memo,a.resume_is_read, a.resume_is_passed, a.resume_is_del, a.resume_is_employee,GROUP_CONCAT( DISTINCT c.professional ) AS professional,GROUP_CONCAT( DISTINCT concat_ws( '|', d.career_date, d.career_unit, d.career_post, d.career_leave_reason ) ) AS career,GROUP_CONCAT( DISTINCT e.certificate ) AS certificate,GROUP_CONCAT( DISTINCT f.honour ) AS honourFROMtb_resume_list aLEFT JOIN tb_professional_info c ON a.id = c.person_idLEFT JOIN tb_career_info d ON a.id = d.person_idLEFT JOIN tb_certificate_info e ON a.id = e.person_idLEFT JOIN tb_honour_info f ON a.id = f.person_id<where><if test="resumeStatusList != null and resumeStatusList.size() != 0">a.resume_is_passed in<foreach collection="resumeStatusList" index="index" item="status" open="(" separator="," close=")">#{status}</foreach></if>and a.resume_is_del = #{delValue}</where>GROUP BYa.idORDER BY a.resume_is_passed ASC, a.resume_is_employee ASC, a.create_time DESC
</select>

3)完善controller、service、mapper类的代码

->TbResumeListController.java

 /*** 简历库** @param tbResumeList* @param pageNo* @param pageSize* @param req* @return*/@AutoLog(value = "简历库")@ApiOperation(value="简历库", notes="简历库")@GetMapping(value = "/list")public Result<?> list(TbResumeList tbResumeList, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,HttpServletRequest req) {Page<TbResumeList> page = new Page<>(pageNo, pageSize);List<Integer> resumeStatusList = new ArrayList<>();resumeStatusList.add(2);int delValue = 0;IPage<TbResumeList> pageList = tbResumeListService.getResumeData(page, resumeStatusList, delValue);return Result.OK(pageList);}

->ITbResumeListService.java

IPage<TbResumeList> getResumeData(Page<TbResumeList> page, List<Integer> resumeStatusList, int delValue);

impl、mapper的代码请参考本文第5段完成。

后端的Java代码已修改完毕,现在我们看看前端Vue页面的代码该如何实现。
4)单元格内显示数据
在TbResumeListList.vue文件中,要将table的列补充完整。在备注字段前增加这4个字段

{title:'工作经历',align:"center",dataIndex: 'career',
},{title:'已获职称',align:"center",dataIndex: 'professional',
},{title:'资格证书',align:"center",dataIndex: 'certificate',
},{title:'曾获荣誉',align:"center",dataIndex: 'honour',
},


现在已经显示了需要的数据,但是这样显示对用户来说是非常不友好的。我们需要修改显示方式。

工作经历、证书等这部分内容是一对多的,也就是说,只能在这行信息内的一个单元格显示,通常有两种方法:1、后面操作格内增加一个[查看工作经历]的功能菜单,点击打开一个窗口显示详细的多条工作经历;2、在这个单元格内再显示一个表格。这里我选择了第二种。原因是:用户方便。

要想在单元格内显示自定义的表格信息。要先知道两点:1、如何在单元格内自定义显示。2、表格的html代码该怎么写。

5)工作经历单元格的自定义显示
参考AntdVue官网后,知道单元格自定义显示的方法:customRender。可以像[操作]单元格一样使用scopedSlots插槽来实现。
首先定义一个插槽并显示表格。

<span slot="customRowTable" slot-scope="text, record"> {{ text }}<div v-if="text" class="careerContainer"><table><tr><th style="width:4%;">#</th><th style="width:23%;">任期</th><th style="width:35%;">公司名称</th><th style="width:13%;">岗位</th><th style="width:25%;">离职原因</th></tr><tr v-for="(c, index) in record.career.split(',')"><td>{{ index+1 }}</td><td style="text-align: left">{{ c.split('|')[0] }}</td><td>{{ c.split('|')[1] }}</td><td>{{ c.split('|')[2] }}</td><td>{{ c.split('|')[3] }}</td></tr></table></div><div v-else style="font-size: 12px;font-style: italic;">{{ text===null?'无':text===''?'无':text==='没有'?'无':text }}</div></span>

还有表格的样式

  .careerContainer table{width:700px;text-align: center}.careerContainer table tr td{font-size: 13px;padding:2px 5px 2px 5px;vertical-align: center;}.careerContainer table tr:nth-of-type(even){background:#eee;}

之后在列定义那增加scopedSlots: { customRender: ‘customRowTable’ }

  {title:'工作经历',align:"center",dataIndex: 'career',scopedSlots: { customRender: 'customRowTable' },  //增加这一行,注意名字要与插槽的名字一致},

现在的显示效果应该是这样,我们继续修改职称、证书、荣誉以及照片的显示样式。

5)照片、职称、证书、荣誉单元格的自定义显示
与工作经历相同,我就直接贴代码了。

<!-- 职称、证书、荣誉的显示采用Tag标签 -->
<!-- 显示方式一样,只是Tag的颜色有区别 -->
<span slot="warpLineByGreenTag" slot-scope="text, record"> {{ text }}<div v-if="text && text !== '无' && text !== '没有'"><div v-for="(t, index) in text.split(',')" :key="t.toString()+'_green'" style="margin:1px 0 1px 0;"><a-tag color="#87d068" style="margin:0;">{{ t }}</a-tag></div></div><div v-else style="font-size: 12px;font-style: italic;">{{ text===null?'无':text===''?'无':text==='没有'?'无':text }}</div>
</span>

照片的样式用到了v-viewer组件

安装命令:npm install v-viewer --save

记得要引用哦,全局单一都可以

<span slot="imgSlot" slot-scope="text"> {{ text }}<span v-if="!text" style="font-size: 12px;font-style: italic;">无图片</span><viewer v-else><img :src="showFileUrl(text)" height="100px" style="margin:0;padding:0;cursor:pointer;" alt="图片"/></viewer>
</span>

至此,我们已经完成了最终表格样式的显示。接下来要实现剩余3个页面简历库 暂存简历 回收站

7、新建3个vue页面、菜单及后台代码

复制vue页面,并重命名
可以复制写好的vue代码,改一下名字。我这里分别取名:

Resume↓
TbResumeList.vue(简历库)
TbResumeNewList.vue(新投简历)
TbResumeRecycleList.vue(回收站)
TbResumeTempList.vue(暂存简历)

新增三个菜单
然后在菜单管理内新增其他三个菜单,这里我就不演示了。

后端Java接口
要实现四个页面显示不同状态的数据,需要动态传入不同的状态参数来实现。之前多表查询已经将动态查询做好了,现在只需要传入不同的参数即可。
新投简历显示新简历、不通过两个状态的记录也就是resume_is_passed字段为1或3,暂存简历显示resume_is_passed为4的记录,简历库显示resume_is_passed为2的记录,回收站显示resume_is_del为1的记录。

所以代码如下:
这里只粘贴了简历库的java代码,其他代码请自行编写。

/*** 简历库** @param pageNo 当前页* @param pageSize 每页数量* @return Result*/
@AutoLog(value = "简历库")
@ApiOperation(value="简历库", notes="简历库")
@GetMapping(value = "/list")
public Result<?> queryPageList(@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {Page<TbResumeList> page = new Page<>(pageNo, pageSize);List<Integer> resumeStatusList = new ArrayList<>();resumeStatusList.add(2);  //状态为2已通过的状态int delValue = 0;          //这里为是否放入回收站的状态。0:不放入,1:放入IPage<TbResumeList> pageList = tbResumeListService.getResumeData(page, resumeStatusList, delValue);return Result.OK(pageList);
}

完成后,不同页面应该能显示不同的数据记录了,大家可以手动改一下状态值,看数据能否正常显示。

8、增加功能按钮

#mermaid-svg-t5sWwgSpDuMTbxYR {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-t5sWwgSpDuMTbxYR .error-icon{fill:#552222;}#mermaid-svg-t5sWwgSpDuMTbxYR .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-t5sWwgSpDuMTbxYR .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-t5sWwgSpDuMTbxYR .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-t5sWwgSpDuMTbxYR .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-t5sWwgSpDuMTbxYR .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-t5sWwgSpDuMTbxYR .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-t5sWwgSpDuMTbxYR .marker{fill:#333333;stroke:#333333;}#mermaid-svg-t5sWwgSpDuMTbxYR .marker.cross{stroke:#333333;}#mermaid-svg-t5sWwgSpDuMTbxYR svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-t5sWwgSpDuMTbxYR .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-t5sWwgSpDuMTbxYR .cluster-label text{fill:#333;}#mermaid-svg-t5sWwgSpDuMTbxYR .cluster-label span{color:#333;}#mermaid-svg-t5sWwgSpDuMTbxYR .label text,#mermaid-svg-t5sWwgSpDuMTbxYR span{fill:#333;color:#333;}#mermaid-svg-t5sWwgSpDuMTbxYR .node rect,#mermaid-svg-t5sWwgSpDuMTbxYR .node circle,#mermaid-svg-t5sWwgSpDuMTbxYR .node ellipse,#mermaid-svg-t5sWwgSpDuMTbxYR .node polygon,#mermaid-svg-t5sWwgSpDuMTbxYR .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-t5sWwgSpDuMTbxYR .node .label{text-align:center;}#mermaid-svg-t5sWwgSpDuMTbxYR .node.clickable{cursor:pointer;}#mermaid-svg-t5sWwgSpDuMTbxYR .arrowheadPath{fill:#333333;}#mermaid-svg-t5sWwgSpDuMTbxYR .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-t5sWwgSpDuMTbxYR .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-t5sWwgSpDuMTbxYR .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-t5sWwgSpDuMTbxYR .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-t5sWwgSpDuMTbxYR .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-t5sWwgSpDuMTbxYR .cluster text{fill:#333;}#mermaid-svg-t5sWwgSpDuMTbxYR .cluster span{color:#333;}#mermaid-svg-t5sWwgSpDuMTbxYR div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-t5sWwgSpDuMTbxYR :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

通过
不通过
暂存
新简历
简历库
回收站
暂存简历

增加功能菜单、处理脚本及后台接口
新投简历的后续操作有:删除通过拒绝暂存四项。先修改action插槽内的菜单:

<span slot="action" slot-scope="text, record"><a-popconfirm title="确定通过该简历吗?" @confirm="() => handlePass(record.id)"><a>通过</a></a-popconfirm><a-divider type="vertical"/><a-popconfirm title="确定拒绝该简历吗?" @confirm="() => handleRefuse(record.id)"><a>拒绝</a></a-popconfirm><br><a-dropdown><a class="ant-dropdown-link">更多 <a-icon type="down" /></a><a-menu slot="overlay"><a-menu-item>
<!--                <a @click="handleDetail(record)">详情</a>--><a @click="handleTemp(record.id)">暂存</a></a-menu-item><a-menu-item><a-popconfirm title="确定移入回收站吗?" @confirm="() => handleRecycle(record.id)"><a>删除</a></a-popconfirm></a-menu-item></a-menu></a-dropdown>
</span>

然后添加处理脚本:

handlePass(id){let that = this;getAction(this.url.pass, {id: id}).then((res) => {if (res.success) {that.$message.success(res.message);that.loadData();} else {that.$message.warning(res.message);}});
},
handleRefuse(id) {let that = this;getAction(this.url.refuse, {id: id}).then((res) => {if (res.success) {that.$message.success(res.message);that.loadData();} else {that.$message.warning(res.message);}});
},
handleTemp(id){let that = this;getAction(this.url.temp, {id: id}).then((res) => {if (res.success) {that.$message.success(res.message);that.loadData();} else {that.$message.warning(res.message);}});
},
handleRecycle(id){let that = this;getAction(this.url.recycle, {id: id}).then((res) => {if (res.success) {that.$message.success(res.message);that.loadData();} else {that.$message.warning(res.message);}});
},

以及接口地址

pass: "/hr/tbResumeList/pass",
refuse: "/hr/tbResumeList/refuse",
temp: "/hr/tbResumeList/temp",
recycle: "/hr/tbResumeList/recycle",

增加后台Java处理逻辑接口

/*** 新简历通过** @param id id* @return Result*/
@AutoLog(value = "新简历通过")
@ApiOperation(value="新简历通过", notes="新简历通过")
@GetMapping(value = "/pass")
public Result<?> pass(@RequestParam(name="id") String id) {String changeValue = "2";if(tbResumeListService.changeResumeStatus(id, changeValue)){return Result.OK("操作成功!");}else{return Result.OK("操作失败!");}
}/*** 新简历拒绝** @param id id* @return Result*/
@AutoLog(value = "新简历拒绝")
@ApiOperation(value="新简历拒绝", notes="新简历拒绝")
@GetMapping(value = "/refuse")
public Result<?> refuse(@RequestParam(name="id") String id) {String changeValue = "3";if(tbResumeListService.changeResumeStatus(id, changeValue)){return Result.OK("操作成功!");}else{return Result.OK("操作失败!");}
}/*** 暂存新简历** @param id id* @return Result*/
@AutoLog(value = "暂存新简历")
@ApiOperation(value="暂存新简历", notes="暂存新简历")
@GetMapping(value = "/temp")
public Result<?> temp(@RequestParam(name="id") String id) {String changeValue = "4";if(tbResumeListService.changeResumeStatus(id, changeValue)){return Result.OK("操作成功!");}else{return Result.OK("操作失败!");}
}/*** 新简历放入回收站** @param id id* @return Result*/
@AutoLog(value = "新简历放入回收站")
@ApiOperation(value="新简历放入回收站", notes="新简历放入回收站")
@GetMapping(value = "/recycle")
public Result<?> recycle(@RequestParam(name="id") String id) {if(tbResumeListService.recycleResume(id, 1)){return Result.OK("移入回收站成功!");}else{return Result.OK("移入回收站失败!");}
}

以及SQL语句

<update id="changeResumeStatus" parameterType="String">UPDATE tb_resume_list SET resume_is_passed = #{changeValue} where id = #{id}
</update><update id="recycleResume">UPDATE tb_resume_list SET resume_is_del = #{delValue} where id = #{id}
</update>

简历库的后续操作有:入职删除 两项。
暂存简历的后续操作有:通过拒绝删除 三项。
回收站的后续操作有:永久删除还原 两项。

这些功能与新投简历的功能类似,请大家自行完成。

9、结束

至此,简历管理已经能实现它的基本功能了。人资管理系统的一个整体性能强的系统,在新投简历审核成功,需要办理入职的过程时,需要将简历数据表内的数据拷贝到员工管理数据表中,并为员工开通账号以便员工能在手机中继续完善入职后的其他信息(家庭关系、紧急联络人等)。

代码下载: 传送门

[Java开发]搭建人力资源管理系统——简历管理模块(附带下载链接)相关推荐

  1. 最新版阿里巴巴Java开发手册(嵩山版)-附免费下载链接

    2020年8月3日,阿里技术官方宣布,阿里巴巴<Java 开发手册(嵩山版)>现已正式发布. <阿里巴巴 Java 开发手册>始于阿里内部规约,在全球Java开发者共同努力下, ...

  2. 十个经典java开发项目及其描述-简历用

    十个经典java开发项目及其描述-简历用 1.项目名称:中介管理软件 2.项目名称:菜园(电商) 3.项目名称:房产中介管理系统 4.项目名称:物流信息平台 5.项目名称:销售存储管理系统 6.项目名 ...

  3. 客户管理系统代码项目_西安人力资源管理系统如何有效管理销售,提高工作的效率...

    人力资源管理系统如何有效管理销售,提高工作的效率 发布人:汇聚华企管理系统 原创分享 销售过程会出现的管理问题各种各样,比如说库存状态,比如说报价,又比如说客户关系管理,其实这些管理上的问题都能用软件 ...

  4. java开发的公文管理系统源代码_基于jsp的公文管理系统-JavaEE实现公文管理系统 - java项目源码...

    基于jsp+servlet+pojo+mysql实现一个javaee/javaweb的公文管理系统, 该项目可用各类java课程设计大作业中, 公文管理系统的系统架构分为前后台两部分, 最终实现在线上 ...

  5. JavaWeb简历管理模块

    Javaweb简历管理模块笔记 模块简介 要求 开发工具 静态效果展示 总结 代码仓库地址 项目代码笔记 数据库和JDBC代码 项目结构 文件上传和接收 jQuery实现ajax 分页 使用selen ...

  6. Java-Web机试练习题一、后台管理系统——管理员管理模块

    题目:后台管理系统--管理员管理模块 一. 语言和环境 1. 实现语言:JAVA 语言. 2. 环境要求:MyEclipse/Eclipse + Tomcat + MySql. 3. 使用技术:Jsp ...

  7. 图书管理系统jsp代码_【程序源代码】使用Java开发的图书管理系统

    关键字:java 管理系统  正文 | 内容 01 - [概述] 使用Java开发的图书管理系统,读者可以注册登录,登录时会判断账号类型再分别跳到各自对应的页面,读者可以查找,借阅,还书,查看历史借阅 ...

  8. java开发企业级权限管理系统_Java开发企业级权限管理系统 视频教程

    第1章 课程整体概述与权限管理系统介绍 1-1 为什么企业级项目需要权限管理 1-2 权限管理的核心是什么? 1-3 理想中的权限管理应该是什么样的? 1-4 主流开源权限管理框架有哪些? 1-5 1 ...

  9. 06_04_任务一:拉勾教育后台管理系统[课程管理模块、图片上传、 BeanUtils封装实体类](SSM)

    拉勾教育后台管理系统(SSM) 1. 项目架构 1.1 项目介绍 ​ 拉勾教育后台管理系统,是提供给拉勾教育的相关业务人员使用的一个后台管理系统, 业务人员可以在 这个后台管理系统中,对课程信息.广告 ...

最新文章

  1. wpf+xml实现的一个随机生成早晚餐的小demo
  2. ​京东AI研究院获QuAC机器阅读理解竞赛冠军,EL-QA模型能力业界领先
  3. apply筛选 pandas_更快的pandas.apply搜索方法
  4. python使用符号 表示单行注释-Python注释符号(多行注释和单行注释)用法详解...
  5. android Log图文详解(Log.v,Log.d,Log.i,Log.w,Log.e)
  6. SpringBoot+AntV实现一次前后端交互渲染多个饼状图
  7. matlab数字滤波器设计函数汇总(转载)
  8. kernel移植——从三星官方内核开始移植
  9. 电脑运行java游戏,电脑运行软件卡顿?这几招游戏或是办公,让你速度飞起!...
  10. 用汇编的眼光看C++(之指针2)
  11. LeetCode 113. Path Sum II
  12. Log4net使用指南[转]
  13. 结合源码探讨Android距离传感器亮灭屏机制
  14. 【老兵不朽】时隔1年,jQuery 发布新版 3.4.0
  15. 人脸识别 特征值脸_你的脸值多少钱?
  16. [JDK1.8] Java-I/O流使用概述
  17. update set命令用来修改表中的数据
  18. java mvc接收json_详解springmvc 接收json对象的两种方式
  19. 星加坡php开发_PHP 中文简繁互转代码 完美支持大陆、香港、台湾及新加坡
  20. 《西部世界》暗示了大数据人工智能什么

热门文章

  1. android+win8+双系统,Android/Win8双系统 天敏iBox睿盒D9i评测上
  2. 关于Android中Button的Backgroud背景设置默认为蓝紫色,且无法修改的问题
  3. 《C++ Primer》第15章 15.2节习题答案
  4. docker安装minio无法访问
  5. 用mask-rcnn训练自己的数据
  6. 2021.11.08【web刷题记录】
  7. android输入法框架分析,Android输入法架构.ppt
  8. 可汗学院计算机课程都有哪些,要录制可汗学院教学视频你需要哪些硬件和软件?...
  9. 腾讯云tcp认证资料考点包含哪些知识?
  10. 网络异常处理,ping测试报:一般故障