TRX 1 ano atrás
pai
commit
db7556e4a2
16 arquivos alterados com 755 adições e 87 exclusões
  1. 29 0
      FullCardClient/src/main/java/com/zhongshu/card/client/model/devices/permiss/Device2UseUsableSearch.java
  2. 0 3
      FullCardClient/src/main/java/com/zhongshu/card/client/model/visitor/VisitorMainParam.java
  3. 27 0
      FullCardClient/src/main/java/com/zhongshu/card/client/model/visitor/VisitorReViewParam.java
  4. 99 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/controller/visitor/VisitorMainController.java
  5. 17 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/devices/Device2UseUsableDao.java
  6. 17 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/devices/extend/Device2UseUsableDaoExtend.java
  7. 70 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/devices/impl/Device2UseUsableDaoImpl.java
  8. 2 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/dao/visitor/VisitorSettingDeviceDao.java
  9. 7 13
      FullCardServer/src/main/java/com/zhongshu/card/server/core/domain/devices/permiss/Device2UseUsable.java
  10. 14 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/domain/visitor/VisitorMain.java
  11. 112 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/service/devices/permiss/Device2UseUsableService.java
  12. 87 68
      FullCardServer/src/main/java/com/zhongshu/card/server/core/service/devices/permiss/DevicePermissVerifyService.java
  13. 14 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/service/org/OrganizationUserServiceImpl.java
  14. 186 3
      FullCardServer/src/main/java/com/zhongshu/card/server/core/service/visitor/VisitorMainService.java
  15. 23 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/timer/SchedulEarlyMorning.java
  16. 51 0
      FullCardServer/src/main/java/com/zhongshu/card/server/core/util/TempUserUtil.java

+ 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;
+}

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

@@ -48,7 +48,4 @@ public class VisitorMainParam {
     @Schema(description = "访问时间长")
     private Long minutes;
 
-    @Schema(description = "可使用的设备id集合")
-    private List<String> deviceIds = new ArrayList<>();
-
 }

+ 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<>();
+
+}

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

@@ -0,0 +1,99 @@
+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.server.core.service.visitor.VisitorMainService;
+import com.zhongshu.card.server.core.service.visitor.VisitorSettingDeviceService;
+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 VisitorSettingDeviceService visitorSettingDeviceService;
+
+    @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);
+    }
+
+}

+ 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;
+    }
+
+}

+ 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);
 }

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

@@ -2,17 +2,16 @@ package com.zhongshu.card.server.core.domain.devices.permiss;
 
 import com.zhongshu.card.client.type.permiss.DevicePermissTempType;
 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,16 +25,8 @@ 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;
@@ -43,6 +34,9 @@ public class Device2UseUsable extends SuperMain {
     @Schema(description = "数据id")
     private String fromDataId;
 
+    @Schema(description = "设备id")
+    private List<String> deviceIds;
+
     @Schema(description = "开始时间")
     private Long startTime;
 

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

@@ -50,10 +50,19 @@ public class VisitorMain extends SuperMain {
     @Schema(description = "审核时间")
     private Long reviewTime;
 
+    @Schema(description = "审核备注")
+    private String reviewRemark;
+
     @Schema(description = "是否已失效")
     private Boolean isCancel = Boolean.FALSE;
 
+    @Schema(description = "审核是否成功")
+    private Boolean reViewSuccess;
+
     //-------------------------------申请信息start--------------------
+    @Schema(description = "临时用户id")
+    private String tempUserId;
+
     @Schema(description = "申请人userId")
     private String applyUserId;
 
@@ -105,4 +114,9 @@ public class VisitorMain extends SuperMain {
     @DBRef(lazy = true)
     private List<DeviceInfo> deviceInfos = new ArrayList<>();
 
+    //----------------------访问信息 start----------------
+
+    @Schema(description = "第一次访问时间")
+    private Long firstVisitTime;
+
 }

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

@@ -0,0 +1,112 @@
+package com.zhongshu.card.server.core.service.devices.permiss;
+
+import com.github.microservice.net.ResultContent;
+import com.zhongshu.card.client.model.devices.permiss.Device2UseUsableSearch;
+import com.zhongshu.card.client.type.permiss.DevicePermissTempType;
+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(DevicePermissTempType.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.getStartTime());
+        entity.setEndTime(visitorMain.getEndTime());
+        entity.setTtl(new Date(visitorMain.getEndTime()));
+        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) {
+        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() == DevicePermissTempType.Visitor) {
+                    // 访客的数据
+                    msg = visitorMainService.markVisitor(device2UseUsable.getFromDataId());
+                }
+            }
+            return ResultContent.buildSuccess(msg);
+        }
+        return ResultContent.buildFail(msg);
+    }
+
+}

+ 87 - 68
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);
+        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);
+            if (resultContent.isSuccess()) {
+                hasPermission = true;
+                deviceUserParam.setUserName(resultContent.getMsg());
             } 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());
         }

+ 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;
+    }
+
     /**
      * 转换机构用户信息(基本信息 角色  部门)
      *

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

@@ -1,5 +1,7 @@
 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;
@@ -7,14 +9,27 @@ 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.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.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.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;
@@ -51,20 +66,64 @@ public class VisitorMainService extends SuperService {
     @Autowired
     private SceneComponentDao sceneComponentDao;
 
+    @Autowired
+    private UserCountDao userCountDao;
+
+    @Autowired
+    private OrganizationUserDao organizationUserDao;
+
+    @Autowired
+    private OrganizationManagerServiceImpl organizationManagerService;
+
+    @Autowired
+    private OrganizationUserServiceImpl organizationUserService;
+
+    @Autowired
+    private UserFaceService userFaceService;
+
+    @Autowired
+    private CommonService commonService;
+
+    @Autowired
+    private Device2UseUsableService device2UseUsableService;
+
     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("到访时间不能为空");
+        }
+        if (startTime <= System.currentTimeMillis()) {
+            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("组件不存在");
         }
 
+        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 +132,33 @@ 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);
 
+        String tempUserId = applyUserId;
+        if (StringUtils.isEmpty(tempUserId)) {
+            tempUserId = TempUserUtil.getVisitorTempUserId();
+        }
+        entity.setTempUserId(tempUserId);
         visitorMainDao.save(entity);
         return ResultContent.buildSuccess();
     }
@@ -111,6 +191,109 @@ 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 String markVisitor(String fromDataId) {
+        if (StringUtils.isNotEmpty(fromDataId)) {
+            VisitorMain visitorMain = visitorMainDao.findTopById(fromDataId);
+            if (ObjectUtils.isEmpty(visitorMain)) {
+                return "";
+            }
+            if (visitorMain.getState() == VisitorState.WaitVisit) {
+                visitorMain.setState(VisitorState.Visit);
+                visitorMain.setFirstVisitTime(System.currentTimeMillis());
+                visitorMainDao.save(visitorMain);
+                return visitorMain.getName();
+            }
+        }
+        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();
+    }
+
     public VisitorMainModel toModel(VisitorMain entity) {
         VisitorMainModel model = null;
         if (ObjectUtils.isNotEmpty(entity)) {

+ 23 - 0
FullCardServer/src/main/java/com/zhongshu/card/server/core/timer/SchedulEarlyMorning.java

@@ -0,0 +1,23 @@
+package com.zhongshu.card.server.core.timer;
+
+import lombok.extern.slf4j.Slf4j;
+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 {
+
+    // 每天凌晨1点执行
+    @Scheduled(cron = "0 0 1 * * ?")
+    public void executeMorning() {
+
+    }
+
+}

+ 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;
+    }
+}