فهرست منبع

Merge remote-tracking branch 'origin/master'

wujiefeng 1 سال پیش
والد
کامیت
cd16ea1919
28فایلهای تغییر یافته به همراه1002 افزوده شده و 137 حذف شده
  1. 29 0
      FullCardClient/src/main/java/com/zhongshu/card/client/model/devices/permiss/Device2UseUsableSearch.java
  2. 18 1
      FullCardClient/src/main/java/com/zhongshu/card/client/model/visitor/VisitorMainModel.java
  3. 14 4
      FullCardClient/src/main/java/com/zhongshu/card/client/model/visitor/VisitorMainParam.java
  4. 3 0
      FullCardClient/src/main/java/com/zhongshu/card/client/model/visitor/VisitorMainSearch.java
  5. 27 0
      FullCardClient/src/main/java/com/zhongshu/card/client/model/visitor/VisitorReViewParam.java
  6. 0 18
      FullCardClient/src/main/java/com/zhongshu/card/client/type/permiss/DevicePermissTempType.java
  7. 116 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/controller/visitor/VisitorMainController.java
  8. 17 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/devices/Device2UseUsableDao.java
  9. 17 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/devices/extend/Device2UseUsableDaoExtend.java
  10. 70 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/devices/impl/Device2UseUsableDaoImpl.java
  11. 3 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/visitor/VisitorMainDao.java
  12. 2 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/visitor/VisitorSettingDeviceDao.java
  13. 4 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/visitor/impl/VisitorMainDaoImpl.java
  14. 12 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/domain/devices/DeviceUseRecords.java
  15. 9 15
      FullCardServer/src/main/java/com/zhongshu/card/server/core/domain/devices/permiss/Device2UseUsable.java
  16. 44 1
      FullCardServer/src/main/java/com/zhongshu/card/server/core/domain/visitor/VisitorMain.java
  17. 1 1
      FullCardServer/src/main/java/com/zhongshu/card/server/core/domain/visitor/VisitorSetting.java
  18. 2 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/service/devices/DeviceUseRecordService.java
  19. 121 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/service/devices/permiss/Device2UseUsableService.java
  20. 88 69
      FullCardServer/src/main/java/com/zhongshu/card/server/core/service/devices/permiss/DevicePermissVerifyService.java
  21. 4 2
      FullCardServer/src/main/java/com/zhongshu/card/server/core/service/gateDoor/GateDoorService.java
  22. 14 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/service/org/OrganizationUserServiceImpl.java
  23. 270 6
      FullCardServer/src/main/java/com/zhongshu/card/server/core/service/visitor/VisitorMainService.java
  24. 3 20
      FullCardServer/src/main/java/com/zhongshu/card/server/core/service/visitor/VisitorSettingService.java
  25. 29 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/time/SchedulEarlyMorning.java
  26. 29 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/time/SchedulOneHour.java
  27. 51 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/util/TempUserUtil.java
  28. 5 0
      FullCardServer/src/main/resources/application-dev.yml

+ 29 - 0
FullCardClient/src/main/java/com/zhongshu/card/client/model/devices/permiss/Device2UseUsableSearch.java

@@ -0,0 +1,29 @@
+package com.zhongshu.card.client.model.devices.permiss;
+
+import com.zhongshu.card.client.model.base.SuperSearch;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author TRX
+ * @date 2025/2/11
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class Device2UseUsableSearch extends SuperSearch {
+
+    @Schema(description = "使用方(用户或者什么)的关联的数据id")
+    private List<String> useDataIds = new ArrayList<>();
+
+    @Schema(description = "设备id")
+    private List<String> deviceIds;
+
+    @Schema(description = "当前时间")
+    private Long currentTime;
+}

+ 18 - 1
FullCardClient/src/main/java/com/zhongshu/card/client/model/visitor/VisitorMainModel.java

@@ -1,7 +1,6 @@
 package com.zhongshu.card.client.model.visitor;
 
 import com.zhongshu.card.client.model.base.SuperModel;
-import com.zhongshu.card.client.model.devices.DeviceInfoModel;
 import com.zhongshu.card.client.model.devices.DeviceInfoSimpleModel;
 import com.zhongshu.card.client.model.org.OrganizationUserSimpleModel;
 import com.zhongshu.card.client.model.org.UserCountSimpleModel;
@@ -12,7 +11,9 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * @author TRX
@@ -103,4 +104,20 @@ public class VisitorMainModel extends SuperModel {
     @Schema(description = "设备列表")
     private List<DeviceInfoSimpleModel> deviceInfos = new ArrayList<>();
 
+    @Schema(description = "第一次访问时间")
+    private Long firstVisitTime;
+
+    @Schema(description = "到访部门")
+    private String departments = "";
+
+    @Schema(description = "到访单位")
+    private String unit;
+
+    @Schema(description = "说明")
+    private String visitorRemark;
+
+    @Schema(description = "到访地址")
+    private String visitAddress;
+
+    private Map<String, Object> meatInfo = new HashMap<>();
 }

+ 14 - 4
FullCardClient/src/main/java/com/zhongshu/card/client/model/visitor/VisitorMainParam.java

@@ -3,8 +3,8 @@ package com.zhongshu.card.client.model.visitor;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * @author TRX
@@ -48,7 +48,17 @@ public class VisitorMainParam {
     @Schema(description = "访问时间长")
     private Long minutes;
 
-    @Schema(description = "可使用的设备id集合")
-    private List<String> deviceIds = new ArrayList<>();
+    @Schema(description = "到访部门")
+    private String departments = "";
 
+    @Schema(description = "到访单位")
+    private String unit;
+
+    @Schema(description = "说明")
+    private String visitorRemark;
+
+    @Schema(description = "到访地址")
+    private String visitAddress;
+
+    private Map<String, Object> meatInfo = new HashMap<>();
 }

+ 3 - 0
FullCardClient/src/main/java/com/zhongshu/card/client/model/visitor/VisitorMainSearch.java

