From 2d23f61febcaf1e91be16b26354498d117f73855 Mon Sep 17 00:00:00 2001 From: lSun <15893999301@qq.com> Date: Tue, 12 Aug 2025 13:39:47 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=9C=E6=B0=91=E5=B7=A5=E7=94=A8=E5=B7=A5?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=8F=B0=E8=B4=A6=E5=AE=9A=E6=97=B6=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bonus/ahsbs/base/dao/AttLedgerDao.java | 60 ++++ .../ahsbs/base/entity/AttLedgerBean.java | 58 ++++ .../ahsbs/base/entity/XbgAttReportData.java | 34 ++ .../base/entity/XbgAttReportDataDetail.java | 22 ++ .../bonus/ahsbs/base/task/AttLedgerTask.java | 294 ++++++++++++++++++ .../com/bonus/ahsbs/base/util/IDUtils.java | 36 ++- .../mappers/base/AttLedgerMapper.xml | 143 +++++++++ 7 files changed, 642 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/bonus/ahsbs/base/dao/AttLedgerDao.java create mode 100644 src/main/java/com/bonus/ahsbs/base/entity/AttLedgerBean.java create mode 100644 src/main/java/com/bonus/ahsbs/base/entity/XbgAttReportData.java create mode 100644 src/main/java/com/bonus/ahsbs/base/entity/XbgAttReportDataDetail.java create mode 100644 src/main/java/com/bonus/ahsbs/base/task/AttLedgerTask.java create mode 100644 src/main/resources/mappers/base/AttLedgerMapper.xml diff --git a/src/main/java/com/bonus/ahsbs/base/dao/AttLedgerDao.java b/src/main/java/com/bonus/ahsbs/base/dao/AttLedgerDao.java new file mode 100644 index 0000000..ecd9ef9 --- /dev/null +++ b/src/main/java/com/bonus/ahsbs/base/dao/AttLedgerDao.java @@ -0,0 +1,60 @@ +package com.bonus.ahsbs.base.dao; + +import com.bonus.ahsbs.base.entity.AttLedgerBean; +import com.bonus.ahsbs.base.entity.XbgAttReportData; +import com.bonus.ahsbs.base.entity.XbgAttReportDataDetail; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * packageName com.bonus.ahsbs.base.dao + * + * @author lsun + * @version 1.0.0 + * @className AttLedgerDao (此处以class为例) + * @date 2025/8/8 + * @description 农民工用工管理台账数据访问层 + */ +@Repository(value = "AttLedgerDao") +public interface AttLedgerDao { + /** + * 获取所有项目下的人员信息 + * @return + */ + List getPersonesByPro(); + + /** + * 获取考勤信息 + * @return + */ + List getAttendanceInfo(); + + /** + * 批量插入xbg_att_report_data表数据 + * @param reportDataList + */ + void batchInsertXbgAttReportData(List reportDataList); + + /** + * 批量插入xbg_att_report_data_detail表数据 + * @param detailList + */ + void batchInsertXbgAttReportDataDetail(List detailList); + + /** + * 获取工程的出入场时间 + * @return + */ + List getProjectTime(); + + /** + * 删除xbg_att_report_data表数据 + */ + void deleteXbgAttReportData(); + + /** + * 删除xbg_att_report_data_detail表数据 + */ + void deleteXbgAttReportDataDetail(); +} \ No newline at end of file diff --git a/src/main/java/com/bonus/ahsbs/base/entity/AttLedgerBean.java b/src/main/java/com/bonus/ahsbs/base/entity/AttLedgerBean.java new file mode 100644 index 0000000..30888b9 --- /dev/null +++ b/src/main/java/com/bonus/ahsbs/base/entity/AttLedgerBean.java @@ -0,0 +1,58 @@ +package com.bonus.ahsbs.base.entity; + +import lombok.Data; + +/** + * packageName com.bonus.ahsbs.base.entity + * + * @author lsun + * @version 1.0.0 + * @className AttLedgerBean (此处以class为例) + * @date 2025/8/8 + * @description 农民工用工管理台账 + */ +@Data +public class AttLedgerBean { + private String proName;//工程名称 + private String proType;//工程类型 + private String dydj;//电压等级 + private String proState;//工程状态 + + private String personName;//姓名 + private String sex;//性别 + private String teamName;//所属班组 + private String postName;//岗位 + private String idNumber;//身份证ID + + private String subId; + private String subName;//分包单位 + private String contactInfo;//联系方式 + private String proId; + private String teamId; + private String nation;//民族 + private String age;//年龄 + private String enDate;//进场时间 + private String exDate;//出场时间 + private String checkNum;//出勤天数 字符串格式,用","隔开 + private String contract;//合同约定工价 + private String birthDate; + private String contractNum;//合同数 + private String contractId;//合同Id + private String contractPath;//合同路径 + + private String einTime;//入场时间3 + + private String exitTime;//出场时间 + + private String startTime;//开始时间 + private String endTime;//结果时间 + private String postId; // 工种/岗位ID + + private String month;//月份 + private String achievementsMoney;//绩效范围 + + private String fristTime;//第一次人员入场时间 + private String lastTime;//工程完工时间 + + private String currentDay;//考勤时间 +} diff --git a/src/main/java/com/bonus/ahsbs/base/entity/XbgAttReportData.java b/src/main/java/com/bonus/ahsbs/base/entity/XbgAttReportData.java new file mode 100644 index 0000000..a761c24 --- /dev/null +++ b/src/main/java/com/bonus/ahsbs/base/entity/XbgAttReportData.java @@ -0,0 +1,34 @@ +package com.bonus.ahsbs.base.entity; + +import lombok.Data; + +/** + * packageName com.bonus.ahsbs.base.entity + * + * @author lsun + * @version 1.0.0 + * @className XbgAttReportData (此处以class为例) + * @date 2025/8/8 + * @description 考勤报表主表:存储员工基本信息与组织归属 + */ +@Data +public class XbgAttReportData { + private String id; // 主键ID + private String name; // 姓名 + private String idCard; // 身份证号 + private String gender; // 性别 + private String ethnicity; // 民族 + private String age; // 年龄 + private String contactInfo; // 联系方式 + private String proId; // 工程(项目)ID,关联工程项目表 + private String subId; // 分包单位ID + private String teamId; // 所在班组ID + private String postId; // 工种/岗位ID + private String contractId; // 合同ID + private String entryDate; // 进场日期 + private String exitDate; // 出场日期 + private String basicSalary; // 基本工资 + private String performanceSalary; // 绩效工资 + private String createTime; // 创建时间 + private String updateTime; // 更新时间 +} \ No newline at end of file diff --git a/src/main/java/com/bonus/ahsbs/base/entity/XbgAttReportDataDetail.java b/src/main/java/com/bonus/ahsbs/base/entity/XbgAttReportDataDetail.java new file mode 100644 index 0000000..801b875 --- /dev/null +++ b/src/main/java/com/bonus/ahsbs/base/entity/XbgAttReportDataDetail.java @@ -0,0 +1,22 @@ +package com.bonus.ahsbs.base.entity; + +import lombok.Data; + +/** + * packageName com.bonus.ahsbs.base.entity + * + * @author lsun + * @version 1.0.0 + * @className XbgAttReportDataDetail (此处以class为例) + * @date 2025/8/8 + * @description 考勤月度明细表:存储每个员工每月的出勤天数 + */ +@Data +public class XbgAttReportDataDetail { + private String id; // 主键ID + private String reportDataId; // 关联 xbg_att_report_data 的ID + private String yearMonth; // 年月 + private String attendanceDays; // 出勤天数 + private String createTime; // 创建时间 + private String updateTime; // 更新时间 +} \ No newline at end of file diff --git a/src/main/java/com/bonus/ahsbs/base/task/AttLedgerTask.java b/src/main/java/com/bonus/ahsbs/base/task/AttLedgerTask.java new file mode 100644 index 0000000..a0190b6 --- /dev/null +++ b/src/main/java/com/bonus/ahsbs/base/task/AttLedgerTask.java @@ -0,0 +1,294 @@ +package com.bonus.ahsbs.base.task; + +import com.bonus.ahsbs.base.dao.AttLedgerDao; +import com.bonus.ahsbs.base.entity.AttLedgerBean; +import com.bonus.ahsbs.base.entity.XbgAttReportData; +import com.bonus.ahsbs.base.entity.XbgAttReportDataDetail; +import com.bonus.ahsbs.core.util.DateTimeHelper; +import com.bonus.ahsbs.base.util.IDUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.time.Period; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * packageName com.bonus.ahsbs.base.task + * + * @author lsun + * @version 1.0.0 + * @className TrainingTask (此处以class为例) + * @date 2025/8/8 + * @description 农民工用工管理台账 + */ +@Component +@Slf4j +@EnableScheduling +@EnableAsync +public class AttLedgerTask { + + @Resource(name = "AttLedgerDao") + private AttLedgerDao dao; + + @Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行 +// @Scheduled(cron = "0 */3 * * * ?") // 每3秒执行一次 + public void add() { + log.info("农民工用工管理台账定时任务开始执行"); + try { + // Step 1: 获取基本信息 + List basicInfoList = dao.getPersonesByPro(); + // Step 2: 获取工程的出入场时间 +// List projectTimeList = dao.getProjectTime(); + + // Step 3: 获取考勤信息 + List attendanceInfoList = dao.getAttendanceInfo(); + + // Step 3: 合并基本信息和考勤信息 + List mergedList = mergeInfo(basicInfoList, attendanceInfoList); + + // Step 4: 插入 xbg_att_report_data 表 + List insertedReportDataList = insertXbgAttReportData(mergedList); + + // Step 5: 插入 xbg_att_report_data_detail 表 + insertXbgAttReportDataDetail(mergedList, insertedReportDataList); + } catch (Exception e) { + log.error(e.toString(), e); + } + log.info("农民工用工管理台账定时任务结束执行"); + } + + private List mergeInfo(List basicInfoList, List attendanceInfoList) { + // 1. 将考勤信息按(身份证号+工程ID+分包id+班组id+岗位id)分组,方便后续查找 + Map> attendanceGroupByKey = attendanceInfoList.stream() + .collect(Collectors.groupingBy(bean -> + bean.getIdNumber() + "_" + bean.getProId() + "_" + + bean.getSubId() + "_" + bean.getTeamId() + "_" + bean.getPostId())); + + // 2. 处理每条基本信息记录 + for (AttLedgerBean basicInfo : basicInfoList) { + // 构造分组key用于查找考勤信息 + String key = basicInfo.getIdNumber() + "_" + basicInfo.getProId() + "_" + + basicInfo.getSubId() + "_" + basicInfo.getTeamId() + "_" + basicInfo.getPostId(); + List attendanceList = attendanceGroupByKey.get(key); + + if (attendanceList != null && !attendanceList.isEmpty()) { + // 按月份统计考勤天数 + Map attendanceByMonth = new HashMap<>(); + + for (AttLedgerBean attendance : attendanceList) { + // 从create_date中提取年月 + String currentDate = attendance.getCurrentDay(); + if (currentDate != null && currentDate.length() >= 7) { + // 提取年月部分 YYYY-MM + String yearMonth = currentDate.substring(0, 7); + // 累加该月份的考勤天数 + attendanceByMonth.merge(yearMonth, 1, Integer::sum); + } + } + + // 构建考勤天数和月份字符串 + StringBuilder checkNumBuilder = new StringBuilder(); + StringBuilder monthBuilder = new StringBuilder(); + + int count = 0; + for (Map.Entry monthEntry : attendanceByMonth.entrySet()) { + if (count > 0) { + checkNumBuilder.append(","); + monthBuilder.append(","); + } + monthBuilder.append(monthEntry.getKey()); + checkNumBuilder.append(monthEntry.getValue()); + count++; + } + + basicInfo.setCheckNum(checkNumBuilder.toString()); + basicInfo.setMonth(monthBuilder.toString()); + + // 更新工程ID等信息(如果还没有设置) + if (basicInfo.getProId() == null && attendanceList.size() > 0) { + AttLedgerBean attendance = attendanceList.get(0); + basicInfo.setProId(attendance.getProId()); + basicInfo.setSubId(attendance.getSubId()); + basicInfo.setTeamId(attendance.getTeamId()); + basicInfo.setPostId(attendance.getPostId()); + basicInfo.setContractId(attendance.getContractId()); + } + } + } + + // 3. 更新工程的入场和出场时间 + for (AttLedgerBean basicInfo : basicInfoList) { + // 设置入场和出场日期字段(用于报表主表) + basicInfo.setEnDate(basicInfo.getEinTime() != null ? basicInfo.getEinTime().substring(0, 10) : null); + basicInfo.setExDate(basicInfo.getExitTime() != null ? basicInfo.getExitTime().substring(0, 10) : null); + } + + return basicInfoList; + } + + private List insertXbgAttReportData(List mergedList) { + List reportDataList = new ArrayList<>(); + + // 先为每个报告数据生成唯一ID + Map beanToIdMap = new HashMap<>(); + + for (AttLedgerBean bean : mergedList) { + XbgAttReportData reportData = new XbgAttReportData(); + String id = IDUtils.createID(); + reportData.setId(id); + beanToIdMap.put(bean, id); + + reportData.setName(bean.getPersonName()); + reportData.setIdCard(bean.getIdNumber()); + reportData.setGender(bean.getSex()); + reportData.setEthnicity(bean.getNation()); + reportData.setAge(calculateAge(bean.getBirthDate())); // 使用计算的年龄 + reportData.setContactInfo(bean.getContactInfo()); + reportData.setProId(bean.getProId()); + reportData.setSubId(bean.getSubId()); + reportData.setTeamId(bean.getTeamId()); + reportData.setPostId(bean.getPostId()); + reportData.setContractId(bean.getContractId()); + reportData.setEntryDate(bean.getEnDate()); + reportData.setExitDate(bean.getExDate()); + reportData.setBasicSalary(getBasicSalary(bean)); + reportData.setPerformanceSalary(getPerformanceSalary(bean)); + reportData.setCreateTime(DateTimeHelper.getNowDate()); + reportData.setUpdateTime(DateTimeHelper.getNowDate()); + reportDataList.add(reportData); + } + // 插入之前删除之前的数据 + dao.deleteXbgAttReportData(); + // 批量插入 xbg_att_report_data 表 + dao.batchInsertXbgAttReportData(reportDataList); + + return reportDataList; + } + + /** + * 根据出生日期计算年龄 + * @param birthDate 出生日期,格式为 "yyyy年M月d日" 或 "yyyy年M月d" 或 "yyyy-MM-dd" + * @return 年龄字符串 + */ + private String calculateAge(String birthDate) { + if (birthDate == null || birthDate.trim().isEmpty()) { + return null; + } + + try { + LocalDate birthLocalDate; + // 尝试解析"yyyy年M月d日"或"yyyy年M月d"格式 + if (birthDate.contains("年") && birthDate.contains("月")) { + // 检查是否包含"日" + String pattern = birthDate.contains("日") ? "yyyy年M月d日" : "yyyy年M月d"; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + birthLocalDate = LocalDate.parse(birthDate, formatter); + } else { + // 解析"yyyy-MM-dd"格式 + birthLocalDate = LocalDate.parse(birthDate); + } + + // 获取当前日期 + LocalDate now = LocalDate.now(); + // 计算年龄 + int age = Period.between(birthLocalDate, now).getYears(); + return String.valueOf(age); + } catch (Exception e) { + // 如果解析失败,返回null + return null; + } + } + + private void insertXbgAttReportDataDetail(List mergedList, List insertedReportDataList) { + // 创建从(身份证号+工程ID+分包id+班组id+岗位id)到reportData的映射,处理重复键的情况 + Map keyToReportDataMap = insertedReportDataList.stream() + .collect(Collectors.toMap( + reportData -> reportData.getIdCard() + "_" + reportData.getProId() + "_" + + reportData.getSubId() + "_" + reportData.getTeamId() + "_" + reportData.getPostId(), + Function.identity(), + (existing, replacement) -> existing)); // 当出现重复键时,保留第一个值 + + List detailList = new ArrayList<>(); + + for (AttLedgerBean bean : mergedList) { + // 根据(身份证号+工程ID+分包id+班组id+岗位id)获取对应的reportData + String key = bean.getIdNumber() + "_" + bean.getProId() + "_" + + bean.getSubId() + "_" + bean.getTeamId() + "_" + bean.getPostId(); + XbgAttReportData reportData = keyToReportDataMap.get(key); + if (reportData == null) { + continue; // 如果没有对应的主表记录,则跳过 + } + + if (bean.getCheckNum() != null && !bean.getCheckNum().isEmpty() + && bean.getMonth() != null && !bean.getMonth().isEmpty()) { + String[] checkNums = bean.getCheckNum().split(","); + String[] months = bean.getMonth().split(","); + + // 确保考勤天数和月份数组长度一致 + int length = Math.min(checkNums.length, months.length); + + for (int i = 0; i < length; i++) { + XbgAttReportDataDetail detail = new XbgAttReportDataDetail(); + detail.setReportDataId(reportData.getId()); // 使用正确的ID + detail.setYearMonth(months[i]); + detail.setAttendanceDays(checkNums[i]); + detail.setCreateTime(DateTimeHelper.getNowDate()); + detail.setUpdateTime(DateTimeHelper.getNowDate()); + + detailList.add(detail); + } + } + } + + // 插入之前删除之前数据 + dao.deleteXbgAttReportDataDetail(); + // 批量插入 xbg_att_report_data_detail 表 + if (!detailList.isEmpty()) { + dao.batchInsertXbgAttReportDataDetail(detailList); + } + } + + private String getBasicSalary(AttLedgerBean bean) { + // 自定义方法获取基本工资 + if (bean.getContract() != null && !bean.getContract().isEmpty()) { + String[] contractParts = bean.getContract().split(","); + if (contractParts.length > 0) { + return contractParts[0]; + } + } + return "0"; + } + + private String getPerformanceSalary(AttLedgerBean bean) { + // 自定义方法获取绩效工资 + if (bean.getContract() != null && !bean.getContract().isEmpty()) { + String[] contractParts = bean.getContract().split(","); + if (contractParts.length > 1) { + return contractParts[1]; + } + } + return "0"; + } + + private Long getReportDataId(AttLedgerBean bean) { + // 自定义方法获取 report_data_id,这里只是一个示例实现 + return System.currentTimeMillis(); // 实际应根据业务逻辑获取正确的ID + } + + private String getYearMonth(int index) { + // 自定义方法获取年月,这里只是一个示例实现 + LocalDate date = LocalDate.now().minusMonths(index); + return date.format(DateTimeFormatter.ofPattern("yyyy-MM")); // 实际应根据业务逻辑获取正确的年月 + } +} \ No newline at end of file diff --git a/src/main/java/com/bonus/ahsbs/base/util/IDUtils.java b/src/main/java/com/bonus/ahsbs/base/util/IDUtils.java index aba465c..71e3b07 100644 --- a/src/main/java/com/bonus/ahsbs/base/util/IDUtils.java +++ b/src/main/java/com/bonus/ahsbs/base/util/IDUtils.java @@ -7,6 +7,8 @@ package com.bonus.ahsbs.base.util; */ public class IDUtils { private static byte[] lock = new byte[0]; + private static long lastTimestamp = 0; + private static long sequence = 0; /**位数,默认是8位*/ private final static long w = 100000000; @@ -14,10 +16,34 @@ public class IDUtils { public static String createID() { long r = 0; synchronized (lock) { - r = (long) ((Math.random() + 1) * w); + long timestamp = System.currentTimeMillis(); + // 如果同一毫秒内生成多个ID,增加序列号 + if (timestamp == lastTimestamp) { + sequence = (sequence + 1) % 1000; + // 如果序列号达到上限,则等待下一毫秒 + if (sequence == 0) { + timestamp = waitNextMillis(timestamp); + } + } else { + sequence = 0; + } + lastTimestamp = timestamp; + + // 使用时间戳加上序列号生成唯一ID + return String.valueOf(timestamp * 1000 + sequence); } - - return System.currentTimeMillis() + String.valueOf(r).substring(1); } - -} + + /** + * 等待下一毫秒 + * @param lastTimestamp 上一毫秒时间戳 + * @return 下一毫秒时间戳 + */ + private static long waitNextMillis(long lastTimestamp) { + long timestamp = System.currentTimeMillis(); + while (timestamp <= lastTimestamp) { + timestamp = System.currentTimeMillis(); + } + return timestamp; + } +} \ No newline at end of file diff --git a/src/main/resources/mappers/base/AttLedgerMapper.xml b/src/main/resources/mappers/base/AttLedgerMapper.xml new file mode 100644 index 0000000..ef93c64 --- /dev/null +++ b/src/main/resources/mappers/base/AttLedgerMapper.xml @@ -0,0 +1,143 @@ + + + + + update xbg_att_report_data + set is_active = 0 + + + + update xbg_att_report_data_detail + set is_active = 0 + + + + + + + + + + INSERT INTO xbg_att_report_data ( + id, + name, + id_card, + gender, + ethnicity, + age, + contact_info, + pro_id, + sub_id, + team_id, + post_id, + contract_id, + entry_date, + exit_date, + basic_salary, + performance_salary + ) VALUES + + ( + #{item.id}, + #{item.name}, + #{item.idCard}, + #{item.gender}, + #{item.ethnicity}, + #{item.age}, + #{item.contactInfo}, + #{item.proId}, + #{item.subId}, + #{item.teamId}, + #{item.postId}, + #{item.contractId}, + #{item.entryDate}, + #{item.exitDate}, + #{item.basicSalary}, + #{item.performanceSalary} + ) + + + + + INSERT INTO xbg_att_report_data_detail ( + report_data_id, + `year_month`, + attendance_days + ) VALUES + + ( + #{item.reportDataId}, + #{item.yearMonth}, + #{item.attendanceDays} + ) + + + \ No newline at end of file