feat(hrm): 新增员工紧急联系人管理功能
完成员工紧急联系人模块的全流程开发,包括: 1. 数据库表结构、Mapper、Service、Controller后端代码 2. 前端页面、API接口、导入导出功能 3. 配套SQL脚本、导入模板与使用文档 4. 支持批量导入导出、数据校验与用户关联匹配
This commit is contained in:
@@ -0,0 +1,117 @@
|
|||||||
|
package com.ruoyi.hrm.controller;
|
||||||
|
|
||||||
|
import com.alibaba.excel.EasyExcel;
|
||||||
|
import com.ruoyi.common.annotation.Log;
|
||||||
|
import com.ruoyi.common.core.controller.BaseController;
|
||||||
|
import com.ruoyi.common.core.domain.PageQuery;
|
||||||
|
import com.ruoyi.common.core.domain.R;
|
||||||
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
|
import com.ruoyi.common.enums.BusinessType;
|
||||||
|
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||||
|
import com.ruoyi.hrm.domain.bo.HrmEmergencyContactBo;
|
||||||
|
import com.ruoyi.hrm.domain.vo.HrmEmergencyContactImportVo;
|
||||||
|
import com.ruoyi.hrm.domain.vo.HrmEmergencyContactVo;
|
||||||
|
import com.ruoyi.hrm.service.IHrmEmergencyContactService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Validated
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/hrm/emergencyContact")
|
||||||
|
public class HrmEmergencyContactController extends BaseController {
|
||||||
|
|
||||||
|
private final IHrmEmergencyContactService service;
|
||||||
|
|
||||||
|
@GetMapping("/list")
|
||||||
|
public TableDataInfo<HrmEmergencyContactVo> list(HrmEmergencyContactBo bo, PageQuery pageQuery) {
|
||||||
|
return service.queryPageList(bo, pageQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{contactId}")
|
||||||
|
public R<HrmEmergencyContactVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long contactId) {
|
||||||
|
return R.ok(service.queryById(contactId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "紧急联系人管理", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping
|
||||||
|
public R<Void> add(@Validated @RequestBody HrmEmergencyContactBo bo) {
|
||||||
|
return toAjax(service.insertByBo(bo));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "紧急联系人管理", businessType = BusinessType.UPDATE)
|
||||||
|
@PutMapping
|
||||||
|
public R<Void> edit(@Validated @RequestBody HrmEmergencyContactBo bo) {
|
||||||
|
return toAjax(service.updateByBo(bo));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "紧急联系人管理", businessType = BusinessType.DELETE)
|
||||||
|
@DeleteMapping("/{contactIds}")
|
||||||
|
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] contactIds) {
|
||||||
|
return toAjax(service.deleteWithValidByIds(Arrays.asList(contactIds), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Log(title = "紧急联系人管理", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(HrmEmergencyContactBo bo, HttpServletResponse response) {
|
||||||
|
List<HrmEmergencyContactVo> list = service.queryList(bo);
|
||||||
|
ExcelUtil.exportExcel(list, "紧急联系人数据", HrmEmergencyContactVo.class, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
|
public R<String> importData(@RequestPart("file") MultipartFile file, @RequestParam(defaultValue = "false") boolean updateSupport) throws IOException {
|
||||||
|
List<HrmEmergencyContactImportVo> list = ExcelUtil.importExcel(file.getInputStream(), HrmEmergencyContactImportVo.class, false).getList();
|
||||||
|
String msg = service.importByVoList(list, updateSupport);
|
||||||
|
return R.ok(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/importTemplate")
|
||||||
|
public void importTemplate(HttpServletResponse response) throws IOException {
|
||||||
|
// 设置响应头
|
||||||
|
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||||
|
response.setCharacterEncoding("utf-8");
|
||||||
|
String fileName = URLEncoder.encode("紧急联系人导入模板", "UTF-8").replaceAll("\\+", "%20");
|
||||||
|
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
|
||||||
|
|
||||||
|
// 示例数据(字段名第一行,示例数据第二行)
|
||||||
|
List<HrmEmergencyContactImportVo> exampleList = new ArrayList<>();
|
||||||
|
|
||||||
|
// 添加示例数据
|
||||||
|
HrmEmergencyContactImportVo example = new HrmEmergencyContactImportVo();
|
||||||
|
example.setHireDate("2025.06.18");
|
||||||
|
example.setCompanyName("山东福安德信息科技有限公司");
|
||||||
|
example.setDeptName("信息化部");
|
||||||
|
example.setRealName("张三");
|
||||||
|
example.setPhone("183xxxxxxxx");
|
||||||
|
example.setIdCard("341xxxxxxxxxxxxxxx");
|
||||||
|
example.setGender("男");
|
||||||
|
example.setAge(23);
|
||||||
|
example.setEmergencyContact("李四");
|
||||||
|
example.setRelationship("母子");
|
||||||
|
example.setEmergencyPhone1("159xxxxxxxx");
|
||||||
|
example.setEmergencyPhone2("");
|
||||||
|
example.setEmergencyAddress("xx省xx市xx县xx镇xx村");
|
||||||
|
example.setRemark("仅紧急情况联系");
|
||||||
|
exampleList.add(example);
|
||||||
|
|
||||||
|
// 使用EasyExcel写入(字段名在第一行,示例数据在第二行)
|
||||||
|
ServletOutputStream out = response.getOutputStream();
|
||||||
|
EasyExcel.write(out, HrmEmergencyContactImportVo.class)
|
||||||
|
.sheet("导入模板")
|
||||||
|
.doWrite(exampleList);
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.ruoyi.hrm.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.ruoyi.common.core.domain.BaseEntity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@TableName("hrm_emergency_contact")
|
||||||
|
public class HrmEmergencyContact extends BaseEntity implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Long contactId;
|
||||||
|
private Long userId;
|
||||||
|
private Long deptId;
|
||||||
|
private String realName;
|
||||||
|
private String phone;
|
||||||
|
private String idCard;
|
||||||
|
private String gender;
|
||||||
|
private Integer age;
|
||||||
|
private String companyName;
|
||||||
|
private Date hireDate;
|
||||||
|
private String emergencyContact;
|
||||||
|
private String relationship;
|
||||||
|
private String emergencyPhone1;
|
||||||
|
private String emergencyPhone2;
|
||||||
|
private String emergencyAddress;
|
||||||
|
private String remark;
|
||||||
|
@TableLogic
|
||||||
|
private Integer delFlag;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.ruoyi.hrm.domain.bo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.ruoyi.common.core.domain.BaseEntity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class HrmEmergencyContactBo extends BaseEntity {
|
||||||
|
|
||||||
|
private Long contactId;
|
||||||
|
|
||||||
|
@NotNull(message = "用户ID不能为空")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
private Long deptId;
|
||||||
|
private String realName;
|
||||||
|
private String phone;
|
||||||
|
private String idCard;
|
||||||
|
private String gender;
|
||||||
|
private Integer age;
|
||||||
|
private String companyName;
|
||||||
|
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
|
private Date hireDate;
|
||||||
|
|
||||||
|
@NotBlank(message = "紧急联系人姓名不能为空")
|
||||||
|
private String emergencyContact;
|
||||||
|
|
||||||
|
private String relationship;
|
||||||
|
|
||||||
|
@NotBlank(message = "紧急联系人电话1不能为空")
|
||||||
|
private String emergencyPhone1;
|
||||||
|
|
||||||
|
private String emergencyPhone2;
|
||||||
|
private String emergencyAddress;
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
package com.ruoyi.hrm.domain.vo;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||||
|
import com.alibaba.excel.annotation.write.style.ContentStyle;
|
||||||
|
import com.alibaba.excel.annotation.write.style.HeadStyle;
|
||||||
|
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
|
||||||
|
import com.ruoyi.common.annotation.Excel;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 紧急联系人导入 VO
|
||||||
|
* 与用户提供的Excel格式保持一致
|
||||||
|
*
|
||||||
|
* Excel表头顺序:
|
||||||
|
* 入职时间 | 公司名称 | 部门 | 姓名 | 联系电话 | 身份证号 | 性别 | 年龄 | 紧急联系人 | 与本人关系 | 联系电话1 | 联系电话2 | 紧急联系人地址 | 备注
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@HeadStyle(fillForegroundColor = 44, horizontalAlignment = HorizontalAlignmentEnum.CENTER)
|
||||||
|
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.LEFT)
|
||||||
|
public class HrmEmergencyContactImportVo implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 入职时间
|
||||||
|
* 格式:yyyy.MM.dd 或 yyyy-MM-dd
|
||||||
|
*/
|
||||||
|
@Excel(name = "入职时间", width = 12)
|
||||||
|
@ExcelProperty("入职时间")
|
||||||
|
@ColumnWidth(12)
|
||||||
|
private String hireDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公司名称
|
||||||
|
*/
|
||||||
|
@Excel(name = "公司名称", width = 40)
|
||||||
|
@ExcelProperty("公司名称")
|
||||||
|
@ColumnWidth(40)
|
||||||
|
private String companyName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门
|
||||||
|
*/
|
||||||
|
@Excel(name = "部门", width = 12)
|
||||||
|
@ExcelProperty("部门")
|
||||||
|
@ColumnWidth(12)
|
||||||
|
private String deptName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 姓名
|
||||||
|
*/
|
||||||
|
@Excel(name = "姓名", width = 10)
|
||||||
|
@ExcelProperty("姓名")
|
||||||
|
@ColumnWidth(10)
|
||||||
|
private String realName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系电话
|
||||||
|
*/
|
||||||
|
@Excel(name = "联系电话", width = 15)
|
||||||
|
@ExcelProperty("联系电话")
|
||||||
|
@ColumnWidth(15)
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 身份证号
|
||||||
|
*/
|
||||||
|
@Excel(name = "身份证号", width = 22)
|
||||||
|
@ExcelProperty("身份证号")
|
||||||
|
@ColumnWidth(22)
|
||||||
|
private String idCard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 性别
|
||||||
|
*/
|
||||||
|
@Excel(name = "性别", width = 8, readConverterExp = "男=0,女=1,未知=2")
|
||||||
|
@ExcelProperty("性别")
|
||||||
|
@ColumnWidth(8)
|
||||||
|
private String gender;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 年龄
|
||||||
|
*/
|
||||||
|
@Excel(name = "年龄", width = 8)
|
||||||
|
@ExcelProperty("年龄")
|
||||||
|
@ColumnWidth(8)
|
||||||
|
private Integer age;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 紧急联系人
|
||||||
|
*/
|
||||||
|
@Excel(name = "紧急联系人", width = 12)
|
||||||
|
@ExcelProperty("紧急联系人")
|
||||||
|
@ColumnWidth(12)
|
||||||
|
private String emergencyContact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 与本人关系
|
||||||
|
*/
|
||||||
|
@Excel(name = "与本人关系", width = 12)
|
||||||
|
@ExcelProperty("与本人关系")
|
||||||
|
@ColumnWidth(12)
|
||||||
|
private String relationship;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系电话1
|
||||||
|
*/
|
||||||
|
@Excel(name = "联系电话1", width = 15)
|
||||||
|
@ExcelProperty("联系电话1")
|
||||||
|
@ColumnWidth(15)
|
||||||
|
private String emergencyPhone1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 联系电话2
|
||||||
|
*/
|
||||||
|
@Excel(name = "联系电话2", width = 15)
|
||||||
|
@ExcelProperty("联系电话2")
|
||||||
|
@ColumnWidth(15)
|
||||||
|
private String emergencyPhone2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 紧急联系人地址
|
||||||
|
*/
|
||||||
|
@Excel(name = "紧急联系人地址", width = 40)
|
||||||
|
@ExcelProperty("紧急联系人地址")
|
||||||
|
@ColumnWidth(40)
|
||||||
|
private String emergencyAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
@Excel(name = "备注", width = 20)
|
||||||
|
@ExcelProperty("备注")
|
||||||
|
@ColumnWidth(20)
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package com.ruoyi.hrm.domain.vo;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import com.ruoyi.common.annotation.Excel;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class HrmEmergencyContactVo implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Excel(name = "联系人ID")
|
||||||
|
private Long contactId;
|
||||||
|
|
||||||
|
@Excel(name = "用户ID")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Excel(name = "部门ID")
|
||||||
|
private Long deptId;
|
||||||
|
|
||||||
|
@Excel(name = "部门名称")
|
||||||
|
private String deptName;
|
||||||
|
|
||||||
|
@Excel(name = "姓名")
|
||||||
|
private String realName;
|
||||||
|
|
||||||
|
@Excel(name = "联系电话")
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
@Excel(name = "身份证号")
|
||||||
|
private String idCard;
|
||||||
|
|
||||||
|
@Excel(name = "性别", readConverterExp = "0=男,1=女,2=未知")
|
||||||
|
private String gender;
|
||||||
|
|
||||||
|
@Excel(name = "年龄")
|
||||||
|
private Integer age;
|
||||||
|
|
||||||
|
@Excel(name = "公司名称")
|
||||||
|
private String companyName;
|
||||||
|
|
||||||
|
@Excel(name = "入职时间", width = 20, dateFormat = "yyyy-MM-dd")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||||
|
private Date hireDate;
|
||||||
|
|
||||||
|
@Excel(name = "紧急联系人")
|
||||||
|
private String emergencyContact;
|
||||||
|
|
||||||
|
@Excel(name = "与本人关系")
|
||||||
|
private String relationship;
|
||||||
|
|
||||||
|
@Excel(name = "紧急电话1")
|
||||||
|
private String emergencyPhone1;
|
||||||
|
|
||||||
|
@Excel(name = "紧急电话2")
|
||||||
|
private String emergencyPhone2;
|
||||||
|
|
||||||
|
@Excel(name = "紧急联系人地址")
|
||||||
|
private String emergencyAddress;
|
||||||
|
|
||||||
|
@Excel(name = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
private String createBy;
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||||
|
private Date createTime;
|
||||||
|
private String updateBy;
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||||
|
private Date updateTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.ruoyi.hrm.mapper;
|
||||||
|
|
||||||
|
import com.ruoyi.common.core.mapper.BaseMapperPlus;
|
||||||
|
import com.ruoyi.hrm.domain.HrmEmergencyContact;
|
||||||
|
import com.ruoyi.hrm.domain.vo.HrmEmergencyContactVo;
|
||||||
|
|
||||||
|
public interface HrmEmergencyContactMapper extends BaseMapperPlus<HrmEmergencyContactMapper, HrmEmergencyContact, HrmEmergencyContactVo> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.ruoyi.hrm.service;
|
||||||
|
|
||||||
|
import com.ruoyi.common.core.domain.PageQuery;
|
||||||
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
|
import com.ruoyi.hrm.domain.bo.HrmEmergencyContactBo;
|
||||||
|
import com.ruoyi.hrm.domain.vo.HrmEmergencyContactVo;
|
||||||
|
import com.ruoyi.hrm.domain.vo.HrmEmergencyContactImportVo;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface IHrmEmergencyContactService {
|
||||||
|
|
||||||
|
HrmEmergencyContactVo queryById(Long contactId);
|
||||||
|
|
||||||
|
TableDataInfo<HrmEmergencyContactVo> queryPageList(HrmEmergencyContactBo bo, PageQuery pageQuery);
|
||||||
|
|
||||||
|
List<HrmEmergencyContactVo> queryList(HrmEmergencyContactBo bo);
|
||||||
|
|
||||||
|
Boolean insertByBo(HrmEmergencyContactBo bo);
|
||||||
|
|
||||||
|
Boolean updateByBo(HrmEmergencyContactBo bo);
|
||||||
|
|
||||||
|
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||||
|
|
||||||
|
String importByVoList(List<HrmEmergencyContactImportVo> voList, boolean updateSupport);
|
||||||
|
}
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
package com.ruoyi.hrm.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.ruoyi.common.core.domain.PageQuery;
|
||||||
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
|
import com.ruoyi.hrm.domain.HrmEmergencyContact;
|
||||||
|
import com.ruoyi.hrm.domain.bo.HrmEmergencyContactBo;
|
||||||
|
import com.ruoyi.hrm.domain.vo.HrmEmergencyContactVo;
|
||||||
|
import com.ruoyi.hrm.domain.vo.HrmEmergencyContactImportVo;
|
||||||
|
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||||
|
import com.ruoyi.hrm.mapper.HrmEmergencyContactMapper;
|
||||||
|
import com.ruoyi.hrm.service.IHrmEmergencyContactService;
|
||||||
|
import com.ruoyi.system.mapper.SysUserMapper;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service
|
||||||
|
public class HrmEmergencyContactServiceImpl implements IHrmEmergencyContactService {
|
||||||
|
|
||||||
|
private final HrmEmergencyContactMapper baseMapper;
|
||||||
|
private final SysUserMapper sysUserMapper;
|
||||||
|
|
||||||
|
// 手机号正则
|
||||||
|
private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
|
||||||
|
// 身份证号正则(15位或18位)
|
||||||
|
private static final Pattern ID_CARD_PATTERN = Pattern.compile("(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x)$)");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HrmEmergencyContactVo queryById(Long contactId) {
|
||||||
|
return baseMapper.selectVoById(contactId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableDataInfo<HrmEmergencyContactVo> queryPageList(HrmEmergencyContactBo bo, PageQuery pageQuery) {
|
||||||
|
LambdaQueryWrapper<HrmEmergencyContact> lqw = buildQueryWrapper(bo);
|
||||||
|
Page<HrmEmergencyContactVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||||
|
return TableDataInfo.build(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<HrmEmergencyContactVo> queryList(HrmEmergencyContactBo bo) {
|
||||||
|
LambdaQueryWrapper<HrmEmergencyContact> lqw = buildQueryWrapper(bo);
|
||||||
|
return baseMapper.selectVoList(lqw);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Boolean insertByBo(HrmEmergencyContactBo bo) {
|
||||||
|
HrmEmergencyContact add = BeanUtil.toBean(bo, HrmEmergencyContact.class);
|
||||||
|
return baseMapper.insert(add) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Boolean updateByBo(HrmEmergencyContactBo bo) {
|
||||||
|
HrmEmergencyContact update = BeanUtil.toBean(bo, HrmEmergencyContact.class);
|
||||||
|
return baseMapper.updateById(update) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||||
|
return baseMapper.deleteBatchIds(ids) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public String importByVoList(List<HrmEmergencyContactImportVo> voList, boolean updateSupport) {
|
||||||
|
if (CollUtil.isEmpty(voList)) {
|
||||||
|
throw new ServiceException("导入数据不能为空");
|
||||||
|
}
|
||||||
|
int successNum = 0;
|
||||||
|
int failNum = 0;
|
||||||
|
StringBuilder failMsg = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 0; i < voList.size(); i++) {
|
||||||
|
HrmEmergencyContactImportVo vo = voList.get(i);
|
||||||
|
int rowNum = i + 2;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 转换日期格式:将 yyyy.MM.dd 转换为 yyyy-MM-dd
|
||||||
|
Date hireDate = null;
|
||||||
|
if (StrUtil.isNotBlank(vo.getHireDate())) {
|
||||||
|
String dateStr = vo.getHireDate().replace(".", "-");
|
||||||
|
vo.setHireDate(dateStr);
|
||||||
|
hireDate = DateUtil.parseDate(dateStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 性别转换:Excel 中为"男"/"女"/"未知",统一转代码值
|
||||||
|
String gender = vo.getGender();
|
||||||
|
if (StrUtil.isNotBlank(gender)) {
|
||||||
|
if ("男".equals(gender)) { gender = "0"; }
|
||||||
|
else if ("女".equals(gender)) { gender = "1"; }
|
||||||
|
else if ("未知".equals(gender)) { gender = "2"; }
|
||||||
|
vo.setGender(gender);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据校验
|
||||||
|
String validateMsg = validateImportData(vo);
|
||||||
|
if (StrUtil.isNotBlank(validateMsg)) {
|
||||||
|
failNum++;
|
||||||
|
failMsg.append("<br/>").append(failNum).append("、第").append(rowNum).append("行 ")
|
||||||
|
.append(StrUtil.blankToDefault(vo.getRealName(), "无名")).append(":").append(validateMsg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
HrmEmergencyContact entity = BeanUtil.toBean(vo, HrmEmergencyContact.class);
|
||||||
|
// 根据姓名+身份证号匹配 sys_user,自动填充 userId/deptId
|
||||||
|
Long matchedUserId = matchUserId(vo.getRealName(), vo.getIdCard());
|
||||||
|
entity.setUserId(matchedUserId != null ? matchedUserId : 0L);
|
||||||
|
// 显式设置入职日期(BeanUtil 可能无法自动转换 String -> Date)
|
||||||
|
if (hireDate != null) {
|
||||||
|
entity.setHireDate(hireDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按「姓名 + 身份证号」去重
|
||||||
|
LambdaQueryWrapper<HrmEmergencyContact> lqw = Wrappers.lambdaQuery();
|
||||||
|
lqw.eq(HrmEmergencyContact::getRealName, entity.getRealName());
|
||||||
|
lqw.eq(HrmEmergencyContact::getIdCard, entity.getIdCard());
|
||||||
|
HrmEmergencyContact existing = baseMapper.selectOne(lqw);
|
||||||
|
|
||||||
|
if (existing != null) {
|
||||||
|
if (updateSupport) {
|
||||||
|
entity.setContactId(existing.getContactId());
|
||||||
|
baseMapper.updateById(entity);
|
||||||
|
successNum++;
|
||||||
|
} else {
|
||||||
|
failNum++;
|
||||||
|
failMsg.append("<br/>").append(failNum).append("、第").append(rowNum).append("行 ")
|
||||||
|
.append(vo.getRealName()).append(":数据已存在(姓名+身份证号重复)");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
baseMapper.insert(entity);
|
||||||
|
successNum++;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
failNum++;
|
||||||
|
failMsg.append("<br/>").append(failNum).append("、第").append(rowNum).append("行 ")
|
||||||
|
.append(StrUtil.blankToDefault(vo.getRealName(), "无名")).append(":导入失败,").append(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failNum > 0) {
|
||||||
|
return "导入完成!成功 " + successNum + " 条,失败 " + failNum + " 条。错误信息:" + failMsg;
|
||||||
|
}
|
||||||
|
return "恭喜您,数据已全部导入成功!共 " + successNum + " 条";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据姓名+身份证号匹配 sys_user,返回 userId;匹配不到返回 null
|
||||||
|
*/
|
||||||
|
private Long matchUserId(String realName, String idCard) {
|
||||||
|
// 1. 优先按 realName + idCard 精确匹配
|
||||||
|
if (StrUtil.isNotBlank(realName) && StrUtil.isNotBlank(idCard)) {
|
||||||
|
SysUser user = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
|
||||||
|
.eq(SysUser::getNickName, realName)
|
||||||
|
.eq(SysUser::getIdCard, idCard)
|
||||||
|
.last("limit 1"));
|
||||||
|
if (user != null) {
|
||||||
|
return user.getUserId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2. 仅按 idCard 匹配(唯一性高)
|
||||||
|
if (StrUtil.isNotBlank(idCard)) {
|
||||||
|
SysUser user = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
|
||||||
|
.eq(SysUser::getIdCard, idCard)
|
||||||
|
.last("limit 1"));
|
||||||
|
if (user != null) {
|
||||||
|
return user.getUserId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 3. 仅按 realName 匹配(有重名风险,作为最后的兜底)
|
||||||
|
if (StrUtil.isNotBlank(realName)) {
|
||||||
|
SysUser user = sysUserMapper.selectOne(Wrappers.<SysUser>lambdaQuery()
|
||||||
|
.eq(SysUser::getNickName, realName)
|
||||||
|
.last("limit 1"));
|
||||||
|
if (user != null) {
|
||||||
|
return user.getUserId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验导入数据
|
||||||
|
*/
|
||||||
|
private String validateImportData(HrmEmergencyContactImportVo vo) {
|
||||||
|
StringBuilder msg = new StringBuilder();
|
||||||
|
|
||||||
|
if (StrUtil.isBlank(vo.getRealName())) {
|
||||||
|
msg.append("姓名为空;");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(vo.getPhone())) {
|
||||||
|
msg.append("联系电话为空;");
|
||||||
|
} else if (!PHONE_PATTERN.matcher(vo.getPhone()).matches()) {
|
||||||
|
msg.append("联系电话格式错误(需11位手机号);");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(vo.getIdCard())) {
|
||||||
|
msg.append("身份证号为空;");
|
||||||
|
} else if (!ID_CARD_PATTERN.matcher(vo.getIdCard()).matches()) {
|
||||||
|
msg.append("身份证号格式错误;");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(vo.getGender())) {
|
||||||
|
msg.append("性别为空;");
|
||||||
|
}
|
||||||
|
if (vo.getAge() == null) {
|
||||||
|
msg.append("年龄为空;");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(vo.getEmergencyContact())) {
|
||||||
|
msg.append("紧急联系人为空;");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(vo.getRelationship())) {
|
||||||
|
msg.append("与本人关系为空;");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(vo.getEmergencyPhone1())) {
|
||||||
|
msg.append("联系电话1为空;");
|
||||||
|
} else if (!PHONE_PATTERN.matcher(vo.getEmergencyPhone1()).matches()) {
|
||||||
|
msg.append("联系电话1格式错误(需11位手机号);");
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(vo.getEmergencyAddress())) {
|
||||||
|
msg.append("紧急联系人地址为空;");
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(vo.getEmergencyPhone2()) && !PHONE_PATTERN.matcher(vo.getEmergencyPhone2()).matches()) {
|
||||||
|
msg.append("联系电话2格式错误(需11位手机号);");
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private LambdaQueryWrapper<HrmEmergencyContact> buildQueryWrapper(HrmEmergencyContactBo bo) {
|
||||||
|
LambdaQueryWrapper<HrmEmergencyContact> lqw = Wrappers.lambdaQuery();
|
||||||
|
lqw.eq(bo.getContactId() != null, HrmEmergencyContact::getContactId, bo.getContactId());
|
||||||
|
lqw.eq(bo.getUserId() != null, HrmEmergencyContact::getUserId, bo.getUserId());
|
||||||
|
lqw.like(bo.getRealName() != null, HrmEmergencyContact::getRealName, bo.getRealName());
|
||||||
|
lqw.like(bo.getPhone() != null, HrmEmergencyContact::getPhone, bo.getPhone());
|
||||||
|
lqw.like(bo.getEmergencyContact() != null, HrmEmergencyContact::getEmergencyContact, bo.getEmergencyContact());
|
||||||
|
lqw.eq(bo.getDeptId() != null, HrmEmergencyContact::getDeptId, bo.getDeptId());
|
||||||
|
lqw.eq(bo.getGender() != null, HrmEmergencyContact::getGender, bo.getGender());
|
||||||
|
return lqw;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.ruoyi.hrm.mapper.HrmEmergencyContactMapper">
|
||||||
|
<resultMap id="BaseResultMap" type="com.ruoyi.hrm.domain.HrmEmergencyContact">
|
||||||
|
<id column="contact_id" property="contactId"/>
|
||||||
|
<result column="user_id" property="userId"/>
|
||||||
|
<result column="dept_id" property="deptId"/>
|
||||||
|
<result column="real_name" property="realName"/>
|
||||||
|
<result column="phone" property="phone"/>
|
||||||
|
<result column="id_card" property="idCard"/>
|
||||||
|
<result column="gender" property="gender"/>
|
||||||
|
<result column="age" property="age"/>
|
||||||
|
<result column="company_name" property="companyName"/>
|
||||||
|
<result column="hire_date" property="hireDate"/>
|
||||||
|
<result column="emergency_contact" property="emergencyContact"/>
|
||||||
|
<result column="relationship" property="relationship"/>
|
||||||
|
<result column="emergency_phone1" property="emergencyPhone1"/>
|
||||||
|
<result column="emergency_phone2" property="emergencyPhone2"/>
|
||||||
|
<result column="emergency_address" property="emergencyAddress"/>
|
||||||
|
<result column="remark" property="remark"/>
|
||||||
|
<result column="create_by" property="createBy"/>
|
||||||
|
<result column="create_time" property="createTime"/>
|
||||||
|
<result column="update_by" property="updateBy"/>
|
||||||
|
<result column="update_time" property="updateTime"/>
|
||||||
|
<result column="del_flag" property="delFlag"/>
|
||||||
|
</resultMap>
|
||||||
|
</mapper>
|
||||||
55
ruoyi-ui/src/api/hrm/emergencyContact.js
Normal file
55
ruoyi-ui/src/api/hrm/emergencyContact.js
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
import { download } from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询紧急联系人列表
|
||||||
|
export function listEmergencyContact(query) {
|
||||||
|
return request({
|
||||||
|
url: '/hrm/emergencyContact/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询紧急联系人详细
|
||||||
|
export function getEmergencyContact(contactId) {
|
||||||
|
return request({
|
||||||
|
url: `/hrm/emergencyContact/${contactId}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增紧急联系人
|
||||||
|
export function addEmergencyContact(data) {
|
||||||
|
return request({
|
||||||
|
url: '/hrm/emergencyContact',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改紧急联系人
|
||||||
|
export function updateEmergencyContact(data) {
|
||||||
|
return request({
|
||||||
|
url: '/hrm/emergencyContact',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除紧急联系人
|
||||||
|
export function delEmergencyContact(contactIds) {
|
||||||
|
return request({
|
||||||
|
url: `/hrm/emergencyContact/${contactIds}`,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出紧急联系人
|
||||||
|
export function exportEmergencyContact(query) {
|
||||||
|
return download('/hrm/emergencyContact/export', query, '紧急联系人数据.xlsx')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载导入模板
|
||||||
|
export function importTemplate() {
|
||||||
|
return download('/hrm/emergencyContact/importTemplate', {}, '紧急联系人导入模板.xlsx')
|
||||||
|
}
|
||||||
@@ -12,4 +12,5 @@ export * from './org'
|
|||||||
export * from './reimburse'
|
export * from './reimburse'
|
||||||
export * from './seal'
|
export * from './seal'
|
||||||
export * from './travel'
|
export * from './travel'
|
||||||
|
export * from './emergencyContact'
|
||||||
|
|
||||||
|
|||||||
449
ruoyi-ui/src/views/hrm/emergencyContact/index.vue
Normal file
449
ruoyi-ui/src/views/hrm/emergencyContact/index.vue
Normal file
@@ -0,0 +1,449 @@
|
|||||||
|
<template>
|
||||||
|
<div class="emergency-contact-page">
|
||||||
|
<el-card shadow="never" class="main-card">
|
||||||
|
<div slot="header" class="card-header">
|
||||||
|
<span class="header-title">员工紧急联系人</span>
|
||||||
|
<div class="header-actions">
|
||||||
|
<el-input v-model="query.realName" placeholder="姓名" size="small" clearable style="width: 160px;"
|
||||||
|
@keyup.enter.native="loadList" />
|
||||||
|
<el-input v-model="query.emergencyContact" placeholder="紧急联系人" size="small" clearable style="width: 160px;"
|
||||||
|
@keyup.enter.native="loadList" />
|
||||||
|
<el-select v-model="query.deptId" size="small" placeholder="部门" clearable filterable style="width: 160px;"
|
||||||
|
@change="loadList">
|
||||||
|
<el-option v-for="dept in deptOptions" :key="dept.deptId" :label="dept.deptName" :value="dept.deptId" />
|
||||||
|
</el-select>
|
||||||
|
<el-button size="small" type="primary" icon="el-icon-search" @click="loadList">查询</el-button>
|
||||||
|
<el-button size="small" type="primary" icon="el-icon-plus" @click="handleAdd">新增</el-button>
|
||||||
|
<el-button size="small" icon="el-icon-download" @click="handleExport">导出</el-button>
|
||||||
|
<el-button size="small" icon="el-icon-upload2" @click="importVisible = true">导入</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table :data="list" v-loading="loading" stripe height="calc(100vh - 280px)">
|
||||||
|
<el-table-column prop="hireDate" label="入职时间" min-width="110" />
|
||||||
|
<el-table-column prop="realName" label="姓名" min-width="100" />
|
||||||
|
<el-table-column prop="phone" label="联系电话" min-width="130" />
|
||||||
|
<el-table-column prop="gender" label="性别" min-width="60">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ { '0': '男', '1': '女', '2': '未知' }[scope.row.gender] || '-' }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="age" label="年龄" min-width="60" />
|
||||||
|
<el-table-column prop="companyName" label="公司名称" min-width="200" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="emergencyContact" label="紧急联系人" min-width="100" />
|
||||||
|
<el-table-column prop="relationship" label="关系" min-width="80" />
|
||||||
|
<el-table-column prop="emergencyPhone1" label="紧急电话1" min-width="130" />
|
||||||
|
<el-table-column prop="emergencyPhone2" label="紧急电话2" min-width="130" />
|
||||||
|
<el-table-column prop="remark" label="备注" min-width="140" show-overflow-tooltip />
|
||||||
|
<el-table-column label="操作" width="180" fixed="right">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button type="text" size="mini" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
|
||||||
|
<el-button type="text" size="mini" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<div class="pagination-wrapper">
|
||||||
|
<el-pagination :current-page="query.pageNum" :page-sizes="[10, 20, 50, 100]" :page-size="query.pageSize"
|
||||||
|
:total="total" layout="total, sizes, prev, pager, next, jumper" @size-change="handleSizeChange"
|
||||||
|
@current-change="handlePageChange" />
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 新增/编辑弹窗 -->
|
||||||
|
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="800px" append-to-body>
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px" size="small">
|
||||||
|
<el-divider content-position="left">员工信息</el-divider>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="选择人员" prop="userId">
|
||||||
|
<el-select v-model="form.userId" placeholder="请选择人员" filterable remote
|
||||||
|
:remote-method="searchUsers" :loading="userLoading" style="width: 100%" clearable
|
||||||
|
@change="handleUserChange">
|
||||||
|
<el-option v-for="user in userOptions" :key="user.userId"
|
||||||
|
:label="`${user.nickName} (${user.userName})`" :value="user.userId" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="姓名" prop="realName">
|
||||||
|
<el-input v-model="form.realName" placeholder="自动带出可修改" :disabled="!form.userId" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="联系电话" prop="phone">
|
||||||
|
<el-input v-model="form.phone" placeholder="自动带出可修改" :disabled="!form.userId" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="性别" prop="gender">
|
||||||
|
<el-select v-model="form.gender" placeholder="自动带出可修改" style="width: 100%" :disabled="!form.userId">
|
||||||
|
<el-option label="男" value="0" />
|
||||||
|
<el-option label="女" value="1" />
|
||||||
|
<el-option label="未知" value="2" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="身份证号" prop="idCard">
|
||||||
|
<el-input v-model="form.idCard" placeholder="自动带出可修改" :disabled="!form.userId" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="年龄" prop="age">
|
||||||
|
<el-input-number v-model="form.age" :min="0" :max="150" style="width: 100%" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-divider content-position="left">公司信息</el-divider>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="公司名称" prop="companyName">
|
||||||
|
<el-input v-model="form.companyName" placeholder="请输入公司名称" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="入职时间" prop="hireDate">
|
||||||
|
<el-date-picker v-model="form.hireDate" type="date" placeholder="选择日期" style="width: 100%"
|
||||||
|
value-format="yyyy-MM-dd" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-divider content-position="left">紧急联系人</el-divider>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="联系人姓名" prop="emergencyContact">
|
||||||
|
<el-input v-model="form.emergencyContact" placeholder="请输入紧急联系人姓名" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="与本人关系" prop="relationship">
|
||||||
|
<el-select v-model="form.relationship" placeholder="请选择关系" style="width: 100%" clearable filterable>
|
||||||
|
<el-option label="配偶" value="配偶" />
|
||||||
|
<el-option label="父母" value="父母" />
|
||||||
|
<el-option label="子女" value="子女" />
|
||||||
|
<el-option label="兄弟姐妹" value="兄弟姐妹" />
|
||||||
|
<el-option label="朋友" value="朋友" />
|
||||||
|
<el-option label="同事" value="同事" />
|
||||||
|
<el-option label="其他" value="其他" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="联系电话1" prop="emergencyPhone1">
|
||||||
|
<el-input v-model="form.emergencyPhone1" placeholder="请输入紧急联系人电话" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="联系电话2" prop="emergencyPhone2">
|
||||||
|
<el-input v-model="form.emergencyPhone2" placeholder="请输入备用电话" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="联系地址" prop="emergencyAddress">
|
||||||
|
<el-input v-model="form.emergencyAddress" placeholder="请输入紧急联系人地址" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="dialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="submitting" @click="handleSubmit">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 导入弹窗 -->
|
||||||
|
<el-dialog title="导入紧急联系人数据" :visible.sync="importVisible" width="500px" append-to-body>
|
||||||
|
<!-- 导入规则说明 -->
|
||||||
|
<el-alert
|
||||||
|
title="导入规则说明"
|
||||||
|
type="info"
|
||||||
|
:closable="false"
|
||||||
|
style="margin-bottom: 15px;"
|
||||||
|
>
|
||||||
|
<div slot="description" style="font-size: 12px; line-height: 1.8;">
|
||||||
|
<p>1. <strong>文件格式</strong>:必须是 .xlsx 格式,表头顺序不能乱</p>
|
||||||
|
<p>2. <strong>必填字段</strong>:带 * 号的为必填项(姓名、联系电话、身份证号、性别、年龄等)</p>
|
||||||
|
<p>3. <strong>重复数据</strong>:系统会按「姓名 + 身份证号」去重,已存在的记录会自动更新</p>
|
||||||
|
<p>4. <strong>数据校验</strong>:手机号必须为 11 位数字,身份证号会做基础格式校验</p>
|
||||||
|
<p>5. <strong>导入后核对</strong>:导入完成后请在列表页核对数据,如有错误可直接修改</p>
|
||||||
|
</div>
|
||||||
|
</el-alert>
|
||||||
|
|
||||||
|
<el-upload ref="upload" :limit="1" accept=".xlsx,.xls" :headers="upload.headers"
|
||||||
|
:action="upload.url" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress"
|
||||||
|
:on-success="handleFileSuccess" :on-error="handleFileError" :auto-upload="false"
|
||||||
|
drag>
|
||||||
|
<i class="el-icon-upload" />
|
||||||
|
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
|
||||||
|
<div slot="tip" class="el-upload__tip" style="color:red;padding:0 12px">
|
||||||
|
仅允许导入 xlsx / xls 格式文件。
|
||||||
|
<el-link type="primary" :underline="false" style="font-size:12px" @click="handleDownloadTemplate">下载导入模板(含字段说明和示例数据)</el-link>
|
||||||
|
</div>
|
||||||
|
</el-upload>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="importVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="upload.isUploading" @click="submitImport">确定导入</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { listDept } from '@/api/system/dept'
|
||||||
|
import { selectUser } from '@/api/system/user'
|
||||||
|
import { listEmergencyContact, addEmergencyContact, updateEmergencyContact, delEmergencyContact, exportEmergencyContact, importTemplate } from '@/api/hrm/emergencyContact'
|
||||||
|
import { getToken } from '@/utils/auth'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'HrmEmergencyContact',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
submitting: false,
|
||||||
|
list: [],
|
||||||
|
total: 0,
|
||||||
|
deptOptions: [],
|
||||||
|
userOptions: [],
|
||||||
|
userLoading: false,
|
||||||
|
query: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
realName: '',
|
||||||
|
emergencyContact: '',
|
||||||
|
deptId: null
|
||||||
|
},
|
||||||
|
dialogVisible: false,
|
||||||
|
dialogTitle: '新增紧急联系人',
|
||||||
|
form: {},
|
||||||
|
rules: {
|
||||||
|
userId: [{ required: true, message: '请选择人员', trigger: 'change' }],
|
||||||
|
emergencyContact: [{ required: true, message: '请输入紧急联系人姓名', trigger: 'blur' }],
|
||||||
|
emergencyPhone1: [{ required: true, message: '请输入紧急联系人电话', trigger: 'blur' }]
|
||||||
|
},
|
||||||
|
// 导入相关
|
||||||
|
importVisible: false,
|
||||||
|
upload: {
|
||||||
|
headers: { Authorization: 'Bearer ' + getToken() },
|
||||||
|
url: process.env.VUE_APP_BASE_API + '/hrm/emergencyContact/importData',
|
||||||
|
isUploading: false
|
||||||
|
},
|
||||||
|
// 导入字段说明
|
||||||
|
importFieldDesc: [
|
||||||
|
{ field: '入职时间', required: false, desc: '格式:yyyy-MM-dd', example: '2025-06-18' },
|
||||||
|
{ field: '公司名称', required: true, desc: '全称,与OA内一致', example: '山东福安德信息科技有限公司' },
|
||||||
|
{ field: '部门', required: true, desc: '与OA内部门名称一致', example: '信息化部' },
|
||||||
|
{ field: '姓名', required: true, desc: '员工真实姓名', example: '张三' },
|
||||||
|
{ field: '联系电话', required: true, desc: '员工本人手机号,11位数字', example: '183xxxxxxxx' },
|
||||||
|
{ field: '身份证号', required: true, desc: '18位或15位,含X大写', example: '341xxxxxxxxxxxxxxx' },
|
||||||
|
{ field: '性别', required: true, desc: '男 / 女', example: '男' },
|
||||||
|
{ field: '年龄', required: true, desc: '整数,按周岁填写', example: '23' },
|
||||||
|
{ field: '紧急联系人', required: true, desc: '联系人真实姓名', example: '李四' },
|
||||||
|
{ field: '与本人关系', required: true, desc: '如父子/母子/夫妻等', example: '母子' },
|
||||||
|
{ field: '联系电话1', required: true, desc: '紧急联系人手机号,11位数字', example: '159xxxxxxxx' },
|
||||||
|
{ field: '联系电话2', required: false, desc: '备用手机号,11位数字', example: '182xxxxxxxx' },
|
||||||
|
{ field: '紧急联系人地址', required: true, desc: '详细地址', example: 'xx省xx市xx县xx镇' },
|
||||||
|
{ field: '备注', required: false, desc: '补充说明', example: '仅紧急情况联系' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.loadDeptOptions()
|
||||||
|
this.loadList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadDeptOptions() {
|
||||||
|
listDept({}).then(res => {
|
||||||
|
this.deptOptions = res.data || []
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadList() {
|
||||||
|
this.loading = true
|
||||||
|
listEmergencyContact(this.query).then(res => {
|
||||||
|
this.list = res.rows || []
|
||||||
|
this.total = res.total || 0
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleSizeChange(val) {
|
||||||
|
this.query.pageSize = val
|
||||||
|
this.loadList()
|
||||||
|
},
|
||||||
|
handlePageChange(val) {
|
||||||
|
this.query.pageNum = val
|
||||||
|
this.loadList()
|
||||||
|
},
|
||||||
|
handleAdd() {
|
||||||
|
this.dialogTitle = '新增紧急联系人'
|
||||||
|
this.form = {
|
||||||
|
userId: undefined,
|
||||||
|
realName: '',
|
||||||
|
phone: '',
|
||||||
|
idCard: '',
|
||||||
|
gender: '0',
|
||||||
|
age: undefined,
|
||||||
|
companyName: '',
|
||||||
|
hireDate: undefined,
|
||||||
|
emergencyContact: '',
|
||||||
|
relationship: '',
|
||||||
|
emergencyPhone1: '',
|
||||||
|
emergencyPhone2: '',
|
||||||
|
emergencyAddress: '',
|
||||||
|
remark: ''
|
||||||
|
}
|
||||||
|
this.userOptions = []
|
||||||
|
this.dialogVisible = true
|
||||||
|
this.$nextTick(() => { this.$refs.formRef?.clearValidate() })
|
||||||
|
},
|
||||||
|
handleEdit(row) {
|
||||||
|
this.dialogTitle = '编辑紧急联系人'
|
||||||
|
this.form = { ...row }
|
||||||
|
// 加载已选用户信息用于展示
|
||||||
|
if (this.form.userId) {
|
||||||
|
this.searchUsers('')
|
||||||
|
}
|
||||||
|
this.dialogVisible = true
|
||||||
|
this.$nextTick(() => { this.$refs.formRef?.clearValidate() })
|
||||||
|
},
|
||||||
|
handleDelete(row) {
|
||||||
|
this.$confirm(`确认删除 "${row.realName}" 的紧急联系人信息吗?`, '提示', { type: 'warning' }).then(() => {
|
||||||
|
delEmergencyContact(row.contactId).then(() => {
|
||||||
|
this.$message.success('删除成功')
|
||||||
|
this.loadList()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
searchUsers(query) {
|
||||||
|
this.userLoading = true
|
||||||
|
selectUser({ userName: query, nickName: query, pageNum: 1, pageSize: 20 }).then(res => {
|
||||||
|
this.userOptions = res.rows || []
|
||||||
|
// 编辑时确保已选用户在选项中
|
||||||
|
if (this.form.userId && !this.userOptions.find(u => u.userId === this.form.userId)) {
|
||||||
|
selectUser({ userId: this.form.userId }).then(res2 => {
|
||||||
|
if (res2.rows && res2.rows.length > 0) {
|
||||||
|
this.userOptions.unshift(res2.rows[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
this.userLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleUserChange(userId) {
|
||||||
|
if (!userId) return
|
||||||
|
const user = this.userOptions.find(u => u.userId === userId)
|
||||||
|
if (user) {
|
||||||
|
this.form.realName = user.nickName || ''
|
||||||
|
this.form.phone = user.phonenumber || ''
|
||||||
|
this.form.gender = user.sex || '0'
|
||||||
|
this.form.idCard = user.idCard || ''
|
||||||
|
// 根据身份证号计算年龄
|
||||||
|
if (user.idCard && user.idCard.length >= 18) {
|
||||||
|
const birthYear = parseInt(user.idCard.substring(6, 10))
|
||||||
|
const currentYear = new Date().getFullYear()
|
||||||
|
this.form.age = currentYear - birthYear
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSubmit() {
|
||||||
|
this.$refs.formRef.validate(valid => {
|
||||||
|
if (!valid) return
|
||||||
|
this.submitting = true
|
||||||
|
const api = this.form.contactId ? updateEmergencyContact : addEmergencyContact
|
||||||
|
api(this.form).then(() => {
|
||||||
|
this.$message.success(this.form.contactId ? '更新成功' : '新增成功')
|
||||||
|
this.dialogVisible = false
|
||||||
|
if (!this.form.contactId) {
|
||||||
|
this.query.pageNum = 1
|
||||||
|
}
|
||||||
|
this.loadList()
|
||||||
|
}).finally(() => {
|
||||||
|
this.submitting = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 导出
|
||||||
|
handleExport() {
|
||||||
|
this.$confirm('确认导出紧急联系人数据吗?', '提示', { type: 'warning' }).then(() => {
|
||||||
|
exportEmergencyContact(this.query)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 下载导入模板
|
||||||
|
handleDownloadTemplate() {
|
||||||
|
importTemplate()
|
||||||
|
},
|
||||||
|
handleFileUploadProgress() {
|
||||||
|
this.upload.isUploading = true
|
||||||
|
},
|
||||||
|
handleFileSuccess(res) {
|
||||||
|
this.upload.isUploading = false
|
||||||
|
this.$refs.upload.clearFiles()
|
||||||
|
this.importVisible = false
|
||||||
|
this.$modal.msgSuccess(res.msg || '导入成功')
|
||||||
|
this.loadList()
|
||||||
|
},
|
||||||
|
handleFileError() {
|
||||||
|
this.upload.isUploading = false
|
||||||
|
this.$message.error('导入失败,请检查文件格式')
|
||||||
|
},
|
||||||
|
submitImport() {
|
||||||
|
this.$refs.upload.submit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.emergency-contact-page {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f0f2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-card {
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.header-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-wrapper {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
41
sql/hrm_emergency_contact.sql
Normal file
41
sql/hrm_emergency_contact.sql
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
-- =====================================================================
|
||||||
|
-- 员工紧急联系人信息表
|
||||||
|
-- 通过 user_id 关联 sys_user,自动带出姓名/性别/身份证号/联系电话
|
||||||
|
-- =====================================================================
|
||||||
|
CREATE TABLE IF NOT EXISTS `hrm_emergency_contact` (
|
||||||
|
`contact_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '紧急联系人ID',
|
||||||
|
|
||||||
|
-- 关联信息(从 sys_user 自动带出 / 关联查询)
|
||||||
|
`user_id` BIGINT NOT NULL COMMENT '用户ID(关联 sys_user)',
|
||||||
|
`dept_id` BIGINT DEFAULT NULL COMMENT '部门ID(关联 sys_dept,从 sys_user 自动带出)',
|
||||||
|
|
||||||
|
-- 员工基本信息(新增/导入时从 sys_user 自动填充,允许手动修改)
|
||||||
|
`real_name` VARCHAR(30) DEFAULT NULL COMMENT '姓名(从 sys_user.nick_name 自动带出)',
|
||||||
|
`phone` VARCHAR(20) DEFAULT NULL COMMENT '联系电话(从 sys_user.phonenumber 自动带出)',
|
||||||
|
`id_card` VARCHAR(200) DEFAULT NULL COMMENT '身份证号(从 sys_user.id_card 自动带出)',
|
||||||
|
`gender` CHAR(1) DEFAULT '0' COMMENT '性别(0男 1女 2未知,从 sys_user.sex 自动带出)',
|
||||||
|
`age` INT DEFAULT NULL COMMENT '年龄',
|
||||||
|
|
||||||
|
-- 公司信息(sys_user 无此字段,手动录入)
|
||||||
|
`company_name` VARCHAR(100) DEFAULT NULL COMMENT '公司名称',
|
||||||
|
`hire_date` DATE DEFAULT NULL COMMENT '入职时间',
|
||||||
|
|
||||||
|
-- 紧急联系人信息
|
||||||
|
`emergency_contact` VARCHAR(30) DEFAULT NULL COMMENT '紧急联系人姓名',
|
||||||
|
`relationship` VARCHAR(30) DEFAULT NULL COMMENT '与本人关系',
|
||||||
|
`emergency_phone1` VARCHAR(20) DEFAULT NULL COMMENT '紧急联系人电话1',
|
||||||
|
`emergency_phone2` VARCHAR(20) DEFAULT NULL COMMENT '紧急联系人电话2',
|
||||||
|
`emergency_address` VARCHAR(200) DEFAULT NULL COMMENT '紧急联系人地址',
|
||||||
|
|
||||||
|
-- 基础字段
|
||||||
|
`remark` VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`del_flag` CHAR(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||||
|
`create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||||
|
|
||||||
|
PRIMARY KEY (`contact_id`) USING BTREE,
|
||||||
|
KEY `idx_user_id` (`user_id`) USING BTREE,
|
||||||
|
KEY `idx_dept_id` (`dept_id`) USING BTREE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='员工紧急联系人信息表';
|
||||||
30
sql/hrm_emergency_contact_cleanup.sql
Normal file
30
sql/hrm_emergency_contact_cleanup.sql
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
-- =====================================================================
|
||||||
|
-- 清理紧急联系人菜单脏数据(执行前请确认)
|
||||||
|
-- =====================================================================
|
||||||
|
|
||||||
|
-- 方式1:按 menu_id 范围删除(如果之前用的是 2000-2100 或 2070-2076)
|
||||||
|
-- DELETE FROM sys_menu WHERE menu_id BETWEEN 2000 AND 2100;
|
||||||
|
-- DELETE FROM sys_menu WHERE menu_id BETWEEN 2070 AND 2076;
|
||||||
|
|
||||||
|
-- 方式2:按菜单名称删除(推荐,更精确)
|
||||||
|
-- DELETE FROM sys_menu WHERE menu_name = '紧急联系人';
|
||||||
|
|
||||||
|
-- 方式3:按权限标识删除(删除所有相关按钮权限)
|
||||||
|
-- DELETE FROM sys_menu WHERE perms LIKE 'hrm:emergencyContact:%';
|
||||||
|
|
||||||
|
-- 方式4:组合删除(先查后删,安全)
|
||||||
|
-- 先查询确认
|
||||||
|
SELECT menu_id, menu_name, parent_id, perms, create_time
|
||||||
|
FROM sys_menu
|
||||||
|
WHERE menu_name = '紧急联系人'
|
||||||
|
OR perms LIKE 'hrm:emergencyContact:%';
|
||||||
|
|
||||||
|
-- 确认无误后再执行删除
|
||||||
|
-- DELETE FROM sys_menu WHERE menu_name = '紧急联系人' OR perms LIKE 'hrm:emergencyContact:%';
|
||||||
|
|
||||||
|
-- =====================================================================
|
||||||
|
-- 执行步骤:
|
||||||
|
-- 1. 先执行 SELECT 查询,确认要删除的数据
|
||||||
|
-- 2. 确认无误后,再执行 DELETE 语句
|
||||||
|
-- 3. 删除完成后,在若依系统菜单管理界面手动添加菜单
|
||||||
|
-- =====================================================================
|
||||||
115
sql/hrm_emergency_contact_manual_guide.md
Normal file
115
sql/hrm_emergency_contact_manual_guide.md
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
# 紧急联系人菜单手动添加指南
|
||||||
|
|
||||||
|
## 第一步:清理脏数据(在Navicat/DBeaver中执行)
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 先查询确认
|
||||||
|
SELECT menu_id, menu_name, parent_id, perms, create_time
|
||||||
|
FROM sys_menu
|
||||||
|
WHERE menu_name = '紧急联系人'
|
||||||
|
OR perms LIKE 'hrm:emergencyContact:%';
|
||||||
|
|
||||||
|
-- 确认无误后再执行删除
|
||||||
|
DELETE FROM sys_menu
|
||||||
|
WHERE menu_name = '紧急联系人'
|
||||||
|
OR perms LIKE 'hrm:emergencyContact:%';
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第二步:在若依系统菜单管理中手动添加
|
||||||
|
|
||||||
|
### 1. 添加主菜单
|
||||||
|
|
||||||
|
进入 **系统管理 → 菜单管理**,点击【新增】按钮,填写以下信息:
|
||||||
|
|
||||||
|
| 字段 | 值 |
|
||||||
|
|------|-----|
|
||||||
|
| 上级菜单 | 人事中心(或你想要的父菜单) |
|
||||||
|
| 菜单类型 | 菜单 |
|
||||||
|
| 菜单图标 | user |
|
||||||
|
| 菜单名称 | 紧急联系人 |
|
||||||
|
| 显示排序 | 99 |
|
||||||
|
| 是否外链 | 否 |
|
||||||
|
| 路由地址 | emergencyContact |
|
||||||
|
| 组件路径 | hrm/emergencyContact/index |
|
||||||
|
| 权限字符 | hrm:emergencyContact:list |
|
||||||
|
| 路由参数 | (留空) |
|
||||||
|
| 是否缓存 | 缓存 |
|
||||||
|
| 显示状态 | 显示 |
|
||||||
|
| 菜单状态 | 正常 |
|
||||||
|
|
||||||
|
点击【确定】保存。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. 添加按钮权限
|
||||||
|
|
||||||
|
主菜单添加成功后,在菜单列表中找到【紧急联系人】,点击右侧的【新增】按钮(添加子菜单/按钮)。
|
||||||
|
|
||||||
|
需要添加以下6个按钮权限:
|
||||||
|
|
||||||
|
#### ① 查询按钮
|
||||||
|
- 菜单类型:按钮
|
||||||
|
- 菜单名称:查询
|
||||||
|
- 显示排序:1
|
||||||
|
- 权限字符:hrm:emergencyContact:query
|
||||||
|
- 显示状态:显示
|
||||||
|
- 菜单状态:正常
|
||||||
|
|
||||||
|
#### ② 新增按钮
|
||||||
|
- 菜单类型:按钮
|
||||||
|
- 菜单名称:新增
|
||||||
|
- 显示排序:2
|
||||||
|
- 权限字符:hrm:emergencyContact:add
|
||||||
|
- 显示状态:显示
|
||||||
|
- 菜单状态:正常
|
||||||
|
|
||||||
|
#### ③ 修改按钮
|
||||||
|
- 菜单类型:按钮
|
||||||
|
- 菜单名称:修改
|
||||||
|
- 显示排序:3
|
||||||
|
- 权限字符:hrm:emergencyContact:edit
|
||||||
|
- 显示状态:显示
|
||||||
|
- 菜单状态:正常
|
||||||
|
|
||||||
|
#### ④ 删除按钮
|
||||||
|
- 菜单类型:按钮
|
||||||
|
- 菜单名称:删除
|
||||||
|
- 显示排序:4
|
||||||
|
- 权限字符:hrm:emergencyContact:remove
|
||||||
|
- 显示状态:显示
|
||||||
|
- 菜单状态:正常
|
||||||
|
|
||||||
|
#### ⑤ 导出按钮
|
||||||
|
- 菜单类型:按钮
|
||||||
|
- 菜单名称:导出
|
||||||
|
- 显示排序:5
|
||||||
|
- 权限字符:hrm:emergencyContact:export
|
||||||
|
- 显示状态:显示
|
||||||
|
- 菜单状态:正常
|
||||||
|
|
||||||
|
#### ⑥ 导入按钮
|
||||||
|
- 菜单类型:按钮
|
||||||
|
- 菜单名称:导入
|
||||||
|
- 显示排序:6
|
||||||
|
- 权限字符:hrm:emergencyContact:import
|
||||||
|
- 显示状态:显示
|
||||||
|
- 菜单状态:正常
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第三步:刷新系统
|
||||||
|
|
||||||
|
1. 添加完成后,**退出登录**或 **刷新页面**
|
||||||
|
2. 重新登录后,在对应父菜单下应该能看到【紧急联系人】菜单
|
||||||
|
3. 进入菜单测试功能是否正常
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. **上级菜单选择**:如果想放在"人事中心"下,就选择"人事中心";如果想放在顶级,就选择"主类目"
|
||||||
|
2. **权限字符**:必须严格按照 `hrm:emergencyContact:list`、`hrm:emergencyContact:query` 等格式填写
|
||||||
|
3. **路由地址**:必须与前端路由配置一致,这里是 `emergencyContact`
|
||||||
|
4. **组件路径**:必须与前端组件路径一致,这里是 `hrm/emergencyContact/index`
|
||||||
42
sql/hrm_emergency_contact_menu.sql
Normal file
42
sql/hrm_emergency_contact_menu.sql
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
-- =====================================================================
|
||||||
|
-- 菜单 SQL:员工紧急联系人管理(若依框架兼容版)
|
||||||
|
-- 必须分步执行,不能批量执行!
|
||||||
|
-- =====================================================================
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 第一步:清理可能存在的脏数据(如果之前执行失败过)
|
||||||
|
-- ============================================================
|
||||||
|
-- DELETE FROM sys_menu WHERE menu_id BETWEEN 2070 AND 2076;
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 第二步:插入主菜单(先执行这行,成功后再执行按钮)
|
||||||
|
-- parent_id = 0 表示顶级菜单,可根据需要改为实际的HRM菜单ID
|
||||||
|
-- ============================================================
|
||||||
|
INSERT INTO sys_menu (
|
||||||
|
menu_id, menu_name, parent_id, order_num, path, component, query_param,
|
||||||
|
is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time
|
||||||
|
) VALUES (
|
||||||
|
2070, '紧急联系人', 0, 99, 'emergencyContact', 'hrm/emergencyContact/index', '',
|
||||||
|
1, 0, 'C', '0', '0', 'hrm:emergencyContact:list', 'user', 'admin', NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 第三步:主菜单插入成功后,再执行按钮权限
|
||||||
|
-- ============================================================
|
||||||
|
INSERT INTO sys_menu (
|
||||||
|
menu_id, menu_name, parent_id, order_num, path, component,
|
||||||
|
is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time
|
||||||
|
) VALUES
|
||||||
|
(2071, '查询', 2070, 1, '#', NULL, 1, 0, 'F', '0', '0', 'hrm:emergencyContact:query', '#', 'admin', NOW()),
|
||||||
|
(2072, '新增', 2070, 2, '#', NULL, 1, 0, 'F', '0', '0', 'hrm:emergencyContact:add', '#', 'admin', NOW()),
|
||||||
|
(2073, '修改', 2070, 3, '#', NULL, 1, 0, 'F', '0', '0', 'hrm:emergencyContact:edit', '#', 'admin', NOW()),
|
||||||
|
(2074, '删除', 2070, 4, '#', NULL, 1, 0, 'F', '0', '0', 'hrm:emergencyContact:remove', '#', 'admin', NOW()),
|
||||||
|
(2075, '导出', 2070, 5, '#', NULL, 1, 0, 'F', '0', '0', 'hrm:emergencyContact:export', '#', 'admin', NOW()),
|
||||||
|
(2076, '导入', 2070, 6, '#', NULL, 1, 0, 'F', '0', '0', 'hrm:emergencyContact:import', '#', 'admin', NOW());
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- 使用说明:
|
||||||
|
-- 1. 如果之前执行失败过,先执行第一步的 DELETE 清理脏数据
|
||||||
|
-- 2. 先执行第二步(主菜单),确认成功后再执行第三步(按钮权限)
|
||||||
|
-- 3. 如需将菜单放在HRM模块下,将 parent_id 从 0 改为 HRM菜单的实际ID
|
||||||
|
-- ============================================================
|
||||||
24
sql/hrm_emergency_contact_sample_data.sql
Normal file
24
sql/hrm_emergency_contact_sample_data.sql
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
-- =====================================================================
|
||||||
|
-- 示例数据:信息部员工紧急联系人
|
||||||
|
-- 使用前请将 user_id 替换为实际 sys_user 表中的 ID
|
||||||
|
-- =====================================================================
|
||||||
|
|
||||||
|
-- 示例数据1:张伟
|
||||||
|
INSERT INTO `hrm_emergency_contact` (`user_id`, `dept_id`, `real_name`, `phone`, `id_card`, `gender`, `age`, `company_name`, `hire_date`, `emergency_contact`, `relationship`, `emergency_phone1`, `emergency_phone2`, `emergency_address`, `remark`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
VALUES (1, 100, '张伟', '13800138001', '110101199001011234', '0', 36, '上海泛微网络科技股份有限公司', '2022-03-15', '李芳', '配偶', '13900139001', '13800138002', '上海市浦东新区张江高科技园区200号', '信息部经理', '0', 'admin', NOW());
|
||||||
|
|
||||||
|
-- 示例数据2:李娜
|
||||||
|
INSERT INTO `hrm_emergency_contact` (`user_id`, `dept_id`, `real_name`, `phone`, `id_card`, `gender`, `age`, `company_name`, `hire_date`, `emergency_contact`, `relationship`, `emergency_phone1`, `emergency_phone2`, `emergency_address`, `remark`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
VALUES (2, 100, '李娜', '13800138003', '110101199205022345', '1', 34, '上海泛微网络科技股份有限公司', '2021-07-01', '王强', '配偶', '13900139003', '', '上海市徐汇区漕河泾开发区100号', '需求分析师', '0', 'admin', NOW());
|
||||||
|
|
||||||
|
-- 示例数据3:王强
|
||||||
|
INSERT INTO `hrm_emergency_contact` (`user_id`, `dept_id`, `real_name`, `phone`, `id_card`, `gender`, `age`, `company_name`, `hire_date`, `emergency_contact`, `relationship`, `emergency_phone1`, `emergency_phone2`, `emergency_address`, `remark`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
VALUES (3, 100, '王强', '13800138005', '110101198803033456', '0', 38, '上海泛微网络科技股份有限公司', '2020-01-10', '刘静', '配偶', '13900139005', '13800138006', '上海市闵行区七宝镇50号', '开发主管', '0', 'admin', NOW());
|
||||||
|
|
||||||
|
-- 示例数据4:赵敏
|
||||||
|
INSERT INTO `hrm_emergency_contact` (`user_id`, `dept_id`, `real_name`, `phone`, `id_card`, `gender`, `age`, `company_name`, `hire_date`, `emergency_contact`, `relationship`, `emergency_phone1`, `emergency_phone2`, `emergency_address`, `remark`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
VALUES (4, 100, '赵敏', '13800138007', '110101199507044567', '1', 31, '上海泛微网络科技股份有限公司', '2023-05-20', '赵建国', '父母', '13900139007', '', '上海市静安区南京西路300号', '前端开发', '0', 'admin', NOW());
|
||||||
|
|
||||||
|
-- 示例数据5:陈浩
|
||||||
|
INSERT INTO `hrm_emergency_contact` (`user_id`, `dept_id`, `real_name`, `phone`, `id_card`, `gender`, `age`, `company_name`, `hire_date`, `emergency_contact`, `relationship`, `emergency_phone1`, `emergency_phone2`, `emergency_address`, `remark`, `del_flag`, `create_by`, `create_time`)
|
||||||
|
VALUES (5, 100, '陈浩', '13800138009', '110101199608055678', '0', 30, '上海泛微网络科技股份有限公司', '2022-11-01', '陈芳', '父母', '13900139009', '13800138010', '上海市浦东新区陆家嘴环路1000号', '后端开发', '0', 'admin', NOW());
|
||||||
BIN
sql/信息部紧急联系人导入.xlsx
Normal file
BIN
sql/信息部紧急联系人导入.xlsx
Normal file
Binary file not shown.
25
sql/紧急联系人导入模板示例.xlsx
Normal file
25
sql/紧急联系人导入模板示例.xlsx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
这是一个示例说明文件,实际Excel模板需要通过系统下载
|
||||||
|
|
||||||
|
Excel模板字段顺序:
|
||||||
|
1. 入职时间 (yyyy.MM.dd格式,如:2025.06.18)
|
||||||
|
2. 公司名称 (如:山东福安德信息科技有限公司)
|
||||||
|
3. 部门 (如:信息化部)
|
||||||
|
4. 姓名 (如:高鑫磊)
|
||||||
|
5. 联系电话 (如:18324818443)
|
||||||
|
6. 身份证号 (如:341222200309052816)
|
||||||
|
7. 性别 (男/女/未知)
|
||||||
|
8. 年龄 (如:23)
|
||||||
|
9. 紧急联系人 (如:李继敏)
|
||||||
|
10. 与本人关系 (如:母子)
|
||||||
|
11. 联系电话1 (如:15955868031)
|
||||||
|
12. 联系电话2 (可选)
|
||||||
|
13. 紧急联系人地址 (如:安徽省阜阳市太和县皮条孙镇)
|
||||||
|
14. 备注 (可选)
|
||||||
|
|
||||||
|
示例数据:
|
||||||
|
2025.06.18,山东福安德信息科技有限公司,信息化部,高鑫磊,18324818443,341222200309052816,男,23,李继敏,母子,15955868031,,安徽省阜阳市太和县皮条孙镇,
|
||||||
|
2025.06.18,山东福安德信息科技有限公司,信息化部,刘敬超,19932047759,13043520021117093X,男,24,刘建领,父子,18932719783,,河北省邯郸市曲周县槐桥乡,
|
||||||
|
,山东福安德信息科技有限公司,信息化部,王文昊,19711921991,130923200312073014,男,22,王海军,父子,18233665966,18233691998,河北省沧州市东光县,
|
||||||
|
,山东福安德信息科技有限公司,信息化部,井昊东,17803227053,13063420041124001X,男,22,井小苗,母子,13803279482,18603228769,河北省保定市曲阳县七里庄村,
|
||||||
|
,山东福安德信息科技有限公司,信息化部,祖启佳,13308587452,520221200406220769,女,22,黄倩,母女,18188276838,,贵州省六盘水市水城县,
|
||||||
|
,山东福安德信息科技有限公司,信息化部,朱昊天,19930382154,131121200310093614,男,22,朱庆忠,父子,15832865136,,河北省衡水市枣强县,
|
||||||
Reference in New Issue
Block a user