@@ -41,6 +41,9 @@ public class VisitorMainSearch extends SuperSearch {
     @Schema(description = "手机号码")
     private String phone;
 
+    @Schema(description = "审核是否成功")
+    private Boolean reViewSuccess;
+
     @Schema(description = "访客类型")
     private List<String> visitorTypes;
 

+ 27 - 0
FullCardClient/src/main/java/com/zhongshu/card/client/model/visitor/VisitorReViewParam.java

@@ -0,0 +1,27 @@
+package com.zhongshu.card.client.model.visitor;
+
+import com.zhongshu.card.client.model.base.IDParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author TRX
+ * @date 2025/2/11
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class VisitorReViewParam extends IDParam {
+
+    @Schema(description = "审核备注")
+    private String reviewRemark;
+
+    @Schema(description = "可使用的设备id集合")
+    private List<String> deviceIds = new ArrayList<>();
+
+}

+ 0 - 18
FullCardClient/src/main/java/com/zhongshu/card/client/type/permiss/DevicePermissTempType.java

@@ -1,18 +0,0 @@
-package com.zhongshu.card.client.type.permiss;
-
-import lombok.Getter;
-
-/**
- * 消息类型
- */
-public enum DevicePermissTempType {
-    Visitor("访客"),
-    ;
-
-    @Getter
-    private String remark;
-
-    DevicePermissTempType(String remark) {
-        this.remark = remark;
-    }
-}

+ 116 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/controller/visitor/VisitorMainController.java

@@ -0,0 +1,116 @@
+package com.zhongshu.card.server.core.controller.visitor;
+
+import com.github.microservice.auth.security.annotations.ResourceAuth;
+import com.github.microservice.auth.security.helper.AuthHelper;
+import com.github.microservice.auth.security.type.AuthType;
+import com.github.microservice.net.ResultContent;
+import com.zhongshu.card.client.model.base.IDParam;
+import com.zhongshu.card.client.model.visitor.VisitorMainModel;
+import com.zhongshu.card.client.model.visitor.VisitorMainParam;
+import com.zhongshu.card.client.model.visitor.VisitorMainSearch;
+import com.zhongshu.card.client.model.visitor.VisitorReViewParam;
+import com.zhongshu.card.server.core.service.visitor.VisitorMainService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.web.PageableDefault;
+import org.springframework.util.Assert;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 访客管理
+ *
+ * @author TRX
+ * @date 2024/6/5
+ */
+@RestController
+@RequestMapping("/visitorManager")
+@Tag(name = "访客管理-申请")
+public class VisitorMainController {
+
+    @Autowired
+    private VisitorMainService visitorMainService;
+
+    @Autowired
+    private AuthHelper authHelper;
+
+    @Operation(summary = "访客申请", description = "访客申请")
+    @RequestMapping(value = "saveInfo", method = {RequestMethod.POST})
+    public ResultContent saveInfo(@RequestBody VisitorMainParam param) {
+        return this.visitorMainService.saveInfo(param);
+    }
+
+    @ResourceAuth(value = "user", type = AuthType.User)
+    @Operation(summary = "删除数据", description = "删除数据")
+    @RequestMapping(value = "deleteInfo", method = {RequestMethod.POST})
+    public ResultContent deleteInfo(@RequestBody IDParam param) {
+        return this.visitorMainService.deleteInfo(param.getId());
+    }
+
+    @ResourceAuth(value = "user", type = AuthType.User)
+    @Operation(summary = "我的审核列表-分页查询", description = "数据列表-分页查询")
+    @RequestMapping(value = {"myReViewPage"}, method = {RequestMethod.POST})
+    public ResultContent<Page<VisitorMainModel>> myReViewPage(
+            @Parameter(hidden = true) @PageableDefault(page = 0, size = 10) Pageable pageable,
+            @Parameter(required = false) VisitorMainSearch param) {
+        Assert.hasText(param.getProjectOid(), "projectOid不能为空");
+        String visitorUserId = "";
+        if (authHelper.getCurrentUser() != null) {
+            visitorUserId = authHelper.getCurrentUser().getUserId();
+        }
+        param.setVisitorUserId(visitorUserId);
+        return visitorMainService.page(param, pageable);
+    }
+
+    @ResourceAuth(value = "user", type = AuthType.User)
+    @Operation(summary = "我的申请列表-分页查询(已登录的)", description = "数据列表-分页查询")
+    @RequestMapping(value = {"myApplyPage"}, method = {RequestMethod.POST})
+    public ResultContent<Page<VisitorMainModel>> myApplyPage(
+            @Parameter(hidden = true) @PageableDefault(page = 0, size = 10) Pageable pageable,
+            @Parameter(required = false) VisitorMainSearch param) {
+        Assert.hasText(param.getProjectOid(), "projectOid不能为空");
+        String applyUserId = "";
+        if (authHelper.getCurrentUser() != null) {
+            applyUserId = authHelper.getCurrentUser().getUserId();
+        }
+        param.setApplyUserId(applyUserId);
+        return visitorMainService.page(param, pageable);
+    }
+
+    @Operation(summary = "我的申请列表-分页查询(未登录的)", description = "数据列表-分页查询")
+    @RequestMapping(value = {"myApplyPageUnLogin"}, method = {RequestMethod.POST})
+    public ResultContent<Page<VisitorMainModel>> myApplyPageUnLogin(
+            @Parameter(hidden = true) @PageableDefault(page = 0, size = 10) Pageable pageable,
+            @Parameter(required = false) VisitorMainSearch param) {
+        Assert.hasText(param.getProjectOid(), "projectOid不能为空");
+        Assert.hasText(param.getOpenId(), "openId不能为空");
+        return visitorMainService.page(param, pageable);
+    }
+
+    @Operation(summary = "访客申请详情", description = "访客申请详情")
+    @RequestMapping(value = "getInfo", method = {RequestMethod.POST})
+    public ResultContent getInfo(@RequestBody IDParam param) {
+        return this.visitorMainService.getInfo(param.getId());
+    }
+
+    @ResourceAuth(value = "user", type = AuthType.User)
+    @Operation(summary = "审核--拒绝申请", description = "审核--拒绝申请")
+    @RequestMapping(value = "refuseVisitApply", method = {RequestMethod.POST})
+    public ResultContent refuseVisitApply(@RequestBody VisitorReViewParam param) {
+        return this.visitorMainService.refuseVisitApply(param);
+    }
+
+    @ResourceAuth(value = "user", type = AuthType.User)
+    @Operation(summary = "审核--通过申请", description = "审核--通过申请")
+    @RequestMapping(value = "passVisitApply", method = {RequestMethod.POST})
+    public ResultContent passVisitApply(@RequestBody VisitorReViewParam param) {
+        return this.visitorMainService.passVisitApply(param);
+    }
+
+}

+ 17 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/devices/Device2UseUsableDao.java

@@ -0,0 +1,17 @@
+package com.zhongshu.card.server.core.dao.devices;
+
+import com.github.microservice.components.data.mongo.mongo.dao.MongoDao;
+import com.zhongshu.card.server.core.dao.devices.extend.Device2UseUsableDaoExtend;
+import com.zhongshu.card.server.core.domain.devices.permiss.Device2UseUsable;
+
+/**
+ * 设备临时权限Dao
+ *
+ * @author TRX
+ * @date 2024/3/21
+ */
+public interface Device2UseUsableDao extends MongoDao<Device2UseUsable>, Device2UseUsableDaoExtend {
+
+    Device2UseUsable findTopById(String id);
+
+}

+ 17 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/devices/extend/Device2UseUsableDaoExtend.java

@@ -0,0 +1,17 @@
+package com.zhongshu.card.server.core.dao.devices.extend;
+
+import com.zhongshu.card.client.model.devices.permiss.Device2UseUsableSearch;
+import com.zhongshu.card.server.core.domain.devices.permiss.Device2UseUsable;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+/**
+ * @Author TRX
+ * @CreateDate: 2023/7/7
+ * @Version: 1.0
+ */
+public interface Device2UseUsableDaoExtend {
+
+    Page<Device2UseUsable> page(Pageable pageable, Device2UseUsableSearch param);
+
+}

+ 70 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/devices/impl/Device2UseUsableDaoImpl.java

@@ -0,0 +1,70 @@
+package com.zhongshu.card.server.core.dao.devices.impl;
+
+import com.github.microservice.components.data.mongo.mongo.helper.DBHelper;
+import com.zhongshu.card.client.model.devices.permiss.Device2UseUsableSearch;
+import com.zhongshu.card.server.core.dao.BaseImpl;
+import com.zhongshu.card.server.core.dao.devices.extend.Device2UseUsableDaoExtend;
+import com.zhongshu.card.server.core.domain.devices.permiss.Device2UseUsable;
+import com.zhongshu.card.server.core.util.CommonUtil;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @Author TRX
+ * @CreateDate: 2023/4/12
+ * @Version: 1.0
+ */
+public class Device2UseUsableDaoImpl extends BaseImpl implements Device2UseUsableDaoExtend {
+
+    @Autowired
+    private DBHelper dbHelper;
+
+    @Override
+    public Page<Device2UseUsable> page(Pageable pageable, Device2UseUsableSearch param) {
+        Criteria criteria = buildFilterCriteria(param);
+
+        Sort sort = buildSort(param);
+        Query query = Query.query(criteria);
+        query.with(sort);
+        return dbHelper.pages(query, pageable, Device2UseUsable.class);
+    }
+
+    private Criteria buildFilterCriteria(Device2UseUsableSearch param) {
+        Criteria criteria = buildCriteriaNotOid(param);
+
+        if (StringUtils.isNotEmpty(param.getProjectOid())) {
+            criteria.and("projectOid").is(param.getProjectOid());
+        }
+
+        if (ObjectUtils.isNotEmpty(param.getUseDataIds())) {
+            criteria.and("useDataIds").in(param.getUseDataIds());
+        }
+
+        if (ObjectUtils.isNotEmpty(param.getDeviceIds())) {
+            criteria.and("deviceIds").in(param.getDeviceIds());
+        }
+
+        if (!CommonUtil.longIsEmpty(param.getCurrentTime())) {
+            criteria.and("endTime").gte(param.getCurrentTime());
+            criteria.and("startTime").lte(param.getCurrentTime());
+        }
+
+        // 模糊搜索
+        List<Criteria> criterias = new ArrayList<>();
+        if (!CollectionUtils.isEmpty(criterias)) {
+            criteria.andOperator(criterias.toArray(new Criteria[]{}));
+        }
+        return criteria;
+    }
+
+}

+ 3 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/visitor/VisitorMainDao.java

@@ -1,6 +1,7 @@
 package com.zhongshu.card.server.core.dao.visitor;
 
 import com.github.microservice.components.data.mongo.mongo.dao.MongoDao;
+import com.zhongshu.card.client.type.visitor.VisitorState;
 import com.zhongshu.card.server.core.dao.visitor.extend.VisitorMainDaoExtend;
 import com.zhongshu.card.server.core.domain.visitor.VisitorMain;
 
@@ -16,4 +17,6 @@ public interface VisitorMainDao extends MongoDao<VisitorMain>, VisitorMainDaoExt
 
     List<VisitorMain> findByIdIn(List<String> ids);
 
+    List<VisitorMain> findByState(VisitorState state);
+
 }

