人脸使用组件

This commit is contained in:
方亮 2026-02-10 16:29:19 +08:00
parent 7cd61b935c
commit 4c9ddf7251
22 changed files with 799 additions and 289 deletions

View File

@ -0,0 +1,26 @@
package com.bonus.bmw.config;
import com.bonus.bmw.utils.FaceFeatureExtractorUtil;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class FaceServiceInitializer implements ApplicationRunner {
private final FaceServiceProperties properties;
public FaceServiceInitializer(FaceServiceProperties properties) {
this.properties = properties;
}
@Override
public void run(ApplicationArguments args) {
// Spring 启动完成后注入值到静态工具类
if (properties.getBaseUrl() != null) {
FaceFeatureExtractorUtil.setBaseUrl(properties.getBaseUrl());
}
if (properties.getFaceUrl() != null) {
FaceFeatureExtractorUtil.setFaceUrl(properties.getFaceUrl());
}
}
}

View File

@ -0,0 +1,13 @@
package com.bonus.bmw.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "face.service")
@Data
public class FaceServiceProperties {
private String baseUrl;
private String faceUrl;
}

View File

@ -24,9 +24,7 @@ import com.bonus.common.security.annotation.RequiresPermissionsOrInnerAuth;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -34,7 +32,6 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.*;
@ -862,11 +859,8 @@ public class PmProjectController extends BaseController {
String fileName = URLEncoder.encode("三表一册", "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
// 3. 创建全局Workbook复用用于多Sheet
// Workbook wb = new SXSSFWorkbook(); // SXSSFWorkbook大数据量导出避免OOM
XSSFWorkbook wb = new XSSFWorkbook();
try {
// 4. 为每个Sheet创建ExcelUtil并添加到Workbook
// 4.1 Sheet1农民工花名册
ExportProMonthTableRoster eptr = new ExportProMonthTableRoster();
Map<String, Object> map1 = new HashMap<>();
@ -877,7 +871,7 @@ public class PmProjectController extends BaseController {
itemMap.put("subName", vo.getSubName());
itemMap.put("teamName", vo.getTeamName());
itemMap.put("userName", vo.getUserName());
itemMap.put("sex", vo.getSex());
itemMap.put("sex", "1".equals(vo.getSex()) ? "" : "");
itemMap.put("workName", vo.getWorkName());
itemMap.put("unitAndCode", vo.getUnitAndCode());
itemMap.put("period", vo.getPeriod());
@ -886,7 +880,7 @@ public class PmProjectController extends BaseController {
itemMap.put("phone", vo.getPhone());
itemMap.put("inTime", vo.getInTime());
itemMap.put("outTime", vo.getOutTime());
itemMap.put("onDuty", vo.getOnDuty());
itemMap.put("onDuty", "1".equals(vo.getOnDuty()) ? "在岗" : "离岗");
itemMap.put("remark", vo.getRemark());
mapList1.add(itemMap);
}
@ -981,9 +975,6 @@ public class PmProjectController extends BaseController {
map4.put("proName",userWagePayVo.getProName());
euwp.createSheet(wb,map4);
// 5. 将Workbook写入响应流
wb.write(response.getOutputStream());
response.flushBuffer(); // 强制刷新流

View File

@ -2,11 +2,12 @@ package com.bonus.bmw.controller;
import com.bonus.bmw.domain.dto.PmWorkerDto;
import com.bonus.bmw.domain.dto.WebFileDto;
import com.bonus.bmw.domain.face.FaceResult;
import com.bonus.bmw.domain.vo.PmWorker;
import com.bonus.bmw.domain.vo.PmWorkerImport;
import com.bonus.bmw.service.PmWorkerService;
import com.bonus.bmw.utils.FaceFeatureExtractorUtil;
import com.bonus.common.core.utils.encryption.Sm4Utils;
import com.bonus.common.core.utils.face.ArcFaceHelper;
import com.bonus.common.core.utils.json.FastJsonHelper;
import com.bonus.common.core.utils.poi.ExcelUtil;
import com.bonus.common.core.web.controller.BaseController;
@ -24,7 +25,6 @@ import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -188,42 +188,26 @@ public class PmWorkerController extends BaseController {
@PostMapping("/faceDetection")
@SysLog(title = "人脸照片合格检测", businessType = OperaType.UPDATE, logType = 0, module = "施工人员->出入场管理->人员入场管理", details = "人脸照片合格检测")
public AjaxResult faceDetection(@RequestParam(value = "file") MultipartFile file) {
if (file == null || file.isEmpty()) {
return AjaxResult.error("文件为空:" );
if (file == null || file.isEmpty()) {
return AjaxResult.error("文件为空" );
}
File fileData = null;
try {
fileData = FaceFeatureExtractorUtil.multipartToFile(file);
FaceResult faceResult = FaceFeatureExtractorUtil.extractFeature(fileData);
if (200 == faceResult.getCode()){
return AjaxResult.success(faceResult.getMsg());
}else{
return AjaxResult.error(faceResult.getMsg());
}
// 创建临时文件
File tempFile = null;
try {
// 获取文件后缀
String originalFilename = file.getOriginalFilename();
String suffix = "";
if (originalFilename != null && originalFilename.contains(".")) {
suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
}
// 创建临时文件
tempFile = Files.createTempFile("temp-image-", suffix).toFile();
tempFile.deleteOnExit(); // JVM退出时自动删除
// MultipartFile 写入临时文件
file.transferTo(tempFile);
ArcFaceHelper arcFaceHelper = new ArcFaceHelper();
// 调用原方法传入临时文件的路径
String faceFeatures;
try {
faceFeatures = arcFaceHelper.getIsFaceImage(tempFile.getAbsolutePath());
} catch (Exception e) {
return AjaxResult.error("人脸照片识别有问题");
}
String[] split = faceFeatures.split(",");
if ("200".equals(split[0])){
return AjaxResult.success(split[1]);
}else{
return AjaxResult.error(split[1]);
}
} catch (IOException e) {
// 处理异常如磁盘满权限不足等
e.printStackTrace();
return AjaxResult.error("人脸检测失败:"+e.getMessage());
} catch (IOException e) {
logger.error("人脸检测失败:", e);
return AjaxResult.error("人脸检测失败:"+e.getMessage());
} finally {
if (fileData != null && fileData.exists()) {
boolean delete = fileData.delete();
}
}
}
/**
@ -238,46 +222,22 @@ public class PmWorkerController extends BaseController {
if (base64file == null || base64file.isEmpty()) {
return AjaxResult.error("文件为空");
}
File tempFile = null;
File fileData = null;
try {
// 解码base64数据
String base64Data = base64file;
if (base64file.startsWith("data:image")) {
// 如果是data URL格式提取base64部分
base64Data = base64file.substring(base64file.indexOf(",") + 1);
}
// 确定文件扩展名简单处理可根据实际需求调整
String suffix = ".jpg"; // 默认jpg格式
if (base64file.contains("png")) {
suffix = ".png";
} else if (base64file.contains("jpeg")) {
suffix = ".jpeg";
}
// 创建临时文件
tempFile = Files.createTempFile("temp-image-", suffix).toFile();
tempFile.deleteOnExit(); // JVM退出时自动删除
// 将base64数据写入临时文件
byte[] imageBytes = java.util.Base64.getDecoder().decode(base64Data);
java.nio.file.Files.write(tempFile.toPath(), imageBytes);
ArcFaceHelper arcFaceHelper = new ArcFaceHelper();
// 调用原方法传入临时文件的路径
String faceFeatures = null;
try {
faceFeatures = arcFaceHelper.getIsFaceImage(tempFile.getAbsolutePath());
} catch (Exception e) {
return AjaxResult.error("人脸照片识别有问题");
}
String[] split = faceFeatures.split(",");
if ("200".equals(split[0])){
return AjaxResult.success(split[1]);
fileData =FaceFeatureExtractorUtil.base64ToFile(base64file, "face_detection");;
FaceResult faceResult = FaceFeatureExtractorUtil.extractFeature(fileData);
if (200 == faceResult.getCode()){
return AjaxResult.success(faceResult.getMsg());
}else{
return AjaxResult.error(split[1]);
return AjaxResult.error(faceResult.getMsg());
}
} catch (IOException e) {
// 处理异常如磁盘满权限不足等
e.printStackTrace();
} catch (Exception e) {
logger.error("人脸检测失败:", e);
return AjaxResult.error("人脸检测失败:"+e.getMessage());
} finally {
if (fileData != null && fileData.exists()) {
boolean delete = fileData.delete();
}
}
}

View File

@ -187,7 +187,6 @@ public class RepairCardApplyController extends BaseController {
*/
@PostMapping("/updateRepairCardApply")
public AjaxResult updateRepairCardApply(@RequestParam(value = "file", required = false) MultipartFile[] files, @RequestParam(value = "fileMsg", required = false) String fileMsg, @RequestParam(value = "params") String params) {
try {
params= Sm4Utils.decrypt(params);
fileMsg= Sm4Utils.decrypt(fileMsg);

View File

@ -103,4 +103,6 @@ public class PmWorkerDto {
*/
private String lightStatus;
private String workerName;
}

View File

@ -0,0 +1,15 @@
package com.bonus.bmw.domain.face;
import lombok.Data;
@Data
public class FaceResult {
private int code;
private String msg;
private Object data;
public FaceResult(int code, String msg, Object o) {
this.code = code;
this.msg = msg;
this.data = o;
}
}

View File

@ -0,0 +1,16 @@
package com.bonus.bmw.domain.face;
import lombok.Data;
@Data
public class GroupInfo {
private Long id;
private String name;
private String createTime;
public GroupInfo(Long id, String name, String createTime) {
this.id = id;
this.name = name;
this.createTime = createTime;
}
}

View File

@ -0,0 +1,16 @@
package com.bonus.bmw.domain.face;
import lombok.Data;
@Data
public class UserInfo {
private Long id;
private String name;
private Long groupId;
public UserInfo(Long id, String name, Long groupId) {
this.id = id;
this.name = name;
this.groupId = groupId;
}
}

View File

@ -11,8 +11,6 @@ public interface AppRecognitionService {
String uploadFaceRecognition(MultipartFile facePhoto, FaceRecognitionBean bean);
String uploadFaceRecognition(String facePhoto, FaceRecognitionBean bean);
AjaxResult getFaceRecognition(MultipartFile facePhoto, String proId);
AjaxResult bankCardRecognition(BankCardBean bean);

View File

@ -1,21 +1,19 @@
package com.bonus.bmw.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.bonus.bmw.domain.dto.BankCardBean;
import com.bonus.bmw.domain.dto.BmWorkerEinUserVo;
import com.bonus.bmw.domain.dto.IdCardBean;
import com.bonus.bmw.domain.face.FaceResult;
import com.bonus.bmw.domain.face.UserInfo;
import com.bonus.bmw.domain.po.FaceRecognitionBean;
import com.bonus.bmw.mapper.AppRecognitionMapper;
import com.bonus.bmw.service.AppRecognitionService;
import com.bonus.bmw.utils.BaiduRecognitionUtils;
import com.bonus.bmw.utils.FaceStatusCodeReturn;
import com.bonus.bmw.utils.FaceFeatureExtractorUtil;
import com.bonus.common.core.constant.Constants;
import com.bonus.common.core.utils.DateUtils;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.utils.json.FastJsonHelper;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.system.api.model.UploadFileVo;
import lombok.extern.slf4j.Slf4j;
@ -30,8 +28,8 @@ import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.File;
import java.net.URLEncoder;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
@ -49,8 +47,8 @@ public class AppRecognitionServiceImpl implements AppRecognitionService {
@Autowired
private FileUploadUtils fileUploadUtils;
@Value("${face.path}")
public String faceUrl;
@Value("${face.groupId}")
private Long groupId;
/**
* 人脸识别-人脸照片采集入库
@ -61,128 +59,41 @@ public class AppRecognitionServiceImpl implements AppRecognitionService {
@Override
public String uploadFaceRecognition(MultipartFile facePhoto, FaceRecognitionBean bean) {
try {
// 最多尝试两次避免无限循环 ,删除无需重复
int maxRetries = 1;
if(!"delete".equals(bean.getOptMode())){
// 1. 获取文件字节数组
byte[] bytes = facePhoto.getBytes();
// 2. 使用 Base64 编码
String fileBase64 = Base64.getEncoder().encodeToString(bytes);
// 根据文件类型添加相应的前缀
String originalFilename = facePhoto.getOriginalFilename();
if (originalFilename != null && originalFilename.toLowerCase().endsWith(".png")) {
bean.setImg("data:image/png;base64," + fileBase64);
} else {
bean.setImg("data:image/jpeg;base64," + fileBase64);
}
maxRetries = 2;
FaceResult faceResult = FaceFeatureExtractorUtil.updateUserByIdNumber(bean.getIdNumber(), groupId, FaceFeatureExtractorUtil.multipartToFile(facePhoto));
if(faceResult.getCode() == 200) {
// 解析 data 数组
return "人脸入库成功";
}else{
bean.setImg("data:image/jpeg;base64,fddsdafretrthwuwtrewyewtrweet");
}
for (int i = 0; i < maxRetries; i++) {
String body = HttpUtil.post(faceUrl + "/updatedb",
FastJsonHelper.beanToJsonStr(bean));
log.error(body);
JSONObject jsonObject = FastJsonHelper.jsonStrToJsonObj(body);
String code = jsonObject.getString("code");
if(StringUtils.isEmpty(code)){
log.error("公司人脸识别大傻逼,code不放一起");
code = jsonObject.getJSONObject("detail").getString("code");
}
if ("30019".equals(code) && i == 0) {
// 第一次遇到30019错误时设置replace模式再试一次
bean.setOptMode("replace");
} else {
// 其他情况直接返回结果
return "30002".equals(code) ? FaceStatusCodeReturn.faceStatusCodeReturn(30002)
: FaceStatusCodeReturn.faceStatusCodeReturn(Integer.parseInt(code));
}
return faceResult.getMsg();
}
} catch (Exception e) {
log.error("上传文件失败", e);
return "公司内部人脸识别服务处理异常";
return "人脸识别服务处理异常";
}
return "公司内部人脸识别服务处理异常";
}
/**
* 人脸识别-人脸照片采集入库
* @param facePhoto url
* @param bean
* @return
*/
@Override
public String uploadFaceRecognition(String facePhoto, FaceRecognitionBean bean) {
try {
// 最多尝试两次避免无限循环 ,删除无需重复
int maxRetries = 1;
if(!"delete".equals(bean.getOptMode())){
log.error("进人脸服务器的人脸图片:{}", facePhoto);
bean.setImg("data:image/png;base64,"+facePhoto);
maxRetries = 2;
}else{
bean.setImg("data:image/png;base64,fddsdafretrthwuwtrewyewtrweet");
}
for (int i = 0; i < maxRetries; i++) {
String body = HttpUtil.post(faceUrl + "/updatedb",
FastJsonHelper.beanToJsonStr(bean));
log.error(body);
JSONObject jsonObject = FastJsonHelper.jsonStrToJsonObj(body);
String code = jsonObject.getString("code");
if(StringUtils.isEmpty(code)){
log.error("公司人脸识别大傻逼,code不放一起");
code = jsonObject.getJSONObject("detail").getString("code");
}
if ("30019".equals(code) && i == 0) {
// 第一次遇到30019错误时设置replace模式再试一次
bean.setOptMode("replace");
} else {
// 其他情况直接返回结果
return "30002".equals(code) ? FaceStatusCodeReturn.faceStatusCodeReturn(30002)
: FaceStatusCodeReturn.faceStatusCodeReturn(Integer.parseInt(code));
}
}
} catch (Exception e) {
log.error("上传文件失败", e);
return "公司内部人脸识别服务处理异常";
}
return "公司内部人脸识别服务处理异常";
}
@Override
public AjaxResult getFaceRecognition(MultipartFile facePhoto, String proId) {
try {
// 1. 获取文件字节数组
byte[] bytes = facePhoto.getBytes();
// 2. 使用 Base64 编码
String fileBase64 = Base64.getEncoder().encodeToString(bytes);
// 根据文件类型添加相应的前缀
String originalFilename = facePhoto.getOriginalFilename();
if (originalFilename != null && originalFilename.toLowerCase().endsWith(".png")) {
fileBase64 = "data:image/png;base64," + fileBase64;
} else {
fileBase64 = "data:image/jpeg;base64," + fileBase64;
}
String body = HttpUtil.post(faceUrl + "/facerecognition",
FastJsonHelper.beanToJsonStr(new FaceRecognitionBean(fileBase64)));
log.info("人脸识别响应内容: {}", body);
JSONObject jsonObject = FastJsonHelper.jsonStrToJsonObj(body);
String code = jsonObject.getString("code");
File file = FaceFeatureExtractorUtil.multipartToFile(facePhoto);
FaceResult faceResult = FaceFeatureExtractorUtil.faceRecognition(groupId, file);
BmWorkerEinUserVo sysFile = new BmWorkerEinUserVo();
if(!"30000".equals(code)){
sysFile.setFaceResult(false);
sysFile.setFaceRemark(body);
if(faceResult.getCode() == 200) {
// 解析 data 数组
UserInfo obj = (UserInfo) faceResult.getData();
if (obj != null) {
String idNumber = obj.getName();
// 1. 获取用户信息
sysFile = mapper.getOnUserInfoByIdNumber(idNumber,proId);
sysFile.setFaceResult(true);
sysFile.setImage(faceResult.getMsg());
return AjaxResult.success(sysFile);
}else {
return AjaxResult.error("人脸接口返回异常");
}
}else{
String data = jsonObject.getString("data");
JSONArray jsonArray = FastJsonHelper.jsonArrStrToJsonArr(data);
String idNumber = (String) jsonArray.get(0);
// 1. 获取用户信息
sysFile = mapper.getOnUserInfoByIdNumber(idNumber,proId);
sysFile.setFaceResult(true);
return AjaxResult.error(faceResult.getMsg());
}
return !"30000".equals(code) ? AjaxResult.error(FaceStatusCodeReturn.faceStatusCodeReturn(Integer.parseInt(code)))
: AjaxResult.success(sysFile);
} catch (Exception e) {
log.error("上传文件失败", e);
return AjaxResult.error("未找到人脸信息");
@ -295,8 +206,4 @@ public class AppRecognitionServiceImpl implements AppRecognitionService {
}
}
}

View File

@ -2,12 +2,13 @@ package com.bonus.bmw.service.impl;
import cn.hutool.core.date.DateUtil;
import com.bonus.bmw.domain.dto.PmWorkerDto;
import com.bonus.bmw.domain.face.FaceResult;
import com.bonus.bmw.domain.po.FaceRecognitionBean;
import com.bonus.bmw.domain.vo.*;
import com.bonus.bmw.mapper.*;
import com.bonus.bmw.service.AppRecognitionService;
import com.bonus.bmw.service.AppService;
import com.bonus.bmw.service.UrkSendService;
import com.bonus.bmw.utils.FaceFeatureExtractorUtil;
import com.bonus.common.core.constant.Constants;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.core.web.domain.AjaxResult;
@ -18,6 +19,7 @@ import com.bonus.system.api.model.UploadFileVo;
import com.github.pagehelper.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@ -43,15 +45,15 @@ public class AppServiceImpl implements AppService {
@Autowired
private PmWorkerMapper pmWorkerMapper;
@Value("${face.groupId}")
private Long groupId;
/**
* 引入urk服务 调用考勤机服务
*/
@Autowired
private UrkSendService urkSendService;
@Resource
private AppRecognitionService appRecognitionService;
@Resource
private BmWorkerWageCardMapper wageCardMapper;
@Autowired
@ -148,12 +150,10 @@ public class AppServiceImpl implements AppService {
//下发人脸到考勤机
urkSendService.sendUserToDevice(record.getId(), record.getProId(), record.getSubId(), record.getTeamId(),"0");
//下发人脸到人脸库
FaceRecognitionBean faceRecognitionBean = new FaceRecognitionBean();
faceRecognitionBean.setUniqueKey(record.getIdNumber());
faceRecognitionBean.setOptMode("add");
UploadFileVo fileBast64 = fileUploadUtils.getFileBast64(record.getPhotoIds(), "", Constants.FILE_UPLOAD_WORKER, "");
if (fileBast64 != null) {
sb.append(appRecognitionService.uploadFaceRecognition(fileBast64.getBast64(), faceRecognitionBean));
FaceResult faceResult = FaceFeatureExtractorUtil.updateUserByIdNumberBase64(record.getIdNumber(), groupId,fileBast64.getBast64());
sb.append(faceResult.getMsg());
}
}
//入场相关数据添加
@ -229,11 +229,10 @@ public class AppServiceImpl implements AppService {
}
//下发人脸到人脸库
FaceRecognitionBean faceRecognitionBean = new FaceRecognitionBean();
faceRecognitionBean.setUniqueKey(record.getIdNumber());
faceRecognitionBean.setOptMode("add");
UploadFileVo fileBast64 = fileUploadUtils.getFileBast64(record.getPhotoIds(), "", Constants.FILE_UPLOAD_WORKER, "");
if (fileBast64 != null) {
sb.append(appRecognitionService.uploadFaceRecognition(fileBast64.getBast64(), faceRecognitionBean));
FaceResult faceResult = FaceFeatureExtractorUtil.updateUserByIdNumberBase64(record.getIdNumber(), groupId,fileBast64.getBast64());
sb.append(faceResult.getMsg());
}
}
if(record.getEinStatus() == 1){

View File

@ -2,7 +2,6 @@ package com.bonus.bmw.service.impl;
import com.bonus.bmw.domain.dto.PmWorkerDto;
import com.bonus.bmw.domain.dto.WebFileDto;
import com.bonus.bmw.domain.po.FaceRecognitionBean;
import com.bonus.bmw.domain.vo.MapBeanVo;
import com.bonus.bmw.domain.vo.PmWorker;
import com.bonus.bmw.mapper.PmWorkerExitMapper;
@ -96,15 +95,6 @@ public class PmWorkerExitServiceImpl implements PmWorkerExitService {
}
}
private void delAppFace(Integer workerId) {
String idNumber = mapper.getIdNumberByWorkerId(workerId);
//下发人脸到人脸库
FaceRecognitionBean faceRecognitionBean = new FaceRecognitionBean();
faceRecognitionBean.setUniqueKey(idNumber);
faceRecognitionBean.setOptMode("delete");
appRecognitionService.uploadFaceRecognition("", faceRecognitionBean);
}
@Override
public AjaxResult updateWorkerBatchExit(List<PmWorkerDto> list) throws Exception {
StringBuilder sb = new StringBuilder();

View File

@ -3,11 +3,12 @@ package com.bonus.bmw.service.impl;
import cn.hutool.core.date.DateUtil;
import com.bonus.bmw.domain.dto.PmWorkerDto;
import com.bonus.bmw.domain.dto.WebFileDto;
import com.bonus.bmw.domain.po.FaceRecognitionBean;
import com.bonus.bmw.domain.face.FaceResult;
import com.bonus.bmw.domain.po.MapBeanPo;
import com.bonus.bmw.domain.vo.*;
import com.bonus.bmw.mapper.PmWorkerMapper;
import com.bonus.bmw.service.*;
import com.bonus.bmw.utils.FaceFeatureExtractorUtil;
import com.bonus.common.core.constant.Constants;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.common.core.utils.StringUtils;
@ -20,16 +21,21 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.validation.Validator;
import java.io.File;
import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@ -58,6 +64,9 @@ public class PmWorkerServiceImpl implements PmWorkerService{
@Autowired
protected Validator validator;
@Value("${face.groupId}")
private Long groupId;
/**
* 引入urk服务 调用考勤机服务
*/
@ -140,13 +149,21 @@ public class PmWorkerServiceImpl implements PmWorkerService{
}
//下发人脸到人脸库
if(!uploadFileVos.isEmpty()){
FaceRecognitionBean faceRecognitionBean = new FaceRecognitionBean();
faceRecognitionBean.setUniqueKey(record.getIdNumber());
faceRecognitionBean.setOptMode("add");
if(isBase64){
sb.append(appRecognitionService.uploadFaceRecognition(record.getFacePhotoBase64(), faceRecognitionBean));
FaceResult faceResult = FaceFeatureExtractorUtil.updateUserByIdNumberBase64(record.getIdNumber(), groupId, record.getFacePhotoBase64());
sb.append(faceResult.getMsg());
}else{
sb.append(appRecognitionService.uploadFaceRecognition(facePhoto, faceRecognitionBean));
File file = null;
try {
file = FaceFeatureExtractorUtil.multipartToFile(facePhoto);
FaceResult faceResult = FaceFeatureExtractorUtil.updateUserByIdNumber(record.getIdNumber(), groupId, file);
sb.append(faceResult.getMsg());
} finally {
if (file != null && file.exists()) {
boolean delete = file.delete();
// 或使用 Hutool: FileUtil.del(file);
}
}
}
}
}
@ -452,20 +469,27 @@ public class PmWorkerServiceImpl implements PmWorkerService{
}
//下发人脸到人脸库
if(!uploadFileVos.isEmpty()){
FaceRecognitionBean faceRecognitionBean = new FaceRecognitionBean();
faceRecognitionBean.setUniqueKey(record.getIdNumber());
faceRecognitionBean.setOptMode("add");
if(isBase64){
sb.append(appRecognitionService.uploadFaceRecognition(record.getFacePhotoBase64(), faceRecognitionBean));
FaceResult faceResult = FaceFeatureExtractorUtil.updateUserByIdNumberBase64(record.getIdNumber(), groupId, record.getFacePhotoBase64());
sb.append(faceResult.getMsg());
}else{
sb.append(appRecognitionService.uploadFaceRecognition(facePhoto, faceRecognitionBean));
File file = null;
try {
file = FaceFeatureExtractorUtil.multipartToFile(facePhoto);
FaceResult faceResult = FaceFeatureExtractorUtil.updateUserByIdNumber(record.getIdNumber(), groupId, file);
sb.append(faceResult.getMsg());
} finally {
if (file != null && file.exists()) {
boolean delete = file.delete();
}
}
}
}
}
if(record.getEinStatus() == 1){
//已经入过场了
//是否修改工种
if(record.getPostId() != null && record.getPostId() > 0){
if(record.getPostId() != null && record.getPostId() > 0 && record.getPostName() != null && !record.getPostName().isEmpty()){
mapper.updateWorkerPost(record);
}
addWorkerWageCardDataAndContract(record,fileMsg);
@ -479,7 +503,6 @@ public class PmWorkerServiceImpl implements PmWorkerService{
log.error("人员下发考勤机失败:",e);
sb.append("人员下发考勤机失败--");
}
addWorkerEinData(record,fileMsg);
}
return AjaxResult.success(sb.append("--基础数据更新成功").toString());

View File

@ -168,7 +168,7 @@ public class RepairCardApplyServiceImpl implements RepairCardApplyService {
@Override
public AjaxResult updateRepairCardApply(RepairCardApplyDto cardApplyDto, FileBasicMsgDto fileBasicMsgDto) {
cardApplyDto.setApplyUser(SecurityUtils.getUsername());
cardApplyDto.setApplyUser(SecurityUtils.getLoginUser().getUsername());
Integer num = repairCardApplyMapper.updateRepairCardApply(cardApplyDto);
if (num > 0) {
repairCardApplyMapper.delRepairCardRecord(cardApplyDto);

View File

@ -0,0 +1,558 @@
package com.bonus.bmw.utils;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.bonus.bmw.domain.face.FaceResult;
import com.bonus.bmw.domain.face.GroupInfo;
import com.bonus.bmw.domain.face.UserInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 人脸识别算法服务Python 微服务工具类
* 统一管理 API 地址使用 Hutool 封装 HTTP 调用
*/
public class FaceFeatureExtractorUtil {
private static final Logger log = LoggerFactory.getLogger(FaceFeatureExtractorUtil.class);
// ========== 基础配置 ==========
private static String BASE_URL = "http://192.168.0.37:18080/api";
private static String FACE_URL = "http://192.168.0.37:18000";
// ========== API 路径常量 ==========
private static final String EXTRACT_FEATURE_PATH = "/api/extract_feature";
private static final String HEALTH_CHECK_PATH = "/health";
public static final String GROUP_ADD_PATH = "/groups/add";
public static final String GROUP_LIST_PATH = "/groups/list";
public static final String USER_ADD_PATH = "/users/add";
public static final String USER_UPDATE_PATH = "/users/update";
public static final String USER_SEARCH_PATH = "/users/search";
public static final String USER_LIST_PATH = "/users/list";
/**
* 设置算法服务的基础 URL
*/
public static void setBaseUrl(String baseUrl) {
if (baseUrl != null && !baseUrl.trim().isEmpty()) {
BASE_URL = baseUrl.trim();
}
}
/**
* 设置算法服务的人脸 URL
*/
public static void setFaceUrl(String faceUrl) {
if (faceUrl != null && !faceUrl.trim().isEmpty()) {
FACE_URL = faceUrl.trim();
}
}
/**
* 提取人脸特征向量
*
* @param imageFile 人脸图片文件jpg/png
* @return ExtractResult 包含成功状态特征向量错误信息等
*/
public static FaceResult extractFeature(File imageFile) {
if (imageFile == null || !imageFile.exists()) {
return new FaceResult(500, "Image file is null or not exists", null);
}
try {
System.out.println("开始调用算法服务:"+FACE_URL + EXTRACT_FEATURE_PATH);
HttpResponse response = HttpRequest.post(FACE_URL + EXTRACT_FEATURE_PATH).form("image", imageFile).timeout(10000) // 10秒超时
.execute();
int status = response.getStatus();
String body = response.body();
if (status != 200) {
return new FaceResult(status, "HTTP error: " + status, null);
}
JSONObject json = JSONUtil.parseObj(body);
boolean success = json.getBool("success", false);
String message = json.getStr("message", "Unknown error");
if (!success) {
return new FaceResult(500, message, null);
}
// 解析 1024 维特征
List<Double> featureList = json.getJSONArray("feature").toList(Double.class);
double[] featureArray = new double[featureList.size()];
for (int i = 0; i < featureList.size(); i++) {
featureArray[i] = featureList.get(i);
}
return new FaceResult(200, "人脸验证成功", featureArray);
} catch (Exception e) {
String errorMsg = "Exception during feature extraction: " + ExceptionUtil.stacktraceToString(e);
return new FaceResult(500, errorMsg, null);
}
}
/**
* 健康检查
*/
public static FaceResult healthCheck() {
try {
HttpResponse response = HttpRequest.get(FACE_URL + HEALTH_CHECK_PATH).timeout(3000).execute();
if (response.getStatus() == 200) {
JSONObject json = JSONUtil.parseObj(response.body());
return "healthy".equals(json.getStr("status")) ? new FaceResult(200, "服务正常", null): new FaceResult(500, "服务异常", null);
}
return new FaceResult(500, "服务健康检查异常", null);
} catch (Exception e) {
return new FaceResult(500, "服务健康检查异常", null);
}
}
/**
* 创建分组
*
* @param name 分组名称必填
* @param description 分组描述可选可传 null
* @return 返回结果对象包含 idnamecreateTime
*/
public static FaceResult addGroup(String name, String description) {
if (name == null || name.trim().isEmpty()) {
throw new IllegalArgumentException("分组名称不能为空");
}
// 构建请求体 JSON
JSONObject requestBody = JSONUtil.createObj().set("name", name).set("description", description); // Hutool 会自动忽略 null 不会序列化
try {
HttpResponse response = HttpRequest.post(BASE_URL + GROUP_ADD_PATH).body(requestBody.toString()) // 发送 JSON 字符串
.contentType("application/json") // 设置 Content-Type
.timeout(5000) // 超时 5
.execute();
// 解析响应
int status = response.getStatus();
String body = response.body();
if (status != 200) {
return new FaceResult(status, "创建分组-人脸库返回异常", null);
}
JSONObject respJson = JSONUtil.parseObj(body);
int code = respJson.getInt("code", -1);
String msg = respJson.getStr("msg", "Unknown");
if (code != 200) {
return new FaceResult(status, msg, null);
}
// 提取 data 部分
JSONObject data = respJson.getJSONObject("data");
Long id = data.getLong("id");
String groupName = data.getStr("name");
String createTime = data.getStr("createTime");
return new FaceResult(status, "success", new GroupInfo(id, groupName, createTime));
} catch (Exception e) {
return new FaceResult(500, "请求异常: " + e.getMessage(), null);
}
}
/**
* 获取所有分组列表
*
* @return 返回结果对象包含 idnamecreateTime
*/
public static FaceResult getGroupList() {
try {
// 构建请求体 JSON
HttpResponse response = HttpRequest.get(BASE_URL + GROUP_LIST_PATH).timeout(5000).execute();
// 解析响应
int status = response.getStatus();
String body = response.body();
if (status != 200) {
return new FaceResult(status, "获取分组列表-人脸库返回异常", null);
}
JSONObject respJson = JSONUtil.parseObj(body);
int code = respJson.getInt("code", -1);
String msg = respJson.getStr("msg", "Unknown");
if (code != 200) {
return new FaceResult(status, msg, null);
}
// 解析 data 数组
JSONArray dataArray = respJson.getJSONArray("data");
List<GroupInfo> groupList = new ArrayList<>();
if (dataArray != null) {
for (Object obj : dataArray) {
if (obj instanceof JSONObject) {
JSONObject item = (JSONObject) obj;
Long id = item.getLong("id");
String name = item.getStr("name");
// 注意list 接口不返回 createTime所以只取 id name
groupList.add(new GroupInfo(id, name, null));
}
}
}
return new FaceResult(status, "success", groupList);
} catch (Exception e) {
return new FaceResult(500, "请求异常: " + e.getMessage(), null);
}
}
/**
* 核心方法新增人员
* 支持格式
* @param idNumber 人员主键
* @param groupId 分组ID可为 null
* @param photoFile 图片
* @return 添加结果
*/
public static FaceResult addUser(String idNumber, Long groupId, File photoFile) {
if (idNumber == null || idNumber.trim().isEmpty()) {
return new FaceResult(500, "人员主键不能为空", null);
}
if (photoFile == null || !photoFile.exists()) {
return new FaceResult(500, "照片文件无效", null);
}
try {
HttpRequest request = HttpRequest.post(BASE_URL + USER_ADD_PATH)
.form("name", idNumber)
// Hutool 自动处理 multipart
.form("photo", photoFile);
if (groupId != null) {
request.form("groupId", groupId.toString());
}
HttpResponse response = request.timeout(10000).execute();
int status = response.getStatus();
String body = response.body();
if (status != 200) {
return new FaceResult(500, "HTTP Error: " + status, null);
}
JSONObject respJson = JSONUtil.parseObj(body);
int code = respJson.getInt("code", -1);
String msg = respJson.getStr("msg", "Unknown");
if (code != 200) {
return new FaceResult(status, msg, null);
}
JSONObject data = respJson.getJSONObject("data");
Long id = data.getLong("id");
String savedName = data.getStr("name");
Long savedGroupId = data.getLong("groupId", null);
UserInfo userInfo = new UserInfo(id, savedName, savedGroupId);
return new FaceResult(status, "success", userInfo);
} catch (Exception e) {
return new FaceResult(500, "请求异常: " + e.getMessage(), null);
}
}
/**
* 核心方法通过文件上传更新人员信息
*
* @param id 人员ID必填
* @param idNumber 人员主键必填
* @param groupId 分组ID可为 null表示不修改
* @param photoFile 新照片文件可为 null表示不修改
* @return 更新结果
*/
public static FaceResult updateUser(Long id, String idNumber, Long groupId, File photoFile) {
if (id == null || id <= 0) {
return new FaceResult(500, "人员ID无效", null);
}
if (idNumber == null || idNumber.trim().isEmpty()) {
return new FaceResult(500, "人员主键不能为空", null);
}
try {
HttpRequest request = HttpRequest.post(BASE_URL + USER_UPDATE_PATH +"/"+ id)
.form("name", idNumber); // 必填
if (groupId != null) {
request.form("groupId", groupId.toString());
}
if (photoFile != null && photoFile.exists()) {
request.form("photo", photoFile);
}
HttpResponse response = request.timeout(10000).execute();
int status = response.getStatus();
String body = response.body();
if (status != 200) {
return new FaceResult(status, "HTTP Error: " + status, null);
}
JSONObject respJson = JSONUtil.parseObj(body);
int code = respJson.getInt("code", -1);
String msg = respJson.getStr("msg", "Unknown");
if (code != 200) {
return new FaceResult(status, msg, null);
}
// 可根据实际返回结构解析 data此处简化为只返回成功状态
return new FaceResult(status, "success", null);
} catch (Exception e) {
return new FaceResult(500, "请求异常: " + e.getMessage(), null);
}
}
/**
* 用于上传一张人脸照片并在指定分组内检索最相似的人
* @param photoFile 人员主键关键词可为 null 或空表示不筛选
* @param groupId 分组ID可为 null表示不筛选
* @return 查询结果
*/
public static FaceResult faceRecognition(Long groupId, File photoFile) {
if (photoFile == null || !photoFile.exists()) {
return new FaceResult(500, "照片文件无效", null);
}
if (groupId == null || groupId <= 0) {
return new FaceResult(500, "分组Id不能为空", null);
}
try {
HttpRequest request = HttpRequest.post(BASE_URL + USER_SEARCH_PATH)
.form("photo", photoFile)
.form("groupId", groupId);
HttpResponse response = request.timeout(10000).execute();
int status = response.getStatus();
String body = response.body();
if (status != 200) {
return new FaceResult(status, "HTTP Error: " + status, null);
}
JSONObject respJson = JSONUtil.parseObj(body);
int code = respJson.getInt("code", -1);
String msg = respJson.getStr("msg", "Unknown");
if (code != 200) {
return new FaceResult(status, msg, null);
}
// 解析 data 数组
JSONObject obj = respJson.getJSONObject("data");
UserInfo userInfo = null;
if (obj != null) {
Long id = obj.getLong("id");
String userName = obj.getStr("name");
Long gid = obj.getLong("groupId", null);
userInfo = new UserInfo(id,userName,gid);
}
// 可根据实际返回结构解析 data此处简化为只返回成功状态
return new FaceResult(status, "检测成功", userInfo);
} catch (Exception e) {
return new FaceResult(500, "请求异常: " + e.getMessage(), null);
}
}
/**
* 通过主键去更新人员数据
*
* @param idNumber 人员主键关键词可为 null 或空表示不筛选
* @param groupId 分组ID可为 null表示不筛选
* @return 查询结果
*/
public static FaceResult updateUserByIdNumber(String idNumber, Long groupId, File photoFile) {
try {
FaceResult faceResult = getFaceUserList(idNumber, groupId);
if(faceResult.getCode() !=200){
return faceResult;
}
List<UserInfo> userList = (List<UserInfo>) faceResult.getData();
if(userList.isEmpty()){
return addUser(idNumber, groupId, photoFile);
}else if(userList.size()>1){
return new FaceResult(500, "查询到多个人员主键,请去人脸库查找问题", null);
}else {
return updateUser(userList.get(0).getId(), idNumber, groupId, photoFile);
}
} catch (Exception e) {
return new FaceResult(500, "请求异常: " + e.getMessage(), null);
}
}
/**
* 获取人员列表支持按人员主键模糊查询按分组筛选
*
* @param idNumber 人员主键关键词可为 null 或空表示不筛选
* @param groupId 分组ID可为 null表示不筛选
* @return 查询结果
*/
public static FaceResult getFaceUserList(String idNumber, Long groupId) {
try {
HttpRequest request = HttpRequest.get(BASE_URL + USER_LIST_PATH);
// 动态添加查询参数仅当值有效时
if (idNumber != null && !idNumber.trim().isEmpty()) {
request.form("name", idNumber.trim()); // Hutool GET 也支持 .form() 自动转 query
}
if (groupId != null && groupId > 0) {
request.form("groupId", groupId.toString());
}
HttpResponse response = request.timeout(5000).execute();
int status = response.getStatus();
String body = response.body();
if (status != 200) {
return new FaceResult(status, "HTTP Error: " + status, null);
}
JSONObject respJson = JSONUtil.parseObj(body);
int code = respJson.getInt("code", -1);
String msg = respJson.getStr("msg", "Unknown");
if (code != 200) {
return new FaceResult(status, msg, null);
}
// 解析 data 数组
JSONArray dataArray = respJson.getJSONArray("data");
List<UserInfo> userList = new ArrayList<>();
if (dataArray != null) {
for (Object obj : dataArray) {
if (obj instanceof JSONObject) {
JSONObject item = (JSONObject) obj;
Long id = item.getLong("id");
String userName = item.getStr("name");
Long gid = item.getLong("groupId", null);
userList.add(new UserInfo(id, userName, gid));
}
}
}
return new FaceResult(status, "success", userList);
} catch (Exception e) {
return new FaceResult(500, "请求异常: " + e.getMessage(), null);
}
}
/**
* 便捷方法通过 Base64 字符串新增人员
* 支持格式
* - Base64: "/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAg..."
* - Data URL: "data:image/jpeg;base64,/9j/4AAQ..."
* @param idNumber 人员主键
* @param groupId 分组ID可为 null
* @param base64Image Base64 编码的图片
* @return 添加结果
*/
public static FaceResult addUserWithBase64(String idNumber, Long groupId, String base64Image) {
if (base64Image == null || base64Image.trim().isEmpty()) {
return new FaceResult(500, "Base64 图片为空", null);
}
File tempFile = null;
try {
tempFile = base64ToFile(base64Image, "face_add_");
if (tempFile == null) {
return new FaceResult(500, "无法创建临时文件", null);
}
return addUser(idNumber, groupId, tempFile);
} catch (IllegalArgumentException e) {
return new FaceResult(500, "Base64 格式无效: " + e.getMessage(), null);
} catch (IORuntimeException e) {
return new FaceResult(500, "写入临时文件失败: " + e.getMessage(), null);
} finally {
if (tempFile != null && tempFile.exists()) {
FileUtil.del(tempFile);
}
}
}
/**
* 便捷方法通过 Base64 更新人员信息
*
* @param id 人员ID
* @param idNumber idNumber必填
* @param groupId 分组ID可为 null
* @param base64Image Base64 编码的图片可为 null
* @return 更新结果
*/
public static FaceResult updateUserWithBase64(Long id, String idNumber, Long groupId, String base64Image) {
File tempFile = null;
try {
if (base64Image != null && !base64Image.trim().isEmpty()) {
tempFile = base64ToFile(base64Image, "face_update_");
if (tempFile == null) {
return new FaceResult(500, "无法创建临时文件", null);
}
}
// base64Image 为空 tempFile null表示不更新照片
return updateUser(id, idNumber, groupId, tempFile);
} catch (IllegalArgumentException e) {
return new FaceResult(500, "Base64 格式无效: " + e.getMessage(), null);
} catch (IORuntimeException e) {
return new FaceResult(500, "写入临时文件失败: " + e.getMessage(), null);
} finally {
if (tempFile != null && tempFile.exists()) {
FileUtil.del(tempFile);
}
}
}
/**
* 通过主键去更新人员数据
*
* @param idNumber 人员主键关键词可为 null 或空表示不筛选
* @param groupId 分组ID可为 null表示不筛选
* @return 查询结果
*/
public static FaceResult updateUserByIdNumberBase64(String idNumber, Long groupId, String photoFileBase64) {
try {
FaceResult faceResult = getFaceUserList(idNumber, groupId);
if(faceResult.getCode() !=200){
return faceResult;
}
List<UserInfo> userList = (List<UserInfo>) faceResult.getData();
if(userList.isEmpty()){
return addUserWithBase64(idNumber, groupId, photoFileBase64);
}else if(userList.size()>1){
return new FaceResult(500, "查询到多个人员主键,请去人脸库查找问题", null);
}else {
return updateUserWithBase64(userList.get(0).getId(), idNumber, groupId, photoFileBase64);
}
} catch (Exception e) {
return new FaceResult(500, "请求异常: " + e.getMessage(), null);
}
}
/**
* Base64 编码的图片字符串转换为临时文件
*
* @param base64Image 支持纯 Base64 Data URL 格式 data:image/jpeg;base64,...
* @param prefix 临时文件前缀 "face_add_", "face_update_"用于区分用途
* @return 临时 File 对象若输入无效则返回 null
* @throws IllegalArgumentException Base64 格式非法
* @throws IORuntimeException 写入临时文件失败
*/
public static File base64ToFile(String base64Image, String prefix) {
if (base64Image == null || base64Image.trim().isEmpty()) {
return null;
}
String base64Data = base64Image.trim();
// 去除 Data URL 前缀
Pattern pattern = Pattern.compile("^data:image/(jpeg|jpg|png);base64,(.*)$", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(base64Data);
if (matcher.matches()) {
base64Data = matcher.group(2);
}
// 解码
byte[] imageBytes = Base64.getDecoder().decode(base64Data);
// 生成唯一文件名
String fileName = (prefix != null ? prefix : "temp_") + IdUtil.fastSimpleUUID() + ".jpg";
String tempPath = System.getProperty("java.io.tmpdir") + "/" + fileName;
// 写入临时文件
return FileUtil.writeBytes(imageBytes, tempPath);
}
public static File multipartToFile(MultipartFile multipartFile) throws IOException {
// 创建临时文件自动在系统临时目录
File tempFile = File.createTempFile(
"upload_",
"." + getExtension(multipartFile.getOriginalFilename())
);
// MultipartFile 写入临时文件
multipartFile.transferTo(tempFile);
return tempFile;
}
// 辅助方法获取文件扩展名
private static String getExtension(String fileName) {
if (fileName == null || fileName.lastIndexOf(".") == -1) {
return ""; // 无扩展名
}
return fileName.substring(fileName.lastIndexOf(".") + 1);
}
}

View File

@ -28,4 +28,7 @@ jasypt:
password: Encrypt
#人脸
face:
path: http://112.29.103.165:1616/faceIdentification
service:
base-url: http://192.168.0.37:18080/api
face-url: http://192.168.0.37:18000
groupId: 5

View File

@ -36,9 +36,9 @@
SELECT
psc.id AS sub_com_id,
psc.sub_company_name,
SUM(CASE WHEN pp.pro_status = '0' THEN 1 ELSE 0 END) AS buildProNum,
SUM(CASE WHEN pp.pro_status = '2' THEN 1 ELSE 0 END) AS preProNum,
SUM(CASE WHEN pp.pro_status = '4' THEN 1 ELSE 0 END) AS completedProNum,
COUNT(DISTINCT CASE WHEN pp.pro_status = '0' THEN pp.id ELSE null END) AS buildProNum,
COUNT(DISTINCT CASE WHEN pp.pro_status = '2' THEN pp.id ELSE null END) AS preProNum,
COUNT(DISTINCT CASE WHEN pp.pro_status = '4' THEN pp.id ELSE null END) AS completedProNum,
COUNT(DISTINCT bsc.sub_id) AS subNum,
COUNT(DISTINCT bstc.team_id) AS teamNum,
COUNT(DISTINCT bwem.worker_id) AS einNum,

View File

@ -275,7 +275,7 @@
count(1)
FROM
bm_worker_ein_msg bwem
INNER JOIN bm_att_person bap ON bap.worker_id
INNER JOIN bm_att_person bap ON bap.worker_id = bwem.worker_id
AND bap.pro_id = bwem.pro_id
WHERE
bwem.worker_id = #{workerId}

View File

@ -435,8 +435,8 @@
<if test="teamName != null and teamName != ''">
and locate(#{teamName}, bwem.team_name) > 0
</if>
<if test="name != null and name != ''">
and pw.name like concat('%',#{name},'%')
<if test="workerName != null and workerName != ''">
and pw.name like concat('%',#{workerName},'%')
</if>
GROUP BY
pw.id,bwem.pro_id

View File

@ -1,20 +1,5 @@
package com.bonus.job.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.bonus.common.log.annotation.SysLog;
import com.bonus.common.log.enums.OperaType;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.bonus.common.core.constant.Constants;
import com.bonus.common.core.exception.job.TaskException;
import com.bonus.common.core.utils.StringUtils;
@ -22,16 +7,24 @@ import com.bonus.common.core.utils.poi.ExcelUtil;
import com.bonus.common.core.web.controller.BaseController;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.common.log.annotation.SysLog;
import com.bonus.common.log.enums.OperaType;
import com.bonus.common.security.annotation.RequiresPermissions;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.job.domain.SysJob;
import com.bonus.job.service.ISysJobService;
import com.bonus.job.util.CronUtils;
import com.bonus.job.util.ScheduleUtils;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 调度任务信息操作处理
*
*
* @author bonus
*/
@RestController
@ -165,7 +158,7 @@ public class SysJobController extends BaseController
* 定时任务立即执行一次
*/
@RequiresPermissions("monitor:job:changeStatus")
@PostMapping("/run")
@PostMapping("/run")
@SysLog(title = "定时任务", businessType = OperaType.UPDATE,logType = 0,module = "系统监控->定时任务",details = "定时任务立即执行一次")
public AjaxResult run(@RequestBody SysJob job) throws SchedulerException
{

View File

@ -1,7 +1,11 @@
package com.bonus.job.service;
import java.util.List;
import javax.annotation.PostConstruct;
import com.bonus.common.core.constant.ScheduleConstants;
import com.bonus.common.core.exception.job.TaskException;
import com.bonus.job.domain.SysJob;
import com.bonus.job.mapper.SysJobMapper;
import com.bonus.job.util.CronUtils;
import com.bonus.job.util.ScheduleUtils;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
@ -9,16 +13,13 @@ import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.bonus.common.core.constant.ScheduleConstants;
import com.bonus.common.core.exception.job.TaskException;
import com.bonus.job.domain.SysJob;
import com.bonus.job.mapper.SysJobMapper;
import com.bonus.job.util.CronUtils;
import com.bonus.job.util.ScheduleUtils;
import javax.annotation.PostConstruct;
import java.util.List;
/**
* 定时任务调度信息 服务层
*
*
* @author bonus
*/
@Service
@ -46,7 +47,7 @@ public class SysJobServiceImpl implements ISysJobService
/**
* 获取quartz调度器的计划任务列表
*
*
* @param job 调度信息
* @return
*/
@ -58,7 +59,7 @@ public class SysJobServiceImpl implements ISysJobService
/**
* 通过调度任务ID查询调度信息
*
*
* @param jobId 调度任务ID
* @return 调度任务对象信息
*/
@ -70,7 +71,7 @@ public class SysJobServiceImpl implements ISysJobService
/**
* 暂停任务
*
*
* @param job 调度信息
*/
@Override
@ -90,7 +91,7 @@ public class SysJobServiceImpl implements ISysJobService
/**
* 恢复任务
*
*
* @param job 调度信息
*/
@Override
@ -110,7 +111,7 @@ public class SysJobServiceImpl implements ISysJobService
/**
* 删除任务后所对应的trigger也将被删除
*
*
* @param job 调度信息
*/
@Override
@ -129,7 +130,7 @@ public class SysJobServiceImpl implements ISysJobService
/**
* 批量删除调度信息
*
*
* @param jobIds 需要删除的任务ID
* @return 结果
*/
@ -146,7 +147,7 @@ public class SysJobServiceImpl implements ISysJobService
/**
* 任务调度状态修改
*
*
* @param job 调度信息
*/
@Override
@ -168,7 +169,7 @@ public class SysJobServiceImpl implements ISysJobService
/**
* 立即运行任务
*
*
* @param job 调度信息
*/
@Override
@ -193,7 +194,7 @@ public class SysJobServiceImpl implements ISysJobService
/**
* 新增任务
*
*
* @param job 调度信息 调度信息
*/
@Override
@ -211,7 +212,7 @@ public class SysJobServiceImpl implements ISysJobService
/**
* 更新任务的时间表达式
*
*
* @param job 调度信息
*/
@Override
@ -229,7 +230,7 @@ public class SysJobServiceImpl implements ISysJobService
/**
* 更新任务
*
*
* @param job 任务对象
* @param jobGroup 任务组名
*/
@ -248,7 +249,7 @@ public class SysJobServiceImpl implements ISysJobService
/**
* 校验cron表达式是否有效
*
*
* @param cronExpression 表达式
* @return 结果
*/
@ -257,4 +258,4 @@ public class SysJobServiceImpl implements ISysJobService
{
return CronUtils.isValid(cronExpression);
}
}
}