Ver Fonte

人脸识别管理模块

lihao16 há 1 ano atrás
pai
commit
bf96dc2061

+ 19 - 0
inspur-admin/src/main/java/com/inspur/web/controller/partywork/PartyMeetingInfoController.java

@@ -3,6 +3,7 @@ package com.inspur.web.controller.partywork;
 import java.util.List;
 import javax.servlet.http.HttpServletResponse;
 
+import com.inspur.domain.app.PartyAppUser;
 import com.inspur.domain.partywork.PartyMeetingInfo;
 import com.inspur.service.partywork.IPartyMeetingInfoService;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -156,4 +157,22 @@ public class PartyMeetingInfoController extends BaseController
     {
         return AjaxResult.success(partyMeetingInfoService.getFileImage(id));
     }
+
+    /**
+     * 三会一课主题活动大屏端签到
+     */
+    @PostMapping(value = "/sign")
+    public AjaxResult meetingSign(@RequestBody PartyAppUser partyAppUser)
+    {
+        int i = partyMeetingInfoService.meetingSign(partyAppUser);
+        if (i == -1) {
+            return AjaxResult.error("未到签到时间,会议开始前一小时可签到!");
+        } else if (i == -2) {
+            return AjaxResult.error("签到时间已过,会议已结束!");
+        } else if (i == -3) {
+            return AjaxResult.error("用户无权限,签到失败!");
+        } else {
+            return AjaxResult.success(i);
+        }
+    }
 }

+ 4 - 4
inspur-admin/src/main/resources/application.yml

@@ -18,11 +18,11 @@ inspur:
   captchaType: math
   server:
     # 项目部署方式 nginx tomcat
-    type: nginx
+    type: tomcat
     # tomcat部署 项目根路径
     tomcat-path: /party-admin
     # 服务部署Ip
-    ip: 192.168.31.146
+    ip: 117.73.13.40
 
 # 开发环境配置
 server:
@@ -152,8 +152,8 @@ netty:
   url: http://hycp.guoziyu.cn/inspur-admin/largeScreen/party/netty
   idUrl: http://hycp.guoziyu.cn/inspur-admin/largeScreen/party/netty/id
   playUrl: http://hycp.guoziyu.cn/inspur-admin/largeScreen/party/netty/play
-  # controlUrl: http://hycp.guoziyu.cn/inspur-admin/largeScreen/party/netty/control
-  controlUrl: http://127.0.0.1:8901/largeScreen/party/netty/control
+  controlUrl: http://hycp.guoziyu.cn/inspur-admin/largeScreen/party/netty/control
+  # controlUrl: http://127.0.0.1:8901/largeScreen/party/netty/control
 
 # 项目相关配置
 SM2:

+ 76 - 0
inspur-ai/src/main/java/com/inspur/face/controller/CompreFaceController.java

@@ -0,0 +1,76 @@
+package com.inspur.face.controller;
+
+import com.inspur.common.core.controller.BaseController;
+import com.inspur.common.core.domain.AjaxResult;
+import com.inspur.common.core.page.TableDataInfo;
+import com.inspur.face.domain.PartyFaceRecognition;
+import com.inspur.face.domain.PartyMemberFace;
+import com.inspur.face.domain.SubjectBean;
+import com.inspur.face.service.CompreFaceService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+
+/**
+ * compreface 算法接口
+ *
+ * @author lihao16
+ */
+@RestController
+@RequestMapping(value = "/compreface")
+public class CompreFaceController extends BaseController {
+
+    @Autowired
+    private CompreFaceService compreFaceService;
+
+    /**
+     * 创建人脸信息
+     * @param subject
+     * @return
+     */
+    @PostMapping("/recognition/subjects")
+    public AjaxResult addSubject(@RequestBody SubjectBean subject) {
+        return compreFaceService.addSubject(subject);
+    }
+
+
+    @PostMapping("/recognition/faces")
+    public AjaxResult uploadFace(@RequestParam("subject")String subject, @RequestBody MultipartFile file) {
+        return compreFaceService.uploadFace(subject,file);
+    }
+
+    @PostMapping("/recognition/faces2")
+    public AjaxResult uploadFace2(@RequestBody PartyMemberFace partyMemberFace) {
+        return compreFaceService.uploadFace2(partyMemberFace);
+    }
+
+    @PostMapping("/recognition/recognize")
+    public AjaxResult recognizeFace(@RequestBody MultipartFile file) {
+        return compreFaceService.recognizeFace(file);
+    }
+
+    @GetMapping("/record/{id}")
+    public AjaxResult recordInfo(@PathVariable("id") Long id) {
+        return compreFaceService.recordInfo(id);
+    }
+
+    /**
+     * 查询党员基础信息列表
+     */
+    @GetMapping("/member/list")
+    public TableDataInfo memberList(PartyMemberFace partyMemberFace)
+    {
+        List<PartyMemberFace> list = compreFaceService.selectPartyMemberFaceList(partyMemberFace);
+        return getDataTable(list);
+    }
+
+    @GetMapping("/recognition/list")
+    public TableDataInfo recognitionList(PartyFaceRecognition partyFaceRecognition)
+    {
+        List<PartyFaceRecognition> list = compreFaceService.selectPartyFaceRecognitionList(partyFaceRecognition);
+        return getDataTable(list);
+    }
+}

+ 45 - 0
inspur-ai/src/main/java/com/inspur/face/domain/PartyFaceRecognition.java

@@ -0,0 +1,45 @@
+package com.inspur.face.domain;
+
+import com.inspur.common.annotation.Excel;
+import com.inspur.common.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 人脸识别记录对象 party_face_recognition
+ *
+ * @author inspur
+ * @date 2024-05-20
+ */
+@Data
+public class PartyFaceRecognition extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 主键ID */
+    private Long id;
+
+    /** 请求参数 */
+    @Excel(name = "请求参数")
+    private String reqParam;
+
+    /** 接口响应 */
+    @Excel(name = "接口响应")
+    private String rspCode;
+
+    /** 接口响应 */
+    @Excel(name = "接口响应")
+    private String rspMsg;
+
+    /** 1-上传姓名 2-上传人脸 3-人脸识别 */
+    @Excel(name = "1-上传姓名 2-上传人脸 3-人脸识别")
+    private Integer opType;
+
+    /** 1-等待 2-完成 */
+    @Excel(name = "0-未知 1-成功 2-失败")
+    private Integer opStatus;
+
+    private Long userTableId;
+
+    private Long memberId;
+
+}

+ 26 - 0
inspur-ai/src/main/java/com/inspur/face/domain/PartyMemberFace.java

@@ -0,0 +1,26 @@
+package com.inspur.face.domain;
+
+import lombok.Data;
+
+/**
+ * 党员人脸识别
+ *
+ * @author lihao16
+ */
+@Data
+public class PartyMemberFace extends PartyFaceRecognition{
+
+    private String name;
+
+    private Integer gender;
+
+    private Long memberId;
+
+    private String orgName;
+
+    private String mobile;
+
+    private String picPath;
+
+
+}