+ 2 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/visitor/VisitorSettingDeviceDao.java

@@ -16,5 +16,7 @@ public interface VisitorSettingDeviceDao extends MongoDao<VisitorSettingDevice>,
 
     List<VisitorSettingDevice> findByIdIn(List<String> ids);
 
+    List<VisitorSettingDevice> findBySceneComponentId(String sceneComponentId);
+
     VisitorSettingDevice findTopBySceneComponentIdAndDeviceId(String sceneComponentId, String deviceId);
 }

+ 4 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/visitor/impl/VisitorMainDaoImpl.java

@@ -78,6 +78,10 @@ public class VisitorMainDaoImpl extends BaseImpl implements VisitorMainDaoExtend
             criteria.and("deviceIds").in(param.getDeviceIds());
         }
 
+        if (param.getReViewSuccess() != null) {
+            criteria.and("reViewSuccess").is(param.getReViewSuccess());
+        }
+
         // 模糊搜索
         List<Criteria> criterias = new ArrayList<>();
         if (StringUtils.isNotEmpty(param.getName())) {

+ 12 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/domain/devices/DeviceUseRecords.java

@@ -5,6 +5,8 @@ import com.github.microservice.models.type.DeviceType;
 import com.github.microservice.types.deviceUse.DeviceUseState;
 import com.github.microservice.types.deviceUse.OperateState;
 import com.github.microservice.types.deviceUse.OperateType;
+import com.github.microservice.types.user.DevicePermissFromType;
+import com.github.microservice.types.user.UserFromType;
 import com.zhongshu.card.client.model.devices.DeviceInfoStoreModel;
 import com.zhongshu.card.client.model.org.UserCountSimpleModel;
 import com.zhongshu.card.client.model.school.CardInfoStoreModel;
@@ -88,9 +90,19 @@ public class DeviceUseRecords extends SuperMain {
     private String pic = "";
 
     //------------------用户信息 start-------------------
+
+    @Schema(description = "权限来自哪里的配置")
+    private DevicePermissFromType permissFromType = DevicePermissFromType.SystemConfig;
+
+    @Schema(description = "用户类型")
+    private UserFromType userFromType = UserFromType.SystemUser;
+
     @Schema(description = "用户userId")
     private String userId;
 
+    @Schema(description = "用户名称")
+    private String userName;
+
     @Schema(description = "用户信息")
     public UserCountSimpleModel userAccount;
 

+ 9 - 15
FullCardServer/src/main/java/com/zhongshu/card/server/core/domain/devices/permiss/Device2UseUsable.java

@@ -1,18 +1,17 @@
 package com.zhongshu.card.server.core.domain.devices.permiss;
 
-import com.zhongshu.card.client.type.permiss.DevicePermissTempType;
+import com.github.microservice.types.user.DevicePermissFromType;
 import com.zhongshu.card.server.core.domain.base.SuperMain;
-import com.zhongshu.card.server.core.domain.org.OrganizationUser;
-import com.zhongshu.card.server.core.domain.org.UserAccount;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import org.springframework.data.mongodb.core.index.Indexed;
-import org.springframework.data.mongodb.core.mapping.DBRef;
 import org.springframework.data.mongodb.core.mapping.Document;
 
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
 
 /**
  * 用户可使用设备临时绑定
@@ -26,23 +25,18 @@ import java.util.Date;
 @AllArgsConstructor
 public class Device2UseUsable extends SuperMain {
 
-    @Schema(description = "可使用的用户信息")
-    @DBRef(lazy = true)
-    private UserAccount userAccount;
-
-    @Schema(description = "机构用户信息")
-    @DBRef(lazy = true)
-    private OrganizationUser organizationUser;
-
-    @Schema(description = "用户userId")
-    private String userId;
+    @Schema(description = "使用方(用户或者什么)的关联的数据id")
+    private List<String> useDataIds = new ArrayList<>();
 
     @Schema(description = "临时权限来自哪里")
-    private DevicePermissTempType tempType;
+    private DevicePermissFromType tempType;
 
     @Schema(description = "数据id")
     private String fromDataId;
 
+    @Schema(description = "设备id")
+    private List<String> deviceIds;
+
     @Schema(description = "开始时间")
     private Long startTime;
 

+ 44 - 1
FullCardServer/src/main/java/com/zhongshu/card/server/core/domain/visitor/VisitorMain.java

@@ -1,5 +1,6 @@
 package com.zhongshu.card.server.core.domain.visitor;
 
+import com.github.microservice.types.user.UserFromType;
 import com.zhongshu.card.client.type.visitor.VisitorState;
 import com.zhongshu.card.server.core.domain.base.SuperMain;
 import com.zhongshu.card.server.core.domain.devices.DeviceInfo;
@@ -14,7 +15,9 @@ import org.springframework.data.mongodb.core.mapping.DBRef;
 import org.springframework.data.mongodb.core.mapping.Document;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 访客主信息
@@ -50,10 +53,26 @@ public class VisitorMain extends SuperMain {
     @Schema(description = "审核时间")
     private Long reviewTime;
 
-    @Schema(description = "是否已失效")
+    @Schema(description = "审核备注")
+    private String reviewRemark;
+
+    @Schema(description = "是否已失效(审核通过,但使用时间已过)")
     private Boolean isCancel = Boolean.FALSE;
 
+    @Schema(description = "审核是否成功")
+    private Boolean reViewSuccess;
+
+    @Schema(description = "是否已清理人脸信息")
+    private Boolean isClearFace = Boolean.FALSE;
+
     //-------------------------------申请信息start--------------------
+
+    @Schema(description = "用户类型")
+    private UserFromType userFromType;
+
+    @Schema(description = "临时用户id")
+    private String tempUserId;
+
     @Schema(description = "申请人userId")
     private String applyUserId;
 
@@ -95,6 +114,12 @@ public class VisitorMain extends SuperMain {
     @Schema(description = "结束时间")
     private Long endTime;
 
+    @Schema(description = "权限开始时间")
+    private Long perStartTime;
+
+    @Schema(description = "权限结束时间")
+    private Long perEndTime;
+
     @Schema(description = "访问时间长")
     private Long minutes;
 
@@ -105,4 +130,22 @@ public class VisitorMain extends SuperMain {
     @DBRef(lazy = true)
     private List<DeviceInfo> deviceInfos = new ArrayList<>();
 
+    //----------------------访问信息 start----------------
+
+    @Schema(description = "第一次访问时间")
+    private Long firstVisitTime;
+
+    @Schema(description = "到访部门")
+    private String departments = "";
+
+    @Schema(description = "到访单位")
+    private String unit;
+
+    @Schema(description = "说明")
+    private String visitorRemark;
+
+    @Schema(description = "到访地址")
+    private String visitAddress;
+
+    private Map<String, Object> meatInfo = new HashMap<>();
 }

+ 1 - 1
FullCardServer/src/main/java/com/zhongshu/card/server/core/domain/visitor/VisitorSetting.java

@@ -39,7 +39,7 @@ public class VisitorSetting extends SuperMain {
     @Schema(description = "访客类型,值从字典来")
     private List<String> visitorTypes;
 
-    @Schema(description = "授权时间")
+    @Schema(description = "授权时间(小时)提前")
     private Long minutes;
 
     @Schema(description = "表单列表")

+ 2 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/service/devices/DeviceUseRecordService.java

@@ -103,11 +103,13 @@ public class DeviceUseRecordService extends SuperService {
         // 返回数据
         String mqttDataId = param.getMqttDataId();
         DeviceUseRecords deviceUseRecord = null;
+
         log.info("saveDeviceUseRecord mqttDataId: {}", mqttDataId);
         if (StringUtils.isNotEmpty(mqttDataId)) {
             deviceUseRecord = init(mqttDataId);
             if (ObjectUtils.isNotEmpty(deviceUseRecord)) {
                 BeanUtils.copyProperties(param, deviceUseRecord);
+
                 String deviceId = param.getDeviceId();
                 String cardNo = param.getCardNo();
                 String userId = param.getUserId();

+ 121 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/service/devices/permiss/Device2UseUsableService.java

@@ -0,0 +1,121 @@
+package com.zhongshu.card.server.core.service.devices.permiss;
+
+import com.github.microservice.models.gateDoor.use.GateDoorUseParam;
+import com.github.microservice.net.ResultContent;
+import com.github.microservice.types.user.DevicePermissFromType;
+import com.zhongshu.card.client.model.devices.permiss.Device2UseUsableSearch;
+import com.zhongshu.card.server.core.dao.devices.Device2UseUsableDao;
+import com.zhongshu.card.server.core.dao.visitor.VisitorSettingDeviceDao;
+import com.zhongshu.card.server.core.domain.devices.permiss.Device2UseUsable;
+import com.zhongshu.card.server.core.domain.visitor.VisitorMain;
+import com.zhongshu.card.server.core.domain.visitor.VisitorSettingDevice;
+import com.zhongshu.card.server.core.service.visitor.VisitorMainService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author TRX
+ * @date 2025/2/11
+ */
+@Slf4j
+@Service
+public class Device2UseUsableService {
+
+    @Autowired
+    private Device2UseUsableDao device2UseUsableDao;
+
+    @Autowired
+    private VisitorSettingDeviceDao visitorSettingDeviceDao;
+
+    @Autowired
+    private VisitorMainService visitorMainService;
+
+    /**
+     * 更加访客申请信息 写入对应的设备 临时权限
+     *
+     * @param visitorMain
+     * @return
+     */
+    public ResultContent addByVisitorData(VisitorMain visitorMain) {
+        if (ObjectUtils.isEmpty(visitorMain)) {
+            return ResultContent.buildFail("访客数据为空");
+        }
+        Device2UseUsable entity = new Device2UseUsable();
+        entity.setFromDataId(visitorMain.getId());
+        entity.setTempType(DevicePermissFromType.Visitor);
+
+        List<String> useDataIds = new ArrayList<>();
+        useDataIds.add(visitorMain.getTempUserId());
+        if (StringUtils.isNotEmpty(visitorMain.getApplyUserId())) {
+            useDataIds.add(visitorMain.getApplyUserId());
+        }
+
+        entity.setUseDataIds(useDataIds);
+        entity.setStartTime(visitorMain.getPerStartTime());
+        entity.setEndTime(visitorMain.getPerEndTime());
+        entity.setTtl(new Date(visitorMain.getPerEndTime()));
+        List<String> deviceIds = visitorMain.getDeviceIds();
+        if (ObjectUtils.isEmpty(deviceIds)) {
+            List<VisitorSettingDevice> list = visitorSettingDeviceDao.findBySceneComponentId(visitorMain.getSceneComponentId());
+            if (ObjectUtils.isNotEmpty(list)) {
+                deviceIds = list.stream().map(VisitorSettingDevice::getDeviceId).collect(Collectors.toList());
+            }
+        }
+        entity.setDeviceIds(deviceIds);
+        entity.setProjectOid(visitorMain.getProjectOid());
+        entity.setOid(visitorMain.getOid());
+
+        device2UseUsableDao.save(entity);
+        return ResultContent.buildSuccess();
+    }
+
+    /**
+     * 验证失败 临时权限
+     *
+     * @param userId
+     * @param deviceId
+     * @return
+     */
+    public ResultContent<String> verifyDevice(String userId, String deviceId,
+            String projectOid, GateDoorUseParam deviceUserParam) {
+        String msg = "失败";
+
+        Device2UseUsableSearch param = new Device2UseUsableSearch();
+        param.setUseDataIds(List.of(userId));
+        param.setProjectOid(projectOid);
+        param.setDeviceIds(List.of(deviceId));
+        param.setCurrentTime(System.currentTimeMillis());
+        Pageable pageable = PageRequest.of(0, 1);
+        Page<Device2UseUsable> page = device2UseUsableDao.page(pageable, param);
+        List<Device2UseUsable> list = page.getContent();
+        if (ObjectUtils.isNotEmpty(list)) {
+            msg = "成功";
+            for (Device2UseUsable device2UseUsable : list) {
+                if (device2UseUsable.getTempType() == DevicePermissFromType.Visitor) {
+                    deviceUserParam.setPermissFromType(DevicePermissFromType.Visitor);
+
+                    // 访客的数据
+                    VisitorMain entity = visitorMainService.markVisitor(device2UseUsable.getFromDataId());
+                    if (ObjectUtils.isNotEmpty(entity) && deviceUserParam != null) {
+                        deviceUserParam.setUserName(entity.getName());
+                        deviceUserParam.setUserFromType(entity.getUserFromType());
+                    }
+                }
+            }
+            return ResultContent.buildSuccess(msg);
+        }
+        return ResultContent.buildFail(msg);
+    }
+
+}

+ 88 - 69
FullCardServer/src/main/java/com/zhongshu/card/server/core/service/devices/permiss/DevicePermissVerifyService.java

@@ -21,6 +21,7 @@ import com.zhongshu.card.server.core.domain.devices.DeviceInfo;
 import com.zhongshu.card.server.core.domain.devices.permiss.DevicePermiss;
 import com.zhongshu.card.server.core.domain.devices.permiss.PermissTimeSlot;
 import com.zhongshu.card.server.core.domain.org.UserAccount;
+import com.zhongshu.card.server.core.util.TempUserUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -61,6 +62,9 @@ public class DevicePermissVerifyService {
     @Autowired
     private UserPermissDataCacheService userPermissDataCacheService;
 
+    @Autowired
+    private Device2UseUsableService device2UseUsableService;
+
     /**
      * 验证用户是否有设备的使用权限
      *
@@ -78,21 +82,24 @@ public class DevicePermissVerifyService {
         }
 
         StopWatch stopWatch = new StopWatch();
-        stopWatch.start("用户信息");
-        String msg = "";
-
-        // 验证用户基础信息
-        UserAccount userAccount = userCountDao.findTopByUserId(userId);
-        if (ObjectUtils.isEmpty(userAccount)) {
-            return ResultContent.buildFail("用户不存在");
-        }
-        msg = userAccount.getName();
-        if (userAccount.getState() != UserState.Normal) {
-            return ResultContent.buildFail("用户不可用");
+        String msg = "没有使用权限";
+
+        boolean isSystemUser = TempUserUtil.idIsUserId(userId);
+        if (isSystemUser) {
+            stopWatch.start("用户信息");
+            // 验证用户基础信息
+            UserAccount userAccount = userCountDao.findTopByUserId(userId);
+            if (ObjectUtils.isEmpty(userAccount)) {
+                return ResultContent.buildFail("用户不存在");
+            }
+            msg = userAccount.getName();
+            if (userAccount.getState() != UserState.Normal) {
+                return ResultContent.buildFail("用户不可用");
+            }
+            deviceUserParam.setUserName(userAccount.getName());
+            stopWatch.stop();
         }
 
-        stopWatch.stop();
-
         stopWatch.start("查询设备信息");
         // 验证设备
         DeviceInfo deviceInfo = deviceInfoDao.findTopByDeviceId(deviceId);
@@ -108,76 +115,88 @@ public class DevicePermissVerifyService {
 
         boolean hasPermission = false;
         String projectOid = deviceInfo.getProjectOid();
-        stopWatch.start("查询绑定的设备权限");
-        DevicePermiss devicePermiss = devicePermissDao.findTopByUserIdAndDeviceIdAndProjectOidAndDataState(userId, deviceId, projectOid, DataState.Enable);
-        if (ObjectUtils.isNotEmpty(devicePermiss)) {
-            hasPermission = true;
-        }
-        stopWatch.stop();
-
-        if (!hasPermission) {
-
-            stopWatch.start("查询用户项目权限数据");
-            Map<String, UserCacheModel> map = userPermissDataCacheService.getUserAndDeviceCacheData(userId, deviceId, projectOid);
-            stopWatch.stop();
-
-            UserCacheModel userCacheModel = map.get(userId);
-            stopWatch.start("查询当前时间段");
-            // 查找当前时间对应的时段信息
-            List<PermissTimeSlot> permissTimeSlots = getCurrentTimeSlot(projectOid);
+        deviceUserParam.setProjectOid(projectOid);
+
+        if (isSystemUser) {
+            // 系统用户类型
+            stopWatch.start("查询绑定的设备权限");
+            DevicePermiss devicePermiss = devicePermissDao.findTopByUserIdAndDeviceIdAndProjectOidAndDataState(userId, deviceId, projectOid, DataState.Enable);
+            if (ObjectUtils.isNotEmpty(devicePermiss)) {
+                hasPermission = true;
+            }
             stopWatch.stop();
+            if (!hasPermission) {
+                stopWatch.start("查询用户项目权限数据");
+                Map<String, UserCacheModel> map = userPermissDataCacheService.getUserAndDeviceCacheData(userId, deviceId, projectOid);
+                stopWatch.stop();
+
+                UserCacheModel userCacheModel = map.get(userId);
+                stopWatch.start("查询当前时间段");
+                // 查找当前时间对应的时段信息
+                List<PermissTimeSlot> permissTimeSlots = getCurrentTimeSlot(projectOid);
+                stopWatch.stop();
+
+                if (userCacheModel != null && userCacheModel.isSuccess() && ObjectUtils.isNotEmpty(permissTimeSlots)) {
+                    // 查看权限规则 是否包含该设备
+                    PermissSettingListSearch search = new PermissSettingListSearch();
+
+                    search.setProjectOid(projectOid);
+                    List<String> permissSettingIds = new ArrayList<>();
+                    permissTimeSlots.parallelStream().forEach(it -> {
+                        if (ObjectUtils.isNotEmpty(it.getPermissSettingIds())) {
+                            permissSettingIds.addAll(it.getPermissSettingIds());
+                        }
+                    });
+                    search.setPermissSettingIds(permissSettingIds);
 
-            if (userCacheModel != null && userCacheModel.isSuccess() && ObjectUtils.isNotEmpty(permissTimeSlots)) {
-                // 查看权限规则 是否包含该设备
-                PermissSettingListSearch search = new PermissSettingListSearch();
-
-                search.setProjectOid(projectOid);
-                List<String> permissSettingIds = new ArrayList<>();
-                permissTimeSlots.parallelStream().forEach(it -> {
-                    if (ObjectUtils.isNotEmpty(it.getPermissSettingIds())) {
-                        permissSettingIds.addAll(it.getPermissSettingIds());
-                    }
-                });
-                search.setPermissSettingIds(permissSettingIds);
-
-                // 用户关联的权限
-                search.setSex(userCacheModel.getSex());
-                search.setDataIds(userCacheModel.getDataIds());
+                    // 用户关联的权限
+                    search.setSex(userCacheModel.getSex());
+                    search.setDataIds(userCacheModel.getDataIds());
 
-                UserCacheModel deviceCacheModel = map.get(deviceId);
+                    UserCacheModel deviceCacheModel = map.get(deviceId);
 
-                if (deviceCacheModel != null && deviceCacheModel.isSuccess()) {
-                    search.setDeviceTypes(List.of(deviceCacheModel.getDeviceType()));
-                    // 设备所在的分组
-                    search.setDeviceIds(deviceCacheModel.getDataIds());
+                    if (deviceCacheModel != null && deviceCacheModel.isSuccess()) {
+                        search.setDeviceTypes(List.of(deviceCacheModel.getDeviceType()));
+                        // 设备所在的分组
+                        search.setDeviceIds(deviceCacheModel.getDataIds());
 
-                    stopWatch.start("规则数据查询");
-                    boolean b = permissSettingListDao.isExit(search);
-                    if (b) {
-                        hasPermission = true;
+                        stopWatch.start("规则数据查询");
+                        boolean b = permissSettingListDao.isExit(search);
+                        if (b) {
+                            hasPermission = true;
+                        } else {
+                            msg = "未查询到权限";
+                        }
+                        stopWatch.stop();
                     } else {
-                        msg = "未查询到权限";
+                        hasPermission = false;
+                        if (ObjectUtils.isEmpty(deviceCacheModel)) {
+                            msg = "设备权限为空";
+                        } else if (!deviceCacheModel.isSuccess()) {
+                            msg = deviceCacheModel.getMsg();
+                        }
                     }
-                    stopWatch.stop();
                 } else {
                     hasPermission = false;
-                    if (ObjectUtils.isEmpty(deviceCacheModel)) {
-                        msg = "设备权限为空";
-                    } else if (!deviceCacheModel.isSuccess()) {
-                        msg = deviceCacheModel.getMsg();
+                    if (ObjectUtils.isEmpty(permissTimeSlots)) {
+                        msg = "规则时间段为空";
+                    } else if (ObjectUtils.isEmpty(userCacheModel)) {
+                        msg = "用户权限数据为空";
+                    } else if (!userCacheModel.isSuccess()) {
+                        msg = userCacheModel.getMsg();
                     }
                 }
+            }
+        }
+
+        if (!hasPermission) {
+            ResultContent<String> resultContent = device2UseUsableService.verifyDevice(userId, deviceId, projectOid, deviceUserParam);
+            if (resultContent.isSuccess()) {
+                hasPermission = true;
             } else {
-                hasPermission = false;
-                if (ObjectUtils.isEmpty(permissTimeSlots)) {
-                    msg = "规则时间段为空";
-                } else if (ObjectUtils.isEmpty(userCacheModel)) {
-                    msg = "用户权限数据为空";
-                } else if (!userCacheModel.isSuccess()) {
-                    msg = userCacheModel.getMsg();
-                }
             }
         }
+
         if (ObjectUtils.isNotEmpty(deviceUserParam)) {
             deviceUserParam.setUseTime(stopWatch.getTotalTimeMillis());
         }

+ 4 - 2
FullCardServer/src/main/java/com/zhongshu/card/server/core/service/gateDoor/GateDoorService.java

@@ -179,6 +179,7 @@ public class GateDoorService extends SuperService {
             String userId = info.getCustomId();
 
             GateDoorUseParam deviceUserParam = new GateDoorUseParam();
+            // 验证权限
             ResultContent<String> resultContent = devicePermissVerifyService.verifyDevice(userId, deviceId, deviceUserParam);
             deviceUserParam.setMqttDataId(mqttDataId);
             deviceUserParam.setOperateType(OperateType.Face);
@@ -188,7 +189,7 @@ public class GateDoorService extends SuperService {
             deviceUserParam.setPic(info.getPic());
             if (resultContent.isSuccess()) {
                 result.setSuccess();
-                result.setMsg(resultContent.getContent());
+                result.setMsg(deviceUserParam.getUserName());
                 deviceUserParam.setOperateState(OperateState.Success);
                 deviceUserParam.setIsPassed(Boolean.TRUE);
                 deviceUserParam.setVerifyMsg(resultContent.getContent());
@@ -198,7 +199,8 @@ public class GateDoorService extends SuperService {
                 deviceUserParam.setIsPassed(Boolean.FALSE);
                 deviceUserParam.setVerifyMsg(resultContent.getMsg());
             }
-            // 添加设备使用记录
+
+            // 保存设备使用记录
             deviceUseRecordService.asyncSaveRecord(deviceUserParam);
         } else {
             result.setFailed("参数错误");

+ 14 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/service/org/OrganizationUserServiceImpl.java

@@ -875,6 +875,20 @@ public class OrganizationUserServiceImpl extends SuperService {
         }
     }
 
+    /**
+     * 查询用户在项目绑定的机构用户信息
+     *
+     * @param projectOid
+     * @param userAccount
+     * @return
+     */
+    public OrganizationUser getUserInProjectBindOrgUserInfo(String projectOid, UserAccount userAccount) {
+        if (StringUtils.isNotEmpty(projectOid) && ObjectUtils.isNotEmpty(userAccount)) {
+            return organizationUserDao.findTopByUserAndProjectOidAndIsOrg(userAccount, projectOid, Boolean.TRUE);
+        }
+        return null;
+    }
+
     /**
      * 转换机构用户信息(基本信息 角色  部门)
      *

+ 270 - 6
FullCardServer/src/main/java/com/zhongshu/card/server/core/service/visitor/VisitorMainService.java

@@ -1,26 +1,46 @@
 package com.zhongshu.card.server.core.service.visitor;
 
+import com.github.microservice.auth.client.model.UserFaceUploadModel;
+import com.github.microservice.auth.client.service.UserFaceService;
 import com.github.microservice.components.data.base.util.PageEntityUtil;
 import com.github.microservice.net.ResultContent;
 import com.github.microservice.net.ResultMessage;
+import com.github.microservice.types.user.UserFromType;
 import com.zhongshu.card.client.model.devices.DeviceInfoSimpleModel;
 import com.zhongshu.card.client.model.visitor.VisitorMainModel;
 import com.zhongshu.card.client.model.visitor.VisitorMainParam;
 import com.zhongshu.card.client.model.visitor.VisitorMainSearch;
+import com.zhongshu.card.client.model.visitor.VisitorReViewParam;
+import com.zhongshu.card.client.type.visitor.VisitorState;
+import com.zhongshu.card.client.utils.DateUtils;
 import com.zhongshu.card.server.core.dao.devices.DeviceInfoDao;
+import com.zhongshu.card.server.core.dao.org.OrganizationUserDao;
+import com.zhongshu.card.server.core.dao.org.UserCountDao;
 import com.zhongshu.card.server.core.dao.scene.SceneComponentDao;
 import com.zhongshu.card.server.core.dao.visitor.VisitorMainDao;
+import com.zhongshu.card.server.core.dao.visitor.VisitorSettingDao;
+import com.zhongshu.card.server.core.domain.devices.DeviceInfo;
+import com.zhongshu.card.server.core.domain.org.OrganizationUser;
+import com.zhongshu.card.server.core.domain.org.UserAccount;
 import com.zhongshu.card.server.core.domain.scene.SceneComponent;
 import com.zhongshu.card.server.core.domain.visitor.VisitorMain;
+import com.zhongshu.card.server.core.domain.visitor.VisitorSetting;
+import com.zhongshu.card.server.core.service.base.CommonService;
 import com.zhongshu.card.server.core.service.base.SuperService;
 import com.zhongshu.card.server.core.service.devices.DeviceInfoServiceImpl;
+import com.zhongshu.card.server.core.service.devices.permiss.Device2UseUsableService;
+import com.zhongshu.card.server.core.service.org.OrganizationUserServiceImpl;
+import com.zhongshu.card.server.core.service.orgManager.OrganizationManagerServiceImpl;
 import com.zhongshu.card.server.core.service.user.UserAccountServiceImpl;
+import com.zhongshu.card.server.core.util.CommonUtil;
+import com.zhongshu.card.server.core.util.TempUserUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
 import org.springframework.stereotype.Service;
 
@@ -39,9 +59,6 @@ public class VisitorMainService extends SuperService {
     @Autowired
     private VisitorMainDao visitorMainDao;
 
-    @Autowired
-    private DeviceInfoDao deviceInfoDao;
-
     @Autowired
     private DeviceInfoServiceImpl deviceInfoService;
 
@@ -51,20 +68,63 @@ public class VisitorMainService extends SuperService {
     @Autowired
     private SceneComponentDao sceneComponentDao;
 
+    @Autowired
+    private UserCountDao userCountDao;
+
+    @Autowired
+    private OrganizationUserServiceImpl organizationUserService;
+
+    @Autowired
+    private UserFaceService userFaceService;
+
+    @Autowired
+    private CommonService commonService;
+
+    @Autowired
+    private Device2UseUsableService device2UseUsableService;
+
+    @Autowired
+    private VisitorSettingDao visitorSettingDao;
+
     public ResultContent saveInfo(VisitorMainParam param) {
         if (StringUtils.isEmpty(param.getSceneComponentId())) {
             return ResultContent.buildFail("sceneComponentId 不能为空");
         }
-        if (StringUtils.isEmpty(param.getSceneComponentId())) {
-            return ResultContent.buildFail("sceneComponentId 不能为空");
+        if (StringUtils.isEmpty(param.getVisitorUserId())) {
+            return ResultContent.buildFail("visitorUserId 不能为空");
+        }
+        if (StringUtils.isEmpty(param.getFaceUrl())) {
+            return ResultContent.buildFail("faceUrl 不能为空");
+        }
+        Long startTime = param.getStartTime();
+        if (CommonUtil.longIsEmpty(startTime)) {
+            return ResultContent.buildFail("到访时间不能为空");
         }
+        Long minutes = param.getMinutes();
+        if (CommonUtil.longIsEmpty(minutes)) {
+            return ResultContent.buildFail("访问时长不能为空");
+        }
+        Long endTime = startTime + minutes * 60 * 1000l;
 
+        // 所属组件信息
         String sceneComponentId = param.getSceneComponentId();
         SceneComponent sceneComponent = sceneComponentDao.findTopById(sceneComponentId);
         if (ObjectUtils.isEmpty(sceneComponent)) {
             return ResultContent.buildFail("组件不存在");
         }
 
+        VisitorSetting visitorSetting = visitorSettingDao.findTopBySceneComponentId(sceneComponentId);
+        if (ObjectUtils.isEmpty(visitorSetting)) {
+            return ResultContent.buildFail("访客组件参数未配置");
+        }
+
+        String projectOid = sceneComponent.getProjectOid();
+        UserAccount visitorUserAccount = userCountDao.findTopByUserId(param.getVisitorUserId());
+        if (ObjectUtils.isEmpty(visitorUserAccount)) {
+            return ResultContent.buildFail("被访人不存在");
+        }
+        OrganizationUser organizationUser = organizationUserService.getUserInProjectBindOrgUserInfo(projectOid, visitorUserAccount);
+
         VisitorMain entity = null;
         if (StringUtils.isNotEmpty(param.getId())) {
             entity = visitorMainDao.findTopById(param.getId());
@@ -73,12 +133,45 @@ public class VisitorMainService extends SuperService {
             }
             initUpdateEntity(entity);
         } else {
+            entity = new VisitorMain();
             initEntityNoCheckOid(entity);
+            entity.setState(VisitorState.WaitReView);
         }
+        BeanUtils.copyProperties(param, entity);
 
+        entity.setVisitorUserAccount(visitorUserAccount);
+        entity.setOrganizationUser(organizationUser);
 
-        BeanUtils.copyProperties(param, param);
+        // 申请用户
+        String applyUserId = getCurrentUserId();
+        UserAccount applyUserAccount = null;
+        if (StringUtils.isNotEmpty(applyUserId)) {
+            applyUserAccount = userCountDao.findTopByUserId(applyUserId);
+            OrganizationUser organizationUser1 = organizationUserService.getUserInProjectBindOrgUserInfo(projectOid, applyUserAccount);
+            entity.setApplyOrganizationUser(organizationUser1);
+        }
+        entity.setApplyUserId(applyUserId);
+        entity.setApplyUserAccount(applyUserAccount);
+        entity.setEndTime(endTime);
+        entity.setProjectOid(projectOid);
+
+        Long preMinutes = visitorSetting.getMinutes();
+        if (preMinutes == null) {
+            preMinutes = 0L;
+        }
+        Long perStartTime = startTime - preMinutes * 60 * 60 * 1000l;
+        Long perEndTime = DateUtils.getDayEndTime(endTime);
+        entity.setPerStartTime(perStartTime);
+        entity.setPerEndTime(perEndTime);
 
+        String tempUserId = applyUserId;
+        UserFromType userFromType = UserFromType.SystemUser;
+        if (StringUtils.isEmpty(tempUserId)) {
+            tempUserId = TempUserUtil.getVisitorTempUserId();
+            userFromType = UserFromType.VisitorUser;
+        }
+        entity.setUserFromType(userFromType);
+        entity.setTempUserId(tempUserId);
         visitorMainDao.save(entity);
         return ResultContent.buildSuccess();
     }
@@ -88,6 +181,7 @@ public class VisitorMainService extends SuperService {
         if (entity == null) {
             return ResultContent.buildFail(String.format(ResultMessage.DATA_NOT_EXIST, id));
         }
+        checkReViewInfo(entity);
         return ResultContent.buildSuccess(toModel(entity));
     }
 
@@ -111,6 +205,176 @@ public class VisitorMainService extends SuperService {
         return ResultContent.buildSuccess(PageEntityUtil.concurrent2PageModel(page, this::toModel));
     }
 
+    /**
+     * 拒绝
+     *
+     * @param param
+     * @return
+     */
+    public ResultContent refuseVisitApply(VisitorReViewParam param) {
+        VisitorMain visitorMain = visitorMainDao.findTopById(param.getId());
+        if (visitorMain == null) {
+            return ResultContent.buildFail(String.format(ResultMessage.DATA_NOT_EXIST, param.getId()));
+        }
+        ResultContent resultContent = checkReViewInfo(visitorMain);
+        if (resultContent.isFailed()) {
+            return resultContent;
+        }
+        // 已拒绝状态
+        visitorMain.setState(VisitorState.Refuse);
+        visitorMain.setReviewRemark(param.getReviewRemark());
+        visitorMain.setReViewSuccess(Boolean.FALSE);
+        visitorMainDao.save(visitorMain);
+        return ResultContent.buildSuccess();
+    }
+
+    /**
+     * 审核通过
+     *
+     * @param param
+     * @return
+     */
+    public ResultContent passVisitApply(VisitorReViewParam param) {
+        VisitorMain visitorMain = visitorMainDao.findTopById(param.getId());
+        if (visitorMain == null) {
+            return ResultContent.buildFail(String.format(ResultMessage.DATA_NOT_EXIST, param.getId()));
+        }
+        ResultContent resultContent = checkReViewInfo(visitorMain);
+        if (resultContent.isFailed()) {
+            return resultContent;
+        }
+        // 通过状态
+        visitorMain.setState(VisitorState.WaitVisit);
+        visitorMain.setReviewRemark(param.getReviewRemark());
+        visitorMain.setReViewSuccess(Boolean.TRUE);
+        if (ObjectUtils.isNotEmpty(param.getDeviceIds())) {
+            List<DeviceInfo> deviceInfos = deviceInfoService.getDevicesByDeviceIds(param.getDeviceIds());
+            visitorMain.setDeviceInfos(deviceInfos);
+        }
+        visitorMain.setDeviceIds(param.getDeviceIds());
+
+        String faceBase64 = commonService.getUrlFileBase64(visitorMain.getFaceUrl());
+        String updateFaceFileId = "";
+        // 维护管理权限中心用户的头像信息
+        UserFaceUploadModel userFaceUploadModel = new UserFaceUploadModel();
+        userFaceUploadModel.setUserId(visitorMain.getTempUserId());
+        userFaceUploadModel.setFile(faceBase64);
+        userFaceUploadModel.setUpdateFaceFileId(updateFaceFileId);
+        com.github.microservice.auth.client.content.ResultContent<String> content = userFaceService.upload(userFaceUploadModel);
+        if (content.isFailed()) {
+            return ResultContent.buildFail(content.getMsg());
+        }
+        updateFaceFileId = content.getContent();
+        visitorMain.setFaceFileId(updateFaceFileId);
+
+        // 把用户头像对应的设备权限写入 临时权限表
+        device2UseUsableService.addByVisitorData(visitorMain);
+
+        visitorMainDao.save(visitorMain);
+        return ResultContent.buildSuccess();
+    }
+
+    /**
+     * 标记访客权限使用
+     *
+     * @param fromDataId
+     */
+    public VisitorMain markVisitor(String fromDataId) {
+        if (StringUtils.isNotEmpty(fromDataId)) {
+            VisitorMain visitorMain = visitorMainDao.findTopById(fromDataId);
+            if (ObjectUtils.isEmpty(visitorMain)) {
+                return null;
+            }
+            if (visitorMain.getState() == VisitorState.WaitVisit) {
+                visitorMain.setState(VisitorState.Visit);
+                visitorMain.setFirstVisitTime(System.currentTimeMillis());
+                visitorMainDao.save(visitorMain);
+                return visitorMain;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 检查数据 审核是否是否已过期
+     *
+     * @param visitorMain
+     * @return
+     */
+    public ResultContent checkReViewInfo(VisitorMain visitorMain) {
+        if (ObjectUtils.isNotEmpty(visitorMain)) {
+            if (visitorMain.getState() == VisitorState.WaitReView && visitorMain.getEndTime() <= System.currentTimeMillis()) {
+                // 待审核 结束时间已过期
+                visitorMain.setState(VisitorState.Cancel);
+                visitorMain.setReviewRemark("申请数据已失效");
+                visitorMainDao.save(visitorMain);
+                return ResultContent.buildFail("数据已失效");
+            }
+        }
+        return ResultContent.buildSuccess();
+    }
+
+    /**
+     * 检查数据是否过期
+     *
+     * @param visitorMain
+     * @return
+     */
+    public ResultContent checkExpireInfo(VisitorMain visitorMain) {
+        if (ObjectUtils.isNotEmpty(visitorMain)) {
+            if (visitorMain.getReViewSuccess() != null && visitorMain.getReViewSuccess() && visitorMain.getEndTime() <= System.currentTimeMillis()) {
+                com.github.microservice.auth.client.content.ResultContent resultContent = userFaceService.delete(visitorMain.getTempUserId(), visitorMain.getFaceFileId());
+                if (resultContent.isSuccess()) {
+                    visitorMain.setIsCancel(Boolean.TRUE);
+                    visitorMain.setIsClearFace(Boolean.TRUE);
+                    visitorMainDao.save(visitorMain);
+                    return ResultContent.buildSuccess();
+                } else {
+                    return ResultContent.buildFail(resultContent.getMsg());
+                }
+            }
+        }
+        return ResultContent.buildFail("数据为空");
+    }
+
+    /**
+     * 每天检查数据,,如果访问时间已过期,则清除人脸数据
+     */
+    public void loopCheckVisitorData() {
+        this.checkAllWaitReView();
+        this.checkAllOverTimeData();
+    }
+
+    /**
+     * 检查所有的 审核通过的是否过期(好清理人脸信息)
+     */
+    private void checkAllOverTimeData() {
+        VisitorMainSearch param = new VisitorMainSearch();
+        param.setReViewSuccess(Boolean.TRUE);
+        param.setIsCancel(Boolean.FALSE);
+
+        Pageable pageable = PageRequest.of(0, 100);
+        Page<VisitorMain> page = visitorMainDao.page(pageable, param);
+        List<VisitorMain> list = page.getContent();
+        if (ObjectUtils.isNotEmpty(list)) {
+            list.forEach(visitorMain -> {
+                checkExpireInfo(visitorMain);
+            });
+        }
+    }
+
+    /**
+     * 检查所有的待审核得数据是否过期
+     */
+    private void checkAllWaitReView() {
+        List<VisitorMain> list = visitorMainDao.findByState(VisitorState.WaitReView);
+        if (ObjectUtils.isNotEmpty(list)) {
+            list.stream().forEach(visitorMain -> {
+                checkReViewInfo(visitorMain);
+            });
+        }
+    }
+
     public VisitorMainModel toModel(VisitorMain entity) {
         VisitorMainModel model = null;
         if (ObjectUtils.isNotEmpty(entity)) {

+ 3 - 20
FullCardServer/src/main/java/com/zhongshu/card/server/core/service/visitor/VisitorSettingService.java

@@ -3,10 +3,6 @@ package com.zhongshu.card.server.core.service.visitor;
 import com.github.microservice.net.ResultContent;
 import com.zhongshu.card.client.model.visitor.setting.VisitorSettingModel;
 import com.zhongshu.card.client.model.visitor.setting.VisitorSettingParam;
-import com.zhongshu.card.server.core.dao.devices.DeviceProductBindDeviceDao;
-import com.zhongshu.card.server.core.dao.devices.DeviceProductDao;
-import com.zhongshu.card.server.core.dao.devices.DeviceProductProvideServeDao;
-import com.zhongshu.card.server.core.dao.org.OrganizationDao;
 import com.zhongshu.card.server.core.dao.org.RoleDao;
 import com.zhongshu.card.server.core.dao.scene.SceneComponentDao;
 import com.zhongshu.card.server.core.dao.visitor.VisitorSettingDao;
@@ -14,7 +10,6 @@ import com.zhongshu.card.server.core.domain.org.Role;
 import com.zhongshu.card.server.core.domain.scene.SceneComponent;
 import com.zhongshu.card.server.core.domain.visitor.VisitorSetting;
 import com.zhongshu.card.server.core.service.base.SuperService;
-import com.zhongshu.card.server.core.service.org.OrganizationServiceImpl;
 import com.zhongshu.card.server.core.service.user.RoleServiceImpl;
 import com.zhongshu.card.server.core.util.BeanUtils;
 import lombok.extern.slf4j.Slf4j;
@@ -33,21 +28,6 @@ import java.util.List;
 @Service
 public class VisitorSettingService extends SuperService {
 
-    @Autowired
-    private DeviceProductDao deviceProductDao;
-
-    @Autowired
-    private DeviceProductBindDeviceDao deviceProductBindDeviceDao;
-
-    @Autowired
-    private DeviceProductProvideServeDao deviceProductProvideServeDao;
-
-    @Autowired
-    private OrganizationDao organizationDao;
-
-    @Autowired
-    private OrganizationServiceImpl organizationService;
-
     @Autowired
     private VisitorSettingDao visitorSettingDao;
 
@@ -71,6 +51,9 @@ public class VisitorSettingService extends SuperService {
         if (ObjectUtils.isEmpty(sceneComponent)) {
             return ResultContent.buildFail("组件不存在");
         }
+        if (param.getMinutes() == null || param.getMinutes() < 0) {
+            return ResultContent.buildFail("授权时间不能为空或小于0");
+        }
 
         VisitorSetting visitorSetting = visitorSettingDao.findTopBySceneComponentId(sceneComponent.getId());
         if (ObjectUtils.isEmpty(visitorSetting)) {

+ 29 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/time/SchedulEarlyMorning.java

@@ -0,0 +1,29 @@
+package com.zhongshu.card.server.core.time;
+
+import com.zhongshu.card.server.core.service.visitor.VisitorMainService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author TRX
+ * @date 2025/2/11
+ */
+@Slf4j
+@EnableScheduling
+@Component
+public class SchedulEarlyMorning {
+
+    @Autowired
+    private VisitorMainService visitorMainService;
+
+    // 每天凌晨1点执行
+    @Scheduled(cron = "0 0 1 * * ?")
+    public void executeMorning() {
+        log.info("Early Morning");
+        visitorMainService.loopCheckVisitorData();
+    }
+
+}

+ 29 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/time/SchedulOneHour.java

@@ -0,0 +1,29 @@
+package com.zhongshu.card.server.core.time;
+
+import com.zhongshu.card.server.core.service.visitor.VisitorMainService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author TRX
+ * @date 2025/2/11
+ */
+@Slf4j
+@EnableScheduling
+@Component
+public class SchedulOneHour {
+
+    @Autowired
+    private VisitorMainService visitorMainService;
+
+    // 每小时
+    @Scheduled(cron = "0 0 */1 * * ?")
+    public void execute() {
+        log.info("every hour");
+        visitorMainService.loopCheckVisitorData();
+    }
+
+}

+ 51 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/util/TempUserUtil.java

@@ -0,0 +1,51 @@
+package com.zhongshu.card.server.core.util;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * @author TRX
+ * @date 2025/2/12
+ */
+public class TempUserUtil {
+
+    /**
+     * 生成一个 访客的临时用户userId
+     *
+     * @return
+     */
+    public static String getVisitorTempUserId() {
+        return "tempUser_visitor_" + CommonUtil.UUID();
+    }
+
+    /**
+     * 判断id是否是系统用户id 格式
+     *
+     * @param id
+     * @return
+     */
+    public static boolean idIsUserId(String id) {
+        if (StringUtils.isEmpty(id)) {
+            return false;
+        }
+        if (idIsVisitorId(id)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 判断id是否是访客临时用户id
+     *
+     * @param id
+     * @return
+     */
+    public static boolean idIsVisitorId(String id) {
+        if (StringUtils.isEmpty(id)) {
+            return false;
+        }
+        if (id.indexOf("visitor") > 0) {
+            return true;
+        }
+        return false;
+    }
+}

+ 5 - 0
FullCardServer/src/main/resources/application-dev.yml

@@ -159,3 +159,8 @@ dictionary:
                                                                                  {key: wait, name: 待审核, description: 待审核, sort: 1},
                                                                                  {key: pass, name: 已通过, description: 已通过, sort: 1},
                                                                                  {key: refuse, name: 已拒绝, description: 已拒绝, sort: 1}]}
+    - { key: visitorType, name: 访客类型, description: 访客类型, sort: 19,
+        item: [
+          { key: conventional, name: 会议洽谈, description: 会议洽谈, sort: 1 },
+          { key: visiting, name: 探亲访友, description: 探亲访友, sort: 2 },
+          { key: business, name: 业务沟通, description: 业务沟通, sort: 3 } ] }