zhoulisky пре 10 месеци
родитељ
комит
1810155666
32 измењених фајлова са 1588 додато и 41 уклоњено
  1. 12 0
      kd-service-api/kd-scientific-api/src/main/java/org/sky/scientific/pojo/dto/AttendanceDto.java
  2. 21 0
      kd-service-api/kd-scientific-api/src/main/java/org/sky/scientific/pojo/dto/XmGoodsDTO.java
  3. 59 0
      kd-service-api/kd-scientific-api/src/main/java/org/sky/scientific/pojo/entity/XmDirectCostEntity.java
  4. 77 0
      kd-service-api/kd-scientific-api/src/main/java/org/sky/scientific/pojo/entity/XmGoodsEntity.java
  5. 74 0
      kd-service-api/kd-scientific-api/src/main/java/org/sky/scientific/pojo/entity/XmLeaseEntity.java
  6. 21 0
      kd-service-api/kd-scientific-api/src/main/java/org/sky/scientific/pojo/vo/XmGoodsVO.java
  7. 13 7
      kd-service/kd-scientific/src/main/java/org/sky/scientific/controller/AttendanceController.java
  8. 84 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/controller/XmDirectCostController.java
  9. 90 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/controller/XmGoodsController.java
  10. 84 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/controller/XmLeaseController.java
  11. 51 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/excel/XmDirectCostExcel.java
  12. 69 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/excel/XmGoodsExcel.java
  13. 67 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/excel/XmLeaseExcel.java
  14. 1 1
      kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/AttendanceMapper.java
  15. 2 2
      kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/AttendanceMapper.xml
  16. 45 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmDirectCostMapper.java
  17. 53 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmDirectCostMapper.xml
  18. 46 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmGoodsMapper.java
  19. 62 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmGoodsMapper.xml
  20. 45 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmLeaseMapper.java
  21. 62 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmLeaseMapper.xml
  22. 2 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmMapper.java
  23. 11 3
      kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmMapper.xml
  24. 7 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/service/IAttendanceService.java
  25. 58 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/service/IXmDirectCostService.java
  26. 60 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/service/IXmGoodsService.java
  27. 58 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/service/IXmLeaseService.java
  28. 60 18
      kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/AttendanceServiceImpl.java
  29. 15 10
      kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/CgQtServiceImpl.java
  30. 91 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/XmDirectCostServiceImpl.java
  31. 97 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/XmGoodsServiceImpl.java
  32. 91 0
      kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/XmLeaseServiceImpl.java

+ 12 - 0
kd-service-api/kd-scientific-api/src/main/java/org/sky/scientific/pojo/dto/AttendanceDto.java

@@ -1,12 +1,19 @@
 package org.sky.scientific.pojo.dto;
 
 import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
 import lombok.Data;
