Ver Fonte

Merge branch 'dev' into nb-pc-rabbitmq

18339543638 há 3 anos atrás
pai
commit
d7de60381d
53 ficheiros alterados com 998 adições e 270 exclusões
  1. 1 1
      nb-admin/src/main/java/com/nb/admin/controller/monitor/OnlineUserController.java
  2. 4 0
      nb-auth/pom.xml
  3. 12 0
      nb-auth/src/main/java/com/nb/auth/delay/AuthDelayConstant.java
  4. 23 0
      nb-auth/src/main/java/com/nb/auth/delay/AuthDelayMessage.java
  5. 74 0
      nb-auth/src/main/java/com/nb/auth/delay/AuthDelayMessageHandler.java
  6. 77 0
      nb-auth/src/main/java/com/nb/auth/sa/DefaultSaTokenListener.java
  7. 82 1
      nb-auth/src/main/java/com/nb/auth/sa/SaConfig.java
  8. 178 178
      nb-auth/src/main/java/com/nb/auth/sa/SaTokenActionDefaultImpl.java
  9. 1 0
      nb-auth/src/main/java/com/nb/auth/sa/SaTokenConfig.java
  10. 4 0
      nb-common/config-common/src/main/java/com/nb/common/config/mybatisplus/interceptor/DefaultTenantLineInnerInterceptor.java
  11. 0 1
      nb-common/crud-common/src/main/java/com/nb/common/crud/BaseService.java
  12. 0 5
      nb-common/crud-common/src/main/java/com/nb/common/crud/controller/BaseCrudController.java
  13. 5 1
      nb-common/crud-common/src/main/java/com/nb/common/crud/controller/BaseCurdAuthController.java
  14. 6 0
      nb-common/delay-queue-common/src/main/java/com/nb/common/queue/delay/message/DelayMessage.java
  15. 1 1
      nb-common/ws-common/src/main/java/com/nb/common/websocket/WebSocketConstant.java
  16. 24 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/msg/handler/ISubSuccessProcessor.java
  17. 25 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/msg/handler/IUnSubSuccessProcessor.java
  18. 5 1
      nb-common/ws-common/src/main/java/com/nb/common/websocket/msg/handler/SubMsgRequestHandler.java
  19. 4 1
      nb-common/ws-common/src/main/java/com/nb/common/websocket/msg/handler/UnSubMsgRequestHandler.java
  20. 0 5
      nb-im/src/main/java/com/nb/im/controller/ImRoomController.java
  21. 53 0
      nb-im/src/main/java/com/nb/im/job/ImRoomJob.java
  22. 20 0
      nb-im/src/main/java/com/nb/im/room/ImRoomOperator.java
  23. 37 6
      nb-im/src/main/java/com/nb/im/room/ImRoomOperatorManager.java
  24. 6 0
      nb-im/src/main/java/com/nb/im/utils/ImUtils.java
  25. 47 0
      nb-im/src/main/java/com/nb/im/ws/ImSubProcessor.java
  26. 1 0
      nb-im/src/main/java/com/nb/im/ws/ImSubscribe.java
  27. 45 0
      nb-im/src/main/java/com/nb/im/ws/ImUnSubProcessor.java
  28. 50 0
      nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/AssistUserController.java
  29. 12 0
      nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/CaptchaController.java
  30. 1 1
      nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/PatientOperationController.java
  31. 0 5
      nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/base/AppAssistantBaseCrudController.java
  32. 27 0
      nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/vo/ResetCaptchaVo.java
  33. 34 0
      nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/vo/ResetPswVo.java
  34. 2 1
      nb-service/app-assistant/src/main/java/com/nb/app/assistant/enums/CaptchaEnum.java
  35. 6 1
      nb-service/app-assistant/src/main/java/com/nb/app/assistant/service/LocalAssistantUserBindService.java
  36. 10 0
      nb-service/app-assistant/src/main/java/com/nb/app/assistant/service/LocalAssistantUserService.java
  37. 2 1
      nb-service/app-assistant/src/main/java/com/nb/app/assistant/utils/CaptchaUtil.java
  38. 46 0
      nb-service/app-assistant/src/main/java/com/nb/app/assistant/utils/ResetPswUtil.java
  39. 0 4
      nb-service/app-doctor/src/main/java/com/nb/app/doctor/controller/base/AppDoctorBaseCrudController.java
  40. 2 2
      nb-service/app-doctor/src/main/java/com/nb/app/doctor/controller/vo/MonitorEvalVo.java
  41. 40 6
      nb-service/app-doctor/src/main/java/com/nb/app/doctor/service/LocalAppDoctorUserService.java
  42. 0 5
      nb-service/app-msg/src/main/java/com/nb/app/msg/controller/AppConsultController.java
  43. 0 4
      nb-service/app-msg/src/main/java/com/nb/app/msg/controller/AppMsgController.java
  44. 1 5
      nb-service/web-service/src/main/java/com/nb/web/service/bus/controller/BusDeviceController.java
  45. 0 5
      nb-service/web-service/src/main/java/com/nb/web/service/bus/controller/BusInfusionHistoryController.java
  46. 0 4
      nb-service/web-service/src/main/java/com/nb/web/service/bus/controller/BusPatientController.java
  47. 4 0
      nb-service/web-service/src/main/java/com/nb/web/service/bus/entity/BusHospitalEntity.java
  48. 10 2
      nb-service/web-service/src/main/java/com/nb/web/service/bus/websocket/topic/WebSocketCloseHandler.java
  49. 0 6
      nb-service/web-service/src/main/java/com/nb/web/service/log/controller/SysRunningLogController.java
  50. 7 3
      nb-service/web-service/src/main/java/com/nb/web/service/system/auth/WebAuthGranter.java
  51. 7 12
      nb-service/web-service/src/main/java/com/nb/web/service/system/controller/SysApplyController.java
  52. 1 1
      nb-service/web-service/src/main/java/com/nb/web/service/system/controller/SysUserController.java
  53. 1 1
      pom.xml

+ 1 - 1
nb-admin/src/main/java/com/nb/admin/controller/monitor/OnlineUserController.java

