Browse Source

5555555555

zhouli 7 months ago
parent
commit
c2ab6fed9d

+ 14 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/controller/AttendanceController.java

@@ -39,6 +39,13 @@ public class AttendanceController extends KdController {
 		return R.data(service.selectAttendancePage(attendance, Condition.getPage(query)));
 	}
 
+	@GetMapping("/fetch")
+	@ApiOperationSupport(order = 2)
+	@Operation(summary = "每月考勤信息-引用当月研发人员名单")
+	public R<Boolean> fetch(String yearAndMonth) {
+		return R.status(service.fetch(yearAndMonth));
+	}
+
 	@PostMapping("/submit/batch")
 	@ApiOperationSupport(order = 3)
 	@Operation(summary = "每月考勤信息-批量新增或修改")
@@ -75,4 +82,11 @@ public class AttendanceController extends KdController {
 		return R.status(service.clearAttendance(attendanceList));
 	}
 
+	@DeleteMapping("/delete")
+	@ApiOperationSupport(order = 8)
+	@Operation(summary = "每月考勤信息-删除", description = "多个unicode、yearAndMonth")
+	public R deleteAttendance(@RequestBody List<AttendanceDto> attendanceList) {
+		return R.status(service.deleteAttendance(attendanceList));
+	}
+
 }

+ 15 - 1
kd-service/kd-scientific/src/main/java/org/sky/scientific/controller/XmTechnicianHoursController.java

@@ -56,6 +56,13 @@ public class XmTechnicianHoursController extends KdController {
 		return R.success("操作成功");
 	}
 
+	@GetMapping("/fetch")
+	@ApiOperationSupport(order = 4)
+	@Operation(summary = "引用当月参研人员名单")
+	public R<Boolean> fetch(String yearAndMonth) {
+		return R.status(service.fetch(yearAndMonth));
+	}
+
 	@PostMapping("/submit/batch")
 	@ApiOperationSupport(order = 5)
 	@Operation(summary = "新增/修改")
