新增员工资产信息后端实施计划
This commit is contained in:
@@ -45,6 +45,13 @@
|
|||||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 测试依赖 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package com.ruoyi.info.collection.controller;
|
||||||
|
|
||||||
|
import com.ruoyi.info.collection.domain.excel.CcdiAssetInfoExcel;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.AssetImportFailureVO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.ImportResultVO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
|
||||||
|
import com.ruoyi.info.collection.service.ICcdiAssetInfoImportService;
|
||||||
|
import com.ruoyi.info.collection.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.TableDataInfo;
|
||||||
|
import com.ruoyi.common.enums.BusinessType;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
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.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工资产信息Controller
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-12
|
||||||
|
*/
|
||||||
|
@Tag(name = "员工资产信息管理")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ccdi/assetInfo")
|
||||||
|
public class CcdiAssetInfoController extends BaseController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ICcdiAssetInfoImportService assetInfoImportService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载导入模板
|
||||||
|
*/
|
||||||
|
@Operation(summary = "下载资产导入模板")
|
||||||
|
@PostMapping("/importTemplate")
|
||||||
|
public void importTemplate(HttpServletResponse response) {
|
||||||
|
EasyExcelUtil.importTemplateWithDictDropdown(response, CcdiAssetInfoExcel.class, "员工资产信息");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入员工资产信息
|
||||||
|
*/
|
||||||
|
@Operation(summary = "导入员工资产信息")
|
||||||
|
@PreAuthorize("@ss.hasPermi('ccdi:baseStaff:import')")
|
||||||
|
@Log(title = "员工资产信息", businessType = BusinessType.IMPORT)
|
||||||
|
@PostMapping("/importData")
|
||||||
|
public AjaxResult importData(MultipartFile file) throws Exception {
|
||||||
|
List<CcdiAssetInfoExcel> list = EasyExcelUtil.importExcel(file.getInputStream(), CcdiAssetInfoExcel.class);
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
return error("至少需要一条数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
String taskId = assetInfoImportService.importAssetInfo(list);
|
||||||
|
ImportResultVO result = new ImportResultVO();
|
||||||
|
result.setTaskId(taskId);
|
||||||
|
result.setStatus("PROCESSING");
|
||||||
|
result.setMessage("导入任务已提交,正在后台处理");
|
||||||
|
return AjaxResult.success("导入任务已提交,正在后台处理", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询导入状态
|
||||||
|
*/
|
||||||
|
@Operation(summary = "查询员工资产导入状态")
|
||||||
|
@PreAuthorize("@ss.hasPermi('ccdi:baseStaff:import')")
|
||||||
|
@GetMapping("/importStatus/{taskId}")
|
||||||
|
public AjaxResult getImportStatus(@PathVariable String taskId) {
|
||||||
|
return success(assetInfoImportService.getImportStatus(taskId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询导入失败记录
|
||||||
|
*/
|
||||||
|
@Operation(summary = "查询员工资产导入失败记录")
|
||||||
|
@PreAuthorize("@ss.hasPermi('ccdi:baseStaff:import')")
|
||||||
|
@GetMapping("/importFailures/{taskId}")
|
||||||
|
public TableDataInfo getImportFailures(
|
||||||
|
@PathVariable String taskId,
|
||||||
|
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||||
|
@RequestParam(defaultValue = "10") Integer pageSize) {
|
||||||
|
List<AssetImportFailureVO> failures = assetInfoImportService.getImportFailures(taskId);
|
||||||
|
int fromIndex = (pageNum - 1) * pageSize;
|
||||||
|
int toIndex = Math.min(fromIndex + pageSize, failures.size());
|
||||||
|
if (fromIndex >= failures.size()) {
|
||||||
|
return getDataTable(new ArrayList<>(), failures.size());
|
||||||
|
}
|
||||||
|
return getDataTable(failures.subList(fromIndex, toIndex), failures.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.ruoyi.info.collection.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工资产信息对象 ccdi_asset_info
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-12
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("ccdi_asset_info")
|
||||||
|
public class CcdiAssetInfo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 资产ID */
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
private Long assetId;
|
||||||
|
|
||||||
|
/** 归属员工身份证号 */
|
||||||
|
private String familyId;
|
||||||
|
|
||||||
|
/** 资产实际持有人身份证号 */
|
||||||
|
private String personId;
|
||||||
|
|
||||||
|
/** 资产大类 */
|
||||||
|
private String assetMainType;
|
||||||
|
|
||||||
|
/** 资产小类 */
|
||||||
|
private String assetSubType;
|
||||||
|
|
||||||
|
/** 资产名称 */
|
||||||
|
private String assetName;
|
||||||
|
|
||||||
|
/** 产权占比 */
|
||||||
|
private BigDecimal ownershipRatio;
|
||||||
|
|
||||||
|
/** 购买/评估日期 */
|
||||||
|
private Date purchaseEvalDate;
|
||||||
|
|
||||||
|
/** 资产原值 */
|
||||||
|
private BigDecimal originalValue;
|
||||||
|
|
||||||
|
/** 当前估值 */
|
||||||
|
private BigDecimal currentValue;
|
||||||
|
|
||||||
|
/** 估值截止日期 */
|
||||||
|
private Date valuationDate;
|
||||||
|
|
||||||
|
/** 资产状态 */
|
||||||
|
private String assetStatus;
|
||||||
|
|
||||||
|
/** 备注 */
|
||||||
|
private String remarks;
|
||||||
|
|
||||||
|
/** 创建者 */
|
||||||
|
@TableField(fill = FieldFill.INSERT)
|
||||||
|
private String createBy;
|
||||||
|
|
||||||
|
/** 创建时间 */
|
||||||
|
@TableField(fill = FieldFill.INSERT)
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
/** 更新者 */
|
||||||
|
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||||
|
private String updateBy;
|
||||||
|
|
||||||
|
/** 更新时间 */
|
||||||
|
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||||
|
private Date updateTime;
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package com.ruoyi.info.collection.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.Pattern;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工资产信息DTO
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-12
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "员工资产信息")
|
||||||
|
public class CcdiAssetInfoDTO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 资产实际持有人身份证号 */
|
||||||
|
@NotBlank(message = "资产实际持有人身份证号不能为空")
|
||||||
|
@Pattern(regexp = "^[1-9]\\d{5}(18|19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$", message = "资产实际持有人身份证号格式不正确")
|
||||||
|
@Schema(description = "资产实际持有人身份证号")
|
||||||
|
private String personId;
|
||||||
|
|
||||||
|
/** 资产大类 */
|
||||||
|
@NotBlank(message = "资产大类不能为空")
|
||||||
|
@Size(max = 20, message = "资产大类长度不能超过20个字符")
|
||||||
|
@Schema(description = "资产大类")
|
||||||
|
private String assetMainType;
|
||||||
|
|
||||||
|
/** 资产小类 */
|
||||||
|
@NotBlank(message = "资产小类不能为空")
|
||||||
|
@Size(max = 50, message = "资产小类长度不能超过50个字符")
|
||||||
|
@Schema(description = "资产小类")
|
||||||
|
private String assetSubType;
|
||||||
|
|
||||||
|
/** 资产名称 */
|
||||||
|
@NotBlank(message = "资产名称不能为空")
|
||||||
|
@Size(max = 200, message = "资产名称长度不能超过200个字符")
|
||||||
|
@Schema(description = "资产名称")
|
||||||
|
private String assetName;
|
||||||
|
|
||||||
|
/** 产权占比 */
|
||||||
|
@Schema(description = "产权占比")
|
||||||
|
private BigDecimal ownershipRatio;
|
||||||
|
|
||||||
|
/** 购买/评估日期 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@Schema(description = "购买/评估日期")
|
||||||
|
private Date purchaseEvalDate;
|
||||||
|
|
||||||
|
/** 资产原值 */
|
||||||
|
@Schema(description = "资产原值")
|
||||||
|
private BigDecimal originalValue;
|
||||||
|
|
||||||
|
/** 当前估值 */
|
||||||
|
@NotNull(message = "当前估值不能为空")
|
||||||
|
@Schema(description = "当前估值")
|
||||||
|
private BigDecimal currentValue;
|
||||||
|
|
||||||
|
/** 估值截止日期 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@Schema(description = "估值截止日期")
|
||||||
|
private Date valuationDate;
|
||||||
|
|
||||||
|
/** 资产状态 */
|
||||||
|
@NotBlank(message = "资产状态不能为空")
|
||||||
|
@Size(max = 10, message = "资产状态长度不能超过10个字符")
|
||||||
|
@Schema(description = "资产状态")
|
||||||
|
private String assetStatus;
|
||||||
|
|
||||||
|
/** 备注 */
|
||||||
|
@Size(max = 500, message = "备注长度不能超过500个字符")
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remarks;
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import lombok.Data;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 员工信息新增 DTO
|
* 员工信息新增 DTO
|
||||||
@@ -51,4 +52,7 @@ public class CcdiBaseStaffAddDTO implements Serializable {
|
|||||||
/** 状态 */
|
/** 状态 */
|
||||||
@NotBlank(message = "状态不能为空")
|
@NotBlank(message = "状态不能为空")
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
|
/** 资产信息列表 */
|
||||||
|
private List<CcdiAssetInfoDTO> assetInfoList;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import lombok.Data;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 员工信息编辑 DTO
|
* 员工信息编辑 DTO
|
||||||
@@ -49,4 +50,7 @@ public class CcdiBaseStaffEditDTO implements Serializable {
|
|||||||
|
|
||||||
/** 状态 */
|
/** 状态 */
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
|
/** 资产信息列表 */
|
||||||
|
private List<CcdiAssetInfoDTO> assetInfoList;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package com.ruoyi.info.collection.domain.excel;
|
||||||
|
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import com.alibaba.excel.annotation.write.style.ColumnWidth;
|
||||||
|
import com.ruoyi.common.annotation.Required;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工资产信息Excel导入导出对象
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-12
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CcdiAssetInfoExcel implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 资产实际持有人身份证号 */
|
||||||
|
@ExcelProperty(value = "资产实际持有人身份证号*", index = 0)
|
||||||
|
@ColumnWidth(22)
|
||||||
|
@Required
|
||||||
|
private String personId;
|
||||||
|
|
||||||
|
/** 资产大类 */
|
||||||
|
@ExcelProperty(value = "资产大类*", index = 1)
|
||||||
|
@ColumnWidth(16)
|
||||||
|
@Required
|
||||||
|
private String assetMainType;
|
||||||
|
|
||||||
|
/** 资产小类 */
|
||||||
|
@ExcelProperty(value = "资产小类*", index = 2)
|
||||||
|
@ColumnWidth(18)
|
||||||
|
@Required
|
||||||
|
private String assetSubType;
|
||||||
|
|
||||||
|
/** 资产名称 */
|
||||||
|
@ExcelProperty(value = "资产名称*", index = 3)
|
||||||
|
@ColumnWidth(24)
|
||||||
|
@Required
|
||||||
|
private String assetName;
|
||||||
|
|
||||||
|
/** 产权占比 */
|
||||||
|
@ExcelProperty(value = "产权占比", index = 4)
|
||||||
|
@ColumnWidth(12)
|
||||||
|
private BigDecimal ownershipRatio;
|
||||||
|
|
||||||
|
/** 购买/评估日期 */
|
||||||
|
@ExcelProperty(value = "购买/评估日期", index = 5)
|
||||||
|
@ColumnWidth(16)
|
||||||
|
private Date purchaseEvalDate;
|
||||||
|
|
||||||
|
/** 资产原值 */
|
||||||
|
@ExcelProperty(value = "资产原值", index = 6)
|
||||||
|
@ColumnWidth(16)
|
||||||
|
private BigDecimal originalValue;
|
||||||
|
|
||||||
|
/** 当前估值 */
|
||||||
|
@ExcelProperty(value = "当前估值*", index = 7)
|
||||||
|
@ColumnWidth(16)
|
||||||
|
@Required
|
||||||
|
private BigDecimal currentValue;
|
||||||
|
|
||||||
|
/** 估值截止日期 */
|
||||||
|
@ExcelProperty(value = "估值截止日期", index = 8)
|
||||||
|
@ColumnWidth(16)
|
||||||
|
private Date valuationDate;
|
||||||
|
|
||||||
|
/** 资产状态 */
|
||||||
|
@ExcelProperty(value = "资产状态*", index = 9)
|
||||||
|
@ColumnWidth(14)
|
||||||
|
@Required
|
||||||
|
private String assetStatus;
|
||||||
|
|
||||||
|
/** 备注 */
|
||||||
|
@ExcelProperty(value = "备注", index = 10)
|
||||||
|
@ColumnWidth(28)
|
||||||
|
private String remarks;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.ruoyi.info.collection.domain.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工资产信息导入失败记录VO
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-12
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "员工资产信息导入失败记录")
|
||||||
|
public class AssetImportFailureVO {
|
||||||
|
|
||||||
|
/** 资产实际持有人身份证号 */
|
||||||
|
@Schema(description = "资产实际持有人身份证号")
|
||||||
|
private String personId;
|
||||||
|
|
||||||
|
/** 资产大类 */
|
||||||
|
@Schema(description = "资产大类")
|
||||||
|
private String assetMainType;
|
||||||
|
|
||||||
|
/** 资产小类 */
|
||||||
|
@Schema(description = "资产小类")
|
||||||
|
private String assetSubType;
|
||||||
|
|
||||||
|
/** 资产名称 */
|
||||||
|
@Schema(description = "资产名称")
|
||||||
|
private String assetName;
|
||||||
|
|
||||||
|
/** 产权占比 */
|
||||||
|
@Schema(description = "产权占比")
|
||||||
|
private BigDecimal ownershipRatio;
|
||||||
|
|
||||||
|
/** 当前估值 */
|
||||||
|
@Schema(description = "当前估值")
|
||||||
|
private BigDecimal currentValue;
|
||||||
|
|
||||||
|
/** 资产状态 */
|
||||||
|
@Schema(description = "资产状态")
|
||||||
|
private String assetStatus;
|
||||||
|
|
||||||
|
/** 错误信息 */
|
||||||
|
@Schema(description = "错误信息")
|
||||||
|
private String errorMessage;
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.ruoyi.info.collection.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.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工资产信息VO
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-12
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "员工资产信息")
|
||||||
|
public class CcdiAssetInfoVO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 资产实际持有人身份证号 */
|
||||||
|
@Schema(description = "资产实际持有人身份证号")
|
||||||
|
private String personId;
|
||||||
|
|
||||||
|
/** 资产大类 */
|
||||||
|
@Schema(description = "资产大类")
|
||||||
|
private String assetMainType;
|
||||||
|
|
||||||
|
/** 资产小类 */
|
||||||
|
@Schema(description = "资产小类")
|
||||||
|
private String assetSubType;
|
||||||
|
|
||||||
|
/** 资产名称 */
|
||||||
|
@Schema(description = "资产名称")
|
||||||
|
private String assetName;
|
||||||
|
|
||||||
|
/** 产权占比 */
|
||||||
|
@Schema(description = "产权占比")
|
||||||
|
private BigDecimal ownershipRatio;
|
||||||
|
|
||||||
|
/** 购买/评估日期 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@Schema(description = "购买/评估日期")
|
||||||
|
private Date purchaseEvalDate;
|
||||||
|
|
||||||
|
/** 资产原值 */
|
||||||
|
@Schema(description = "资产原值")
|
||||||
|
private BigDecimal originalValue;
|
||||||
|
|
||||||
|
/** 当前估值 */
|
||||||
|
@Schema(description = "当前估值")
|
||||||
|
private BigDecimal currentValue;
|
||||||
|
|
||||||
|
/** 估值截止日期 */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@Schema(description = "估值截止日期")
|
||||||
|
private Date valuationDate;
|
||||||
|
|
||||||
|
/** 资产状态 */
|
||||||
|
@Schema(description = "资产状态")
|
||||||
|
private String assetStatus;
|
||||||
|
|
||||||
|
/** 备注 */
|
||||||
|
@Schema(description = "备注")
|
||||||
|
private String remarks;
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import lombok.Data;
|
|||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 员工信息 VO
|
* 员工信息 VO
|
||||||
@@ -56,4 +57,7 @@ public class CcdiBaseStaffVO implements Serializable {
|
|||||||
|
|
||||||
/** 更新者 */
|
/** 更新者 */
|
||||||
private String updateBy;
|
private String updateBy;
|
||||||
|
|
||||||
|
/** 资产信息列表 */
|
||||||
|
private List<CcdiAssetInfoVO> assetInfoList;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package com.ruoyi.info.collection.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiAssetInfo;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工资产信息 数据层
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-12
|
||||||
|
*/
|
||||||
|
public interface CcdiAssetInfoMapper extends BaseMapper<CcdiAssetInfo> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按归属员工身份证号查询资产列表
|
||||||
|
*
|
||||||
|
* @param familyId 归属员工身份证号
|
||||||
|
* @return 资产列表
|
||||||
|
*/
|
||||||
|
List<CcdiAssetInfo> selectByFamilyId(@Param("familyId") String familyId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按归属员工身份证号删除资产
|
||||||
|
*
|
||||||
|
* @param familyId 归属员工身份证号
|
||||||
|
* @return 影响行数
|
||||||
|
*/
|
||||||
|
int deleteByFamilyId(@Param("familyId") String familyId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除归属员工资产
|
||||||
|
*
|
||||||
|
* @param familyIds 归属员工身份证号列表
|
||||||
|
* @return 影响行数
|
||||||
|
*/
|
||||||
|
int deleteByFamilyIds(@Param("familyIds") List<String> familyIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按资产实际持有人身份证号查询资产列表
|
||||||
|
*
|
||||||
|
* @param personId 资产实际持有人身份证号
|
||||||
|
* @return 资产列表
|
||||||
|
*/
|
||||||
|
List<CcdiAssetInfo> selectByPersonId(@Param("personId") String personId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量插入资产数据
|
||||||
|
*
|
||||||
|
* @param list 资产列表
|
||||||
|
* @return 影响行数
|
||||||
|
*/
|
||||||
|
int insertBatch(@Param("list") List<CcdiAssetInfo> list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按员工身份证号查询归属信息
|
||||||
|
*
|
||||||
|
* @param personIds 资产实际持有人身份证号列表
|
||||||
|
* @return 归属映射
|
||||||
|
*/
|
||||||
|
List<Map<String, String>> selectOwnerByEmployeeIdCards(@Param("personIds") List<String> personIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按员工家庭关系身份证号查询归属信息
|
||||||
|
*
|
||||||
|
* @param personIds 资产实际持有人身份证号列表
|
||||||
|
* @return 归属映射
|
||||||
|
*/
|
||||||
|
List<Map<String, String>> selectOwnerByFamilyRelationIdCards(@Param("personIds") List<String> personIds);
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.ruoyi.info.collection.service;
|
||||||
|
|
||||||
|
import com.ruoyi.info.collection.domain.excel.CcdiAssetInfoExcel;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.AssetImportFailureVO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工资产信息异步导入 服务层
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-12
|
||||||
|
*/
|
||||||
|
public interface ICcdiAssetInfoImportService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动异步导入任务
|
||||||
|
*
|
||||||
|
* @param excelList Excel实体列表
|
||||||
|
* @return 任务ID
|
||||||
|
*/
|
||||||
|
String importAssetInfo(List<CcdiAssetInfoExcel> excelList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 异步导入员工资产数据
|
||||||
|
*
|
||||||
|
* @param excelList Excel实体列表
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @param userName 用户名
|
||||||
|
*/
|
||||||
|
void importAssetInfoAsync(List<CcdiAssetInfoExcel> excelList, String taskId, String userName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询导入状态
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @return 导入状态
|
||||||
|
*/
|
||||||
|
ImportStatusVO getImportStatus(String taskId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询导入失败记录
|
||||||
|
*
|
||||||
|
* @param taskId 任务ID
|
||||||
|
* @return 失败记录列表
|
||||||
|
*/
|
||||||
|
List<AssetImportFailureVO> getImportFailures(String taskId);
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.ruoyi.info.collection.service;
|
||||||
|
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiAssetInfo;
|
||||||
|
import com.ruoyi.info.collection.domain.dto.CcdiAssetInfoDTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工资产信息 服务层
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-12
|
||||||
|
*/
|
||||||
|
public interface ICcdiAssetInfoService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按归属员工身份证号查询资产列表
|
||||||
|
*
|
||||||
|
* @param familyId 归属员工身份证号
|
||||||
|
* @return 资产列表
|
||||||
|
*/
|
||||||
|
List<CcdiAssetInfo> selectByFamilyId(String familyId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按归属员工身份证号覆盖资产列表
|
||||||
|
*
|
||||||
|
* @param familyId 归属员工身份证号
|
||||||
|
* @param assetInfoList 资产列表
|
||||||
|
*/
|
||||||
|
void replaceByFamilyId(String familyId, List<CcdiAssetInfoDTO> assetInfoList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除单个员工资产
|
||||||
|
*
|
||||||
|
* @param familyId 归属员工身份证号
|
||||||
|
* @return 影响行数
|
||||||
|
*/
|
||||||
|
int deleteByFamilyId(String familyId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量删除员工资产
|
||||||
|
*
|
||||||
|
* @param familyIds 归属员工身份证号列表
|
||||||
|
* @return 影响行数
|
||||||
|
*/
|
||||||
|
int deleteByFamilyIds(List<String> familyIds);
|
||||||
|
}
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
package com.ruoyi.info.collection.service.impl;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiAssetInfo;
|
||||||
|
import com.ruoyi.info.collection.domain.excel.CcdiAssetInfoExcel;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.AssetImportFailureVO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.ImportResult;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiAssetInfoMapper;
|
||||||
|
import com.ruoyi.info.collection.service.ICcdiAssetInfoImportService;
|
||||||
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
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.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工资产信息异步导入服务层处理
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-12
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@EnableAsync
|
||||||
|
public class CcdiAssetInfoImportServiceImpl implements ICcdiAssetInfoImportService {
|
||||||
|
|
||||||
|
private static final String STATUS_KEY_PREFIX = "import:assetInfo:";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CcdiAssetInfoMapper assetInfoMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Resource
|
||||||
|
private ICcdiAssetInfoImportService assetInfoImportService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public String importAssetInfo(List<CcdiAssetInfoExcel> excelList) {
|
||||||
|
if (excelList == null || excelList.isEmpty()) {
|
||||||
|
throw new RuntimeException("至少需要一条数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
String taskId = UUID.randomUUID().toString();
|
||||||
|
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", System.currentTimeMillis());
|
||||||
|
statusData.put("message", "正在处理...");
|
||||||
|
|
||||||
|
String statusKey = STATUS_KEY_PREFIX + taskId;
|
||||||
|
redisTemplate.opsForHash().putAll(statusKey, statusData);
|
||||||
|
redisTemplate.expire(statusKey, 7, TimeUnit.DAYS);
|
||||||
|
|
||||||
|
assetInfoImportService.importAssetInfoAsync(excelList, taskId, currentUserName());
|
||||||
|
return taskId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Async
|
||||||
|
@Transactional
|
||||||
|
public void importAssetInfoAsync(List<CcdiAssetInfoExcel> excelList, String taskId, String userName) {
|
||||||
|
List<CcdiAssetInfo> successList = new ArrayList<>();
|
||||||
|
List<AssetImportFailureVO> failures = new ArrayList<>();
|
||||||
|
|
||||||
|
List<String> personIds = excelList.stream()
|
||||||
|
.map(CcdiAssetInfoExcel::getPersonId)
|
||||||
|
.filter(StringUtils::isNotEmpty)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
Map<String, Set<String>> ownerMap = buildOwnerMap(personIds);
|
||||||
|
|
||||||
|
for (CcdiAssetInfoExcel excel : excelList) {
|
||||||
|
try {
|
||||||
|
validateExcel(excel);
|
||||||
|
Set<String> familyIds = ownerMap.get(excel.getPersonId());
|
||||||
|
if (familyIds == null || familyIds.isEmpty()) {
|
||||||
|
throw new RuntimeException("未找到资产归属员工");
|
||||||
|
}
|
||||||
|
if (familyIds.size() > 1) {
|
||||||
|
throw new RuntimeException("资产归属员工不唯一");
|
||||||
|
}
|
||||||
|
|
||||||
|
CcdiAssetInfo assetInfo = new CcdiAssetInfo();
|
||||||
|
BeanUtils.copyProperties(excel, assetInfo);
|
||||||
|
assetInfo.setFamilyId(familyIds.iterator().next());
|
||||||
|
assetInfo.setCreateBy(userName);
|
||||||
|
assetInfo.setUpdateBy(userName);
|
||||||
|
successList.add(assetInfo);
|
||||||
|
} catch (Exception e) {
|
||||||
|
AssetImportFailureVO failureVO = new AssetImportFailureVO();
|
||||||
|
BeanUtils.copyProperties(excel, failureVO);
|
||||||
|
failureVO.setErrorMessage(e.getMessage());
|
||||||
|
failures.add(failureVO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!successList.isEmpty()) {
|
||||||
|
assetInfoMapper.insertBatch(successList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!failures.isEmpty()) {
|
||||||
|
redisTemplate.opsForValue().set(STATUS_KEY_PREFIX + taskId + ":failures", failures, 7, TimeUnit.DAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportResult result = new ImportResult();
|
||||||
|
result.setTotalCount(excelList.size());
|
||||||
|
result.setSuccessCount(successList.size());
|
||||||
|
result.setFailureCount(failures.size());
|
||||||
|
updateImportStatus(taskId, failures.isEmpty() ? "SUCCESS" : "PARTIAL_SUCCESS", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImportStatusVO getImportStatus(String taskId) {
|
||||||
|
String key = STATUS_KEY_PREFIX + taskId;
|
||||||
|
if (Boolean.FALSE.equals(redisTemplate.hasKey(key))) {
|
||||||
|
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<AssetImportFailureVO> getImportFailures(String taskId) {
|
||||||
|
Object failuresObj = redisTemplate.opsForValue().get(STATUS_KEY_PREFIX + taskId + ":failures");
|
||||||
|
if (failuresObj == null) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
return JSON.parseArray(JSON.toJSONString(failuresObj), AssetImportFailureVO.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Set<String>> buildOwnerMap(List<String> personIds) {
|
||||||
|
Map<String, Set<String>> result = new LinkedHashMap<>();
|
||||||
|
mergeOwnerMappings(result, assetInfoMapper.selectOwnerByEmployeeIdCards(personIds));
|
||||||
|
mergeOwnerMappings(result, assetInfoMapper.selectOwnerByFamilyRelationIdCards(personIds));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mergeOwnerMappings(Map<String, Set<String>> result, List<Map<String, String>> mappings) {
|
||||||
|
if (mappings == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Map<String, String> mapping : mappings) {
|
||||||
|
String personId = mapping.get("personId");
|
||||||
|
String familyId = mapping.get("familyId");
|
||||||
|
if (StringUtils.isEmpty(personId) || StringUtils.isEmpty(familyId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
result.computeIfAbsent(personId, key -> new java.util.LinkedHashSet<>()).add(familyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateExcel(CcdiAssetInfoExcel excel) {
|
||||||
|
if (StringUtils.isEmpty(excel.getPersonId())) {
|
||||||
|
throw new RuntimeException("资产实际持有人身份证号不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(excel.getAssetMainType())) {
|
||||||
|
throw new RuntimeException("资产大类不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(excel.getAssetSubType())) {
|
||||||
|
throw new RuntimeException("资产小类不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(excel.getAssetName())) {
|
||||||
|
throw new RuntimeException("资产名称不能为空");
|
||||||
|
}
|
||||||
|
if (excel.getCurrentValue() == null) {
|
||||||
|
throw new RuntimeException("当前估值不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(excel.getAssetStatus())) {
|
||||||
|
throw new RuntimeException("资产状态不能为空");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateImportStatus(String taskId, String status, ImportResult result) {
|
||||||
|
Map<String, Object> statusData = new HashMap<>();
|
||||||
|
statusData.put("status", status);
|
||||||
|
statusData.put("successCount", result.getSuccessCount());
|
||||||
|
statusData.put("failureCount", result.getFailureCount());
|
||||||
|
statusData.put("progress", 100);
|
||||||
|
statusData.put("endTime", System.currentTimeMillis());
|
||||||
|
statusData.put("message", "SUCCESS".equals(status)
|
||||||
|
? "全部成功!共导入" + result.getTotalCount() + "条数据"
|
||||||
|
: "成功" + result.getSuccessCount() + "条,失败" + result.getFailureCount() + "条");
|
||||||
|
redisTemplate.opsForHash().putAll(STATUS_KEY_PREFIX + taskId, statusData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String currentUserName() {
|
||||||
|
try {
|
||||||
|
return SecurityUtils.getUsername();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "system";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package com.ruoyi.info.collection.service.impl;
|
||||||
|
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiAssetInfo;
|
||||||
|
import com.ruoyi.info.collection.domain.dto.CcdiAssetInfoDTO;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiAssetInfoMapper;
|
||||||
|
import com.ruoyi.info.collection.service.ICcdiAssetInfoService;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工资产信息 服务层处理
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
* @date 2026-03-12
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class CcdiAssetInfoServiceImpl implements ICcdiAssetInfoService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CcdiAssetInfoMapper assetInfoMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CcdiAssetInfo> selectByFamilyId(String familyId) {
|
||||||
|
return assetInfoMapper.selectByFamilyId(familyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void replaceByFamilyId(String familyId, List<CcdiAssetInfoDTO> assetInfoList) {
|
||||||
|
assetInfoMapper.deleteByFamilyId(familyId);
|
||||||
|
if (assetInfoList == null || assetInfoList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<CcdiAssetInfo> saveList = assetInfoList.stream()
|
||||||
|
.filter(item -> !isEmptyRow(item))
|
||||||
|
.map(item -> toEntity(familyId, item))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (!saveList.isEmpty()) {
|
||||||
|
assetInfoMapper.insertBatch(saveList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteByFamilyId(String familyId) {
|
||||||
|
return assetInfoMapper.deleteByFamilyId(familyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int deleteByFamilyIds(List<String> familyIds) {
|
||||||
|
if (familyIds == null || familyIds.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return assetInfoMapper.deleteByFamilyIds(familyIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CcdiAssetInfo toEntity(String familyId, CcdiAssetInfoDTO dto) {
|
||||||
|
CcdiAssetInfo assetInfo = new CcdiAssetInfo();
|
||||||
|
BeanUtils.copyProperties(dto, assetInfo);
|
||||||
|
assetInfo.setFamilyId(familyId);
|
||||||
|
return assetInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isEmptyRow(CcdiAssetInfoDTO dto) {
|
||||||
|
return StringUtils.isEmpty(dto.getPersonId())
|
||||||
|
&& StringUtils.isEmpty(dto.getAssetMainType())
|
||||||
|
&& StringUtils.isEmpty(dto.getAssetSubType())
|
||||||
|
&& StringUtils.isEmpty(dto.getAssetName())
|
||||||
|
&& dto.getCurrentValue() == null
|
||||||
|
&& StringUtils.isEmpty(dto.getAssetStatus())
|
||||||
|
&& dto.getOwnershipRatio() == null
|
||||||
|
&& dto.getPurchaseEvalDate() == null
|
||||||
|
&& dto.getOriginalValue() == null
|
||||||
|
&& dto.getValuationDate() == null
|
||||||
|
&& StringUtils.isEmpty(dto.getRemarks());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,10 +7,12 @@ import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffAddDTO;
|
|||||||
import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffEditDTO;
|
import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffEditDTO;
|
||||||
import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffQueryDTO;
|
import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffQueryDTO;
|
||||||
import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffExcel;
|
import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffExcel;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.CcdiAssetInfoVO;
|
||||||
import com.ruoyi.info.collection.domain.vo.CcdiBaseStaffOptionVO;
|
import com.ruoyi.info.collection.domain.vo.CcdiBaseStaffOptionVO;
|
||||||
import com.ruoyi.info.collection.domain.vo.CcdiBaseStaffVO;
|
import com.ruoyi.info.collection.domain.vo.CcdiBaseStaffVO;
|
||||||
import com.ruoyi.info.collection.enums.EmployeeStatus;
|
import com.ruoyi.info.collection.enums.EmployeeStatus;
|
||||||
import com.ruoyi.info.collection.mapper.CcdiBaseStaffMapper;
|
import com.ruoyi.info.collection.mapper.CcdiBaseStaffMapper;
|
||||||
|
import com.ruoyi.info.collection.service.ICcdiAssetInfoService;
|
||||||
import com.ruoyi.info.collection.service.ICcdiBaseStaffImportService;
|
import com.ruoyi.info.collection.service.ICcdiBaseStaffImportService;
|
||||||
import com.ruoyi.info.collection.service.ICcdiBaseStaffService;
|
import com.ruoyi.info.collection.service.ICcdiBaseStaffService;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
@@ -40,6 +42,9 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService {
|
|||||||
@Resource
|
@Resource
|
||||||
private RedisTemplate<String, Object> redisTemplate;
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ICcdiAssetInfoService assetInfoService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询员工列表
|
* 查询员工列表
|
||||||
*
|
*
|
||||||
@@ -104,7 +109,15 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService {
|
|||||||
@Override
|
@Override
|
||||||
public CcdiBaseStaffVO selectBaseStaffById(Long staffId) {
|
public CcdiBaseStaffVO selectBaseStaffById(Long staffId) {
|
||||||
CcdiBaseStaff staff = baseStaffMapper.selectById(staffId);
|
CcdiBaseStaff staff = baseStaffMapper.selectById(staffId);
|
||||||
return convertToVO(staff);
|
CcdiBaseStaffVO vo = convertToVO(staff);
|
||||||
|
if (staff != null) {
|
||||||
|
vo.setAssetInfoList(assetInfoService.selectByFamilyId(staff.getIdCard()).stream().map(asset -> {
|
||||||
|
CcdiAssetInfoVO assetInfoVO = new CcdiAssetInfoVO();
|
||||||
|
BeanUtils.copyProperties(asset, assetInfoVO);
|
||||||
|
return assetInfoVO;
|
||||||
|
}).toList());
|
||||||
|
}
|
||||||
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,6 +144,7 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService {
|
|||||||
CcdiBaseStaff staff = new CcdiBaseStaff();
|
CcdiBaseStaff staff = new CcdiBaseStaff();
|
||||||
BeanUtils.copyProperties(addDTO, staff);
|
BeanUtils.copyProperties(addDTO, staff);
|
||||||
int result = baseStaffMapper.insert(staff);
|
int result = baseStaffMapper.insert(staff);
|
||||||
|
assetInfoService.replaceByFamilyId(addDTO.getIdCard(), addDTO.getAssetInfoList());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -144,6 +158,11 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public int updateBaseStaff(CcdiBaseStaffEditDTO editDTO) {
|
public int updateBaseStaff(CcdiBaseStaffEditDTO editDTO) {
|
||||||
|
CcdiBaseStaff existing = baseStaffMapper.selectById(editDTO.getStaffId());
|
||||||
|
if (existing == null) {
|
||||||
|
throw new RuntimeException("员工不存在");
|
||||||
|
}
|
||||||
|
|
||||||
// 检查身份证号唯一性(排除自己)
|
// 检查身份证号唯一性(排除自己)
|
||||||
if (StringUtils.isNotEmpty(editDTO.getIdCard())) {
|
if (StringUtils.isNotEmpty(editDTO.getIdCard())) {
|
||||||
LambdaQueryWrapper<CcdiBaseStaff> wrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<CcdiBaseStaff> wrapper = new LambdaQueryWrapper<>();
|
||||||
@@ -158,6 +177,11 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService {
|
|||||||
BeanUtils.copyProperties(editDTO, staff);
|
BeanUtils.copyProperties(editDTO, staff);
|
||||||
int result = baseStaffMapper.updateById(staff);
|
int result = baseStaffMapper.updateById(staff);
|
||||||
|
|
||||||
|
if (!StringUtils.equals(existing.getIdCard(), editDTO.getIdCard())) {
|
||||||
|
assetInfoService.deleteByFamilyId(existing.getIdCard());
|
||||||
|
}
|
||||||
|
assetInfoService.replaceByFamilyId(editDTO.getIdCard(), editDTO.getAssetInfoList());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +194,13 @@ public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public int deleteBaseStaffByIds(Long[] staffIds) {
|
public int deleteBaseStaffByIds(Long[] staffIds) {
|
||||||
return baseStaffMapper.deleteBatchIds(List.of(staffIds));
|
List<Long> idList = List.of(staffIds);
|
||||||
|
List<String> familyIds = baseStaffMapper.selectBatchIds(idList).stream()
|
||||||
|
.map(CcdiBaseStaff::getIdCard)
|
||||||
|
.filter(StringUtils::isNotEmpty)
|
||||||
|
.toList();
|
||||||
|
assetInfoService.deleteByFamilyIds(familyIds);
|
||||||
|
return baseStaffMapper.deleteBatchIds(idList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
<?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.info.collection.mapper.CcdiAssetInfoMapper">
|
||||||
|
|
||||||
|
<resultMap id="CcdiAssetInfoResultMap" type="com.ruoyi.info.collection.domain.CcdiAssetInfo">
|
||||||
|
<id property="assetId" column="asset_id"/>
|
||||||
|
<result property="familyId" column="family_id"/>
|
||||||
|
<result property="personId" column="person_id"/>
|
||||||
|
<result property="assetMainType" column="asset_main_type"/>
|
||||||
|
<result property="assetSubType" column="asset_sub_type"/>
|
||||||
|
<result property="assetName" column="asset_name"/>
|
||||||
|
<result property="ownershipRatio" column="ownership_ratio"/>
|
||||||
|
<result property="purchaseEvalDate" column="purchase_eval_date"/>
|
||||||
|
<result property="originalValue" column="original_value"/>
|
||||||
|
<result property="currentValue" column="current_value"/>
|
||||||
|
<result property="valuationDate" column="valuation_date"/>
|
||||||
|
<result property="assetStatus" column="asset_status"/>
|
||||||
|
<result property="remarks" column="remarks"/>
|
||||||
|
<result property="createBy" column="create_by"/>
|
||||||
|
<result property="createTime" column="create_time"/>
|
||||||
|
<result property="updateBy" column="update_by"/>
|
||||||
|
<result property="updateTime" column="update_time"/>
|
||||||
|
</resultMap>
|
||||||
|
|
||||||
|
<select id="selectByFamilyId" resultMap="CcdiAssetInfoResultMap">
|
||||||
|
SELECT
|
||||||
|
asset_id, family_id, person_id, asset_main_type, asset_sub_type, asset_name,
|
||||||
|
ownership_ratio, purchase_eval_date, original_value, current_value,
|
||||||
|
valuation_date, asset_status, remarks, create_by, create_time, update_by, update_time
|
||||||
|
FROM ccdi_asset_info
|
||||||
|
WHERE family_id = #{familyId}
|
||||||
|
ORDER BY create_time DESC, asset_id DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectByPersonId" resultMap="CcdiAssetInfoResultMap">
|
||||||
|
SELECT
|
||||||
|
asset_id, family_id, person_id, asset_main_type, asset_sub_type, asset_name,
|
||||||
|
ownership_ratio, purchase_eval_date, original_value, current_value,
|
||||||
|
valuation_date, asset_status, remarks, create_by, create_time, update_by, update_time
|
||||||
|
FROM ccdi_asset_info
|
||||||
|
WHERE person_id = #{personId}
|
||||||
|
ORDER BY create_time DESC, asset_id DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<delete id="deleteByFamilyId">
|
||||||
|
DELETE FROM ccdi_asset_info
|
||||||
|
WHERE family_id = #{familyId}
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<delete id="deleteByFamilyIds">
|
||||||
|
DELETE FROM ccdi_asset_info
|
||||||
|
WHERE family_id IN
|
||||||
|
<foreach collection="familyIds" item="familyId" open="(" separator="," close=")">
|
||||||
|
#{familyId}
|
||||||
|
</foreach>
|
||||||
|
</delete>
|
||||||
|
|
||||||
|
<insert id="insertBatch">
|
||||||
|
INSERT INTO ccdi_asset_info
|
||||||
|
(family_id, person_id, asset_main_type, asset_sub_type, asset_name,
|
||||||
|
ownership_ratio, purchase_eval_date, original_value, current_value,
|
||||||
|
valuation_date, asset_status, remarks, create_by, create_time, update_by, update_time)
|
||||||
|
VALUES
|
||||||
|
<foreach collection="list" item="item" separator=",">
|
||||||
|
(#{item.familyId}, #{item.personId}, #{item.assetMainType}, #{item.assetSubType}, #{item.assetName},
|
||||||
|
#{item.ownershipRatio}, #{item.purchaseEvalDate}, #{item.originalValue}, #{item.currentValue},
|
||||||
|
#{item.valuationDate}, #{item.assetStatus}, #{item.remarks}, #{item.createBy}, NOW(), #{item.updateBy}, NOW())
|
||||||
|
</foreach>
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<select id="selectOwnerByEmployeeIdCards" resultType="map">
|
||||||
|
SELECT
|
||||||
|
id_card AS personId,
|
||||||
|
id_card AS familyId
|
||||||
|
FROM ccdi_base_staff
|
||||||
|
WHERE id_card IN
|
||||||
|
<foreach collection="personIds" item="personId" open="(" separator="," close=")">
|
||||||
|
#{personId}
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectOwnerByFamilyRelationIdCards" resultType="map">
|
||||||
|
SELECT
|
||||||
|
relation_cert_no AS personId,
|
||||||
|
person_id AS familyId
|
||||||
|
FROM ccdi_staff_fmy_relation
|
||||||
|
WHERE is_emp_family = 1
|
||||||
|
AND relation_cert_no IN
|
||||||
|
<foreach collection="personIds" item="personId" open="(" separator="," close=")">
|
||||||
|
#{personId}
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
package com.ruoyi.info.collection.mapper;
|
||||||
|
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiAssetInfo;
|
||||||
|
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
|
||||||
|
import org.apache.ibatis.mapping.BoundSql;
|
||||||
|
import org.apache.ibatis.mapping.Environment;
|
||||||
|
import org.apache.ibatis.mapping.MappedStatement;
|
||||||
|
import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
|
||||||
|
import org.apache.ibatis.session.Configuration;
|
||||||
|
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
|
||||||
|
import org.apache.ibatis.type.TypeAliasRegistry;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class CcdiAssetInfoMapperTest {
|
||||||
|
|
||||||
|
private static final String RESOURCE = "mapper/info/collection/CcdiAssetInfoMapper.xml";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void selectByFamilyId_shouldFilterByFamilyId() throws Exception {
|
||||||
|
MappedStatement mappedStatement = loadMappedStatement(
|
||||||
|
"com.ruoyi.info.collection.mapper.CcdiAssetInfoMapper.selectByFamilyId");
|
||||||
|
|
||||||
|
String sql = renderSql(mappedStatement, Map.of("familyId", "320101199001010011"));
|
||||||
|
|
||||||
|
assertTrue(sql.contains("FROM ccdi_asset_info"), sql);
|
||||||
|
assertTrue(sql.contains("WHERE family_id = ?"), sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void selectByPersonId_shouldFilterByPersonId() throws Exception {
|
||||||
|
MappedStatement mappedStatement = loadMappedStatement(
|
||||||
|
"com.ruoyi.info.collection.mapper.CcdiAssetInfoMapper.selectByPersonId");
|
||||||
|
|
||||||
|
String sql = renderSql(mappedStatement, Map.of("personId", "320101199201010022"));
|
||||||
|
|
||||||
|
assertTrue(sql.contains("FROM ccdi_asset_info"), sql);
|
||||||
|
assertTrue(sql.contains("WHERE person_id = ?"), sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void deleteByFamilyIds_shouldRenderInClause() throws Exception {
|
||||||
|
MappedStatement mappedStatement = loadMappedStatement(
|
||||||
|
"com.ruoyi.info.collection.mapper.CcdiAssetInfoMapper.deleteByFamilyIds");
|
||||||
|
|
||||||
|
String sql = renderSql(mappedStatement, Map.of("familyIds", List.of("A", "B")));
|
||||||
|
|
||||||
|
assertTrue(sql.contains("DELETE FROM ccdi_asset_info"), sql);
|
||||||
|
assertTrue(sql.contains("family_id IN"), sql);
|
||||||
|
assertFalse(sql.contains("IN ()"), sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void insertBatch_shouldIncludeAllBusinessColumns() throws Exception {
|
||||||
|
MappedStatement mappedStatement = loadMappedStatement(
|
||||||
|
"com.ruoyi.info.collection.mapper.CcdiAssetInfoMapper.insertBatch");
|
||||||
|
|
||||||
|
CcdiAssetInfo assetInfo = new CcdiAssetInfo();
|
||||||
|
assetInfo.setFamilyId("320101199001010011");
|
||||||
|
assetInfo.setPersonId("320101199201010022");
|
||||||
|
assetInfo.setAssetMainType("车辆");
|
||||||
|
assetInfo.setAssetSubType("小汽车");
|
||||||
|
assetInfo.setAssetName("家庭车辆");
|
||||||
|
assetInfo.setCurrentValue(new BigDecimal("100000.00"));
|
||||||
|
assetInfo.setAssetStatus("正常");
|
||||||
|
|
||||||
|
String sql = renderSql(mappedStatement, Map.of("list", List.of(assetInfo)));
|
||||||
|
|
||||||
|
assertTrue(sql.contains("INSERT INTO ccdi_asset_info"), sql);
|
||||||
|
assertTrue(sql.contains("family_id"), sql);
|
||||||
|
assertTrue(sql.contains("person_id"), sql);
|
||||||
|
assertTrue(sql.contains("asset_main_type"), sql);
|
||||||
|
assertTrue(sql.contains("current_value"), sql);
|
||||||
|
assertTrue(sql.contains("asset_status"), sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void ownerLookupQueries_shouldResolveFromEmployeeAndFamilyRelation() throws Exception {
|
||||||
|
MappedStatement employeeStatement = loadMappedStatement(
|
||||||
|
"com.ruoyi.info.collection.mapper.CcdiAssetInfoMapper.selectOwnerByEmployeeIdCards");
|
||||||
|
MappedStatement familyStatement = loadMappedStatement(
|
||||||
|
"com.ruoyi.info.collection.mapper.CcdiAssetInfoMapper.selectOwnerByFamilyRelationIdCards");
|
||||||
|
|
||||||
|
String employeeSql = renderSql(employeeStatement, Map.of("personIds", List.of("A")));
|
||||||
|
String familySql = renderSql(familyStatement, Map.of("personIds", List.of("B")));
|
||||||
|
|
||||||
|
assertTrue(employeeSql.contains("FROM ccdi_base_staff"), employeeSql);
|
||||||
|
assertTrue(employeeSql.contains("id_card AS personId"), employeeSql);
|
||||||
|
assertTrue(employeeSql.contains("id_card AS familyId"), employeeSql);
|
||||||
|
|
||||||
|
assertTrue(familySql.contains("FROM ccdi_staff_fmy_relation"), familySql);
|
||||||
|
assertTrue(familySql.contains("relation_cert_no AS personId"), familySql);
|
||||||
|
assertTrue(familySql.contains("person_id AS familyId"), familySql);
|
||||||
|
assertTrue(familySql.contains("is_emp_family = 1"), familySql);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MappedStatement loadMappedStatement(String statementId) throws Exception {
|
||||||
|
Configuration configuration = new Configuration();
|
||||||
|
configuration.setEnvironment(new Environment("test", new JdbcTransactionFactory(), new NoOpDataSource()));
|
||||||
|
registerTypeAliases(configuration.getTypeAliasRegistry());
|
||||||
|
configuration.getLanguageRegistry().register(XMLLanguageDriver.class);
|
||||||
|
configuration.addMapper(CcdiAssetInfoMapper.class);
|
||||||
|
|
||||||
|
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(RESOURCE)) {
|
||||||
|
XMLMapperBuilder xmlMapperBuilder =
|
||||||
|
new XMLMapperBuilder(inputStream, configuration, RESOURCE, configuration.getSqlFragments());
|
||||||
|
xmlMapperBuilder.parse();
|
||||||
|
}
|
||||||
|
return configuration.getMappedStatement(statementId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String renderSql(MappedStatement mappedStatement, Map<String, Object> params) {
|
||||||
|
BoundSql boundSql = mappedStatement.getBoundSql(new HashMap<>(params));
|
||||||
|
return boundSql.getSql().replaceAll("\\s+", " ").trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerTypeAliases(TypeAliasRegistry typeAliasRegistry) {
|
||||||
|
typeAliasRegistry.registerAlias("map", Map.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NoOpDataSource implements DataSource {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.sql.Connection getConnection() {
|
||||||
|
throw new UnsupportedOperationException("Not required for SQL rendering tests");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.sql.Connection getConnection(String username, String password) {
|
||||||
|
throw new UnsupportedOperationException("Not required for SQL rendering tests");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.io.PrintWriter getLogWriter() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLogWriter(java.io.PrintWriter out) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLoginTimeout(int seconds) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLoginTimeout() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.util.logging.Logger getParentLogger() {
|
||||||
|
return java.util.logging.Logger.getGlobal();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T unwrap(Class<T> iface) {
|
||||||
|
throw new UnsupportedOperationException("Not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWrapperFor(Class<?> iface) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
package com.ruoyi.info.collection.service;
|
||||||
|
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiAssetInfo;
|
||||||
|
import com.ruoyi.info.collection.domain.excel.CcdiAssetInfoExcel;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.AssetImportFailureVO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.ImportStatusVO;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiAssetInfoMapper;
|
||||||
|
import com.ruoyi.info.collection.service.impl.CcdiAssetInfoImportServiceImpl;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.data.redis.core.HashOperations;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.core.ValueOperations;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyMap;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.ArgumentMatchers.startsWith;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class CcdiAssetInfoImportServiceImplTest {
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private CcdiAssetInfoImportServiceImpl service;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CcdiAssetInfoMapper assetInfoMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ICcdiAssetInfoImportService assetInfoImportService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private HashOperations<String, Object, Object> hashOperations;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ValueOperations<String, Object> valueOperations;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void assetInfoExcel_shouldExcludeAssetIdAndFamilyId() {
|
||||||
|
Set<String> fieldNames = Arrays.stream(CcdiAssetInfoExcel.class.getDeclaredFields())
|
||||||
|
.map(field -> field.getName())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
assertFalse(fieldNames.contains("assetId"));
|
||||||
|
assertFalse(fieldNames.contains("familyId"));
|
||||||
|
assertTrue(fieldNames.contains("personId"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void importAssetInfo_shouldUseDedicatedAssetTaskKeys() {
|
||||||
|
List<CcdiAssetInfoExcel> excelList = List.of(buildExcel("320101199001010011", "房产"));
|
||||||
|
when(redisTemplate.opsForHash()).thenReturn(hashOperations);
|
||||||
|
|
||||||
|
String taskId = service.importAssetInfo(excelList);
|
||||||
|
|
||||||
|
verify(hashOperations).putAll(eq("import:assetInfo:" + taskId), anyMap());
|
||||||
|
verify(redisTemplate).expire("import:assetInfo:" + taskId, 7, TimeUnit.DAYS);
|
||||||
|
verify(assetInfoImportService).importAssetInfoAsync(eq(excelList), eq(taskId), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void importAssetInfoAsync_shouldResolveFamilyIdFromEmployeeIdCard() {
|
||||||
|
CcdiAssetInfoExcel excel = buildExcel("320101199001010011", "房产");
|
||||||
|
when(redisTemplate.opsForHash()).thenReturn(hashOperations);
|
||||||
|
when(assetInfoMapper.selectOwnerByEmployeeIdCards(List.of("320101199001010011")))
|
||||||
|
.thenReturn(List.of(owner("320101199001010011", "320101199001010011")));
|
||||||
|
when(assetInfoMapper.selectOwnerByFamilyRelationIdCards(List.of("320101199001010011")))
|
||||||
|
.thenReturn(List.of());
|
||||||
|
|
||||||
|
service.importAssetInfoAsync(List.of(excel), "task-1", "tester");
|
||||||
|
|
||||||
|
ArgumentCaptor<List<CcdiAssetInfo>> captor = ArgumentCaptor.forClass(List.class);
|
||||||
|
verify(assetInfoMapper).insertBatch(captor.capture());
|
||||||
|
assertEquals("320101199001010011", captor.getValue().get(0).getFamilyId());
|
||||||
|
assertEquals("320101199001010011", captor.getValue().get(0).getPersonId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void importAssetInfoAsync_shouldResolveFamilyIdFromFamilyRelationIdCard() {
|
||||||
|
CcdiAssetInfoExcel excel = buildExcel("320101199201010022", "车辆");
|
||||||
|
when(redisTemplate.opsForHash()).thenReturn(hashOperations);
|
||||||
|
when(assetInfoMapper.selectOwnerByEmployeeIdCards(List.of("320101199201010022")))
|
||||||
|
.thenReturn(List.of());
|
||||||
|
when(assetInfoMapper.selectOwnerByFamilyRelationIdCards(List.of("320101199201010022")))
|
||||||
|
.thenReturn(List.of(owner("320101199201010022", "320101199001010011")));
|
||||||
|
|
||||||
|
service.importAssetInfoAsync(List.of(excel), "task-2", "tester");
|
||||||
|
|
||||||
|
ArgumentCaptor<List<CcdiAssetInfo>> captor = ArgumentCaptor.forClass(List.class);
|
||||||
|
verify(assetInfoMapper).insertBatch(captor.capture());
|
||||||
|
assertEquals("320101199001010011", captor.getValue().get(0).getFamilyId());
|
||||||
|
assertEquals("320101199201010022", captor.getValue().get(0).getPersonId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void importAssetInfoAsync_shouldStoreFailureRowsOnlyForBadRecords() {
|
||||||
|
CcdiAssetInfoExcel good = buildExcel("320101199001010011", "房产");
|
||||||
|
CcdiAssetInfoExcel bad = buildExcel("320101199001010099", "车辆");
|
||||||
|
|
||||||
|
when(redisTemplate.opsForHash()).thenReturn(hashOperations);
|
||||||
|
when(redisTemplate.opsForValue()).thenReturn(valueOperations);
|
||||||
|
when(assetInfoMapper.selectOwnerByEmployeeIdCards(List.of("320101199001010011", "320101199001010099")))
|
||||||
|
.thenReturn(List.of(owner("320101199001010011", "320101199001010011")));
|
||||||
|
when(assetInfoMapper.selectOwnerByFamilyRelationIdCards(List.of("320101199001010011", "320101199001010099")))
|
||||||
|
.thenReturn(List.of());
|
||||||
|
|
||||||
|
service.importAssetInfoAsync(List.of(good, bad), "task-3", "tester");
|
||||||
|
|
||||||
|
ArgumentCaptor<List<CcdiAssetInfo>> insertCaptor = ArgumentCaptor.forClass(List.class);
|
||||||
|
verify(assetInfoMapper).insertBatch(insertCaptor.capture());
|
||||||
|
assertEquals(1, insertCaptor.getValue().size());
|
||||||
|
assertEquals("320101199001010011", insertCaptor.getValue().get(0).getFamilyId());
|
||||||
|
|
||||||
|
ArgumentCaptor<Object> failureCaptor = ArgumentCaptor.forClass(Object.class);
|
||||||
|
verify(valueOperations).set(eq("import:assetInfo:task-3:failures"), failureCaptor.capture(), eq(7L), eq(TimeUnit.DAYS));
|
||||||
|
List<?> failures = (List<?>) failureCaptor.getValue();
|
||||||
|
assertEquals(1, failures.size());
|
||||||
|
AssetImportFailureVO failure = (AssetImportFailureVO) failures.get(0);
|
||||||
|
assertEquals("320101199001010099", failure.getPersonId());
|
||||||
|
assertTrue(failure.getErrorMessage().contains("未找到资产归属员工"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void importAssetInfoAsync_shouldFailWhenOwnerIsAmbiguous() {
|
||||||
|
CcdiAssetInfoExcel excel = buildExcel("320101199201010022", "车辆");
|
||||||
|
when(redisTemplate.opsForHash()).thenReturn(hashOperations);
|
||||||
|
when(redisTemplate.opsForValue()).thenReturn(valueOperations);
|
||||||
|
when(assetInfoMapper.selectOwnerByEmployeeIdCards(List.of("320101199201010022")))
|
||||||
|
.thenReturn(List.of(
|
||||||
|
owner("320101199201010022", "320101199001010011"),
|
||||||
|
owner("320101199201010022", "320101199001010033")
|
||||||
|
));
|
||||||
|
when(assetInfoMapper.selectOwnerByFamilyRelationIdCards(List.of("320101199201010022")))
|
||||||
|
.thenReturn(List.of());
|
||||||
|
|
||||||
|
service.importAssetInfoAsync(List.of(excel), "task-4", "tester");
|
||||||
|
|
||||||
|
verify(assetInfoMapper, never()).insertBatch(any());
|
||||||
|
ArgumentCaptor<Object> failureCaptor = ArgumentCaptor.forClass(Object.class);
|
||||||
|
verify(valueOperations).set(eq("import:assetInfo:task-4:failures"), failureCaptor.capture(), eq(7L), eq(TimeUnit.DAYS));
|
||||||
|
AssetImportFailureVO failure = (AssetImportFailureVO) ((List<?>) failureCaptor.getValue()).get(0);
|
||||||
|
assertTrue(failure.getErrorMessage().contains("资产归属员工不唯一"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getImportStatusAndFailures_shouldUseAssetPrefixes() {
|
||||||
|
when(redisTemplate.opsForHash()).thenReturn(hashOperations);
|
||||||
|
when(redisTemplate.opsForValue()).thenReturn(valueOperations);
|
||||||
|
when(redisTemplate.hasKey("import:assetInfo:task-5")).thenReturn(true);
|
||||||
|
when(hashOperations.entries("import:assetInfo:task-5")).thenReturn(Map.of(
|
||||||
|
"taskId", "task-5",
|
||||||
|
"status", "SUCCESS",
|
||||||
|
"totalCount", 1,
|
||||||
|
"successCount", 1,
|
||||||
|
"failureCount", 0,
|
||||||
|
"progress", 100,
|
||||||
|
"startTime", 1L,
|
||||||
|
"endTime", 2L,
|
||||||
|
"message", "全部成功"
|
||||||
|
));
|
||||||
|
AssetImportFailureVO failureVO = new AssetImportFailureVO();
|
||||||
|
failureVO.setPersonId("320101199001010099");
|
||||||
|
failureVO.setErrorMessage("未找到资产归属员工");
|
||||||
|
when(valueOperations.get("import:assetInfo:task-5:failures")).thenReturn(List.of(failureVO));
|
||||||
|
|
||||||
|
ImportStatusVO statusVO = service.getImportStatus("task-5");
|
||||||
|
List<AssetImportFailureVO> failures = service.getImportFailures("task-5");
|
||||||
|
|
||||||
|
assertEquals("task-5", statusVO.getTaskId());
|
||||||
|
assertEquals("SUCCESS", statusVO.getStatus());
|
||||||
|
assertNotNull(failures);
|
||||||
|
assertEquals(1, failures.size());
|
||||||
|
assertEquals("320101199001010099", failures.get(0).getPersonId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private CcdiAssetInfoExcel buildExcel(String personId, String assetMainType) {
|
||||||
|
CcdiAssetInfoExcel excel = new CcdiAssetInfoExcel();
|
||||||
|
excel.setPersonId(personId);
|
||||||
|
excel.setAssetMainType(assetMainType);
|
||||||
|
excel.setAssetSubType(assetMainType + "小类");
|
||||||
|
excel.setAssetName(assetMainType + "名称");
|
||||||
|
excel.setCurrentValue(new BigDecimal("100.00"));
|
||||||
|
excel.setAssetStatus("正常");
|
||||||
|
return excel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, String> owner(String personId, String familyId) {
|
||||||
|
return Map.of("personId", personId, "familyId", familyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package com.ruoyi.info.collection.service;
|
||||||
|
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiAssetInfo;
|
||||||
|
import com.ruoyi.info.collection.domain.dto.CcdiAssetInfoDTO;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiAssetInfoMapper;
|
||||||
|
import com.ruoyi.info.collection.service.impl.CcdiAssetInfoServiceImpl;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyList;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class CcdiAssetInfoServiceImplTest {
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private CcdiAssetInfoServiceImpl service;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CcdiAssetInfoMapper assetInfoMapper;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void selectByFamilyId_shouldReturnMapperResult() {
|
||||||
|
List<CcdiAssetInfo> expected = List.of(new CcdiAssetInfo());
|
||||||
|
when(assetInfoMapper.selectByFamilyId("320101199001010011")).thenReturn(expected);
|
||||||
|
|
||||||
|
List<CcdiAssetInfo> result = service.selectByFamilyId("320101199001010011");
|
||||||
|
|
||||||
|
assertSame(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void replaceByFamilyId_shouldDeleteThenInsertNormalizedRows() {
|
||||||
|
CcdiAssetInfoDTO selfOwnedAsset = buildDto("320101199001010011", "房产");
|
||||||
|
CcdiAssetInfoDTO familyOwnedAsset = buildDto("320101199201010022", "车辆");
|
||||||
|
|
||||||
|
service.replaceByFamilyId("320101199001010011", List.of(selfOwnedAsset, familyOwnedAsset));
|
||||||
|
|
||||||
|
verify(assetInfoMapper).deleteByFamilyId("320101199001010011");
|
||||||
|
ArgumentCaptor<List<CcdiAssetInfo>> captor = ArgumentCaptor.forClass(List.class);
|
||||||
|
verify(assetInfoMapper).insertBatch(captor.capture());
|
||||||
|
|
||||||
|
List<CcdiAssetInfo> savedList = captor.getValue();
|
||||||
|
assertEquals(2, savedList.size());
|
||||||
|
assertEquals("320101199001010011", savedList.get(0).getFamilyId());
|
||||||
|
assertEquals("320101199001010011", savedList.get(0).getPersonId());
|
||||||
|
assertEquals("320101199001010011", savedList.get(1).getFamilyId());
|
||||||
|
assertEquals("320101199201010022", savedList.get(1).getPersonId());
|
||||||
|
assertEquals("房产", savedList.get(0).getAssetMainType());
|
||||||
|
assertEquals("车辆", savedList.get(1).getAssetMainType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void replaceByFamilyId_shouldIgnoreEmptyRows() {
|
||||||
|
CcdiAssetInfoDTO emptyRow = new CcdiAssetInfoDTO();
|
||||||
|
|
||||||
|
service.replaceByFamilyId("320101199001010011", List.of(emptyRow));
|
||||||
|
|
||||||
|
verify(assetInfoMapper).deleteByFamilyId("320101199001010011");
|
||||||
|
verify(assetInfoMapper, never()).insertBatch(anyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void deleteByFamilyId_shouldDelegateToMapper() {
|
||||||
|
when(assetInfoMapper.deleteByFamilyId("320101199001010011")).thenReturn(1);
|
||||||
|
|
||||||
|
int result = service.deleteByFamilyId("320101199001010011");
|
||||||
|
|
||||||
|
assertEquals(1, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void deleteByFamilyIds_shouldDelegateToMapper() {
|
||||||
|
List<String> familyIds = List.of("320101199001010011", "320101199001010033");
|
||||||
|
when(assetInfoMapper.deleteByFamilyIds(familyIds)).thenReturn(2);
|
||||||
|
|
||||||
|
int result = service.deleteByFamilyIds(familyIds);
|
||||||
|
|
||||||
|
assertEquals(2, result);
|
||||||
|
verify(assetInfoMapper).deleteByFamilyIds(eq(familyIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
private CcdiAssetInfoDTO buildDto(String personId, String assetMainType) {
|
||||||
|
CcdiAssetInfoDTO dto = new CcdiAssetInfoDTO();
|
||||||
|
dto.setPersonId(personId);
|
||||||
|
dto.setAssetMainType(assetMainType);
|
||||||
|
dto.setAssetSubType(assetMainType + "小类");
|
||||||
|
dto.setAssetName(assetMainType + "名称");
|
||||||
|
dto.setCurrentValue(new BigDecimal("100.00"));
|
||||||
|
dto.setAssetStatus("正常");
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.ruoyi.info.collection.service;
|
||||||
|
|
||||||
|
import com.ruoyi.info.collection.domain.dto.CcdiAssetInfoDTO;
|
||||||
|
import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffAddDTO;
|
||||||
|
import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffEditDTO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.CcdiAssetInfoVO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.CcdiBaseStaffVO;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
|
|
||||||
|
class CcdiBaseStaffServiceAssetAggregationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void addDto_shouldExposeAssetInfoList() {
|
||||||
|
CcdiBaseStaffAddDTO addDTO = new CcdiBaseStaffAddDTO();
|
||||||
|
List<CcdiAssetInfoDTO> assetInfoList = List.of(new CcdiAssetInfoDTO());
|
||||||
|
|
||||||
|
addDTO.setAssetInfoList(assetInfoList);
|
||||||
|
|
||||||
|
assertSame(assetInfoList, addDTO.getAssetInfoList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void editDto_shouldExposeAssetInfoList() {
|
||||||
|
CcdiBaseStaffEditDTO editDTO = new CcdiBaseStaffEditDTO();
|
||||||
|
List<CcdiAssetInfoDTO> assetInfoList = List.of(new CcdiAssetInfoDTO());
|
||||||
|
|
||||||
|
editDTO.setAssetInfoList(assetInfoList);
|
||||||
|
|
||||||
|
assertSame(assetInfoList, editDTO.getAssetInfoList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void staffVo_shouldExposeAssetInfoList() {
|
||||||
|
CcdiBaseStaffVO staffVO = new CcdiBaseStaffVO();
|
||||||
|
List<CcdiAssetInfoVO> assetInfoList = List.of(new CcdiAssetInfoVO());
|
||||||
|
|
||||||
|
staffVO.setAssetInfoList(assetInfoList);
|
||||||
|
|
||||||
|
assertSame(assetInfoList, staffVO.getAssetInfoList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
package com.ruoyi.info.collection.service;
|
||||||
|
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiAssetInfo;
|
||||||
|
import com.ruoyi.info.collection.domain.CcdiBaseStaff;
|
||||||
|
import com.ruoyi.info.collection.domain.dto.CcdiAssetInfoDTO;
|
||||||
|
import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffAddDTO;
|
||||||
|
import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffEditDTO;
|
||||||
|
import com.ruoyi.info.collection.domain.vo.CcdiBaseStaffVO;
|
||||||
|
import com.ruoyi.info.collection.mapper.CcdiBaseStaffMapper;
|
||||||
|
import com.ruoyi.info.collection.service.impl.CcdiBaseStaffServiceImpl;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class CcdiBaseStaffServiceImplTest {
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private CcdiBaseStaffServiceImpl service;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CcdiBaseStaffMapper baseStaffMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ICcdiBaseStaffImportService importAsyncService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ICcdiAssetInfoService assetInfoService;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void insertBaseStaff_shouldPersistEmployeeThenReplaceAssetsUsingEmployeeIdCard() {
|
||||||
|
CcdiBaseStaffAddDTO addDTO = new CcdiBaseStaffAddDTO();
|
||||||
|
addDTO.setStaffId(1001L);
|
||||||
|
addDTO.setName("张三");
|
||||||
|
addDTO.setDeptId(10L);
|
||||||
|
addDTO.setIdCard("320101199001010011");
|
||||||
|
addDTO.setPhone("13812345678");
|
||||||
|
addDTO.setStatus("0");
|
||||||
|
addDTO.setAssetInfoList(List.of(
|
||||||
|
buildAssetDto("320101199001010011", "房产"),
|
||||||
|
buildAssetDto("320101199201010022", "车辆")
|
||||||
|
));
|
||||||
|
|
||||||
|
when(baseStaffMapper.selectById(1001L)).thenReturn(null);
|
||||||
|
when(baseStaffMapper.selectCount(any())).thenReturn(0L);
|
||||||
|
when(baseStaffMapper.insert(any(CcdiBaseStaff.class))).thenReturn(1);
|
||||||
|
|
||||||
|
int result = service.insertBaseStaff(addDTO);
|
||||||
|
|
||||||
|
assertEquals(1, result);
|
||||||
|
ArgumentCaptor<List<CcdiAssetInfoDTO>> captor = ArgumentCaptor.forClass(List.class);
|
||||||
|
verify(assetInfoService).replaceByFamilyId(eq("320101199001010011"), captor.capture());
|
||||||
|
List<CcdiAssetInfoDTO> savedAssets = captor.getValue();
|
||||||
|
assertEquals(2, savedAssets.size());
|
||||||
|
assertEquals("320101199001010011", savedAssets.get(0).getPersonId());
|
||||||
|
assertEquals("320101199201010022", savedAssets.get(1).getPersonId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void updateBaseStaff_shouldReplaceAssetsForCurrentIdCard() {
|
||||||
|
CcdiBaseStaff existing = new CcdiBaseStaff();
|
||||||
|
existing.setStaffId(1001L);
|
||||||
|
existing.setIdCard("320101199001010011");
|
||||||
|
|
||||||
|
CcdiBaseStaffEditDTO editDTO = new CcdiBaseStaffEditDTO();
|
||||||
|
editDTO.setStaffId(1001L);
|
||||||
|
editDTO.setDeptId(10L);
|
||||||
|
editDTO.setName("张三");
|
||||||
|
editDTO.setIdCard("320101199001010011");
|
||||||
|
editDTO.setPhone("13812345678");
|
||||||
|
editDTO.setStatus("0");
|
||||||
|
editDTO.setAssetInfoList(List.of(buildAssetDto("320101199201010022", "车辆")));
|
||||||
|
|
||||||
|
when(baseStaffMapper.selectById(1001L)).thenReturn(existing);
|
||||||
|
when(baseStaffMapper.selectCount(any())).thenReturn(0L);
|
||||||
|
when(baseStaffMapper.updateById(any(CcdiBaseStaff.class))).thenReturn(1);
|
||||||
|
|
||||||
|
int result = service.updateBaseStaff(editDTO);
|
||||||
|
|
||||||
|
assertEquals(1, result);
|
||||||
|
verify(assetInfoService, never()).deleteByFamilyId("320101199001010011");
|
||||||
|
verify(assetInfoService).replaceByFamilyId("320101199001010011", editDTO.getAssetInfoList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void updateBaseStaff_shouldDeleteOldAssetsWhenIdCardChanges() {
|
||||||
|
CcdiBaseStaff existing = new CcdiBaseStaff();
|
||||||
|
existing.setStaffId(1001L);
|
||||||
|
existing.setIdCard("320101199001010099");
|
||||||
|
|
||||||
|
CcdiBaseStaffEditDTO editDTO = new CcdiBaseStaffEditDTO();
|
||||||
|
editDTO.setStaffId(1001L);
|
||||||
|
editDTO.setDeptId(10L);
|
||||||
|
editDTO.setName("张三");
|
||||||
|
editDTO.setIdCard("320101199001010011");
|
||||||
|
editDTO.setPhone("13812345678");
|
||||||
|
editDTO.setStatus("0");
|
||||||
|
editDTO.setAssetInfoList(List.of(buildAssetDto("320101199201010022", "车辆")));
|
||||||
|
|
||||||
|
when(baseStaffMapper.selectById(1001L)).thenReturn(existing);
|
||||||
|
when(baseStaffMapper.selectCount(any())).thenReturn(0L);
|
||||||
|
when(baseStaffMapper.updateById(any(CcdiBaseStaff.class))).thenReturn(1);
|
||||||
|
|
||||||
|
service.updateBaseStaff(editDTO);
|
||||||
|
|
||||||
|
verify(assetInfoService).deleteByFamilyId("320101199001010099");
|
||||||
|
verify(assetInfoService).replaceByFamilyId("320101199001010011", editDTO.getAssetInfoList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void selectBaseStaffById_shouldReturnAssetInfoList() {
|
||||||
|
CcdiBaseStaff staff = new CcdiBaseStaff();
|
||||||
|
staff.setStaffId(1001L);
|
||||||
|
staff.setName("张三");
|
||||||
|
staff.setIdCard("320101199001010011");
|
||||||
|
staff.setStatus("0");
|
||||||
|
|
||||||
|
CcdiAssetInfo assetInfo = new CcdiAssetInfo();
|
||||||
|
assetInfo.setFamilyId("320101199001010011");
|
||||||
|
assetInfo.setPersonId("320101199201010022");
|
||||||
|
assetInfo.setAssetMainType("车辆");
|
||||||
|
assetInfo.setAssetSubType("小汽车");
|
||||||
|
assetInfo.setAssetName("家庭车辆");
|
||||||
|
assetInfo.setCurrentValue(new BigDecimal("100000.00"));
|
||||||
|
assetInfo.setAssetStatus("正常");
|
||||||
|
|
||||||
|
when(baseStaffMapper.selectById(1001L)).thenReturn(staff);
|
||||||
|
when(assetInfoService.selectByFamilyId("320101199001010011")).thenReturn(List.of(assetInfo));
|
||||||
|
|
||||||
|
CcdiBaseStaffVO result = service.selectBaseStaffById(1001L);
|
||||||
|
|
||||||
|
assertNotNull(result.getAssetInfoList());
|
||||||
|
assertEquals(1, result.getAssetInfoList().size());
|
||||||
|
assertEquals("320101199201010022", result.getAssetInfoList().get(0).getPersonId());
|
||||||
|
assertEquals("车辆", result.getAssetInfoList().get(0).getAssetMainType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void deleteBaseStaffByIds_shouldCascadeDeleteAssets() {
|
||||||
|
CcdiBaseStaff staff1 = new CcdiBaseStaff();
|
||||||
|
staff1.setStaffId(1001L);
|
||||||
|
staff1.setIdCard("320101199001010011");
|
||||||
|
CcdiBaseStaff staff2 = new CcdiBaseStaff();
|
||||||
|
staff2.setStaffId(1002L);
|
||||||
|
staff2.setIdCard("320101199001010022");
|
||||||
|
|
||||||
|
when(baseStaffMapper.selectBatchIds(List.of(1001L, 1002L))).thenReturn(List.of(staff1, staff2));
|
||||||
|
when(baseStaffMapper.deleteBatchIds(List.of(1001L, 1002L))).thenReturn(2);
|
||||||
|
|
||||||
|
int result = service.deleteBaseStaffByIds(new Long[]{1001L, 1002L});
|
||||||
|
|
||||||
|
assertEquals(2, result);
|
||||||
|
verify(assetInfoService).deleteByFamilyIds(List.of("320101199001010011", "320101199001010022"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private CcdiAssetInfoDTO buildAssetDto(String personId, String assetMainType) {
|
||||||
|
CcdiAssetInfoDTO dto = new CcdiAssetInfoDTO();
|
||||||
|
dto.setPersonId(personId);
|
||||||
|
dto.setAssetMainType(assetMainType);
|
||||||
|
dto.setAssetSubType(assetMainType + "小类");
|
||||||
|
dto.setAssetName(assetMainType + "名称");
|
||||||
|
dto.setCurrentValue(new BigDecimal("100.00"));
|
||||||
|
dto.setAssetStatus("正常");
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user