@@ -40,7 +40,7 @@ public class OnlineUserController {
     @SaCheckPermission("monitor:online:page")
     @Log(title = "在线用户分页查询")
     public R page(Page reqPage, String username, String userPlatform) {
-        List<String> keys = SecurityUtil.getStpLogic().searchTokenValue("", -1, 0);
+        List<String> keys = SecurityUtil.getStpLogic().searchTokenValue("", -1, 0,false);
         List<LoginUser> loginUserList = Lists.newArrayList();
         for (String key : keys) {
             // token sample, Authorization:login:token:8734da0866f4440daeea3d836d5ecf8c

+ 4 - 0
nb-auth/pom.xml

@@ -13,6 +13,10 @@
 
 
     <dependencies>
+        <dependency>
+            <groupId>com.tuoren</groupId>
+            <artifactId>delay-queue-common</artifactId>
+        </dependency>
         <dependency>
             <groupId>com.tuoren</groupId>
             <artifactId>nb-core</artifactId>

+ 12 - 0
nb-auth/src/main/java/com/nb/auth/delay/AuthDelayConstant.java

@@ -0,0 +1,12 @@
+package com.nb.auth.delay;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName AuthDelayConstant.java
+ * @Description TODO
+ * @createTime 2022年09月16日 13:46:00
+ */
+public class AuthDelayConstant {
+    public static final String AUTH_HANDLER="auth_login";
+}

+ 23 - 0
nb-auth/src/main/java/com/nb/auth/delay/AuthDelayMessage.java

@@ -0,0 +1,23 @@
+package com.nb.auth.delay;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName AuthDelayMessage.java
+ * @Description TODO
+ * @createTime 2022年09月16日 13:40:00
+ */
+@Data
+@AllArgsConstructor(staticName = "of")
+public class AuthDelayMessage implements Serializable {
+    private String loginType;
+    private String tokenValue;
+    private long activityTimeout;
+    private TimeUnit unit;
+}

+ 74 - 0
nb-auth/src/main/java/com/nb/auth/delay/AuthDelayMessageHandler.java

@@ -0,0 +1,74 @@
+package com.nb.auth.delay;
+
+import cn.dev33.satoken.dao.SaTokenDao;
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.exception.SaTokenException;
+import cn.dev33.satoken.stp.StpLogic;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.nb.auth.utils.SecurityUtil;
+import com.nb.common.queue.delay.handler.DelayMessageHandler;
+import com.nb.common.queue.delay.manager.DelayMessageManager;
+import com.nb.common.queue.delay.message.DelayMessage;
+import com.nb.common.queue.delay.message.DelayMessageProperties;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName AuthDelayHandler.java
+ * @Description TODO
+ * @createTime 2022年09月16日 13:46:00
+ */
+@Component
+@Slf4j
+public class AuthDelayMessageHandler implements DelayMessageHandler {
+    @Autowired
+    @Lazy
+    private DelayMessageManager delayMessageManager;
+    @Override
+    public String getId() {
+        return AuthDelayConstant.AUTH_HANDLER;
+    }
+
+    @Override
+    public String description() {
+        return "登录成功后处理,清除冗余token,减少冗余资源";
+    }
+
+    @Override
+    public void handle(DelayMessage message) {
+        AuthDelayMessage body = message.getBody().as(AuthDelayMessage.class);
+        if(body==null){
+            return;
+        }
+        if(StrUtil.isEmpty(body.getTokenValue())){
+            return;
+        }
+        String tokenValue = body.getTokenValue();
+        StpLogic stpLogic =null;
+        try {
+            stpLogic = SecurityUtil.getStpLogic(body.getLoginType());
+            long timeout = stpLogic.getTokenActivityTimeoutByToken(tokenValue);
+            if(timeout == SaTokenDao.NOT_VALUE_EXPIRE) {
+                throw NotLoginException.newInstance(body.getLoginType(), NotLoginException.TOKEN_TIMEOUT, tokenValue);
+            }
+            //继续判断
+            delayMessageManager.add(new DelayMessage(message, AuthDelayConstant.AUTH_HANDLER, DelayMessageProperties.of(TimeUnit.SECONDS,body.getActivityTimeout())));
+        }catch (NotLoginException e){
+            //已过期,清除
+            if(stpLogic!=null){
+                stpLogic.logoutByTokenValue(tokenValue);
+            }
+            log.info("清除冗余tokenValue:{},loginType:{}",tokenValue,body.getLoginType());
+        }catch (SaTokenException e){
+            log.error("清除冗余token数据发生错误,message:{}", JSONUtil.toJsonStr(body),e);
+        }
+
+    }
+}

+ 77 - 0
nb-auth/src/main/java/com/nb/auth/sa/DefaultSaTokenListener.java

@@ -0,0 +1,77 @@
+package com.nb.auth.sa;
+
+import cn.dev33.satoken.config.SaTokenConfig;
+import cn.dev33.satoken.listener.SaTokenListener;
+import cn.dev33.satoken.stp.SaLoginModel;
+import com.nb.auth.delay.AuthDelayConstant;
+import com.nb.auth.delay.AuthDelayMessage;
+import com.nb.common.queue.delay.manager.DelayMessageManager;
+import com.nb.common.queue.delay.message.DelayMessage;
+import com.nb.common.queue.delay.message.DelayMessageProperties;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName DefaultSaTokenListener.java
+ * @Description TODO
+ * @createTime 2022年09月16日 13:38:00
+ */
+@Component
+@AllArgsConstructor
+@Slf4j
+public class DefaultSaTokenListener implements SaTokenListener {
+    private final DelayMessageManager delayMessageManager;
+    private final SaTokenConfig saTokenConfig;
+
+
+    @Override
+    public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
+        AuthDelayMessage message = AuthDelayMessage.of(loginType, tokenValue, saTokenConfig.getActivityTimeout(), TimeUnit.SECONDS);
+        log.info("账号{}登录成功,tokenValue:{},loginType:{}",loginId,loginModel.getToken(),loginType);
+        delayMessageManager.add(new DelayMessage(message, AuthDelayConstant.AUTH_HANDLER, DelayMessageProperties.of(TimeUnit.SECONDS,saTokenConfig.getActivityTimeout())));
+    }
+
+    @Override
+    public void doLogout(String loginType, Object loginId, String tokenValue) {
+
+    }
+
+    @Override
+    public void doKickout(String loginType, Object loginId, String tokenValue) {
+
+    }
+
+    @Override
+    public void doReplaced(String loginType, Object loginId, String tokenValue) {
+
+    }
+
+    @Override
+    public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {
+
+    }
+
+    @Override
+    public void doUntieDisable(String loginType, Object loginId, String service) {
+
+    }
+
+    @Override
+    public void doCreateSession(String id) {
+
+    }
+
+    @Override
+    public void doLogoutSession(String id) {
+
+    }
+
+    @Override
+    public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
+
+    }
+}

+ 82 - 1
nb-auth/src/main/java/com/nb/auth/sa/SaConfig.java

@@ -1,13 +1,20 @@
 package com.nb.auth.sa;
 
 import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.annotation.*;
+import cn.dev33.satoken.basic.SaBasicUtil;
 import cn.dev33.satoken.dao.SaTokenDaoRedisJackson;
+import cn.dev33.satoken.exception.NotPermissionException;
 import cn.dev33.satoken.stp.StpLogic;
+import cn.dev33.satoken.strategy.SaStrategy;
+import cn.hutool.core.util.StrUtil;
 import com.nb.auth.enums.StpTypeEnum;
+import com.nb.auth.utils.SecurityUtil;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.PostConstruct;
+import java.util.regex.Pattern;
 
 /**
  * @author lifang
@@ -20,13 +27,87 @@ import javax.annotation.PostConstruct;
 @AllArgsConstructor
 public class SaConfig {
     private final SaTokenDaoRedisJackson saTokenDaoRedisJackson;
+    private final DefaultSaTokenListener defaultSaTokenListener;
     @PostConstruct
     public void init(){
-        SaManager.setSaTokenAction(new SaTokenActionDefaultImpl());
+        SaStrategy.me.hasElement=(list,element)->{
+            // 空集合直接返回false
+            if(list == null || list.size() == 0) {
+                return false;
+            }
+            // 先尝试一下简单匹配,如果可以匹配成功则无需继续模糊匹配
+            if (list.contains(element)) {
+                return true;
+            }
+            // 开始模糊匹配
+            for (String patt : list) {
+                if(vagueMatch(patt, element)) {
+                    return true;
+                }
+            }
+            // 走出for循环说明没有一个元素可以匹配成功
+            return false;
+        };
+        SaStrategy.me.checkElementAnnotation=target->{
+            // 校验 @SaCheckLogin 注解
+            SaCheckLogin checkLogin = (SaCheckLogin) SaStrategy.me.getAnnotation.apply(target, SaCheckLogin.class);
+            if(checkLogin != null) {
+                SaManager.getStpLogic(checkLogin.type()).checkByAnnotation(checkLogin);
+            }
+
+            // 校验 @SaCheckRole 注解
+            SaCheckRole checkRole = (SaCheckRole) SaStrategy.me.getAnnotation.apply(target, SaCheckRole.class);
+            if(checkRole != null) {
+                SaManager.getStpLogic(checkRole.type()).checkByAnnotation(checkRole);
+            }
+
+            // 校验 @SaCheckPermission 注解
+            SaCheckPermission checkPermission = (SaCheckPermission) SaStrategy.me.getAnnotation.apply(target, SaCheckPermission.class);
+            if(checkPermission != null) {
+                String type= StrUtil.isBlankIfStr(checkPermission.type())?"login":checkPermission.type();
+                StpLogic stpLogic = SecurityUtil.getStpLogic();
+                if (!type.equals(stpLogic.getLoginType())) {
+                    throw new NotPermissionException("无权限访问此体系接口");
+                }
+                SaManager.getStpLogic(checkPermission.type()).checkByAnnotation(checkPermission);
+            }
+
+            // 校验 @SaCheckSafe 注解
+            SaCheckSafe checkSafe = (SaCheckSafe) SaStrategy.me.getAnnotation.apply(target, SaCheckSafe.class);
+            if(checkSafe != null) {
+                SaManager.getStpLogic(checkSafe.type()).checkByAnnotation(checkSafe);
+            }
+
+            // 校验 @SaCheckBasic 注解
+            SaCheckBasic checkBasic = (SaCheckBasic) SaStrategy.me.getAnnotation.apply(target, SaCheckBasic.class);
+            if(checkBasic != null) {
+                SaBasicUtil.check(checkBasic.realm(), checkBasic.account());
+            }
+        };
+//        SaManager.setSaTokenContext();
+//        SaManager.setSaTokenAction(new SaTokenActionDefaultImpl());
         SaManager.setSaTokenDao(saTokenDaoRedisJackson);
+//        SaManager.setSaTokenListener(defaultSaTokenListener);
         StpTypeEnum[] values = StpTypeEnum.values();
         for (StpTypeEnum value : values) {
             SaManager.putStpLogic(new StpLogic(value.getText()));
         }
     }
+
+    /**
+     * 字符串模糊匹配
+     * <p>example:
+     * <p> user-add user*    --  true
+     * <p> art-add user*     --  false
+     * @param patt 表达式
+     * @param str 待匹配的字符串
+     * @return 是否可以匹配
+     */
+    public static boolean vagueMatch(String patt, String str) {
+        // 如果表达式不带有*号,则只需简单equals即可 (速度提升200倍)
+        if(!str.contains("*")&&!patt.contains("*")) {
+            return patt.equals(str);
+        }
+        return Pattern.matches(str.replaceAll("\\*", ".*"), patt)||Pattern.matches(patt.replaceAll("\\*", ".*"), str);
+    }
 }

+ 178 - 178
nb-auth/src/main/java/com/nb/auth/sa/SaTokenActionDefaultImpl.java