+import org.sky.scientific.pojo.vo.DailyAttendance;
+
+import java.util.List;
 
 @Data
 public class AttendanceDto {
 
 	@Schema(description = "研发人员id")
+	@NotNull(message = "请选择研发人员")
 	private Long technicianId;
 
 	@Schema(description = "姓名")
@@ -22,6 +29,11 @@ public class AttendanceDto {
 	private String personnelType;
 
 	@Schema(description = "年月")
+	@NotBlank(message = "参数yearAndMonth不能为空")
 	private String yearAndMonth;
 
+	@NotEmpty(message = "请填写考勤明细")
+	@Schema(description = "考勤明细")
+	private List<DailyAttendance> dailyAttendances;
+
 }

+ 21 - 0
kd-service-api/kd-scientific-api/src/main/java/org/sky/scientific/pojo/dto/XmGoodsDTO.java

@@ -0,0 +1,21 @@
+
+package org.sky.scientific.pojo.dto;
+
+import org.sky.scientific.pojo.entity.XmGoodsEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.io.Serial;
+
+/**
+ * 研发项目物料清单 数据传输对象实体类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class XmGoodsDTO extends XmGoodsEntity {
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+}

+ 59 - 0
kd-service-api/kd-scientific-api/src/main/java/org/sky/scientific/pojo/entity/XmDirectCostEntity.java

@@ -0,0 +1,59 @@
+
+package org.sky.scientific.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.sky.core.tenant.mp.TenantEntity;
+import org.sky.core.tool.utils.DateUtil;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serial;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 研发项目直投费用清单 实体类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@Data
+@TableName("kd_xm_direct_cost")
+@Schema(description = "XmDirectCost对象")
+@EqualsAndHashCode(callSuper = true)
+public class XmDirectCostEntity extends TenantEntity {
+
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "所属年月,如:202505")
+	private String yearAndMonth;
+
+	@Schema(description = "日期,如:2025-02-15")
+	@DateTimeFormat(pattern = DateUtil.PATTERN_DATE)
+	@JsonFormat(pattern = DateUtil.PATTERN_DATE)
+	private Date useDate;
+
+	@Schema(description = "研发项目id")
+	@NotNull(message = "请选择研发项目")
+	private Long xmId;
+
+	@Schema(description = "研发项目名称")
+	@TableField(exist = false)
+	private String xmmc;
+
+	@Schema(description = "研发项目编号")
+	@TableField(exist = false)
+	private String xmbh;
+
+	@Schema(description = "直投费用类型")
+	private String type;
+
+	@Schema(description = "金额")
+	private BigDecimal amount;
+}

+ 77 - 0
kd-service-api/kd-scientific-api/src/main/java/org/sky/scientific/pojo/entity/XmGoodsEntity.java

@@ -0,0 +1,77 @@
+
+package org.sky.scientific.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.sky.core.tenant.mp.TenantEntity;
+import org.sky.core.tool.utils.DateUtil;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serial;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 研发项目物料清单 实体类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@Data
+@TableName("kd_xm_goods")
+@Schema(description = "XmGoods对象")
+@EqualsAndHashCode(callSuper = true)
+public class XmGoodsEntity extends TenantEntity {
+
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "所属年月,如:202505")
+	private String yearAndMonth;
+
+	@Schema(description = "领用日期,如:20250215")
+	@DateTimeFormat(pattern = DateUtil.PATTERN_DATE)
+	@JsonFormat(pattern = DateUtil.PATTERN_DATE)
+	private Date useDate;
+
+	@Schema(description = "研发项目id")
+	@NotNull(message = "请选择研发项目")
+	private Long xmId;
+
+	@Schema(description = "研发项目名称")
+	@TableField(exist = false)
+	private String xmmc;
+
+	@Schema(description = "研发项目编号")
+	@TableField(exist = false)
+	private String xmbh;
+
+	@Schema(description = "类型")
+	private String type;
+
+	@Schema(description = "编号")
+	private String code;
+
+	@Schema(description = "名称")
+	private String name;
+
+	@Schema(description = "规格型号")
+	private String model;
+
+	@Schema(description = "单位")
+	private String unit;
+
+	@Schema(description = "单价(元)")
+	private BigDecimal unitPrice;
+
+	@Schema(description = "领用数量")
+	private Integer useQuantity;
+
+	@Schema(description = "金额")
+	private BigDecimal amount;
+}

+ 74 - 0
kd-service-api/kd-scientific-api/src/main/java/org/sky/scientific/pojo/entity/XmLeaseEntity.java

@@ -0,0 +1,74 @@
+
+package org.sky.scientific.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.sky.core.tenant.mp.TenantEntity;
+import org.sky.core.tool.utils.DateUtil;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serial;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 研发项目租赁清单 实体类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@Data
+@TableName("kd_xm_lease")
+@Schema(description = "XmLease对象")
+@EqualsAndHashCode(callSuper = true)
+public class XmLeaseEntity extends TenantEntity {
+
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	@Schema(description = "所属年月,如:202505")
+	private String yearAndMonth;
+
+	@Schema(description = "租赁日期,如:2025-02-15")
+	@DateTimeFormat(pattern = DateUtil.PATTERN_DATE)
+	@JsonFormat(pattern = DateUtil.PATTERN_DATE)
+	private Date leaseDate;
+
+	@Schema(description = "研发项目id")
+	@NotNull(message = "请选择研发项目")
+	private Long xmId;
+
+	@Schema(description = "研发项目名称")
+	@TableField(exist = false)
+	private String xmmc;
+
+	@Schema(description = "研发项目编号")
+	@TableField(exist = false)
+	private String xmbh;
+
+	@Schema(description = "类型")
+	private String type;
+
+	@Schema(description = "名称")
+	private String name;
+
+	@Schema(description = "规格型号")
+	private String model;
+
+	@Schema(description = "使用天数或使用量")
+	private Integer quantity;
+
+	@Schema(description = "单价(元)")
+	private BigDecimal unitPrice;
+
+	@Schema(description = "总价(不含税)")
+	private BigDecimal amount;
+
+	@Schema(description = "备注")
+	private String remark;
+}

+ 21 - 0
kd-service-api/kd-scientific-api/src/main/java/org/sky/scientific/pojo/vo/XmGoodsVO.java

@@ -0,0 +1,21 @@
+
+package org.sky.scientific.pojo.vo;
+
+import org.sky.scientific.pojo.entity.XmGoodsEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.io.Serial;
+
+/**
+ * 研发项目物料清单 视图实体类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class XmGoodsVO extends XmGoodsEntity {
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+}

+ 13 - 7
kd-service/kd-scientific/src/main/java/org/sky/scientific/controller/AttendanceController.java

@@ -12,7 +12,6 @@ import org.sky.core.mp.support.Condition;
 import org.sky.core.mp.support.Query;
 import org.sky.core.tool.api.R;
 import org.sky.scientific.pojo.dto.AttendanceDto;
-import org.sky.scientific.pojo.entity.AttendanceEntity;
 import org.sky.scientific.pojo.vo.AttendanceVO;
 import org.sky.scientific.service.IAttendanceService;
 import org.springframework.web.bind.annotation.*;
@@ -34,15 +33,22 @@ public class AttendanceController extends KdController {
 		return R.data(service.selectAttendancePage(attendance, Condition.getPage(query)));
 	}
 
-	@PostMapping("/submit")
-	@ApiOperationSupport(order = 2)
-	@Operation(summary = "每月考勤信息-新增或修改")
-	public R submit(@Valid @RequestBody AttendanceEntity attendance) {
-		return R.status(service.submit(attendance));
+//	@PostMapping("/submit")
+//	@ApiOperationSupport(order = 2)
+//	@Operation(summary = "每月考勤信息-新增或修改")
+//	public R submit(@Valid @RequestBody AttendanceEntity attendance) {
+//		return R.status(service.submit(attendance));
+//	}
+
+	@PostMapping("/submit/batch")
+	@ApiOperationSupport(order = 3)
+	@Operation(summary = "每月考勤信息-批量新增或修改")
+	public R submit(@Valid @RequestBody AttendanceDto attendance) {
+		return R.status(service.batchSubmit(attendance));
 	}
 
 	@PostMapping("/import")
-	@ApiOperationSupport(order = 3)
+	@ApiOperationSupport(order = 4)
 	@Operation(summary = "每月考勤信息-导入", description = "传入excel")
 	public R importAttendance(MultipartFile file,String yearAndMonth) {
 		service.importAttendance(file, yearAndMonth);

+ 84 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/controller/XmDirectCostController.java

@@ -0,0 +1,84 @@
+
+package org.sky.scientific.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import lombok.AllArgsConstructor;
+import org.sky.core.boot.ctrl.KdController;
+import org.sky.core.excel.util.ExcelUtil;
+import org.sky.core.mp.support.Condition;
+import org.sky.core.mp.support.Query;
+import org.sky.core.secure.KdUser;
+import org.sky.core.secure.annotation.IsAdmin;
+import org.sky.core.tool.api.R;
+import org.sky.core.tool.utils.DateUtil;
+import org.sky.core.tool.utils.Func;
+import org.sky.scientific.excel.XmDirectCostExcel;
+import org.sky.scientific.pojo.entity.XmDirectCostEntity;
+import org.sky.scientific.service.IXmDirectCostService;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 研发项目租赁清单 控制器
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/direct-cost")
+@Tag(name = "研发项目-直接投入费用")
+public class XmDirectCostController extends KdController {
+
+	private final IXmDirectCostService service;
+
+	@GetMapping("/page")
+	@ApiOperationSupport(order = 3)
+	@Operation(summary = "直接投入费用-基本信息台账-分页")
+	public R<IPage<XmDirectCostEntity>> page(XmDirectCostEntity dto, Query query) {
+		IPage<XmDirectCostEntity> pages = service.selectXmDirectCostPage(Condition.getPage(query), dto);
+		return R.data(pages);
+	}
+
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 6)
+	@Operation(summary = "直接投入费用-基本信息台账-新增或修改")
+	public R submit(@Valid @RequestBody XmDirectCostEntity entity) {
+		return R.status(service.submit(entity));
+	}
+
+	@PostMapping("/import")
+	@ApiOperationSupport(order = 4)
+	@Operation(summary = "直接投入费用-基本信息台账-导入")
+	public R importXmLease(MultipartFile file, String yearAndMonth) {
+		return R.data(service.importXmDirectCost(file, yearAndMonth));
+	}
+
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 7)
+	@Operation(summary = "直接投入费用-基本信息台账-批量删除", description = "传入ids")
+	public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(service.physicalDeleteByIds(Func.toLongList(ids)));
+	}
+
+	@IsAdmin
+	@GetMapping("/export")
+	@ApiOperationSupport(order = 9)
+	@Operation(summary = "直接投入费用-基本信息台账-导出数据")
+	public void export(@Parameter(hidden = true) @RequestParam Map<String, Object> map, KdUser kdUser, HttpServletResponse response) {
+		QueryWrapper<XmDirectCostEntity> queryWrapper = Condition.getQueryWrapper(map, XmDirectCostEntity.class);
+		List<XmDirectCostExcel> list = service.exportXmDirectCost(queryWrapper);
+		ExcelUtil.export(response, "直接投入费用-基本信息台账" + DateUtil.time(), "直接投入费用-基本信息台账", list, XmDirectCostExcel.class);
+	}
+
+}

+ 90 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/controller/XmGoodsController.java

@@ -0,0 +1,90 @@
+
+package org.sky.scientific.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import lombok.AllArgsConstructor;
+import org.sky.core.boot.ctrl.KdController;
+import org.sky.core.excel.util.ExcelUtil;
+import org.sky.core.mp.support.Condition;
+import org.sky.core.mp.support.Query;
+import org.sky.core.secure.KdUser;
+import org.sky.core.secure.annotation.IsAdmin;
+import org.sky.core.tool.api.R;
+import org.sky.core.tool.utils.DateUtil;
+import org.sky.core.tool.utils.Func;
+import org.sky.scientific.excel.XmGoodsExcel;
+import org.sky.scientific.pojo.dto.XmGoodsDTO;
+import org.sky.scientific.pojo.entity.XmGoodsEntity;
+import org.sky.scientific.pojo.vo.XmGoodsVO;
+import org.sky.scientific.service.IXmGoodsService;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 物料清单 控制器
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/goods")
+@Tag(name = "研发项目-物料管理")
+public class XmGoodsController extends KdController {
+
+	private final IXmGoodsService service;
+
+	@GetMapping("/page")
+	@ApiOperationSupport(order = 3)
+	@Operation(summary = "研发领料燃料动力明细清单-分页", description = "传入xmGoods")
+	public R<IPage<XmGoodsVO>> page(XmGoodsDTO dto, Query query) {
+		IPage<XmGoodsVO> pages = service.selectXmGoodsPage(Condition.getPage(query), dto);
+		return R.data(pages);
+	}
+
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 6)
+	@Operation(summary = "研发领料燃料动力明细清单-新增或修改", description = "传入xmGoods")
+	public R submit(@Valid @RequestBody XmGoodsEntity xmGoods) {
+		return R.status(service.submit(xmGoods));
+	}
+
+	@PostMapping("/import")
+	@ApiOperationSupport(order = 4)
+	@Operation(summary = "研发领料燃料动力明细清单-导入", description = "传入excel")
+	public R importXmGoods(MultipartFile file, String yearAndMonth) {
+		return R.data(service.importXmGoods(file, yearAndMonth));
+	}
+
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 7)
+	@Operation(summary = "研发领料燃料动力明细清单-批量删除", description = "传入ids")
+	public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(service.physicalDeleteByIds(Func.toLongList(ids)));
+	}
+
+	@IsAdmin
+	@GetMapping("/export")
+	@ApiOperationSupport(order = 9)
+	@Operation(summary = "研发领料燃料动力明细清单-导出数据", description = "传入xmGoods")
+	public void exportXmGoods(@Parameter(hidden = true) @RequestParam Map<String, Object> xmGoods, KdUser kdUser, HttpServletResponse response) {
+		QueryWrapper<XmGoodsEntity> queryWrapper = Condition.getQueryWrapper(xmGoods, XmGoodsEntity.class);
+		//if (!AuthUtil.isAdministrator()) {
+		//	queryWrapper.lambda().eq(XmGoods::getTenantId, kdUser.getTenantId());
+		//}
+		//queryWrapper.lambda().eq(XmGoodsEntity::getIsDeleted, KdConstant.DB_NOT_DELETED);
+		List<XmGoodsExcel> list = service.exportXmGoods(queryWrapper);
+		ExcelUtil.export(response, "研发项目物料清单数据" + DateUtil.time(), "研发项目物料清单数据表", list, XmGoodsExcel.class);
+	}
+
+}

+ 84 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/controller/XmLeaseController.java

@@ -0,0 +1,84 @@
+
+package org.sky.scientific.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import lombok.AllArgsConstructor;
+import org.sky.core.boot.ctrl.KdController;
+import org.sky.core.excel.util.ExcelUtil;
+import org.sky.core.mp.support.Condition;
+import org.sky.core.mp.support.Query;
+import org.sky.core.secure.KdUser;
+import org.sky.core.secure.annotation.IsAdmin;
+import org.sky.core.tool.api.R;
+import org.sky.core.tool.utils.DateUtil;
+import org.sky.core.tool.utils.Func;
+import org.sky.scientific.excel.XmLeaseExcel;
+import org.sky.scientific.pojo.entity.XmLeaseEntity;
+import org.sky.scientific.service.IXmLeaseService;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 研发项目租赁清单 控制器
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/lease")
+@Tag(name = "研发项目-租赁管理")
+public class XmLeaseController extends KdController {
+
+	private final IXmLeaseService service;
+
+	@GetMapping("/page")
+	@ApiOperationSupport(order = 3)
+	@Operation(summary = "研发租赁资产使用记录和费用汇总表-分页")
+	public R<IPage<XmLeaseEntity>> page(XmLeaseEntity dto, Query query) {
+		IPage<XmLeaseEntity> pages = service.selectXmLeasePage(Condition.getPage(query), dto);
+		return R.data(pages);
+	}
+
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 6)
+	@Operation(summary = "研发租赁资产使用记录和费用汇总表-新增或修改")
+	public R submit(@Valid @RequestBody XmLeaseEntity xmLease) {
+		return R.status(service.submit(xmLease));
+	}
+
+	@PostMapping("/import")
+	@ApiOperationSupport(order = 4)
+	@Operation(summary = "研发租赁资产使用记录和费用汇总表-导入")
+	public R importXmLease(MultipartFile file, String yearAndMonth) {
+		return R.data(service.importXmLease(file, yearAndMonth));
+	}
+
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 7)
+	@Operation(summary = "研发租赁资产使用记录和费用汇总表-批量删除", description = "传入ids")
+	public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(service.physicalDeleteByIds(Func.toLongList(ids)));
+	}
+
+	@IsAdmin
+	@GetMapping("/export")
+	@ApiOperationSupport(order = 9)
+	@Operation(summary = "研发租赁资产使用记录和费用汇总表-导出数据")
+	public void export(@Parameter(hidden = true) @RequestParam Map<String, Object> xmLease, KdUser kdUser, HttpServletResponse response) {
+		QueryWrapper<XmLeaseEntity> queryWrapper = Condition.getQueryWrapper(xmLease, XmLeaseEntity.class);
+		List<XmLeaseExcel> list = service.exportXmLease(queryWrapper);
+		ExcelUtil.export(response, "研发租赁资产使用记录和费用汇总表" + DateUtil.time(), "研发租赁资产使用记录和费用汇总表", list, XmLeaseExcel.class);
+	}
+
+}

+ 51 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/excel/XmDirectCostExcel.java

@@ -0,0 +1,51 @@
+
+package org.sky.scientific.excel;
+
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.alibaba.excel.annotation.write.style.ContentRowHeight;
+import com.alibaba.excel.annotation.write.style.HeadRowHeight;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.sky.core.tool.utils.DateUtil;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+
+/**
+ * 研发项目直接投入费用 Excel实体类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@Data
+@ColumnWidth(25)
+@HeadRowHeight(20)
+@ContentRowHeight(18)
+public class XmDirectCostExcel implements Serializable {
+
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	@ExcelProperty("日期")
+	@DateTimeFormat(pattern = DateUtil.PATTERN_DATE)
+	@JsonFormat(pattern = DateUtil.PATTERN_DATE)
+	private Date useDate;
+
+	@ExcelProperty("研发项目编号")
+	private String xmbh;
+
+	@ExcelProperty("研发项目名称")
+	private String xmmc;
+
+ 	@ExcelProperty("直投费用类型")
+	private String type;
+
+	@ExcelProperty("金额(元)")
+	private BigDecimal amount;
+}

+ 69 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/excel/XmGoodsExcel.java

@@ -0,0 +1,69 @@
+
+package org.sky.scientific.excel;
+
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.alibaba.excel.annotation.write.style.ContentRowHeight;
+import com.alibaba.excel.annotation.write.style.HeadRowHeight;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.sky.core.tool.utils.DateUtil;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+
+/**
+ * 研发项目物料清单 Excel实体类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@Data
+@ColumnWidth(25)
+@HeadRowHeight(20)
+@ContentRowHeight(18)
+public class XmGoodsExcel implements Serializable {
+
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	@ExcelProperty("领用日期")
+	@DateTimeFormat(pattern = DateUtil.PATTERN_DATE)
+	@JsonFormat(pattern = DateUtil.PATTERN_DATE)
+	private Date useDate;
+
+	@ExcelProperty("研发项目名称")
+	private String xmmc;
+
+	@ExcelProperty("研发项目编号")
+	private String xmbh;
+
+ 	@ExcelProperty("类型")
+	private String type;
+
+	@ExcelProperty("物资编号")
+	private String code;
+
+	@ExcelProperty("物资名称")
+	private String name;
+
+	@ExcelProperty("型号规格")
+	private String model;
+
+	@ExcelProperty("单位")
+	private String unit;
+
+	@ExcelProperty("单价(元)")
+	private BigDecimal unitPrice;
+
+	@ExcelProperty("领用数量")
+	private Integer useQuantity;
+
+	@ExcelProperty("金额(元)")
+	private BigDecimal amount;
+}

+ 67 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/excel/XmLeaseExcel.java

@@ -0,0 +1,67 @@
+
+package org.sky.scientific.excel;
+
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.alibaba.excel.annotation.write.style.ContentRowHeight;
+import com.alibaba.excel.annotation.write.style.HeadRowHeight;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.sky.core.tool.utils.DateUtil;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+
+/**
+ * 研发项目物料清单 Excel实体类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@Data
+@ColumnWidth(25)
+@HeadRowHeight(20)
+@ContentRowHeight(18)
+public class XmLeaseExcel implements Serializable {
+
+	@Serial
+	private static final long serialVersionUID = 1L;
+
+	@ExcelProperty("租赁日期")
+	@DateTimeFormat(pattern = DateUtil.PATTERN_DATE)
+	@JsonFormat(pattern = DateUtil.PATTERN_DATE)
+	private Date leaseDate;
+
+	@ExcelProperty("研发项目编号")
+	private String xmbh;
+
+	@ExcelProperty("研发项目名称")
+	private String xmmc;
+
+ 	@ExcelProperty("租赁资产类型")
+	private String type;
+
+	@ExcelProperty("租赁资产名称")
+	private String name;
+
+	@ExcelProperty("型号规格")
+	private String model;
+
+	@Schema(description = "使用天数或使用量")
+	private Integer quantity;
+
+	@Schema(description = "单价(元)")
+	private BigDecimal unitPrice;
+
+	@Schema(description = "总价(不含税)")
+	private BigDecimal amount;
+
+	@Schema(description = "备注")
+	private String remark;
+}

+ 1 - 1
kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/AttendanceMapper.java

@@ -25,7 +25,7 @@ public interface AttendanceMapper extends BaseMapper<AttendanceEntity> {
 
 	Long selectPrimaryKeyByTechnicianIdAndWorkDate(@Param("technicianId") Long technicianId, @Param("workDate") String workDate);
 
-	int batchSave(List<AttendanceEntity> list);
+	int batchInsert(List<AttendanceEntity> list);
 
 	List<DailyAttendance> selectDailyAttendanceByTechnicianAndMonth(@Param("technicianId") Long technicianId, @Param("yearAndMonth") String yearAndMonth);
 

+ 2 - 2
kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/AttendanceMapper.xml

@@ -62,7 +62,7 @@
     </select>
 
     <update id="batchUpdate" parameterType="java.util.List">
-        <foreach collection="list" item="record" open="" separator=";" close="">
+        <foreach collection="list" item="record" separator=";">
             update kd_attendance_records
             set work_hours = #{record.workHours}
             where id = #{record.id}
@@ -73,7 +73,7 @@
         select id from kd_attendance_records where technician_id = #{technicianId} and work_date = #{workDate}
     </select>
 
-    <insert id="batchSave" parameterType="java.util.List">
+    <insert id="batchInsert" parameterType="java.util.List">
         insert into kd_attendance_records(tenant_id,technician_id,work_date,work_hours,create_user,create_dept)
         VALUES
         <foreach collection="list" item="a" separator=",">

+ 45 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmDirectCostMapper.java

@@ -0,0 +1,45 @@
+
+package org.sky.scientific.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.ibatis.annotations.Param;
+import org.sky.scientific.excel.XmDirectCostExcel;
+import org.sky.scientific.pojo.entity.XmDirectCostEntity;
+
+import java.util.List;
+
+/**
+ * 研发项目直投费用清单 Mapper 接口
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+public interface XmDirectCostMapper extends BaseMapper<XmDirectCostEntity> {
+
+	/**
+	 * 自定义分页
+	 *
+	 * @param page 分页参数
+	 * @param xmDirectCost 查询参数
+	 * @return List<XmDirectCostEntity>
+	 */
+	List<XmDirectCostEntity> selectXmDirectCostPage(IPage page, @Param("ew") XmDirectCostEntity xmDirectCost);
+
+
+	/**
+	 * 获取导出数据
+	 *
+	 * @param queryWrapper 查询条件
+	 * @return List<XmLeaseExcel>
+	 */
+	List<XmDirectCostExcel> exportXmDirectCost(@Param("ew") Wrapper<XmDirectCostEntity> queryWrapper);
+
+	/**
+	 * 批量删除
+	 * @param ids
+     * @return
+	 */
+	int physicalDeleteByIds(List<Long> ids);
+}

