SignInServiceImpl.java
13.2 KB
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
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
package com.ruoyi.in.service.impl;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.common.utils.uuid.Seq;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.driver.domain.Driver;
import com.ruoyi.driver.mapper.DriverMapper;
import com.ruoyi.equipment.domain.Equipment;
import com.ruoyi.equipment.mapper.EquipmentMapper;
import com.ruoyi.pojo.response.ResponseScheduling;
import com.ruoyi.pojo.response.SignInResponseVo;
import com.ruoyi.service.ThreadJobService;
import com.ruoyi.utils.ConstDateUtil;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.in.mapper.SignInMapper;
import com.ruoyi.in.domain.SignIn;
import com.ruoyi.in.service.ISignInService;
import javax.annotation.Resource;
import static com.ruoyi.common.ConstDriverProperties.PERSONNEL_POSTS_DRIVER;
import static com.ruoyi.common.ErrorTypeProperties.*;
import static com.ruoyi.common.ConstSignInConstSignInProperties.*;
import static com.ruoyi.common.redispre.GlobalRedisPreName.DRIVER_SCHEDULING_PRE;
import static com.ruoyi.common.redispre.GlobalRedisPreName.REDIS_SIGN_IN_DRIVER_ALCOHOL_OVERFLOW;
/**
* 签到Service业务层处理
*
* @author guzijian
* @date 2023-07-05
*/
@Service
public class SignInServiceImpl implements ISignInService {
private Logger log = LoggerFactory.getLogger(SignInServiceImpl.class);
@Autowired
private SignInMapper signInMapper;
@Autowired
private DriverMapper driverMapper;
@Autowired
private EquipmentMapper equipmentMapper;
@Autowired
private RedisCache redisCache;
@Resource
private ThreadJobService threadJobConfig;
/**
* 查询签到
*
* @param id 签到主键
* @return 签到
*/
@Override
public SignIn selectSignInById(Long id) {
return signInMapper.selectSignInById(id);
}
/**
* 查询签到列表
*
* @param signIn 签到
* @return 签到
*/
@Override
public List<SignIn> selectSignInList(SignIn signIn) {
return signInMapper.selectSignInList(signIn);
}
/**
* 新增签到
*
* @param signIn 签到
* @return 结果
*/
@Override
public AjaxResult insertSignIn(SignIn signIn) {
// 查询员工信息
Driver driver = driverMapper.getDriverInfoByJobCode(signIn.getJobCode());
if (Objects.isNull(driver)) return AjaxResult.error("这个工号的员工不存在!");
// 查询地址
Equipment equipment = equipmentMapper.selectEquipmentByDeviceId(signIn.getDeviceId());
SignInResponseVo vo = getSignInResponseVo(signIn, equipment);
signIn.setCreateTime(new Date());
signIn.setRemark("");
// 签到检查 酒精检查 超时检查 排班检查
if (checkSignIn(signIn, driver)) {
signIn.setStatus(SIGN_IN_SUCCESS);
} else {
signIn.setStatus(SIGN_IN_FAIL);
}
signIn.setIp(IpUtils.getIpAddr());
// base64转图片
// uploadImage(signIn);
signInMapper.insertSignIn(signIn);
// TODO redis 存储每个人的签到 用于后续考勤
// 驾驶人员二次签到酒精测试异常
if (PERSONNEL_POSTS_DRIVER.equals(driver.getPosts()) && SIGN_IN_FAIL.equals(signIn.getStatus()) && signIn.getRemark().contains(ALCOHOL_SIGN_IN_ERROR)) {
AjaxResult result = getAjaxResultByDriverSignInfo(signIn, vo);
if (!Objects.isNull(result)) {
return result;
}
}
return SIGN_IN_SUCCESS.equals(signIn.getStatus()) ? AjaxResult.success(SIGN_IN_SUCCESS_STRING, vo) : AjaxResult.error(SIGN_IN_ERROR + signIn.getRemark(), vo);
}
/**
* 修改签到
*
* @param signIn 签到
* @return 结果
*/
@Override
public int updateSignIn(SignIn signIn) {
signIn.setUpdateTime(DateUtils.getNowDate());
return signInMapper.updateSignIn(signIn);
}
/**
* 批量删除签到
*
* @param ids 需要删除的签到主键
* @return 结果
*/
@Override
public int deleteSignInByIds(Long[] ids) {
return signInMapper.deleteSignInByIds(ids);
}
/**
* 删除签到信息
*
* @param id 签到主键
* @return 结果
*/
@Override
public int deleteSignInById(Long id) {
return signInMapper.deleteSignInById(id);
}
@Override
public AjaxResult addSignIn(SignIn signIn) throws IOException {
// 查询员工信息
Driver driver = driverMapper.getDriverInfoByJobCode(signIn.getJobCode());
if (Objects.isNull(driver)) return AjaxResult.error("这个工号的员工不存在!");
// 查询地址
Equipment equipment = equipmentMapper.selectEquipmentByDeviceId(signIn.getDeviceId());
SignInResponseVo vo = getSignInResponseVo(signIn, equipment);
signIn.setCreateTime(new Date());
signIn.setRemark("");
// 签到检查
if (checkSignIn(signIn, driver)) {
signIn.setStatus(SIGN_IN_SUCCESS);
} else {
signIn.setStatus(SIGN_IN_FAIL);
}
// base64转图片
signIn.setIp(IpUtils.getIpAddr());
uploadImage(signIn);
signInMapper.insertSignIn(signIn);
// TODO redis 存储每个人的签到 用于后续考勤
// 驾驶人员二次签到酒精测试异常
if (PERSONNEL_POSTS_DRIVER.equals(driver.getPosts()) && SIGN_IN_FAIL.equals(signIn.getStatus()) && signIn.getRemark().contains(ALCOHOL_SIGN_IN_ERROR)) {
AjaxResult result = getAjaxResultByDriverSignInfo(signIn, vo);
if (!Objects.isNull(result)) {
return result;
}
}
return SIGN_IN_SUCCESS.equals(signIn.getStatus()) ? AjaxResult.success(SIGN_IN_SUCCESS_STRING, vo) : AjaxResult.error(SIGN_IN_ERROR + signIn.getRemark(), vo);
}
private SignInResponseVo getSignInResponseVo(SignIn signIn, Equipment equipment) {
SignInResponseVo vo = new SignInResponseVo();
if (Objects.isNull(equipment)) {
equipment = new Equipment();
}
vo.setAddress(equipment.getAddress());
vo.setDeviceId(signIn.getDeviceId());
return vo;
}
private AjaxResult getAjaxResultByDriverSignInfo(SignIn signIn, SignInResponseVo vo) {
String key = REDIS_SIGN_IN_DRIVER_ALCOHOL_OVERFLOW + ConstDateUtil.formatDate("yyyyMMdd");
// 驾驶员酒精测试连续超标两次则提示换人
Integer count = redisCache.getCacheMapValue(key, signIn.getJobCode());
if (Objects.isNull(count) || count.equals(0)) {
count = 1;
redisCache.setCacheMapValue(key, signIn.getJobCode(), count);
} else {
count = redisCache.setIncrementMapValue(key, signIn.getJobCode(), 1);
}
if (SIGN_IN_ERROR_COUNT.compareTo(count) <= 0) {
// TODO
return AjaxResult.error(SIGN_IN_ERROR + signIn.getRemark() + ",酒精测试不通过" + count + "次请更换车辆驾驶员", vo);
}
return null;
}
private boolean checkSignIn(SignIn signIn, Driver driver) {
boolean result = true;
if (Objects.isNull(driver)) {
return true;
}
// TODO 排班校验 和签到超时校验 非司售未作
result = checkWorkDay(signIn, driver.getPosts());
// 酒精测试校验 确定 且员工工种是驾驶员
if (ALCOHOL_FLAG_YES.equals(signIn.getAlcoholFlag()) && PERSONNEL_POSTS_DRIVER.equals(driver.getPosts())) {
if (new BigDecimal(20).compareTo(signIn.getAlcoholIntake()) > 0) {
result = true;
} else {
signIn.setRemark(signIn.getRemark() + ALCOHOL_SIGN_IN_ERROR);
result = false;
}
}
return result;
}
/**
* 排班和超时检查
*
* @param signIn
* @param posts
* @return
*/
private boolean checkWorkDay(SignIn signIn, String posts) {
boolean result = true;
List<ResponseScheduling> jobs = null;
switch (posts) {
case "驾驶员":
// 查询工号对应的排班 司售人员
jobs = redisCache.getCacheMapValue(DRIVER_SCHEDULING_PRE + ConstDateUtil.formatDate("yyyyMMdd"), signIn.getJobCode());
if (Objects.isNull(jobs) || jobs.size() == 0) {
signIn.setRemark(signIn.getRemark() + WORK_DAY_ERROR);
result = false;
}
break;
case "1":
// 查询工号对应的排班 非司售人员
// 查询数据库
result = true;
break;
}
// 超时校验司售人员
if (result) {
// TODO 非司售人员
result = checkTimeOut(signIn, jobs, posts);
}
return result;
}
private boolean checkTimeOut(SignIn signIn, List<ResponseScheduling> driver, String posts) {
// 那发车时间和到站时间作为开始上班的时间
if (PERSONNEL_POSTS_DRIVER.equals(posts)) {
return driverCheckTimeOut(signIn, driver);
} else {
return true;
}
}
private static boolean driverCheckTimeOut(SignIn signIn, List<ResponseScheduling> driver) {
LocalDateTime startTime = ConstDateUtil.getLocalDateTimeByLongTime(driver.get(0).getFcsjT());
LocalDateTime endTime = ConstDateUtil.getLocalDateTimeByLongTime(driver.get(driver.size() - 1).getZdsjT());
LocalDateTime signTime = ConstDateUtil.getLocalDateTimeByLongTime(signIn.getCreateTime().getTime());
long morningBetween = ChronoUnit.MINUTES.between(startTime, signTime);
long afternoonBetween = ChronoUnit.MINUTES.between(endTime, signTime);
// 签到范围一小时内
if (Math.abs(morningBetween) <= 60 || Math.abs(afternoonBetween) <= 60) {
return true;
} else {
signIn.setRemark(signIn.getRemark() + SIGN_IN_TIMEOUT);
return false;
}
}
private void uploadImage(SignIn signIn) throws IOException {
String base64 = signIn.getImage();
// 图片路径
String filePath = RuoYiConfig.getUploadPath();
// 固定jpg文件
String fileName = "";
// 看是否带有base64前缀 有就判断文件类型 没有默认jpg
fileName = checkImageBase64Format(signIn.getImage());
fileName = extractFilename(fileName);
// 获取相对路径
String absPath = getAbsoluteFile(filePath, fileName).getAbsolutePath();
// 获取文件上传路径
String pathFileName = getPathFileName(filePath, fileName);
signIn.setImage(pathFileName);
// 异步上传文件
threadJobConfig.asyncStartUploadBase64Image(absPath, base64);
}
/**
* 获取相对路径名
*
* @param uploadDir
* @param fileName
* @return
* @throws IOException
*/
public File getAbsoluteFile(String uploadDir, String fileName) throws IOException {
File desc = new File(uploadDir + File.separator + fileName);
if (!desc.exists()) {
if (!desc.getParentFile().exists()) {
desc.getParentFile().mkdirs();
}
}
return desc;
}
/**
* 获取扩展文件名
*
* @param extendFileName
* @return
*/
public String extractFilename(String extendFileName) {
return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
FilenameUtils.getBaseName(UUID.randomUUID().toString().replace("-", "")), Seq.getId(Seq.uploadSeqType), extendFileName);
}
/**
* @param uploadDir
* @param fileName
* @return
* @throws IOException
*/
public String getPathFileName(String uploadDir, String fileName) throws IOException {
int dirLastIndex = RuoYiConfig.getProfile().length() + 1;
String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
}
/**
* 检查文件类型
*
* @param base64ImgData
* @return
*/
public static String checkImageBase64Format(String base64ImgData) {
byte[] b = Base64.getDecoder().decode(base64ImgData);
String type = "";
if (0x424D == ((b[0] & 0xff) << 8 | (b[1] & 0xff))) {
type = "bmp";
} else if (0x8950 == ((b[0] & 0xff) << 8 | (b[1] & 0xff))) {
type = "png";
} else {
type = "jpg";
}
// else if (0xFFD8 == ((b[0] & 0xff) << 8 | (b[1] & 0xff))) {
// type = "jpg";
// }
return type;
}
}