@@ -1,178 +1,178 @@
-package com.nb.auth.sa;
-
-import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.UUID;
-import java.util.regex.Pattern;
-
-import cn.dev33.satoken.SaManager;
-import cn.dev33.satoken.action.SaTokenAction;
-import cn.dev33.satoken.annotation.SaCheckBasic;
-import cn.dev33.satoken.annotation.SaCheckLogin;
-import cn.dev33.satoken.annotation.SaCheckPermission;
-import cn.dev33.satoken.annotation.SaCheckRole;
-import cn.dev33.satoken.annotation.SaCheckSafe;
-import cn.dev33.satoken.basic.SaBasicUtil;
-import cn.dev33.satoken.exception.NotPermissionException;
-import cn.dev33.satoken.session.SaSession;
-import cn.dev33.satoken.stp.StpLogic;
-import cn.dev33.satoken.strategy.SaStrategy;
-import cn.dev33.satoken.util.SaFoxUtil;
-import cn.dev33.satoken.util.SaTokenConsts;
-import cn.hutool.core.util.StrUtil;
-import com.nb.auth.utils.SecurityUtil;
-
-/**
- * <h1> v1.27+ 此接口已废弃,目前版本暂时向下兼容,请及时更换为 SaStrategy </h1>
- * <p> Sa-Token 逻辑代理接口 [默认实现类]  </p> 
- * @author kong
- *
- */
-public class SaTokenActionDefaultImpl implements SaTokenAction {
-
-	/**
-	 * 创建一个Token 
-	 */
-	@Override
-	public String createToken(Object loginId, String loginType) {
-		// 根据配置的tokenStyle生成不同风格的token 
-		String tokenStyle = SaManager.getConfig().getTokenStyle();
-		// uuid 
-		if(SaTokenConsts.TOKEN_STYLE_UUID.equals(tokenStyle)) {
-			return UUID.randomUUID().toString();
-		}
-		// 简单uuid (不带下划线)
-		if(SaTokenConsts.TOKEN_STYLE_SIMPLE_UUID.equals(tokenStyle)) {
-			return UUID.randomUUID().toString().replaceAll("-", "");
-		}
-		// 32位随机字符串
-		if(SaTokenConsts.TOKEN_STYLE_RANDOM_32.equals(tokenStyle)) {
-			return SaFoxUtil.getRandomString(32);
-		}
-		// 64位随机字符串
-		if(SaTokenConsts.TOKEN_STYLE_RANDOM_64.equals(tokenStyle)) {
-			return SaFoxUtil.getRandomString(64);
-		}
-		// 128位随机字符串
-		if(SaTokenConsts.TOKEN_STYLE_RANDOM_128.equals(tokenStyle)) {
-			return SaFoxUtil.getRandomString(128);
-		}
-		// tik风格 (2_14_16)
-		if(SaTokenConsts.TOKEN_STYLE_TIK.equals(tokenStyle)) {
-			return SaFoxUtil.getRandomString(2) + "_" + SaFoxUtil.getRandomString(14) + "_" + SaFoxUtil.getRandomString(16) + "__";
-		}
-		// 默认,还是uuid 
-		return UUID.randomUUID().toString();
-	}
-
-	/**
-	 * 创建一个Session 
-	 */
-	@Override
-	public SaSession createSession(String sessionId) {
-		return new SaSession(sessionId);
-	}
-
-	/**
-	 * 判断:集合中是否包含指定元素(模糊匹配) 
-	 */
-	@Override
-	public boolean hasElement(List<String> list, String element) {
-		
-		// 空集合直接返回false
-		if(list == null || list.size() == 0) {
-			return false;
-		}
-
-		// 先尝试一下简单匹配,如果可以匹配成功则无需继续模糊匹配 
-		if (list.contains(element)) {
-			return true;
-		}
-		
-		// 开始模糊匹配 
-		for (String patt : list) {
-			if(vagueMatch(patt, element)) {
-				return true;
-			}
-		}
-		
-		// 走出for循环说明没有一个元素可以匹配成功 
-		return false;
-	}
-
-	/**
-	 * 对一个Method对象进行注解检查(注解鉴权内部实现) 
-	 */
-	@Override
-	public void checkMethodAnnotation(Method method) {
-
-		// 先校验 Method 所属 Class 上的注解 
-		validateAnnotation(method.getDeclaringClass());
-		
-		// 再校验 Method 上的注解  
-		validateAnnotation(method);
-	}
-
-	/**
-	 * 从指定元素校验注解 
-	 * @param target see note 
-	 */
-	@Override
-	public void validateAnnotation(AnnotatedElement target) {
-
-		// 校验 @SaCheckLogin 注解 
-		SaCheckLogin checkLogin = (SaCheckLogin) SaStrategy.me.getAnnotation.apply(target, SaCheckLogin.class);
-		if(checkLogin != null) {
-			SaManager.getStpLogic(checkLogin.type()).checkByAnnotation(checkLogin);
-		}
-		
-		// 校验 @SaCheckRole 注解 
-		SaCheckRole checkRole = (SaCheckRole) SaStrategy.me.getAnnotation.apply(target, SaCheckRole.class);
-		if(checkRole != null) {
-			SaManager.getStpLogic(checkRole.type()).checkByAnnotation(checkRole);
-		}
-		
-		// 校验 @SaCheckPermission 注解
-		SaCheckPermission checkPermission = (SaCheckPermission) SaStrategy.me.getAnnotation.apply(target, SaCheckPermission.class);
-		if(checkPermission != null) {
-			String type= StrUtil.isBlankIfStr(checkPermission.type())?"login":checkPermission.type();
-			StpLogic stpLogic = SecurityUtil.getStpLogic();
-			if (!type.equals(stpLogic.getLoginType())) {
-				throw new NotPermissionException("无权限访问此体系接口");
-			}
-			SaManager.getStpLogic(checkPermission.type()).checkByAnnotation(checkPermission);
-		}
-
-		// 校验 @SaCheckSafe 注解
-		SaCheckSafe checkSafe = (SaCheckSafe) SaStrategy.me.getAnnotation.apply(target, SaCheckSafe.class);
-		if(checkSafe != null) {
-			SaManager.getStpLogic(checkSafe.type()).checkByAnnotation(checkSafe);
-		}
-		
-		// 校验 @SaCheckBasic 注解
-		SaCheckBasic checkBasic = (SaCheckBasic) SaStrategy.me.getAnnotation.apply(target, SaCheckBasic.class);
-		if(checkBasic != null) {
-			SaBasicUtil.check(checkBasic.realm(), checkBasic.account());
-		}
-		
-	}
-
-
-	/**
-	 * 字符串模糊匹配
-	 * <p>example:
-	 * <p> user-add user*    --  true
-	 * <p> art-add user*     --  false
-	 * @param patt 表达式
-	 * @param str 待匹配的字符串
-	 * @return 是否可以匹配
-	 */
-	public static boolean vagueMatch(String patt, String str) {
-		// 如果表达式不带有*号,则只需简单equals即可 (速度提升200倍)
-		if(!str.contains("*")&&!patt.contains("*")) {
-			return patt.equals(str);
-		}
-		return Pattern.matches(str.replaceAll("\\*", ".*"), patt)||Pattern.matches(patt.replaceAll("\\*", ".*"), str);
-	}
-}
+//package com.nb.auth.sa;
+//
+//import java.lang.reflect.AnnotatedElement;
+//import java.lang.reflect.Method;
+//import java.util.List;
+//import java.util.UUID;
+//import java.util.regex.Pattern;
+//
+//import cn.dev33.satoken.SaManager;
+//import cn.dev33.satoken.action.SaTokenAction;
+//import cn.dev33.satoken.annotation.SaCheckBasic;
+//import cn.dev33.satoken.annotation.SaCheckLogin;
+//import cn.dev33.satoken.annotation.SaCheckPermission;
+//import cn.dev33.satoken.annotation.SaCheckRole;
+//import cn.dev33.satoken.annotation.SaCheckSafe;
+//import cn.dev33.satoken.basic.SaBasicUtil;
+//import cn.dev33.satoken.exception.NotPermissionException;
+//import cn.dev33.satoken.session.SaSession;
+//import cn.dev33.satoken.stp.StpLogic;
+//import cn.dev33.satoken.strategy.SaStrategy;
+//import cn.dev33.satoken.util.SaFoxUtil;
+//import cn.dev33.satoken.util.SaTokenConsts;
+//import cn.hutool.core.util.StrUtil;
+//import com.nb.auth.utils.SecurityUtil;
+//
+///**
+// * <h1> v1.27+ 此接口已废弃,目前版本暂时向下兼容,请及时更换为 SaStrategy </h1>
+// * <p> Sa-Token 逻辑代理接口 [默认实现类]  </p>
+// * @author kong
+// *
+// */
+//public class SaTokenActionDefaultImpl implements SaTokenAction {
+//
+//	/**
+//	 * 创建一个Token
+//	 */
+//	@Override
+//	public String createToken(Object loginId, String loginType) {
+//		// 根据配置的tokenStyle生成不同风格的token
+//		String tokenStyle = SaManager.getConfig().getTokenStyle();
+//		// uuid
+//		if(SaTokenConsts.TOKEN_STYLE_UUID.equals(tokenStyle)) {
+//			return UUID.randomUUID().toString();
+//		}
+//		// 简单uuid (不带下划线)
+//		if(SaTokenConsts.TOKEN_STYLE_SIMPLE_UUID.equals(tokenStyle)) {
+//			return UUID.randomUUID().toString().replaceAll("-", "");
+//		}
+//		// 32位随机字符串
+//		if(SaTokenConsts.TOKEN_STYLE_RANDOM_32.equals(tokenStyle)) {
+//			return SaFoxUtil.getRandomString(32);
+//		}
+//		// 64位随机字符串
+//		if(SaTokenConsts.TOKEN_STYLE_RANDOM_64.equals(tokenStyle)) {
+//			return SaFoxUtil.getRandomString(64);
+//		}
+//		// 128位随机字符串
+//		if(SaTokenConsts.TOKEN_STYLE_RANDOM_128.equals(tokenStyle)) {
+//			return SaFoxUtil.getRandomString(128);
+//		}
+//		// tik风格 (2_14_16)
+//		if(SaTokenConsts.TOKEN_STYLE_TIK.equals(tokenStyle)) {
+//			return SaFoxUtil.getRandomString(2) + "_" + SaFoxUtil.getRandomString(14) + "_" + SaFoxUtil.getRandomString(16) + "__";
+//		}
+//		// 默认,还是uuid
+//		return UUID.randomUUID().toString();
+//	}
+//
+//	/**
+//	 * 创建一个Session
+//	 */
+//	@Override
+//	public SaSession createSession(String sessionId) {
+//		return new SaSession(sessionId);
+//	}
+//
+//	/**
+//	 * 判断:集合中是否包含指定元素(模糊匹配)
+//	 */
+//	@Override
+//	public boolean hasElement(List<String> list, String element) {
+//
+//		// 空集合直接返回false
+//		if(list == null || list.size() == 0) {
+//			return false;
+//		}
+//
+//		// 先尝试一下简单匹配,如果可以匹配成功则无需继续模糊匹配
+//		if (list.contains(element)) {
+//			return true;
+//		}
+//
+//		// 开始模糊匹配
+//		for (String patt : list) {
+//			if(vagueMatch(patt, element)) {
+//				return true;
+//			}
+//		}
+//
+//		// 走出for循环说明没有一个元素可以匹配成功
+//		return false;
+//	}
+//
+//	/**
+//	 * 对一个Method对象进行注解检查(注解鉴权内部实现)
+//	 */
+//	@Override
+//	public void checkMethodAnnotation(Method method) {
+//
+//		// 先校验 Method 所属 Class 上的注解
+//		validateAnnotation(method.getDeclaringClass());
+//
+//		// 再校验 Method 上的注解
+//		validateAnnotation(method);
+//	}
+//
+//	/**
+//	 * 从指定元素校验注解
+//	 * @param target see note
+//	 */
+//	@Override
+//	public void validateAnnotation(AnnotatedElement target) {
+//
+//		// 校验 @SaCheckLogin 注解
+//		SaCheckLogin checkLogin = (SaCheckLogin) SaStrategy.me.getAnnotation.apply(target, SaCheckLogin.class);
+//		if(checkLogin != null) {
+//			SaManager.getStpLogic(checkLogin.type()).checkByAnnotation(checkLogin);
+//		}
+//
+//		// 校验 @SaCheckRole 注解
+//		SaCheckRole checkRole = (SaCheckRole) SaStrategy.me.getAnnotation.apply(target, SaCheckRole.class);
+//		if(checkRole != null) {
+//			SaManager.getStpLogic(checkRole.type()).checkByAnnotation(checkRole);
+//		}
+//
+//		// 校验 @SaCheckPermission 注解
+//		SaCheckPermission checkPermission = (SaCheckPermission) SaStrategy.me.getAnnotation.apply(target, SaCheckPermission.class);
+//		if(checkPermission != null) {
+//			String type= StrUtil.isBlankIfStr(checkPermission.type())?"login":checkPermission.type();
+//			StpLogic stpLogic = SecurityUtil.getStpLogic();
+//			if (!type.equals(stpLogic.getLoginType())) {
+//				throw new NotPermissionException("无权限访问此体系接口");
+//			}
+//			SaManager.getStpLogic(checkPermission.type()).checkByAnnotation(checkPermission);
+//		}
+//
+//		// 校验 @SaCheckSafe 注解
+//		SaCheckSafe checkSafe = (SaCheckSafe) SaStrategy.me.getAnnotation.apply(target, SaCheckSafe.class);
+//		if(checkSafe != null) {
+//			SaManager.getStpLogic(checkSafe.type()).checkByAnnotation(checkSafe);
+//		}
+//
+//		// 校验 @SaCheckBasic 注解
+//		SaCheckBasic checkBasic = (SaCheckBasic) SaStrategy.me.getAnnotation.apply(target, SaCheckBasic.class);
+//		if(checkBasic != null) {
+//			SaBasicUtil.check(checkBasic.realm(), checkBasic.account());
+//		}
+//
+//	}
+//
+//
+//	/**
+//	 * 字符串模糊匹配
+//	 * <p>example:
+//	 * <p> user-add user*    --  true
+//	 * <p> art-add user*     --  false
+//	 * @param patt 表达式
+//	 * @param str 待匹配的字符串
+//	 * @return 是否可以匹配
+//	 */
+//	public static boolean vagueMatch(String patt, String str) {
+//		// 如果表达式不带有*号,则只需简单equals即可 (速度提升200倍)
+//		if(!str.contains("*")&&!patt.contains("*")) {
+//			return patt.equals(str);
+//		}
+//		return Pattern.matches(str.replaceAll("\\*", ".*"), patt)||Pattern.matches(patt.replaceAll("\\*", ".*"), str);
+//	}
+//}

