package com.gs.dingtalk; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.gs.dingtalk.config.URLEncoder; import com.gs.dingtalk.entity.QwStaff; import com.gs.dingtalk.mapper.QwStaffMapper; import com.gs.dingtalk.service.QwCheckinDataService; import com.gs.dingtalk.service.SendDingtalkService; import com.gs.dingtalk.service.SimpleExample; import com.gs.dingtalk.service.VwCjScSjTsBbService; import com.gs.dingtalk.service.WorkWXService; import com.gs.dingtalk.service.QwCheckinDayDataService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; @SpringBootTest class DeviceReceivingApplicationTests { @Autowired private VwCjScSjTsBbService vwCjScSjTsBbService; @Autowired private WorkWXService workWXService; @Autowired private QwStaffMapper qwStaffMapper; @Autowired private QwCheckinDataService qwCheckinDataService; @Autowired private QwCheckinDayDataService qwCheckinDayDataService; /** * 测试导出生产数据并发送钉钉消息 * 功能:查询VW_CJ_SC_SJ_TS_BB表数据 -> 导出Excel -> 发送钉钉文件消息 */ @Test void testExportAndSendProductionData() throws Exception { System.out.println("=== 开始测试导出生产数据并发送钉钉 ==="); try { boolean result = vwCjScSjTsBbService.exportAndSendToDingtalk(); if (result) { System.out.println("✓ 生产数据导出并发送成功"); System.out.println(" - 数据已从 VW_CJ_SC_SJ_TS_BB 表查询"); System.out.println(" - Excel 文件已生成并保存到 D:\\BIFile\\"); System.out.println(" - 钉钉文件消息已发送"); } else { System.out.println("✗ 生产数据导出或发送失败"); } } catch (Exception e) { System.out.println("✗ 导出并发送时发生异常: " + e.getMessage()); e.printStackTrace(); } System.out.println("=== 测试结束 ==="); } @Test void testGetCheckinDataByQwStaff() { System.out.println("=== 开始测试通过QW_STAFF表获取打卡数据 ==="); // 企业微信打卡接口限制: // 1. 获取记录时间跨度不超过30天 // 2. 用户列表不超过100个。若用户超过100个,请分批获取(已在Service层实现自动分批) // 3. 接口返回最多3000条打卡数据 // 4. 标准打卡时间只对于固定排班和自定义排班两种类型有效 // 5. 接口调用频率限制为600次/分钟(已在Service层实现批次间延迟) try { long currentTime = System.currentTimeMillis() / 1000; long oneDaySeconds = 86400; long thirtyDaysSeconds = 30 * oneDaySeconds; long endTime = (currentTime / oneDaySeconds) * oneDaySeconds - 1; long startTime = endTime - oneDaySeconds + 1; // 验证时间跨度不超过30天 long timeSpan = endTime - startTime; if (timeSpan > thirtyDaysSeconds) { System.out.println("✗ 时间跨度超过30天限制: " + (timeSpan / oneDaySeconds) + "天"); return; } System.out.println(" - 开始时间: " + new java.util.Date(startTime * 1000)); System.out.println(" - 结束时间: " + new java.util.Date(endTime * 1000)); System.out.println(" - 时间跨度: " + (timeSpan / oneDaySeconds) + "天 (限制: ≤30天)"); // 获取用户总数 long totalUsers = qwStaffMapper.selectCount(new LambdaQueryWrapper() .isNotNull(QwStaff::getAccount) .ne(QwStaff::getAccount, "")); System.out.println(" - QW_STAFF表用户总数: " + totalUsers); if (totalUsers > 100) { int batchCount = (int) ((totalUsers + 99) / 100); System.out.println(" - 将自动分批处理: " + batchCount + "批 (每批≤100用户)"); } List checkinDataList = workWXService.getCheckinDataByQwStaff(startTime, endTime); if (checkinDataList != null && !checkinDataList.isEmpty()) { System.out.println("✓ 成功获取打卡数据"); System.out.println(" - 打卡记录总数: " + checkinDataList.size()); System.out.println(" - 前5条数据:"); checkinDataList.stream().limit(5).forEach(data -> { System.out.println(" * userid: " + data.getUserid() + ", 打卡时间: " + new java.util.Date(data.getCheckinTime() * 1000) + ", 打卡类型: " + data.getCheckinType() + ", 异常类型: " + data.getExceptionType() + ", 地点: " + data.getLocationDetail()); }); // 保存到数据库 System.out.println(" - 开始保存到数据库..."); int insertCount = qwCheckinDataService.saveCheckinDataBatch(checkinDataList); System.out.println("✓ 保存完成,新增记录数: " + insertCount + ", 跳过(已存在): " + (checkinDataList.size() - insertCount)); } else { System.out.println("✗ 获取的打卡数据为空(可能QW_STAFF表无数据或时间范围内无打卡记录)"); } } catch (IOException e) { System.out.println("✗ 获取打卡数据失败: " + e.getMessage()); e.printStackTrace(); } System.out.println("=== 测试结束 ==="); } @Test void testGetCheckinDataById() { System.out.println("=== 开始测试通过QW_STAFF表获取打卡数据 ==="); QwStaff qwStaff = qwStaffMapper.selectById(3); if (qwStaff == null || qwStaff.getAccount() == null || qwStaff.getAccount().isEmpty()) { System.out.println("✗ 未找到ID为3的员工或员工account为空"); return; } System.out.println(" - 员工姓名: " + qwStaff.getName()); System.out.println(" - 员工账号: " + qwStaff.getAccount()); try { long currentTime = System.currentTimeMillis() / 1000; long oneDaySeconds = 86400; long thirtyDaysSeconds = 30 * oneDaySeconds; // 昨天结束时间(23:59:59) long yesterdayEnd = ((currentTime / oneDaySeconds) - 1) * oneDaySeconds + oneDaySeconds - 1; // 20天前开始时间(00:00:00) long twentyDaysAgoStart = yesterdayEnd - 20 * oneDaySeconds + 1; long endTime = yesterdayEnd; long startTime = twentyDaysAgoStart; // 验证时间跨度不超过30天 long timeSpan = endTime - startTime; if (timeSpan > thirtyDaysSeconds) { System.out.println("✗ 时间跨度超过30天限制: " + (timeSpan / oneDaySeconds) + "天"); return; } System.out.println(" - 开始时间: " + new java.util.Date(startTime * 1000) + " (20天前)"); System.out.println(" - 结束时间: " + new java.util.Date(endTime * 1000) + " (昨天)"); System.out.println(" - 时间跨度: " + (timeSpan / oneDaySeconds) + "天"); List useridList = new java.util.ArrayList<>(); useridList.add(qwStaff.getAccount()); List checkinDataList = workWXService.getCheckinData(startTime, endTime, useridList); if (checkinDataList != null && !checkinDataList.isEmpty()) { System.out.println("✓ 成功获取打卡数据"); System.out.println(" - 打卡记录总数: " + checkinDataList.size()); checkinDataList.forEach(data -> { System.out.println(" * 打卡时间: " + new java.util.Date(data.getCheckinTime() * 1000) + ", 打卡类型: " + data.getCheckinType() + ", 异常类型: " + data.getExceptionType() + ", 地点: " + data.getLocationDetail()); }); } else { System.out.println("✗ 该员工在时间范围内无打卡记录"); } } catch (IOException e) { System.out.println("✗ 获取打卡数据失败: " + e.getMessage()); e.printStackTrace(); } System.out.println("=== 测试结束 ==="); } @Test void testGetWorkWXUserList() { System.out.println("=== 开始测试获取企业微信用户列表 ==="); try { List userList = workWXService.getUserList(); if (userList != null && !userList.isEmpty()) { System.out.println("✓ 成功获取企业微信用户列表"); System.out.println(" - 用户总数: " + userList.size()); System.out.println(" - 前10条数据:"); userList.stream().limit(10).forEach(user -> { System.out.println(" * userid: " + user.getUserid() + ", 姓名: " + user.getName() + ", 部门: " + user.getDepartment()); }); } else { System.out.println("✗ 获取的用户列表为空"); } } catch (IOException e) { System.out.println("✗ 获取用户列表失败: " + e.getMessage()); e.printStackTrace(); } System.out.println("=== 测试结束 ==="); } @Test void testSyncUsersToQwStaff() { System.out.println("=== 开始测试同步企业微信用户到QW_STAFF表 ==="); try { int insertCount = workWXService.syncUsersToQwStaff(); System.out.println("✓ 同步完成"); System.out.println(" - 新增用户数: " + insertCount); } catch (IOException e) { System.out.println("✗ 同步用户失败: " + e.getMessage()); e.printStackTrace(); } System.out.println("=== 测试结束 ==="); } /** * 测试获取打卡日报数据 * 接口限制:100次/分钟,时间跨度不超过30天 */ @Test void testGetCheckinDayData() { System.out.println("=== 开始测试获取打卡日报数据 ==="); try { long currentTime = System.currentTimeMillis() / 1000; long oneDaySeconds = 86400; // 获取昨天的日报数据(starttime和endtime需要是同一天) long yesterdayStart = ((currentTime / oneDaySeconds) - 1) * oneDaySeconds; long startTime = yesterdayStart; long endTime = yesterdayStart; // 日报接口starttime和endtime需相同 System.out.println(" - 查询日期: " + new java.util.Date(startTime * 1000)); // 获取用户总数 long totalUsers = qwStaffMapper.selectCount(new LambdaQueryWrapper() .isNotNull(QwStaff::getAccount) .ne(QwStaff::getAccount, "")); System.out.println(" - QW_STAFF表用户总数: " + totalUsers); List dayDataList = workWXService.getCheckinDayDataByQwStaff(startTime, endTime); if (dayDataList != null && !dayDataList.isEmpty()) { System.out.println("✓ 成功获取打卡日报数据"); System.out.println(" - 日报记录总数: " + dayDataList.size()); System.out.println(" - 前5条数据:"); dayDataList.stream().limit(5).forEach(data -> { WorkWXService.BaseInfo baseInfo = data.getBaseInfo(); WorkWXService.SummaryInfo summaryInfo = data.getSummaryInfo(); System.out.println(" * 姓名: " + (baseInfo != null ? baseInfo.getName() : "N/A") + ", 账号: " + (baseInfo != null ? baseInfo.getAcctid() : "N/A") + ", 部门: " + (baseInfo != null ? baseInfo.getDepartsName() : "N/A") + ", 打卡次数: " + (summaryInfo != null ? summaryInfo.getCheckinCount() : 0) + ", 实际工时(秒): " + (summaryInfo != null ? summaryInfo.getRegularWorkSec() : 0) + ", 标准工时(秒): " + (summaryInfo != null ? summaryInfo.getStandardWorkSec() : 0)); // 打印异常信息 if (data.getExceptionInfos() != null && !data.getExceptionInfos().isEmpty()) { data.getExceptionInfos().forEach(ex -> { String exType = getExceptionTypeName(ex.getException()); System.out.println(" 异常: " + exType + ", 次数: " + ex.getCount() + ", 时长(秒): " + ex.getDuration()); }); } }); // 保存到数据库 System.out.println(" - 开始保存打卡日报数据到数据库..."); int insertCount = qwCheckinDayDataService.saveDayDataBatch(dayDataList); System.out.println("✓ 保存完成,新增记录数: " + insertCount + ", 更新(已存在): " + (dayDataList.size() - insertCount)); } else { System.out.println("✗ 获取的打卡日报数据为空"); } } catch (IOException e) { System.out.println("✗ 获取打卡日报数据失败: " + e.getMessage()); e.printStackTrace(); } System.out.println("=== 测试结束 ==="); } /** * 测试获取指定员工的打卡日报数据 */ @Test void testGetCheckinDayDataById() { System.out.println("=== 开始测试获取指定员工打卡日报数据 ==="); QwStaff qwStaff = qwStaffMapper.selectById(3); if (qwStaff == null || qwStaff.getAccount() == null || qwStaff.getAccount().isEmpty()) { System.out.println("✗ 未找到ID为3的员工或员工account为空"); return; } System.out.println(" - 员工姓名: " + qwStaff.getName()); System.out.println(" - 员工账号: " + qwStaff.getAccount()); try { long currentTime = System.currentTimeMillis() / 1000; long oneDaySeconds = 86400; // 获取昨天的日报 long yesterdayStart = ((currentTime / oneDaySeconds) - 1) * oneDaySeconds; long startTime = yesterdayStart; long endTime = yesterdayStart; System.out.println(" - 查询日期: " + new java.util.Date(startTime * 1000)); List useridList = new java.util.ArrayList<>(); useridList.add(qwStaff.getAccount()); List dayDataList = workWXService.getCheckinDayData(startTime, endTime, useridList); if (dayDataList != null && !dayDataList.isEmpty()) { System.out.println("✓ 成功获取打卡日报数据"); dayDataList.forEach(data -> { WorkWXService.BaseInfo baseInfo = data.getBaseInfo(); WorkWXService.SummaryInfo summaryInfo = data.getSummaryInfo(); System.out.println(" 基础信息:"); System.out.println(" - 姓名: " + (baseInfo != null ? baseInfo.getName() : "N/A")); System.out.println(" - 部门: " + (baseInfo != null ? baseInfo.getDepartsName() : "N/A")); System.out.println(" - 规则: " + (baseInfo != null && baseInfo.getRuleInfo() != null ? baseInfo.getRuleInfo().getGroupname() : "N/A")); System.out.println(" 汇总信息:"); System.out.println(" - 打卡次数: " + (summaryInfo != null ? summaryInfo.getCheckinCount() : 0)); System.out.println(" - 实际工时: " + (summaryInfo != null ? formatSeconds(summaryInfo.getRegularWorkSec()) : "0")); System.out.println(" - 标准工时: " + (summaryInfo != null ? formatSeconds(summaryInfo.getStandardWorkSec()) : "0")); if (data.getExceptionInfos() != null && !data.getExceptionInfos().isEmpty()) { System.out.println(" 异常信息:"); data.getExceptionInfos().forEach(ex -> { String exType = getExceptionTypeName(ex.getException()); System.out.println(" - " + exType + ": " + ex.getCount() + "次, 时长: " + formatSeconds(ex.getDuration())); }); } if (data.getOtInfo() != null && data.getOtInfo().getOtStatus() != null && data.getOtInfo().getOtStatus() > 0) { System.out.println(" 加班信息:"); System.out.println(" - 加班时长: " + formatSeconds(data.getOtInfo().getOtDuration())); } }); } else { System.out.println("✗ 该员工在指定日期无打卡日报数据"); } } catch (IOException e) { System.out.println("✗ 获取打卡日报数据失败: " + e.getMessage()); e.printStackTrace(); } System.out.println("=== 测试结束 ==="); } /** * 格式化秒数为时分秒 */ private String formatSeconds(Integer seconds) { if (seconds == null || seconds == 0) { return "0秒"; } int hours = seconds / 3600; int minutes = (seconds % 3600) / 60; int secs = seconds % 60; StringBuilder sb = new StringBuilder(); if (hours > 0) sb.append(hours).append("小时"); if (minutes > 0) sb.append(minutes).append("分钟"); if (secs > 0) sb.append(secs).append("秒"); return sb.toString(); } /** * 获取异常类型名称 * @param exceptionType 异常类型代码:1-迟到;2-早退;3-缺卡;4-旷工;5-地点异常;6-设备异常 */ private String getExceptionTypeName(Integer exceptionType) { if (exceptionType == null) { return "未知"; } switch (exceptionType) { case 1: return "迟到"; case 2: return "早退"; case 3: return "缺卡"; case 4: return "旷工"; case 5: return "地点异常"; case 6: return "设备异常"; default: return "未知"; } } }