+ 15 - 0
inspur-ai/src/main/java/com/inspur/face/domain/SubjectBean.java

@@ -0,0 +1,15 @@
+package com.inspur.face.domain;
+
+import lombok.Data;
+
+/**
+ * subject bean
+ *
+ * @author lihao16
+ */
+@Data
+public class SubjectBean {
+
+    private String subject;
+
+}

+ 66 - 0
inspur-ai/src/main/java/com/inspur/face/mapper/PartyFaceRecognitionMapper.java

@@ -0,0 +1,66 @@
+package com.inspur.face.mapper;
+
+import com.inspur.face.domain.PartyFaceRecognition;
+import com.inspur.face.domain.PartyMemberFace;
+
+import java.util.List;
+
+
+/**
+ * 人脸识别记录Mapper接口
+ *
+ * @author inspur
+ * @date 2024-05-20
+ */
+public interface PartyFaceRecognitionMapper
+{
+    /**
+     * 查询人脸识别记录
+     *
+     * @param id 人脸识别记录主键
+     * @return 人脸识别记录
+     */
+    public PartyFaceRecognition selectPartyFaceRecognitionById(Long id);
+
+    /**
+     * 查询人脸识别记录列表
+     *
+     * @param partyFaceRecognition 人脸识别记录
+     * @return 人脸识别记录集合
+     */
+    public List<PartyFaceRecognition> selectPartyFaceRecognitionList(PartyFaceRecognition partyFaceRecognition);
+
+    /**
+     * 新增人脸识别记录
+     *
+     * @param partyFaceRecognition 人脸识别记录
+     * @return 结果
+     */
+    public int insertPartyFaceRecognition(PartyFaceRecognition partyFaceRecognition);
+
+    /**
+     * 修改人脸识别记录
+     *
+     * @param partyFaceRecognition 人脸识别记录
+     * @return 结果
+     */
+    public int updatePartyFaceRecognition(PartyFaceRecognition partyFaceRecognition);
+
+    /**
+     * 删除人脸识别记录
+     *
+     * @param id 人脸识别记录主键
+     * @return 结果
+     */
+    public int deletePartyFaceRecognitionById(Long id);
+
+    /**
+     * 批量删除人脸识别记录
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deletePartyFaceRecognitionByIds(Long[] ids);
+
+    public List<PartyMemberFace> selectPartyMemberFaceList(PartyMemberFace partyMemberFace);
+}

+ 32 - 0
inspur-ai/src/main/java/com/inspur/face/service/CompreFaceService.java

@@ -0,0 +1,32 @@
+package com.inspur.face.service;
+
+import com.inspur.common.core.domain.AjaxResult;
+import com.inspur.face.domain.PartyFaceRecognition;
+import com.inspur.face.domain.PartyMemberFace;
+import com.inspur.face.domain.SubjectBean;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * compreface 算法接口 service
+ *
+ * @author lihao16
+ */
+public interface CompreFaceService {
+
+
+    public AjaxResult addSubject(SubjectBean subject);
+
+    public AjaxResult uploadFace(String subject, MultipartFile file);
+
+    public AjaxResult recognizeFace(MultipartFile file);
+
+    public AjaxResult recordInfo(Long id);
+
+    public List<PartyMemberFace> selectPartyMemberFaceList(PartyMemberFace partyMemberFace);
+
+    public AjaxResult uploadFace2(PartyMemberFace partyMemberFace);
+
+    public List<PartyFaceRecognition> selectPartyFaceRecognitionList(PartyFaceRecognition partyFaceRecognition);
+}

+ 424 - 0
inspur-ai/src/main/java/com/inspur/face/service/impl/CompreFaceServiceImpl.java

@@ -0,0 +1,424 @@
+package com.inspur.face.service.impl;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpStatus;
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.inspur.common.config.InspurConfig;
+import com.inspur.common.constant.Constants;
+import com.inspur.common.core.domain.AjaxResult;
+import com.inspur.common.utils.DateUtils;
+import com.inspur.common.utils.SecurityUtils;
+import com.inspur.common.utils.StringUtils;
+import com.inspur.common.utils.file.FileUploadUtils;
+import com.inspur.common.utils.file.FileUtils;
+import com.inspur.face.domain.PartyFaceRecognition;
+import com.inspur.face.domain.PartyMemberFace;
+import com.inspur.face.domain.SubjectBean;
+import com.inspur.face.mapper.PartyFaceRecognitionMapper;
+import com.inspur.face.service.CompreFaceService;
+import com.inspur.framework.config.ServerConfig;
+import com.inspur.system.domain.SysTableList;
+import com.inspur.system.domain.SysUserTableRel;
+import com.inspur.system.service.ISysUserTableRelService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import static com.inspur.common.utils.PageUtils.startPage;
+
+/**
+ * compreface 算法接口 service
+ *
+ * @author lihao16
+ */
+@Service
+public class CompreFaceServiceImpl implements CompreFaceService {
+
+    private static final Logger log = LoggerFactory.getLogger(CompreFaceServiceImpl.class);
+
+    @Autowired
+    private ServerConfig serverConfig;
+
+    @Autowired
+    private PartyFaceRecognitionMapper partyFaceRecognitionMapper;
+
+    @Autowired
+    private ISysUserTableRelService sysUserTableRelService;
+
+    private static final String FACE_RECOGNITION_TABLE_NAME = "party_face_recognition";
+
+    private final static String MEMBER_TABLE_NAME = "party_member_manage";
+
+    /**
+     * 添加subject URL
+     */
+    public static final String URL_ADD_SUBJECT = "http://117.73.13.40:8000/api/v1/recognition/subjects";
+
+    /**
+     * 上传人脸照片 URL
+     */
+    public static final String URL_UPLOAD_FACE = "http://117.73.13.40:8000/api/v1/recognition/faces?subject=";
+
+    /**
+     * 人脸识别 URL
+     */
+    // public static final String URL_FACE_RECOGNITION = "http://117.73.13.40:8000/api/v1/recognition/recognize?face_plugins=landmarks&face_plugins=gender&face_plugins=age&face_plugins=pose";
+    public static final String URL_FACE_RECOGNITION = "http://117.73.13.40:8000/api/v1/recognition/recognize";
+
+    private final static String API_KEY = "fccde51d-9b32-4468-97b1-cf454b473e55";
+
+    private static final String FILE_TEMP_PATH = "/home/inspur/party-admin/temp/";
+
+
+    @Override
+    public List<PartyFaceRecognition> selectPartyFaceRecognitionList(PartyFaceRecognition partyFaceRecognition) {
+        Long userId = SecurityUtils.getLoginUser().getUserId();
+        partyFaceRecognition.setUserTableId(getUserTableId(FACE_RECOGNITION_TABLE_NAME, userId, 0));
+        startPage();
+        return partyFaceRecognitionMapper.selectPartyFaceRecognitionList(partyFaceRecognition);
+    }
+
+    @Override
+    public AjaxResult addSubject(SubjectBean subject) {
+        // 数据库创建记录
+        Long userId = SecurityUtils.getLoginUser().getUserId();
+        PartyFaceRecognition partyFaceRecognition = new PartyFaceRecognition();
+        partyFaceRecognition.setReqParam(subject.getSubject());
+        partyFaceRecognition.setOpType(1);
+        partyFaceRecognition.setOpStatus(0);
+        partyFaceRecognition.setCreateTime(DateUtils.getNowDate());
+        partyFaceRecognition.setUserTableId(getUserTableId(FACE_RECOGNITION_TABLE_NAME, userId, 0));
+        partyFaceRecognitionMapper.insertPartyFaceRecognition(partyFaceRecognition);
+        // 调用算法服务
+        String rspCode = "";
+        String rspMsg = "";
+        Integer opStatus = 1;
+        try {
+            // 发送请求添加subject
+            HttpResponse response = HttpRequest.post(URL_ADD_SUBJECT)
+                    .body("{\"subject\":\"" + subject.getSubject() + "\"}")
+                    .header("x-api-key", API_KEY)
+                    .execute();
+            // 解析返回结果
+            rspCode = String.valueOf(response.getStatus());
+            rspMsg = response.body();
+            if (!String.valueOf(HttpStatus.HTTP_CREATED).equals(rspCode)) {
+                opStatus = 2;
+                log.info("addSubject error,subject:{},rspMsg:{}",subject.getSubject(),rspMsg);
+            }
+        }catch (Exception e) {
+            opStatus = 2;
+            rspMsg = e.getMessage();
+            log.info("addSubjectTask error,subject:{}",subject.getSubject(),e);
+        }finally {
+            partyFaceRecognition.setOpStatus(opStatus);
+            partyFaceRecognition.setRspCode(rspCode);
+            partyFaceRecognition.setRspMsg(rspMsg);
+            partyFaceRecognition.setUpdateTime(DateUtils.getNowDate());
+            partyFaceRecognitionMapper.updatePartyFaceRecognition(partyFaceRecognition);
+        }
+        return AjaxResult.success(partyFaceRecognition);
+    }
+
+
+
+    @Override
+    public AjaxResult uploadFace(String subject, MultipartFile file) {
+        // 保存数据库
+        Long userId = SecurityUtils.getLoginUser().getUserId();
+        Map<String,String> fileMap = uploadFile(file);
+        JSONObject reqParam = new JSONObject();
+        reqParam.put("subject", subject);
+        reqParam.put("url", fileMap.get("url"));
+        String filePath = getFilePathByUrl(fileMap.get("url"));
+        reqParam.put("filePath", filePath);
+        PartyFaceRecognition partyFaceRecognition = new PartyFaceRecognition();
+        partyFaceRecognition.setReqParam(reqParam.toJSONString());
+        partyFaceRecognition.setOpType(2);
+        partyFaceRecognition.setOpStatus(0);
+        partyFaceRecognition.setCreateTime(DateUtils.getNowDate());
+        partyFaceRecognition.setUserTableId(getUserTableId(FACE_RECOGNITION_TABLE_NAME, userId, 0));
+        partyFaceRecognitionMapper.insertPartyFaceRecognition(partyFaceRecognition);
+        // 调用算法服务
+        String rspCode = "";
+        String rspMsg = "";
+        Integer opStatus = 1;
+        try {
+            File imageFile = new File(filePath);
+            // 发送请求添加subject
+            HttpResponse response = HttpRequest.post(URL_UPLOAD_FACE + subject)
+                    .form("file",imageFile)
+                    .header("x-api-key", API_KEY)
+                    .execute();
+            // 解析返回结果
+            rspCode = String.valueOf(response.getStatus());
+            rspMsg = response.body();
+            if (!String.valueOf(HttpStatus.HTTP_CREATED).equals(rspCode)) {
+                opStatus = 2;
+                log.info("uploadFace error,subject:{},rspMsg:{}",subject,rspMsg);
+            }
+        }catch (Exception e) {
+            opStatus = 2;
+            rspMsg = e.getMessage();
+            log.info("uploadFace error,reqParam:{}",partyFaceRecognition.getReqParam(),e);
+        }finally {
+            partyFaceRecognition.setOpStatus(opStatus);
+            partyFaceRecognition.setRspCode(rspCode);
+            partyFaceRecognition.setRspMsg(rspMsg);
+            partyFaceRecognition.setUpdateTime(DateUtils.getNowDate());
+            partyFaceRecognitionMapper.updatePartyFaceRecognition(partyFaceRecognition);
+        }
+        return AjaxResult.success(partyFaceRecognition);
+    }
+
+    @Override
+    public AjaxResult recognizeFace(MultipartFile file) {
+        Long userId = SecurityUtils.getLoginUser().getUserId();
+        Map<String,String> fileMap = uploadFile(file);
+        JSONObject reqParam = new JSONObject();
+        reqParam.put("url", fileMap.get("url"));
+        String filePath = getFilePathByUrl(fileMap.get("url"));
+        reqParam.put("filePath", filePath);
+        PartyFaceRecognition partyFaceRecognition = new PartyFaceRecognition();
+        partyFaceRecognition.setReqParam(reqParam.toJSONString());
+        partyFaceRecognition.setOpType(3);
+        partyFaceRecognition.setOpStatus(0);
+        partyFaceRecognition.setCreateTime(DateUtils.getNowDate());
+        partyFaceRecognition.setUserTableId(getUserTableId(FACE_RECOGNITION_TABLE_NAME, userId, 0));
+        partyFaceRecognitionMapper.insertPartyFaceRecognition(partyFaceRecognition);
+        // 调用算法服务
+        String rspCode = "";
+        String rspMsg = "";
+        Integer opStatus = 1;
+        try {
+            File imageFile = new File(filePath);
+            // 发送请求添加subject
+            HttpResponse response = HttpRequest.post(URL_FACE_RECOGNITION)
+                    .form("file",imageFile)
+                    .header("x-api-key", API_KEY)
+                    .execute();
+            // 解析返回结果
+            rspCode = String.valueOf(response.getStatus());
+            rspMsg = response.body();
+            if (!String.valueOf(HttpStatus.HTTP_OK).equals(rspCode)) {
+                opStatus = 2;
+                log.info("recognizeFace error,file:{},rspMsg:{}",fileMap.get("url"),rspMsg);
+            }
+        }catch (Exception e) {
+            opStatus = 2;
+            rspMsg = e.getMessage();
+            log.info("recognizeFace error,file:{}",fileMap.get("url"),e);
+        }finally {
+            partyFaceRecognition.setOpStatus(opStatus);
+            partyFaceRecognition.setRspCode(rspCode);
+            partyFaceRecognition.setRspMsg(rspMsg);
+            partyFaceRecognition.setUpdateTime(DateUtils.getNowDate());
+            partyFaceRecognitionMapper.updatePartyFaceRecognition(partyFaceRecognition);
+        }
+        return AjaxResult.success(partyFaceRecognition);
+    }
+
+    @Override
+    public AjaxResult recordInfo(Long id) {
+        PartyFaceRecognition result = partyFaceRecognitionMapper.selectPartyFaceRecognitionById(id);
+        return AjaxResult.success(result);
+    }
+
+    @Override
+    public List<PartyMemberFace> selectPartyMemberFaceList(PartyMemberFace partyMemberFace) {
+        SysTableList tableInfo = sysUserTableRelService.selectTableInfoByName(MEMBER_TABLE_NAME,0);
+        Long tableId = tableInfo.getId();
+        SysUserTableRel tableRel = sysUserTableRelService.getRelByUserTableId(SecurityUtils.getLoginUser().getUserId(),tableId);
+        Long userTableId = tableRel.getUserTableId();
+        partyMemberFace.setUserTableId(userTableId);
+        startPage();
+        return partyFaceRecognitionMapper.selectPartyMemberFaceList(partyMemberFace);
+    }
+
+    @Override
+    public AjaxResult uploadFace2(PartyMemberFace partyMemberFace) {
+        // 查询当前党员是否已经增加subject
+        PartyFaceRecognition subjectParam = new PartyFaceRecognition();
+        subjectParam.setMemberId(partyMemberFace.getMemberId());
+        subjectParam.setOpStatus(1);
+        subjectParam.setOpType(1);
+        List<PartyFaceRecognition> subjectList = partyFaceRecognitionMapper.selectPartyFaceRecognitionList(subjectParam);
+        if (CollectionUtils.isEmpty(subjectList)) {
+            PartyFaceRecognition partyFaceRecognition1 = addSubject2(partyMemberFace);
+            if (StringUtils.isEmpty(partyFaceRecognition1.getRspCode()) || !String.valueOf(HttpStatus.HTTP_CREATED).equals(partyFaceRecognition1.getRspCode())) {
+                JSONObject rspMsgJson = JSON.parseObject(partyFaceRecognition1.getRspMsg());
+                return AjaxResult.error("上传人脸失败 : " + rspMsgJson.getString("message"));
+            }
+        }
+        PartyFaceRecognition partyFaceRecognition2 = uploadFace2AI(partyMemberFace);
+        if (StringUtils.isEmpty(partyFaceRecognition2.getRspCode()) || !String.valueOf(HttpStatus.HTTP_CREATED).equals(partyFaceRecognition2.getRspCode())) {
+            JSONObject rspMsgJson = JSON.parseObject(partyFaceRecognition2.getRspMsg());
+            return AjaxResult.error("上传人脸失败 : " + rspMsgJson.getString("message"));
+        }
+
+        return AjaxResult.success();
+    }
+
+    private PartyFaceRecognition uploadFace2AI(PartyMemberFace partyMemberFace) {
+        // 查询当前党员是否已经成功上传过人脸
+        PartyFaceRecognition subjectParam = new PartyFaceRecognition();
+        subjectParam.setMemberId(partyMemberFace.getMemberId());
+        subjectParam.setOpStatus(1);
+        subjectParam.setOpType(2);
+        List<PartyFaceRecognition> subjectList = partyFaceRecognitionMapper.selectPartyFaceRecognitionList(subjectParam);
+        String subject = partyMemberFace.getMemberId() + "_" + partyMemberFace.getName();
+        PartyFaceRecognition partyFaceRecognition = new PartyFaceRecognition();
+        if (CollectionUtils.isEmpty(subjectList)) {
+            // 保存数据库
+            Long userId = SecurityUtils.getLoginUser().getUserId();
+            JSONObject reqParam = new JSONObject();
+            reqParam.put("subject", subject);
+            reqParam.put("url", partyMemberFace.getPicPath());
+            partyFaceRecognition.setReqParam(reqParam.toJSONString());
+            partyFaceRecognition.setOpType(2);
+            partyFaceRecognition.setOpStatus(0);
+            partyFaceRecognition.setCreateTime(DateUtils.getNowDate());
+            partyFaceRecognition.setMemberId(partyMemberFace.getMemberId());
+            partyFaceRecognition.setUserTableId(getUserTableId(FACE_RECOGNITION_TABLE_NAME, userId, 0));
+            partyFaceRecognitionMapper.insertPartyFaceRecognition(partyFaceRecognition);
+        }else {
+            partyFaceRecognition = subjectList.get(0);
+        }
+        // 调用算法服务
+        String rspCode = "";
+        String rspMsg = "";
+        Integer opStatus = 1;
+        File imageFile = downloadFile(partyMemberFace.getPicPath());
+        try {
+            // 发送请求添加subject
+            HttpResponse response = HttpRequest.post(URL_UPLOAD_FACE + subject)
+                    .form("file",imageFile)
+                    .header("x-api-key", API_KEY)
+                    .execute();
+            // 解析返回结果
+            rspCode = String.valueOf(response.getStatus());
+            rspMsg = response.body();
+            if (!String.valueOf(HttpStatus.HTTP_CREATED).equals(rspCode)) {
+                opStatus = 2;
+                log.info("uploadFace error,subject:{},rspMsg:{}",subject,rspMsg);
+            }
+        }catch (Exception e) {
+            opStatus = 2;
+            rspMsg = e.getMessage();
+            log.info("uploadFace error,reqParam:{}",partyFaceRecognition.getReqParam(),e);
+        }finally {
+            // 删除临时文件
+            if (imageFile.exists()) {
+                boolean delB = imageFile.delete();
+                log.info("delete txtFile file : {}",delB);
+            }
+            partyFaceRecognition.setOpStatus(opStatus);
+            partyFaceRecognition.setRspCode(rspCode);
+            partyFaceRecognition.setRspMsg(rspMsg);
+            partyFaceRecognition.setUpdateTime(DateUtils.getNowDate());
+            partyFaceRecognitionMapper.updatePartyFaceRecognition(partyFaceRecognition);
+        }
+        return partyFaceRecognition;
+    }
+
+    private PartyFaceRecognition addSubject2(PartyMemberFace partyMemberFace) {
+        // 数据库创建记录
+        Long userId = SecurityUtils.getLoginUser().getUserId();
+        PartyFaceRecognition partyFaceRecognition = new PartyFaceRecognition();
+        String subject = partyMemberFace.getMemberId() + "_" + partyMemberFace.getName();
+        partyFaceRecognition.setReqParam(subject);
+        partyFaceRecognition.setOpType(1);
+        partyFaceRecognition.setOpStatus(0);
+        partyFaceRecognition.setCreateTime(DateUtils.getNowDate());
+        partyFaceRecognition.setUserTableId(getUserTableId(FACE_RECOGNITION_TABLE_NAME, userId, 0));
+        partyFaceRecognition.setMemberId(partyMemberFace.getMemberId());
+        partyFaceRecognitionMapper.insertPartyFaceRecognition(partyFaceRecognition);
+        // 调用算法服务
+        String rspCode = "";
+        String rspMsg = "";
+        Integer opStatus = 1;
+        try {
+            // 发送请求添加subject
+            HttpResponse response = HttpRequest.post(URL_ADD_SUBJECT)
+                    .body("{\"subject\":\"" + subject + "\"}")
+                    .header("x-api-key", API_KEY)
+                    .execute();
+            // 解析返回结果
+            rspCode = String.valueOf(response.getStatus());
+            rspMsg = response.body();
+            if (!String.valueOf(HttpStatus.HTTP_CREATED).equals(rspCode)) {
+                opStatus = 2;
+                log.info("addSubject error,subject:{},rspMsg:{}",subject,rspMsg);
+            }
+        }catch (Exception e) {
+            opStatus = 2;
+            rspMsg = e.getMessage();
+            log.info("addSubjectTask error,subject:{}",subject,e);
+        }finally {
+            partyFaceRecognition.setOpStatus(opStatus);
+            partyFaceRecognition.setRspCode(rspCode);
+            partyFaceRecognition.setRspMsg(rspMsg);
+            partyFaceRecognition.setUpdateTime(DateUtils.getNowDate());
+            partyFaceRecognitionMapper.updatePartyFaceRecognition(partyFaceRecognition);
+        }
+        return partyFaceRecognition;
+    }
+
+    private Map<String, String> uploadFile(MultipartFile file) {
+        Map<String,String> resultMap = new HashMap<>();
+        try
+        {
+            // 上传文件路径
+            String filePath = InspurConfig.getUploadPath();
+            // 上传并返回新文件名称
+            String fileName = FileUploadUtils.upload(filePath, file);
+            String url = serverConfig.getNewUrl() + fileName;
+            resultMap.put("url", url);
+            resultMap.put("fileName", fileName);
+            resultMap.put("newFileName", FileUtils.getName(fileName));
+            resultMap.put("originalFilename", file.getOriginalFilename());
+            return resultMap;
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    private Long getUserTableId(String tableName, Long userId,Integer dateType) {
+        SysTableList tableInfo = sysUserTableRelService.selectTableInfoByName(tableName,dateType);
+        Long tableId = tableInfo.getId();
+        SysUserTableRel tableRel = sysUserTableRelService.getRelByUserTableId(userId,tableId);
+        Long userTableId = tableRel.getUserTableId();
+        return userTableId;
+    }
+
+    private String getFilePathByUrl(String url) {
+        // 本地资源路径
+        String basePath = InspurConfig.getProfile();
+        // 数据库资源地址
+        return basePath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX);
+    }
+
+    private static File downloadFile(String imageUrl) {
+        String filePath = FILE_TEMP_PATH + UUID.randomUUID().toString() + ".png";
+        // 下载文件
+        HttpUtil.downloadFile(imageUrl, filePath);
+        log.info("download file success,file path : {}:" ,filePath);
+        return new File(filePath);
+    }
+
+
+}

+ 118 - 0
inspur-ai/src/main/resources/mapper/PartyFaceRecognitionMapper.xml

@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.inspur.face.mapper.PartyFaceRecognitionMapper">
+
+    <resultMap type="PartyFaceRecognition" id="PartyFaceRecognitionResult">
+        <result property="id"    column="id"    />
+        <result property="reqParam"    column="req_param"    />
+        <result property="rspCode"    column="rsp_code"    />
+        <result property="rspMsg"    column="rsp_msg"    />
+        <result property="opType"    column="op_type"    />
+        <result property="opStatus"    column="op_status"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="userTableId"    column="user_table_id"    />
+        <result property="memberId"    column="member_id"    />
+    </resultMap>
+
+    <sql id="selectPartyFaceRecognitionVo">
+        select id, req_param, rsp_code, rsp_msg, op_type, op_status, create_time, update_time,user_table_id,member_id from party_face_recognition
+    </sql>
+
+    <select id="selectPartyFaceRecognitionList" parameterType="PartyFaceRecognition" resultMap="PartyFaceRecognitionResult">
+        <include refid="selectPartyFaceRecognitionVo"/>
+        <where>
+            <if test="reqParam != null  and reqParam != ''"> and req_param = #{reqParam}</if>
+            <if test="rspCode != null  and rspCode != ''"> and rsp_code = #{rspCode}</if>
+            <if test="rspMsg != null  and rspMsg != ''"> and rsp_msg = #{rspMsg}</if>
+            <if test="opType != null "> and op_type = #{opType}</if>
+            <if test="opStatus != null "> and op_status = #{opStatus}</if>
+            <if test="userTableId != null "> and user_table_id = #{userTableId}</if>
+            <if test="memberId != null "> and member_id = #{memberId}</if>
+        </where>
+    </select>
+
+    <select id="selectPartyFaceRecognitionById" parameterType="Long" resultMap="PartyFaceRecognitionResult">
+        <include refid="selectPartyFaceRecognitionVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertPartyFaceRecognition" parameterType="PartyFaceRecognition" useGeneratedKeys="true" keyProperty="id">
+        insert into party_face_recognition
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="reqParam != null">req_param,</if>
+            <if test="rspCode != null">rsp_code,</if>
+            <if test="rspMsg != null">rsp_msg,</if>
+            <if test="opType != null">op_type,</if>
+            <if test="opStatus != null">op_status,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="userTableId != null">user_table_id,</if>
+            <if test="memberId != null">member_id,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="reqParam != null">#{reqParam},</if>
+            <if test="rspCode != null">#{rspCode},</if>
+            <if test="rspMsg != null">#{rspMsg},</if>
+            <if test="opType != null">#{opType},</if>
+            <if test="opStatus != null">#{opStatus},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="userTableId != null">#{userTableId},</if>
+            <if test="memberId != null">#{memberId},</if>
+        </trim>
+    </insert>
+
+    <update id="updatePartyFaceRecognition" parameterType="PartyFaceRecognition">
+        update party_face_recognition
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="reqParam != null">req_param = #{reqParam},</if>
+            <if test="rspCode != null">rsp_code = #{rspCode},</if>
+            <if test="rspMsg != null">rsp_msg = #{rspMsg},</if>
+            <if test="opType != null">op_type = #{opType},</if>
+            <if test="opStatus != null">op_status = #{opStatus},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="memberId != null">member_id = #{memberId},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deletePartyFaceRecognitionById" parameterType="Long">
+        delete from party_face_recognition where id = #{id}
+    </delete>
+
+    <delete id="deletePartyFaceRecognitionByIds" parameterType="String">
+        delete from party_face_recognition where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+    <select id="selectPartyMemberFaceList" parameterType="com.inspur.face.domain.PartyMemberFace" resultType="com.inspur.face.domain.PartyMemberFace">
+        SELECT
+            mm.id AS memberId,
+            mm.NAME,
+            mm.gender,
+            mm.org_id,
+            mm.pic_path AS picPath,
+            om.NAME AS orgName,
+            mm.mobile,
+            IFNULL( fr.op_status, 0 ) AS opStatus,
+            fr.rsp_code AS rspCode,
+            fr.rsp_msg AS rspMsg,
+            fr.create_time AS createTime,
+            fr.update_time AS updateTime
+        FROM
+            party_member_manage mm
+        LEFT JOIN (select * from party_face_recognition where op_type = #{opType}) fr ON mm.id = fr.member_id
+        LEFT JOIN party_org_manage om ON mm.org_id = om.id
+        <where>
+            <if test="name != null  and name != ''"> and mm.name = #{name}</if>
+            <if test="gender != null  and gender != ''"> and mm.gender = #{gender}</if>
+            <if test="userTableId != null "> and mm.user_table_id = #{userTableId}</if>
+        </where>
+    </select>
+</mapper>

+ 8 - 0
inspur-party/src/main/java/com/inspur/service/partywork/IPartyMeetingInfoService.java

@@ -151,4 +151,12 @@ public interface IPartyMeetingInfoService
      * @return
      */
     public List<PartyMeetingFollow> getFileImage(Long id);
+
+    /**
+     * 三会一课主题活动大屏端签到
+     *
+     * @param partyAppUser
+     * @return
+     */
+    public int meetingSign(PartyAppUser partyAppUser);
 }

+ 74 - 1
inspur-party/src/main/java/com/inspur/service/partywork/impl/PartyMeetingInfoServiceImpl.java

@@ -8,12 +8,14 @@ import com.google.zxing.common.BitMatrix;
 import com.google.zxing.qrcode.QRCodeWriter;
 import com.inspur.common.config.InspurConfig;
 import com.inspur.common.constant.Constants;
+import com.inspur.common.core.domain.entity.SysUser;
 import com.inspur.common.exception.ServiceException;
 import com.inspur.common.utils.DateUtils;
 import com.inspur.common.utils.LibreOfficeConvertUtil;
 import com.inspur.common.utils.SecurityUtils;
 import com.inspur.common.utils.spring.SpringUtils;
 import com.inspur.domain.app.PartyAppUser;
+import com.inspur.domain.app.PartyMemberInfoVo;
 import com.inspur.domain.partyscreen.PartyMenu;
 import com.inspur.domain.partywork.*;
 import com.inspur.domain.screen.MenuDataReqVo;
@@ -21,6 +23,8 @@ import com.inspur.dt.service.DengTaSyncService;
 import com.inspur.framework.config.ServerConfig;
 import com.inspur.framework.manager.AsyncManager;
 import com.inspur.mapper.*;
+import com.inspur.netty.message.push.PushMessageType;
+import com.inspur.netty.server.PushMessageUtil;
 import com.inspur.service.app.IPartyAppUserService;
 import com.inspur.service.partyscreen.IPartyMenuService;
 import com.inspur.service.partywork.IPartyAttendanceRecordService;
@@ -30,6 +34,7 @@ import com.inspur.service.partywork.IPartyOrgManageService;
 import com.inspur.system.domain.SysTableList;
 import com.inspur.system.domain.SysUserTableRel;
 import com.inspur.system.domain.SysUserWxRel;
+import com.inspur.system.mapper.SysUserMapper;
 import com.inspur.system.mapper.SysUserWxRelMapper;
 import com.inspur.system.service.ISysUserTableRelService;
 import org.apache.commons.fileupload.disk.DiskFileItem;
@@ -102,7 +107,11 @@ public class PartyMeetingInfoServiceImpl implements IPartyMeetingInfoService
     private PartyMeetingFollowMapper partyMeetingFollowMapper;
 
     @Autowired
-    private DengTaSyncService dengTaSyncService;
+    private SysUserMapper sysUserMapper;
+
+
+    @Value("${netty.idUrl}")
+    private String nettyIdUrl;
 
     @Autowired
     private ServerConfig serverConfig;
@@ -953,4 +962,68 @@ public class PartyMeetingInfoServiceImpl implements IPartyMeetingInfoService
     public List<PartyMeetingFollow> getFileImage(Long id) {
         return partyMeetingFollowMapper.selectPartyMeetingFollowByFId(id,2);
     }
+
+    @Override
+    public int meetingSign(PartyAppUser partyAppUser) {
+        Long meetingId = partyAppUser.getId();
+        // 获取会议详情
+        PartyMeetingInfo partyMeetingInfo = partyMeetingInfoMapper.selectPartyMeetingInfoById(meetingId);
+        // 会议开始时间
+        Date beginTime = partyMeetingInfo.getBeginTime();
+        // 会议开始时间-1小时
+        Calendar rightNow = Calendar.getInstance();
+        rightNow.setTime(beginTime);
+        rightNow.add(Calendar.HOUR,-1);
+        Date beginTimeNew = rightNow.getTime();
+        // 会议结束时间
+        Date endTime = partyMeetingInfo.getEndTime();
+        // 系统时间
+        Date nowTime = DateUtils.getNowDate();
+        if (beginTimeNew.compareTo(nowTime) > 0) {
+            // 未到签到时间
+            return -1;
+        } else if (nowTime.compareTo(endTime) > 0) {
+            // 签到已结束
+            return -2;
+        }
+        Long adminUserId = SecurityUtils.getLoginUser().getUserId();
+        // 获取党员ID
+        Long memberId = partyAppUser.getMemberId();
+        PartyAttendanceRecord partyAttendanceRecord = new PartyAttendanceRecord();
+        partyAttendanceRecord.setCreateTime(DateUtils.getNowDate());
+        partyAttendanceRecord.setMeetingId(meetingId);
+        partyAttendanceRecord.setAttendanceStatus(1);
+        partyAttendanceRecord.setMemberId(memberId);
+        partyAttendanceRecord.setSigntype(partyAppUser.getDataType());
+
+        // 判断是否有需要签到
+        PartyAttendanceRecord attendanceRecord = new PartyAttendanceRecord();
+        attendanceRecord.setMeetingId(meetingId);
+        attendanceRecord.setMemberId(memberId);
+        List<PartyAttendanceRecord> partyAttendanceRecords = partyAttendanceRecordMapper.selectPartyAttendanceRecordList(attendanceRecord);
+        if (CollectionUtils.isEmpty(partyAttendanceRecords)) {
+            return -3;
+        }
+        int result = partyAttendanceRecordMapper.updateAppAttendanceRecord(partyAttendanceRecord);
+        // 新启线程 发送长连接给大屏端
+        if (result > 0) {
+            Thread sendThread = new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    sendMessageToInspur(adminUserId,meetingId, PushMessageType.MEETING_SIGN.getValue());
+                }
+            });
+            sendThread.start();
+        }
+
+        return result;
+    }
+    private void sendMessageToInspur(Long adminUserId, Long meetingId,String messageType) {
+        SysUser sysUser = sysUserMapper.selectUserById(adminUserId);
+        if (null == sysUser) {
+            return;
+        }
+        String userName = sysUser.getUserName();
+        PushMessageUtil.pushMessageAndIdToRemote(userName,messageType,meetingId,nettyIdUrl);
+    }
 }

