| | |
| | | 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; |
| | |
| | | |
| | | @Autowired |
| | | private QwCheckinDataService qwCheckinDataService; |
| | | |
| | | @Autowired |
| | | private QwCheckinDayDataService qwCheckinDayDataService; |
| | | |
| | | /** |
| | | * 测试导出生产数据并发送钉钉消息 |
| | |
| | | // 3. 接口返回最多3000条打卡数据 |
| | | // 4. 标准打卡时间只对于固定排班和自定义排班两种类型有效 |
| | | // 5. 接口调用频率限制为600次/分钟(已在Service层实现批次间延迟) |
| | | |
| | | //接口返回的原始数据 |
| | | //{ |
| | | // "errcode":0, |
| | | // "errmsg":"ok", |
| | | // "checkindata": [{ |
| | | // "userid" : "james", |
| | | // "groupname" : "打卡一组", |
| | | // "checkin_type" : "上班打卡", |
| | | // "exception_type" : "地点异常", |
| | | // "checkin_time" : 1492617610, |
| | | // "location_title" : "依澜府", |
| | | // "location_detail" : "四川省成都市武侯区益州大道中段784号附近", |
| | | // "wifiname" : "办公一区", |
| | | // "notes" : "路上堵车,迟到了5分钟", |
| | | // "wifimac" : "3c:46:d8:0c:7a:70", |
| | | // "mediaids":["WWCISP_G8PYgRaOVHjXWUWFqchpBqqqUpGj0OyR9z6WTwhnMZGCPHxyviVstiv_2fTG8YOJq8L8zJT2T2OvTebANV-2MQ"], |
| | | // "sch_checkin_time" : 1492617610, |
| | | // "groupid" : 1, |
| | | // "schedule_id" : 0, |
| | | // "timeline_id" : 2 |
| | | // },{ |
| | | // "userid" : "paul", |
| | | // "groupname" : "打卡二组", |
| | | // "checkin_type" : "外出打卡", |
| | | // "exception_type" : "时间异常", |
| | | // "checkin_time" : 1492617620, |
| | | // "location_title" : "重庆出口加工区", |
| | | // "location_detail" : "重庆市渝北区金渝大道101号金渝大道", |
| | | // "wifiname" : "办公室二区", |
| | | // "notes" : "", |
| | | // "wifimac" : "3c:46:d8:0c:7a:71", |
| | | // "mediaids":["WWCISP_G8PYgRaOVHjXWUWFqchpBqqqUpGj0OyR9z6WTwhnMZGCPHxyviVstiv_2fTG8YOJq8L8zJT2T2OvTebANV-2MQ"], |
| | | // "lat": 30547645, |
| | | // "lng": 104063236, |
| | | // "deviceid":"E5FA89F6-3926-4972-BE4F-4A7ACF4701E2", |
| | | // "sch_checkin_time" : 1492617610, |
| | | // "groupid" : 2, |
| | | // "schedule_id" : 3, |
| | | // "timeline_id" : 1 |
| | | // }] |
| | | //} |
| | | |
| | | //checkindata的字段说明 |
| | | //userid 用户id |
| | | //groupname 打卡规则名称 |
| | | //checkin_type 打卡类型。字符串,目前有:上班打卡,下班打卡,外出打卡,仅记录打卡时间和位置 |
| | | //exception_type 异常类型,字符串,包括:时间异常,地点异常,未打卡,wifi异常,非常用设备。如果有多个异常,以分号间隔 |
| | | //checkin_time 打卡时间。Unix时间戳 |
| | | //location_title 打卡地点title |
| | | //location_detail 打卡地点详情 |
| | | //wifiname 打卡wifi名称 |
| | | //notes 打卡备注 |
| | | //wifimac 打卡的MAC地址/bssid |
| | | //mediaids 打卡的附件media_id,可使用media/get获取附件 |
| | | //lat 位置打卡地点纬度,是实际纬度的1000000倍,与腾讯地图一致采用GCJ-02坐标系统标准 |
| | | //lng 位置打卡地点经度,是实际经度的1000000倍,与腾讯地图一致采用GCJ-02坐标系统标准 |
| | | //deviceid 打卡设备id |
| | | //sch_checkin_time 标准打卡时间,指此次打卡时间对应的标准上班时间或标准下班时间 |
| | | //groupid 规则id,表示打卡记录所属规则的id |
| | | //schedule_id 班次id,表示打卡记录所属规则中,所属班次的id |
| | | //timeline_id 时段id,表示打卡记录所属规则中,某一班次中的某一时段的id,如上下班时间为9:00-12:00、13:00-18:00的班次中,9:00-12:00为其中一组时段 |
| | | |
| | | try { |
| | | long currentTime = System.currentTimeMillis() / 1000; |
| | |
| | | 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<QwStaff>() |
| | | .isNotNull(QwStaff::getAccount) |
| | | .ne(QwStaff::getAccount, "")); |
| | | System.out.println(" - QW_STAFF表用户总数: " + totalUsers); |
| | | |
| | | List<WorkWXService.CheckinDayData> 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<String> useridList = new java.util.ArrayList<>(); |
| | | useridList.add(qwStaff.getAccount()); |
| | | |
| | | List<WorkWXService.CheckinDayData> 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 "未知"; |
| | | } |
| | | } |
| | | |
| | | } |