diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaSalaryMasterController.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaSalaryMasterController.java index 13eef0f..6d41273 100644 --- a/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaSalaryMasterController.java +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaSalaryMasterController.java @@ -19,7 +19,9 @@ import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.oa.domain.vo.OaSalaryMasterVo; import com.ruoyi.oa.domain.bo.OaSalaryMasterBo; +import com.ruoyi.oa.domain.dto.BatchInsertSalaryStringDto; import com.ruoyi.oa.service.IOaSalaryMasterService; +import com.ruoyi.oa.utils.SalaryStringConverter; import com.ruoyi.common.core.page.TableDataInfo; /** @@ -109,4 +111,19 @@ public class OaSalaryMasterController extends BaseController { return toAjax(iOaSalaryMasterService.batchInsertDetails(bo)); } + /** + * 批量插入工资明细(处理字符串数字格式) + * 专门用于处理前端传递的驼峰命名但数字为字符串格式的数据 + * + * @param requestDto 字符串格式的请求DTO + */ + @Log(title = "批量插入工资明细", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/batchInsertDetailsWithStringConvert") + public R batchInsertDetailsWithStringConvert(@Validated @RequestBody BatchInsertSalaryStringDto requestDto) { + // 将字符串DTO转换为后端BO + OaSalaryMasterBo bo = SalaryStringConverter.convertToMasterBo(requestDto); + return toAjax(iOaSalaryMasterService.batchInsertDetails(bo)); + } + } diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/dto/BatchInsertSalaryStringDto.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/dto/BatchInsertSalaryStringDto.java new file mode 100644 index 0000000..81b2d98 --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/dto/BatchInsertSalaryStringDto.java @@ -0,0 +1,66 @@ +package com.ruoyi.oa.domain.dto; + +import lombok.Data; +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotBlank; +import java.util.List; + +/** + * 批量插入工资明细请求DTO - 处理驼峰命名的字符串数字格式 + * + * @author Joshi + * @date 2025-09-08 + */ +@Data +public class BatchInsertSalaryStringDto { + + /** + * 单位名称 + */ + @NotBlank(message = "单位名称不能为空") + private String unitName; + + /** + * 工资所属期间,格式如:2025-8 + */ + @NotBlank(message = "工资期间不能为空") + private String salaryPeriod; + + /** + * 总经理审批状态或姓名 + */ + private String gmApproval; + + /** + * 财务审核状态或姓名 + */ + private String financeAudit; + + /** + * 出纳姓名 + */ + private String cashier; + + /** + * 部门主管姓名 + */ + private String deptManager; + + /** + * 经办人姓名 + */ + private String operator; + + /** + * 备注 + */ + private String remark; + + /** + * 工资明细列表 + */ + @Valid + @NotEmpty(message = "明细列表不能为空") + private List salaryDetailList; +} \ No newline at end of file diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/dto/SalaryDetailStringDto.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/dto/SalaryDetailStringDto.java new file mode 100644 index 0000000..6c92c5a --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/dto/SalaryDetailStringDto.java @@ -0,0 +1,377 @@ +package com.ruoyi.oa.domain.dto; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; +import java.math.BigDecimal; + +/** + * 工资明细字符串DTO - 用于接收前端字符串格式的数字字段 + * + * @author Joshi + * @date 2025-09-08 + */ +@Data +public class SalaryDetailStringDto { + + /** + * 主键,自增 + */ + private Long detailId; + + /** + * 关联主表ID + */ + private Long mainId; + + /** + * 序号(字符串格式) + */ + private String serialNumber; + + /** + * 部门 + */ + private String dept; + + /** + * 员工姓名 + */ + private String name; + + /** + * 基本工资(字符串格式) + */ + private String basicSalary; + + /** + * 岗位工资(字符串格式) + */ + private String postSalary; + + /** + * 餐补(字符串格式) + */ + private String mealAllowance; + + /** + * 住房补贴(字符串格式) + */ + private String housingAllowance; + + /** + * 公交补贴(字符串格式) + */ + private String busAllowance; + + /** + * 出差天数(字符串格式) + */ + private String businessDaysOther; + + /** + * 出差补助(字符串格式) + */ + private String businessAllowance; + + /** + * 社保补助(字符串格式) + */ + private String socialSecurityAllowance; + + /** + * 加班时长(字符串格式) + */ + private String overtimeHours; + + /** + * 加班标准(字符串格式) + */ + private String overtimeRate; + + /** + * 加班工资总计(字符串格式) + */ + private String overtimeTotal; + + /** + * 出勤天数(字符串格式) + */ + private String businessDays; + + /** + * 请假扣款(字符串格式) + */ + private String leaveDeduction; + + /** + * 其他扣款(字符串格式) + */ + private String otherDeduction; + + /** + * 应发工资(字符串格式) + */ + private String grossSalary; + + /** + * 个人缴纳养老保险(字符串格式) + */ + private String personalPension; + + /** + * 个人缴纳医疗保险(字符串格式) + */ + private String personalMedical; + + /** + * 个人缴纳失业保险(字符串格式) + */ + private String personalUnemployment; + + /** + * 个人缴纳大病医疗(字符串格式) + */ + private String personalBigMedical; + + /** + * 个人缴纳住房公积金(字符串格式) + */ + private String personalHousingFund; + + /** + * 个人所得税(字符串格式) + */ + private String personalTax; + + /** + * 实发工资(字符串格式) + */ + private String netSalary; + + /** + * 企业缴纳养老保险(字符串格式) + */ + private String enterprisePension; + + /** + * 企业缴纳医疗保险(字符串格式) + */ + private String enterpriseMedical; + + /** + * 企业缴纳工伤保险(字符串格式) + */ + private String enterpriseInjury; + + /** + * 企业缴纳失业保险(字符串格式) + */ + private String enterpriseUnemployment; + + /** + * 企业缴纳生育保险(字符串格式) + */ + private String enterpriseMaternity; + + /** + * 企业缴纳住房公积金(字符串格式) + */ + private String enterpriseHousingFund; + + /** + * 企业缴纳大病医疗(字符串格式) + */ + private String enterpriseBigMedical; + + /** + * 单位总支出(字符串格式) + */ + private String unitTotalExpense; + + /** + * 备注 + */ + private String remark; + + // 辅助方法:安全地将字符串转换为BigDecimal + @JsonIgnore + private BigDecimal parseDecimal(String value) { + if (value == null || value.trim().isEmpty()) { + return BigDecimal.ZERO; + } + try { + return new BigDecimal(value.trim()); + } catch (NumberFormatException e) { + return BigDecimal.ZERO; + } + } + + // 辅助方法:安全地将字符串转换为Long + @JsonIgnore + private Long parseLong(String value) { + if (value == null || value.trim().isEmpty()) { + return 0L; + } + try { + return Long.parseLong(value.trim()); + } catch (NumberFormatException e) { + return 0L; + } + } + + // 转换方法,返回数值类型 + @JsonIgnore + public Long getSerialNumberAsLong() { + return parseLong(serialNumber); + } + + @JsonIgnore + public BigDecimal getBasicSalaryAsDecimal() { + return parseDecimal(basicSalary); + } + + @JsonIgnore + public BigDecimal getPostSalaryAsDecimal() { + return parseDecimal(postSalary); + } + + @JsonIgnore + public BigDecimal getMealAllowanceAsDecimal() { + return parseDecimal(mealAllowance); + } + + @JsonIgnore + public BigDecimal getHousingAllowanceAsDecimal() { + return parseDecimal(housingAllowance); + } + + @JsonIgnore + public BigDecimal getBusAllowanceAsDecimal() { + return parseDecimal(busAllowance); + } + + @JsonIgnore + public Long getBusinessDaysOtherAsLong() { + return parseLong(businessDaysOther); + } + + @JsonIgnore + public BigDecimal getBusinessAllowanceAsDecimal() { + return parseDecimal(businessAllowance); + } + + @JsonIgnore + public BigDecimal getSocialSecurityAllowanceAsDecimal() { + return parseDecimal(socialSecurityAllowance); + } + + @JsonIgnore + public BigDecimal getOvertimeHoursAsDecimal() { + return parseDecimal(overtimeHours); + } + + @JsonIgnore + public BigDecimal getOvertimeRateAsDecimal() { + return parseDecimal(overtimeRate); + } + + @JsonIgnore + public BigDecimal getOvertimeTotalAsDecimal() { + return parseDecimal(overtimeTotal); + } + + @JsonIgnore + public Long getBusinessDaysAsLong() { + return parseLong(businessDays); + } + + @JsonIgnore + public BigDecimal getLeaveDeductionAsDecimal() { + return parseDecimal(leaveDeduction); + } + + @JsonIgnore + public BigDecimal getOtherDeductionAsDecimal() { + return parseDecimal(otherDeduction); + } + + @JsonIgnore + public BigDecimal getGrossSalaryAsDecimal() { + return parseDecimal(grossSalary); + } + + @JsonIgnore + public BigDecimal getPersonalPensionAsDecimal() { + return parseDecimal(personalPension); + } + + @JsonIgnore + public BigDecimal getPersonalMedicalAsDecimal() { + return parseDecimal(personalMedical); + } + + @JsonIgnore + public BigDecimal getPersonalUnemploymentAsDecimal() { + return parseDecimal(personalUnemployment); + } + + @JsonIgnore + public BigDecimal getPersonalBigMedicalAsDecimal() { + return parseDecimal(personalBigMedical); + } + + @JsonIgnore + public BigDecimal getPersonalHousingFundAsDecimal() { + return parseDecimal(personalHousingFund); + } + + @JsonIgnore + public BigDecimal getPersonalTaxAsDecimal() { + return parseDecimal(personalTax); + } + + @JsonIgnore + public BigDecimal getNetSalaryAsDecimal() { + return parseDecimal(netSalary); + } + + @JsonIgnore + public BigDecimal getEnterprisePensionAsDecimal() { + return parseDecimal(enterprisePension); + } + + @JsonIgnore + public BigDecimal getEnterpriseMedicalAsDecimal() { + return parseDecimal(enterpriseMedical); + } + + @JsonIgnore + public BigDecimal getEnterpriseInjuryAsDecimal() { + return parseDecimal(enterpriseInjury); + } + + @JsonIgnore + public BigDecimal getEnterpriseUnemploymentAsDecimal() { + return parseDecimal(enterpriseUnemployment); + } + + @JsonIgnore + public BigDecimal getEnterpriseMaternityAsDecimal() { + return parseDecimal(enterpriseMaternity); + } + + @JsonIgnore + public BigDecimal getEnterpriseHousingFundAsDecimal() { + return parseDecimal(enterpriseHousingFund); + } + + @JsonIgnore + public BigDecimal getEnterpriseBigMedicalAsDecimal() { + return parseDecimal(enterpriseBigMedical); + } + + @JsonIgnore + public BigDecimal getUnitTotalExpenseAsDecimal() { + return parseDecimal(unitTotalExpense); + } +} \ No newline at end of file diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/utils/SalaryStringConverter.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/utils/SalaryStringConverter.java new file mode 100644 index 0000000..7a78c03 --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/utils/SalaryStringConverter.java @@ -0,0 +1,115 @@ +package com.ruoyi.oa.utils; + +import com.ruoyi.oa.domain.bo.OaSalaryDetailBo; +import com.ruoyi.oa.domain.bo.OaSalaryMasterBo; +import com.ruoyi.oa.domain.dto.BatchInsertSalaryStringDto; +import com.ruoyi.oa.domain.dto.SalaryDetailStringDto; +import cn.hutool.core.collection.CollUtil; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 工资字符串数据转换工具类 + * + * @author Joshi + * @date 2025-09-08 + */ +public class SalaryStringConverter { + + /** + * 将字符串格式的请求DTO转换为后端BO对象 + * + * @param requestDto 字符串格式的请求DTO + * @return 后端BO对象 + */ + public static OaSalaryMasterBo convertToMasterBo(BatchInsertSalaryStringDto requestDto) { + if (requestDto == null) { + return null; + } + + OaSalaryMasterBo masterBo = new OaSalaryMasterBo(); + masterBo.setUnitName(requestDto.getUnitName()); + masterBo.setSalaryPeriod(requestDto.getSalaryPeriod()); + masterBo.setGmApproval(requestDto.getGmApproval()); + masterBo.setFinanceAudit(requestDto.getFinanceAudit()); + masterBo.setCashier(requestDto.getCashier()); + masterBo.setDeptManager(requestDto.getDeptManager()); + masterBo.setOperator(requestDto.getOperator()); + masterBo.setRemark(requestDto.getRemark()); + + // 转换明细列表 + if (CollUtil.isNotEmpty(requestDto.getSalaryDetailList())) { + List detailBoList = requestDto.getSalaryDetailList().stream() + .map(SalaryStringConverter::convertToDetailBo) + .collect(Collectors.toList()); + masterBo.setSalaryDetailList(detailBoList); + } + + return masterBo; + } + + /** + * 将字符串格式的明细DTO转换为后端明细BO对象 + * + * @param stringDto 字符串格式的明细DTO + * @return 后端明细BO对象 + */ + public static OaSalaryDetailBo convertToDetailBo(SalaryDetailStringDto stringDto) { + if (stringDto == null) { + return null; + } + + OaSalaryDetailBo detailBo = new OaSalaryDetailBo(); + + // 基本信息 + detailBo.setDetailId(stringDto.getDetailId()); + detailBo.setMainId(stringDto.getMainId()); + detailBo.setSerialNumber(stringDto.getSerialNumberAsLong()); + detailBo.setDept(stringDto.getDept()); + detailBo.setName(stringDto.getName()); + detailBo.setRemark(stringDto.getRemark()); + + // 工资项目 - 使用转换方法 + detailBo.setBasicSalary(stringDto.getBasicSalaryAsDecimal()); + detailBo.setPostSalary(stringDto.getPostSalaryAsDecimal()); + detailBo.setMealAllowance(stringDto.getMealAllowanceAsDecimal()); + detailBo.setHousingAllowance(stringDto.getHousingAllowanceAsDecimal()); + detailBo.setBusAllowance(stringDto.getBusAllowanceAsDecimal()); + detailBo.setBusinessDaysOther(stringDto.getBusinessDaysOtherAsLong()); + detailBo.setBusinessAllowance(stringDto.getBusinessAllowanceAsDecimal()); + detailBo.setSocialSecurityAllowance(stringDto.getSocialSecurityAllowanceAsDecimal()); + + // 加班相关 + detailBo.setOvertimeHours(stringDto.getOvertimeHoursAsDecimal()); + detailBo.setOvertimeRate(stringDto.getOvertimeRateAsDecimal()); + detailBo.setOvertimeTotal(stringDto.getOvertimeTotalAsDecimal()); + detailBo.setBusinessDays(stringDto.getBusinessDaysAsLong()); + + // 扣款项目 + detailBo.setLeaveDeduction(stringDto.getLeaveDeductionAsDecimal()); + detailBo.setOtherDeduction(stringDto.getOtherDeductionAsDecimal()); + detailBo.setGrossSalary(stringDto.getGrossSalaryAsDecimal()); + + // 个人缴费 + detailBo.setPersonalPension(stringDto.getPersonalPensionAsDecimal()); + detailBo.setPersonalMedical(stringDto.getPersonalMedicalAsDecimal()); + detailBo.setPersonalUnemployment(stringDto.getPersonalUnemploymentAsDecimal()); + detailBo.setPersonalBigMedical(stringDto.getPersonalBigMedicalAsDecimal()); + detailBo.setPersonalHousingFund(stringDto.getPersonalHousingFundAsDecimal()); + detailBo.setPersonalTax(stringDto.getPersonalTaxAsDecimal()); + detailBo.setNetSalary(stringDto.getNetSalaryAsDecimal()); + + // 企业缴费 + detailBo.setEnterprisePension(stringDto.getEnterprisePensionAsDecimal()); + detailBo.setEnterpriseMedical(stringDto.getEnterpriseMedicalAsDecimal()); + detailBo.setEnterpriseInjury(stringDto.getEnterpriseInjuryAsDecimal()); + detailBo.setEnterpriseUnemployment(stringDto.getEnterpriseUnemploymentAsDecimal()); + detailBo.setEnterpriseMaternity(stringDto.getEnterpriseMaternityAsDecimal()); + detailBo.setEnterpriseHousingFund(stringDto.getEnterpriseHousingFundAsDecimal()); + detailBo.setEnterpriseBigMedical(stringDto.getEnterpriseBigMedicalAsDecimal()); + detailBo.setUnitTotalExpense(stringDto.getUnitTotalExpenseAsDecimal()); + + return detailBo; + } +} \ No newline at end of file