+ 53 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmDirectCostMapper.xml

@@ -0,0 +1,53 @@
+<?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="org.sky.scientific.mapper.XmDirectCostMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="ResultMap" type="org.sky.scientific.pojo.entity.XmDirectCostEntity">
+        <result column="id" property="id"/>
+        <result column="tenant_id" property="tenantId"/>
+        <result column="year_and_month" property="yearAndMonth"/>
+        <result column="use_date" property="useDate"/>
+        <result column="xm_id" property="xmId"/>
+        <result column="xmmc" property="xmmc"/>
+        <result column="xmbh" property="xmbh"/>
+        <result column="type" property="type"/>
+        <result column="amount" property="amount"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_dept" property="createDept"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+    </resultMap>
+
+    <delete id="physicalDeleteByIds">
+        Delete FROM kd_xm_direct_cost
+        WHERE id IN
+        <foreach item="item" index="index" collection="list" separator="," close=")" open="(">
+            #{item}
+        </foreach>
+    </delete>
+
+    <select id="selectXmDirectCostPage" resultMap="ResultMap">
+        select kxl.*, xm.xmmc, xm.xmbh
+        from kd_xm_direct_cost kxl
+        left join kd_xm xm on xm.id = kxl.xm_id
+        where kxl.is_deleted = 0 and kxl.year_and_month = #{ew.yearAndMonth}
+        <if test="ew.xmmc!=null and ew.xmbh!=''">and xm.xmmc like concat('%',#{ew.xmmc},'%')</if>
+        <if test="ew.xmbh!=null and ew.xmbh!=''">and xm.xmbh like concat('%',#{ew.xmbh},'%')</if>
+        <if test="ew.type!=null and ew.type!=''">and xm.type = #{ew.type}</if>
+    </select>
+
+    <select id="exportXmDirectCost" resultType="org.sky.scientific.excel.XmDirectCostExcel">
+        select kxl.*, xm.xmmc, xm.xmbh
+        from kd_xm_direct_cost kxl
+        left join kd_xm xm on xm.id = kxl.xm_id
+        where kxl.is_deleted = 0 and kxl.year_and_month = #{ew.yearAndMonth}
+        <if test="ew.xmmc!=null and ew.xmbh!=''">and xm.xmmc like concat('%',#{ew.xmmc},'%')</if>
+        <if test="ew.xmbh!=null and ew.xmbh!=''">and xm.xmbh like concat('%',#{ew.xmbh},'%')</if>
+        <if test="ew.type!=null and ew.type!=''">and xm.type = #{ew.type}</if>
+    </select>
+
+</mapper>

+ 46 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmGoodsMapper.java

@@ -0,0 +1,46 @@
+
+package org.sky.scientific.mapper;
+
+import org.sky.scientific.pojo.dto.XmGoodsDTO;
+import org.sky.scientific.pojo.entity.XmGoodsEntity;
+import org.sky.scientific.pojo.vo.XmGoodsVO;
+import org.sky.scientific.excel.XmGoodsExcel;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.ibatis.annotations.Param;
+import java.util.List;
+
+/**
+ * 研发项目物料清单 Mapper 接口
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+public interface XmGoodsMapper extends BaseMapper<XmGoodsEntity> {
+
+	/**
+	 * 自定义分页
+	 *
+	 * @param page 分页参数
+	 * @param xmGoods 查询参数
+	 * @return List<XmGoodsVO>
+	 */
+	List<XmGoodsVO> selectXmGoodsPage(IPage page, @Param("ew") XmGoodsDTO xmGoods);
+
+
+	/**
+	 * 获取导出数据
+	 *
+	 * @param queryWrapper 查询条件
+	 * @return List<XmGoodsExcel>
+	 */
+	List<XmGoodsExcel> exportXmGoods(@Param("ew") Wrapper<XmGoodsEntity> queryWrapper);
+
+	/**
+	 * 批量删除
+	 * @param ids
+	 * @return
+	 */
+	int physicalDeleteByIds(List<Long> ids);
+}

+ 62 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmGoodsMapper.xml

@@ -0,0 +1,62 @@
+<?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="org.sky.scientific.mapper.XmGoodsMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="ResultMap" type="org.sky.scientific.pojo.entity.XmGoodsEntity">
+        <result column="id" property="id"/>
+        <result column="tenant_id" property="tenantId"/>
+        <result column="year_and_month" property="yearAndMonth"/>
+        <result column="use_date" property="useDate"/>
+        <result column="xm_id" property="xmId"/>
+        <result column="xmmc" property="xmmc"/>
+        <result column="xmbh" property="xmbh"/>
+        <result column="type" property="type"/>
+        <result column="code" property="code"/>
+        <result column="name" property="name"/>
+        <result column="model" property="model"/>
+        <result column="unit" property="unit"/>
+        <result column="unit_price" property="unitPrice"/>
+        <result column="use_quantity" property="useQuantity"/>
+        <result column="amount" property="amount"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_dept" property="createDept"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+    </resultMap>
+
+    <resultMap id="ResultVoMap" type="org.sky.scientific.pojo.vo.XmGoodsVO" extends="ResultMap">
+
+    </resultMap>
+
+    <delete id="physicalDeleteByIds">
+        Delete FROM kd_xm_goods
+        WHERE id IN
+        <foreach item="item" index="index" collection="list" separator="," close=")" open="(">
+            #{item}
+        </foreach>
+    </delete>
+
+
+    <select id="selectXmGoodsPage" resultMap="ResultVoMap">
+        select kxg.*, xm.xmmc, xm.xmbh
+        from kd_xm_goods kxg
+        left join kd_xm xm on xm.id = kxg.xm_id
+        where kxg.is_deleted = 0 and kxg.year_and_month = #{ew.yearAndMonth}
+        <if test="ew.xmmc!=null and ew.xmbh!=''">and xm.xmmc like concat('%',#{ew.xmmc},'%')</if>
+        <if test="ew.xmbh!=null and ew.xmbh!=''">and xm.xmbh like concat('%',#{ew.xmbh},'%')</if>
+        <if test="ew.type!=null and ew.type!=''">and xm.type = #{ew.type}</if>
+        <if test="ew.code!=null and ew.code!=''">and kxg.code like concat('%',#{ew.code},'%')</if>
+        <if test="ew.name!=null and ew.name!=''">and kxg.name like concat('%',#{ew.name},'%')</if>
+        <if test="ew.model!=null and ew.model!=''">and kxg.model like concat('%',#{ew.model},'%')</if>
+    </select>
+
+
+    <select id="exportXmGoods" resultType="org.sky.scientific.excel.XmGoodsExcel">
+        SELECT * FROM kd_xm_goods ${ew.customSqlSegment}
+    </select>
+
+</mapper>

+ 45 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmLeaseMapper.java

@@ -0,0 +1,45 @@
+
+package org.sky.scientific.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.ibatis.annotations.Param;
+import org.sky.scientific.excel.XmLeaseExcel;
+import org.sky.scientific.pojo.entity.XmLeaseEntity;
+
+import java.util.List;
+
+/**
+ * 研发项目租赁清单 Mapper 接口
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+public interface XmLeaseMapper extends BaseMapper<XmLeaseEntity> {
+
+	/**
+	 * 自定义分页
+	 *
+	 * @param page 分页参数
+	 * @param xmLease 查询参数
+	 * @return List<XmLeaseEntity>
+	 */
+	List<XmLeaseEntity> selectXmLeasePage(IPage page, @Param("ew") XmLeaseEntity xmLease);
+
+
+	/**
+	 * 获取导出数据
+	 *
+	 * @param queryWrapper 查询条件
+	 * @return List<XmLeaseExcel>
+	 */
+	List<XmLeaseExcel> exportXmLease(@Param("ew") Wrapper<XmLeaseEntity> queryWrapper);
+
+	/**
+	 * 批量删除
+	 * @param ids
+     * @return
+	 */
+	int physicalDeleteByIds(List<Long> ids);
+}

+ 62 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmLeaseMapper.xml

@@ -0,0 +1,62 @@
+<?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="org.sky.scientific.mapper.XmLeaseMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="ResultMap" type="org.sky.scientific.pojo.entity.XmLeaseEntity">
+        <result column="id" property="id"/>
+        <result column="tenant_id" property="tenantId"/>
+        <result column="year_and_month" property="yearAndMonth"/>
+        <result column="lease_date" property="leaseDate"/>
+        <result column="xm_id" property="xmId"/>
+        <result column="xmmc" property="xmmc"/>
+        <result column="xmbh" property="xmbh"/>
+        <result column="type" property="type"/>
+        <result column="name" property="name"/>
+        <result column="model" property="model"/>
+        <result column="unit_price" property="unitPrice"/>
+        <result column="quantity" property="quantity"/>
+        <result column="amount" property="amount"/>
+        <result column="remark" property="remark"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_dept" property="createDept"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+    </resultMap>
+
+    <delete id="physicalDeleteByIds">
+        Delete FROM kd_xm_lease
+        WHERE id IN
+        <foreach item="item" index="index" collection="list" separator="," close=")" open="(">
+            #{item}
+        </foreach>
+    </delete>
+
+    <select id="selectXmLeasePage" resultMap="ResultMap">
+        select kxl.*, xm.xmmc, xm.xmbh
+        from kd_xm_lease kxl
+        left join kd_xm xm on xm.id = kxl.xm_id
+        where kxl.is_deleted = 0 and kxl.year_and_month = #{ew.yearAndMonth}
+        <if test="ew.xmmc!=null and ew.xmbh!=''">and xm.xmmc like concat('%',#{ew.xmmc},'%')</if>
+        <if test="ew.xmbh!=null and ew.xmbh!=''">and xm.xmbh like concat('%',#{ew.xmbh},'%')</if>
+        <if test="ew.type!=null and ew.type!=''">and xm.type = #{ew.type}</if>
+        <if test="ew.name!=null and ew.name!=''">and kxl.name like concat('%',#{ew.name},'%')</if>
+        <if test="ew.model!=null and ew.model!=''">and kxl.model like concat('%',#{ew.model},'%')</if>
+    </select>
+
+    <select id="exportXmLease" resultType="org.sky.scientific.excel.XmLeaseExcel">
+        select kxl.*, xm.xmmc, xm.xmbh
+        from kd_xm_lease kxl
+        left join kd_xm xm on xm.id = kxl.xm_id
+        where kxl.is_deleted = 0 and kxl.year_and_month = #{ew.yearAndMonth}
+        <if test="ew.xmmc!=null and ew.xmbh!=''">and xm.xmmc like concat('%',#{ew.xmmc},'%')</if>
+        <if test="ew.xmbh!=null and ew.xmbh!=''">and xm.xmbh like concat('%',#{ew.xmbh},'%')</if>
+        <if test="ew.type!=null and ew.type!=''">and xm.type = #{ew.type}</if>
+        <if test="ew.name!=null and ew.name!=''">and kxl.name like concat('%',#{ew.name},'%')</if>
+        <if test="ew.model!=null and ew.model!=''">and kxl.model like concat('%',#{ew.model},'%')</if>
+    </select>
+
+</mapper>

+ 2 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmMapper.java

@@ -66,4 +66,6 @@ public interface XmMapper extends BaseMapper<XmEntity> {
 	XmVO selectByXmIdAndYearMonth(Map map);
 
 	XmVO selectByXmId(Long xmId);
+
+	Long getXmIdByXmmcOrXmbh(@Param("yearAndMonth") String yearAndMonth,@Param("xmmc") String xmmc, @Param("xmbh") String xmbh);
 }

+ 11 - 3
kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmMapper.xml

@@ -39,16 +39,17 @@
         SELECT
             xm.id,
             xm.XMBH,
-            COALESCE( (SELECT bgrz.BGHDZ FROM kd_xm_bgrz bgrz WHERE bgrz.XM_ID = xm.id AND bgrz.ZDMC = 'xmmc' AND DATE_FORMAT(bgrz.BGSXSJ, '%Y%m') <![CDATA[<=]]> #{ew.yearAndMonth} ORDER BY bgrz.BGSXSJ DESC LIMIT 1), xm.XMMC ) AS XMMC
+            COALESCE( (SELECT bgrz.BGHDZ FROM kd_xm_bgrz bgrz WHERE bgrz.XM_ID = xm.id AND bgrz.ZDMC = 'xmmc' AND DATE_FORMAT(bgrz.BGSXSJ, '%Y%m') <![CDATA[<=]]> #{ew.yearAndMonth} ORDER BY bgrz.BGSXSJ DESC LIMIT 1), xm.XMMC ) AS XMMC,
+            xmkssj,
+            xmjssj
         FROM kd_xm xm
-        WHERE xm.is_deleted = 0
+        WHERE xm.is_deleted = 0 and DATE_FORMAT(xmkssj, '%Y%m') <![CDATA[<=]]> #{ew.yearAndMonth} and DATE_FORMAT(xmjssj, '%Y%m') >= #{ew.yearAndMonth}
     </select>
 
     <select id="exportXm" resultType="org.sky.scientific.excel.XmExcel">
         SELECT * FROM kd_xm ${ew.customSqlSegment}
     </select>
 
-
     <select id="summaryPage" resultType="org.sky.scientific.pojo.vo.XmSummary">
         SELECT xm.id, xm.XMBH,
         COALESCE( (SELECT bgrz.BGHDZ FROM kd_xm_bgrz bgrz WHERE bgrz.XM_ID = xm.id AND bgrz.ZDMC = 'xmmc' AND DATE_FORMAT(bgrz.BGSXSJ, '%Y%m') <![CDATA[<=]]> #{ew.yearAndMonth} ORDER BY bgrz.BGSXSJ DESC LIMIT 1), xm.XMMC ) AS XMMC,
@@ -127,4 +128,11 @@
         FROM kd_xm xm
         where id = #{xmId}
     </select>
+    <select id="getXmIdByXmmcOrXmbh" resultType="java.lang.Long">
+        SELECT id
+        FROM kd_xm xm
+        where xm.is_deleted = 0
+        <if test="xmmc!=null and xmmc!=''">and xmmc = #{xmmc}</if>
+        <if test="xmbh!=null and xmbh!=''">and xmbh = #{xmbh}</if>
+    </select>
 </mapper>

+ 7 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/IAttendanceService.java

@@ -37,4 +37,11 @@ public interface IAttendanceService extends BaseService<AttendanceEntity> {
 	 * @param yearAndMonth 年月
 	 */
 	void importAttendance(MultipartFile file, String yearAndMonth);
+
+	/**
+	 * 研发人员考勤表-批量新增或修改
+	 * @param attendance
+	 * @return
+	 */
+	boolean batchSubmit(AttendanceDto attendance);
 }

+ 58 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/IXmDirectCostService.java

@@ -0,0 +1,58 @@
+
+package org.sky.scientific.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.sky.core.mp.base.BaseService;
+import org.sky.scientific.excel.XmDirectCostExcel;
+import org.sky.scientific.pojo.entity.XmDirectCostEntity;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * 研发项目直投费用清单 服务类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+public interface IXmDirectCostService extends BaseService<XmDirectCostEntity> {
+	/**
+	 * 自定义分页
+	 *
+	 * @param page 分页参数
+	 * @param dto 查询参数
+	 * @return IPage<XmDirectCostEntity>
+	 */
+	IPage<XmDirectCostEntity> selectXmDirectCostPage(IPage<XmDirectCostEntity> page, XmDirectCostEntity dto);
+
+
+	/**
+	 * 导出数据
+	 *
+	 * @param queryWrapper 查询条件
+	 * @return List<XmDirectCostExcel>
+	 */
+	List<XmDirectCostExcel> exportXmDirectCost(Wrapper<XmDirectCostEntity> queryWrapper);
+
+	/**
+     * 导入数据
+	 * @param file
+     * @param yearAndMonth
+	 */
+	boolean importXmDirectCost(MultipartFile file, String yearAndMonth);
+
+	/**
+	 * 删除
+	 * @param ids
+	 * @return
+	 */
+	boolean physicalDeleteByIds(List<Long> ids);
+
+	/**
+     * 修改或新增
+	 * @param xmDirectCost
+     * @return
+	 */
+	boolean submit(XmDirectCostEntity xmDirectCost);
+}

+ 60 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/IXmGoodsService.java

@@ -0,0 +1,60 @@
+
+package org.sky.scientific.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import org.sky.scientific.pojo.dto.XmGoodsDTO;
+import org.sky.scientific.pojo.entity.XmGoodsEntity;
+import org.sky.scientific.pojo.vo.XmGoodsVO;
+import org.sky.scientific.excel.XmGoodsExcel;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.sky.core.mp.base.BaseService;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * 研发项目物料清单 服务类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+public interface IXmGoodsService extends BaseService<XmGoodsEntity> {
+	/**
+	 * 自定义分页
+	 *
+	 * @param page 分页参数
+	 * @param dto 查询参数
+	 * @return IPage<XmGoodsVO>
+	 */
+	IPage<XmGoodsVO> selectXmGoodsPage(IPage<XmGoodsVO> page, XmGoodsDTO dto);
+
+
+	/**
+	 * 导出数据
+	 *
+	 * @param queryWrapper 查询条件
+	 * @return List<XmGoodsExcel>
+	 */
+	List<XmGoodsExcel> exportXmGoods(Wrapper<XmGoodsEntity> queryWrapper);
+
+	/**
+	 * 导入数据
+	 * @param file
+	 * @param yearAndMonth
+	 */
+	boolean importXmGoods(MultipartFile file, String yearAndMonth);
+
+	/**
+	 * 删除
+	 * @param ids
+	 * @return
+	 */
+	boolean physicalDeleteByIds(List<Long> ids);
+
+	/**
+	 * 修改或新增
+	 * @param xmGoods
+	 * @return
+	 */
+	boolean submit(XmGoodsEntity xmGoods);
+}

+ 58 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/IXmLeaseService.java

@@ -0,0 +1,58 @@
+
+package org.sky.scientific.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.sky.core.mp.base.BaseService;
+import org.sky.scientific.excel.XmLeaseExcel;
+import org.sky.scientific.pojo.entity.XmLeaseEntity;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * 研发项目租赁清单 服务类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+public interface IXmLeaseService extends BaseService<XmLeaseEntity> {
+	/**
+	 * 自定义分页
+	 *
+	 * @param page 分页参数
+	 * @param dto 查询参数
+	 * @return IPage<XmGoodsVO>
+	 */
+	IPage<XmLeaseEntity> selectXmLeasePage(IPage<XmLeaseEntity> page, XmLeaseEntity dto);
+
+
+	/**
+	 * 导出数据
+	 *
+	 * @param queryWrapper 查询条件
+	 * @return List<XmGoodsExcel>
+	 */
+	List<XmLeaseExcel> exportXmLease(Wrapper<XmLeaseEntity> queryWrapper);
+
+	/**
+     * 导入数据
+	 * @param file
+     * @param yearAndMonth
+	 */
+	boolean importXmLease(MultipartFile file, String yearAndMonth);
+
+	/**
+	 * 删除
+	 * @param ids
+	 * @return
+	 */
+	boolean physicalDeleteByIds(List<Long> ids);
+
+	/**
+     * 修改或新增
+	 * @param xmGoods
+     * @return
+	 */
+	boolean submit(XmLeaseEntity xmLease);
+}

+ 60 - 18
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/AttendanceServiceImpl.java

@@ -45,7 +45,7 @@ public class AttendanceServiceImpl extends BaseServiceImpl<AttendanceMapper, Att
 
 	@Override
 	public IPage<AttendanceVO> selectAttendancePage(AttendanceDto attendance, IPage<AttendanceVO> page) {
-		if(StringUtil.isBlank(attendance.getYearAndMonth())) {
+		if (StringUtil.isBlank(attendance.getYearAndMonth())) {
 			throw new ServiceException("参数yearAndMonth不能为空");
 		}
 		List<AttendanceVO> list = baseMapper.selectAttendancePage(page, attendance);
@@ -108,15 +108,13 @@ public class AttendanceServiceImpl extends BaseServiceImpl<AttendanceMapper, Att
 			if (technicianId == null) {
 				throw new ServiceException("序号为[" + record.getSerialNumber() + "]的工号和者身份证都不存在");
 			}
-//			List<AttendanceEntity> dataByTechnicianMonthly = dbList.stream().filter(e -> e.getTechnicianId().equals(technicianId) && Objects.equals(e.getWorkDate().substring(0, 6), yearAndMonth)).toList();
 			List<AttendanceEntity> dataByTechnicianMonthly = dbList.stream().filter(e -> e.getTechnicianId().equals(technicianId)).toList();
 			for (DailyAttendance dailyAttendance : record.getDailyAttendances()) {
 
 				List<Long> primaryKeyList = dataByTechnicianMonthly.stream().filter(e -> Objects.equals(e.getWorkDate(), dailyAttendance.getWorkDate())).map(AttendanceEntity::getId).toList();
 				Long primaryKey = CollectionUtil.isEmpty(primaryKeyList) ? null : primaryKeyList.get(0);
-//					baseMapper.selectPrimaryKeyByTechnicianIdAndWorkDate(technicianId, dailyAttendance.getDate());
+				AttendanceEntity entity = new AttendanceEntity();
 				if (primaryKey == null) {
-					AttendanceEntity entity = new AttendanceEntity();
 					entity.setTechnicianId(technicianId);
 					entity.setWorkDate(dailyAttendance.getWorkDate());
 					entity.setWorkHours(dailyAttendance.getWorkHours());
@@ -125,28 +123,72 @@ public class AttendanceServiceImpl extends BaseServiceImpl<AttendanceMapper, Att
 					entity.setCreateDept(Func.toLong(SecureUtil.getDeptId()));
 					insertList.add(entity);
 				} else {
-					AttendanceEntity entity = new AttendanceEntity();
 					entity.setId(primaryKey);
 					entity.setWorkHours(dailyAttendance.getWorkHours());
 					updateList.add(entity);
 				}
-				if (insertList.size() % batchCount == 0) {
-					int insertCount = baseMapper.batchSave(insertList);
-					insertList.clear();
+				if (!insertList.isEmpty() && insertList.size() % batchCount == 0) {
+					int insertCount = baseMapper.batchInsert(insertList);
+					if (insertCount == batchCount) {
+						insertList.clear();
+					}
+
+				}
+				if (!insertList.isEmpty() && updateList.size() % batchCount == 0) {
+					int updateCount = baseMapper.batchUpdate(updateList);
+					if (updateCount == batchCount) {
+						updateList.clear();
+					}
 				}
-//				if (updateList.size() % batchCount == 0) {
-//					int updateCount = baseMapper.batchUpdate(updateList);
-//					if (updateCount == batchCount) {
-//						updateList.clear();
-//					}
-//				}
 			}
 		}
 		if (!insertList.isEmpty()) {
-			baseMapper.batchSave(insertList);
+			baseMapper.batchInsert(insertList);
+		}
+		if (!updateList.isEmpty()) {
+			baseMapper.batchUpdate(updateList);
+		}
+	}
+
+	@Override
+	public boolean batchSubmit(AttendanceDto attendance) {
+		List<AttendanceEntity> dbList = baseMapper.selectByYearAndMonth(attendance.getYearAndMonth());
+		List<AttendanceEntity> dataByTechnicianMonthly = dbList.stream().filter(e -> e.getTechnicianId().equals(attendance.getTechnicianId())).toList();
+
+		//需要新增的,以便后续批量新增
+		List<AttendanceEntity> insertList = new ArrayList<>();
+		//需要更新的,以便后续批量修改
+		List<AttendanceEntity> updateList = new ArrayList<>();
+
+		for (DailyAttendance dailyAttendance : attendance.getDailyAttendances()) {
+
+			List<Long> primaryKeyList = dataByTechnicianMonthly.stream().filter(e -> Objects.equals(e.getWorkDate(), dailyAttendance.getWorkDate())).map(AttendanceEntity::getId).toList();
+			Long primaryKey = CollectionUtil.isEmpty(primaryKeyList) ? null : primaryKeyList.get(0);
+			AttendanceEntity entity = new AttendanceEntity();
+			if (primaryKey == null) {
+				entity.setTechnicianId(attendance.getTechnicianId());
+				entity.setWorkDate(dailyAttendance.getWorkDate());
+				entity.setWorkHours(dailyAttendance.getWorkHours());
+				entity.setTenantId(SecureUtil.getTenantId());
+				entity.setCreateUser(SecureUtil.getUserId());
+				entity.setCreateDept(Func.toLong(SecureUtil.getDeptId()));
+				insertList.add(entity);
+			} else {
+				entity.setId(primaryKey);
+				entity.setWorkHours(dailyAttendance.getWorkHours());
+				updateList.add(entity);
+			}
+
+		}
+
+		if (!insertList.isEmpty()) {
+			baseMapper.batchInsert(insertList);
+			insertList.clear();
+		}
+		if (!updateList.isEmpty()) {
+			baseMapper.batchUpdate(updateList);
+			updateList.clear();
 		}
-//		if (!updateList.isEmpty()) {
-//			baseMapper.batchUpdate(updateList);
-//		}
+		return true;
 	}
 }

+ 15 - 10
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/CgQtServiceImpl.java

@@ -9,6 +9,7 @@ import org.sky.core.log.exception.ServiceException;
 import org.sky.core.mp.base.BaseServiceImpl;
 import org.sky.core.tool.utils.BeanUtil;
 import org.sky.core.tool.utils.CollectionUtil;
+import org.sky.core.tool.utils.StringUtil;
 import org.sky.scientific.excel.CgQtExcel;
 import org.sky.scientific.mapper.CgQtMapper;
 import org.sky.scientific.mapper.XmMapper;
@@ -46,27 +47,31 @@ public class CgQtServiceImpl extends BaseServiceImpl<CgQtMapper, CgQtEntity> imp
 	}
 
 	@Transactional
-    @Override
-    public void importQt(MultipartFile file) {
+	@Override
+	public void importQt(MultipartFile file) {
 		List<CgQtExcel> data = ExcelUtil.read(file, 0, 2, CgQtExcel.class);
-		if(CollectionUtil.isEmpty(data)){
+		if (CollectionUtil.isEmpty(data)) {
 			throw new ServiceException("未能从模板中读取数据,请检查模板格式是否正确");
 		}
 		for (CgQtExcel excel : data) {
 			CgQtEntity qtDTO = Objects.requireNonNull(BeanUtil.copyProperties(excel, CgQtDTO.class));
 			this.save(qtDTO);
 		}
-    }
+	}
 
 	@Override
 	public boolean save(CgQtEntity cgQt) {
-		if (cgQt.getXmbh() != null) {
-			XmEntity dbXm = xmMapper.selectOne(Wrappers.<XmEntity>lambdaQuery().eq(XmEntity::getXmbh, cgQt.getXmbh()));
-			if(dbXm==null){
-				throw new ServiceException("项目编号["+cgQt.getXmbh()+"]不存在,导入失败,请检查数据");
+		if (!StringUtil.isAllBlank(cgQt.getXmmc(), cgQt.getXmbh())) {
+			XmEntity dbXm = xmMapper.selectOne(Wrappers.<XmEntity>lambdaQuery()
+				.eq(XmEntity::getXmbh, cgQt.getXmbh())
+				.or()
+				.eq(XmEntity::getXmmc, cgQt.getXmmc()));
+			if (dbXm == null) {
+				throw new ServiceException("研发项目不存在,导入失败,请检查数据");
 			}
-			cgQt.setXmId(dbXm != null ? dbXm.getId() : null);
-			cgQt.setXmmc(dbXm != null ? dbXm.getXmmc() : null);
+			cgQt.setXmId(dbXm.getId());
+			cgQt.setXmmc(dbXm.getXmmc());
+			cgQt.setXmbh(dbXm.getXmbh());
 		}
 		return super.save(cgQt);
 	}

+ 91 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/XmDirectCostServiceImpl.java

@@ -0,0 +1,91 @@
+
+package org.sky.scientific.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import jakarta.annotation.Resource;
+import org.sky.core.excel.util.ExcelUtil;
+import org.sky.core.log.exception.ServiceException;
+import org.sky.core.mp.base.BaseServiceImpl;
+import org.sky.core.tool.utils.BeanUtil;
+import org.sky.core.tool.utils.CollectionUtil;
+import org.sky.core.tool.utils.StringUtil;
+import org.sky.scientific.excel.XmDirectCostExcel;
+import org.sky.scientific.mapper.XmDirectCostMapper;
+import org.sky.scientific.mapper.XmMapper;
+import org.sky.scientific.pojo.entity.XmDirectCostEntity;
+import org.sky.scientific.service.IXmDirectCostService;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 研发项目直投费用清单 服务实现类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@Service
+public class XmDirectCostServiceImpl extends BaseServiceImpl<XmDirectCostMapper, XmDirectCostEntity> implements IXmDirectCostService {
+
+	@Resource
+	private XmMapper xmMapper;
+
+	@Override
+	public IPage<XmDirectCostEntity> selectXmDirectCostPage(IPage<XmDirectCostEntity> page, XmDirectCostEntity dto) {
+		if (StringUtil.isBlank(dto.getYearAndMonth())) {
+			throw new ServiceException("参数yearAndMonth不能为空");
+		}
+		return page.setRecords(baseMapper.selectXmDirectCostPage(page, dto));
+	}
+
+
+	@Override
+	public List<XmDirectCostExcel> exportXmDirectCost(Wrapper<XmDirectCostEntity> queryWrapper) {
+		return baseMapper.exportXmDirectCost(queryWrapper);
+	}
+
+	@Override
+	public boolean importXmDirectCost(MultipartFile file, String yearAndMonth) {
+		if (StringUtil.isBlank(yearAndMonth)) {
+			throw new ServiceException("参数yearAndMonth不能为空");
+		}
+		List<XmDirectCostExcel> data = ExcelUtil.read(file, 0, 2, XmDirectCostExcel.class);
+		if (CollectionUtil.isEmpty(data)) {
+			throw new ServiceException("未能从模板中读取数据,请检查模板格式是否正确");
+		}
+		List<XmDirectCostEntity> insertList = new ArrayList<>();
+		for (XmDirectCostExcel excel : data) {
+			XmDirectCostEntity entity = Objects.requireNonNull(BeanUtil.copyProperties(excel, XmDirectCostEntity.class));
+			if (!StringUtil.isAllBlank(excel.getXmmc(), excel.getXmbh())) {
+				//根据项目名称或编号查询xmId
+				Long xmId = xmMapper.getXmIdByXmmcOrXmbh(yearAndMonth, excel.getXmmc(), excel.getXmbh());
+				if (xmId == null) {
+					throw new ServiceException("研发项目[" + (StringUtil.isNotBlank(excel.getXmmc()) ? excel.getXmmc() + "," : "") + (StringUtil.isNotBlank(excel.getXmbh()) ? excel.getXmbh() : "") + "]不存在,请检查模板数据");
+				}
+				entity.setXmId(xmId);
+
+			}
+			entity.setYearAndMonth(yearAndMonth);
+			insertList.add(entity);
+		}
+		return this.saveBatch(insertList);
+	}
+
+	@Override
+	public boolean physicalDeleteByIds(List<Long> ids) {
+		return baseMapper.physicalDeleteByIds(ids) > 0;
+	}
+
+	@Override
+	public boolean submit(XmDirectCostEntity xmDirectCost) {
+		if (StringUtil.isBlank(xmDirectCost.getYearAndMonth())) {
+			throw new ServiceException("参数yearAndMonth不能为空");
+		}
+		return this.saveOrUpdate(xmDirectCost);
+	}
+
+}

+ 97 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/XmGoodsServiceImpl.java

@@ -0,0 +1,97 @@
+
+package org.sky.scientific.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import jakarta.annotation.Resource;
+import org.sky.core.excel.util.ExcelUtil;
+import org.sky.core.log.exception.ServiceException;
+import org.sky.core.mp.base.BaseServiceImpl;
+import org.sky.core.tool.utils.BeanUtil;
+import org.sky.core.tool.utils.CollectionUtil;
+import org.sky.core.tool.utils.StringUtil;
+import org.sky.scientific.excel.XmGoodsExcel;
+import org.sky.scientific.mapper.XmGoodsMapper;
+import org.sky.scientific.mapper.XmMapper;
+import org.sky.scientific.pojo.dto.XmGoodsDTO;
+import org.sky.scientific.pojo.entity.XmGoodsEntity;
+import org.sky.scientific.pojo.vo.XmGoodsVO;
+import org.sky.scientific.service.IXmGoodsService;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 研发项目物料清单 服务实现类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@Service
+public class XmGoodsServiceImpl extends BaseServiceImpl<XmGoodsMapper, XmGoodsEntity> implements IXmGoodsService {
+
+	@Resource
+	private XmMapper xmMapper;
+
+	@Override
+	public IPage<XmGoodsVO> selectXmGoodsPage(IPage<XmGoodsVO> page, XmGoodsDTO dto) {
+		if (StringUtil.isBlank(dto.getYearAndMonth())) {
+			throw new ServiceException("参数yearAndMonth不能为空");
+		}
+		return page.setRecords(baseMapper.selectXmGoodsPage(page, dto));
+	}
+
+
+	@Override
+	public List<XmGoodsExcel> exportXmGoods(Wrapper<XmGoodsEntity> queryWrapper) {
+		List<XmGoodsExcel> xmGoodsList = baseMapper.exportXmGoods(queryWrapper);
+		//xmGoodsList.forEach(xmGoods -> {
+		//	xmGoods.setTypeName(DictCache.getValue(DictEnum.YES_NO, XmGoods.getType()));
+		//});
+		return xmGoodsList;
+	}
+
+	@Override
+	public boolean importXmGoods(MultipartFile file, String yearAndMonth) {
+		if (StringUtil.isBlank(yearAndMonth)) {
+			throw new ServiceException("参数yearAndMonth不能为空");
+		}
+		List<XmGoodsExcel> data = ExcelUtil.read(file, 0, 2, XmGoodsExcel.class);
+		if (CollectionUtil.isEmpty(data)) {
+			throw new ServiceException("未能从模板中读取数据,请检查模板格式是否正确");
+		}
+		List<XmGoodsEntity> insertList = new ArrayList<>();
+		for (XmGoodsExcel excel : data) {
+			XmGoodsEntity entity = Objects.requireNonNull(BeanUtil.copyProperties(excel, XmGoodsDTO.class));
+			if (!StringUtil.isAllBlank(excel.getXmmc(), excel.getXmbh())) {
+				//根据项目名称或编号查询xmId
+				Long xmId = xmMapper.getXmIdByXmmcOrXmbh(yearAndMonth, excel.getXmmc(), excel.getXmbh());
+				if (xmId == null) {
+					throw new ServiceException("研发项目[" + (StringUtil.isNotBlank(excel.getXmmc()) ? excel.getXmmc() + "," : "") + (StringUtil.isNotBlank(excel.getXmbh()) ? excel.getXmbh() : "") + "]不存在,请检查模板数据");
+				}
+				entity.setXmId(xmId);
+
+			}
+			entity.setYearAndMonth(yearAndMonth);
+			insertList.add(entity);
+		}
+		return this.saveBatch(insertList);
+	}
+
+	@Override
+	public boolean physicalDeleteByIds(List<Long> ids) {
+		return baseMapper.physicalDeleteByIds(ids) > 0;
+	}
+
+	@Override
+	public boolean submit(XmGoodsEntity xmGoods) {
+		if (StringUtil.isBlank(xmGoods.getYearAndMonth())) {
+			throw new ServiceException("参数yearAndMonth不能为空");
+		}
+		return this.saveOrUpdate(xmGoods);
+	}
+
+}

+ 91 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/XmLeaseServiceImpl.java

@@ -0,0 +1,91 @@
+
+package org.sky.scientific.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import jakarta.annotation.Resource;
+import org.sky.core.excel.util.ExcelUtil;
+import org.sky.core.log.exception.ServiceException;
+import org.sky.core.mp.base.BaseServiceImpl;
+import org.sky.core.tool.utils.BeanUtil;
+import org.sky.core.tool.utils.CollectionUtil;
+import org.sky.core.tool.utils.StringUtil;
+import org.sky.scientific.excel.XmLeaseExcel;
+import org.sky.scientific.mapper.XmLeaseMapper;
+import org.sky.scientific.mapper.XmMapper;
+import org.sky.scientific.pojo.entity.XmLeaseEntity;
+import org.sky.scientific.service.IXmLeaseService;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 研发项目租赁清单 服务实现类
+ *
+ * @author Kd
+ * @since 2025-07-17
+ */
+@Service
+public class XmLeaseServiceImpl extends BaseServiceImpl<XmLeaseMapper, XmLeaseEntity> implements IXmLeaseService {
+
+	@Resource
+	private XmMapper xmMapper;
+
+	@Override
+	public IPage<XmLeaseEntity> selectXmLeasePage(IPage<XmLeaseEntity> page, XmLeaseEntity dto) {
+		if (StringUtil.isBlank(dto.getYearAndMonth())) {
+			throw new ServiceException("参数yearAndMonth不能为空");
+		}
+		return page.setRecords(baseMapper.selectXmLeasePage(page, dto));
+	}
+
+
+	@Override
+	public List<XmLeaseExcel> exportXmLease(Wrapper<XmLeaseEntity> queryWrapper) {
+		return baseMapper.exportXmLease(queryWrapper);
+	}
+
+	@Override
+	public boolean importXmLease(MultipartFile file, String yearAndMonth) {
+		if (StringUtil.isBlank(yearAndMonth)) {
+			throw new ServiceException("参数yearAndMonth不能为空");
+		}
+		List<XmLeaseExcel> data = ExcelUtil.read(file, 0, 2, XmLeaseExcel.class);
+		if (CollectionUtil.isEmpty(data)) {
+			throw new ServiceException("未能从模板中读取数据,请检查模板格式是否正确");
+		}
+		List<XmLeaseEntity> insertList = new ArrayList<>();
+		for (XmLeaseExcel excel : data) {
+			XmLeaseEntity entity = Objects.requireNonNull(BeanUtil.copyProperties(excel, XmLeaseEntity.class));
+			if (!StringUtil.isAllBlank(excel.getXmmc(), excel.getXmbh())) {
+				//根据项目名称或编号查询xmId
+				Long xmId = xmMapper.getXmIdByXmmcOrXmbh(yearAndMonth, excel.getXmmc(), excel.getXmbh());
+				if (xmId == null) {
+					throw new ServiceException("研发项目[" + (StringUtil.isNotBlank(excel.getXmmc()) ? excel.getXmmc() + "," : "") + (StringUtil.isNotBlank(excel.getXmbh()) ? excel.getXmbh() : "") + "]不存在,请检查模板数据");
+				}
+				entity.setXmId(xmId);
+
+			}
+			entity.setYearAndMonth(yearAndMonth);
+			insertList.add(entity);
+		}
+		return this.saveBatch(insertList);
+	}
+
+	@Override
+	public boolean physicalDeleteByIds(List<Long> ids) {
+		return baseMapper.physicalDeleteByIds(ids) > 0;
+	}
+
+	@Override
+	public boolean submit(XmLeaseEntity xmLease) {
+		if (StringUtil.isBlank(xmLease.getYearAndMonth())) {
+			throw new ServiceException("参数yearAndMonth不能为空");
+		}
+		return this.saveOrUpdate(xmLease);
+	}
+
+}