feat 员工调动记录
This commit is contained in:
@@ -23,6 +23,12 @@
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 系统模块 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- easyexcel工具 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
|
||||
@@ -5,10 +5,7 @@ import com.ruoyi.ccdi.domain.dto.CcdiBaseStaffAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiBaseStaffEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiBaseStaffQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiBaseStaffExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiBaseStaffVO;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportFailureVO;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportResultVO;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
||||
import com.ruoyi.ccdi.domain.vo.*;
|
||||
import com.ruoyi.ccdi.service.ICcdiBaseStaffImportService;
|
||||
import com.ruoyi.ccdi.service.ICcdiBaseStaffService;
|
||||
import com.ruoyi.ccdi.utils.EasyExcelUtil;
|
||||
@@ -61,6 +58,17 @@ public class CcdiBaseStaffController extends BaseController {
|
||||
return getDataTable(result.getRecords(), result.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询员工下拉列表
|
||||
*/
|
||||
@Operation(summary = "查询员工下拉列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:baseStaff:list')")
|
||||
@GetMapping("/options")
|
||||
public AjaxResult getStaffOptions(@RequestParam(required = false) String query) {
|
||||
List<CcdiBaseStaffOptionVO> list = baseStaffService.selectStaffOptions(query);
|
||||
return success(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出员工列表
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
package com.ruoyi.ccdi.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffTransferAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffTransferEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffTransferQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiStaffTransferExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiStaffTransferVO;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportResultVO;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
||||
import com.ruoyi.ccdi.domain.vo.StaffTransferImportFailureVO;
|
||||
import com.ruoyi.ccdi.service.ICcdiStaffTransferImportService;
|
||||
import com.ruoyi.ccdi.service.ICcdiStaffTransferService;
|
||||
import com.ruoyi.ccdi.utils.EasyExcelUtil;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.PageDomain;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.page.TableSupport;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 员工调动记录Controller
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
@Tag(name = "员工调动记录管理")
|
||||
@RestController
|
||||
@RequestMapping("/ccdi/staffTransfer")
|
||||
public class CcdiStaffTransferController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private ICcdiStaffTransferService transferService;
|
||||
|
||||
@Resource
|
||||
private ICcdiStaffTransferImportService transferImportService;
|
||||
|
||||
/**
|
||||
* 查询员工调动记录列表
|
||||
*/
|
||||
@Operation(summary = "查询员工调动记录列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffTransfer:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(CcdiStaffTransferQueryDTO queryDTO) {
|
||||
// 使用MyBatis Plus分页
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
Page<CcdiStaffTransferVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
|
||||
Page<CcdiStaffTransferVO> result = transferService.selectTransferPage(page, queryDTO);
|
||||
return getDataTable(result.getRecords(), result.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出员工调动记录列表
|
||||
*/
|
||||
@Operation(summary = "导出员工调动记录列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffTransfer:export')")
|
||||
@Log(title = "员工调动记录", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, CcdiStaffTransferQueryDTO queryDTO) {
|
||||
List<CcdiStaffTransferExcel> list = transferService.selectTransferListForExport(queryDTO);
|
||||
EasyExcelUtil.exportExcel(response, list, CcdiStaffTransferExcel.class, "员工调动记录信息");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取员工调动记录详细信息
|
||||
*/
|
||||
@Operation(summary = "获取员工调动记录详细信息")
|
||||
@Parameter(name = "id", description = "主键ID", required = true)
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffTransfer:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable Long id) {
|
||||
return success(transferService.selectTransferById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增员工调动记录
|
||||
*/
|
||||
@Operation(summary = "新增员工调动记录")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffTransfer:add')")
|
||||
@Log(title = "员工调动记录", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@Validated @RequestBody CcdiStaffTransferAddDTO addDTO) {
|
||||
return toAjax(transferService.insertTransfer(addDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改员工调动记录
|
||||
*/
|
||||
@Operation(summary = "修改员工调动记录")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffTransfer:edit')")
|
||||
@Log(title = "员工调动记录", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@Validated @RequestBody CcdiStaffTransferEditDTO editDTO) {
|
||||
return toAjax(transferService.updateTransfer(editDTO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除员工调动记录
|
||||
*/
|
||||
@Operation(summary = "删除员工调动记录")
|
||||
@Parameter(name = "ids", description = "主键ID数组", required = true)
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffTransfer:remove')")
|
||||
@Log(title = "员工调动记录", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(transferService.deleteTransferByIds(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载带字典下拉框的导入模板
|
||||
* 使用@DictDropdown注解自动添加下拉框
|
||||
*/
|
||||
@Operation(summary = "下载导入模板")
|
||||
@PostMapping("/importTemplate")
|
||||
public void importTemplate(HttpServletResponse response) {
|
||||
EasyExcelUtil.importTemplateWithDictDropdown(response, CcdiStaffTransferExcel.class, "员工调动记录信息");
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步导入员工调动记录
|
||||
*/
|
||||
@Operation(summary = "异步导入员工调动记录")
|
||||
@Parameter(name = "file", description = "导入文件", required = true)
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffTransfer:import')")
|
||||
@Log(title = "员工调动记录", businessType = BusinessType.IMPORT)
|
||||
@PostMapping("/importData")
|
||||
public AjaxResult importData(@Parameter(description = "导入文件") MultipartFile file) throws Exception {
|
||||
List<CcdiStaffTransferExcel> list = EasyExcelUtil.importExcel(file.getInputStream(), CcdiStaffTransferExcel.class);
|
||||
|
||||
if (list == null || list.isEmpty()) {
|
||||
return error("至少需要一条数据");
|
||||
}
|
||||
|
||||
// 提交异步任务
|
||||
String taskId = transferService.importTransfer(list);
|
||||
|
||||
// 立即返回,不等待后台任务完成
|
||||
ImportResultVO result = new ImportResultVO();
|
||||
result.setTaskId(taskId);
|
||||
result.setStatus("PROCESSING");
|
||||
result.setMessage("导入任务已提交,正在后台处理");
|
||||
|
||||
return AjaxResult.success("导入任务已提交,正在后台处理", result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询导入状态
|
||||
*/
|
||||
@Operation(summary = "查询导入状态")
|
||||
@Parameter(name = "taskId", description = "任务ID", required = true)
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffTransfer:import')")
|
||||
@GetMapping("/importStatus/{taskId}")
|
||||
public AjaxResult getImportStatus(@PathVariable String taskId) {
|
||||
ImportStatusVO statusVO = transferImportService.getImportStatus(taskId);
|
||||
return success(statusVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询导入失败记录
|
||||
*/
|
||||
@Operation(summary = "查询导入失败记录")
|
||||
@Parameter(name = "taskId", description = "任务ID", required = true)
|
||||
@Parameter(name = "pageNum", description = "页码", required = false)
|
||||
@Parameter(name = "pageSize", description = "每页条数", required = false)
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:staffTransfer:import')")
|
||||
@GetMapping("/importFailures/{taskId}")
|
||||
public TableDataInfo getImportFailures(
|
||||
@PathVariable String taskId,
|
||||
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize) {
|
||||
|
||||
List<StaffTransferImportFailureVO> failures = transferImportService.getImportFailures(taskId);
|
||||
|
||||
// 手动分页
|
||||
int fromIndex = (pageNum - 1) * pageSize;
|
||||
int toIndex = Math.min(fromIndex + pageSize, failures.size());
|
||||
|
||||
List<StaffTransferImportFailureVO> pageData = failures.subList(fromIndex, toIndex);
|
||||
|
||||
return getDataTable(pageData, failures.size());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.ruoyi.ccdi.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 员工调动记录对象 ccdi_staff_transfer
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
@Data
|
||||
@TableName("ccdi_staff_transfer")
|
||||
public class CcdiStaffTransfer implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/** 员工ID,关联ccdi_base_staff.staff_id */
|
||||
private Long staffId;
|
||||
|
||||
/** 调动类型 */
|
||||
private String transferType;
|
||||
|
||||
/** 调动子类型 */
|
||||
private String transferSubType;
|
||||
|
||||
/** 调动前部门ID */
|
||||
private Long deptIdBefore;
|
||||
|
||||
/** 调动前部门 */
|
||||
private String deptNameBefore;
|
||||
|
||||
/** 调动前职级 */
|
||||
private String gradeBefore;
|
||||
|
||||
/** 调动前岗位 */
|
||||
private String positionBefore;
|
||||
|
||||
/** 调动前薪酬等级 */
|
||||
private String salaryLevelBefore;
|
||||
|
||||
/** 调动后部门ID */
|
||||
private Long deptIdAfter;
|
||||
|
||||
/** 调动后部门 */
|
||||
private String deptNameAfter;
|
||||
|
||||
/** 调动后职级 */
|
||||
private String gradeAfter;
|
||||
|
||||
/** 调动后岗位 */
|
||||
private String positionAfter;
|
||||
|
||||
/** 调动后薪酬等级 */
|
||||
private String salaryLevelAfter;
|
||||
|
||||
/** 调动日期 */
|
||||
private Date transferDate;
|
||||
|
||||
/** 创建时间 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
/** 更新时间 */
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Date updateTime;
|
||||
|
||||
/** 创建人 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createdBy;
|
||||
|
||||
/** 更新人 */
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private String updatedBy;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.ruoyi.ccdi.domain.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 员工调动记录新增DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "员工调动记录新增")
|
||||
public class CcdiStaffTransferAddDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 员工ID */
|
||||
@NotNull(message = "员工ID不能为空")
|
||||
@Schema(description = "员工ID")
|
||||
private Long staffId;
|
||||
|
||||
/** 调动类型 */
|
||||
@NotBlank(message = "调动类型不能为空")
|
||||
@Size(max = 50, message = "调动类型长度不能超过50个字符")
|
||||
@Schema(description = "调动类型")
|
||||
private String transferType;
|
||||
|
||||
/** 调动子类型 */
|
||||
@Size(max = 100, message = "调动子类型长度不能超过100个字符")
|
||||
@Schema(description = "调动子类型")
|
||||
private String transferSubType;
|
||||
|
||||
/** 调动前部门ID */
|
||||
@NotNull(message = "调动前部门ID不能为空")
|
||||
@Schema(description = "调动前部门ID")
|
||||
private Long deptIdBefore;
|
||||
|
||||
/** 调动前部门 */
|
||||
@Size(max = 200, message = "调动前部门长度不能超过200个字符")
|
||||
@Schema(description = "调动前部门")
|
||||
private String deptNameBefore;
|
||||
|
||||
/** 调动前职级 */
|
||||
@Size(max = 50, message = "调动前职级长度不能超过50个字符")
|
||||
@Schema(description = "调动前职级")
|
||||
private String gradeBefore;
|
||||
|
||||
/** 调动前岗位 */
|
||||
@Size(max = 100, message = "调动前岗位长度不能超过100个字符")
|
||||
@Schema(description = "调动前岗位")
|
||||
private String positionBefore;
|
||||
|
||||
/** 调动前薪酬等级 */
|
||||
@Size(max = 50, message = "调动前薪酬等级长度不能超过50个字符")
|
||||
@Schema(description = "调动前薪酬等级")
|
||||
private String salaryLevelBefore;
|
||||
|
||||
/** 调动后部门ID */
|
||||
@NotNull(message = "调动后部门ID不能为空")
|
||||
@Schema(description = "调动后部门ID")
|
||||
private Long deptIdAfter;
|
||||
|
||||
/** 调动后部门 */
|
||||
@Size(max = 200, message = "调动后部门长度不能超过200个字符")
|
||||
@Schema(description = "调动后部门")
|
||||
private String deptNameAfter;
|
||||
|
||||
/** 调动后职级 */
|
||||
@Size(max = 50, message = "调动后职级长度不能超过50个字符")
|
||||
@Schema(description = "调动后职级")
|
||||
private String gradeAfter;
|
||||
|
||||
/** 调动后岗位 */
|
||||
@Size(max = 100, message = "调动后岗位长度不能超过100个字符")
|
||||
@Schema(description = "调动后岗位")
|
||||
private String positionAfter;
|
||||
|
||||
/** 调动后薪酬等级 */
|
||||
@Size(max = 50, message = "调动后薪酬等级长度不能超过50个字符")
|
||||
@Schema(description = "调动后薪酬等级")
|
||||
private String salaryLevelAfter;
|
||||
|
||||
/** 调动日期 */
|
||||
@NotNull(message = "调动日期不能为空")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@Schema(description = "调动日期")
|
||||
private Date transferDate;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.ruoyi.ccdi.domain.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 员工调动记录修改DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "员工调动记录修改")
|
||||
public class CcdiStaffTransferEditDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@NotNull(message = "主键ID不能为空")
|
||||
@Schema(description = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/** 员工ID */
|
||||
@NotNull(message = "员工ID不能为空")
|
||||
@Schema(description = "员工ID")
|
||||
private Long staffId;
|
||||
|
||||
/** 调动类型 */
|
||||
@Size(max = 50, message = "调动类型长度不能超过50个字符")
|
||||
@Schema(description = "调动类型")
|
||||
private String transferType;
|
||||
|
||||
/** 调动子类型 */
|
||||
@Size(max = 100, message = "调动子类型长度不能超过100个字符")
|
||||
@Schema(description = "调动子类型")
|
||||
private String transferSubType;
|
||||
|
||||
/** 调动前部门ID */
|
||||
@Schema(description = "调动前部门ID")
|
||||
private Long deptIdBefore;
|
||||
|
||||
/** 调动前部门 */
|
||||
@Size(max = 200, message = "调动前部门长度不能超过200个字符")
|
||||
@Schema(description = "调动前部门")
|
||||
private String deptNameBefore;
|
||||
|
||||
/** 调动前职级 */
|
||||
@Size(max = 50, message = "调动前职级长度不能超过50个字符")
|
||||
@Schema(description = "调动前职级")
|
||||
private String gradeBefore;
|
||||
|
||||
/** 调动前岗位 */
|
||||
@Size(max = 100, message = "调动前岗位长度不能超过100个字符")
|
||||
@Schema(description = "调动前岗位")
|
||||
private String positionBefore;
|
||||
|
||||
/** 调动前薪酬等级 */
|
||||
@Size(max = 50, message = "调动前薪酬等级长度不能超过50个字符")
|
||||
@Schema(description = "调动前薪酬等级")
|
||||
private String salaryLevelBefore;
|
||||
|
||||
/** 调动后部门ID */
|
||||
@Schema(description = "调动后部门ID")
|
||||
private Long deptIdAfter;
|
||||
|
||||
/** 调动后部门 */
|
||||
@Size(max = 200, message = "调动后部门长度不能超过200个字符")
|
||||
@Schema(description = "调动后部门")
|
||||
private String deptNameAfter;
|
||||
|
||||
/** 调动后职级 */
|
||||
@Size(max = 50, message = "调动后职级长度不能超过50个字符")
|
||||
@Schema(description = "调动后职级")
|
||||
private String gradeAfter;
|
||||
|
||||
/** 调动后岗位 */
|
||||
@Size(max = 100, message = "调动后岗位长度不能超过100个字符")
|
||||
@Schema(description = "调动后岗位")
|
||||
private String positionAfter;
|
||||
|
||||
/** 调动后薪酬等级 */
|
||||
@Size(max = 50, message = "调动后薪酬等级长度不能超过50个字符")
|
||||
@Schema(description = "调动后薪酬等级")
|
||||
private String salaryLevelAfter;
|
||||
|
||||
/** 调动日期 */
|
||||
@NotNull(message = "调动日期不能为空")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@Schema(description = "调动日期")
|
||||
private Date transferDate;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.ruoyi.ccdi.domain.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 员工调动记录查询DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "员工调动记录查询")
|
||||
public class CcdiStaffTransferQueryDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 员工ID(模糊查询) */
|
||||
@Schema(description = "员工ID")
|
||||
private Long staffId;
|
||||
|
||||
/** 员工姓名(模糊查询) */
|
||||
@Schema(description = "员工姓名")
|
||||
private String staffName;
|
||||
|
||||
/** 调动类型(精确查询) */
|
||||
@Schema(description = "调动类型")
|
||||
private String transferType;
|
||||
|
||||
/** 调动子类型 */
|
||||
@Schema(description = "调动子类型")
|
||||
private String transferSubType;
|
||||
|
||||
/** 调动前部门ID */
|
||||
@Schema(description = "调动前部门ID")
|
||||
private Long deptIdBefore;
|
||||
|
||||
/** 调动后部门ID */
|
||||
@Schema(description = "调动后部门ID")
|
||||
private Long deptIdAfter;
|
||||
|
||||
/** 调动日期开始 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@Schema(description = "调动日期开始")
|
||||
private Date transferDateStart;
|
||||
|
||||
/** 调动日期结束 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@Schema(description = "调动日期结束")
|
||||
private Date transferDateEnd;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.ruoyi.ccdi.domain.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 员工调动记录唯一键DTO
|
||||
* 用于唯一性校验:员工ID + 调动前部门ID + 调动后部门ID + 调动日期
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-11
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "员工调动记录唯一键")
|
||||
public class TransferUniqueKey implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 员工ID
|
||||
*/
|
||||
@Schema(description = "员工ID")
|
||||
private Long staffId;
|
||||
|
||||
/**
|
||||
* 调动前部门ID
|
||||
*/
|
||||
@Schema(description = "调动前部门ID")
|
||||
private Long deptIdBefore;
|
||||
|
||||
/**
|
||||
* 调动后部门ID
|
||||
*/
|
||||
@Schema(description = "调动后部门ID")
|
||||
private Long deptIdAfter;
|
||||
|
||||
/**
|
||||
* 调动日期
|
||||
*/
|
||||
@Schema(description = "调动日期")
|
||||
private Date transferDate;
|
||||
|
||||
/**
|
||||
* 生成唯一标识字符串
|
||||
* 格式: staffId_deptIdBefore_deptIdAfter_transferDate的时间戳
|
||||
*
|
||||
* @return 唯一标识字符串
|
||||
*/
|
||||
public String toUniqueString() {
|
||||
return staffId + "_" +
|
||||
deptIdBefore + "_" +
|
||||
deptIdAfter + "_" +
|
||||
(transferDate != null ? transferDate.getTime() : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从AddDTO构建唯一键
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @return 唯一键
|
||||
*/
|
||||
public static TransferUniqueKey from(CcdiStaffTransferAddDTO addDTO) {
|
||||
TransferUniqueKey key = new TransferUniqueKey();
|
||||
key.setStaffId(addDTO.getStaffId());
|
||||
key.setDeptIdBefore(addDTO.getDeptIdBefore());
|
||||
key.setDeptIdAfter(addDTO.getDeptIdAfter());
|
||||
key.setTransferDate(addDTO.getTransferDate());
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从EditDTO构建唯一键
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @return 唯一键
|
||||
*/
|
||||
public static TransferUniqueKey from(CcdiStaffTransferEditDTO editDTO) {
|
||||
TransferUniqueKey key = new TransferUniqueKey();
|
||||
key.setStaffId(editDTO.getStaffId());
|
||||
key.setDeptIdBefore(editDTO.getDeptIdBefore());
|
||||
key.setDeptIdAfter(editDTO.getDeptIdAfter());
|
||||
key.setTransferDate(editDTO.getTransferDate());
|
||||
return key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.ruoyi.ccdi.domain.excel;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||
import com.ruoyi.common.annotation.DictDropdown;
|
||||
import com.ruoyi.common.annotation.Required;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 员工调动记录Excel导入导出对象
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
@Data
|
||||
public class CcdiStaffTransferExcel implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 员工ID */
|
||||
@ExcelProperty(value = "员工ID*", index = 0)
|
||||
@ColumnWidth(15)
|
||||
@Required
|
||||
private Long staffId;
|
||||
|
||||
/** 调动类型 */
|
||||
@ExcelProperty(value = "调动类型*", index = 1)
|
||||
@ColumnWidth(15)
|
||||
@DictDropdown(dictType = "ccdi_transfer_type")
|
||||
@Required
|
||||
private String transferType;
|
||||
|
||||
/** 调动子类型 */
|
||||
@ExcelProperty(value = "调动子类型", index = 2)
|
||||
@ColumnWidth(15)
|
||||
private String transferSubType;
|
||||
|
||||
/** 调动前部门ID */
|
||||
@ExcelProperty(value = "调动前部门ID*", index = 3)
|
||||
@ColumnWidth(15)
|
||||
@Required
|
||||
private Long deptIdBefore;
|
||||
|
||||
/** 调动前职级 */
|
||||
@ExcelProperty(value = "调动前职级", index = 4)
|
||||
@ColumnWidth(15)
|
||||
private String gradeBefore;
|
||||
|
||||
/** 调动前岗位 */
|
||||
@ExcelProperty(value = "调动前岗位", index = 5)
|
||||
@ColumnWidth(15)
|
||||
private String positionBefore;
|
||||
|
||||
/** 调动前薪酬等级 */
|
||||
@ExcelProperty(value = "调动前薪酬等级", index = 6)
|
||||
@ColumnWidth(15)
|
||||
private String salaryLevelBefore;
|
||||
|
||||
/** 调动后部门ID */
|
||||
@ExcelProperty(value = "调动后部门ID*", index = 7)
|
||||
@ColumnWidth(15)
|
||||
@Required
|
||||
private Long deptIdAfter;
|
||||
|
||||
/** 调动后职级 */
|
||||
@ExcelProperty(value = "调动后职级", index = 8)
|
||||
@ColumnWidth(15)
|
||||
private String gradeAfter;
|
||||
|
||||
/** 调动后岗位 */
|
||||
@ExcelProperty(value = "调动后岗位", index = 9)
|
||||
@ColumnWidth(15)
|
||||
private String positionAfter;
|
||||
|
||||
/** 调动后薪酬等级 */
|
||||
@ExcelProperty(value = "调动后薪酬等级", index = 10)
|
||||
@ColumnWidth(15)
|
||||
private String salaryLevelAfter;
|
||||
|
||||
/** 调动日期 */
|
||||
@ExcelProperty(value = "调动日期*", index = 11)
|
||||
@ColumnWidth(15)
|
||||
@Required
|
||||
private Date transferDate;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.ruoyi.ccdi.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 员工选项VO(用于下拉选择框)
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
@Data
|
||||
public class CcdiBaseStaffOptionVO {
|
||||
|
||||
/**
|
||||
* 员工ID
|
||||
*/
|
||||
private Long staffId;
|
||||
|
||||
/**
|
||||
* 员工姓名
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String deptName;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.ruoyi.ccdi.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 员工调动记录VO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "员工调动记录")
|
||||
public class CcdiStaffTransferVO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@Schema(description = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/** 员工ID */
|
||||
@Schema(description = "员工ID")
|
||||
private Long staffId;
|
||||
|
||||
/** 员工姓名 */
|
||||
@Schema(description = "员工姓名")
|
||||
private String staffName;
|
||||
|
||||
/** 调动类型 */
|
||||
@Schema(description = "调动类型")
|
||||
private String transferType;
|
||||
|
||||
/** 调动子类型 */
|
||||
@Schema(description = "调动子类型")
|
||||
private String transferSubType;
|
||||
|
||||
/** 调动前部门ID */
|
||||
@Schema(description = "调动前部门ID")
|
||||
private Long deptIdBefore;
|
||||
|
||||
/** 调动前部门 */
|
||||
@Schema(description = "调动前部门")
|
||||
private String deptNameBefore;
|
||||
|
||||
/** 调动前职级 */
|
||||
@Schema(description = "调动前职级")
|
||||
private String gradeBefore;
|
||||
|
||||
/** 调动前岗位 */
|
||||
@Schema(description = "调动前岗位")
|
||||
private String positionBefore;
|
||||
|
||||
/** 调动前薪酬等级 */
|
||||
@Schema(description = "调动前薪酬等级")
|
||||
private String salaryLevelBefore;
|
||||
|
||||
/** 调动后部门ID */
|
||||
@Schema(description = "调动后部门ID")
|
||||
private Long deptIdAfter;
|
||||
|
||||
/** 调动后部门 */
|
||||
@Schema(description = "调动后部门")
|
||||
private String deptNameAfter;
|
||||
|
||||
/** 调动后职级 */
|
||||
@Schema(description = "调动后职级")
|
||||
private String gradeAfter;
|
||||
|
||||
/** 调动后岗位 */
|
||||
@Schema(description = "调动后岗位")
|
||||
private String positionAfter;
|
||||
|
||||
/** 调动后薪酬等级 */
|
||||
@Schema(description = "调动后薪酬等级")
|
||||
private String salaryLevelAfter;
|
||||
|
||||
/** 调动日期 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@Schema(description = "调动日期")
|
||||
private Date transferDate;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Schema(description = "创建时间")
|
||||
private Date createTime;
|
||||
|
||||
/** 更新时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Schema(description = "更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
/** 创建人 */
|
||||
@Schema(description = "创建人")
|
||||
private String createdBy;
|
||||
|
||||
/** 更新人 */
|
||||
@Schema(description = "更新人")
|
||||
private String updatedBy;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.ruoyi.ccdi.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 员工调动记录导入失败记录VO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "员工调动记录导入失败记录")
|
||||
public class StaffTransferImportFailureVO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 员工ID */
|
||||
@Schema(description = "员工ID")
|
||||
private Long staffId;
|
||||
|
||||
/** 员工姓名 */
|
||||
@Schema(description = "员工姓名")
|
||||
private String staffName;
|
||||
|
||||
/** 调动类型 */
|
||||
@Schema(description = "调动类型")
|
||||
private String transferType;
|
||||
|
||||
/** 调动子类型 */
|
||||
@Schema(description = "调动子类型")
|
||||
private String transferSubType;
|
||||
|
||||
/** 调动前部门 */
|
||||
@Schema(description = "调动前部门")
|
||||
private String deptNameBefore;
|
||||
|
||||
/** 调动前职级 */
|
||||
@Schema(description = "调动前职级")
|
||||
private String gradeBefore;
|
||||
|
||||
/** 调动前岗位 */
|
||||
@Schema(description = "调动前岗位")
|
||||
private String positionBefore;
|
||||
|
||||
/** 调动前薪酬等级 */
|
||||
@Schema(description = "调动前薪酬等级")
|
||||
private String salaryLevelBefore;
|
||||
|
||||
/** 调动后部门 */
|
||||
@Schema(description = "调动后部门")
|
||||
private String deptNameAfter;
|
||||
|
||||
/** 调动后职级 */
|
||||
@Schema(description = "调动后职级")
|
||||
private String gradeAfter;
|
||||
|
||||
/** 调动后岗位 */
|
||||
@Schema(description = "调动后岗位")
|
||||
private String positionAfter;
|
||||
|
||||
/** 调动后薪酬等级 */
|
||||
@Schema(description = "调动后薪酬等级")
|
||||
private String salaryLevelAfter;
|
||||
|
||||
/** 调动日期 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@Schema(description = "调动日期")
|
||||
private Date transferDate;
|
||||
|
||||
/** 错误信息 */
|
||||
@Schema(description = "错误信息")
|
||||
private String errorMessage;
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.CcdiBaseStaff;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiBaseStaffQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiBaseStaffOptionVO;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiBaseStaffVO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@@ -36,4 +37,13 @@ public interface CcdiBaseStaffMapper extends BaseMapper<CcdiBaseStaff> {
|
||||
* @return 影响行数
|
||||
*/
|
||||
int insertBatch(@Param("list") List<CcdiBaseStaff> list);
|
||||
|
||||
/**
|
||||
* 查询员工选项(用于下拉选择框)
|
||||
* <p>支持按员工ID或姓名模糊搜索,只返回在职员工</p>
|
||||
*
|
||||
* @param query 搜索关键词(员工ID或姓名),可为空
|
||||
* @return 员工选项列表,最多返回100条
|
||||
*/
|
||||
List<CcdiBaseStaffOptionVO> selectStaffOptions(@Param("query") String query);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.ruoyi.ccdi.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.CcdiStaffTransfer;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffTransferQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.TransferUniqueKey;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiStaffTransferVO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 员工调动记录 数据层
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
public interface CcdiStaffTransferMapper extends BaseMapper<CcdiStaffTransfer> {
|
||||
|
||||
/**
|
||||
* 分页查询员工调动记录列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryDTO 查询条件
|
||||
* @return 员工调动记录VO分页结果
|
||||
*/
|
||||
Page<CcdiStaffTransferVO> selectTransferPage(@Param("page") Page<CcdiStaffTransferVO> page,
|
||||
@Param("query") CcdiStaffTransferQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 查询员工调动记录详情
|
||||
*
|
||||
* @param id 主键ID
|
||||
* @return 员工调动记录VO
|
||||
*/
|
||||
CcdiStaffTransferVO selectTransferById(@Param("id") Long id);
|
||||
|
||||
/**
|
||||
* 查询员工调动记录列表(用于导出)
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 员工调动记录VO列表
|
||||
*/
|
||||
List<CcdiStaffTransferVO> selectTransferListForExport(@Param("query") CcdiStaffTransferQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 批量插入员工调动记录数据
|
||||
*
|
||||
* @param list 员工调动记录列表
|
||||
* @return 插入行数
|
||||
*/
|
||||
int insertBatch(@Param("list") List<CcdiStaffTransfer> list);
|
||||
|
||||
/**
|
||||
* 查询单条记录是否存在(根据唯一键:员工ID + 调动前部门ID + 调动后部门ID + 调动日期)
|
||||
*
|
||||
* @param key 唯一键
|
||||
* @return 存在的记录,不存在返回null
|
||||
*/
|
||||
CcdiStaffTransfer checkExists(@Param("key") TransferUniqueKey key);
|
||||
|
||||
/**
|
||||
* 查询单条记录是否存在(排除指定ID)
|
||||
*
|
||||
* @param key 唯一键
|
||||
* @param excludeId 排除的记录ID
|
||||
* @return 存在的记录,不存在返回null
|
||||
*/
|
||||
CcdiStaffTransfer checkExistsExcludeId(@Param("key") TransferUniqueKey key,
|
||||
@Param("excludeId") Long excludeId);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.ruoyi.ccdi.domain.dto.CcdiBaseStaffAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiBaseStaffEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiBaseStaffQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiBaseStaffExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiBaseStaffOptionVO;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiBaseStaffVO;
|
||||
|
||||
import java.util.List;
|
||||
@@ -83,4 +84,13 @@ public interface ICcdiBaseStaffService {
|
||||
*/
|
||||
String importBaseStaff(List<CcdiBaseStaffExcel> excelList, Boolean isUpdateSupport);
|
||||
|
||||
/**
|
||||
* 查询员工下拉列表
|
||||
* 支持按员工ID或姓名模糊搜索,只返回在职员工
|
||||
*
|
||||
* @param query 搜索关键词(员工ID或姓名)
|
||||
* @return 员工选项列表
|
||||
*/
|
||||
List<CcdiBaseStaffOptionVO> selectStaffOptions(String query);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.ruoyi.ccdi.service;
|
||||
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiStaffTransferExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
||||
import com.ruoyi.ccdi.domain.vo.StaffTransferImportFailureVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 员工调动记录异步导入 服务层
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
public interface ICcdiStaffTransferImportService {
|
||||
|
||||
/**
|
||||
* 异步导入员工调动记录数据
|
||||
*
|
||||
* @param excelList Excel实体列表
|
||||
* @param taskId 任务ID
|
||||
* @param userName 用户名
|
||||
*/
|
||||
void importTransferAsync(List<CcdiStaffTransferExcel> excelList, String taskId, String userName);
|
||||
|
||||
/**
|
||||
* 查询导入失败记录
|
||||
*
|
||||
* @param taskId 任务ID
|
||||
* @return 失败记录列表
|
||||
*/
|
||||
List<StaffTransferImportFailureVO> getImportFailures(String taskId);
|
||||
|
||||
/**
|
||||
* 查询导入状态
|
||||
*
|
||||
* @param taskId 任务ID
|
||||
* @return 导入状态信息
|
||||
*/
|
||||
ImportStatusVO getImportStatus(String taskId);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.ruoyi.ccdi.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffTransferAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffTransferEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffTransferQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiStaffTransferExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiStaffTransferVO;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 员工调动记录 服务层
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
public interface ICcdiStaffTransferService {
|
||||
|
||||
/**
|
||||
* 查询员工调动记录列表
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 员工调动记录VO集合
|
||||
*/
|
||||
List<CcdiStaffTransferVO> selectTransferList(CcdiStaffTransferQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 分页查询员工调动记录列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryDTO 查询条件
|
||||
* @return 员工调动记录VO分页结果
|
||||
*/
|
||||
Page<CcdiStaffTransferVO> selectTransferPage(Page<CcdiStaffTransferVO> page, CcdiStaffTransferQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 查询员工调动记录详情
|
||||
*
|
||||
* @param id 主键ID
|
||||
* @return 员工调动记录VO
|
||||
*/
|
||||
CcdiStaffTransferVO selectTransferById(Long id);
|
||||
|
||||
/**
|
||||
* 新增员工调动记录
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
int insertTransfer(CcdiStaffTransferAddDTO addDTO);
|
||||
|
||||
/**
|
||||
* 修改员工调动记录
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
int updateTransfer(CcdiStaffTransferEditDTO editDTO);
|
||||
|
||||
/**
|
||||
* 批量删除员工调动记录
|
||||
*
|
||||
* @param ids 需要删除的主键ID
|
||||
* @return 结果
|
||||
*/
|
||||
int deleteTransferByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 查询员工调动记录列表(用于导出)
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 员工调动记录Excel实体集合
|
||||
*/
|
||||
List<CcdiStaffTransferExcel> selectTransferListForExport(CcdiStaffTransferQueryDTO queryDTO);
|
||||
|
||||
/**
|
||||
* 导入员工调动记录数据(异步)
|
||||
*
|
||||
* @param excelList Excel实体列表
|
||||
* @return 任务ID
|
||||
*/
|
||||
String importTransfer(List<CcdiStaffTransferExcel> excelList);
|
||||
|
||||
/**
|
||||
* 新增时校验唯一性
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @throws ServiceException 如果记录已存在
|
||||
*/
|
||||
void checkUniqueForAdd(CcdiStaffTransferAddDTO addDTO);
|
||||
|
||||
/**
|
||||
* 编辑时校验唯一性
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @throws ServiceException 如果记录已存在
|
||||
*/
|
||||
void checkUniqueForEdit(CcdiStaffTransferEditDTO editDTO);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import com.ruoyi.ccdi.domain.dto.CcdiBaseStaffAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiBaseStaffEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiBaseStaffQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiBaseStaffExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiBaseStaffOptionVO;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiBaseStaffVO;
|
||||
import com.ruoyi.ccdi.enums.EmployeeStatus;
|
||||
import com.ruoyi.ccdi.mapper.CcdiBaseStaffMapper;
|
||||
@@ -205,6 +206,18 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询员工下拉列表
|
||||
* 支持按员工ID或姓名模糊搜索,只返回在职员工
|
||||
*
|
||||
* @param query 搜索关键词(员工ID或姓名)
|
||||
* @return 员工选项列表
|
||||
*/
|
||||
@Override
|
||||
public List<CcdiBaseStaffOptionVO> selectStaffOptions(String query) {
|
||||
return baseStaffMapper.selectStaffOptions(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
package com.ruoyi.ccdi.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.ruoyi.ccdi.domain.CcdiStaffTransfer;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffTransferAddDTO;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiStaffTransferExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportResult;
|
||||
import com.ruoyi.ccdi.domain.vo.ImportStatusVO;
|
||||
import com.ruoyi.ccdi.domain.vo.StaffTransferImportFailureVO;
|
||||
import com.ruoyi.ccdi.mapper.CcdiStaffTransferMapper;
|
||||
import com.ruoyi.ccdi.service.ICcdiStaffTransferImportService;
|
||||
import com.ruoyi.common.core.domain.entity.SysDept;
|
||||
import com.ruoyi.common.utils.DictUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.system.mapper.SysDeptMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 员工调动记录异步导入服务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
@Service
|
||||
@EnableAsync
|
||||
public class CcdiStaffTransferImportServiceImpl implements ICcdiStaffTransferImportService {
|
||||
|
||||
@Resource
|
||||
private CcdiStaffTransferMapper transferMapper;
|
||||
|
||||
@Resource
|
||||
private SysDeptMapper deptMapper;
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@Override
|
||||
@Async
|
||||
@Transactional
|
||||
public void importTransferAsync(List<CcdiStaffTransferExcel> excelList, String taskId, String userName) {
|
||||
List<CcdiStaffTransfer> newRecords = new ArrayList<>();
|
||||
List<StaffTransferImportFailureVO> failures = new ArrayList<>();
|
||||
|
||||
// 批量查询已存在的唯一键组合
|
||||
Set<String> existingKeys = getExistingTransferKeys(excelList);
|
||||
|
||||
// 用于检测Excel内部的重复键
|
||||
Set<String> excelProcessedKeys = new HashSet<>();
|
||||
|
||||
// 分类数据
|
||||
for (int i = 0; i < excelList.size(); i++) {
|
||||
CcdiStaffTransferExcel excel = excelList.get(i);
|
||||
|
||||
try {
|
||||
// 转换为AddDTO进行验证
|
||||
CcdiStaffTransferAddDTO addDTO = new CcdiStaffTransferAddDTO();
|
||||
BeanUtils.copyProperties(excel, addDTO);
|
||||
|
||||
// 验证数据
|
||||
validateTransferData(addDTO);
|
||||
|
||||
// 生成唯一键
|
||||
String uniqueKey = buildUniqueKey(addDTO.getStaffId(), addDTO.getDeptIdBefore(),
|
||||
addDTO.getDeptIdAfter(), addDTO.getTransferDate());
|
||||
|
||||
if (existingKeys.contains(uniqueKey)) {
|
||||
// 数据库中已存在
|
||||
throw new RuntimeException(String.format(
|
||||
"该员工在%s的调动记录已存在(从%s调往%s)",
|
||||
addDTO.getTransferDate(),
|
||||
addDTO.getDeptNameBefore(),
|
||||
addDTO.getDeptNameAfter()
|
||||
));
|
||||
} else if (excelProcessedKeys.contains(uniqueKey)) {
|
||||
// Excel内部重复
|
||||
throw new RuntimeException(String.format(
|
||||
"该记录与Excel第%d行重复",
|
||||
excelProcessedKeys.size() + 1
|
||||
));
|
||||
} else {
|
||||
CcdiStaffTransfer transfer = new CcdiStaffTransfer();
|
||||
// 从addDTO复制,因为validateTransferData已经补全了部门名称
|
||||
BeanUtils.copyProperties(addDTO, transfer);
|
||||
transfer.setCreatedBy(userName);
|
||||
transfer.setUpdatedBy(userName);
|
||||
newRecords.add(transfer);
|
||||
excelProcessedKeys.add(uniqueKey);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
StaffTransferImportFailureVO failure = new StaffTransferImportFailureVO();
|
||||
BeanUtils.copyProperties(excel, failure);
|
||||
failure.setErrorMessage(e.getMessage());
|
||||
failures.add(failure);
|
||||
}
|
||||
}
|
||||
|
||||
// 批量插入新数据
|
||||
if (!newRecords.isEmpty()) {
|
||||
saveBatch(newRecords, 500);
|
||||
}
|
||||
|
||||
// 保存失败记录到Redis
|
||||
if (!failures.isEmpty()) {
|
||||
String failuresKey = "import:staffTransfer:" + taskId + ":failures";
|
||||
redisTemplate.opsForValue().set(failuresKey, failures, 7, TimeUnit.DAYS);
|
||||
}
|
||||
|
||||
ImportResult result = new ImportResult();
|
||||
result.setTotalCount(excelList.size());
|
||||
result.setSuccessCount(newRecords.size());
|
||||
result.setFailureCount(failures.size());
|
||||
|
||||
// 更新最终状态
|
||||
String finalStatus = result.getFailureCount() == 0 ? "SUCCESS" : "PARTIAL_SUCCESS";
|
||||
updateImportStatus(taskId, finalStatus, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量查询已存在的调动记录唯一键
|
||||
*
|
||||
* @param excelList Excel数据列表
|
||||
* @return 已存在的唯一键集合
|
||||
*/
|
||||
private Set<String> getExistingTransferKeys(List<CcdiStaffTransferExcel> excelList) {
|
||||
// 提取所有有效的唯一键
|
||||
Set<String> allKeys = excelList.stream()
|
||||
.filter(excel -> excel.getStaffId() != null
|
||||
&& excel.getDeptIdBefore() != null
|
||||
&& excel.getDeptIdAfter() != null
|
||||
&& excel.getTransferDate() != null)
|
||||
.map(excel -> buildUniqueKey(excel.getStaffId(), excel.getDeptIdBefore(),
|
||||
excel.getDeptIdAfter(), excel.getTransferDate()))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (allKeys.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
// 查询数据库中已存在的记录
|
||||
LambdaQueryWrapper<CcdiStaffTransfer> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.select(CcdiStaffTransfer::getStaffId,
|
||||
CcdiStaffTransfer::getDeptIdBefore,
|
||||
CcdiStaffTransfer::getDeptIdAfter,
|
||||
CcdiStaffTransfer::getTransferDate);
|
||||
|
||||
List<CcdiStaffTransfer> existingTransfers = transferMapper.selectList(wrapper);
|
||||
|
||||
// 构建已存在的唯一键集合
|
||||
return existingTransfers.stream()
|
||||
.map(t -> buildUniqueKey(t.getStaffId(), t.getDeptIdBefore(),
|
||||
t.getDeptIdAfter(), t.getTransferDate()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建唯一键
|
||||
*
|
||||
* @param staffId 员工ID
|
||||
* @param deptIdBefore 调动前部门ID
|
||||
* @param deptIdAfter 调动后部门ID
|
||||
* @param transferDate 调动日期
|
||||
* @return 唯一键字符串
|
||||
*/
|
||||
private String buildUniqueKey(Long staffId, Long deptIdBefore, Long deptIdAfter, Date transferDate) {
|
||||
String dateStr = new java.text.SimpleDateFormat("yyyy-MM-dd").format(transferDate);
|
||||
return staffId + "_" + deptIdBefore + "_" + deptIdAfter + "_" + dateStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证员工调动记录数据
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
*/
|
||||
private void validateTransferData(CcdiStaffTransferAddDTO addDTO) {
|
||||
// 验证必填字段
|
||||
if (addDTO.getStaffId() == null) {
|
||||
throw new RuntimeException("员工ID不能为空");
|
||||
}
|
||||
if (StringUtils.isEmpty(addDTO.getTransferType())) {
|
||||
throw new RuntimeException("调动类型不能为空");
|
||||
}
|
||||
if (addDTO.getTransferDate() == null) {
|
||||
throw new RuntimeException("调动日期不能为空");
|
||||
}
|
||||
|
||||
// 验证调动前部门ID
|
||||
if (addDTO.getDeptIdBefore() == null) {
|
||||
throw new RuntimeException("调动前部门ID不能为空");
|
||||
}
|
||||
|
||||
// 验证调动后部门ID
|
||||
if (addDTO.getDeptIdAfter() == null) {
|
||||
throw new RuntimeException("调动后部门ID不能为空");
|
||||
}
|
||||
|
||||
// 将调动类型从中文转换为码值
|
||||
String transferTypeCode = DictUtils.getDictValue("ccdi_transfer_type", addDTO.getTransferType());
|
||||
if (StringUtils.isEmpty(transferTypeCode)) {
|
||||
throw new RuntimeException("调动类型[" + addDTO.getTransferType() + "]无效,请检查字典数据");
|
||||
}
|
||||
addDTO.setTransferType(transferTypeCode);
|
||||
|
||||
// 验证部门ID是否存在并获取部门名称
|
||||
String deptNameBefore = getDeptNameById(addDTO.getDeptIdBefore());
|
||||
addDTO.setDeptNameBefore(deptNameBefore);
|
||||
|
||||
String deptNameAfter = getDeptNameById(addDTO.getDeptIdAfter());
|
||||
addDTO.setDeptNameAfter(deptNameAfter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据部门ID查询部门名称
|
||||
*
|
||||
* @param deptId 部门ID
|
||||
* @return 部门名称
|
||||
* @throws RuntimeException 如果部门不存在
|
||||
*/
|
||||
private String getDeptNameById(Long deptId) {
|
||||
if (deptId == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SysDept dept = deptMapper.selectDeptById(deptId);
|
||||
|
||||
if (dept == null) {
|
||||
throw new RuntimeException("部门ID " + deptId + " 不存在,请检查部门信息");
|
||||
}
|
||||
|
||||
return dept.getDeptName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量保存
|
||||
*/
|
||||
private void saveBatch(List<CcdiStaffTransfer> list, int batchSize) {
|
||||
for (int i = 0; i < list.size(); i += batchSize) {
|
||||
int end = Math.min(i + batchSize, list.size());
|
||||
List<CcdiStaffTransfer> subList = list.subList(i, end);
|
||||
transferMapper.insertBatch(subList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新导入状态
|
||||
*/
|
||||
private void updateImportStatus(String taskId, String status, ImportResult result) {
|
||||
String key = "import:staffTransfer:" + taskId;
|
||||
Map<String, Object> statusData = new HashMap<>();
|
||||
statusData.put("status", status);
|
||||
statusData.put("totalCount", result.getTotalCount());
|
||||
statusData.put("successCount", result.getSuccessCount());
|
||||
statusData.put("failureCount", result.getFailureCount());
|
||||
statusData.put("progress", 100);
|
||||
statusData.put("endTime", System.currentTimeMillis());
|
||||
|
||||
if ("SUCCESS".equals(status)) {
|
||||
statusData.put("message", "全部成功!共导入" + result.getTotalCount() + "条数据");
|
||||
} else {
|
||||
statusData.put("message", "成功" + result.getSuccessCount() + "条,失败" + result.getFailureCount() + "条");
|
||||
}
|
||||
|
||||
redisTemplate.opsForHash().putAll(key, statusData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImportStatusVO getImportStatus(String taskId) {
|
||||
String key = "import:staffTransfer:" + taskId;
|
||||
Boolean hasKey = redisTemplate.hasKey(key);
|
||||
|
||||
if (Boolean.FALSE.equals(hasKey)) {
|
||||
throw new RuntimeException("任务不存在或已过期");
|
||||
}
|
||||
|
||||
Map<Object, Object> statusMap = redisTemplate.opsForHash().entries(key);
|
||||
|
||||
ImportStatusVO statusVO = new ImportStatusVO();
|
||||
statusVO.setTaskId((String) statusMap.get("taskId"));
|
||||
statusVO.setStatus((String) statusMap.get("status"));
|
||||
statusVO.setTotalCount((Integer) statusMap.get("totalCount"));
|
||||
statusVO.setSuccessCount((Integer) statusMap.get("successCount"));
|
||||
statusVO.setFailureCount((Integer) statusMap.get("failureCount"));
|
||||
statusVO.setProgress((Integer) statusMap.get("progress"));
|
||||
statusVO.setStartTime((Long) statusMap.get("startTime"));
|
||||
statusVO.setEndTime((Long) statusMap.get("endTime"));
|
||||
statusVO.setMessage((String) statusMap.get("message"));
|
||||
|
||||
return statusVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StaffTransferImportFailureVO> getImportFailures(String taskId) {
|
||||
String key = "import:staffTransfer:" + taskId + ":failures";
|
||||
Object failuresObj = redisTemplate.opsForValue().get(key);
|
||||
|
||||
if (failuresObj == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return JSON.parseArray(JSON.toJSONString(failuresObj), StaffTransferImportFailureVO.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
package com.ruoyi.ccdi.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.domain.CcdiStaffTransfer;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffTransferAddDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffTransferEditDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.CcdiStaffTransferQueryDTO;
|
||||
import com.ruoyi.ccdi.domain.dto.TransferUniqueKey;
|
||||
import com.ruoyi.ccdi.domain.excel.CcdiStaffTransferExcel;
|
||||
import com.ruoyi.ccdi.domain.vo.CcdiStaffTransferVO;
|
||||
import com.ruoyi.ccdi.mapper.CcdiBaseStaffMapper;
|
||||
import com.ruoyi.ccdi.mapper.CcdiStaffTransferMapper;
|
||||
import com.ruoyi.ccdi.service.ICcdiStaffTransferImportService;
|
||||
import com.ruoyi.ccdi.service.ICcdiStaffTransferService;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 员工调动记录 服务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2026-02-10
|
||||
*/
|
||||
@Service
|
||||
public class CcdiStaffTransferServiceImpl implements ICcdiStaffTransferService {
|
||||
|
||||
@Resource
|
||||
private CcdiStaffTransferMapper transferMapper;
|
||||
|
||||
@Resource
|
||||
private ICcdiStaffTransferImportService transferImportService;
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@Resource
|
||||
private CcdiBaseStaffMapper staffMapper;
|
||||
|
||||
/**
|
||||
* 查询员工调动记录列表
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 员工调动记录VO集合
|
||||
*/
|
||||
@Override
|
||||
public java.util.List<CcdiStaffTransferVO> selectTransferList(CcdiStaffTransferQueryDTO queryDTO) {
|
||||
Page<CcdiStaffTransferVO> page = new Page<>(1, Integer.MAX_VALUE);
|
||||
Page<CcdiStaffTransferVO> resultPage = transferMapper.selectTransferPage(page, queryDTO);
|
||||
return resultPage.getRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询员工调动记录列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryDTO 查询条件
|
||||
* @return 员工调动记录VO分页结果
|
||||
*/
|
||||
@Override
|
||||
public Page<CcdiStaffTransferVO> selectTransferPage(Page<CcdiStaffTransferVO> page, CcdiStaffTransferQueryDTO queryDTO) {
|
||||
return transferMapper.selectTransferPage(page, queryDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询员工调动记录列表(用于导出)
|
||||
*
|
||||
* @param queryDTO 查询条件
|
||||
* @return 员工调动记录Excel实体集合
|
||||
*/
|
||||
@Override
|
||||
public java.util.List<CcdiStaffTransferExcel> selectTransferListForExport(CcdiStaffTransferQueryDTO queryDTO) {
|
||||
return transferMapper.selectTransferListForExport(queryDTO).stream().map(vo -> {
|
||||
CcdiStaffTransferExcel excel = new CcdiStaffTransferExcel();
|
||||
BeanUtils.copyProperties(vo, excel);
|
||||
return excel;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询员工调动记录详情
|
||||
*
|
||||
* @param id 主键ID
|
||||
* @return 员工调动记录VO
|
||||
*/
|
||||
@Override
|
||||
public CcdiStaffTransferVO selectTransferById(Long id) {
|
||||
return transferMapper.selectTransferById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增员工调动记录
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public int insertTransfer(CcdiStaffTransferAddDTO addDTO) {
|
||||
// 唯一性校验
|
||||
checkUniqueForAdd(addDTO);
|
||||
|
||||
CcdiStaffTransfer transfer = new CcdiStaffTransfer();
|
||||
BeanUtils.copyProperties(addDTO, transfer);
|
||||
int result = transferMapper.insert(transfer);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改员工调动记录
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public int updateTransfer(CcdiStaffTransferEditDTO editDTO) {
|
||||
// 唯一性校验(排除当前记录)
|
||||
checkUniqueForEdit(editDTO);
|
||||
|
||||
CcdiStaffTransfer transfer = new CcdiStaffTransfer();
|
||||
BeanUtils.copyProperties(editDTO, transfer);
|
||||
int result = transferMapper.updateById(transfer);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除员工调动记录
|
||||
*
|
||||
* @param ids 需要删除的主键ID
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public int deleteTransferByIds(Long[] ids) {
|
||||
return transferMapper.deleteBatchIds(java.util.List.of(ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入员工调动记录数据(异步)
|
||||
*
|
||||
* @param excelList Excel实体列表
|
||||
* @return 任务ID
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public String importTransfer(java.util.List<CcdiStaffTransferExcel> excelList) {
|
||||
if (StringUtils.isNull(excelList) || excelList.isEmpty()) {
|
||||
throw new RuntimeException("至少需要一条数据");
|
||||
}
|
||||
|
||||
// 生成任务ID
|
||||
String taskId = UUID.randomUUID().toString();
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
// 获取当前用户名
|
||||
String userName = SecurityUtils.getUsername();
|
||||
|
||||
// 初始化Redis状态
|
||||
String statusKey = "import:staffTransfer:" + taskId;
|
||||
Map<String, Object> statusData = new HashMap<>();
|
||||
statusData.put("taskId", taskId);
|
||||
statusData.put("status", "PROCESSING");
|
||||
statusData.put("totalCount", excelList.size());
|
||||
statusData.put("successCount", 0);
|
||||
statusData.put("failureCount", 0);
|
||||
statusData.put("progress", 0);
|
||||
statusData.put("startTime", startTime);
|
||||
statusData.put("message", "正在处理...");
|
||||
|
||||
redisTemplate.opsForHash().putAll(statusKey, statusData);
|
||||
redisTemplate.expire(statusKey, 7, TimeUnit.DAYS);
|
||||
|
||||
// 调用异步导入服务
|
||||
transferImportService.importTransferAsync(excelList, taskId, userName);
|
||||
|
||||
return taskId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增时校验唯一性
|
||||
*
|
||||
* @param addDTO 新增DTO
|
||||
* @throws ServiceException 如果记录已存在
|
||||
*/
|
||||
@Override
|
||||
public void checkUniqueForAdd(CcdiStaffTransferAddDTO addDTO) {
|
||||
TransferUniqueKey key = TransferUniqueKey.from(addDTO);
|
||||
CcdiStaffTransfer existing = transferMapper.checkExists(key);
|
||||
if (existing != null) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
String dateStr = sdf.format(addDTO.getTransferDate());
|
||||
throw new ServiceException("该员工在 [" + dateStr + "] 的调动记录已存在(从[" +
|
||||
addDTO.getDeptNameBefore() + "]调往[" + addDTO.getDeptNameAfter() + "])");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑时校验唯一性
|
||||
*
|
||||
* @param editDTO 编辑DTO
|
||||
* @throws ServiceException 如果记录已存在
|
||||
*/
|
||||
@Override
|
||||
public void checkUniqueForEdit(CcdiStaffTransferEditDTO editDTO) {
|
||||
TransferUniqueKey key = TransferUniqueKey.from(editDTO);
|
||||
CcdiStaffTransfer existing = transferMapper.checkExistsExcludeId(key, editDTO.getId());
|
||||
if (existing != null) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
String dateStr = sdf.format(editDTO.getTransferDate());
|
||||
throw new ServiceException("该员工在 [" + dateStr + "] 的调动记录已存在(从[" +
|
||||
editDTO.getDeptNameBefore() + "]调往[" + editDTO.getDeptNameAfter() + "])");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,4 +77,25 @@
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<!-- 查询员工选项(用于下拉选择框) -->
|
||||
<!-- 支持按员工ID或姓名模糊搜索,只返回在职员工 -->
|
||||
<select id="selectStaffOptions" resultType="com.ruoyi.ccdi.domain.vo.CcdiBaseStaffOptionVO">
|
||||
SELECT
|
||||
e.staff_id,
|
||||
e.name,
|
||||
e.dept_id,
|
||||
d.dept_name
|
||||
FROM ccdi_base_staff e
|
||||
LEFT JOIN sys_dept d ON e.dept_id = d.dept_id
|
||||
<where>
|
||||
e.status = '0'
|
||||
<if test="query != null and query != ''">
|
||||
AND (CAST(e.staff_id AS CHAR) LIKE CONCAT('%', #{query}, '%')
|
||||
OR e.name LIKE CONCAT('%', #{query}, '%'))
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY e.staff_id
|
||||
LIMIT 100
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
<?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.ccdi.mapper.CcdiStaffTransferMapper">
|
||||
|
||||
<!-- 员工调动记录ResultMap -->
|
||||
<resultMap type="com.ruoyi.ccdi.domain.vo.CcdiStaffTransferVO" id="CcdiStaffTransferVOResult">
|
||||
<id property="id" column="id"/>
|
||||
<result property="staffId" column="staff_id"/>
|
||||
<result property="staffName" column="staff_name"/>
|
||||
<result property="transferType" column="transfer_type"/>
|
||||
<result property="transferSubType" column="transfer_sub_type"/>
|
||||
<result property="deptIdBefore" column="dept_id_before"/>
|
||||
<result property="deptNameBefore" column="dept_name_before"/>
|
||||
<result property="gradeBefore" column="grade_before"/>
|
||||
<result property="positionBefore" column="position_before"/>
|
||||
<result property="salaryLevelBefore" column="salary_level_before"/>
|
||||
<result property="deptIdAfter" column="dept_id_after"/>
|
||||
<result property="deptNameAfter" column="dept_name_after"/>
|
||||
<result property="gradeAfter" column="grade_after"/>
|
||||
<result property="positionAfter" column="position_after"/>
|
||||
<result property="salaryLevelAfter" column="salary_level_after"/>
|
||||
<result property="transferDate" column="transfer_date"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="createdBy" column="created_by"/>
|
||||
<result property="updatedBy" column="updated_by"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 分页查询员工调动记录列表 -->
|
||||
<select id="selectTransferPage" resultMap="CcdiStaffTransferVOResult">
|
||||
SELECT
|
||||
t.id, t.staff_id, s.name as staff_name, t.transfer_type, t.transfer_sub_type,
|
||||
t.dept_id_before, t.dept_name_before, t.grade_before, t.position_before, t.salary_level_before,
|
||||
t.dept_id_after, t.dept_name_after, t.grade_after, t.position_after, t.salary_level_after,
|
||||
t.transfer_date, t.created_by, t.create_time, t.updated_by, t.update_time
|
||||
FROM ccdi_staff_transfer t
|
||||
LEFT JOIN ccdi_base_staff s ON t.staff_id = s.staff_id
|
||||
<where>
|
||||
<if test="query.staffId != null">
|
||||
AND t.staff_id = #{query.staffId}
|
||||
</if>
|
||||
<if test="query.staffName != null and query.staffName != ''">
|
||||
AND s.name LIKE CONCAT('%', #{query.staffName}, '%')
|
||||
</if>
|
||||
<if test="query.transferType != null and query.transferType != ''">
|
||||
AND t.transfer_type = #{query.transferType}
|
||||
</if>
|
||||
<if test="query.transferSubType != null and query.transferSubType != ''">
|
||||
AND t.transfer_sub_type = #{query.transferSubType}
|
||||
</if>
|
||||
<if test="query.deptIdBefore != null">
|
||||
AND t.dept_id_before = #{query.deptIdBefore}
|
||||
</if>
|
||||
<if test="query.deptIdAfter != null">
|
||||
AND t.dept_id_after = #{query.deptIdAfter}
|
||||
</if>
|
||||
<if test="query.transferDateStart != null">
|
||||
AND t.transfer_date >= #{query.transferDateStart}
|
||||
</if>
|
||||
<if test="query.transferDateEnd != null">
|
||||
AND t.transfer_date <= #{query.transferDateEnd}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY t.transfer_date DESC, t.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询员工调动记录详情 -->
|
||||
<select id="selectTransferById" resultMap="CcdiStaffTransferVOResult">
|
||||
SELECT
|
||||
t.id, t.staff_id, s.name as staff_name, t.transfer_type, t.transfer_sub_type,
|
||||
t.dept_id_before, t.dept_name_before, t.grade_before, t.position_before, t.salary_level_before,
|
||||
t.dept_id_after, t.dept_name_after, t.grade_after, t.position_after, t.salary_level_after,
|
||||
t.transfer_date, t.created_by, t.create_time, t.updated_by, t.update_time
|
||||
FROM ccdi_staff_transfer t
|
||||
LEFT JOIN ccdi_base_staff s ON t.staff_id = s.staff_id
|
||||
WHERE t.id = #{id}
|
||||
</select>
|
||||
|
||||
<!-- 查询员工调动记录列表(用于导出) -->
|
||||
<select id="selectTransferListForExport" resultMap="CcdiStaffTransferVOResult">
|
||||
SELECT
|
||||
t.id, t.staff_id, s.name as staff_name, t.transfer_type, t.transfer_sub_type,
|
||||
t.dept_id_before, t.dept_name_before, t.grade_before, t.position_before, t.salary_level_before,
|
||||
t.dept_id_after, t.dept_name_after, t.grade_after, t.position_after, t.salary_level_after,
|
||||
t.transfer_date, t.created_by, t.create_time, t.updated_by, t.update_time
|
||||
FROM ccdi_staff_transfer t
|
||||
LEFT JOIN ccdi_base_staff s ON t.staff_id = s.staff_id
|
||||
<where>
|
||||
<if test="query.staffId != null">
|
||||
AND t.staff_id = #{query.staffId}
|
||||
</if>
|
||||
<if test="query.staffName != null and query.staffName != ''">
|
||||
AND s.name LIKE CONCAT('%', #{query.staffName}, '%')
|
||||
</if>
|
||||
<if test="query.transferType != null and query.transferType != ''">
|
||||
AND t.transfer_type = #{query.transferType}
|
||||
</if>
|
||||
<if test="query.transferSubType != null and query.transferSubType != ''">
|
||||
AND t.transfer_sub_type = #{query.transferSubType}
|
||||
</if>
|
||||
<if test="query.deptIdBefore != null">
|
||||
AND t.dept_id_before = #{query.deptIdBefore}
|
||||
</if>
|
||||
<if test="query.deptIdAfter != null">
|
||||
AND t.dept_id_after = #{query.deptIdAfter}
|
||||
</if>
|
||||
<if test="query.transferDateStart != null">
|
||||
AND t.transfer_date >= #{query.transferDateStart}
|
||||
</if>
|
||||
<if test="query.transferDateEnd != null">
|
||||
AND t.transfer_date <= #{query.transferDateEnd}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY t.transfer_date DESC, t.create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 批量插入员工调动记录数据 -->
|
||||
<insert id="insertBatch">
|
||||
INSERT INTO ccdi_staff_transfer
|
||||
(staff_id, transfer_type, transfer_sub_type, dept_id_before, dept_name_before, grade_before,
|
||||
position_before, salary_level_before, dept_id_after, dept_name_after, grade_after,
|
||||
position_after, salary_level_after, transfer_date, created_by, create_time, updated_by, update_time)
|
||||
VALUES
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.staffId}, #{item.transferType}, #{item.transferSubType}, #{item.deptIdBefore},
|
||||
#{item.deptNameBefore}, #{item.gradeBefore}, #{item.positionBefore}, #{item.salaryLevelBefore},
|
||||
#{item.deptIdAfter}, #{item.deptNameAfter}, #{item.gradeAfter}, #{item.positionAfter},
|
||||
#{item.salaryLevelAfter}, #{item.transferDate}, #{item.createdBy}, NOW(), #{item.updatedBy}, NOW())
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<!-- 查询单条记录是否存在(根据唯一键) -->
|
||||
<select id="checkExists" resultType="com.ruoyi.ccdi.domain.CcdiStaffTransfer">
|
||||
SELECT
|
||||
id, staff_id, dept_id_before, dept_id_after, transfer_date
|
||||
FROM ccdi_staff_transfer
|
||||
WHERE staff_id = #{key.staffId}
|
||||
AND dept_id_before = #{key.deptIdBefore}
|
||||
AND dept_id_after = #{key.deptIdAfter}
|
||||
AND transfer_date = #{key.transferDate}
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<!-- 查询单条记录是否存在(排除指定ID) -->
|
||||
<select id="checkExistsExcludeId" resultType="com.ruoyi.ccdi.domain.CcdiStaffTransfer">
|
||||
SELECT
|
||||
id, staff_id, dept_id_before, dept_id_after, transfer_date
|
||||
FROM ccdi_staff_transfer
|
||||
WHERE staff_id = #{key.staffId}
|
||||
AND dept_id_before = #{key.deptIdBefore}
|
||||
AND dept_id_after = #{key.deptIdAfter}
|
||||
AND transfer_date = #{key.transferDate}
|
||||
AND id != #{excludeId}
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user