+ 1 - 0
nb-auth/src/main/java/com/nb/auth/sa/SaTokenConfig.java

@@ -66,6 +66,7 @@ public class SaTokenConfig {
         IGNORE_URL.add("/system/curl/**");
         IGNORE_URL.add("/system/sysConfig/getTime");
         IGNORE_URL.add("/system/sysDept/**");
+        IGNORE_URL.add("/assist/phone/**");
     }
 
 }

+ 4 - 0
nb-common/config-common/src/main/java/com/nb/common/config/mybatisplus/interceptor/DefaultTenantLineInnerInterceptor.java

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
 import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
 import com.nb.auth.bean.LoginUser;
+import com.nb.auth.enums.StpTypeEnum;
 import com.nb.auth.utils.SecurityUtil;
 import com.nb.core.entity.TenantGenericEntity;
 import net.sf.jsqlparser.expression.Expression;
@@ -86,6 +87,9 @@ public class DefaultTenantLineInnerInterceptor {
                 if(request==null||request.getRequest() instanceof MockHttpServletRequest){
                     return true;
                 }
+                if (StpTypeEnum.ASSISTANT.getText().equals(SecurityUtil.getStpLogic().loginType)) {
+                    return true;
+                }
                 StringBuffer url = request.getRequest().getRequestURL();
                 if(ignoreUrlTenantId.stream().anyMatch(ignoreUrl->url.toString().endsWith(ignoreUrl))){
                     return true;

+ 0 - 1
nb-common/crud-common/src/main/java/com/nb/common/crud/BaseService.java

@@ -325,5 +325,4 @@ public abstract class BaseService<M extends BaseMapper<E>, E,PK extends Serializ
      **/
 
     public  abstract void validateBeforeDelete(PK id) ;
-
 }

+ 0 - 5
nb-common/crud-common/src/main/java/com/nb/common/crud/controller/BaseCrudController.java

@@ -31,9 +31,4 @@ public abstract class BaseCrudController<E, K extends Serializable> implements
     public String getPermissionPrefix() {
         return null;
     }
-
-    @Override
-    public StpLogic getStpLogin() {
-        return SecurityUtil.getStpLogic();
-    }
 }

+ 5 - 1
nb-common/crud-common/src/main/java/com/nb/common/crud/controller/BaseCurdAuthController.java

@@ -2,6 +2,8 @@ package com.nb.common.crud.controller;
 
 import cn.dev33.satoken.stp.StpLogic;
 import cn.hutool.core.text.CharSequenceUtil;
+import com.nb.auth.utils.SecurityUtil;
+
 import java.util.Arrays;
 import java.util.List;
 