+ 60 - 0
inspur-ui/src/api/partywork/face.js

@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 查询人脸识别记录列表
+export function listRecognition(query) {
+  return request({
+    url: '/compreface/member/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function listFaceRecord(query) {
+  return request({
+    url: '/compreface/recognition/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function uploadFace2AI(data) {
+  return request({
+    url: '/compreface/recognition/faces2',
+    method: 'post',
+    data: data,
+  })
+}
+
+// 查询人脸识别记录详细
+export function getRecognition(id) {
+  return request({
+    url: '/system/recognition/' + id,
+    method: 'get'
+  })
+}
+
+// 新增人脸识别记录
+export function addRecognition(data) {
+  return request({
+    url: '/system/recognition',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改人脸识别记录
+export function updateRecognition(data) {
+  return request({
+    url: '/system/recognition',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除人脸识别记录
+export function delRecognition(id) {
+  return request({
+    url: '/system/recognition/' + id,
+    method: 'delete'
+  })
+}

+ 215 - 0
inspur-ui/src/views/party_work/face/record.vue

@@ -0,0 +1,215 @@
+<template>
+  <div class="appNew-container">
+    <el-card shadow="never" class="" style="">
+      <div style="margin-top: 5px;">
+        <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px" style="height: 38px">
+          <el-form-item label="请求参数" prop="reqParam">
+            <el-input v-model="queryParams.reqParam" placeholder="请输入请求参数" clearable @keyup.enter.native="handleQuery"
+            />
+          </el-form-item>
+          <el-form-item label="接口响应" prop="rspCode">
+            <el-input v-model="queryParams.rspCode" placeholder="请输入接口响应" clearable @keyup.enter.native="handleQuery"
+            />
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </el-card>
+    <el-card class="centerCard" shadow="never" style="margin-top: 0px;border-top:0px; height: calc(100vh - 170px)">
+      <el-table v-loading="loading" :data="recognitionList" @selection-change="handleSelectionChange" height="calc(100vh - 260px)">
+  <!--      <el-table-column type="selection" width="55" align="center" />-->
+        <el-table-column label="记录ID" align="center" prop="id" width="80"/>
+        <el-table-column label="识别状态" align="center" prop="opStatus" width="80"/>
+        <el-table-column label="算法响应" align="center" prop="rspCode" width="80"/>
+        <el-table-column label="识别图片" align="left" prop="picPath" width="100">
+          <template slot-scope="scope">
+            <image-preview :src="scope.row.picPath" :width="50" :height="28" style="display: flex;"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="识别参数" align="left" prop="reqParam" :show-overflow-tooltip="true"/>
+        <el-table-column label="识别结果" align="left" prop="rspMsg" :show-overflow-tooltip="true"/>
+        <el-table-column label="识别时间" align="left" prop="createTime" width="200"/>
+      </el-table>
+      <pagination style="margin-right: 5px;margin-bottom: 20px;" v-show="total>0" :total="total" :page.sync="queryParams.pageNum"
+                  :limit.sync="queryParams.pageSize" @pagination="getList"/>
+    </el-card>
+
+  </div>
+</template>
+
+<script>
+import { listFaceRecord } from "@/api/partywork/face";
+
+export default {
+  name: "Recognition",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 人脸识别记录表格数据
+      recognitionList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 12,
+        reqParam: null,
+        rspCode: null,
+        rspMsg: null,
+        opType: 3,
+        opStatus: null,
+        userTableId: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询人脸识别记录列表 */
+    getList() {
+      this.loading = true;
+      listFaceRecord(this.queryParams).then(response => {
+        this.recognitionList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+        this.recognitionList.forEach(item => {
+          item.opStatus = item.opStatus === 1 ? "成功" : "失败";
+          let reqParam = JSON.parse(item.reqParam);
+          item.picPath = reqParam.url;
+        });
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        reqParam: null,
+        rspCode: null,
+        rspMsg: null,
+        opType: null,
+        opStatus: 0,
+        createTime: null,
+        updateTime: null,
+        userTableId: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+  }
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .centerCard .el-card__body {
+  padding: 0;
+  padding-bottom: 20px;
+}
+
+::v-deep .centerCard .el-table::before,
+.el-table--group::after,
+.el-table--border::after {
+  background-color: white;
+}
+
+::v-deep .centerCard .el-table__fixed::before,
+.el-table__fixed-right::before {
+  background-color: white;
+}
+
+.btnCss {
+  float: right;
+  margin-top: 20px;
+  margin-bottom: 20px;
+  margin-right: 20px;
+}
+
+::v-deep .el-dialog {
+  display: flex;
+  flex-direction: column;
+  margin: 0 !important;
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  max-height: calc(100% - 30px);
+  max-width: calc(100% - 30px);
+}
+
+::v-deep .el-dialog__header {
+  border-bottom: 1px solid #F0F0F0;
+}
+
+::v-deep .el-dialog__footer {
+  // padding: 0px;
+  padding-left: 0px;
+  padding-right: 0px;
+  padding-bottom: 10px;
+  border-top: 1px solid #F0F0F0;
+  display: flex;
+  justify-content: end;
+
+  .dialog-footer {
+    display: flex !important;
+    justify-content: flex-end;
+    width: 100%;
+    margin-right: 20px;
+  }
+}
+
+::v-deep .el-dialog .el-dialog__body {
+  flex: 1;
+  overflow: auto;
+}
+.span-ellipsis {
+  width: 100%;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  font-size: 14px;
+}
+::v-deep .el-tree-node.is-current>.el-tree-node__content {
+  color: #CA0001 !important;
+}
+
+</style>

+ 289 - 0
inspur-ui/src/views/party_work/face/setting.vue

@@ -0,0 +1,289 @@
+<template>
+  <div class="appNew-container">
+    <el-card shadow="never" class="" style="">
+      <div style="margin-top: 5px;">
+        <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px" style="height: 38px">
+          <el-form-item label="党员姓名" prop="name">
+            <el-input v-model="queryParams.name" placeholder="请输入党员姓名" :clearable="false" @keyup.enter.native="handleQuery"/>
+          </el-form-item>
+          <el-form-item label="性别" prop="gender">
+            <el-select v-model="queryParams.gender" placeholder="请选择性别" style="width: 200px">
+              <el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label"
+                         :value="dict.value" />
+            </el-select>
+          </el-form-item>
+          <el-form-item style="display:inline-block;float:right;margin-right: 0px; margin-bottom: 10px;">
+            <el-button type="primary" size="mini" @click="handleQuery" icon="el-icon-search">查询</el-button>
+            <el-button type="primary" size="mini" @click="resetQuery" icon="el-icon-refresh">重置</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </el-card>
+    <el-card class="centerCard" shadow="never" style="margin-top: 0px;border-top:0px; height: calc(100vh - 170px)">
+      <el-table v-loading="loading" :data="manageList" @selection-change="handleSelectionChange" height="calc(100vh - 260px)" >
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="党员ID" align="center" prop="memberId" width="80"/>
+        <el-table-column label="党员姓名" align="left" prop="name" width="100"/>
+        <el-table-column label="性别" align="left" prop="gender" width="50">
+          <template slot-scope="scope">
+            <dict-tag :options="dict.type.sys_user_sex" :value="scope.row.gender"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="党支部" align="left" prop="orgName" width="250" :show-overflow-tooltip="true"/>
+        <el-table-column label="手机号" align="left" prop="mobile" width="110"/>
+        <el-table-column label="录入状态" align="center" prop="opStatusStr" width="80" />
+        <el-table-column label="党员人像" align="left" prop="picPath" width="100">
+          <template slot-scope="scope">
+            <image-preview :src="scope.row.picPath" :width="50" :height="28" style="display: flex;"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="算法响应" align="center" prop="rspCode" width="80" />
+        <el-table-column label="响应信息" align="left" prop="rspMsg" width="320" :show-overflow-tooltip="true"/>
+        <el-table-column label="录入时间" align="left" prop="createTime" width="150" />
+        <el-table-column label="更新时间" align="left" prop="updateTime" width="150" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template slot-scope="scope">
+            <el-button size="mini" type="text" icon="el-icon-upload" @click="handleUpdate(scope.row)" >人脸录入</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination style="margin-right: 5px;margin-bottom: 20px;" v-show="total>0" :total="total" :page.sync="queryParams.pageNum"
+                  :page-size.sync="queryParams.pageSize" @pagination="getList"/>
+    </el-card>
+
+    <el-dialog :title="settingTitle" :visible.sync="settingOpen" width="500px" append-to-body :close-on-click-modal="false"
+               :close-on-press-escape="false">
+      <el-form ref="form" :model="form" :rules="rules" label-width="150px">
+        <el-form-item label="" prop="picPath">
+          <image-upload style="height: 200px" v-model="form.picPath"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="cancel">取 消</el-button>
+        <el-button type="primary" @click="submitSettingForm">保 存</el-button>
+      </div>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import {listRecognition, uploadFace2AI} from "@/api/partywork/face";
+
+export default {
+  name: "Manage",
+  dicts: ['sys_user_sex','sys_nation_type','sys_education_type','sys_party_status','sys_party_type'],
+  data() {
+    return {
+      settingTitle: null,
+      settingOpen: false,
+      // 党组织树
+      orgOptions: [],
+      // 选中组织添加党员
+      addEnable: true,
+      handleAddOrgId: null,
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 党员基础信息表格数据
+      manageList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 12,
+        name: null,
+        gender: null,
+        opType: 2
+      },
+      // 表单参数
+      form: {},
+      settingForm:{},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询党员基础信息列表 */
+    getList() {
+      this.loading = true;
+      listRecognition(this.queryParams).then(response => {
+        this.manageList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+        this.manageList.forEach(item => {
+          if (item.opStatus === 1 ) {
+            item.opStatusStr = "已录入";
+          }else if (item.opStatus === 0) {
+            item.opStatusStr = "未录入";
+          }else {
+            item.opStatusStr = "录入失败";
+          }
+        });
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.settingOpen = false;
+      this.reset();
+      this.settingReset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        name: null,
+        gender: null,
+        nation: null,
+        birth: null,
+        idNumber: null,
+        education: null,
+        picPath: null,
+        nativePlace: null,
+        address: null,
+        partyType: "0",
+        joinTime: null,
+        isExcellent: "0",
+        isRetire: "0",
+        status: "0",
+        mobile: null,
+        email: null,
+        filePath: null,
+        sort: null,
+        orgId: null,
+        createTime: null,
+        createBy: null,
+        postIds: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      this.form = row;
+      this.settingOpen = true;
+      this.settingTitle = "设置人脸(" + row.name + ")";
+    },
+    submitSettingForm () {
+      if (this.form.picPath == null || this.form.picPath == '') {
+        this.$modal.msgError("请上传人脸照片");
+        return;
+      }
+      uploadFace2AI(this.form).then(response => {
+        this.$modal.msgSuccess("上传人脸成功!");
+        this.settingOpen = false;
+        this.getList();
+      });
+    },
+
+
+  }
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .centerCard .el-card__body {
+  padding: 0;
+  padding-bottom: 20px;
+}
+
+::v-deep .centerCard .el-table::before,
+.el-table--group::after,
+.el-table--border::after {
+  background-color: white;
+}
+
+::v-deep .centerCard .el-table__fixed::before,
+.el-table__fixed-right::before {
+  background-color: white;
+}
+
+.btnCss {
+  float: right;
+  margin-top: 20px;
+  margin-bottom: 20px;
+  margin-right: 20px;
+}
+
+::v-deep .el-dialog {
+  display: flex;
+  flex-direction: column;
+  margin: 0 !important;
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  max-height: calc(100% - 30px);
+  max-width: calc(100% - 30px);
+}
+
+::v-deep .el-dialog__header {
+  border-bottom: 1px solid #F0F0F0;
+}
+
+::v-deep .el-dialog__footer {
+  // padding: 0px;
+  padding-left: 0px;
+  padding-right: 0px;
+  padding-bottom: 10px;
+  border-top: 1px solid #F0F0F0;
+  display: flex;
+  justify-content: end;
+
+  .dialog-footer {
+    display: flex !important;
+    justify-content: flex-end;
+    width: 100%;
+    margin-right: 20px;
+  }
+}
+
+::v-deep .el-dialog .el-dialog__body {
+  flex: 1;
+  overflow: auto;
+}
+.span-ellipsis {
+  width: 100%;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  font-size: 14px;
+}
+::v-deep .el-tree-node.is-current>.el-tree-node__content {
+  color: #CA0001 !important;
+}
+
+</style>

+ 4 - 4
inspur-ui/src/views/party_work/meeting/info.vue

@@ -46,10 +46,10 @@
               <div v-for="(item,index) in materialOptions">
                 <div style="display: flex;flex-direction: column;justify-content: center;">
                   <span>
-                    <span style="font-weight: bolder;margin: 10px;">链接地址:</span>
-                    <span>{{ item }}</span>
+                    <span style="font-weight: bolder;">链接地址:</span>
+                    <span style="word-break: break-all;word-wrap: break-word">{{ item }}</span>
                   </span>
-                  <span style="margin: 10px;">
+                  <span style="margin-right: 10px;margin-top: 10px;margin-bottom: 10px">
                     <el-button type="primary" @click="showUrl(item)">开始播放</el-button>
                     <el-button type="warning" @click="endShowUrl(item)">结束播放</el-button>
                   </span>
@@ -569,7 +569,7 @@ export default {
       this.websocket.send(message);
     },
     socketConnect() {
-      let socketUrl = "ws://localhost:8080/ws/server/" + getToken();
+      let socketUrl = "ws://117.73.13.40:8080/party-admin/ws/server/" + getToken();
       this.websocket = new WebSocket(socketUrl);
       this.websocket.onopen = function (event) {
         console.log("连接成功");

+ 1 - 1
inspur-ui/vue.config.js

@@ -23,7 +23,7 @@ module.exports = {
   outputDir: 'party-web',
   // outputDir: 'inspur-web',
   // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
-  assetsDir: 'party-web/static',
+  assetsDir: 'static',
   // assetsDir: 'static',
   // 是否开启eslint保存检测,有效值:ture | false | 'error'
   lintOnSave: process.env.NODE_ENV === 'development',