111
tjx
14 小时以前 95e16a3a6877d104d61cb0f99321a31784fcceda
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
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 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;
 
    /**
     * 测试导出生产数据并发送钉钉消息
     * 功能:查询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层实现批次间延迟)
 
        //接口返回的原始数据
        //{
        //   "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;
            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<QwStaff>()
                    .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<WorkWXService.CheckinData> 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<String> useridList = new java.util.ArrayList<>();
            useridList.add(qwStaff.getAccount());
 
            List<WorkWXService.CheckinData> 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<WorkWXService.WorkWXUser> 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("=== 测试结束 ===");
    }
 
}