zouyu
7 小时以前 1b2f1eb44d9f0de6b9238cfe314988a95c87344a
绩效管理:工时汇总对接MES数据&人员考勤调整
已添加4个文件
已修改8个文件
已删除1个文件
759 ■■■■ 文件已修改
inspect-server/src/main/java/com/ruoyi/inspect/aspect/MoveLocationAfterPushMesStockAspect.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/java/com/ruoyi/inspect/service/impl/StaffAttendanceTrackingRecordServiceImpl.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/java/com/ruoyi/inspect/task/SyncStaffAttendanceRecordSchedule.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/java/com/ruoyi/inspect/util/HourDiffCalculator.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/java/com/ruoyi/inspect/util/TimeDiffCalculator.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
performance-server/src/main/java/com/ruoyi/performance/controller/AuxiliaryOriginalHoursController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
performance-server/src/main/java/com/ruoyi/performance/dto/AuxiliaryAllDto.java 92 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
performance-server/src/main/java/com/ruoyi/performance/service/AuxiliaryOriginalHoursService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
performance-server/src/main/java/com/ruoyi/performance/service/impl/AuxiliaryOriginalHoursServiceImpl.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/api/MesApiUtils.java 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/api/mes/MesApiUtils.java 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/api/mes/model/WorkingHoursRecordSumVO.java 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/src/main/java/com/ruoyi/common/utils/api/mes/model/WorkingHoursRecordTotalVO.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
inspect-server/src/main/java/com/ruoyi/inspect/aspect/MoveLocationAfterPushMesStockAspect.java
@@ -4,11 +4,9 @@
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.basic.pojo.IfsInventoryQuantity;
import com.ruoyi.common.config.mes.MesConfig;
import com.ruoyi.common.config.mes.MesProperties;
import com.ruoyi.common.numgen.NumberGenerator;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.api.MesApiUtils;
import com.ruoyi.common.utils.api.mes.MesApiUtils;
import com.ruoyi.inspect.pojo.IfsSplitOrderRecord;
import com.ruoyi.inspect.service.IfsSplitOrderRecordService;
import lombok.extern.slf4j.Slf4j;
inspect-server/src/main/java/com/ruoyi/inspect/service/impl/StaffAttendanceTrackingRecordServiceImpl.java
@@ -19,6 +19,7 @@
import com.ruoyi.inspect.pojo.StaffAttendanceTrackingRecord;
import com.ruoyi.inspect.service.StaffAttendanceTrackingRecordService;
import com.ruoyi.inspect.util.HourDiffCalculator;
import com.ruoyi.inspect.util.TimeDiffCalculator;
import com.ruoyi.inspect.vo.StaffAttendanceVO;
import com.ruoyi.inspect.vo.StaffClockInVO;
import com.ruoyi.performance.dto.PerformanceShiftMapDto;
@@ -90,6 +91,11 @@
    private final static List<String> syncDeviceCode = Arrays.asList("1001538", "1001539", "1001540", "1001541",
            "1001626", "1001627", "1001628", "1001629");
    /**
     * ä¸Šç­æ—¶é—´åˆ¤å®šè¾¹ç•Œå°æ—¶æ•°
     */
    private final static long WORK_TIME_BOUNDARY = 2L;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean syncAttendanceRecord(LocalDateTime startDate, LocalDateTime endDate) {
@@ -140,9 +146,6 @@
    public IPage<StaffAttendanceVO> pageAttendanceRecord(Page<StaffAttendanceTrackingRecord> page,
            StaffAttendanceDTO staffAttendanceDTO) {
        // æŸ¥è¯¢æ‰“卡记录
        System.out.println(staffAttendanceDTO.getStartDate());
        System.out.println(staffAttendanceDTO.getEndDate());
        System.out.println(ObjectUtils.allNotNull(staffAttendanceDTO.getStartDate(),staffAttendanceDTO.getEndDate()));
        Wrapper<StaffAttendanceTrackingRecord> queryWrapper = Wrappers.<StaffAttendanceTrackingRecord>lambdaQuery()
                .eq(StaffAttendanceTrackingRecord::getEnableReport, Boolean.TRUE)
                .between(ObjectUtils.allNotNull(staffAttendanceDTO.getStartDate(),staffAttendanceDTO.getEndDate()),
@@ -181,10 +184,6 @@
                LocalTime currentShiftStartTime = LocalTime.parse(p.getStartTime(), HHmm);
                LocalDateTime currentShiftStartDateTime = LocalDateTime.of(p.getWorkTime().toLocalDate(),
                        currentShiftStartTime);
                // å½“前班次结束时间
                LocalTime currentShiftEndTime = LocalTime.parse(p.getEndTime(), HHmm);
                LocalDateTime currentShiftEndDateTime = LocalDateTime.of(endDateTime.toLocalDate(),
                        currentShiftEndTime);
                // ä¸‹ä¸€ç­æ¬¡å¼€å§‹æ—¶é—´
                LocalDateTime nextShiftStartDateTime = getShiftStartDateTime(i + 1, performanceShifts,
                        startDateTime.plusDays(1L));
@@ -192,15 +191,21 @@
                    // å¦‚果小时差为负数,表示跨天,结束时间需加一
                    endDateTime = endDateTime.plusDays(1L);
                }
                // å½“前班次结束时间
                LocalTime currentShiftEndTime = LocalTime.parse(p.getEndTime(), HHmm);
                LocalDateTime currentShiftEndDateTime = LocalDateTime.of(endDateTime.toLocalDate(),
                        currentShiftEndTime);
                // è¿‡æ»¤å‡ºå½“前人员当前班次的进/出记录
                LocalDateTime workDateTime = null;
                LocalDateTime offWorkDateTime = null;
                List<StaffAttendanceTrackingRecord> enterRecords = filterAttendanceRecord(p.getPersonCode(),
                        EnterOrExitType.ENTER.getValue(), startDateTime, endDateTime, recordList);
                //上班时间判定边界
                LocalDateTime boundaryTime = currentShiftStartDateTime.minusHours(WORK_TIME_BOUNDARY);
                if (!enterRecords.isEmpty()) {
                    // ä¸Šç­æ—¶é—´å’ŒçŠ¶æ€
                    StaffAttendanceTrackingRecord enterRecord = enterRecords.stream()
                            .filter(s -> !s.getSwingTime().isAfter(currentShiftStartDateTime))
                            .filter(s -> !s.getSwingTime().isAfter(currentShiftStartDateTime) && !s.getSwingTime().isBefore(boundaryTime))
                            .max(Comparator.comparing(StaffAttendanceTrackingRecord::getSwingTime))
                            .orElse(new StaffAttendanceTrackingRecord());
                    if (BeanUtil.isEmpty(enterRecord)) {
@@ -244,14 +249,16 @@
                }
                if (ObjectUtils.allNotNull(workDateTime, offWorkDateTime)) {
                    vo.setActualWorkHours(HourDiffCalculator.getHourDiff(workDateTime.toLocalTime().format(HHmm),
                            offWorkDateTime.toLocalTime().format(HHmm)));
                    vo.setActualWorkHours(TimeDiffCalculator.getHourDiff(workDateTime,
                            offWorkDateTime));
                }
                // èµ‹å€¼
                vo.setShiftId(p.getShift());
                vo.setPersonCode(p.getPersonCode());
                vo.setPersonName(p.getUserName());
                vo.setPlannedWorkHours(hourDiff);
                //应勤时长
                double plannedWorkHours = Math.abs(hourDiff);
                vo.setPlannedWorkHours(plannedWorkHours);
                vo.setSwingDate(startDateTime);
                vo.setWorkDateTime(workDateTime);
                vo.setOffWorkDateTime(offWorkDateTime);
inspect-server/src/main/java/com/ruoyi/inspect/task/SyncStaffAttendanceRecordSchedule.java
@@ -23,12 +23,13 @@
    private StaffAttendanceTrackingRecordService trackingRecordService;
    @Scheduled(cron = "0 0 1 * * ?")
    @Scheduled(cron = "0 0 */12 * * ?")
    public void sync() {
        log.info("--------同步考勤记录定时任务开始--------");
        LocalDate yesterday = LocalDate.now(ZoneId.of("Asia/Shanghai")).minusDays(1L);
        LocalDate now = LocalDate.now(ZoneId.of("Asia/Shanghai"));
        LocalDateTime startTime = LocalDateTime.of(yesterday, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(yesterday, LocalTime.MAX);
        LocalDateTime endTime = LocalDateTime.of(now, LocalTime.MAX);
        trackingRecordService.syncAttendanceRecord(startTime,endTime);
        log.info("--------同步考勤记录定时任务结束--------");
    }
inspect-server/src/main/java/com/ruoyi/inspect/util/HourDiffCalculator.java
@@ -2,6 +2,8 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Objects;
import java.util.regex.Pattern;
@@ -39,6 +41,41 @@
        return hourDiff.doubleValue();
    }
    public static void main(String[] args) {
        System.out.println(getHourDiff("07:38","19:26"));
        LocalDateTime localDateTime = LocalDateTime.of(2026, 3, 30, 7, 38);
        LocalDateTime localDateTime2 = LocalDateTime.of(2026, 3, 30, 19, 26);
        System.out.println(getTimeDifference(localDateTime,localDateTime2));
    }
    /**
     * è®¡ç®—两个时间的差值,返回 å¤©:时:分:秒(每位两位数,支持跨天)
     * @param startTime å¼€å§‹æ—¶é—´
     * @param endTime   ç»“束时间
     * @return æ ¼å¼åŒ–后的时间差(例:01天 01时 30分 05秒)
     */
    public static String getTimeDifference(LocalDateTime startTime, LocalDateTime endTime) {
        // 1. è®¡ç®—两个时间的**总毫秒差**(绝对值,避免时间顺序问题)
        long totalMillis = Math.abs(ChronoUnit.MILLIS.between(startTime, endTime));
        // 2. å®šä¹‰æ—¶é—´å•位常量(毫秒)
        final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;  // 1天
        final long MILLIS_PER_HOUR = 60 * 60 * 1000;       // 1小时
        final long MILLIS_PER_MINUTE = 60 * 1000;          // 1分钟
        final long MILLIS_PER_SECOND = 1000;               // 1秒
        // 3. æ‹†åˆ† å¤©ã€æ—¶ã€åˆ†ã€ç§’
        long days = totalMillis / MILLIS_PER_DAY;
        long remainingMillis = totalMillis % MILLIS_PER_DAY;
        long hours = remainingMillis / MILLIS_PER_HOUR;
        remainingMillis %= MILLIS_PER_HOUR;
        long minutes = remainingMillis / MILLIS_PER_MINUTE;
        long seconds = remainingMillis / MILLIS_PER_SECOND;
        // 4. æ ¼å¼åŒ–:%02d = æ•´æ•°è¡¥é›¶åˆ°ä¸¤ä½æ•°ï¼ˆæ ¸å¿ƒï¼æ»¡è¶³ç²¾ç¡®åˆ°ä¸¤ä½æ•°è¦æ±‚)
        return String.format("%02d天 %02d时 %02d分 %02d秒", days, hours, minutes, seconds);
    }
    /**
     * æ ¡éªŒæ—¶é—´æ ¼å¼æ˜¯å¦ä¸ºHH:mm
     */
inspect-server/src/main/java/com/ruoyi/inspect/util/TimeDiffCalculator.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,62 @@
package com.ruoyi.inspect.util;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
/**
 * LocalDateTime æ—¶é—´å·®è®¡ç®—工具
 * åŠŸèƒ½ï¼šä¼ å…¥ä¸¤ä¸ªæ—¶é—´ï¼Œè¿”å›žä¿ç•™ä¸¤ä½å°æ•°çš„æ—¶é—´å·®ï¼ˆå¤©/小时/分钟/秒)
 */
public class TimeDiffCalculator {
    // çº³ç§’换算常量(最精确的时间单位,无精度丢失)
    private static final long NANOS_PER_DAY = 24L * 60 * 60 * 1000000000;
    private static final long NANOS_PER_HOUR = 60L * 60 * 1000000000;
    private static final long NANOS_PER_MINUTE = 60L * 1000000000;
    private static final long NANOS_PER_SECOND = 1000000000L;
    /**
     * è®¡ç®— å¤©æ•° å·®ï¼Œä¿ç•™ä¸¤ä½å°æ•°
     */
    public static double getDayDiff(LocalDateTime start, LocalDateTime end) {
        return calculateDiff(start, end, NANOS_PER_DAY);
    }
    /**
     * è®¡ç®— å°æ—¶ å·®ï¼Œä¿ç•™ä¸¤ä½å°æ•°
     */
    public static double getHourDiff(LocalDateTime start, LocalDateTime end) {
        return calculateDiff(start, end, NANOS_PER_HOUR);
    }
    /**
     * è®¡ç®— åˆ†é’Ÿ å·®ï¼Œä¿ç•™ä¸¤ä½å°æ•°
     */
    public static double getMinuteDiff(LocalDateTime start, LocalDateTime end) {
        return calculateDiff(start, end, NANOS_PER_MINUTE);
    }
    /**
     * è®¡ç®— ç§’ å·®ï¼Œä¿ç•™ä¸¤ä½å°æ•°
     */
    public static double getSecondDiff(LocalDateTime start, LocalDateTime end) {
        return calculateDiff(start, end, NANOS_PER_SECOND);
    }
    /**
     * ç»Ÿä¸€è®¡ç®—逻辑(抽离公共代码)
     * @param unitNanos ç›®æ ‡å•位对应的纳秒数
     */
    private static double calculateDiff(LocalDateTime start, LocalDateTime end, long unitNanos) {
        // 1. è®¡ç®—时间差,取绝对值
        Duration duration = Duration.between(start, end).abs();
        // 2. çº³ç§’转BigDecimal,精确计算
        BigDecimal totalNanos = new BigDecimal(duration.toNanos());
        BigDecimal unit = new BigDecimal(unitNanos);
        // 3. é™¤æ³•运算,保留2位小数,四舍五入
        return totalNanos.divide(unit, 2, RoundingMode.HALF_UP).doubleValue();
    }
}
performance-server/src/main/java/com/ruoyi/performance/controller/AuxiliaryOriginalHoursController.java
@@ -41,4 +41,11 @@
    public Result selectAuxiliaryAllByMonth(AuxiliaryOriginalHoursLookDto dto){
        return Result.success(auxiliaryOriginalHoursService.selectAuxiliaryAllByMonth(dto));
    }
    @ApiOperation(value = "导出工时汇总")
    @GetMapping("/exportWorkHoursTotal")
    public void exportWorkHoursTotal(HttpServletResponse response,AuxiliaryOriginalHoursLookDto dto){
        auxiliaryOriginalHoursService.exportWorkHoursTotal(response,dto);
    }
}
performance-server/src/main/java/com/ruoyi/performance/dto/AuxiliaryAllDto.java
@@ -1,5 +1,7 @@
package com.ruoyi.performance.dto;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -18,22 +20,88 @@
@NoArgsConstructor
public class AuxiliaryAllDto {
    @ApiModelProperty("产量工时")
    private BigDecimal yieldHour;
    @ApiModelProperty("辅助工时")
    private BigDecimal subsidiaryHour;
    @ApiModelProperty("总工时")
    private BigDecimal totalHour;
    @ExcelIgnore
    @ApiModelProperty("人员id")
    private Integer userId;
    @ApiModelProperty("姓名")
    private String userName;
    @ExcelIgnore
    @ApiModelProperty("月份")
    private String month;
    @ExcelProperty(value = {"序号","序号"},index = 0)
    @ApiModelProperty("导出序号")
    private Integer excelIndex;
    @ExcelProperty(value = {"姓名","姓名"},index = 1)
    @ApiModelProperty("姓名")
    private String userName;
    @ExcelProperty(value = {"耐丝域MES","工序绩效"},index = 2)
    @ApiModelProperty("工序绩效-耐丝域")
    private BigDecimal operationPerformanceByNS = BigDecimal.ZERO;
    @ExcelProperty(value = {"耐丝域MES","成品绩效"},index = 3)
    @ApiModelProperty("成品绩效-耐丝域")
    private BigDecimal productPerformanceByNS = BigDecimal.ZERO;
    @ExcelProperty(value = {"耐丝域MES","巡检绩效"},index = 4)
    @ApiModelProperty("巡检绩效-耐丝域")
    private BigDecimal onsiteInspWageByNS = BigDecimal.ZERO;
    @ExcelProperty(value = {"耐丝域MES","杂工工资"},index = 5)
    @ApiModelProperty("杂工工资-耐丝域")
    private BigDecimal handymanWageByNS = BigDecimal.ZERO;
    @ExcelProperty(value = {"科技域MES","工序绩效"},index = 6)
    @ApiModelProperty("工序绩效-科技域")
    private BigDecimal operationPerformanceByKJ = BigDecimal.ZERO;
    @ExcelProperty(value = {"科技域MES","成品绩效"},index = 7)
    @ApiModelProperty("成品绩效-科技域")
    private BigDecimal productPerformanceByKJ = BigDecimal.ZERO;
    @ExcelProperty(value = {"科技域MES","巡检绩效"},index = 8)
    @ApiModelProperty("巡检绩效-科技域")
    private BigDecimal onsiteInspWageByKJ = BigDecimal.ZERO;
    @ExcelProperty(value = {"科技域MES","杂工工资"},index = 9)
    @ApiModelProperty("杂工工资-科技域")
    private BigDecimal handymanWageByKJ = BigDecimal.ZERO;
    @ExcelProperty(value = {"MES汇总","工序绩效"},index = 10)
    @ApiModelProperty("工序绩效-科技域")
    private BigDecimal operationPerformance = BigDecimal.ZERO;
    @ExcelProperty(value = {"MES汇总","成品绩效"},index = 11)
    @ApiModelProperty("成品绩效-科技域")
    private BigDecimal productPerformance = BigDecimal.ZERO;
    @ExcelProperty(value = {"MES汇总","巡检绩效"},index = 12)
    @ApiModelProperty("巡检绩效-科技域")
    private BigDecimal onsiteInspWage = BigDecimal.ZERO;
    @ExcelProperty(value = {"MES汇总","杂工工资"},index = 13)
    @ApiModelProperty("杂工工资-科技域")
    private BigDecimal handymanWage = BigDecimal.ZERO;
    @ExcelProperty(value = {"LIMS","产量工时"},index = 14)
    @ApiModelProperty("产量工时")
    private BigDecimal yieldHour;
    @ExcelProperty(value = {"LIMS","辅助工时"},index = 15)
    @ApiModelProperty("辅助工时")
    private BigDecimal subsidiaryHour;
    @ExcelProperty(value = {"LIMS","总工时"},index = 16)
    @ApiModelProperty("总工时")
    private BigDecimal totalHour;
    public AuxiliaryAllDto(BigDecimal yieldHour, BigDecimal subsidiaryHour, BigDecimal totalHour, Integer userId, String userName, String month) {
        this.yieldHour = yieldHour;
        this.subsidiaryHour = subsidiaryHour;
        this.totalHour = totalHour;
        this.userId = userId;
        this.userName = userName;
        this.month = month;
    }
}
performance-server/src/main/java/com/ruoyi/performance/service/AuxiliaryOriginalHoursService.java
@@ -27,4 +27,6 @@
     * @return
     */
    List<AuxiliaryAllDto> selectAuxiliaryAllByMonth(AuxiliaryOriginalHoursLookDto dto);
    void exportWorkHoursTotal(HttpServletResponse response, AuxiliaryOriginalHoursLookDto dto);
}
performance-server/src/main/java/com/ruoyi/performance/service/impl/AuxiliaryOriginalHoursServiceImpl.java
@@ -2,6 +2,7 @@
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -11,9 +12,16 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.entity.User;
import com.ruoyi.common.enums.ContractType;
import com.ruoyi.common.enums.StaffSkillLevelType;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.api.mes.MesApiUtils;
import com.ruoyi.common.utils.api.mes.model.WorkingHoursRecordSumVO;
import com.ruoyi.common.utils.api.mes.model.WorkingHoursRecordTotalVO;
import com.ruoyi.common.utils.excel.EasyExcelUtils;
import com.ruoyi.common.utils.excel.FullCustomAutoWidthHandler;
import com.ruoyi.common.utils.excel.HeaderContentRowHeightHandler;
import com.ruoyi.performance.dto.AuxiliaryAllDto;
import com.ruoyi.performance.dto.AuxiliaryCorrectionHoursDto;
import com.ruoyi.performance.dto.AuxiliaryOriginalHoursDto;
import com.ruoyi.performance.dto.AuxiliaryOriginalHoursLookDto;
import com.ruoyi.performance.mapper.AuxiliaryCorrectionHoursMapper;
@@ -23,8 +31,10 @@
import com.ruoyi.performance.pojo.AuxiliaryCorrectionHours;
import com.ruoyi.performance.service.AuxiliaryOriginalHoursService;
import com.ruoyi.system.mapper.UserMapper;
import org.apache.commons.math3.analysis.function.Power;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@@ -33,11 +43,14 @@
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@Slf4j
@Service
public class AuxiliaryOriginalHoursServiceImpl implements AuxiliaryOriginalHoursService {
@@ -55,6 +68,9 @@
    @Resource
    AuxiliaryCorrectionHoursMapper auxiliaryCorrectionHoursMapper;
    @Autowired
    private MesApiUtils mesApiUtils;
    @Override
    public IPage<AuxiliaryOriginalHoursDto> selectAuxiliaryOriginalHours(Page page, AuxiliaryOriginalHoursLookDto auxiliaryOriginalHoursLookDto) {
@@ -231,7 +247,18 @@
        dto.setAssistBeginDate(beginDate);
        dto.setAssistEndDate(endDate);
        //查询KJNS和ZTNS域的MES绩效数据
        Map<String, Object> params = new HashMap<>();
        params.put("year",date.getYear());
        params.put("month",date.getMonthValue());
        List<WorkingHoursRecordTotalVO> hoursRecordSumByNS = new ArrayList<>();
        List<WorkingHoursRecordTotalVO> hoursRecordSumByKJ = new ArrayList<>();
        try {
            hoursRecordSumByNS = mesApiUtils.getCheckWorkingHoursRecordSum(ContractType.ZTNS.getValue(), params);
            hoursRecordSumByKJ = mesApiUtils.getCheckWorkingHoursRecordSum(ContractType.KJNS.getValue(), params);
        }catch (Exception e){
            log.error("工时汇总查询异常:{}",e.getMessage());
        }
        // æŸ¥è¯¢äº§é‡å·¥æ—¶
        List<AuxiliaryAllDto> auxiliaryAllDtos = auxiliaryOutputWorkingHoursMapper.selectAuxiliaryAllByMonth(dto, userIds);
@@ -257,11 +284,60 @@
            BigDecimal total = (auxiliaryAllDto.getYieldHour() != null ? auxiliaryAllDto.getYieldHour() : BigDecimal.ZERO)
                    .add(auxiliaryAllDto.getSubsidiaryHour() != null ? auxiliaryAllDto.getSubsidiaryHour() : BigDecimal.ZERO);
            auxiliaryAllDto.setTotalHour(total);
            if(!hoursRecordSumByNS.isEmpty()){
                WorkingHoursRecordTotalVO totalVOByNS = hoursRecordSumByNS.stream().filter(f -> StringUtils.equals(f.getChecker(), auxiliaryAllDto.getUserName())).findFirst().orElse(null);
                if(ObjectUtils.isNotNull(totalVOByNS)){
                    auxiliaryAllDto.setHandymanWageByNS(totalVOByNS.getHandymanWage());
                    auxiliaryAllDto.setOnsiteInspWageByNS(totalVOByNS.getOnsiteInspWage());
                    auxiliaryAllDto.setOperationPerformanceByNS(totalVOByNS.getOperationPerformance());
                    auxiliaryAllDto.setProductPerformanceByNS(totalVOByNS.getProductPerformance());
                }
            }
            if(!hoursRecordSumByKJ.isEmpty()){
                WorkingHoursRecordTotalVO totalVOByKJ = hoursRecordSumByKJ.stream().filter(f -> StringUtils.equals(f.getChecker(), auxiliaryAllDto.getUserName())).findFirst().orElse(null);
                if(ObjectUtils.isNotNull(totalVOByKJ)){
                    auxiliaryAllDto.setHandymanWageByKJ(totalVOByKJ.getHandymanWage());
                    auxiliaryAllDto.setOnsiteInspWageByKJ(totalVOByKJ.getOnsiteInspWage());
                    auxiliaryAllDto.setOperationPerformanceByKJ(totalVOByKJ.getOperationPerformance());
                    auxiliaryAllDto.setProductPerformanceByKJ(totalVOByKJ.getProductPerformance());
                }
            }
        }
        return auxiliaryAllDtos;
    }
    @Override
    public void exportWorkHoursTotal(HttpServletResponse response, AuxiliaryOriginalHoursLookDto dto) {
        response.reset();
        try {
            //1.组装数据
            AtomicInteger excelIndex = new AtomicInteger(1);
            List<AuxiliaryAllDto> auxiliaryAllDtos = selectAuxiliaryAllByMonth(dto);
            auxiliaryAllDtos.forEach(a->{
                a.setExcelIndex(excelIndex.getAndIncrement());
                a.setOperationPerformance(a.getOperationPerformanceByKJ().add(a.getOperationPerformanceByNS()));//工序绩效汇总
                a.setOnsiteInspWage(a.getOnsiteInspWageByKJ().add(a.getOnsiteInspWageByNS()));//巡检绩效汇总
                a.setProductPerformance(a.getProductPerformanceByKJ().add(a.getProductPerformanceByNS()));//成品绩效汇总
                a.setHandymanWage(a.getHandymanWageByKJ().add(a.getHandymanWageByNS()));//杂工工资
            });
            //2.导出
            String fileName = "中天耐丝质量部工时汇总"+ ExcelTypeEnum.XLSX;
            fileName =  URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
            response.setContentType("application/vnd.ms-excel");
            response.setHeader("Cache-Control", "no-cache");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            EasyExcel.write(response.getOutputStream())
                    .head(AuxiliaryAllDto.class)
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    .sheet("Sheet 1")
                    .doWrite(auxiliaryAllDtos);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    private Map<String, AuxiliaryOriginalHoursDto> getData(List<Map<String, Object>> objectMaps, String type) {
        Map<String, AuxiliaryOriginalHoursDto> dtoMap = new HashMap<>();
        for (Map<String, Object> objectMap : objectMaps) {
ruoyi-common/src/main/java/com/ruoyi/common/utils/api/MesApiUtils.java
ÎļþÒÑɾ³ý
ruoyi-common/src/main/java/com/ruoyi/common/utils/api/mes/MesApiUtils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,150 @@
package com.ruoyi.common.utils.api.mes;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference;
import com.ruoyi.common.config.mes.MesConfig;
import com.ruoyi.common.config.mes.MesProperties;
import com.ruoyi.common.utils.api.mes.model.WorkingHoursRecordSumVO;
import com.ruoyi.common.utils.api.mes.model.WorkingHoursRecordTotalVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Slf4j
@Component
public class MesApiUtils {
    @Autowired
    private MesConfig mesConfig;
    /**
     * æ ¹æ®å·¥åŽ‚åŸŸå›žåŽ»mes配置
     * @param contract
     * @return
     */
    public MesProperties getMesPropertiesByContract(String contract){
        return mesConfig.getProps().stream().filter(f-> org.apache.commons.lang3.StringUtils.equals(f.getContract(),contract)).findFirst().orElse(new MesProperties());
    }
    /**
     * èŽ·å–token请求链接
     * @return
     */
    private String getAuthTokenUrl(String ip) {
        return ip + "/auth/oauth/token?randomStr=blockPuzzle&grant_type=password";
    }
    /**
     * æ–°å¢žå®žæ—¶åº“存请求链接
     * @return
     */
    private String getBatchAddStockUrl(String ip){
        return ip + "/mes/stock/batchAddStock";
    }
    /**
     * æ£€æµ‹å·¥æ—¶ç»Ÿè®¡æŸ¥è¯¢è¯·æ±‚链接
     * @return
     */
    private String getCheckWorkingHoursRecordSumUrl(String ip){
        return ip + "/mes/checkWorkingHoursRecord/getCheckWorkingHoursRecordSum";
    }
    /**
     * èŽ·å–mes系统token
     * @return æŽ¥å£å“åº”结果
     */
    public String getToken(MesProperties mesProperties){
        try{
            String bodyStr = "username="+mesProperties.getUser()+"&password="+mesProperties.getPassword();
            String response = HttpRequest.post(getAuthTokenUrl(mesProperties.getIp()))
                    .header("Authorization", "Basic cGlnOnBpZw==")
                    .header("Content-Type", "application/x-www-form-urlencoded")
                    .body(bodyStr,"application/x-www-form-urlencoded").execute().body();
            JSONObject responseObj = JSONObject.parseObject(response);
            if(Objects.nonNull(responseObj.getString("access_token"))){
                return "Bearer " + responseObj.getString("access_token");
            }else{
                throw new RuntimeException(responseObj.getString("msg"));
            }
        }catch (Exception e){
            throw new RuntimeException("获取MES系统token接口异常:"+e.getMessage());
        }
    }
    /**
     * mes新增实时库存接口
     * @param contract å·¥åŽ‚åŸŸ
     * @param requestJsonStr è¯·æ±‚参数json字符串
     * @return æŽ¥å£å“åº”结果
     */
    public boolean batchAddStock(String contract,String requestJsonStr){
        try{
            MesProperties mesProperties = getMesPropertiesByContract(contract);
            String response = HttpRequest.post(getBatchAddStockUrl(mesProperties.getIp()))
                    .header("Authorization", getToken(mesProperties))
                    .header("Content-Type", "application/json")
                    .body(requestJsonStr)
                    .execute()
                    .body();
            JSONObject entries = JSONObject.parseObject(response);
            if(entries.getInteger("code")==0){
                return true;
            }else{
                throw new RuntimeException("【"+contract+"】同步到MES失败:"+entries.getString("msg"));
            }
        }catch (Exception e){
            throw new RuntimeException("【"+contract+"】同步MES实时库存接口异常:"+e.getMessage());
        }
    }
    /**
     * æ£€æµ‹å·¥æ—¶ç»Ÿè®¡æŸ¥è¯¢
     * @return
     */
    public List<WorkingHoursRecordTotalVO> getCheckWorkingHoursRecordSum(String contract,Map<String,Object> params){
        try {
            MesProperties mesProperties = getMesPropertiesByContract(contract);
            String response = HttpRequest.get(getCheckWorkingHoursRecordSumUrl(mesProperties.getIp()))
                    .header("Authorization", getToken(mesProperties))
                    .header("Content-Type", "application/x-www-form-urlencoded")
                    .form(params)
                    .execute()
                    .body();
            JSONObject entries = JSONObject.parseObject(response);
            if(entries.getInteger("code")==0){
                List<WorkingHoursRecordTotalVO> totalVOS = new ArrayList<>();
                List<WorkingHoursRecordSumVO> parseObject = JSONObject.parseObject(entries.getString("data"), new TypeReference<List<WorkingHoursRecordSumVO>>() {}.getType());
                parseObject.forEach(p->{
                    WorkingHoursRecordSumVO.WorkHoursVO monthTotal = p.getWorkingHours().stream().filter(f -> StringUtils.equals(f.getDutyDate(), "月度汇总")).findFirst().orElse(null);
                    WorkingHoursRecordTotalVO totalVO = new WorkingHoursRecordTotalVO();
                    if(ObjectUtils.isNotEmpty(monthTotal)){
                        BeanUtil.copyProperties(monthTotal,totalVO);
                    }
                    totalVO.setYear(p.getYear());
                    totalVO.setMonth(p.getMonth());
                    totalVO.setChecker(p.getChecker());
                    totalVOS.add(totalVO);
                });
                return totalVOS;
            }else{
                throw new RuntimeException("【"+contract+"】拉取MES检测工时失败:"+entries.getString("msg"));
            }
        }catch (Exception e){
            throw new RuntimeException("【"+contract+"】拉取MES检测工时接口异常:"+e.getMessage());
        }
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/api/mes/model/WorkingHoursRecordSumVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,103 @@
package com.ruoyi.common.utils.api.mes.model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
 * åŒæ­¥mes检测工时响应对象
 */
@Data
public class WorkingHoursRecordSumVO {
    /**
     * å¹´ä»½
     */
    @ApiModelProperty("年份")
    private Integer year;
    /**
     * æœˆä»½
     */
    @ApiModelProperty("月份")
    private Integer month;
    /**
     * æ£€æµ‹äºº
     */
    @ApiModelProperty("检测人")
    private String checker;
    /**
     * æ£€æµ‹äººid
     */
    @ApiModelProperty("检测人id")
    private Long staffId;
    /**
     * å·¥æ—¶åˆ—表
     */
    @ApiModelProperty("工时列表")
    private List<WorkHoursVO> workingHours;
    @Data
    public static class WorkHoursVO {
        /**
         * æ—¥æœŸ
         */
        @ApiModelProperty("日期")
        private String dutyDate;
        /**
         * å·¥åºåˆ†å€¼
         */
        @ApiModelProperty("工序分值")
        private BigDecimal operationScore;
        /**
         * å·¥åºç»©æ•ˆ
         */
        @ApiModelProperty("工序绩效")
        private BigDecimal operationPerformance;
        /**
         * æˆå“åˆ†å€¼
         */
        @ApiModelProperty("成品分值")
        private BigDecimal productScore;
        /**
         * æˆå“ç»©æ•ˆ
         */
        @ApiModelProperty("成品绩效")
        private BigDecimal productPerformance;
        /**
         * æ‚工工时
         */
        @ApiModelProperty("杂工工时")
        private BigDecimal handymanHours;
        /**
         * æ‚工工资
         */
        @ApiModelProperty("杂工工资")
        private BigDecimal handymanWage;
        /**
         * å·¡æ£€å·¥èµ„
         */
        @ApiModelProperty("巡检工资")
        private BigDecimal onsiteInspWage;
        /**
         * æ±‡æ€»
         */
        @ApiModelProperty("汇总")
        private BigDecimal total;
    }
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/api/mes/model/WorkingHoursRecordTotalVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,84 @@
package com.ruoyi.common.utils.api.mes.model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class WorkingHoursRecordTotalVO {
    /**
     * å¹´ä»½
     */
    @ApiModelProperty("年份")
    private Integer year;
    /**
     * æœˆä»½
     */
    @ApiModelProperty("月份")
    private Integer month;
    /**
     * æ£€æµ‹äºº
     */
    @ApiModelProperty("检测人")
    private String checker;
    /**
     * æ—¥æœŸ
     */
    @ApiModelProperty("日期")
    private String dutyDate;
    /**
     * å·¥åºåˆ†å€¼
     */
    @ApiModelProperty("工序分值")
    private BigDecimal operationScore;
    /**
     * å·¥åºç»©æ•ˆ
     */
    @ApiModelProperty("工序绩效")
    private BigDecimal operationPerformance;
    /**
     * æˆå“åˆ†å€¼
     */
    @ApiModelProperty("成品分值")
    private BigDecimal productScore;
    /**
     * æˆå“ç»©æ•ˆ
     */
    @ApiModelProperty("成品绩效")
    private BigDecimal productPerformance;
    /**
     * æ‚工工时
     */
    @ApiModelProperty("杂工工时")
    private BigDecimal handymanHours;
    /**
     * æ‚工工资
     */
    @ApiModelProperty("杂工工资")
    private BigDecimal handymanWage;
    /**
     * å·¡æ£€å·¥èµ„
     */
    @ApiModelProperty("巡检工资")
    private BigDecimal onsiteInspWage;
    /**
     * æ±‡æ€»
     */
    @ApiModelProperty("汇总")
    private BigDecimal total;
}