@@ -67,7 +74,14 @@ public class XmTechnicianHoursController extends KdController {
 	@ApiOperationSupport(order = 7)
 	@Operation(summary = "清除工时", description = "{\"yearAndMonth\":\"202507\",\"xmAndUnicodeList\":[{\"xmId\":\"1943241918440747010\",\"unicode\":\"ccd86a42-2369-4517-832e-004307e5237e\"}]}")
 	public R clear(@RequestBody JSONObject dto) {
-		return R.status(service.clear(dto));
+		return R.status(service.clearHours(dto));
+	}
+
+	@DeleteMapping("/delete")
+	@ApiOperationSupport(order = 8)
+	@Operation(summary = "删除", description = "数据结构和 清除接口一致")
+	public R deleteByXmUnicodeAndMonth(@RequestBody JSONObject dto) {
+		return R.status(service.deleteHours(dto));
 	}
 
 	@PostMapping("/export")

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

@@ -38,9 +38,9 @@
 
     <select id="selectAttendancePage" resultMap="ResultVoMap">
         SELECT xt.unicode, t.name, t.number, t.id_card, t.personnel_type
-        FROM kd_xm_technician xt
+        FROM kd_attendance_records xt
         LEFT JOIN kd_technician t on xt.unicode = t.unicode and t.year_and_month = #{ew.yearAndMonth}
-        WHERE xt.year_and_month = #{ew.yearAndMonth}
+        WHERE left(xt.work_date,6) = #{ew.yearAndMonth}
         <if test="ew.name != null">
             and t.name like concat('%',#{ew.name},'%')
         </if>
@@ -54,8 +54,7 @@
             and t.personnel_type = #{ew.personnelType}
         </if>
         group by xt.unicode
-        order by xt.year_and_month desc
-    </select>
+     </select>
 
     <update id="batchUpdate" parameterType="java.util.List">
         <foreach collection="list" item="record" separator=";">
@@ -95,8 +94,8 @@
     </update>
 
     <delete id="deleteByUnicodeAndMonthly">
-        delete from kd_attendance_records where unicode = #{unicode} and left(work_date,6) = #{yearAndMonth}
+        delete
+        from kd_attendance_records
+        where unicode = #{unicode} and left(work_date,6) = #{yearAndMonth}
     </delete>
-
-
 </mapper>

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

@@ -34,7 +34,9 @@ public interface XmTechnicianHoursMapper extends BaseMapper<XmTechnicianHours> {
 	/**
 	 * 清除工时数据
 	 */
-	int clear(@Param("yearAndMonth") String yearAndMonth, @Param("xmId") Long xmId, @Param("unicode") String unicode);
+	int clearByXmUnicodeMonth(@Param("yearAndMonth") String yearAndMonth, @Param("xmId") Long xmId, @Param("unicode") String unicode);
+
+	int deleteByXmUnicodeMonth(@Param("yearAndMonth") String yearAndMonth, @Param("xmId") Long xmId, @Param("unicode") String unicode);
 
     List<JSONObject> selectListForPrint(XmTechnicianHoursVO dto);
 

+ 16 - 9
kd-service/kd-scientific/src/main/java/org/sky/scientific/mapper/XmTechnicianHoursMapper.xml

@@ -36,24 +36,25 @@
 
     <select id="selectHoursPage" resultMap="ResultVoMap" >
         SELECT
-        xt.id,
-        xm.xmmc,xm.xmbh,xm.xm_id,
-        t.name, t.unicode, t.number,t.id_card,t.department,t.nature,t.situation,t.personnel_type
-        FROM kd_xm_technician xt
+            xm.xmmc,xm.xmbh,xm.xm_id,
+            t.name, t.unicode, t.number,t.id_card,t.department,t.nature,t.situation,t.personnel_type
+        FROM kd_xm_technician_hours xt
         LEFT JOIN kd_technician t on xt.unicode = t.unicode and t.year_and_month = #{ew.yearAndMonth}
-        LEFT JOIN (
+        LEFT JOIN
+        (
             SELECT
                 temp.id as xm_id, XMBH,
                 COALESCE(get_xm_info(temp.id,'XMMC', #{ew.yearAndMonth}), temp.XMMC ) AS XMMC
             FROM kd_xm temp
         ) xm ON xt.xm_id = xm.xm_id
-        WHERE xt.year_and_month = #{ew.yearAndMonth}
+        WHERE left(xt.work_date,6) = #{ew.yearAndMonth}
         <if test="ew.xmId!=null">and xm.xm_id = #{ew.xmId}</if>
         <if test="ew.xmmc!=null and ew.xmmc!=''">and xm.XMMC like concat(concat('%', #{ew.xmmc}), '%')</if>
         <if test="ew.name!=null and ew.name!=''">and t.name like concat(concat('%', #{ew.name}), '%')</if>
         <if test="ew.number!=null and ew.number!=''">and t.number like concat(concat('%', #{ew.number}), '%')</if>
         <if test="ew.idCard!=null and ew.idCard!=''">and t.id_card like concat(concat('%', #{ew.idCard}), '%')</if>
         <if test="ew.personnelType!=null and ew.personnelType!=''">and t.personnel_type =#{personnelType}</if>
+        group by xt.xm_id,xt.unicode
     </select>
 
     <update id="batchUpdate" parameterType="java.util.List">
@@ -125,9 +126,9 @@
     <select id="meiyueyanfagongshifenpeibiao" resultMap="TechnicianHoursMonthlyVOMap" parameterType="org.sky.scientific.pojo.dto.TechnicianDTO">
         SELECT
             DISTINCT xt.unicode, name, number, id_card, personnel_type
-        FROM kd_xm_technician xt
+        FROM kd_xm_technician_hours xt
         LEFT JOIN  kd_technician t on t.unicode = xt.unicode and t.year_and_month=#{ew.yearAndMonth}
-        WHERE xt.year_and_month = #{ew.yearAndMonth}
+        WHERE left(xt.work_date,6) = #{ew.yearAndMonth}
         <if test="ew.name!=null and ew.name!=''">and t.name like concat(concat('%', #{ew.name}), '%')</if>
         <if test="ew.number!=null and ew.number!=''">and t.number like concat(concat('%', #{ew.number}), '%')</if>
         <if test="ew.idCard!=null and ew.idCard!=''">and t.id_card like concat(concat('%', #{ew.idCard}), '%')</if>
@@ -161,7 +162,13 @@
          WHERE LEFT(h.work_date, 6) = #{yearAndMonth}
     </select>
 
-    <delete id="clear">
+    <update id="clearByXmUnicodeMonth">
+        update kd_xm_technician_hours
+        set work_hours = 0
+        WHERE left(work_date,6) = #{yearAndMonth} and xm_id = #{xmId} and unicode = #{unicode}
+    </update>
+
+    <delete id="deleteByXmUnicodeMonth">
         DELETE FROM kd_xm_technician_hours
         WHERE left(work_date,6) = #{yearAndMonth} and xm_id = #{xmId} and unicode = #{unicode}
     </delete>

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

@@ -62,7 +62,7 @@
         SELECT
         xt.id,xt.year_and_month,
         xm.*,
-        t.name, t.unicode, t.number,t.id_card,t.department,t.nature,t.situation,t.personnel_type
+        t.name, xt.unicode, t.number,t.id_card,t.department,t.nature,t.situation,t.personnel_type
         FROM kd_xm_technician xt
         LEFT JOIN kd_technician t on xt.unicode = t.unicode and t.year_and_month = #{ew.yearAndMonth}
         LEFT JOIN (

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

@@ -60,4 +60,17 @@ public interface IAttendanceService extends BaseService<AttendanceEntity> {
 	 */
 	boolean clearAttendance(List<AttendanceDto> attendanceList);
 
+	/**
+	 * 每月考勤信息-引用当月研发人员名单
+	 * @param yearAndMonth
+	 * @return
+	 */
+	boolean fetch(String yearAndMonth);
+
+	/**
+	 * 删除当月研发人员
+	 * @param attendanceList
+	 * @return
+	 */
+	boolean deleteAttendance(List<AttendanceDto> attendanceList);
 }

+ 11 - 1
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/IXmTechnicianHoursService.java

@@ -47,7 +47,10 @@ public interface IXmTechnicianHoursService extends BaseService<XmTechnicianHours
 	 * @param dto
 	 * @return
 	 */
-	boolean clear(JSONObject dto);
+	boolean clearHours(JSONObject dto);
+
+
+	boolean deleteHours(JSONObject dto);
 
 	/**
 	 * 导出
@@ -80,4 +83,11 @@ public interface IXmTechnicianHoursService extends BaseService<XmTechnicianHours
 	 */
 	void exportMeiyueyanfagongshifenpeibiao(HttpServletResponse response, TechnicianDTO dto);
 
+	/**
+	 * 引用当月参研人员名单
+	 * @param yearAndMonth
+	 * @return
+	 */
+	boolean fetch(String yearAndMonth);
+
 }

+ 61 - 6
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/AttendanceServiceImpl.java

@@ -12,6 +12,7 @@ import org.sky.core.log.exception.ServiceException;
 import org.sky.core.mp.base.BaseServiceImpl;
 import org.sky.core.secure.utils.SecureUtil;
 import org.sky.core.tool.utils.CollectionUtil;
+import org.sky.core.tool.utils.DateUtil;
 import org.sky.core.tool.utils.Func;
 import org.sky.core.tool.utils.StringUtil;
 import org.sky.scientific.excel.AttendanceMonthlyDataListener;
@@ -60,18 +61,35 @@ public class AttendanceServiceImpl extends BaseServiceImpl<AttendanceMapper, Att
 			throw new ServiceException("参数yearAndMonth不能为空");
 		}
 		List<AttendanceVO> list = baseMapper.selectAttendancePage(page, attendance);
+
+		int year = Integer.parseInt(attendance.getYearAndMonth().substring(0, 4));
+		int month = Integer.parseInt(attendance.getYearAndMonth().substring(4));
+		LocalDate startDate = LocalDate.of(year, month, 1);
+		int daysInMonth = startDate.lengthOfMonth();
+
 		for (AttendanceVO vo : list) {
 			List<DailyAttendance> dailyAttendanceList = baseMapper.selectDailyAttendanceByUnicodeAndMonth(vo.getUnicode(), attendance.getYearAndMonth());
-			if (CollectionUtil.isEmpty(dailyAttendanceList)) {
-				continue;
+			if (dailyAttendanceList==null) {
+				dailyAttendanceList = new ArrayList<>();
+			}
+			for (int i = 0; i < daysInMonth; i++) {
+				String everyDay = startDate.plusDays(i).format(DateTimeFormatter.ofPattern(DateUtil.PATTERN_YYYYMMDD));
+				//过滤某天的出勤数据
+				Optional<DailyAttendance> any = dailyAttendanceList.stream().filter(daily -> Func.equals(daily.getWorkDate(), everyDay)).findAny();
+				DailyAttendance daily = null;
+				if (any.isEmpty()) {
+					daily = new DailyAttendance();
+					daily.setWorkDate(everyDay);
+					daily.setWorkHours(0.0);
+					dailyAttendanceList.add(i, daily);
+				}
 			}
+			vo.setDailyAttendances(dailyAttendanceList);
 			vo.setMonthlyHours(dailyAttendanceList.stream().mapToDouble(DailyAttendance::getWorkHours).sum());
-
 			SettingEntity one = settingMapper.selectOne(Wrappers.<SettingEntity>lambdaQuery().eq(SettingEntity::getYearAndMonth, attendance.getYearAndMonth().substring(0, 4)));
 			if (Func.isNull(one) || Func.isNull(one.getWorkHours())) {
 				throw new ServiceException("企业未设置考勤时长");
 			}
-
 			Double workHours = one.getWorkHours();
 			vo.setMonthlyDays(vo.getMonthlyHours() / workHours);
 			vo.setDailyAttendances(dailyAttendanceList);
@@ -320,7 +338,6 @@ public class AttendanceServiceImpl extends BaseServiceImpl<AttendanceMapper, Att
 				entity.setWorkHours(dailyAttendance.getWorkHours());
 				updateList.add(entity);
 			}
-
 		}
 
 		if (!insertList.isEmpty()) {
@@ -341,9 +358,47 @@ public class AttendanceServiceImpl extends BaseServiceImpl<AttendanceMapper, Att
 		}
 		int affectNum = 0;
 		for (AttendanceDto entity : attendanceList) {
-			affectNum += baseMapper.deleteByUnicodeAndMonthly(entity.getUnicode(), entity.getYearAndMonth());
+			affectNum += baseMapper.clearUnicodeAndMonthly(entity.getUnicode(), entity.getYearAndMonth());
 		}
 		return affectNum >= 0;
 	}
 
+	@Override
+	public boolean fetch(String yearAndMonth) {
+		List<XmTechnicianEntity> list = xmTechnicianMapper.selectList(Wrappers.<XmTechnicianEntity>lambdaQuery().eq(XmTechnicianEntity::getYearAndMonth, yearAndMonth));
+
+		if(Func.isEmpty(list)){
+			throw new ServiceException("本月没有研发人员");
+		}
+
+		List<AttendanceEntity> insertList = new ArrayList<>();
+		for (XmTechnicianEntity xmTechnician : list) {
+			AttendanceEntity attendance = new AttendanceEntity();
+			attendance.setUnicode(xmTechnician.getUnicode());
+			attendance.setWorkDate(yearAndMonth + "01");
+			attendance.setWorkHours(0.0);
+			attendance.setTenantId(SecureUtil.getTenantId());
+			insertList.add(attendance);
+		}
+
+		List<AttendanceEntity> attendanceList = this.baseMapper.selectByYearAndMonth(yearAndMonth);
+		List<String> existsUnicodeList = attendanceList.stream().map(AttendanceEntity::getUnicode).distinct().toList();
+		if(Func.isEmpty(existsUnicodeList)){
+ 			return this.saveBatch(insertList);
+		}else {
+			List<AttendanceEntity> deduplicationList = insertList.stream().filter(item -> !existsUnicodeList.contains(item.getUnicode())).toList();
+			if(Func.isEmpty(deduplicationList)){
+				throw new ServiceException("本月研发人员已全部引用");
+			}
+			return this.saveBatch(deduplicationList);
+		}
+ 	}
+
+	@Override
+	public boolean deleteAttendance(List<AttendanceDto> attendanceList) {
+		for (AttendanceDto dto : attendanceList) {
+ 			baseMapper.deleteByUnicodeAndMonthly(dto.getUnicode(), dto.getYearAndMonth());
+		}
+		return true;
+	}
 }

+ 76 - 12
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/XmTechnicianHoursServiceImpl.java

@@ -5,7 +5,9 @@ import com.alibaba.excel.EasyExcel;
 import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.AllArgsConstructor;
 import lombok.SneakyThrows;
@@ -21,11 +23,9 @@ import org.sky.scientific.excel.XmTechnicianHoursListener;
 import org.sky.scientific.excel.handle.CustomCellStyleHandler;
 import org.sky.scientific.excel.handle.TechnicianWorkMergeStrategy;
 import org.sky.scientific.excel.handle.TechnicianWorkStatisticsMergeStrategy;
-import org.sky.scientific.mapper.AttendanceMapper;
-import org.sky.scientific.mapper.TechnicianMapper;
-import org.sky.scientific.mapper.XmMapper;
-import org.sky.scientific.mapper.XmTechnicianHoursMapper;
+import org.sky.scientific.mapper.*;
 import org.sky.scientific.pojo.dto.TechnicianDTO;
+import org.sky.scientific.pojo.entity.XmTechnicianEntity;
 import org.sky.scientific.pojo.entity.XmTechnicianHours;
 import org.sky.scientific.pojo.vo.DailyAttendance;
 import org.sky.scientific.pojo.vo.DailyHours;
@@ -60,6 +60,7 @@ public class XmTechnicianHoursServiceImpl extends BaseServiceImpl<XmTechnicianHo
 	private final XmMapper xmMapper;
 	private final AttendanceMapper attendanceMapper;
 	private final TechnicianMapper technicianMapper;
+	private final XmTechnicianMapper xmTechnicianMapper;
 
 	@SneakyThrows
 	@Transactional(rollbackFor = Exception.class)
@@ -195,13 +196,28 @@ public class XmTechnicianHoursServiceImpl extends BaseServiceImpl<XmTechnicianHo
 		if (StringUtil.isBlank(dto.getYearAndMonth())) {
 			throw new ServiceException("参数yearAndMonth不能为空");
 		}
+		int year = Integer.parseInt(dto.getYearAndMonth().substring(0, 4));
+		int month = Integer.parseInt(dto.getYearAndMonth().substring(4));
+		LocalDate startDate = LocalDate.of(year, month, 1);
+		int daysInMonth = startDate.lengthOfMonth();
+
 		List<XmTechnicianHoursVO> list = baseMapper.selectHoursPage(page, dto);
 		for (XmTechnicianHoursVO temp : list) {
-			List<DailyAttendance> dailyAttendanceList = baseMapper.selectByXmIdAndUnicode(temp.getXmId(), temp.getUnicode(), dto.getYearAndMonth());
-			if (CollectionUtil.isEmpty(dailyAttendanceList)) {
-				continue;
+
+			List<DailyAttendance> dailyHoursList = baseMapper.selectByXmIdAndUnicode(temp.getXmId(), temp.getUnicode(), dto.getYearAndMonth());
+			for (int i = 0; i < daysInMonth; i++) {
+				String everyDay = startDate.plusDays(i).format(DateTimeFormatter.ofPattern(DateUtil.PATTERN_YYYYMMDD));
+				//过滤某天的工时数据
+				Optional<DailyAttendance> any = dailyHoursList.stream().filter(daily -> Func.equals(daily.getWorkDate(), everyDay)).findAny();
+				DailyAttendance daily = null;
+				if (any.isEmpty()) {
+					daily = new DailyAttendance();
+					daily.setWorkDate(everyDay);
+					daily.setWorkHours(0.0);
+					dailyHoursList.add(i, daily);
+				}
 			}
-			temp.setDailyAttendances(dailyAttendanceList);
+			temp.setDailyAttendances(dailyHoursList);
 		}
 		return page.setRecords(list);
 	}
@@ -283,14 +299,27 @@ public class XmTechnicianHoursServiceImpl extends BaseServiceImpl<XmTechnicianHo
 	}
 
 	@Override
-	public boolean clear(JSONObject dto) {
+	public boolean clearHours(JSONObject dto) {
 		JSONArray xmAndUnicodeList = dto.getJSONArray("xmAndUnicodeList");
 		if (xmAndUnicodeList == null || xmAndUnicodeList.isEmpty()) {
 			throw new ServiceException("参数xmAndUnicodeList不能为空");
 		}
 		for (Object xmAndUnicode : xmAndUnicodeList) {
 			Map<String, String> map = (HashMap<String, String>) xmAndUnicode;
-			baseMapper.clear(dto.getString("yearAndMonth"), Long.valueOf(map.get("xmId")), map.get("unicode"));
+			baseMapper.clearByXmUnicodeMonth(dto.getString("yearAndMonth"), Long.valueOf(map.get("xmId")), map.get("unicode"));
+		}
+		return true;
+	}
+
+	@Override
+	public boolean deleteHours(JSONObject dto) {
+		JSONArray xmAndUnicodeList = dto.getJSONArray("xmAndUnicodeList");
+		if (xmAndUnicodeList == null || xmAndUnicodeList.isEmpty()) {
+			throw new ServiceException("参数xmAndUnicodeList不能为空");
+		}
+		for (Object xmAndUnicode : xmAndUnicodeList) {
+			Map<String, String> map = (HashMap<String, String>) xmAndUnicode;
+			baseMapper.deleteByXmUnicodeMonth(dto.getString("yearAndMonth"), Long.valueOf(map.get("xmId")), map.get("unicode"));
 		}
 		return true;
 	}
@@ -425,8 +454,8 @@ public class XmTechnicianHoursServiceImpl extends BaseServiceImpl<XmTechnicianHo
 		}
 		List<TechnicianHoursMonthlyVO> list = baseMapper.meiyueyanfagongshifenpeibiao(page, dto);
 
-		Integer year = Integer.valueOf(dto.getYearAndMonth().substring(0, 4));
-		Integer month = Integer.valueOf(dto.getYearAndMonth().substring(4));
+		int year = Integer.parseInt(dto.getYearAndMonth().substring(0, 4));
+		int month = Integer.parseInt(dto.getYearAndMonth().substring(4));
 		LocalDate startDate = LocalDate.of(year, month, 1);
 		int daysInMonth = startDate.lengthOfMonth();
 
@@ -524,4 +553,39 @@ public class XmTechnicianHoursServiceImpl extends BaseServiceImpl<XmTechnicianHo
 		}
 	}
 
+	@Override
+	@Transactional
+	public boolean fetch(String yearAndMonth) {
+		List<XmTechnicianEntity> list = xmTechnicianMapper.selectList(Wrappers.<XmTechnicianEntity>lambdaQuery().eq(XmTechnicianEntity::getYearAndMonth, yearAndMonth));
+
+		if (Func.isEmpty(list)) {
+			throw new ServiceException("本月没有参研人员");
+		}
+
+		List<XmTechnicianHours> insertList = new ArrayList<>();
+		for (XmTechnicianEntity xmTechnician : list) {
+			XmTechnicianHours hours = new XmTechnicianHours();
+			hours.setXmId(xmTechnician.getXmId());
+			hours.setUnicode(xmTechnician.getUnicode());
+			hours.setWorkDate(yearAndMonth + "01");
+			hours.setWorkHours(0.0);
+			hours.setTenantId(SecureUtil.getTenantId());
+			insertList.add(hours);
+		}
+
+		LambdaQueryWrapper<XmTechnicianHours> queryWrapper = Wrappers.<XmTechnicianHours>lambdaQuery().apply("left(work_date, 6) = {0}", yearAndMonth);
+		List<XmTechnicianHours> hoursList = baseMapper.selectList(queryWrapper);
+		Map<Long, List<String>> collect = hoursList.stream().collect(Collectors.groupingBy(XmTechnicianHours::getXmId, Collectors.mapping(XmTechnicianHours::getUnicode, Collectors.toList())));
+		if (collect.isEmpty()) {
+			return this.saveBatch(insertList);
+		} else {
+//			collect.get()
+			List<XmTechnicianHours> deduplicationList = insertList.stream().filter(item -> !(collect.containsKey(item.getXmId()) && collect.get(item.getXmId()).contains(item.getUnicode()))).toList();
+			if (Func.isEmpty(deduplicationList)) {
+				throw new ServiceException("本月参研人员已全部引用");
+			}
+			return this.saveBatch(deduplicationList);
+		}
+	}
+
 }