@@ -22,7 +24,9 @@ public interface BaseCurdAuthController {
      **/
     String getPermissionPrefix();
 
-    StpLogic getStpLogin();
+    default StpLogic getStpLogin(){
+        return SecurityUtil.getStpLogic();
+    };
 
     default void saveAuth(){
         if(isAuth()){

+ 6 - 0
nb-common/delay-queue-common/src/main/java/com/nb/common/queue/delay/message/DelayMessage.java

@@ -53,6 +53,12 @@ public class DelayMessage implements Serializable {
         this.properties = properties;
     }
 
+    public DelayMessage(@NonNull Object body, @NonNull String handlerId, @NonNull DelayMessageProperties properties) {
+        this.msgId = UUID.randomUUID().toString();
+        this.body = Value.simple(body);
+        this.handlerId = handlerId;
+        this.properties = properties;
+    }
 
 
     public void check() {

+ 1 - 1
nb-common/ws-common/src/main/java/com/nb/common/websocket/WebSocketConstant.java

@@ -48,7 +48,7 @@ public class WebSocketConstant {
      */
     public static TopicWrapper getTopic(String id,String productName,String param,String tenantId){
         productName=StrUtil.isEmptyIfStr(productName)?"default":productName;
-        tenantId=StrUtil.isNullOrUndefined(tenantId)?"*":tenantId;
+        tenantId=StrUtil.isNullOrUndefined(tenantId)||StrUtil.isBlank(tenantId)?"*":tenantId;
         return TopicWrapper.of(id+"-"+productName+"-"+param+"-"+tenantId,param);
     }
 

+ 24 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/msg/handler/ISubSuccessProcessor.java

@@ -0,0 +1,24 @@
+package com.nb.common.websocket.msg.handler;
+
+import com.nb.common.websocket.msg.MessagingRequest;
+import org.tio.core.ChannelContext;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName ISubSuccessProcessor.java
+ * @Description TODO
+ * @createTime 2022年09月15日 10:13:00
+ */
+public interface ISubSuccessProcessor {
+
+    /**
+     * 描述: 取消订阅成功后
+     * @author lifang
+     * @date 2022/9/15 10:15
+     * @param message
+     * @param channelContext
+     * @return void
+     */
+    void postSub(MessagingRequest message, ChannelContext channelContext);
+}

+ 25 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/msg/handler/IUnSubSuccessProcessor.java

@@ -0,0 +1,25 @@
+package com.nb.common.websocket.msg.handler;
+
+import com.nb.common.websocket.msg.MessagingRequest;
+import org.tio.core.ChannelContext;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName ISubSuccessProcessor.java
+ * @Description TODO
+ * @createTime 2022年09月15日 10:13:00
+ */
+public interface IUnSubSuccessProcessor {
+
+    /**
+     * 描述: 取消订阅成功后
+     * @author lifang
+     * @date 2022/9/15 10:15
+     * @param message
+     * @param channelContext
+     * @return void
+     *
+     */
+    void postUnSub(MessagingRequest message, ChannelContext channelContext);
+}

+ 5 - 1
nb-common/ws-common/src/main/java/com/nb/common/websocket/msg/handler/SubMsgRequestHandler.java

@@ -9,7 +9,7 @@ import org.redisson.api.RPatternTopic;
 import org.redisson.api.RedissonClient;
 import org.springframework.stereotype.Component;
 import org.tio.core.ChannelContext;
-
+import java.util.*;
 /**
  * @author lifang
  * @version 1.0.0
@@ -24,6 +24,8 @@ public class SubMsgRequestHandler implements IMsgRequestHandler {
     private final ObjectMapper objectMapper;
 
     private final RedissonClient redissonClient;
+
+    private final List<ISubSuccessProcessor> processorList;
     @Override
     public MessagingRequest.Type getType() {
         return MessagingRequest.Type.sub;
@@ -35,5 +37,7 @@ public class SubMsgRequestHandler implements IMsgRequestHandler {
         //同一主题只订阅一次
         RPatternTopic rTopic = subTopicMap.computeIfAbsent(topicWrapper.getTopic(), topic->redissonClient.getPatternTopic(topicWrapper.getTopic()));
         addTopicListener(rTopic,channelContext, topicWrapper.getTopic(),message.getId());
+
+        processorList.forEach(processor->processor.postSub(message,channelContext));
     }
 }

+ 4 - 1
nb-common/ws-common/src/main/java/com/nb/common/websocket/msg/handler/UnSubMsgRequestHandler.java

@@ -11,6 +11,7 @@ import org.springframework.stereotype.Component;
 import org.tio.core.ChannelContext;
 
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -26,7 +27,7 @@ import java.util.Set;
 public class UnSubMsgRequestHandler implements IMsgRequestHandler {
     @Getter
     private final ObjectMapper objectMapper;
-
+    private final List<IUnSubSuccessProcessor> processorList;
     @Override
     public MessagingRequest.Type getType() {
         return MessagingRequest.Type.unsub;
@@ -53,5 +54,7 @@ public class UnSubMsgRequestHandler implements IMsgRequestHandler {
             Map<String, DefaultMessageListener> topicListeners = getTopicListeners(channelContext);
             topicListeners.remove(subTopic);
         }
+
+        processorList.forEach(processor->processor.postUnSub(message,channelContext));
     }
 }

+ 0 - 5
nb-im/src/main/java/com/nb/im/controller/ImRoomController.java

@@ -179,9 +179,4 @@ public class ImRoomController implements BaseSaveController<ImRoomEntity,String>
     public String getPermissionPrefix() {
         return null;
     }
-
-    @Override
-    public StpLogic getStpLogin() {
-        return SecurityUtil.getStpLogic();
-    }
 }

+ 53 - 0
nb-im/src/main/java/com/nb/im/job/ImRoomJob.java

@@ -0,0 +1,53 @@
+package com.nb.im.job;
+
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.nb.im.entity.ImRoomEntity;
+import com.nb.im.enums.ImStatusEnum;
+import com.nb.im.service.LocalImRoomService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.Scheduled;
+
+import java.util.Date;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName ImRoomJob.java
+ * @Description TODO
+ * @createTime 2022年09月15日 10:34:00
+ */
+@AllArgsConstructor
+@Configuration
+@Slf4j
+public class ImRoomJob {
+    private final LocalImRoomService imRoomService;
+    /**
+     * 描述:每天凌晨2点计算自动结束聊天室时间
+     * @author lifang
+     * @date 2022/9/15 10:38
+     * @param
+     * @return void
+     */
+    @Scheduled(cron = "0 0 2 * * ?")
+    public void autoFinish(){
+        try {
+            log.info("执行24小时自动结束聊天室任务");
+            Date now = new Date();
+            //24小时之前的时间
+            DateTime offset = DateUtil.offset( now, DateField.HOUR, -24);
+            imRoomService.update(new UpdateWrapper<ImRoomEntity>()
+                    .lambda()
+                    .lt(ImRoomEntity::getSuccessTime, offset)
+                    .eq(ImRoomEntity::getStatus, ImStatusEnum.SUCCESS)
+                    .set(ImRoomEntity::getStatus, ImStatusEnum.AUTO_LIST)
+                    .set(ImRoomEntity::getUpdateTime,now));
+        }catch (Exception e){
+            log.error("24小时自动结束聊天室失败,",e);
+        }
+    }
+}

+ 20 - 0
nb-im/src/main/java/com/nb/im/room/ImRoomOperator.java

@@ -22,6 +22,11 @@ public class ImRoomOperator {
     private final String assitId;
     @Getter
     private final String doctorId;
+
+    @Getter
+    private final Date startTime;
+
+    private boolean doctorOnline=false;
     /**
      * 根据userId+roomId记录未读消息数量,并对未读的key进行保存
      */
@@ -36,6 +41,7 @@ public class ImRoomOperator {
         this.redissonClient=redissonClient;
         this.assitId=room.getAssistId();
         this.doctorId=room.getDoctorId();
+        this.startTime=new Date();
         userIds
                 .forEach(userId-> unReadMap.computeIfAbsent(userId,k->redissonClient.getSet("im:unread:"+id+":"+userId)));
 
@@ -140,4 +146,18 @@ public class ImRoomOperator {
         });
     }
 
+    /**
+     * 描述: 判断聊天室医生是否位于该聊天室内
+     * @author lifang
+     * @date 2022/9/14 17:30
+     * @param
+     * @return boolean
+     */
+    public boolean isOnlineDoctor() {
+        return doctorOnline;
+    }
+
+    public void setDoctorOnline(boolean online){
+         this.doctorOnline=online;
+    }
 }

+ 37 - 6
nb-im/src/main/java/com/nb/im/room/ImRoomOperatorManager.java

@@ -1,5 +1,7 @@
 package com.nb.im.room;
 
+import cn.hutool.core.date.DateUnit;
+import cn.hutool.core.date.DateUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.nb.im.entity.ImRoomUserEntity;
 import com.nb.im.service.LocalImRoomService;
@@ -8,12 +10,11 @@ import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import java.lang.ref.Reference;
-import java.lang.ref.WeakReference;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.WeakHashMap;
+import javax.annotation.PostConstruct;
+import java.util.*;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /**
@@ -26,6 +27,7 @@ import java.util.stream.Collectors;
 @Component
 public class ImRoomOperatorManager {
 
+
     private final Map<String,ImRoomOperator> imRoomOperatorMap=new HashMap<>();
 
     @Autowired
@@ -36,6 +38,35 @@ public class ImRoomOperatorManager {
 
     @Autowired
     private LocalImRoomUserService roomUserService;
+
+    private final ScheduledExecutorService singleThreadEventExecutor = Executors.newSingleThreadScheduledExecutor();
+    public ImRoomOperatorManager(RedissonClient redissonClient, LocalImRoomService roomService, LocalImRoomUserService roomUserService) {
+        this.redissonClient = redissonClient;
+        this.roomService = roomService;
+        this.roomUserService = roomUserService;
+    }
+
+    @PostConstruct
+    public void init(){
+        //定时清除map中的过期房间
+        singleThreadEventExecutor.scheduleAtFixedRate(()->{
+            Date now = new Date();
+            imRoomOperatorMap.values()
+                    .removeIf(roomOperator -> {
+                        Date startTime = roomOperator.getStartTime();
+                        long betweenHours = DateUtil.between(startTime, now, DateUnit.HOUR);
+                        if(betweenHours>48){
+                            //超过48小时强制删除
+                            return true;
+                        }else if(betweenHours>24&&roomOperator.isOnlineDoctor()){
+                            //超过24小时且医生不在线删除
+                            return true;
+                        }
+                        return false;
+                    });
+        },24,24, TimeUnit.HOURS);
+    }
+
     public ImRoomOperator getRoomOperator(String roomId){
         return imRoomOperatorMap.computeIfAbsent(new String(roomId),k->
                 new ImRoomOperator(roomId,

+ 6 - 0
nb-im/src/main/java/com/nb/im/utils/ImUtils.java

@@ -1,6 +1,7 @@
 package com.nb.im.utils;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.nb.common.websocket.PubResponse;
@@ -11,6 +12,7 @@ import com.nb.common.websocket.msg.MessageResponse;
 import com.nb.im.entity.ImMsgEntity;
 import com.nb.im.entity.ImRoomEntity;
 import com.nb.im.entity.ImRoomUserEntity;
+import com.nb.im.enums.SponsorEnum;
 import com.nb.im.room.ImRoomOperator;
 import com.nb.im.room.ImRoomOperatorManager;
 import com.nb.im.service.LocalImMsgService;
@@ -81,6 +83,10 @@ public class ImUtils {
         pubMsgInfo.setSort(roomOperator.generateSortId());
 
         ImMsgEntity roomMsg = BeanUtil.toBean(pubMsgInfo, ImMsgEntity.class);
+        String assitId = roomOperator.getAssitId();
+        if(ObjectUtil.equal(assitId,roomMsg.getSenderId())){
+            roomMsg.setSponsor(SponsorEnum.assist);
+        }
         imRoomMsgService.save(roomMsg);
 
 

+ 47 - 0
nb-im/src/main/java/com/nb/im/ws/ImSubProcessor.java

@@ -0,0 +1,47 @@
+package com.nb.im.ws;
+
+
+import com.nb.auth.bean.LoginUser;
+import com.nb.auth.enums.StpTypeEnum;
+import com.nb.common.websocket.WebSocketConstant;
+
+import com.nb.common.websocket.msg.MessagingRequest;
+import com.nb.common.websocket.msg.handler.ISubSuccessProcessor;
+import com.nb.im.room.ImRoomOperatorManager;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Component;
+import org.tio.core.ChannelContext;
+
+import java.util.List;
+
+import static com.nb.core.Constants.LOGIN_USER_KEY;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName ImHandler.java
+ * @Description TODO
+ * @createTime 2022年09月15日 08:11:00
+ */
+@Component
+@AllArgsConstructor
+public class ImSubProcessor implements ISubSuccessProcessor {
+    private final ImRoomOperatorManager operatorManager;
+
+    @Override
+    public void postSub(MessagingRequest message, ChannelContext channelContext) {
+        if(WebSocketConstant.IM.equals(message.getId())){
+            //即时通信订阅
+            Object obj = channelContext.get(LOGIN_USER_KEY);
+            if(obj!=null&&obj instanceof LoginUser){
+                LoginUser loginUser= (LoginUser) obj;
+                String loginType = loginUser.getLoginType();
+                if(StpTypeEnum.APP_DOCTOR.getText().equals(loginType)){
+                    List<String> params = message.getParams();
+                    params.stream().map(operatorManager::getRoomOperator)
+                            .forEach(imRoomOperator -> imRoomOperator.setDoctorOnline(true));
+                }
+            }
+        }
+    }
+}

+ 1 - 0
nb-im/src/main/java/com/nb/im/ws/ImSubscribe.java

@@ -2,6 +2,7 @@ package com.nb.im.ws;
 
 import com.nb.common.websocket.WebSocketConstant;
 import com.nb.common.websocket.handler.Subscribe;
+import com.nb.common.websocket.msg.MessagingRequest;
 import org.springframework.stereotype.Component;
 import org.tio.core.ChannelContext;
 

+ 45 - 0
nb-im/src/main/java/com/nb/im/ws/ImUnSubProcessor.java

@@ -0,0 +1,45 @@
+package com.nb.im.ws;
+
+import com.nb.auth.bean.LoginUser;
+import com.nb.auth.enums.StpTypeEnum;
+import com.nb.common.websocket.WebSocketConstant;
+import com.nb.common.websocket.msg.MessagingRequest;
+import com.nb.common.websocket.msg.handler.IUnSubSuccessProcessor;
+import com.nb.im.room.ImRoomOperatorManager;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Component;
+import org.tio.core.ChannelContext;
+
+import java.util.List;
+
+import static com.nb.core.Constants.LOGIN_USER_KEY;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName ImUnSubProcessor.java
+ * @Description 取消订阅后
+ * @createTime 2022年09月15日 08:11:00
+ */
+@Component
+@AllArgsConstructor
+public class ImUnSubProcessor implements IUnSubSuccessProcessor {
+    private final ImRoomOperatorManager operatorManager;
+
+    @Override
+    public void postUnSub(MessagingRequest message, ChannelContext channelContext) {
+        if(WebSocketConstant.IM.equals(message.getId())){
+            //即时通信订阅
+            Object obj = channelContext.get(LOGIN_USER_KEY);
+            if(obj!=null&&obj instanceof LoginUser){
+                LoginUser loginUser= (LoginUser) obj;
+                String loginType = loginUser.getLoginType();
+                if(StpTypeEnum.APP_DOCTOR.getText().equals(loginType)){
+                    List<String> params = message.getParams();
+                    params.stream().map(operatorManager::getRoomOperator)
+                            .forEach(imRoomOperator -> imRoomOperator.setDoctorOnline(false));
+                }
+            }
+        }
+    }
+}

+ 50 - 0
nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/AssistUserController.java

@@ -0,0 +1,50 @@
+package com.nb.app.assistant.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.nb.app.assistant.controller.vo.ResetPswVo;
+import com.nb.app.assistant.service.LocalAssistantUserService;
+import com.nb.app.assistant.utils.ResetPswUtil;
+import com.nb.core.exception.CustomException;
+import com.nb.core.result.R;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName UserController.java
+ * @Description TODO
+ * @createTime 2022年09月14日 15:16:00
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/assist/phone")
+@Api(tags = "忘记密码")
+@Slf4j
+public class AssistUserController {
+    private final LocalAssistantUserService userService;
+    private final ResetPswUtil resetPswUtil;
+
+
+
+    @PostMapping("/psw/reset")
+    @ApiOperation(value = "重置密码",notes = "请先调用【验证码】相关接口/api/assist/captcha/reset/validate进行密码校验并获取token")
+    public R<Boolean> reset(@RequestBody@Validated ResetPswVo resource){
+        String token = resetPswUtil.getToken(resource.getPhone(), resource.getCaptcha());
+        if (StrUtil.isEmpty(token)) {
+            throw new CustomException("该请求已失效,请刷新后重试");
+        }
+        if(ObjectUtil.equal(token,resource.getResetToken())){
+            throw new CustomException("token错误,请刷新后重试");
+        }
+        return R.success(userService.resetPsw(resource.getPhone(),resource.getNewPsw()));
+    }
+}

+ 12 - 0
nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/CaptchaController.java

@@ -1,7 +1,11 @@
 package com.nb.app.assistant.controller;
 
 import com.nb.app.assistant.controller.vo.CaptureVo;
+import com.nb.app.assistant.controller.vo.ResetCaptchaVo;
+import com.nb.app.assistant.controller.vo.ResetPswVo;
+import com.nb.app.assistant.enums.CaptchaEnum;
 import com.nb.app.assistant.utils.CaptchaUtil;
+import com.nb.app.assistant.utils.ResetPswUtil;
 import com.nb.core.result.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -26,9 +30,17 @@ import org.springframework.web.bind.annotation.RestController;
 public class CaptchaController {
     private final CaptchaUtil captchaUtil;
 
+    private final ResetPswUtil resetPswUtil;
     @PostMapping("/create")
     @ApiOperation("获取短信验证码")
     public R<String> capture(@RequestBody @Validated CaptureVo vo){
         return R.success(captchaUtil.getCode(vo.getType(),vo.getPhone()));
     }
+
+    @PostMapping("/reset/validate")
+    @ApiOperation(value = "验证码校验",notes = "校验验证码并获取校验token,过期时间24h")
+    public R<String> validateCaptcha(@RequestBody@Validated ResetCaptchaVo resource){
+        captchaUtil.verifyCode(CaptchaEnum.FORGET_PSW,resource.getPhone(),resource.getCaptcha());
+        return R.success(resetPswUtil.createToken(resource.getPhone(),resource.getCaptcha()));
+    }
 }

+ 1 - 1
nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/PatientOperationController.java

@@ -84,7 +84,7 @@ public class PatientOperationController {
      */
     @PostMapping("/save")
     @ApiOperation(value = "发起添加看护人申请")
-    public R<Boolean> saveMonitor(@RequestBody@Validated MonitorAddVo vo){
+    public R<Boolean> saveMonitor(@RequestBody MonitorAddVo vo){
         if(ApplyEnum.INVITE_CODE.equals(vo.getApplyType())&& StrUtil.isEmpty(vo.getInviteCode())){
             throw new CustomException("邀请码不能为空");
         }

+ 0 - 5
nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/base/AppAssistantBaseCrudController.java

@@ -21,9 +21,4 @@ public abstract class AppAssistantBaseCrudController<E, K extends Serializable>
     public boolean isAuth() {
         return false;
     }
-
-    @Override
-    public StpLogic getStpLogin() {
-        return SaManager.getStpLogic(StpTypeEnum.ASSISTANT.getText());
-    }
 }

+ 27 - 0
nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/vo/ResetCaptchaVo.java

@@ -0,0 +1,27 @@
+package com.nb.app.assistant.controller.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName ResetPwsVo.java
+ * @Description TODO
+ * @createTime 2022年09月14日 15:27:00
+ */
+@Data
+@ApiModel("忘记密码验证码校验")
+public class ResetCaptchaVo {
+
+    @ApiModelProperty("手机号")
+    @NotNull(message = "手机号不能为空")
+    private String phone;
+
+    @ApiModelProperty("验证码")
+    @NotNull(message = "验证码不能为空")
+    private String captcha;
+}

+ 34 - 0
nb-service/app-assistant/src/main/java/com/nb/app/assistant/controller/vo/ResetPswVo.java

@@ -0,0 +1,34 @@
+package com.nb.app.assistant.controller.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName ResetPwsVo.java
+ * @Description TODO
+ * @createTime 2022年09月14日 15:27:00
+ */
+@Data
+@ApiModel("忘记密码验证码")
+public class ResetPswVo {
+    @ApiModelProperty("重置密码token,由校验验证码接口获取")
+    @NotNull(message = "resetToken不能为空")
+    private String resetToken;
+
+    @ApiModelProperty("验证码")
+    @NotNull(message = "验证码不能为空")
+    private String captcha;
+
+    @ApiModelProperty("手机号")
+    @NotNull(message = "手机号不能为空")
+    private String phone;
+
+    @ApiModelProperty("新密码")
+    @NotNull(message = "新密码不能为空")
+    private String newPsw;
+}

+ 2 - 1
nb-service/app-assistant/src/main/java/com/nb/app/assistant/enums/CaptchaEnum.java

@@ -16,7 +16,8 @@ import lombok.Getter;
 @AllArgsConstructor
 @JsonFormat(shape = JsonFormat.Shape.OBJECT)
 public enum  CaptchaEnum  implements IEnum<Integer> {
-    PHONE_LOGIN(0,"短信登录")
+    PHONE_LOGIN(0,"短信登录"),
+    FORGET_PSW(1,"忘记密码")
     ;
     /**
      * 与枚举ordinal保持一致

+ 6 - 1
nb-service/app-assistant/src/main/java/com/nb/app/assistant/service/LocalAssistantUserBindService.java

@@ -29,7 +29,6 @@ import com.nb.common.queue.delay.message.DelayMessageProperties;
 import com.nb.core.Value;
 import com.nb.core.exception.CustomException;
 import com.nb.web.api.feign.IPatientClient;
-import org.redisson.RedissonDelayedQueue;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
@@ -88,6 +87,12 @@ public class LocalAssistantUserBindService extends BaseService<AssistantUserBind
         entity.setStatus(BindEnum.WAITING);
         entity.setAssistId(currentUser.getId());
         entity.setAssistNickname(currentUser.getNickname());
+        AssistantUserBindEntity defaultBind = this.getOne(new QueryWrapper<AssistantUserBindEntity>().lambda()
+                .eq(AssistantUserBindEntity::getAssistId, entity.getAssistId())
+                .in(AssistantUserBindEntity::getStatus, BindEnum.WAITING, BindEnum.SUCCESS)
+                .eq(AssistantUserBindEntity::getDefault_,true)
+                .last("limit 1"));
+        entity.setDefault_(defaultBind==null);
         boolean result = this.baseMapper.insert(entity) == 1;
 
         if(result){

+ 10 - 0
nb-service/app-assistant/src/main/java/com/nb/app/assistant/service/LocalAssistantUserService.java

@@ -2,6 +2,7 @@ package com.nb.app.assistant.service;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.extra.spring.SpringUtil;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.nb.app.assistant.api.feign.IAssistantUserClient;
 import com.nb.app.assistant.api.feign.result.AssistantUserResult;
 import com.nb.app.assistant.entity.AssistantUserEntity;
@@ -9,6 +10,7 @@ import com.nb.app.assistant.mapper.AssistantUserMapper;
 import com.nb.app.msg.bean.MsgBean;
 import com.nb.app.msg.enums.MsgEnum;
 import com.nb.app.msg.event.SaveMsgEvent;
+import com.nb.auth.utils.SecurityUtil;
 import com.nb.common.crud.BaseService;
 import org.springframework.stereotype.Component;
 
@@ -47,4 +49,12 @@ public class LocalAssistantUserService extends BaseService<AssistantUserMapper,
     public AssistantUserResult getById(String id) {
         return BeanUtil.copyProperties(super.getById(id),AssistantUserResult.class);
     }
+
+    public Boolean resetPsw(String phone, String newPsw) {
+        String encryptPassword = SecurityUtil.encryptPassword(newPsw);
+        return this
+                .update(new UpdateWrapper<AssistantUserEntity>()
+                        .lambda().eq(AssistantUserEntity::getPhone,phone)
+                        .set(AssistantUserEntity::getPassword,encryptPassword));
+    }
 }

+ 2 - 1
nb-service/app-assistant/src/main/java/com/nb/app/assistant/utils/CaptchaUtil.java

@@ -37,13 +37,14 @@ public class CaptchaUtil {
 
     public boolean verifyCode(CaptchaEnum type,String codeKey,String code){
         String key = getKey(type.name(),codeKey);
-        String result = codeCache.getWithTTLOnly(key);
+        String result = codeCache.remove(key);
         if (StrUtil.isNullOrUndefined(result)) {
             throw new CustomException("验证码已失效");
         }
         if(!result.equals(code)){
             throw new CustomException("验证码错误");
         }
+
         return true;
     }
 

+ 46 - 0
nb-service/app-assistant/src/main/java/com/nb/app/assistant/utils/ResetPswUtil.java

@@ -0,0 +1,46 @@
+package com.nb.app.assistant.utils;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.nb.core.cache.ConfigStorage;
+import com.nb.core.cache.manager.ConfigStorageManager;
+import org.redisson.api.RMapCache;
+import org.redisson.api.RedissonClient;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName ResetPswUtil.java
+ * @Description TODO
+ * @createTime 2022年09月14日 15:37:00
+ */
+@Configuration
+public class ResetPswUtil {
+    private final RMapCache<String, String> tokenCache;
+
+    public ResetPswUtil(RedissonClient redissonClient) {
+        tokenCache = redissonClient.getMapCache("assist:phone:reset");
+    }
+
+    public String createToken(String phone,String code){
+        String token = getToken(phone, code);
+        if(StrUtil.isEmpty(token)){
+            token=IdWorker.get32UUID();
+            tokenCache.put(getKey(phone, code), IdWorker.getIdStr(), 24, TimeUnit.HOURS);
+        }
+        return token;
+    }
+
+    public String getToken(String phone,String code){
+        return tokenCache.remove(getKey(phone, code));
+    }
+
+
+    private String getKey(String phone,String code){
+        return phone+"-"+code;
+    }
+}

+ 0 - 4
nb-service/app-doctor/src/main/java/com/nb/app/doctor/controller/base/AppDoctorBaseCrudController.java

@@ -21,8 +21,4 @@ public abstract class AppDoctorBaseCrudController<E, K extends Serializable> ext
         return true;
     }
 
-    @Override
-    public StpLogic getStpLogin() {
-        return SaManager.getStpLogic(StpTypeEnum.APP_DOCTOR.getText());
-    }
 }

+ 2 - 2
nb-service/app-doctor/src/main/java/com/nb/app/doctor/controller/vo/MonitorEvalVo.java

@@ -25,10 +25,10 @@ public class MonitorEvalVo {
     private String evaluator;
 
     @ApiModelProperty("疼痛部位-正面 具体传值内容即key:value值由传参人决定,传入值=获取值")
-    private Map<String,Object> painFront;
+    private List<String>  painFront;
 
     @ApiModelProperty("疼痛部位-反面 具体传值内容即key:value值由传参人决定,传入值=获取值")
-    private Map<String,Object> painBack;
+    private List<String>  painBack;
 
     @ApiModelProperty("疼痛性质")
     private List<String> painNature;

+ 40 - 6
nb-service/app-doctor/src/main/java/com/nb/app/doctor/service/LocalAppDoctorUserService.java

@@ -13,8 +13,11 @@ import com.nb.app.doctor.api.feign.result.AppDoctorUserResult;
 import com.nb.app.doctor.entity.AppUserConsultConfigEntity;
 import com.nb.app.doctor.mapper.AppDoctorUserMapper;
 import com.nb.app.msg.enums.MsgEnum;
+import com.nb.auth.bean.LoginUser;
+import com.nb.auth.enums.StpTypeEnum;
 import com.nb.auth.utils.SecurityUtil;
 import com.nb.common.crud.BaseService;
+import com.nb.common.websocket.event.DisConnectedEvent;
 import com.nb.core.enums.StatusEnum;
 import com.nb.core.exception.CustomException;
 import com.nb.im.entity.ImMsgEntity;
@@ -23,6 +26,7 @@ import com.nb.im.enums.ImMsgType;
 import com.nb.im.enums.ImStatusEnum;
 import com.nb.im.enums.SponsorEnum;
 import com.nb.im.event.ImMsgEvent;
+import com.nb.im.room.ImRoomOperatorManager;
 import com.nb.im.service.LocalImRoomService;
 import com.nb.im.utils.ImUtils;
 import com.nb.im.ws.PubMsgInfo;
@@ -31,11 +35,12 @@ import org.springframework.context.annotation.Lazy;
 import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
+import org.tio.core.ChannelContext;
 
 import java.io.Serializable;
 import java.util.*;
 import java.util.stream.Collectors;
-
+import static com.nb.core.Constants.LOGIN_USER_KEY;
 /**
  * @author lifang
  * @version 1.0.0
@@ -54,6 +59,10 @@ public class LocalAppDoctorUserService extends BaseService<AppDoctorUserMapper,
     @Lazy
     private LocalImRoomService roomService;
 
+    @Autowired
+    @Lazy
+    private ImRoomOperatorManager roomOperatorManager ;
+
     @Autowired
     @Lazy
     private ImUtils imUtils;
@@ -186,7 +195,27 @@ public class LocalAppDoctorUserService extends BaseService<AppDoctorUserMapper,
         return user==null?null:BeanUtil.copyProperties(this.getById(id),AppDoctorUserResult.class);
     }
 
+    @EventListener
+    public void disConnect(DisConnectedEvent event){
+        ChannelContext channelContext = event.getChannelContext();
+        Object obj = channelContext.get(LOGIN_USER_KEY);
+        //即时通信订阅
+        if(obj!=null&&obj instanceof LoginUser){
+            LoginUser loginUser= (LoginUser) obj;
+            String loginType = loginUser.getLoginType();
+            if(StpTypeEnum.APP_DOCTOR.getText().equals(loginType)){
+                List<ImRoomEntity> rooms = roomService.list(new QueryWrapper<ImRoomEntity>()
+                        .lambda()
+                        .eq(ImRoomEntity::getDoctorId, loginUser.getId())
+                        .eq(ImRoomEntity::getStatus, ImStatusEnum.SUCCESS));
+                rooms.stream()
+                        .map(ImRoomEntity::getId)
+                        .map(roomOperatorManager::getRoomOperator)
+                        .forEach(imRoomOperator -> imRoomOperator.setDoctorOnline(false));
+            }
+        }
 
+    }
 
 
     @EventListener
@@ -225,18 +254,23 @@ public class LocalAppDoctorUserService extends BaseService<AppDoctorUserMapper,
                 }
             }
         }
-        if(!disturb&&MsgEnum.CONSUL.equals(entity.getOperationType())){
+//        if(!disturb&&MsgEnum.CONSUL.equals(entity.getOperationType())){
+        if(!disturb&&!roomOperatorManager.getRoomOperator(imRoomId).isOnlineDoctor()){
+            //医生不位于聊天室内
             payload=StrUtil.isNotBlank(consultConfig.getConsultReply())?consultConfig.getConsultReply():"您好,我已经收到您的咨询,请稍等";
         }
+//        }
+        AppDoctorUserEntity doctorUser = this.getById(room.getDoctorId());
         if(StrUtil.isNotEmpty(payload)){
             PubMsgInfo pubMsgInfo = PubMsgInfo
                     .builder()
                     .roomId(entity.getRoomId())
                     .payload(payload)
-                    .senderType(entity.getSponsor())
-                    .senderId(entity.getSenderId())
-                    .senderNickname(entity.getSenderNickname())
-                    .senderAvatar(entity.getSenderAvatar())
+                    .senderType(SponsorEnum.doctor)
+                    .senderId(doctorUser.getId())
+                    .senderNickname(doctorUser.getRealName())
+                    .sendTimestamp(System.currentTimeMillis())
+                    .senderAvatar(doctorUser.getAvatar())
                     .msgType(ImMsgType.txt)
                     .operationType(MsgEnum.NORMAL)
                     .build();

+ 0 - 5
nb-service/app-msg/src/main/java/com/nb/app/msg/controller/AppConsultController.java

@@ -44,9 +44,4 @@ public class AppConsultController implements BaseSaveController<AppConsultEntity
     public String getPermissionPrefix() {
         return null;
     }
-
-    @Override
-    public StpLogic getStpLogin() {
-        return SecurityUtil.getStpLogic();
-    }
 }

+ 0 - 4
nb-service/app-msg/src/main/java/com/nb/app/msg/controller/AppMsgController.java

@@ -43,8 +43,4 @@ public class AppMsgController implements BaseSaveController<AppMsgEntity,String>
         return null;
     }
 
-    @Override
-    public StpLogic getStpLogin() {
-        return SecurityUtil.getStpLogic();
-    }
 }

+ 1 - 5
nb-service/web-service/src/main/java/com/nb/web/service/bus/controller/BusDeviceController.java

@@ -9,6 +9,7 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.mapper.Mapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.nb.auth.utils.SecurityUtil;
 import com.nb.web.service.bus.controller.vo.DeviceBindVo;
 import com.nb.web.api.entity.BusDeviceEntity;
 import com.nb.web.api.enums.DeviceAlarmEnum;
@@ -86,11 +87,6 @@ public class BusDeviceController implements
         return "device:info";
     }
 
-    @Override
-    public StpLogic getStpLogin() {
-        return SaManager.getStpLogic("");
-    }
-
 
     @Override
     public BaseService<? extends Mapper<BusDeviceEntity>, BusDeviceEntity, String> getService() {

+ 0 - 5
nb-service/web-service/src/main/java/com/nb/web/service/bus/controller/BusInfusionHistoryController.java

@@ -94,9 +94,4 @@ public class BusInfusionHistoryController implements BaseQueryController<BusInfu
     public String getPermissionPrefix() {
         return "bus:infusion";
     }
-
-    @Override
-    public StpLogic getStpLogin() {
-        return SaManager.getStpLogic("");
-    }
 }

+ 0 - 4
nb-service/web-service/src/main/java/com/nb/web/service/bus/controller/BusPatientController.java

@@ -374,8 +374,4 @@ public class BusPatientController  implements BaseQueryController<BusPatientEnti
         return "bus:patient:";
     }
 
-    @Override
-    public StpLogic getStpLogin() {
-        return SaManager.getStpLogic("");
-    }
 }

+ 4 - 0
nb-service/web-service/src/main/java/com/nb/web/service/bus/entity/BusHospitalEntity.java

@@ -2,6 +2,8 @@ package com.nb.web.service.bus.entity;
 
 import com.baomidou.mybatisplus.annotation.*;
 import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
+import com.nb.core.annotation.Phone;
+import com.nb.core.entity.GenericEntity;
 import com.nb.web.api.bean.GeoPoint;
 import com.nb.web.api.bean.Script;
 import com.nb.web.service.bus.hospital.his.strategy.HisStrategyEnum;
@@ -13,6 +15,7 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import org.hibernate.validator.constraints.Length;
 
+import javax.validation.constraints.Email;
 import java.util.Date;
 
 /**
@@ -54,6 +57,7 @@ public class BusHospitalEntity implements RecordModifierEntity, RecordCreationEn
      * 联系电话
      */
     @ApiModelProperty(value = "联系电话")
+    @Phone(groups ={GenericEntity.Insert.class, GenericEntity.Update.class})
     @Length(max = 255,message = "联系电话长度不得超过255个字节")
     private String telephone;
 

+ 10 - 2
nb-service/web-service/src/main/java/com/nb/web/service/bus/websocket/topic/WebSocketCloseHandler.java

@@ -1,14 +1,22 @@
 package com.nb.web.service.bus.websocket.topic;
 
 import cn.hutool.core.util.ObjectUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.nb.common.websocket.DefaultMessageListener;
+import com.nb.common.websocket.handler.TopicWrapper;
+import com.nb.common.websocket.msg.MessagingRequest;
+import com.nb.common.websocket.msg.handler.IMsgRequestHandler;
 import com.nb.web.service.bus.hospital.his.HisScriptSessionManager;
 import com.nb.core.Constants;
 import com.nb.common.websocket.handler.Subscribe;
+import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.tio.core.ChannelContext;
 
+import java.util.Map;
+
 /**
  * @author lifang
  * @version 1.0.0
@@ -18,9 +26,9 @@ import org.tio.core.ChannelContext;
  */
 @Component
 @Slf4j
+@AllArgsConstructor
 public class WebSocketCloseHandler extends Subscribe {
-    @Autowired
-    private HisScriptSessionManager scriptSessionManager;
+    private final HisScriptSessionManager scriptSessionManager;
     @Override
     public String getId() {
         return "";

+ 0 - 6
nb-service/web-service/src/main/java/com/nb/web/service/log/controller/SysRunningLogController.java

@@ -37,10 +37,4 @@ public class SysRunningLogController implements BaseQueryController<SysRunningLo
     public String getPermissionPrefix() {
         return "sys:rlog:";
     }
-
-    @Override
-    public StpLogic getStpLogin() {
-        return SecurityUtil.getStpLogic();
-    }
-
 }

+ 7 - 3
nb-service/web-service/src/main/java/com/nb/web/service/system/auth/WebAuthGranter.java

@@ -1,6 +1,7 @@
 package com.nb.web.service.system.auth;
 
 import cn.dev33.satoken.spring.SpringMVCUtil;
+import cn.dev33.satoken.stp.StpLogic;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@@ -32,6 +33,8 @@ import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import static com.nb.auth.utils.SecurityUtil.LOGIN_USER_KEY;
+
 /**
  * @author lifang
  * @version 1.0.0
@@ -71,7 +74,7 @@ public class WebAuthGranter implements IAuthGranter {
             String requestFrom = request.getHeader("RequestFrom");
             //来自app的请求不需要验证码
             if(!"TuoRenApp".equals(requestFrom)){
-                captchaTool.ver(source.getCodeKey(),source.getCode());
+//                captchaTool.ver(source.getCodeKey(),source.getCode());
             }
         }
         sysUser = sysUserService.getOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getAccount, source.getUsername())
@@ -98,7 +101,8 @@ public class WebAuthGranter implements IAuthGranter {
         Set<String> permissions  = sysMenuService.getPermissionsByUserId(sysUser.getId());
 
         // 登录
-        SecurityUtil.getStpLogic().login(sysUser.getId());
+        StpLogic stpLogic = SecurityUtil.getStpLogic(StpTypeEnum.DEFAULT.getText());
+        stpLogic.login(sysUser.getId());
         LoginUser<Long> loginUser = new LoginUser();
         loginUser.setToken(SecurityUtil.getStpLogic().getTokenValue());
         loginUser.setUserPlatform(UserPlatformEnum.WEB.getCode());
@@ -113,7 +117,7 @@ public class WebAuthGranter implements IAuthGranter {
         loginUser.setLoginType(StpTypeEnum.DEFAULT.getText());
         fillUserAgentInfo(loginUser);
         // 设置用户信息
-        SecurityUtil.setLogin(loginUser);
+        stpLogic.getTokenSession().set(LOGIN_USER_KEY,loginUser);
         return loginUser;
     }
 

+ 7 - 12
nb-service/web-service/src/main/java/com/nb/web/service/system/controller/SysApplyController.java

@@ -12,6 +12,7 @@ import com.nb.web.service.system.entity.SysApply;
 import com.nb.web.service.system.service.impl.LocalSysApplyService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.Authorization;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.validation.annotation.Validated;
@@ -28,7 +29,7 @@ import org.springframework.web.bind.annotation.*;
 @AllArgsConstructor
 @RequestMapping("/sys/apply")
 @Slf4j
-@Api(tags = "第三方应用app接入管理",description = "第三方应用app接入管理 ,权限前缀【sys:apply:】,如查询【sys:apply:query】")
+@Api(tags = "第三方应用app接入管理",description = "第三方应用app接入管理 ,权限前缀【system:open:】,如查询【system:open:query】")
 public class SysApplyController extends BaseCrudController<SysApply,String> {
     private final LocalSysApplyService sysApplyService;
     @Override
@@ -41,8 +42,8 @@ public class SysApplyController extends BaseCrudController<SysApply,String> {
      * 分配菜单
      */
     @PostMapping("/assignMenu")
-    @SaCheckPermission("sys:apply:assignMenu")
-    @ApiOperation("分配菜单,权限【sys:apply:assignMenu】")
+    @SaCheckPermission("system:open:permission")
+    @ApiOperation("分配菜单,权限【system:open:permission】")
     public R assignMenu(@Validated @RequestBody SysApplyAssignMenuDTO req) {
         sysApplyService.assignMenu(req);
         return R.success();
@@ -52,20 +53,14 @@ public class SysApplyController extends BaseCrudController<SysApply,String> {
      * 查询角色关联的菜单
      */
     @GetMapping("/listApplyMenus")
-    @SaCheckPermission("sys:apply:query")
-    @ApiOperation("查询应用所关联菜单,权限【sys:apply:query】")
+//    @SaCheckPermission("sys:apply:query")
+    @ApiOperation(value = "查询应用所关联菜单",authorizations = {@Authorization("无")})
     public R listRoleMenus(@RequestParam String appKey) {
         return R.success(sysApplyService.listApplyMenus(appKey));
     }
 
     @Override
     public String getPermissionPrefix() {
-        return "sys:apply:";
+        return "system:open:";
     }
-
-    @Override
-    public StpLogic getStpLogin() {
-        return SaManager.getStpLogic("");
-    }
-
 }

+ 1 - 1
nb-service/web-service/src/main/java/com/nb/web/service/system/controller/SysUserController.java

@@ -80,7 +80,7 @@ public class SysUserController {
      * 查看
      */
     @GetMapping("/view")
-    @SaCheckPermission("system:sysUser:view")
+    @SaCheckPermission("system:sysUser:page")
     @Log(title = "用户管理查看")
     public R view(@RequestParam String id) {
         return R.success(sysUserService.view(id));

+ 1 - 1
pom.xml

@@ -33,7 +33,7 @@
         <okhttp.version>4.9.3</okhttp.version>
         <velocity.version>2.3</velocity.version>
         <log4j2.version>2.17.1</log4j2.version>
-        <satoken.version>1.29.0</satoken.version>
+        <satoken.version>1.31.0</satoken.version>
         <springfox.version>3.0.0</springfox.version>
         <tio.version>3.6.0.v20200315-RELEASE</tio.version>
         <jython.version>2.7.1</jython.version>