...
 
Commits (73)
[V1.2.0] 2022.11.14
数据库:
1.新增hpgp_ks_hot表
2.hpgp_department_rank表新增rank_score = 0的全部医院数据
功能:
1.从公众号进入时,在李处理的一年内历史就诊记录的表中查询“公众号医院”的三个历史科室展示;
2.从“hpgp_ks_hot”表中查询展示“公众号医院”的科室(热门科室由医院提供,目前暂时用门诊量最大的三个科室代替)为了区分全区和公众号,新增了“gzh”字段;全区的“gzh”字段为“ALL”,公众号的“gzh”字段为“公众号医院编码”
3.在科室排名表(hpgp_department_rank_1028)中新增了全部医院/科室信息,其rank_score标为“0”,与全区排名科室做区分;按照standard_dept(=选择/机器人推荐的科室)、hospital_code(=公众号医院)、rank_score(=0)查询科室,选择有号的进行展示(一个医院中有多个同名科室,如果有号的超过3个那也只展示3个)
\ No newline at end of file
# hphy
# hpgp
黄浦高血压精准导医
\ No newline at end of file
黄浦全科导医
package cn.sh.stc.sict.cloud.auth;
import cn.sh.stc.sict.cloud.common.security.annotation.EnableSictFeignClients;
import cn.sh.stc.sict.cloud.common.swagger.annotation.EnableSictSwagger2;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
/**
* @author F_xh
*/
@EnableSictSwagger2
@SpringCloudApplication
@EnableSictFeignClients
public class SictAuthApplication {
......
......@@ -50,10 +50,13 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
.and()
.authorizeRequests()
.antMatchers(
"/token/**",
"/token/**",
"/v2/api-docs",
"/webjars/**",
"/swagger-resources/**",
"/test/**",
"/actuator/**",
"/mobile/**").permitAll()
"/actuator/**",
"/mobile/**").permitAll()
.anyRequest().authenticated()
.and().csrf().disable()
.apply(mobileSecurityConfigurer());
......
package cn.sh.stc.sict.cloud.auth.endpoint;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.PaginationConstants;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.core.util.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.sh.stc.sict.cloud.common.security.annotation.Inner;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import cn.sh.stc.sict.cloud.common.security.util.SysLogUtils;
import cn.sh.stc.sict.cloud.upms.feign.RemoteLogService;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.ConvertingCursor;
import org.springframework.data.redis.core.Cursor;
......@@ -26,6 +31,7 @@ import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
......@@ -35,117 +41,148 @@ import java.util.Map;
* @Author
* @Date
*/
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/token")
public class SictTokenEndpoint {
private static final String SICT_OAUTH_ACCESS = SecurityConstants.SICT_PREFIX + SecurityConstants.OAUTH_PREFIX + "auth_to_access:";
private static final String SICT_ACCESS = SecurityConstants.SICT_PREFIX + SecurityConstants.OAUTH_PREFIX + "access:";
private final TokenStore tokenStore;
private final RedisTemplate redisTemplate;
private final CacheManager cacheManager;
/**
* 认证页面
*
* @return ModelAndView
*/
@GetMapping("/login")
public ModelAndView require() {
return new ModelAndView("ftl/login");
}
/**
* 退出token
*
* @param authHeader Authorization
*/
@DeleteMapping("/logout")
public R logout(@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authHeader) {
if (StrUtil.isBlank(authHeader)) {
return R.builder()
.code(Constant.BYTE_NO)
.data(Boolean.FALSE)
.msg("退出失败,token 为空").build();
}
String tokenValue = authHeader.replaceAll("(?i)Bearer", "").trim();
OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) {
return R.builder()
.code(Constant.BYTE_NO)
.data(Boolean.FALSE)
.msg("退出失败,token 无效").build();
}
OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken);
SictUser user = (SictUser) cacheManager.getCache(RedisCacheConstant.USER_DETAILS).get(auth2Authentication.getName()).get();
cacheManager.getCache(RedisCacheConstant.USER_DETAILS)
.evict(auth2Authentication.getName());
tokenStore.removeAccessToken(accessToken);
return new R<>(Boolean.TRUE);
}
/**
* 令牌管理调用
*
* @param token token
* @return
*/
@Inner
@DeleteMapping("/{token}")
public R<Boolean> delToken(@PathVariable("token") String token) {
OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
tokenStore.removeAccessToken(oAuth2AccessToken);
return new R<>();
}
/**
* 查询token
*
* @param params 分页参数
* @return
*/
@Inner
@PostMapping("/page")
public R<Page> tokenList(@RequestBody Map<String, Object> params) {
//根据分页参数获取对应数据
String key = String.format("%s", SICT_OAUTH_ACCESS);
List<String> pages = findKeysForPage(key, MapUtil.getInt(params, PaginationConstants.CURRENT)
, MapUtil.getInt(params, PaginationConstants.SIZE));
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
Page result = new Page(MapUtil.getInt(params, PaginationConstants.CURRENT), MapUtil.getInt(params, PaginationConstants.SIZE));
result.setRecords(redisTemplate.opsForValue().multiGet(pages));
result.setTotal(Long.valueOf(redisTemplate.keys(key).size()));
return new R<>(result);
}
private List<String> findKeysForPage(String patternKey, int pageNum, int pageSize) {
ScanOptions options = ScanOptions.scanOptions().match(patternKey).build();
RedisSerializer<String> redisSerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redisConnection -> new ConvertingCursor<>(redisConnection.scan(options), redisSerializer::deserialize));
List<String> result = new ArrayList<>();
int tmpIndex = 0;
int startIndex = (pageNum - 1) * pageSize;
int end = pageNum * pageSize;
assert cursor != null;
while (cursor.hasNext()) {
if (tmpIndex >= startIndex && tmpIndex < end) {
result.add(cursor.next().toString());
tmpIndex++;
continue;
}
if (tmpIndex >= end) {
break;
}
tmpIndex++;
cursor.next();
}
return result;
}
private static final String SICT_OAUTH_ACCESS = SecurityConstants.SICT_PREFIX + SecurityConstants.OAUTH_PREFIX + "auth_to_access:";
private static final String SICT_ACCESS = SecurityConstants.SICT_PREFIX + SecurityConstants.OAUTH_PREFIX + "access:";
private final TokenStore tokenStore;
private final RedisTemplate redisTemplate;
private final CacheManager cacheManager;
private final RemoteLogService remoteLogService;
/**
* 认证页面
*
* @return ModelAndView
*/
@GetMapping("/login")
public ModelAndView require() {
return new ModelAndView("ftl/login");
}
/**
* 退出token
*
* @param authHeader Authorization
*/
@DeleteMapping("/logout")
public R logout(HttpServletRequest request,
@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authHeader) {
if (StrUtil.isBlank(authHeader)) {
return R.builder()
.code(Constant.BYTE_NO)
.data(Boolean.FALSE)
.msg("退出失败,token 为空").build();
}
String tokenValue = authHeader.replaceAll("(?i)Bearer", "").trim();
OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) {
return new R();
}
OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken);
String username = auth2Authentication.getName();
SictUser user = (SictUser) cacheManager.getCache(RedisCacheConstant.USER_DETAILS).get(username).get();
cacheManager.getCache(RedisCacheConstant.USER_DETAILS)
.evict(username);
tokenStore.removeAccessToken(accessToken);
SysLog sysLog = SysLogUtils.getSysLog(request, username);
sysLog.setTitle(username + "-用户登出");
sysLog.setParams(user.getName());
sysLog.setServiceId(auth2Authentication.getOAuth2Request().getClientId());
// 保存退出的token
String token = request.getHeader(HttpHeaders.AUTHORIZATION);
sysLog.setParams(token);
remoteLogService.saveLog(sysLog, SecurityConstants.FROM_IN);
log.info("用户:{} 退出成功, token:{} 已注销", username, token);
return new R<>(Boolean.TRUE);
}
/**
* 令牌管理调用
*
* @param token token
* @return
*/
@Inner
@DeleteMapping("/{token}")
public R<Boolean> delToken(@PathVariable("token") String token) {
OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
tokenStore.removeAccessToken(oAuth2AccessToken);
return new R<>();
}
/**
* 令牌管理调用
*
* @param token token
* @return
*/
@GetMapping("/check/{token}")
public R<Boolean> isValid(@PathVariable("token") String token) {
String tokenValue = token.replaceAll("(?i)Bearer", "").trim();
OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) {
return new R(false);
}
OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken);
return new R<>(auth2Authentication.isAuthenticated());
}
/**
* 查询token
*
* @param params 分页参数
* @return
*/
@Inner
@PostMapping("/page")
public R<Page> tokenList(@RequestBody Map<String, Object> params) {
//根据分页参数获取对应数据
String key = String.format("%s", SICT_OAUTH_ACCESS);
List<String> pages = findKeysForPage(key, MapUtil.getInt(params, PaginationConstants.CURRENT)
, MapUtil.getInt(params, PaginationConstants.SIZE));
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
Page result = new Page(MapUtil.getInt(params, PaginationConstants.CURRENT), MapUtil.getInt(params, PaginationConstants.SIZE));
result.setRecords(redisTemplate.opsForValue().multiGet(pages));
result.setTotal(Long.valueOf(redisTemplate.keys(key).size()));
return new R<>(result);
}
private List<String> findKeysForPage(String patternKey, int pageNum, int pageSize) {
ScanOptions options = ScanOptions.scanOptions().match(patternKey).build();
RedisSerializer<String> redisSerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
Cursor cursor = (Cursor) redisTemplate.executeWithStickyConnection(redisConnection -> new ConvertingCursor<>(redisConnection.scan(options), redisSerializer::deserialize));
List<String> result = new ArrayList<>();
int tmpIndex = 0;
int startIndex = (pageNum - 1) * pageSize;
int end = pageNum * pageSize;
assert cursor != null;
while (cursor.hasNext()) {
if (tmpIndex >= startIndex && tmpIndex < end) {
result.add(cursor.next().toString());
tmpIndex++;
continue;
}
if (tmpIndex >= end) {
break;
}
tmpIndex++;
cursor.next();
}
return result;
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.security.handler.AbstractAuthenticationFailureEvenHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
/**
* @Description
* @Author
* @Date
*/
@Slf4j
@Component
public class SictAuthenticationFailureEvenHandler extends AbstractAuthenticationFailureEvenHandler {
/**
* 处理登录失败方法
* <p>
*
* @param authenticationException 登录的authentication 对象
* @param authentication 登录的authenticationException 对象
*/
@Override
public void handle(AuthenticationException authenticationException, Authentication authentication) {
log.info("用户:{} 登录失败,异常:{}", authentication.getPrincipal(), authenticationException.getLocalizedMessage());
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import cn.sh.stc.sict.cloud.common.security.config.UserAccountProperties;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationFailureHandler;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;
/**
*
* 登录操作次数锁定功能
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationFailureLockEventHandler implements AuthenticationFailureHandler {
private final RedisTemplate<String, String> redisTemplate;
private final UserAccountProperties userAccountProperties;
/**
* 密码错误超过 5 此自动锁定
* <p>
* @param authenticationException 登录的authentication 对象
* @param authentication 登录的authenticationException 对象
* @param request 请求
* @param response 响应
*/
@Async
@Override
@SneakyThrows
public void handle(AuthenticationException authenticationException, Authentication authentication,
HttpServletRequest request, HttpServletResponse response) {
// 只处理账号密码错误异常
if (!(authenticationException instanceof BadCredentialsException) && userAccountProperties.getLimitFlag()) {
return;
}
String username = authentication.getName();
String key = String.format("%s:%s", RedisCacheConstant.LOGIN_ERROR_TIMES, username);
Long times = redisTemplate.opsForValue().increment(key);
// 自动过期时间
redisTemplate.expire(key, userAccountProperties.getLimitTime(), TimeUnit.MINUTES);
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationFailureHandler;
import cn.sh.stc.sict.cloud.common.security.util.SysLogUtils;
import cn.sh.stc.sict.cloud.upms.feign.RemoteLogService;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationFailureLogEventHandler implements AuthenticationFailureHandler {
private final RemoteLogService logService;
/**
* 异步处理,登录失败方法
* <p>
*
* @param authenticationException 登录的authentication 对象
* @param authentication 登录的authenticationException 对象
* @param request 请求
* @param response 响应
*/
@Async
@Override
@SneakyThrows
public void handle(AuthenticationException authenticationException, Authentication authentication,
HttpServletRequest request, HttpServletResponse response) {
String username = authentication.getName();
SysLog sysLog = SysLogUtils.getSysLog(request, username);
sysLog.setTitle(username + "用户登录");
sysLog.setParams(username);
sysLog.setException(authenticationException.getLocalizedMessage());
logService.saveLog(sysLog, SecurityConstants.FROM_IN);
log.info("用户:{} 登录失败,异常:{}", username, authenticationException.getLocalizedMessage());
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationLogoutHandler;
import cn.sh.stc.sict.cloud.common.security.util.SysLogUtils;
import cn.sh.stc.sict.cloud.upms.feign.RemoteLogService;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 退出事件处理
*
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationLogoutEventHandler implements AuthenticationLogoutHandler {
private final RemoteLogService logService;
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
* @param authentication 登录对象
* @param request 请求
* @param response 返回
*/
@Async
@Override
public void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
String username = authentication.getName();
SysLog sysLog = SysLogUtils.getSysLog(request, username);
sysLog.setTitle(username + "用户登出");
sysLog.setParams(username);
// 获取clientId 信息
OAuth2Authentication auth2Authentication = (OAuth2Authentication) authentication;
sysLog.setServiceId(auth2Authentication.getOAuth2Request().getClientId());
// 保存退出的token
String token = request.getHeader(HttpHeaders.AUTHORIZATION);
sysLog.setParams(token);
logService.saveLog(sysLog, SecurityConstants.FROM_IN);
log.info("用户:{} 退出成功, token:{} 已注销", username, token);
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.security.handler.AbstractAuthenticationSuccessEventHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
/**
* @Description
* @Author
* @Date
*/
@Slf4j
@Component
public class SictAuthenticationSuccessEventHandler extends AbstractAuthenticationSuccessEventHandler {
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
*
* @param authentication 登录对象
*/
@Override
public void handle(Authentication authentication) {
log.info("用户:{} 登录成功", authentication.getPrincipal());
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationSuccessHandler;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录操作次数锁定清楚功能
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationSuccessLockEventHandler implements AuthenticationSuccessHandler {
private final RedisTemplate<String, String> redisTemplate;
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
* @param authentication 登录对象
* @param request 请求
* @param response 返回
*/
@Async
@Override
public void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
// String username = authentication.getName();
// String key = String.format("%s:%s:%s", CacheConstants.LOGIN_ERROR_TIMES, tenantKeyStrResolver.key(), username);
// redisTemplate.delete(key);
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationSuccessHandler;
import cn.sh.stc.sict.cloud.common.security.util.SysLogUtils;
import cn.sh.stc.sict.cloud.upms.feign.RemoteLogService;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录成功日志记录
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationSuccessLogEventHandler implements AuthenticationSuccessHandler {
private final RemoteLogService remoteLogService;
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
*
* @param authentication 登录对象
* @param request 请求
* @param response 返回
*/
@Async
@Override
public void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
String username = authentication.getName();
SysLog sysLog = SysLogUtils.getSysLog(request, username);
sysLog.setTitle(username + "用户登录");
sysLog.setParams(username);
remoteLogService.saveLog(sysLog, SecurityConstants.FROM_IN);
log.info("用户:{} 登录成功", username);
}
}
......@@ -11,10 +11,8 @@ spring:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7
namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
config:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7
namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
\ No newline at end of file
server:
port: 12254
spring:
application:
name: @artifactId@
main:
allow-bean-definition-overriding: true
# nacos
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
config:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
......@@ -63,7 +63,7 @@
<appender-ref ref="error"/>
</logger>
<!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 -->
<root level="DEBUG">
<root level="ERROR">
<appender-ref ref="console"/>
<appender-ref ref="debug"/>
</root>
......
......@@ -22,7 +22,7 @@
<mysql.connector.version>8.0.15</mysql.connector.version>
<swagger.core.version>1.5.22</swagger.core.version>
<swagger.version>2.9.2</swagger.version>
<hutool.version>5.5.1</hutool.version>
<hutool.version>5.7.0</hutool.version>
<poi.version>4.1.0</poi.version>
<pinyin4j.version>2.5.1</pinyin4j.version>
<ttl.version>2.10.1</ttl.version>
......@@ -58,11 +58,11 @@
<artifactId>cloud-common-core</artifactId>
<version>${sict.version}</version>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-auth-api</artifactId>
<version>${sict.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>cn.sh.stc.sict</groupId>-->
<!-- <artifactId>cloud-auth-api</artifactId>-->
<!-- <version>${sict.version}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-dynamic-gateway</artifactId>
......
......@@ -80,5 +80,13 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--纳里平台接口调用SDK(公众号用户信息接口)-->
<dependency>
<groupId>com.ngarihealth</groupId>
<artifactId>openapi-sdk-java</artifactId>
<version>1.0-RELEASE</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/openapi-sdk-java-1.0-RELEASE.jar</systemPath>
</dependency>
</dependencies>
</project>
\ No newline at end of file
......@@ -8,75 +8,35 @@ package cn.sh.stc.sict.cloud.common.core.constant;
*/
public class RedisCacheConstant {
/**
* 用户角色与终端类型的分隔符
* 用户角色与终端类型的分隔符
*/
public static final String USER_ROLE_SEPARATOR = "@";
/**
* 微信用户信息明细
*/
public static final String WX_USER_DETAILS = "wx_user_details";
/**
* 基础用户信息明细 base
*/
public static final String BASE_USER_DETAILS = "base_user_details";
/**
* 基础学生信息
*/
public static final String CURRENT_STUDENT = "current_student";
public static final String APP = "hpgp:";
/**
* 基础用户信息明细
*/
public static final String USER_DETAILS = "user_details";
public static final String USER_DETAILS = APP + "user_details";
/**
* 当前登录用户的角色信息
*/
public static final String TOKEN_ROLES = "token_roles";
public static final String TOKEN_ROLES = APP + "token_roles";
/**
* 当前登录用户的详细信息
*/
public static final String TOKEN_CURRENT = "token_current";
/**
* 微信应用缓存
*/
public static final String WECHAT_OFFICALS = "wechat_officals";
/**
* 冷知识点赞数量
*/
public static final String CLD_TRIVIA_NUM = "cld_trivia_num";
/**
* 积分
*/
public static final String CREDIT = "credit";
public static final String CREDIT_NEXT_LEVEL_BY_SCORE = "credit:score:next";
public static final String CREDIT_LEVEL_BY_SCORE = "credit:score:current";
public static final String TOKEN_CURRENT = APP + "token_current";
/**
* 未付款订单
* /**
* 用户短信验证码
*/
public static final String PAY_ORDER_NOT_PAID = "order_info:not_paid";
public static final String SICT_PHONE_CODE_KEY = APP + "SICT_PHONE_CODE_KEY";
/**
* temp 微信支付开关
* 路由存放
*/
public static final String WECHAT_APPLE_PAY_SWITCH = "order_info:wechat_apple_pay_switch";
public static final String ROUTE_KEY = APP + "hp_gateway_route_key";
/**
* 是否需要弹窗
*/
public static final String WECHAT_POP_UP = "pop-up:kindergarten";
public static final String DEPT_NUM_SOURCE_RESULT = "dept_num_source_result";
/**
* 用户短信验证码
*/
public static final String SICT_PHONE_CODE_KEY = "SICT_PHONE_CODE_KEY";
/**
* 路由存放
*/
public static final String ROUTE_KEY = "hp_gateway_route_key";
public static final String DEFAULT_CODE_KEY = APP + "SICT_DEFAULT_CODE_KEY_";
/**
* 验证码前缀
*/
public static final String DEFAULT_CODE_KEY = "SICT_DEFAULT_CODE_KEY_";
public static final String LOGIN_ERROR_TIMES = APP + "login_error_times";
}
......@@ -136,6 +136,14 @@ public interface SecurityConstants {
* openid
*/
String DETAILS_APPID = "appid";
/**
* 医院代码
*/
String HOSPITAL_CODE = "hospitalCode";
/**
* 香山中医用户信息
*/
String XSZY_USER_INFO = "xszyUserInfo";
/**
* 租户ID 字段
*/
......
......@@ -11,4 +11,6 @@ public interface ServiceNameConstants {
* 认证中心
*/
String UPMS_SERVICE = "cloud-upms-biz";
String AUTH_SERVICE = "cloud-auth";
}
package cn.sh.stc.sict.cloud.common.core.constant;
public class UserConstant {
public final static String USER_SOURCE_MOBILE = "mobile";
public final static String USER_SOURCE_SSB = "wd_ssb";
/**
* 0:社保卡
* 1:医保卡
* 2:统一自费就诊卡
* 9:其他卡
*/
public final static String SOCIAL_SECURITY_CARD = "0";
public final static String MEDICAL_INSURANCE_CARD = "1";
public final static String UNIFIED_MEDICAL_TREATMENT_EXPENSE_CARD = "2";
public final static String OTHER_CARD = "9";
}
......@@ -12,6 +12,7 @@ import lombok.Getter;
@AllArgsConstructor
public enum BizCodeConstant {
/* */
USER_PWD_LIMIT(99,""),
TEMP(0,"");
private Integer code;
......
......@@ -22,6 +22,31 @@ public enum LoginTypeEnum {
*/
SMS("sms", "验证码登录"),
/**
* 验证码登录
*/
SSB("ssb", "随申办token"),
/**
* 纳里用户系统公众号
* 香山中医医院公众号
* 上海市黄浦区精神卫生中心
* 上海市黄浦区妇幼保健所
* 上海市黄浦区顺昌医院
* 上海市黄浦区半淞园路街道社区卫生服务中心
*/
WOA_NL("woa_nl", "纳里用户系统公众号登录"),
/**
* 打浦桥,外滩,小东门,老西门,豫园,五里桥,淮海,瑞二
*/
WOA_ZZ("woa_zz", "中智用户系统公众号登录"),
/**
* 上海交通大学医学院附属第九人民医院黄浦分院
*/
WOA_WD("woa_wd", "万达公众号用户系统公众号登录"),
WOA_ND("woa_nd", "万达公众号用户系统南东社区公众号登录"),
/**
* H5登录
*/
......@@ -46,4 +71,13 @@ public enum LoginTypeEnum {
* 描述
*/
private final String description;
public static LoginTypeEnum match(String type) {
for (LoginTypeEnum loginType : LoginTypeEnum.values()) {
if (loginType.getType().equals(type)) {
return loginType;
}
}
return null;
}
}
package cn.sh.stc.sict.cloud.common.core.constant.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 中智用户体系枚举
*
* @author gao
* @date 2023/04/27 15:16
*/
@AllArgsConstructor
@Getter
public enum ZzUserApiEnum {
/**
* 中智用户体系公众号信息
*/
DAPUQIAO("/dpq", "wxd831bfb5879b3522", "booking.hpdapuqiao.com", "42502942300"),
WAITAN("/wt", "wx8f9db9da2fbe1d5b", "booking.hpwaitan.com", "42503639100"),
WULIQIAO("/wlq", "wxa29d485b25f6aaf0", "gzh.hpwlq.com", "79705627000"),
HUAIHAIZHONGLU("/hhzl", "wxf2cbbfdc28aa93e6", "gzh.hphuaihai.com", "42502940700"),
RUIJINERLU("/rjel", "wxf0b1f6ee9e16effd", "booking.shruier.cn", "42502992500"),
YUYUAN("/yy", "wx3691d4535427bfc5", "gzh.yuyuanswydt.cn", "42502884200"),
XIAODONGMEN("/xdm", "wx1e4ca6fecfa4a0bb", "gzh.hpxiaodongmen.com", "42507025800"),
LAOXIMEN("/lxm", "wxdf6e240a731c70ea", "booking.hplxmsw.cn", "42507018600");
private final String relativePath;
private final String appid;
private final String domain;
private final String institutionCode;
public static ZzUserApiEnum find(String appid) {
return Arrays.stream(values())
.filter(institution -> institution.appid.equals(appid))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No Institution with appid " + appid));
}
}
package cn.sh.stc.sict.cloud.common.core.dto;
import lombok.Data;
/**
* 万达随申办接口用户绑卡信息
*/
@Data
public class WDUserCardInfo {
private String id;
private String cardNo;
private String cardType;
private String hospitalId;
}
package cn.sh.stc.sict.cloud.common.core.dto;
import lombok.Data;
import java.util.Date;
/**
* 万达随申办接口用户信息
*/
@Data
public class WDUserInfo {
private String token;
private String id;
private String username;
private String name;
private String personcard;
private String mobile;
private Date birth;
private String avatar;
private Byte gender;
private String verifyStatus;
private Date regtime;
private String openid;
}
package cn.sh.stc.sict.cloud.common.core.dto;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* 万达公众号-用户基础信息
*
* @author gao
* @date 2023/01/13 09:39
*/
@Data
public class WOAWDUserInfo {
private String id;
private String username;
private String personcard;
private String mobile;
private String avator;
private Byte gender;
private Integer verifyStatus;
private Date regtime;
private String openid;
private List<Card> cards;
@Data
public static class Card {
private String hospitalId;
private String cardType;
private String cardNo;
}
}
package cn.sh.stc.sict.cloud.common.core.dto;
import lombok.Data;
import java.util.Date;
/**
* 中智公众号-用户基础信息
*
* @author gao
* @date 2023/01/13 09:39
*/
@Data
public class WOAZzUserInfo {
private String id;
private String username;
private String personcard;
private String mobile;
private String avator;
private Byte gender;
private Integer verifyStatus;
private Date regtime;
private String openid;
}
package cn.sh.stc.sict.cloud.common.core.dto;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.UserConstant;
import lombok.Data;
/**
* 公众号-香山中医医院用户信息
*/
@Data
public class XSZYUserInfo {
/**
* 用户ID
*/
private String userId;
/**
* 就诊人ID
*/
private String mpiId;
/**
* 姓名
*/
private String patientName;
/**
* 证件号
*/
private String certificate;
/**
* 证件类型
*/
private String certificateType;
/**
* 手机号
*/
private String mobile;
/**
* 医院编码
*/
private String hospitalCode;
/**
* 卡类型0:社保卡;1:医保卡;2:统一自费就诊卡;9:其他卡
*/
private String mediCardType;
/**
* 卡号
*/
private String mediCardId;
/**
* 将纳里用户卡类型映射为挂号时的卡类型
* 1:就诊卡
* 2:医保卡
* 3:病历号
* 4:健康卡
* 5:社保卡
* 6:住院卡
* 7:院内健健康卡
* 8:体检卡
*/
public static String fromNlType(String mediCardType) {
if (StrUtil.isBlank(mediCardType)) {
return null;
}
if (mediCardType.equals("5")) {
return UserConstant.SOCIAL_SECURITY_CARD;
} else if (mediCardType.equals("2")) {
return UserConstant.MEDICAL_INSURANCE_CARD;
} else if (mediCardType.equals("1")) {
return UserConstant.UNIFIED_MEDICAL_TREATMENT_EXPENSE_CARD;
} else {
return UserConstant.OTHER_CARD;
}
}
}
......@@ -292,6 +292,11 @@ public class CryptUtil {
String pwdjm = toAES(pwd, token);
System.out.println(toAES(name, token));
System.out.println(pwdjm);
String text = "FaU+wh88VZr4E+YufJyuJMnxPJlQtyst/BkgZ0chipVSTcKNXVEGj9AhQ99wPGzC3QeNAYTU0slgpjqPCEX9lg==";
String test = "FaU+wh88VZr4E+YufJyuJMnxPJlQtyst/BkgZ0chipVSTcKNXVEGj9AhQ99wPGzCbJtQ4HC4oA0aFRYKwbUpiwTBtIGU8VG+Dkmaz+MSi6hSFiR850DYQFXnISMiACvTIR/UWFlDvDX77C6cNUAuVSDIdSpOSmOLTZaiaaOEi2LgVnQHsjOMmKDcVInNOyjvkVovh51wmkzLVxnnfkyjyL0vQx+Q5Jz89rZ92bZbTxZjjoaZ2QDLyoky/ojFRGvgAz8pej/3BIHlRDyFiVLFvkzUGBmYdbpL6cvxIxAt9o9iNkM7c7IIayR2147doob941Pqz3nJkpttEH8tHxJnh6HCFu2ZjxKQIfYigRBdZbXWo01LwYqETJkWKopsqk5ibqbPxTH/BdBtaoH7E6R0jyl0gp7EzF9AvIb653uhntQULJyw8OvRbJUS2aLNNGP1y/GojY61lU0jhMsinoptwzexs29cunBkXhV1CbNQ7l2XfHbPh1zSKWhXoVzYWzXG7j672imxWpuiscmwtJHDPMZeF3UAlBQPdL1xV6Ck6wB8jVzKtVgoeCAAQFqP97RvU+kjPYRhqaVtp3+gKFzIxglae2C0+cgTM2Ogh4BOKqc50EPJx1bjKEOq3UIIFF9nqPrirQBC3BhCfj3aVjLxGxRwH4Ji0dOtceiaKBQlPJcoGZ/3C7/wLroMCNkUSwXycGL54cE1fLS/gbQzQeIm1lz6MiLR8vmiKUiSRATJU/dLpkEbkEJkeFtJvuOjCBRKnsoaisUBzH4S88NrH7GgVfIcQ7dsLIl34GNKQ0KY9fCd3c/6brG97gktH+7qnOhy8N442oAK5QtPQUOBgLmwLQ2hnG+rolwDj4RGCgsIoBSkv3b6lLNvPxvQ7PemGz4hI0/2Pew13KRcc0ezoWdKj3FHKMeZ2xWFkIHjvZY7mU6sFX8CoYcsmrcGFu3qxFYmDjLKqVdSTHaGtkjcnizG/2jCkVZrn7P0+3laM8HS0D6hnNGSeXJAqhkY2f6DTzYKCdv+i7iXw5mT30OFumNtGPWMRYkTq6327y+Asccx3ToBpaQHrbsX29hG9KXMmt40taNI7UGAfepaQuOJaqtRxL1i9J/sOrSwkcD+V3Vn3YnM0RkJU1RdAHqjefcXHfPlpNdCpOzBdj70XVIPwbPr/4pFUluQ/bQ87sqRbWHJr6dFNWQqgrbBUbDRkqgxKTcoAjHdl43QwaWBA6eqG6bqZSBlKB9a+8C8OZUDFRO2T74HJDh9G06iVDf7jN9wtXpVER38yUY1ie/y+IM85uGpmllI3zyUftdNPqwEftRPuYAq8+PNafApfdm286l0v9p2xkdoxFg2Xq3Ddmwry0maCqTOUMgdVV6dyYMCfKSBiJU/4BjfN6ksW4GGv9jtvj8EJKXAiYKokGJUrtx0eNmVo5+k76s2tKgrJOdQG/OoCLQsvxWGtkeH4Q+Ljpx5Ce6Vko6oEk0E3QwQaGWGSnYDuejzgFP3Af2kfzdDl3GWE0prCxwkqfg0PSgw0VxaPGZ1NQ/rxezPI66/XEh2Ap7lk0Rkw4K6mmVst25XHoXS2uajwO6uG9s8ZNcBwltxUptwQE3p16/NaUYSe0UZJ2N+rGZLSIlWwRgAMXdnAe46tP0LD6VIujKko/GoRahUuE1T9Fhy4yEVwoG4eIcOAE4Af/1U3Ol5bPR7mteKetbf5/4CuAaElta2xonovT8bVqJ+6Ic6JE4LrprKNQ2GBCxpDuUaN/w01HKhpR2Hc4NloJTIK09NVUwUHF70HDmgbmqDDWrwt3+J/ia4sA/ziZm3dJWNtmED3b/md9ZPsBQVFfi2glRitVUuwh2rri2MfF12YNKMtos/C87BV7khPVYmtzCX6pcpbLtDDPpJuAc8RDaOMchB4MEx009g5V+KT02kE1yaWT2aK9HfoYkkH5qY21yLGswLdTm8GOL1vN7uT+VTwcRJAJWqNw2FRnqkDnJrOYylzzy8WFoJ7KLfGwZJFmXaGSI8L0bE0xnHoubCylsgb9vRS9XdjtFfusaDwP6hc5zEplaBA2N7K964S57I+O7ABzQSgadO4VsPXuDxlKtOk4ZL25yYGwu9TabdjOR4h5IGYggYyssrAVDImP1eYGs4SoX+RMQLkWhYGomPeaNu49E+yzdS8u+OMjOx92MBntABWZWrl+tRW2D2OCtKQNWRrDafE9WNkkXJENtb67JJ2PlXPevt8XsdlD3/oC+iE2VwJYNiMY0ugxk0TgJ40FoIe+0dHQCJk6I0hPBFCPRDwTrlGw0Wq3JkpOu1/ThlhneuA51eapQ0ZAhOoBf3YAyAJLf1zAH07oQ17+vxhkMElhVbKoZ7KX4IzR0gku5G+QxziGlpWOt1fZYOvvO5QthVy7iLzBR7127HluRatNFSOpdYXhduF8AzI9huXfHYwSlsBRxZpMEaazrLZzyTq+UAKICoHuQCeKRV2AEtorgyrATfK0CrZ7Q8ECCCoH8ERWI4K9Bxb/86i+9Si4/C0SUXg/SbrJSwBiaXXmfhO4uQtxp/ZjMOQ2EUx3OtDkrcyNbrkoqQpcWBCAUx+5eWvxkLPlPW/+Ra3vWDhqYupL2fiB3l0Z5nt6GLV7UxzWe9tF904XxIuN7o8at7qRmXbTqIlaorp4A2gmQG3bq/Cy+XbjR8QcdWRD+Q+3Yd4c3MCxi01PAnXg2qFbqGT5RniMoV28PZP/Jp5OFMSawzlOSTQm1cE/XozP1ESzO6Bs9MFq47hxFgV1gPLJ6qOgTCkQNJzbcEMCN9I6XNDWX/0W+gPr5IwE4vBrV5yExC1XkJ4EVnEvuI99UyLw/zXWPAaEdhFkflz45pJtoxdW8HaPiDBA8om6V9NuoR2Iqd03I5FCww7QzyleeNY2v2kY9QcmOgFtFR4ISoK5RmqgZmfSWpr4uYektikZNZjMCi/bEdjRHkEGglgAL0jzMvNOe9811Qvphf135QAo5P6k9VYSds1sA8iNOp2kGGFM3Jt652RtL0W2t0eTHUUni042ZwW26vjR1SX0F5fP2a9KdqOF6rhTNmffX1UEv+TulLYcVKGv3BINXKgXG22+EefHoARruCqGPWs5RCyWAvZMBeZRp8gfosVWzICZQzHcy2GBhXwpfjvAPXMvMok05a6zIxmu7ABzQSgadO4VsPXuDxlKuH3sss32SZwgDYUS9yQ9JVh5IGYggYyssrAVDImP1eYGs4SoX+RMQLkWhYGomPeaNu49E+yzdS8u+OMjOx92MBntABWZWrl+tRW2D2OCtKQNWRrDafE9WNkkXJENtb67JJ2PlXPevt8XsdlD3/oC+iE2VwJYNiMY0ugxk0TgJ40FoIe+0dHQCJk6I0hPBFCPRDwTrlGw0Wq3JkpOu1/ThlhneuA51eapQ0ZAhOoBf3YAyAJLf1zAH07oQ17+vxhkMElhVbKoZ7KX4IzR0gku5GXVcHomuEaf26zfywObYnmJkL/r6GvF6eH/032Q0kHW/8Qj0yx+NeqOUXmxSPHk40GSb6/cmqYOEPWMyaVXYDTTvzjActpHH4JkFlXaTjo89YB3QVC05EicWjhmZ23wGalaft2hSWs/Lx3xR90+2kcOC19wJc6CUfI5cISSbGq8TRHx32duFDIAgbvcyE0G21oWrAYLWhwlvHvGfJ63aYihuJnIqgIW+nnIHRQuI143VBdAdHr9E2uDD1PpG5hxKlE5hfGK2orY9gBnuKEgODN3VyeCIclc47X+iaPa7ymSPVy/lv4hgyYrF42N8Ymi9UQkxjzrEwe7Gm8WrK3VsqGAj9qIl4F2rqOIi3somz1s3SGr9HJl/+2OaH3UGHxr3RUn2iTTmOM1xndpn+wF4ff7OrfaLXKpphy5ne9+Z04yACuAaElta2xonovT8bVqJ+XZ/LS3e6ahMHJnFWAda4UeUaN/w01HKhpR2Hc4NloJTIK09NVUwUHF70HDmgbmqDDWrwt3+J/ia4sA/ziZm3dJWNtmED3b/md9ZPsBQVFfi2glRitVUuwh2rri2MfF12YNKMtos/C87BV7khPVYmtzCX6pcpbLtDDPpJuAc8RDaOMchB4MEx009g5V+KT02kE1yaWT2aK9HfoYkkH5qY21yLGswLdTm8GOL1vN7uT+VTwcRJAJWqNw2FRnqkDnJrOYylzzy8WFoJ7KLfGwZJFqySbVSTFH5HhQHTIkKhrBdS2LYqGhD41jrK1oQwqNqHPMbErLtxNl2f7bV8203i8+/+zrkcexsRmGJrnyPYVz7LwOVZmtcUoeL8Lnqk2HxMkCdZQr8wM45IximdgdeKUFBp41+krdjbYOqhF4TDkyA2GPFfxI4BzAkn8rdnW/dMUqp/9Nm9Yqk5OXqkjoYBDu9PJQ1Ns+VRz5rtLLUj9l2zx5jAlJfpNalaMk4A1NlBs86xhMH/ypTVzJgmDMlH0UdSboLzoBRBubGAt81XTZe+5HhVDiE0RNm0tC9Hw+bmGZ00tpnQSKFKT33r9RWp2sWGygirXPWS1+UAgvnt1pAzKQ+xK7l348DSDien58AR/pmyIq9a3n00u38GIX5boTaoH4OhKh3n+ln/CyBHH3N4M2AnmBiYN0OepGo62YiTxkdoxFg2Xq3Ddmwry0maCgTtLEyDxIQ+AHPh3HxZ5w0/4BjfN6ksW4GGv9jtvj8EJKXAiYKokGJUrtx0eNmVo5+k76s2tKgrJOdQG/OoCLQsvxWGtkeH4Q+Ljpx5Ce6Vko6oEk0E3QwQaGWGSnYDuejzgFP3Af2kfzdDl3GWE0prCxwkqfg0PSgw0VxaPGZ1NQ/rxezPI66/XEh2Ap7lk0Rkw4K6mmVst25XHoXS2uajwO6uG9s8ZNcBwltxUptwQE3p16/NaUYSe0UZJ2N+rGZLSIlWwRgAMXdnAe46tP0My/lxEeY4BdVF7fkmJHxDn9qerp8Jw6Q4KS4kbRyxc6clls4YO2dNtulJyRwylTWaTNisgmHeiCjN1mFxakwmDWWqzpEO9eMDydxOAfNHz7wFwP4bTx39IXVocahDs1HhngKEM/ZxSW9uXF2bf0eHMVm3NwyC/8PIuZr5RolK2urTBA6Tl1ozH4Uk4z3XYFQMBdpLnsho7MFU/AVo/5twAgslI6fb3CXA2svKl1axrWBqhhroUFv+PZXCoxpWo6w0EzgI1/6zADq5P9E6fXVM0HAS6VBkymNnOxgJQra62ukJHW3VXgfLEMa7jSL4SRRQyK0VgOblkFcS4ALInZzscfUn9tlocgddD2Kxar3U587q6t3R/3eiMi5Mc7AX+18zKQ+xK7l348DSDien58ARKbthenX0b+lkQ2q2qFSx+MHV3jA1JPIlS3+AWhCuNr6A1lxmLOfd0UdNwTdQEejsArgGhJbWtsaJ6L0/G1aifkl4HOPeVv5GGKVU32Hj7RflGjf8NNRyoaUdh3ODZaCUyCtPTVVMFBxe9Bw5oG5qgw1q8Ld/if4muLAP84mZt3SVjbZhA92/5nfWT7AUFRX4toJUYrVVLsIdq64tjHxddmDSjLaLPwvOwVe5IT1WJrcwl+qXKWy7Qwz6SbgHPEQ2UCAABuKjZDm39PYCkJYkvRNcmlk9mivR36GJJB+amNvgL4TA/OJMRwH09/4M8oSVQhuJtEGeibSeE00C5Kfk8JL7XQcNhgCrbZ3sQPoFLihdrcZUOGqiIfT4zc9XirbChHgqYLSNU9SugaieC083CiusLLJtG7J1T62HA4hcReToBw2BJqb1I95UvNdmHhDj3ajUVz6SeJYC8wdTOP//SaA+vkjATi8GtXnITELVeQklh0KKFGL76rvtiVk6aC2PR2EWR+XPjmkm2jF1bwdo+IMEDyibpX026hHYip3TcjkULDDtDPKV541ja/aRj1ByY6AW0VHghKgrlGaqBmZ9Jamvi5h6S2KRk1mMwKL9sR2NEeQQaCWAAvSPMy80573znsoYr7H7tHYbGcEeZtb7J1xFWjddtyQWACHcFC9QgEVG0vRba3R5MdRSeLTjZnBbIXb7eZHxnO9xVPGWkWa+1oAPEPbCXhWR5OqmIl3nkJ2gVDGgPPb35OBRXdfOIiNiSnG8C24C5Glp7ST0UT4VQfofCAv3aVFquQGcKYkZiAhB2AzSvEB6j3BZTIGf6HK4SSRy/8Cg+qkV67gc585p+DR8NSC+DGdifLfdcyL4sFwDhPoSwkWnXPouoWR+D9ibxmG98PAPxRqnYpGSVMuDlKe8liW8/pHm4XQ/Ijybp7B2U3z5lIS/2ZjgIIjd/B/85MULsWz8XMmt8LNrfHAUetCNJiQC9lPqVvIGT0cV6UIfmmn0CK+rNNlgKeAU8iLQOiEQuJ4H7nardUnt0ec5n/MRSJyew2UDdV3jE2SPxdc7CIRcxQ/RqTsufEItqqrGR/GquZgnehKBP5q0l0XP7nKUgyUKY+UWtvOgnInYurPi3fHX7bb6T1TBgY/dcFphj1nFQBvHhtrAT/IbP88UU6UzMtgmr2fslcrsl9TVTlQuJ9Hr80C0E3W3+uOgeKNYd1WDJ9bwrPcPr5Orui5PO6D8JCxuWbo/5geRUrcYoukyuzQLct9pUoHSfPwWe8xunNVQiMgSwn1mDU/Vkwun2dYIXd/qU1Ez/VHeq5hXL30OKcOgcNUvmiKUMULBJbD5U/BLSx4ExoZ3P9EN1ZRf17GELV4Lg1RmG5i3SQaEa5cNPKtlV+TJ2F82WV2VQDsVAascRBPx7IbdJTBVoWz/HwdLJOUKmlVqqbknjx4qJ0TiL5bv0yXt4XCIaqNmoXmNp82NjyP3sWBUQq7FY+Tig68WgblA3qAdfJHSGAjCXPqo2rAOj/U5xv8JFkD6NxFLK5BtcYyN19AD/6N4L/fBkwMTCLP1t9bR7N+ly5X9dRsaRCloqwI3jjHtef4KoiczhqfWgtv8cFN9wqDBF2PUs+zY/NH/EPNCitQB3SDQ3kNupiLLPhPkWTB3YNGrzXFydvNhiOkKTqJRKIgrCaX9oaGc0ZJ5ckCqGRjZ/oNPNgo0fzEIUzLmWET9rEsvRsL59YxFiROrrfbvL4CxxzHdOgGlpAetuxfb2Eb0pcya3jS1o0jtQYB96lpC44lqq1HEvWL0n+w6tLCRwP5XdWfdiczRGQlTVF0AeqN59xcd8+Wk10Kk7MF2PvRdUg/Bs+v/wZqe44/SdpZb7eCeo8FoW0U1ZCqCtsFRsNGSqDEpNyiWibKEnkafri1Q+VGpOBqXtdHyDIdHrUp7OQk8EKzS3ICQg8alNjep8rygV2yu9OiOnNoISLQizyxddKEMuGBNZktIiVbBGAAxd2cB7jq0/cRbvEDXqDKxlyE4BZTP5JTCOvXB1XRDQXdyKAobWnPxPfun3sEyiRMhsOJ3ryOo3+/+zrkcexsRmGJrnyPYVz4BBvGkrs0MrOsel4s1GUXDkCdZQr8wM45IximdgdeKUFBp41+krdjbYOqhF4TDkyA2GPFfxI4BzAkn8rdnW/dMUqp/9Nm9Yqk5OXqkjoYBDu9PJQ1Ns+VRz5rtLLUj9l2zx5jAlJfpNalaMk4A1NlBs86xhMH/ypTVzJgmDMlH0SKpCveHRCprtGhv/lExKp6+5HhVDiE0RNm0tC9Hw+bmojmVRxTCUTEikxJWHTxUoR2pqqWT+8eAWlgjek6BF5sjmMUZIHz3ou9xRc7FEBKrI9fQ1htAhlFCITwApQAqRgj9qIl4F2rqOIi3somz1s2FglzL1e7RzMKqq3m8X7dCLwPa+9oti4j5lC/XU2VsLKnVvJC/bY/2QoXCfh8/6O3uwAc0EoGnTuFbD17g8ZSrGq3JQOykLfjOGRmaLkNR4YeSBmIIGMrLKwFQyJj9XmBrOEqF/kTEC5FoWBqJj3mjbuPRPss3UvLvjjIzsfdjAZ7QAVmVq5frUVtg9jgrSkDVkaw2nxPVjZJFyRDbW+uykRklxfG/Ej/XZT9/95oyOg==";
System.out.println(AESToString(test,token));
// String pwdorigin = AESToString(pwdjm, token);
// System.out.println(pwdorigin);
......
package cn.sh.stc.sict.cloud.common.core.util;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import java.math.BigDecimal;
import java.math.BigInteger;
......@@ -118,4 +119,7 @@ public class NumberUtil {
}
public static Long getLongValue(String value) {
return StrUtil.isBlank(value) ? 0L : Long.parseLong(value);
}
}
package cn.sh.stc.sict.cloud.common.core.util;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.dto.WDUserCardInfo;
import cn.sh.stc.sict.cloud.common.core.dto.WDUserInfo;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
/**
* 随申办工具类
*/
@Slf4j
@UtilityClass
public class SsbUtil {
// 外网测试地址 https://ffyjs.hpwjsns.org.cn:9071/
// private final static String USER_URL = "https://ffyjs.hpwjsns.org.cn:9071/fdapp/api/account/v1/token/info";
// private final static String CARD_URL = "https://ffyjs.hpwjsns.org.cn:9071/fdapp/api/account/v1/user/cards";
// 内网线上地址 http://173.18.1.97:9071/fdapp/
private final static String USER_URL = "http://173.18.1.97:9071/fdapp/api/account/v1/token/info";
private final static String CARD_URL = "http://173.18.1.97:9071/fdapp/api/account/v1/user/cards";
/**
* 获取用户信息
*
* @param token
* @return
*/
public WDUserInfo getUserInfo(String token) {
try {
HttpResponse response = HttpRequest.get(USER_URL)
.header("backdoor", "1")
.header("access-token", token)
.execute();
if (response.getStatus() != 200) {
log.error("随申办token获取用户信息异常-1");
return null;
}
return JSONUtil.toBean(response.body(), WDUserInfo.class);
} catch (Exception ex) {
log.error("随申办token获取用户信息异-2!");
log.error(ex.getMessage(), ex);
return null;
}
}
/**
* 获取用户绑卡信息
*
* @param token
* @return
*/
public List<WDUserCardInfo> getUserCardInfoList(String token) {
try {
HttpResponse response = HttpRequest.get(CARD_URL)
.header("backdoor", "1")
.header("access-token", token)
.execute();
if (response.getStatus() != 200) {
log.error("随申办token获取绑卡信息异常-1");
return null;
}
return JSONUtil.toList(JSONUtil.parseArray(response.body()), WDUserCardInfo.class);
} catch (Exception ex) {
log.error("随申办token获取绑卡信息异-2!");
log.error(ex.getMessage(), ex);
return null;
}
}
}
......@@ -39,247 +39,283 @@ import java.util.*;
@Slf4j
@UtilityClass
public class WebUtils extends org.springframework.web.util.WebUtils {
private final String BASIC_ = "Basic ";
private final String UNKNOWN = "unknown";
private final String BASIC_ = "Basic ";
private final String UNKNOWN = "unknown";
private final String LOCAL127 = "127.0.0.1";
/**
* 判断是否ajax请求
* spring ajax 返回含有 ResponseBody 或者 RestController注解
*
* @param handlerMethod HandlerMethod
* @return 是否ajax请求
*/
public boolean isBody(HandlerMethod handlerMethod) {
ResponseBody responseBody = ClassUtils.getAnnotation(handlerMethod, ResponseBody.class);
return responseBody != null;
}
/**
* 判断是否ajax请求
* spring ajax 返回含有 ResponseBody 或者 RestController注解
*
* @param handlerMethod HandlerMethod
* @return 是否ajax请求
*/
public boolean isBody(HandlerMethod handlerMethod) {
ResponseBody responseBody = ClassUtils.getAnnotation(handlerMethod, ResponseBody.class);
return responseBody != null;
}
/**
* 读取cookie
*
* @param name cookie name
* @return cookie value
*/
public String getCookieVal(String name) {
HttpServletRequest request = WebUtils.getRequest();
Assert.notNull(request, "request from RequestContextHolder is null");
return getCookieVal(request, name);
}
/**
* 读取cookie
*
* @param name cookie name
* @return cookie value
*/
public String getCookieVal(String name) {
HttpServletRequest request = WebUtils.getRequest();
Assert.notNull(request, "request from RequestContextHolder is null");
return getCookieVal(request, name);
}
/**
* 读取cookie
*
* @param request HttpServletRequest
* @param name cookie name
* @return cookie value
*/
public String getCookieVal(HttpServletRequest request, String name) {
Cookie cookie = getCookie(request, name);
return cookie != null ? cookie.getValue() : null;
}
/**
* 读取cookie
*
* @param request HttpServletRequest
* @param name cookie name
* @return cookie value
*/
public String getCookieVal(HttpServletRequest request, String name) {
Cookie cookie = getCookie(request, name);
return cookie != null ? cookie.getValue() : null;
}
/**
* 清除 某个指定的cookie
*
* @param response HttpServletResponse
* @param key cookie key
*/
public void removeCookie(HttpServletResponse response, String key) {
setCookie(response, key, null, 0);
}
/**
* 清除 某个指定的cookie
*
* @param response HttpServletResponse
* @param key cookie key
*/
public void removeCookie(HttpServletResponse response, String key) {
setCookie(response, key, null, 0);
}
/**
* 设置cookie
*
* @param response HttpServletResponse
* @param name cookie name
* @param value cookie value
* @param maxAgeInSeconds maxage
*/
public void setCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds) {
Cookie cookie = new Cookie(name, value);
cookie.setPath("/");
cookie.setMaxAge(maxAgeInSeconds);
cookie.setHttpOnly(true);
response.addCookie(cookie);
}
/**
* 设置cookie
*
* @param response HttpServletResponse
* @param name cookie name
* @param value cookie value
* @param maxAgeInSeconds maxage
*/
public void setCookie(HttpServletResponse response, String name, String value, int maxAgeInSeconds) {
Cookie cookie = new Cookie(name, value);
cookie.setPath("/");
cookie.setMaxAge(maxAgeInSeconds);
cookie.setHttpOnly(true);
response.addCookie(cookie);
}
/**
* 获取 HttpServletRequest
*
* @return {HttpServletRequest}
*/
public HttpServletRequest getRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
/**
* 获取 HttpServletRequest
*
* @return {HttpServletRequest}
*/
public HttpServletRequest getRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
/**
* 获取 HttpServletResponse
*
* @return {HttpServletResponse}
*/
public HttpServletResponse getResponse() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
}
/**
* 获取 HttpServletResponse
*
* @return {HttpServletResponse}
*/
public HttpServletResponse getResponse() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
}
/**
* 返回json
*
* @param response HttpServletResponse
* @param result 结果对象
*/
public void renderJson(HttpServletResponse response, Object result) {
renderJson(response, result, MediaType.APPLICATION_JSON_UTF8_VALUE);
}
/**
* 返回json
*
* @param response HttpServletResponse
* @param result 结果对象
*/
public void renderJson(HttpServletResponse response, Object result) {
renderJson(response, result, MediaType.APPLICATION_JSON_UTF8_VALUE);
}
/**
* 返回json
*
* @param response HttpServletResponse
* @param result 结果对象
* @param contentType contentType
*/
public void renderJson(HttpServletResponse response, Object result, String contentType) {
response.setCharacterEncoding("UTF-8");
response.setContentType(contentType);
try (PrintWriter out = response.getWriter()) {
out.append(JSONUtil.toJsonStr(result));
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
/**
* 返回json
*
* @param response HttpServletResponse
* @param result 结果对象
* @param contentType contentType
*/
public void renderJson(HttpServletResponse response, Object result, String contentType) {
response.setCharacterEncoding("UTF-8");
response.setContentType(contentType);
try (PrintWriter out = response.getWriter()) {
out.append(JSONUtil.toJsonStr(result));
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
/**
* 获取ip
*
* @return {String}
*/
public String getIP() {
return getIP(WebUtils.getRequest());
}
/**
* 获取ip
*
* @return {String}
*/
public String getIP() {
return getIP(WebUtils.getRequest());
}
public String getSession(){
return WebUtils.getSessionId(WebUtils.getRequest());
}
public String getSession() {
return WebUtils.getSessionId(WebUtils.getRequest());
}
/**
* 获取ip
*
* @param request HttpServletRequest
* @return {String}
*/
public String getIP(HttpServletRequest request) {
Assert.notNull(request, "HttpServletRequest is null");
String ip = request.getHeader("X-Requested-For");
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Forwarded-For");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
/**
* 获取ip
*
* @param request HttpServletRequest
* @return {String}
*/
public String getIP(HttpServletRequest request) {
Assert.notNull(request, "HttpServletRequest is null");
String ip = request.getHeader("X-Requested-For");
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Forwarded-For");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return StringUtils.isBlank(ip) ? null : ip.split(",")[0];
}
return StringUtils.isBlank(ip) ? null : ip.split(",")[0];
}
/**
* 从request 获取CLIENT_ID
*
* @return
*/
@SneakyThrows
public String[] getClientId(ServerHttpRequest request) {
String header = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
public String getIP(ServerHttpRequest request) {
HttpHeaders headers = request.getHeaders();
String ip = headers.getFirst("x-forwarded-for");
if (StrUtil.isNotBlank(ip) && !UNKNOWN.equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个ip值,第一个ip才是真实ip
if (ip.indexOf(",") != -1) {
if (LOCAL127.equals(ip.split(",")[0])) {
ip = ip.split(",")[1];
} else {
ip = ip.split(",")[0];
}
}
}
if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = headers.getFirst("Proxy-Client-IP");
}
if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = headers.getFirst("WL-Proxy-Client-IP");
}
if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = headers.getFirst("HTTP_CLIENT_IP");
}
if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
}
if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = headers.getFirst("X-Real-IP");
}
if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddress().getAddress().getHostAddress();
}
return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
}
if (header == null || !header.startsWith(BASIC_)) {
throw new CheckedException("请求头中client信息为空");
}
byte[] base64Token = header.substring(6).getBytes("UTF-8");
byte[] decoded;
try {
decoded = Base64.decode(base64Token);
} catch (IllegalArgumentException e) {
throw new CheckedException(
"Failed to decode basic authentication token");
}
String token = new String(decoded, StandardCharsets.UTF_8);
/**
* 从request 获取CLIENT_ID
*
* @return
*/
@SneakyThrows
public String[] getClientId(ServerHttpRequest request) {
String header = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
int delim = token.indexOf(":");
if (header == null || !header.startsWith(BASIC_)) {
throw new CheckedException("请求头中client信息为空");
}
byte[] base64Token = header.substring(6).getBytes("UTF-8");
byte[] decoded;
try {
decoded = Base64.decode(base64Token);
} catch (IllegalArgumentException e) {
throw new CheckedException(
"Failed to decode basic authentication token");
}
if (delim == -1) {
throw new CheckedException("Invalid basic authentication token");
}
return new String[]{token.substring(0, delim), token.substring(delim + 1)};
}
String token = new String(decoded, StandardCharsets.UTF_8);
/**
*
* @param request HttpServletRequest
* tip: 不可使用WebUtils.getRequest()获取
* @param allowSuffix 文件后缀名 多个以","逗号分隔
* @return
*/
public MultipartFile getRequestFile(@NonNull HttpServletRequest request, @NonNull String allowSuffix){
String errorMsg = StrUtil.EMPTY;
int delim = token.indexOf(":");
String[] suffixs = allowSuffix.split(",");
Set<String> suffixSet = new HashSet<String>(Arrays.asList(suffixs));
if (delim == -1) {
throw new CheckedException("Invalid basic authentication token");
}
return new String[]{token.substring(0, delim), token.substring(delim + 1)};
}
Map<String, MultipartFile> fileMap = ((MultipartHttpServletRequest) request).getFileMap();
MultipartFile file = null;
for (Map.Entry<String, MultipartFile> fileEntity : fileMap.entrySet()) {
file = fileEntity.getValue();
String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf('.') + 1);
if(suffixSet.contains(suffix)){
break;
}
errorMsg = "文件类型不支持";
}
/**
* @param request HttpServletRequest
* tip: 不可使用WebUtils.getRequest()获取
* @param allowSuffix 文件后缀名 多个以","逗号分隔
* @return
*/
public MultipartFile getRequestFile(@NonNull HttpServletRequest request, @NonNull String allowSuffix) {
String errorMsg = StrUtil.EMPTY;
Assert.isTrue(StrUtil.isBlank(errorMsg), errorMsg);
Objects.requireNonNull(file,"excel导入 ---------->>>>>>> 未检测到上传文件");
String[] suffixs = allowSuffix.split(",");
Set<String> suffixSet = new HashSet<String>(Arrays.asList(suffixs));
return file;
}
Map<String, MultipartFile> fileMap = ((MultipartHttpServletRequest) request).getFileMap();
MultipartFile file = null;
for (Map.Entry<String, MultipartFile> fileEntity : fileMap.entrySet()) {
file = fileEntity.getValue();
String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf('.') + 1);
if (suffixSet.contains(suffix)) {
break;
}
errorMsg = "文件类型不支持";
}
/**
* 导出excel
* @param list 数据
* @param writer
* @param name 文件名
*/
@SneakyThrows
public void exportExcel(@NonNull List list,@NonNull ExcelWriter writer, String name) {
writer.setOnlyAlias(true);
HttpServletResponse response = WebUtils.getResponse();
//response为HttpServletResponse对象
response.setContentType("application/vnd.ms-excel;charset=utf-8");
//codes.xls是弹出下载对话框的文件名,不能为中文,中文需自行编码
response.setHeader("Content-Disposition", "attachment;filename=data.xlsx");
ServletOutputStream out = response.getOutputStream();
try {
writer.write(list);
writer.flush(out);
} catch (Exception e) {
log.error("下载[{}]excel异常 =====>>>>> {}", name, e.getMessage());
} finally {
// 关闭writer,释放内存
writer.close();
//关闭输出Servlet流
IoUtil.close(out);
}
}
Assert.isTrue(StrUtil.isBlank(errorMsg), errorMsg);
Objects.requireNonNull(file, "excel导入 ---------->>>>>>> 未检测到上传文件");
return file;
}
/**
* 导出excel
*
* @param list 数据
* @param writer
* @param name 文件名
*/
@SneakyThrows
public void exportExcel(@NonNull List list, @NonNull ExcelWriter writer, String name) {
writer.setOnlyAlias(true);
HttpServletResponse response = WebUtils.getResponse();
//response为HttpServletResponse对象
response.setContentType("application/vnd.ms-excel;charset=utf-8");
//codes.xls是弹出下载对话框的文件名,不能为中文,中文需自行编码
response.setHeader("Content-Disposition", "attachment;filename=data.xlsx");
ServletOutputStream out = response.getOutputStream();
try {
writer.write(list);
writer.flush(out);
} catch (Exception e) {
log.error("下载[{}]excel异常 =====>>>>> {}", name, e.getMessage());
} finally {
// 关闭writer,释放内存
writer.close();
//关闭输出Servlet流
IoUtil.close(out);
}
}
}
package cn.sh.stc.sict.cloud.common.core.util;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.constant.enums.ZzUserApiEnum;
import cn.sh.stc.sict.cloud.common.core.dto.WOAWDUserInfo;
import cn.sh.stc.sict.cloud.common.core.dto.WOAZzUserInfo;
import cn.sh.stc.sict.cloud.common.core.dto.XSZYUserInfo;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import ngari.openapi.Client;
import ngari.openapi.JSONResponseBean;
import ngari.openapi.Request;
import ngari.openapi.Response;
/**
* 医院公众号工具类
* <p>
* 注意事项:
* 1.医院编码是否传递
* 2.手机号必须有,作为用户身份的唯一标识
*/
@Slf4j
@UtilityClass
public class WoaUtil {
/**
* 香山中医医院公众号用户信息获取接口地址(纳里)
*/
private final static String WOA_XSZY_URL = "https://openapi.ngarihealth.com";
private final static String WOA_XSZY_GATEWAY_URL = "/openapi/gateway";
/**
* 内网代理请求地址
*/
private final static String WOA_XSZY_PROXY_PASS_URL = "http://30.30.5.74:9988/woa/xszy";
/**
* 获取用户信息请求地址
*/
private final static String WOA_XSZY_USER_INFO_API_URL = WOA_XSZY_PROXY_PASS_URL + WOA_XSZY_GATEWAY_URL;
/**
* 接口授权信息
*/
private final static String APP_KEY = "ngari635f7f4b0e980e63";
private final static String APP_SECRET = "0e980e634196fcde";
/**
* 获取用户信息服务ID
*/
private final static String SERVICE_ID = "openapi.authenticationService";
/**
* 获取用户信息方法
*/
private final static String METHOD = "apiGetUserInfo";
/**
* 响应头请求唯一ID
*/
private final static String RESPONSE_HEADER_REQUEST_ID = "X-Ca-RequestId";
/**
* 获取用户信息
*
* @param ngCode 纳里授权码
* @return
*/
public XSZYUserInfo getXszyUserInfo(String ngCode) {
//如果开启加密,则必填
String encodingAesKey = "";
Client client = new Client(WOA_XSZY_USER_INFO_API_URL, APP_KEY, APP_SECRET, encodingAesKey);
try {
// 入参说明[授权码,是否回调,拓展参数]
Request request = new Request(SERVICE_ID, METHOD, ListUtil.toList(ngCode, false, null));
Response response = client.execute(request);
if (response.isSuccess()) {
JSONResponseBean result = response.getJsonResponseBean();
XSZYUserInfo xszyUserInfo = Convert.convert(XSZYUserInfo.class, result.getBody());
return xszyUserInfo;
} else {
log.error("香山中医医院公众号token获取用户信息异常-1,requestId = [{}],caError = [{}],error = [{}]", response.getHeader(RESPONSE_HEADER_REQUEST_ID), response.getCaErrorMsg(), response.getErrorMessage());
log.error(JSONUtil.toJsonStr(response));
return null;
}
} catch (Exception ex) {
log.error("香山中医医院公众号token获取用户信息异-2!");
log.error(ex.getMessage(), ex);
return null;
}
}
/**
* 中智公众号用户url
* 打浦桥,外滩,小东门,老西门,豫园,五里桥,淮海,瑞二
*/
private final static String WOA_ZZ_PROXY_PASS_URL = "http://30.30.5.74:9988/woa/zz";
// private final static String WOA_ZZ_PROXY_PASS_URL = "https://booking.hpdapuqiao.com";
private final static String ZZ_USER_INFO_API_URL = "/api/Other/GetPerson";
//private final static String WOA_WD_PROXY_PASS_URL = "https://wxgzh.shjyhpfy.com/api/hosservice/visit/GetUserInfoByToken";
private final static String WOA_WD_PROXY_PASS_URL = "http://30.30.5.74:9988/woa/wd";
private final static String WOA_WD_USER_INFO_URL = WOA_WD_PROXY_PASS_URL + "/api/hosservice/visit/GetUserInfoByToken";
private final static String WOA_WD_ND_PROXY_PASS_URL = "http://30.30.5.74:9988/woa/wdnd";
/**
* 南东社区公众号用户信息
*/
private final static String WOA_WD_ND_USER_INFO_URL = WOA_WD_ND_PROXY_PASS_URL + "/gzh/user/token/info";
public WOAZzUserInfo getZzUserInfo(String appid, String accessToken) {
try {
ZzUserApiEnum zzUserApiEnum = ZzUserApiEnum.find(appid);
String url = WOA_ZZ_PROXY_PASS_URL + zzUserApiEnum.getRelativePath() + ZZ_USER_INFO_API_URL;
HttpResponse response = HttpRequest.get(url)
.header("access-token", accessToken)
.execute();
if (response.getStatus() != 200) {
log.error("中智获取用户信息异常-1");
return null;
}
log.error("response = {}", JSONUtil.toJsonStr(response.body()));
return JSONUtil.toBean(response.body(), WOAZzUserInfo.class);
} catch (Exception ex) {
log.error("中智token获取用户信息异-2!");
log.error(ex.getMessage(), ex);
return null;
}
}
public WOAWDUserInfo getWoaWDUserInfo(String accessToken) {
try {
HttpResponse response = HttpRequest.get(WOA_WD_USER_INFO_URL)
.header("access-token", accessToken)
.execute();
if (response.getStatus() != 200) {
log.error("万达公众号获取用户信息异常-1");
return null;
}
return JSONUtil.toBean(response.body(), WOAWDUserInfo.class);
} catch (Exception ex) {
log.error("万达公众号token获取用户信息异-2!");
log.error(ex.getMessage(), ex);
return null;
}
}
/**
* 获取万达南东社区公众号用户信息
* @param accessToken
* @return
*/
public WOAWDUserInfo getThirdPartyUserInfo(String accessToken){
try {
HttpResponse response = HttpRequest.get(WOA_WD_ND_USER_INFO_URL)
.header("access-token", accessToken)
.execute();
if (response.getStatus() != 200) {
log.error("万达公众号获取用户信息异常-1");
return null;
}
return JSONUtil.toBean(response.body(), WOAWDUserInfo.class);
} catch (Exception ex) {
log.error("万达公众号token获取用户信息异-2!");
log.error(ex.getMessage(), ex);
return null;
}
}
}
......@@ -17,7 +17,9 @@ import javax.sql.DataSource;
*/
@Configuration
@ConditionalOnClass(MybatisPlusConfig.class)
@MapperScan(basePackages = {"cn.sh.stc.sict.**.dao", "com.smarthealth.themestore.*.dao"})
@MapperScan(basePackages = {"cn.sh.stc.sict.**.dao",
"com.smarthealth.themestore.*.dao",
"cn.sh.stc.sict.**.**.dao"})
public class MybatisPlusConfig {
/**
......
......@@ -13,6 +13,9 @@ import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
import java.util.HashSet;
import java.util.Set;
/**
* @Description
* @Author
......@@ -26,7 +29,17 @@ public class GlobalCorsConfig {
*/
private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client,access-token";
private static final String ALLOWED_METHODS = "*";
private static final String ALLOWED_ORIGIN = "*";
private static final Set<String> ALLOWED_ORIGINS = new HashSet<String>(){{
add("https://inno.sh-sict.com");
add("https://hy.hpwjsns.org.cn");
add("http://localhost:12998");
add("http://127.0.0.1:12998");
add("http://sict-gateway:12998");
add("http://192.168.31.140:12998");
add("http://localhost:12999");
add("http://127.0.0.1:12999");
add("http://sict-gateway:12999");
}};
private static final String ALLOWED_Expose = "*";
private static final String MAX_AGE = "18000L";
......@@ -37,7 +50,11 @@ public class GlobalCorsConfig {
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = ctx.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
if(ALLOWED_ORIGINS.contains(request.getHeaders().getOrigin())){
headers.add("Access-Control-Allow-Origin", request.getHeaders().getOrigin());
}else{
headers.add("Access-Control-Allow-Origin", "https://hy.hpwjsns.org.cn");
}
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Max-Age", MAX_AGE);
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
......
package cn.sh.stc.sict.cloud.common.gateway.config;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
/**
* @Description 网关不校验终端配置
* @Author
* @Date
*/
@Data
@Configuration
@RefreshScope
@ConditionalOnExpression("!'${whiteip}'.isEmpty()")
@ConfigurationProperties(prefix = "whiteip")
public class WhitIPConfig {
private Boolean limitFlag;
private List<String> whites = new ArrayList<>();
}
package cn.sh.stc.sict.cloud.common.gateway.feign;
import cn.sh.stc.sict.cloud.common.core.constant.ServiceNameConstants;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.gateway.feign.fallback.RemoteAuthFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @Description
* @Author
* @Date
*/
@FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.AUTH_SERVICE, fallbackFactory = RemoteAuthFallback.class)
//@FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.AUTH_SERVICE)
@Service
public interface RemoteAuthService {
/**
* 通过用户名或手机号查询用户
*
* @param username 用户名
* @param from 调用标志
* @return R
*/
@GetMapping("/token/check/{token}")
R<Boolean> isValid(@PathVariable("token") String token);
}
package cn.sh.stc.sict.cloud.common.gateway.feign.fallback;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.gateway.feign.RemoteAuthService;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author gao
* @date 2023/09/04 09:51
*/
@Component
@Slf4j
public class RemoteAuthFallback implements FallbackFactory<RemoteAuthService> {
@Override
public RemoteAuthService create(Throwable throwable) {
return new RemoteAuthService() {
@Override
public R<Boolean> isValid(String toke) {
log.info("远程调用失败:权限校验错误");
return null;
}
};
}
}
package cn.sh.stc.sict.cloud.common.gateway.filter;
import cn.hutool.core.util.ObjectUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.gateway.feign.RemoteAuthService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
/**
* @author gao
* @date 2023/08/30 10:23
*/
@Slf4j
@Component
@AllArgsConstructor
public class GptServerFilter extends AbstractGatewayFilterFactory {
public final RemoteAuthService remoteAuthService;
public static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String token = request.getHeaders().getFirst(SEC_WEBSOCKET_PROTOCOL);
log.info("ws-token{}", token);
// 权限校验
if (checkToken(token)) {
return chain.filter(exchange);
} else {
return Mono.error(new RuntimeException("权限校验失败"));
}
};
}
/**
* 校验token
*
* @param token
* @return
*/
private boolean checkToken(String token) {
// if (StringUtils.isEmpty(token)) {
// return false;
// }
return true;
// R<Boolean> valid = remoteAuthService.isValid(token);
// if (ObjectUtil.isNull(valid) || ObjectUtil.isNull(valid.getData())) {
// return false;
// }
// return valid.getData();
}
}
......@@ -68,19 +68,19 @@ public class PasswordDecoderFilter extends AbstractGatewayFilterFactory {
}
URI uri = exchange.getRequest().getURI();
log.error("uri ==============>: {}", uri.toString());
// log.error("uri ==============>: {}", uri.toString());
String queryParam = uri.getRawQuery();
log.error("queryParam==============>: {}", queryParam);
// log.error("queryParam==============>: {}", queryParam);
Map<String, String> paramMap = HttpUtil.decodeParamMap(queryParam, CharsetUtil.UTF_8);
log.error("paramMap==============>: {}", paramMap.toString());
// log.error("paramMap==============>: {}", paramMap.toString());
String password = paramMap.get(PASSWORD);
if (StrUtil.isNotBlank(password)) {
try {
// password = decryptAES(password, encodeKey);
log.error("before password: {}", password);
// log.error("before password: {}", password);
password = CryptUtil.AESToString(password, encodeKey);
log.error("after password: {}", password);
// log.error("after password: {}", password);
} catch (Exception e) {
log.error("密码解密失败:password = {}", password);
return Mono.error(e);
......@@ -91,9 +91,9 @@ public class PasswordDecoderFilter extends AbstractGatewayFilterFactory {
if (StrUtil.isNotBlank(username)) {
try {
// password = decryptAES(password, encodeKey);
log.error("before username: {}", username);
// log.error("before username: {}", username);
username = CryptUtil.AESToString(username, encodeKey);
log.error("after username: {}", username);
// log.error("after username: {}", username);
} catch (Exception e) {
log.error("用户名解密失败:username = {}", username);
return Mono.error(e);
......
package cn.sh.stc.sict.cloud.common.gateway.filter;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.core.util.WebUtils;
import cn.sh.stc.sict.cloud.common.gateway.config.WhitIPConfig;
import cn.sh.stc.sict.cloud.common.gateway.util.IPStrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
......@@ -17,53 +28,85 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.G
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;
/**
* @Description
* <p>
* 全局拦截器,作用所有的微服务
* <p>
* 1. 对请求头中参数进行处理 from 参数进行清洗
* 2. 重写StripPrefix = 1,支持全局
* <p>
* 支持swagger添加X-Forwarded-Prefix header (F SR2 已经支持,不需要自己维护)
* @Description <p>
* 全局拦截器,作用所有的微服务
* <p>
* 1. 对请求头中参数进行处理 from 参数进行清洗
* 2. 重写StripPrefix = 1,支持全局
* <p>
* 支持swagger添加X-Forwarded-Prefix header (F SR2 已经支持,不需要自己维护)
* @Author
* @Date
*/
@Slf4j
@Component
@AllArgsConstructor
public class RequestGlobalFilter implements GlobalFilter, Ordered {
private static final String HEADER_NAME = "X-Forwarded-Prefix";
private static final String HEADER_NAME = "X-Forwarded-Prefix";
private final WhitIPConfig whitIPConfig;
private final ObjectMapper objectMapper;
/**
* Process the Web request and (optionally) delegate to the next
* {@code WebFilter} through the given {@link GatewayFilterChain}.
*
* @param exchange the current server exchange
* @param chain provides a way to delegate to the next filter
* @return {@code Mono<Void>} to indicate when request processing is complete
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 清洗请求头中from 参数
ServerHttpRequest request = exchange.getRequest().mutate()
.headers(httpHeaders -> {httpHeaders.remove(SecurityConstants.FROM);})
.build();
/**
* Process the Web request and (optionally) delegate to the next
* {@code WebFilter} through the given {@link GatewayFilterChain}.
*
* @param exchange the current server exchange
* @param chain provides a way to delegate to the next filter
* @return {@code Mono<Void>} to indicate when request processing is complete
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 清洗请求头中from 参数
ServerHttpRequest request = exchange.getRequest().mutate()
.headers(httpHeaders -> {
httpHeaders.remove(SecurityConstants.FROM);
})
.build();
// 2. 重写StripPrefix
addOriginalRequestUrl(exchange, request.getURI());
String rawPath = request.getURI().getRawPath();
String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/"))
.skip(1L).collect(Collectors.joining("/"));
ServerHttpRequest newRequest = request.mutate()
.path(newPath)
.build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
// IP白名单
String ip = WebUtils.getIP(request);
// log.error("RemoteAddress = {}, ip = {}", request.getRemoteAddress(), ip);
try {
if (whitIPConfig.getLimitFlag() && !IPStrUtil.matches(ip, whitIPConfig.getWhites())) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);
response.getHeaders().set("Content-type", "application/json; charset=utf-8");
return response.writeWith(Mono.just(response.bufferFactory()
.wrap(objectMapper.writeValueAsBytes(
R.builder().msg("没有权限访问")
.code(Constant.BYTE_NO).build()))));
}
} catch (
Exception e) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);
response.getHeaders().set("Content-type", "application/json; charset=utf-8");
try {
return response.writeWith(Mono.just(response.bufferFactory()
.wrap(objectMapper.writeValueAsBytes(
R.builder().msg(e.getMessage())
.code(Constant.BYTE_NO).build()))));
} catch (JsonProcessingException e1) {
log.error("对象输出异常", e1);
}
}
// 2. 重写StripPrefix
addOriginalRequestUrl(exchange, request.getURI());
String rawPath = request.getURI().getRawPath();
String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/"))
.skip(1L).collect(Collectors.joining("/"));
ServerHttpRequest newRequest = request.mutate()
.path(newPath)
.build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
return chain.filter(exchange.mutate()
.request(newRequest.mutate()
.build()).build());
}
return chain.filter(exchange.mutate()
.request(newRequest.mutate()
.build()).build());
}
@Override
public int getOrder() {
return -1000;
}
@Override
public int getOrder() {
return -1000;
}
}
package cn.sh.stc.sict.cloud.common.gateway.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import java.util.List;
public class IPStrUtil {
static char START = '*';
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs) {
if (StrUtil.isEmpty(str) || CollUtil.isEmpty(strs)) {
return false;
}
for (String testStr : strs) {
if (matches(str, testStr)) {
return true;
}
}
return false;
}
/**
* 查找指定字符串是否匹配指定字符串数组中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, String... strs) {
if (StrUtil.isEmpty(str) || StrUtil.isAllEmpty(str)) {
return false;
}
for (String testStr : strs) {
if (matches(str, testStr)) {
return true;
}
}
return false;
}
/**
* 查找指定字符串是否匹配
*
* @param str 指定字符串
* @param pattern 需要检查的字符串
* @return 是否匹配
*/
public static boolean matches(String str, String pattern) {
if (StrUtil.isEmpty(pattern) || StrUtil.isEmpty(str)) {
return false;
}
pattern = pattern.replaceAll("\\s*", ""); // 替换空格
int beginOffset = 0; // pattern截取开始位置
int formerStarOffset = -1; // 前星号的偏移位置
int latterStarOffset = -1; // 后星号的偏移位置
String remainingURI = str;
String prefixPattern = "";
String suffixPattern = "";
boolean result = false;
do {
formerStarOffset = StrUtil.indexOf(pattern, START, beginOffset);
prefixPattern = StrUtil.sub(pattern, beginOffset, formerStarOffset > -1 ? formerStarOffset : pattern.length());
// 匹配前缀Pattern
result = remainingURI.contains(prefixPattern);
// 已经没有星号,直接返回
if (formerStarOffset == -1) {
return result;
}
// 匹配失败,直接返回
if (!result)
return false;
if (!StrUtil.isEmpty(prefixPattern)) {
remainingURI = StrUtil.subAfter(str, prefixPattern, true);
}
// 匹配后缀Pattern
latterStarOffset = StrUtil.indexOf(pattern, START, formerStarOffset + 1);
suffixPattern = StrUtil.sub(pattern, formerStarOffset + 1, latterStarOffset > -1 ? latterStarOffset : pattern.length());
result = remainingURI.contains(suffixPattern);
// 匹配失败,直接返回
if (!result)
return false;
if (!StrUtil.isEmpty(suffixPattern)) {
remainingURI = StrUtil.subAfter(str, suffixPattern, true);
}
// 移动指针
beginOffset = latterStarOffset + 1;
}
while (!StrUtil.isEmpty(suffixPattern) && !StrUtil.isEmpty(remainingURI));
return true;
}
@SuppressWarnings("unchecked")
public static <T> T cast(Object obj) {
return (T) obj;
}
}
......@@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
......@@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.security.auth.login.AccountLockedException;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;
......@@ -77,6 +79,28 @@ public class GlobalExceptionHandlerResolver {
return objectR;
}
@ExceptionHandler({BadCredentialsException.class})
@ResponseStatus(HttpStatus.OK)
public R handleBadCredentialsException(BadCredentialsException exception) {
R<Object> objectR = R.builder()
.code(Constant.BYTE_NO)
.msg(exception.getMessage())
.build();
return objectR;
}
@ExceptionHandler({AccountLockedException.class})
@ResponseStatus(HttpStatus.OK)
public R handleBAccountLockedException(AccountLockedException exception) {
R<Object> objectR = R.builder()
.code(Constant.BYTE_NO)
.msg(exception.getMessage())
.build();
return objectR;
}
/**
* AccessDeniedException
*
......
......@@ -19,56 +19,58 @@ import java.util.Map;
* @Date
*/
public class SictUserAuthenticationConverter implements UserAuthenticationConverter {
private static final String N_A = "N/A";
private static final String N_A = "N/A";
/**
* Extract information about the user to be used in an access token (i.e. for resource servers).
*
* @param authentication an authentication representing a user
* @return a map of key values representing the unique information about the user
*/
@Override
public Map<String, ?> convertUserAuthentication(Authentication authentication) {
Map<String, Object> response = new LinkedHashMap<>();
response.put(USERNAME, authentication.getName());
if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
}
return response;
}
/**
* Extract information about the user to be used in an access token (i.e. for resource servers).
*
* @param authentication an authentication representing a user
* @return a map of key values representing the unique information about the user
*/
@Override
public Map<String, ?> convertUserAuthentication(Authentication authentication) {
Map<String, Object> response = new LinkedHashMap<>();
response.put(USERNAME, authentication.getName());
if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
response.put(AUTHORITIES, AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
}
return response;
}
/**
* Inverse of {@link #convertUserAuthentication(Authentication)}. Extracts an Authentication from a map.
*
* @param map a map of user information
* @return an Authentication representing the user or null if there is none
*/
@Override
public Authentication extractAuthentication(Map<String, ?> map) {
if (map.containsKey(USERNAME)) {
Collection<? extends GrantedAuthority> authorities = getAuthorities(map);
/**
* Inverse of {@link #convertUserAuthentication(Authentication)}. Extracts an Authentication from a map.
*
* @param map a map of user information
* @return an Authentication representing the user or null if there is none
*/
@Override
public Authentication extractAuthentication(Map<String, ?> map) {
if (map.containsKey(USERNAME)) {
Collection<? extends GrantedAuthority> authorities = getAuthorities(map);
String username = (String) map.get(USERNAME);
Long id = (Long) map.get(SecurityConstants.DETAILS_USER_ID);
String name = (String) map.get(SecurityConstants.DETAILS_NAME);
String openid = (String) map.get(SecurityConstants.DETAILS_OPENID);
String appid = (String) map.get(SecurityConstants.DETAILS_APPID);
SictUser user = new SictUser(id, "", openid, appid, username, N_A, true
, true, true, true, authorities);
return new UsernamePasswordAuthenticationToken(user, N_A, authorities);
}
return null;
}
String username = (String) map.get(USERNAME);
Long id = (Long) map.get(SecurityConstants.DETAILS_USER_ID);
String name = (String) map.get(SecurityConstants.DETAILS_NAME);
String openid = (String) map.get(SecurityConstants.DETAILS_OPENID);
String appid = (String) map.get(SecurityConstants.DETAILS_APPID);
String hospitalCode = (String) map.get(SecurityConstants.HOSPITAL_CODE);
String xszyUserInfo = (String) map.get(SecurityConstants.XSZY_USER_INFO);
SictUser user = new SictUser(id, "", openid, appid, hospitalCode, username, N_A, true
, true, true, true, authorities, xszyUserInfo);
return new UsernamePasswordAuthenticationToken(user, N_A, authorities);
}
return null;
}
private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map) {
Object authorities = map.get(AUTHORITIES);
if (authorities instanceof String) {
return AuthorityUtils.commaSeparatedStringToAuthorityList((String) authorities);
}
if (authorities instanceof Collection) {
return AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils
.collectionToCommaDelimitedString((Collection<?>) authorities));
}
throw new IllegalArgumentException("Authorities must be either a String or a Collection");
}
private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map) {
Object authorities = map.get(AUTHORITIES);
if (authorities instanceof String) {
return AuthorityUtils.commaSeparatedStringToAuthorityList((String) authorities);
}
if (authorities instanceof Collection) {
return AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils
.collectionToCommaDelimitedString((Collection<?>) authorities));
}
throw new IllegalArgumentException("Authorities must be either a String or a Collection");
}
}
......@@ -17,6 +17,8 @@ import org.springframework.security.oauth2.provider.error.WebResponseExceptionTr
import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import javax.security.auth.login.AccountLockedException;
/**
* @Description
* @Author
......@@ -33,8 +35,12 @@ public class SictWebResponseExceptionTranslator implements WebResponseExceptionT
// Try to extract a SpringSecurityException from the stacktrace
Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e);
Exception ase = (AccountLockedException) throwableAnalyzer.getFirstThrowableOfType(AccountLockedException.class, causeChain);
if(ase != null){
return handleOAuth2Exception(new UnauthorizedException(e.getMessage(), e, HttpStatus.LOCKED.value()));
}
Exception ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class,
ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class,
causeChain);
if (ase != null) {
return handleOAuth2Exception(new UnauthorizedException(e.getMessage(), e));
......
package cn.sh.stc.sict.cloud.common.security.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import java.util.Locale;
//security中文提示信息配置类
@Configuration
public class ReloadMessageConfig {
@Bean //加载中文认证提示信息
public ReloadableResourceBundleMessageSource messageSource(){
Locale.setDefault(Locale.SIMPLIFIED_CHINESE);
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
//加载org/springframework/security包下的中文提示信息 配置文件
messageSource.setBasename("classpath:security/messages_zh_CN");
return messageSource;
}
}
package cn.sh.stc.sict.cloud.common.security.config;
import cn.hutool.core.util.ObjectUtil;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
/**
* 用户账号 配置属性
*/
@Data
@Component
@RefreshScope
@ConditionalOnExpression("!'${user}'.isEmpty()")
@ConfigurationProperties(prefix = "user.account")
public class UserAccountProperties {
private Boolean limitFlag;
private Long limitCount;
private Long limitTime;
public Boolean getLimitFlag() {
return !ObjectUtil.isNull(this.limitFlag) && this.limitFlag;
}
public Long getLimitCount(){
return NumberUtil.isNullOrZero(this.limitCount) ? 5L : this.limitCount;
}
public Long getLimitTime() {
return NumberUtil.isNullOrZero(this.limitTime) ? 30L : this.limitTime;
}
}
package cn.sh.stc.sict.cloud.common.security.exception;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.security.component.SictAuth2ExceptionSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.springframework.http.HttpStatus;
/**
* @author lengleng
* @author F_xh
* @date 2018/7/8
*/
@JsonSerialize(using = SictAuth2ExceptionSerializer.class)
public class UnauthorizedException extends SictAuth2Exception {
private Integer httpErrorCode;
public UnauthorizedException(String msg, Throwable t) {
super(msg);
}
public UnauthorizedException(String msg, Throwable t) {
super(msg);
}
@Override
public String getOAuth2ErrorCode() {
return "unauthorized";
}
public UnauthorizedException(String msg, Throwable t, Integer httpErrorCode) {
super(msg);
this.httpErrorCode = httpErrorCode;
}
@Override
public int getHttpErrorCode() {
return HttpStatus.UNAUTHORIZED.value();
}
@Override
public String getOAuth2ErrorCode() {
return "unauthorized";
}
@Override
public int getHttpErrorCode() {
return NumberUtil.isNullOrZero(this.httpErrorCode) ? HttpStatus.UNAUTHORIZED.value() : this.httpErrorCode;
}
}
......@@ -54,7 +54,7 @@ public class SictFeignClientInterceptor extends OAuth2FeignRequestInterceptor {
boolean isIngore = false;
if (CollectionUtil.isNotEmpty(permitAllUrlProperties.getIgnoreUrls())) {
for (String ingoreUrl : permitAllUrlProperties.getIgnoreUrls()) {
if(template.url().startsWith(ingoreUrl.replace("*", ""))){
if(template.url().startsWith(ingoreUrl.replace("/**", ""))){
isIngore = true;
break;
}
......
package cn.sh.stc.sict.cloud.common.security.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface AuthenticationFailureHandler {
/**
* 业务处理
* @param authenticationException 错误信息
* @param authentication 认证信息
* @param request 请求信息
* @param response 响应信息
*/
void handle(AuthenticationException authenticationException, Authentication authentication,
HttpServletRequest request, HttpServletResponse response);
}
package cn.sh.stc.sict.cloud.common.security.handler;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface AuthenticationLogoutHandler {
/**
* 业务处理
* @param authentication 认证信息
* @param request 请求信息
* @param response 响应信息
*/
void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response);
}
package cn.sh.stc.sict.cloud.common.security.handler;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface AuthenticationSuccessHandler {
/**
* 业务处理
* @param authentication 认证信息
* @param request 请求信息
* @param response 响应信息
*/
void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response);
}
package cn.sh.stc.sict.cloud.common.security.listener;
import cn.hutool.core.collection.CollUtil;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationFailureHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public class AuthenticationFailureEventListener implements ApplicationListener<AbstractAuthenticationFailureEvent> {
@Autowired(required = false)
private List<AuthenticationFailureHandler> failureHandlerList;
/**
* Handle an application event.
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(AbstractAuthenticationFailureEvent event) {
// 此类型事件不传递处理 #2386
if (event instanceof AuthenticationFailureProviderNotFoundEvent) {
return;
}
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpServletResponse response = requestAttributes.getResponse();
AuthenticationException authenticationException = event.getException();
Authentication authentication = (Authentication) event.getSource();
// 调用自定义业务链实现
if (CollUtil.isNotEmpty(failureHandlerList)) {
failureHandlerList.forEach(failureHandler -> failureHandler.handle(authenticationException, authentication,
request, response));
}
}
}
package cn.sh.stc.sict.cloud.common.security.listener;
import cn.hutool.core.collection.CollUtil;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationLogoutHandler;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AuthenticationLogoutSuccessEventListener implements ApplicationListener<AbstractAuthenticationEvent> {
@Autowired(required = false)
private AuthenticationLogoutHandler logoutHandler;
/**
* Handle an application event.
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(AbstractAuthenticationEvent event) {
// 健壮性判断
if (!(event.getSource() instanceof OAuth2Authentication)) {
return;
}
OAuth2Authentication authentication = (OAuth2Authentication) event.getSource();
if (logoutHandler != null && isUserAuthentication(authentication)) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpServletResponse response = requestAttributes.getResponse();
logoutHandler.handle(authentication, request, response);
}
}
private boolean isUserAuthentication(Authentication authentication) {
return authentication.getPrincipal() instanceof SictUser
|| CollUtil.isNotEmpty(authentication.getAuthorities());
}
}
package cn.sh.stc.sict.cloud.common.security.listener;
import cn.hutool.core.collection.CollUtil;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationSuccessHandler;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public class AuthenticationSuccessEventListener implements ApplicationListener<AuthenticationSuccessEvent> {
@Autowired(required = false)
private List<AuthenticationSuccessHandler> successHandlerList;
/**
* Handle an application event.
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(AuthenticationSuccessEvent event) {
Authentication authentication = (Authentication) event.getSource();
if (CollUtil.isNotEmpty(successHandlerList) && isUserAuthentication(authentication)) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpServletResponse response = requestAttributes.getResponse();
successHandlerList.forEach(successHandler -> successHandler.handle(authentication, request, response));
}
}
private boolean isUserAuthentication(Authentication authentication) {
return authentication.getPrincipal() instanceof SictUser
|| CollUtil.isNotEmpty(authentication.getAuthorities());
}
}
......@@ -35,6 +35,17 @@ public class SictUser extends User {
@Setter
private String appId;
/**
* 医院公众号登陆的用户包含医院代码
*/
@Getter
@Setter
private String hospitalCode;
@Getter
@Setter
private String xszyUserInfo;
@Getter
@Setter
private transient String token;
......@@ -44,6 +55,7 @@ public class SictUser extends User {
* {@link DaoAuthenticationProvider}.
*
* @param id 用户ID
* @param hospitalCode 医院代码
* @param username the username presented to the
* <code>DaoAuthenticationProvider</code>
* @param password the password that should be presented to the
......@@ -58,11 +70,25 @@ public class SictUser extends User {
* @throws IllegalArgumentException if a <code>null</code> value was passed either as
* a parameter or as an element in the <code>GrantedAuthority</code> collection
*/
public SictUser(Long id, String phone, String openId, String appId, String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
public SictUser(Long id,
String phone,
String openId,
String appId,
String hospitalCode,
String username,
String password,
boolean enabled,
boolean accountNonExpired,
boolean credentialsNonExpired,
boolean accountNonLocked,
Collection<? extends GrantedAuthority> authorities,
String xszyUserInfo) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
this.id = id;
this.phone = phone;
this.openId = openId;
this.appId = appId;
this.hospitalCode = hospitalCode;
this.xszyUserInfo = xszyUserInfo;
}
}
......@@ -5,7 +5,9 @@ import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.security.config.UserAccountProperties;
import cn.sh.stc.sict.cloud.common.security.util.AuthUtils;
import cn.sh.stc.sict.cloud.upms.dto.UserInfo;
import cn.sh.stc.sict.cloud.upms.feign.RemoteUserService;
......@@ -16,6 +18,7 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
......@@ -26,6 +29,7 @@ import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.security.auth.login.AccountLockedException;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
......@@ -42,9 +46,12 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService {
private static final String BASIC_ = "Basic ";
private final RemoteUserService remoteUserService;
private final CacheManager cacheManager;
private final RedisTemplate<String, String> redisTemplate;
private final UserAccountProperties userAccountProperties;
/**
* 用户密码登录
* .
*
* @param username 用户名
* @return
......@@ -54,6 +61,11 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService {
@SneakyThrows
public UserDetails loadUserByUsername(String username) {
String key = username;
String lockedKey = String.format("%s:%s", RedisCacheConstant.LOGIN_ERROR_TIMES, username);
Long times = NumberUtil.getLongValue(redisTemplate.opsForValue().get(lockedKey));
if (userAccountProperties.getLimitFlag() && times >= userAccountProperties.getLimitCount()) {
throw new AccountLockedException("账号被锁定");
}
Cache cache = cacheManager.getCache(RedisCacheConstant.USER_DETAILS);
if (!StrUtil.containsAny(key, StringPool.COLON)) {
key = key + StringPool.COLON + getAppId();
......@@ -117,12 +129,18 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService {
if (StrUtil.isBlank(user.getUserName())) {
user.setUserName(user.getId().toString());
}
String userName = user.getUserName() + StringPool.COLON + info.getAppId();
return new SictUser(user.getId(), user.getPhone(), info.getOpenId(), info.getAppId(), userName, SecurityConstants.BCRYPT + user.getPasswd(), enabled,
true, true, !Constant.BYTE_YES.equals(user.getStatus()), authorities);
if (StrUtil.isNotBlank(info.getHospitalCode())) {
userName = userName.concat(StringPool.COLON).concat(info.getHospitalCode());
}
String password = SecurityConstants.BCRYPT + user.getPasswd();
// 登录失败5次锁定半小时
boolean nonLockd = !Constant.BYTE_YES.equals(user.getStatus());
return new SictUser(user.getId(), user.getPhone(), info.getOpenId(), info.getAppId(), info.getHospitalCode(), userName, password, enabled,
true, true, nonLockd, authorities, info.getXszyUserInfo());
}
private static String getAppId() {
String appId = "";
try {
......
......@@ -178,6 +178,9 @@ public class SecurityUtils {
current.setName(StrUtil.isBlank(user.getName()) ? user.getUsername() : user.getName());
current.setOpenId(user.getOpenId());
current.setAppId(user.getAppId());
current.setPhone(user.getPhone());
current.setHospitalCode(user.getHospitalCode());
current.setXszyUserInfo(user.getXszyUserInfo());
}
current.setToken(token);
return current;
......
......@@ -57,6 +57,19 @@ public class SysLogUtils {
return sysLog;
}
public SysLog getSysLog(HttpServletRequest request, String username) {
SysLog sysLog = new SysLog();
sysLog.setCreateBy(username);
sysLog.setType(Constant.BYTE_NO);
sysLog.setRemoteAddr(ServletUtil.getClientIP(request));
sysLog.setRequestUri(URLUtil.getPath(request.getRequestURI()));
sysLog.setMethod(request.getMethod());
sysLog.setUserAgent(request.getHeader("user-agent"));
sysLog.setParams(HttpUtil.toParams(request.getParameterMap()));
sysLog.setServiceId("/cloud-auth");
return sysLog;
}
public static Map<String, Object> getKeyAndValue(Object obj) {
Map<String, Object> map = new HashMap<>();
try {
......
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.openfeign.SictHystrixFeignTargeterConfiguration,\
cn.sh.stc.sict.cloud.common.security.feign.SictFeignConfiguration,\
cn.sh.stc.sict.cloud.common.security.service.SictUserDetailsServiceImpl
cn.sh.stc.sict.cloud.common.security.config.UserAccountProperties,\
cn.sh.stc.sict.cloud.common.security.config.ReloadMessageConfig,\
cn.sh.stc.sict.cloud.common.security.service.SictUserDetailsServiceImpl,\
cn.sh.stc.sict.cloud.common.security.component.SictWebResponseExceptionTranslator,\
cn.sh.stc.sict.cloud.common.security.component.ResourceAuthExceptionEntryPoint,\
cn.sh.stc.sict.cloud.common.security.listener.AuthenticationFailureEventListener,\
cn.sh.stc.sict.cloud.common.security.listener.AuthenticationSuccessEventListener,\
cn.sh.stc.sict.cloud.common.security.listener.AuthenticationLogoutSuccessEventListener
AbstractAccessDecisionManager.accessDenied=Access is denied
AbstractLdapAuthenticationProvider.emptyPassword=Empty Password
AbstractSecurityInterceptor.authenticationNotFound=An Authentication object was not found in the SecurityContext
AbstractUserDetailsAuthenticationProvider.badCredentials=Bad credentials
AbstractUserDetailsAuthenticationProvider.credentialsExpired=User credentials have expired
AbstractUserDetailsAuthenticationProvider.disabled=User is disabled
AbstractUserDetailsAuthenticationProvider.expired=User account has expired
AbstractUserDetailsAuthenticationProvider.locked=User account is locked
AbstractUserDetailsAuthenticationProvider.onlySupports=Only UsernamePasswordAuthenticationToken is supported
AccountStatusUserDetailsChecker.credentialsExpired=User credentials have expired
AccountStatusUserDetailsChecker.disabled=User is disabled
AccountStatusUserDetailsChecker.expired=User account has expired
AccountStatusUserDetailsChecker.locked=User account is locked
AclEntryAfterInvocationProvider.noPermission=Authentication {0} has NO permissions to the domain object {1}
AnonymousAuthenticationProvider.incorrectKey=The presented AnonymousAuthenticationToken does not contain the expected key
BindAuthenticator.badCredentials=Bad credentials
BindAuthenticator.emptyPassword=Empty Password
CasAuthenticationProvider.incorrectKey=The presented CasAuthenticationToken does not contain the expected key
CasAuthenticationProvider.noServiceTicket=Failed to provide a CAS service ticket to validate
ConcurrentSessionControlAuthenticationStrategy.exceededAllowed=Maximum sessions of {0} for this principal exceeded
DigestAuthenticationFilter.incorrectRealm=Response realm name {0} does not match system realm name of {1}
DigestAuthenticationFilter.incorrectResponse=Incorrect response
DigestAuthenticationFilter.missingAuth=Missing mandatory digest value for 'auth' QOP; received header {0}
DigestAuthenticationFilter.missingMandatory=Missing mandatory digest value; received header {0}
DigestAuthenticationFilter.nonceCompromised=Nonce token compromised {0}
DigestAuthenticationFilter.nonceEncoding=Nonce is not encoded in Base64; received nonce {0}
DigestAuthenticationFilter.nonceExpired=Nonce has expired/timed out
DigestAuthenticationFilter.nonceNotNumeric=Nonce token should have yielded a numeric first token, but was {0}
DigestAuthenticationFilter.nonceNotTwoTokens=Nonce should have yielded two tokens but was {0}
DigestAuthenticationFilter.usernameNotFound=Username {0} not found
JdbcDaoImpl.noAuthority=User {0} has no GrantedAuthority
JdbcDaoImpl.notFound=User {0} not found
LdapAuthenticationProvider.badCredentials=Bad credentials
LdapAuthenticationProvider.credentialsExpired=User credentials have expired
LdapAuthenticationProvider.disabled=User is disabled
LdapAuthenticationProvider.expired=User account has expired
LdapAuthenticationProvider.locked=User account is locked
LdapAuthenticationProvider.emptyUsername=Empty username not allowed
LdapAuthenticationProvider.onlySupports=Only UsernamePasswordAuthenticationToken is supported
PasswordComparisonAuthenticator.badCredentials=Bad credentials
PersistentTokenBasedRememberMeServices.cookieStolen=Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.
ProviderManager.providerNotFound=No AuthenticationProvider found for {0}
RememberMeAuthenticationProvider.incorrectKey=The presented RememberMeAuthenticationToken does not contain the expected key
RunAsImplAuthenticationProvider.incorrectKey=The presented RunAsUserToken does not contain the expected key
SubjectDnX509PrincipalExtractor.noMatching=No matching pattern was found in subjectDN: {0}
SwitchUserFilter.noCurrentUser=No current user associated with this request
SwitchUserFilter.noOriginalAuthentication=Could not find original Authentication object
......@@ -3,6 +3,7 @@ package cn.sh.stc.sict.cloud.gateway;
import cn.sh.stc.sict.cloud.common.dynamic.gateway.annotation.EnableDynamicRoute;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @Description
......@@ -11,6 +12,7 @@ import org.springframework.cloud.client.SpringCloudApplication;
*/
@EnableDynamicRoute
@SpringCloudApplication
@EnableFeignClients(basePackages = {"cn.sh.stc.sict.cloud.common.gateway.feign"})
public class SictGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(SictGatewayApplication.class, args);
......
......@@ -9,9 +9,9 @@ spring:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7
namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
config:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7
namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
profiles:
......@@ -20,4 +20,4 @@ spring:
logging:
config: classpath:logback-spring.xml
file:
name: ../logs/${spring.application.name}/console.log
\ No newline at end of file
name: ../logs/${spring.application.name}/console.log
server:
port: 12998
spring:
application:
name: @artifactId@
# nacos
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
config:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
profiles:
active: dev
logging:
config: classpath:logback-spring.xml
file:
name: ../logs/${spring.application.name}/console.log
......@@ -63,7 +63,7 @@
<appender-ref ref="error"/>
</logger>
<!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 -->
<root level="INFO">
<root level="ERROR">
<appender-ref ref="console"/>
<appender-ref ref="debug"/>
</root>
......
......@@ -171,6 +171,9 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
<executions>
<execution>
<goals>
......
package cn.sh.stc.sict.cloud.upms.dto;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* @Description 当前登陆人信息
......@@ -19,6 +22,10 @@ public class CurrentUser implements Serializable {
private String appId;
private String idNum;
private String phone;
/**
* 医院公众号登陆的用户包含医院代码
*/
private String hospitalCode;
private Date createTime;
private Byte gender;
private Date registerTime;
......@@ -26,5 +33,14 @@ public class CurrentUser implements Serializable {
* sict_admin
*/
private String adminStr;
/**
* 香山中医公众号用户信息
*/
private String xszyUserInfo;
/**
* 机器人问答
*/
private String qaHistory;
}
......@@ -12,8 +12,24 @@ import lombok.Data;
@Data
public class UserInfo {
/**
* 登陆人openId
*/
private String openId;
/**
* 登陆人公众号appdId
*/
private String appId;
/**
* 医院公众号登陆的用户包含医院代码
*/
private String hospitalCode;
/**
* 香山中医公众号用户信息
*/
private String xszyUserInfo;
/**
* 用户基本信息
*/
......
......@@ -32,6 +32,11 @@ public class SysUserBase extends Model<SysUserBase> {
@ApiModelProperty(value = "用户id")
private Long id;
/**
* 公众号appId
*/
private String appId;
private String openId;
/**
......@@ -90,6 +95,11 @@ public class SysUserBase extends Model<SysUserBase> {
*/
@ApiModelProperty(hidden = true, value = "账号状态:0-正常,1-禁用")
private Byte status;
/**
* 来源
*/
private String source;
/**
*
*/
......@@ -137,6 +147,8 @@ public class SysUserBase extends Model<SysUserBase> {
@ApiModelProperty(hidden = true, value = "")
private Date updateTime;
private Date lastPwdTime;
/**
* 主键值
*/
......
package cn.sh.stc.sict.cloud.upms.config;
import cn.hutool.core.date.DateUtil;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 用户密码修改提示 配置属性
*/
@Data
@Component
@RefreshScope
@ConfigurationProperties(prefix = "user.pwd")
public class UserPwdProperties {
/**
* 是否进行密码修改提示
*/
private Boolean limitFlag;
/**
* 上次修改超过{{limitDays}}天,锁定用户
*/
private Integer limitDays;
/**
* 上次修改超过{{tipsDays}}天,开始提示用户修改密码
*/
private Integer tipsDays;
public boolean getTips(Date lastPwdTime) {
long offsetDays = DateUtil.betweenDay(lastPwdTime, DateUtil.date(), true);
if (offsetDays > tipsDays) {
return true;
}
return false;
}
}
package cn.sh.stc.sict.cloud.upms.controller.feign;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import cn.sh.stc.sict.cloud.upms.service.SysLogService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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 F_xh。
* @date 2020-12-27 11:34:55
*/
@Slf4j
@RestController
@RequestMapping("/feign/log")
@AllArgsConstructor
public class LogFeignController {
private final SysLogService sysLogService;
@PostMapping("/save")
private R<Boolean> saveLog(@RequestBody SysLog sysLog){
sysLogService.save(sysLog);
return new R(true);
}
}
......@@ -5,8 +5,9 @@ import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.security.annotation.Inner;
import cn.sh.stc.sict.cloud.upms.dto.UserInfo;
import cn.sh.stc.sict.cloud.upms.service.SysUserBaseService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
......@@ -20,12 +21,14 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/feign/user/base")
@AllArgsConstructor
public class UserFeignController {
@Autowired
private SysUserBaseService sysUserBaseService;
@Value("${default.sso.user:systemadmin}")
private String defaultSSOUser;
/**
* F_xh 根据用户名获取用户登录信息
*
* @param username
* @return
*/
......@@ -38,17 +41,22 @@ public class UserFeignController {
}
/**
* F_xh 根据移动端 inStr 获取用户登录信息
*
* @return
*/
@Inner
@GetMapping("/social/info/{appId}/{inStr}")
public R social(@PathVariable("appId") String appId,
@PathVariable("inStr") String inStr){
@PathVariable("inStr") String inStr) {
try {
UserInfo info = sysUserBaseService.getUserInfoBySocial(appId, inStr);
UserInfo info = new UserInfo();
if (inStr.contains("cs@token")) {
info = sysUserBaseService.getUserInfo(appId, defaultSSOUser);
} else {
info = sysUserBaseService.getUserInfoBySocial(appId, inStr);
}
return new R().success(info);
} catch (Exception e) {
e.printStackTrace();
......
package cn.sh.stc.sict.cloud.upms.controller.web;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.upms.service.HpRoleMenuService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.sh.stc.sict.cloud.common.core.util.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
......@@ -39,6 +41,7 @@ public class HpMenuController {
*/
@ApiOperation("分页查询 系统菜单表")
@GetMapping("/page")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R getHpMenuPage(Page page, HpMenu hpMenu) {
return new R<>(hpMenuService.page(page, Wrappers.query(hpMenu)));
}
......@@ -61,8 +64,10 @@ public class HpMenuController {
* @param hpMenu 系统菜单表
* @return R
*/
@SysLog
@ApiOperation("新增系统菜单表")
@PostMapping
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R save(@RequestBody HpMenu hpMenu) {
hpMenuService.saveOrUpdate(hpMenu);
return new R<>();
......@@ -73,8 +78,10 @@ public class HpMenuController {
*
* @return R
*/
@SysLog
@ApiOperation("删除系统菜单表")
@DeleteMapping("/{menuId}")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R removeById(@PathVariable Long menuId) {
if (hpRoleMenuService.exist(menuId)) {
return new R().error("不可删除!");
......
package cn.sh.stc.sict.cloud.upms.controller.web;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.upms.dto.RoleDTO;
import cn.sh.stc.sict.cloud.upms.model.HpMenu;
import cn.sh.stc.sict.cloud.upms.model.HpRole;
......@@ -14,8 +15,10 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
......@@ -46,6 +49,7 @@ public class HpRoleController {
*/
@ApiOperation("分页查询 系统角色表")
@GetMapping("/page")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R getHpRolePage(Page page, HpRole hpRole) {
return new R<>(hpRoleService.page(page, Wrappers.query(hpRole)));
}
......@@ -70,15 +74,19 @@ public class HpRoleController {
return new R<>(dto);
}
@SysLog
@ApiOperation("新增/修改系统角色")
@PostMapping
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R save(@RequestBody RoleDTO dto) {
hpRoleService.saveDto(dto);
return new R<>();
}
@SysLog
@ApiOperation("删除系统角色表")
@DeleteMapping("/{id}")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R removeById(@PathVariable Long id) {
// 判断是否可删除
if(hpUserRoleService.exist(id)){
......
package cn.sh.stc.sict.cloud.upms.controller.web;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import cn.sh.stc.sict.cloud.upms.service.SysLogService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.sh.stc.sict.cloud.common.core.util.R;
......@@ -29,24 +31,31 @@ public class SysLogController {
/**
* 分页查询
* @param page 分页对象
*
* @param page 分页对象
* @param sysLog 系统日志
* @return
*/
@ApiOperation("分页查询 系统日志")
@GetMapping("/page")
public R getSysLogPage(Page page, SysLog sysLog) {
return new R<>(sysLogService.page(page,Wrappers.query(sysLog)));
LambdaQueryWrapper<SysLog> wrapper = Wrappers.lambdaQuery();
wrapper.like(StrUtil.isNotBlank(sysLog.getTitle()), SysLog::getTitle, sysLog.getTitle())
.like(StrUtil.isNotBlank(sysLog.getMethod()), SysLog::getMethod, sysLog.getMethod())
.like(StrUtil.isNotBlank(sysLog.getParams()), SysLog::getParams, sysLog.getParams())
.orderByDesc(SysLog::getCreateTime);
return new R<>(sysLogService.page(page, wrapper));
}
/**
* 通过id查询系统日志
*
* @param id id
* @return R
*/
@ApiOperation("通过id查询 系统日志")
@GetMapping("/{id}")
public R getById(@PathVariable("id") Long id){
public R getById(@PathVariable("id") Long id) {
return new R<>(sysLogService.getById(id));
}
......
package cn.sh.stc.sict.cloud.upms.controller.web;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.enums.BizCodeConstant;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.config.UserPwdProperties;
import cn.sh.stc.sict.cloud.upms.dto.ChangePasswordDTO;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.cloud.upms.dto.UserDTO;
import cn.sh.stc.sict.cloud.upms.model.HpMenu;
......@@ -17,6 +24,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.sh.stc.sict.cloud.common.core.util.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
......@@ -50,30 +58,37 @@ public class SysUserBaseController {
* 3. 角色配置
* 4. 重置密码(加密处理)
*/
private SysUserBaseService sysUserBaseService;
private HpRoleService hpRoleService;
private HpUserRoleService hpUserRoleService;
private HpMenuService hpMenuService;
private final SysUserBaseService sysUserBaseService;
private final HpRoleService hpRoleService;
private final HpUserRoleService hpUserRoleService;
private final HpMenuService hpMenuService;
private final UserPwdProperties userPwdProperties;
private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
@ApiOperation("分页查询 系统基础用户表")
@GetMapping("/page")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R getSysUserBasePage(Page page, SysUserBase sysUserBase) {
return new R<>(sysUserBaseService.page(page, Wrappers.query(sysUserBase)));
}
@SysLog
@ApiOperation("新增/修改用户")
@PostMapping
public R save(@RequestBody SysUserBase userBase) {
if (NumberUtil.isNullOrZero(userBase.getId())) {
if(StrUtil.isBlank(userBase.getUserName())){
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R save(@RequestBody SysUserBase user) {
if (NumberUtil.isNullOrZero(user.getId())) {
if (StrUtil.isBlank(user.getUserName())) {
return new R().error("用户名不可为空!");
}
String pw = StrUtil.isBlank(userBase.getPasswd()) ? Constant.DEFAULT_PASSWORD : userBase.getPasswd();
userBase.setPasswd(ENCODER.encode(pw));
String pw = StrUtil.isBlank(user.getPasswd()) ? Constant.DEFAULT_PASSWORD : user.getPasswd();
user.setPasswd(ENCODER.encode(pw));
}
userBase.setStatus(Constant.BYTE_NO);
sysUserBaseService.saveOrUpdate(userBase);
if (sysUserBaseService.exist(user)) {
return new R().error("相同用户名用户已经存在!");
}
user.setStatus(Constant.BYTE_NO);
sysUserBaseService.saveOrUpdate(user);
return new R<>();
}
......@@ -94,7 +109,7 @@ public class SysUserBaseController {
@ApiOperation("获取当前用户信息")
@GetMapping("/info/current")
public R getCurrentUserInfo(){
public R getCurrentUserInfo() {
CurrentUser current = SecurityUtils.getCurrentUser();
if (current == null) {
return new R().error("无登录信息!");
......@@ -109,13 +124,18 @@ public class SysUserBaseController {
dto.setUser(user);
dto.setRoleList(roleList);
dto.setMenuList(menuList);
return new R(dto);
if (userPwdProperties.getLimitFlag() && ObjectUtil.isNotNull(user.getLastPwdTime()) && userPwdProperties.getTips(user.getLastPwdTime())) {
return new R(dto).setBizCode(BizCodeConstant.USER_PWD_LIMIT.getCode());
} else {
return new R(dto);
}
}
@SysLog
@ApiOperation("设置用户角色信息")
@PostMapping("/role")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R saveUserRole(@RequestBody UserDTO dto) {
if (NumberUtil.isNullOrZero(dto.getUser().getId())) {
return new R().error("用户id不可为空!");
......@@ -124,13 +144,63 @@ public class SysUserBaseController {
return new R();
}
@SysLog
@ApiOperation("修改用户密码")
@PutMapping("/password")
public R<?> changePassword(@RequestBody ChangePasswordDTO password) {
if (StrUtil.isBlank(password.getNewPassword()) || StrUtil.isBlank(password.getOldPassword())) {
return new R<>().error("新密码或旧密码不能为空!");
}
if (StrUtil.equals(password.getNewPassword(), password.getOldPassword())) {
return new R<>().error("新密码不能与旧密码相同!");
}
SictUser user = SecurityUtils.getUser();
SysUserBase userBase = sysUserBaseService.getById(user.getId());
if (userBase == null) {
return new R<>().error("用户不存在!");
}
if (!ENCODER.matches(password.getOldPassword(), userBase.getPasswd())) {
return new R<>().error("旧密码不正确!");
}
userBase.setPasswd(ENCODER.encode(password.getNewPassword()));
userBase.setLastPwdTime(DateUtil.date());
sysUserBaseService.updateById(userBase);
sysUserBaseService.initRedisByUserName(userBase.getUserName());
return new R<>().success("");
}
@SysLog
@ApiOperation("重置密码")
@PutMapping("/reset/password")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R<?> resetPassword(@RequestParam("userId") Long userId) {
SysUserBase user = sysUserBaseService.getById(userId);
if (ObjectUtil.isNull(user) || NumberUtil.isNullOrZero(user.getId())) {
return new R<>().error("未找到用户信息!");
}
SysUserBase update = new SysUserBase();
update.setId(userId);
update.setPasswd(ENCODER.encode(Constant.DEFAULT_PASSWORD));
update.setLastPwdTime(DateUtil.date());
sysUserBaseService.updateById(update);
sysUserBaseService.initRedisByUserName(user.getUserName());
return new R<>().success("");
}
/**
* 通过id删除系统基础用户表
*
* @return R
*/
@SysLog
@ApiOperation("删除系统基础用户表")
@DeleteMapping("/{userId}")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
@Transactional(rollbackFor = Exception.class)
public R removeById(@PathVariable Long userId) {
hpUserRoleService.removeByUserId(userId);
......
package cn.sh.stc.sict.cloud.upms.controller.web;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.upms.model.SysWxLog;
import cn.sh.stc.sict.cloud.upms.service.SysWxLogService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 系统日志
*
* @author F_xh。
* @date 2020-12-27 11:34:55
*/
@RestController
@RequestMapping("/wx/syslog")
@AllArgsConstructor
@Slf4j
@Api(tags = "C端系统日志")
public class SysWxLogController {
private SysWxLogService sysWxLogService;
/**
* 分页查询
*
* @param page 分页对象
* @return
*/
@ApiOperation("分页查询 系统日志")
@GetMapping("/page")
public R getSysLogPage(Page page, SysWxLog sysWxLog) {
LambdaQueryWrapper<SysWxLog> wrapper = Wrappers.lambdaQuery();
wrapper.like(StrUtil.isNotBlank(sysWxLog.getTitle()), SysWxLog::getTitle, sysWxLog.getTitle())
.like(StrUtil.isNotBlank(sysWxLog.getMethod()), SysWxLog::getMethod, sysWxLog.getMethod())
.like(StrUtil.isNotBlank(sysWxLog.getParams()), SysWxLog::getParams, sysWxLog.getParams())
.orderByDesc(SysWxLog::getCreateTime);
return new R<>(sysWxLogService.page(page, wrapper));
}
/**
* 通过id查询系统日志
*
* @param id id
* @return R
*/
@ApiOperation("通过id查询 系统日志")
@GetMapping("/{id}")
public R getById(@PathVariable("id") Long id) {
return new R<>(sysWxLogService.getById(id));
}
/**
* 新增系统日志
* @param sysLog 系统日志
* @return R
*/
// @ApiOperation("新增系统日志")
// @PostMapping
// public R save(@RequestBody SysLog sysLog){
// return new R<>(sysLogService.save(sysLog));
// }
/**
* 修改系统日志
* @param sysLog 系统日志
* @return R
*/
// @ApiOperation("修改系统日志")
// @PutMapping
// public R updateById(@RequestBody SysLog sysLog){
// return new R<>(sysLogService.updateById(sysLog));
// }
/**
* 通过id删除系统日志
* @param id id
* @return R
*/
// @ApiOperation("删除系统日志")
// @DeleteMapping("/{id}")
// public R removeById(@PathVariable Long id){
// return new R<>(sysLogService.removeById(id));
// }
}
package cn.sh.stc.sict.cloud.upms.dao;
import cn.sh.stc.sict.cloud.upms.model.SysWxLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 系统日志
*
* @author F_xh
* @date 2020-12-27 11:34:55
*/
@Mapper
public interface SysWxLogMapper extends BaseMapper<SysWxLog> {
}
package cn.sh.stc.sict.cloud.upms.dto;
import lombok.Data;
/**
* @author 75
* @Description
* @Date 2021/5/17 11:00
**/
@Data
public class ChangePasswordDTO {
private Long userId;
private String oldPassword;
private String newPassword;
}
package cn.sh.stc.sict.cloud.upms.model;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
/**
* C端-系统日志
*
* @author F_xh
* @date 2020-12-27 11:34:55
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_wx_log")
public class SysWxLog extends Model<SysWxLog> {
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId
@ApiModelProperty(hidden = false, value = "")
private Long id;
/**
*
*/
@ApiModelProperty(hidden = false, value = "")
private Byte type;
/**
*
*/
@ApiModelProperty(hidden = false, value = "")
private String title;
/**
*
*/
@ApiModelProperty(hidden = false, value = "")
private String serviceId;
/**
*
*/
@ApiModelProperty(hidden = false, value = "")
private String remoteAddr;
/**
*
*/
@ApiModelProperty(hidden = false, value = "")
private String createBy;
/**
*
*/
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(hidden = true, value = "")
private Long createUserId;
/**
*
*/
@ApiModelProperty(hidden = true, value = "")
private String userAgent;
/**
*
*/
@ApiModelProperty(hidden = true, value = "")
private String requestUri;
/**
*
*/
@ApiModelProperty(hidden = true, value = "")
private String method;
/**
*
*/
@ApiModelProperty(hidden = true, value = "")
private String params;
/**
*
*/
@ApiModelProperty(hidden = true, value = "")
private Long time;
/**
*
*/
@ApiModelProperty(hidden = true, value = "")
private String exception;
/**
*
*/
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(hidden = true, value = "")
private Date createTime;
/**
* 主键值
*/
@Override
protected Serializable pkVal() {
return this.id;
}
}
......@@ -18,5 +18,9 @@ public interface SysUserBaseService extends IService<SysUserBase> {
UserInfo getUserInfoBySocial(String appId, String inStr) throws WxErrorException;
boolean saveDto(UserDTO dto);
boolean exist(SysUserBase user);
void initRedisByUserName(String userName);
}
package cn.sh.stc.sict.cloud.upms.service;
import cn.sh.stc.sict.cloud.upms.model.SysWxLog;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* 系统日志
*
* @author F_xh
* @date 2020-12-27 11:34:55
*/
public interface SysWxLogService extends IService<SysWxLog> {
}
package cn.sh.stc.sict.cloud.upms.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import cn.sh.stc.sict.cloud.common.core.constant.UserConstant;
import cn.sh.stc.sict.cloud.common.core.constant.enums.LoginTypeEnum;
import cn.sh.stc.sict.cloud.common.core.dto.WDUserInfo;
import cn.sh.stc.sict.cloud.common.core.dto.WOAWDUserInfo;
import cn.sh.stc.sict.cloud.common.core.dto.WOAZzUserInfo;
import cn.sh.stc.sict.cloud.common.core.dto.XSZYUserInfo;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.core.util.SsbUtil;
import cn.sh.stc.sict.cloud.common.core.util.WoaUtil;
import cn.sh.stc.sict.cloud.upms.dao.SysUserBaseMapper;
import cn.sh.stc.sict.cloud.upms.dto.UserDTO;
import cn.sh.stc.sict.cloud.upms.dto.UserInfo;
import cn.sh.stc.sict.cloud.upms.model.HpUserRole;
import cn.sh.stc.sict.cloud.upms.model.HpRole;
import cn.sh.stc.sict.cloud.upms.model.SysUserBase;
import cn.sh.stc.sict.cloud.upms.service.HpRoleService;
import cn.sh.stc.sict.cloud.upms.service.HpUserRoleService;
import cn.sh.stc.sict.cloud.upms.service.SysUserBaseService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Slf4j
@Service("sysUserBaseService")
@AllArgsConstructor
......@@ -28,6 +50,9 @@ public class SysUserBaseServiceImpl extends ServiceImpl<SysUserBaseMapper, SysUs
private final SysUserBaseMapper sysUserBaseMapper;
private WxMpService wxMpService;
private HpUserRoleService hpUserRoleService;
private HpRoleService hpRoleService;
private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
private final StringRedisTemplate stringRedisTemplate;
@Override
public UserInfo getUserInfo(String appId, String username) {
......@@ -39,6 +64,14 @@ public class SysUserBaseServiceImpl extends ServiceImpl<SysUserBaseMapper, SysUs
UserInfo info = new UserInfo();
info.setSysUserBase(user);
info.setOpenId(user.getOpenId());
List<HpRole> roleList = hpRoleService.listByUserId(user.getId());
if (CollUtil.isNotEmpty(roleList)) {
// 设置角色列表 (ID)
List<String> roleIds = roleList.stream().map(HpRole::getRoleCode)
.collect(Collectors.toList());
info.setRoles(ArrayUtil.toArray(roleIds, String.class));
}
return info;
}
return null;
......@@ -49,25 +82,309 @@ public class SysUserBaseServiceImpl extends ServiceImpl<SysUserBaseMapper, SysUs
log.error("=================> appId = {}, inStr = {}", appId, inStr);
// code = 011Eg6Ga1UOXeA0R5wHa16dkab2Eg6G7
String[] split = inStr.split(StringPool.AT);
if(LoginTypeEnum.SMS.getType().equals(split[0])){
LoginTypeEnum loginType = Optional.ofNullable(LoginTypeEnum.match(split[0])).orElse(LoginTypeEnum.WECHAT);
switch (loginType) {
// 手机号登录
return this.getByPhone(split[2]);
}else{
case SMS:
return this.getByPhone(split[2]);
// 随身办登陆
case SSB:
return this.getBySSBToken(split[0], split[2], split[1]);
// 香山中医院公众号登陆
// inStr = 公众号标识符@公众号appId@token@hospitalCode
case WOA_NL:
return this.getByXszyWoa(split);
// 中智公众号登录
case WOA_ZZ:
return this.getWoaZzUserInfoByToken(split);
// 万达公众号登录
case WOA_WD:
return this.getWoaWDUserInfoByToken(split);
// 万达南东公众号登录
case WOA_ND:
return this.getWoaWDNDUserInfoByToken(split);
// 微信登录
WxOAuth2AccessToken token = wxMpService.getOAuth2Service().getAccessToken(split[2]);
return this.getByOpenId(token.getOpenId());
default:
WxOAuth2AccessToken token = wxMpService.getOAuth2Service().getAccessToken(split[2]);
return this.getByOpenId(token.getOpenId());
}
}
/**
* 获取香山中医医院公众号的用户信息
*
* @param infoArray 登陆信息 ["公众号标识符", "公众号appId", "token"]
* @return
*/
private UserInfo getByXszyWoa(String[] infoArray) {
String source = infoArray[0];
String appId = infoArray[1];
String token = infoArray[2];
String hospitalCode = infoArray[3];
XSZYUserInfo xszyUserInfo = WoaUtil.getXszyUserInfo(token);
if (ObjectUtil.isNull(xszyUserInfo) || StrUtil.isBlank(xszyUserInfo.getUserId())) {
return null;
}
// 传参包含卡号卡类型单独配置
if (infoArray.length == 6) {
xszyUserInfo.setMediCardId(infoArray[4]);
xszyUserInfo.setMediCardType(XSZYUserInfo.fromNlType(infoArray[5]));
}
String xszyUserInfoStr = JSONUtil.toJsonStr(xszyUserInfo);
log.error("woa.login.xszyUser = {}", xszyUserInfoStr);
// 根据用户ID和手机号查询当前用户是否已注册过
LambdaQueryWrapper<SysUserBase> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUserBase::getOpenId, xszyUserInfo.getUserId())
.or()
.eq(SysUserBase::getPhone, xszyUserInfo.getMobile())
.orderByDesc(SysUserBase::getUpdateTime)
.last("limit 1");
SysUserBase user = this.getOne(wrapper);
// 未注册用户默认注册
if (user == null) {
user = new SysUserBase();
user.setUserName(xszyUserInfo.getMobile());
user.setOpenId(xszyUserInfo.getUserId());
user.setName(xszyUserInfo.getPatientName());
// 证件类型为1时,证件号为身份证号
if (Constant.STRING_YES.equals(xszyUserInfo.getCertificateType())) {
user.setIdCard(xszyUserInfo.getCertificate());
}
//user.setSex(userInfo.getGender());
user.setHeadimg(Constant.DEFAULT_AVATAR_IMG);
user.setSource(source);
user.setStatus(Constant.BYTE_NO);
user.setPasswd(ENCODER.encode(Constant.DEFAULT_PASSWORD));
user.setPhone(xszyUserInfo.getMobile());
user.setAppId(appId);
this.save(user);
}
UserInfo info = new UserInfo();
info.setSysUserBase(user);
info.setOpenId(xszyUserInfo.getUserId());
// 设置医疗机构代码,后续查询只显示当前医疗机构下的查询结果
info.setHospitalCode(hospitalCode);
info.setXszyUserInfo(xszyUserInfoStr);
return info;
}
private UserInfo getBySSBToken(String source, String token, String appId) {
WDUserInfo wdUser = SsbUtil.getUserInfo(token);
log.error("ssb.login.wdUser = {}", JSONUtil.toJsonStr(wdUser));
if (ObjectUtil.isNull(wdUser) || StrUtil.isBlank(wdUser.getMobile())) {
return null;
}
LambdaQueryWrapper<SysUserBase> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUserBase::getPhone, wdUser.getMobile());
SysUserBase user = this.getOne(wrapper);
// 未注册用户默认注册
if (user == null) {
user = new SysUserBase();
user.setUserName(wdUser.getUsername());
user.setOpenId(wdUser.getMobile());
user.setName(wdUser.getName());
user.setIdCard(wdUser.getPersoncard());
user.setSex(wdUser.getGender());
user.setHeadimg(wdUser.getAvatar());
user.setSource(source);
user.setStatus(Constant.BYTE_NO);
user.setPasswd(ENCODER.encode(Constant.DEFAULT_PASSWORD));
user.setPhone(wdUser.getMobile());
user.setAppId(appId);
this.save(user);
// List<WDUserCardInfo> cardList = SsbUtil.getUserCardInfoList(token);
}
UserInfo info = new UserInfo();
info.setSysUserBase(user);
info.setOpenId(wdUser.getMobile());
info.setAppId(appId);
return info;
}
private UserInfo getWoaZzUserInfoByToken(String[] infoArray) {
String source = infoArray[0];
String appId = infoArray[1];
String token = infoArray[2];
String hospitalCode = infoArray[3];
WOAZzUserInfo zzUserInfo = WoaUtil.getZzUserInfo(appId, token);
String zzUserInfoStr = JSONUtil.toJsonStr(zzUserInfo);
log.error("woa.login.zzUser = {}", zzUserInfoStr);
if (ObjectUtil.isNull(zzUserInfo) || StrUtil.isBlank(zzUserInfo.getId())) {
return null;
}
// 根据用户ID和手机号查询当前用户是否已注册过
LambdaQueryWrapper<SysUserBase> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUserBase::getOpenId, zzUserInfo.getId())
.or()
.eq(SysUserBase::getPhone, zzUserInfo.getMobile())
.orderByDesc(SysUserBase::getUpdateTime)
.last("limit 1");
SysUserBase user = this.getOne(wrapper);
// 未注册用户默认注册
if (user == null) {
user = new SysUserBase();
user.setUserName(zzUserInfo.getMobile());
user.setOpenId(zzUserInfo.getId());
user.setName(zzUserInfo.getUsername());
user.setIdCard(zzUserInfo.getPersoncard());
user.setSex(zzUserInfo.getGender());
user.setHeadimg(zzUserInfo.getAvator());
user.setSource(source);
user.setStatus(Constant.BYTE_NO);
user.setPasswd(ENCODER.encode(Constant.DEFAULT_PASSWORD));
user.setPhone(zzUserInfo.getMobile());
user.setAppId(appId);
this.save(user);
}
UserInfo info = new UserInfo();
info.setSysUserBase(user);
info.setAppId(appId);
info.setOpenId(zzUserInfo.getId());
// 设置医疗机构代码,后续查询只显示当前医疗机构下的查询结果
info.setHospitalCode(hospitalCode);
return info;
}
private UserInfo getWoaWDUserInfoByToken(String[] infoArray) {
String source = infoArray[0];
String appId = infoArray[1];
String token = infoArray[2];
String hospitalCode = infoArray[3];
WOAWDUserInfo userInfo = WoaUtil.getWoaWDUserInfo(token);
String userInfoStr = JSONUtil.toJsonStr(userInfo);
log.error("woa.login.wdUser = {}", userInfoStr);
if (ObjectUtil.isNull(userInfo) || StrUtil.isBlank(userInfo.getId())) {
return null;
}
// 根据用户ID和手机号查询当前用户是否已注册过
LambdaQueryWrapper<SysUserBase> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUserBase::getOpenId, userInfo.getId())
.or()
.eq(SysUserBase::getPhone, userInfo.getMobile())
.orderByDesc(SysUserBase::getUpdateTime)
.last("limit 1");
SysUserBase user = this.getOne(wrapper);
// 未注册用户默认注册
if (user == null) {
user = new SysUserBase();
user.setUserName(userInfo.getMobile());
user.setOpenId(userInfo.getId());
user.setName(userInfo.getUsername());
user.setIdCard(userInfo.getPersoncard());
user.setSex(userInfo.getGender());
user.setHeadimg(userInfo.getAvator());
user.setSource(source);
user.setStatus(Constant.BYTE_NO);
user.setPasswd(ENCODER.encode(Constant.DEFAULT_PASSWORD));
user.setPhone(userInfo.getMobile());
user.setAppId(appId);
this.save(user);
}
UserInfo info = new UserInfo();
info.setSysUserBase(user);
info.setOpenId(userInfo.getId());
// 设置医疗机构代码,后续查询只显示当前医疗机构下的查询结果
info.setHospitalCode(hospitalCode);
return info;
}
private UserInfo getWoaWDNDUserInfoByToken(String[] infoArray) {
String source = infoArray[0];
String appId = infoArray[1];
String token = infoArray[2];
String hospitalCode = infoArray[3];
WOAWDUserInfo userInfo = WoaUtil.getThirdPartyUserInfo(token);
String userInfoStr = JSONUtil.toJsonStr(userInfo);
log.error("woa.login.wdndUser = {}", userInfoStr);
if (ObjectUtil.isNull(userInfo) || StrUtil.isBlank(userInfo.getId())) {
return null;
}
// 根据用户ID和手机号查询当前用户是否已注册过
LambdaQueryWrapper<SysUserBase> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUserBase::getOpenId, userInfo.getId())
.or()
.eq(SysUserBase::getPhone, userInfo.getMobile())
.orderByDesc(SysUserBase::getUpdateTime)
.last("limit 1");
SysUserBase user = this.getOne(wrapper);
// 未注册用户默认注册
if (user == null) {
user = new SysUserBase();
user.setUserName(userInfo.getMobile());
user.setOpenId(userInfo.getId());
user.setName(userInfo.getUsername());
user.setIdCard(userInfo.getPersoncard());
user.setSex(userInfo.getGender());
user.setHeadimg(userInfo.getAvator());
user.setSource(source);
user.setStatus(Constant.BYTE_NO);
user.setPasswd(ENCODER.encode(Constant.DEFAULT_PASSWORD));
user.setPhone(userInfo.getMobile());
user.setAppId(appId);
this.save(user);
}
UserInfo info = new UserInfo();
info.setSysUserBase(user);
info.setOpenId(userInfo.getId());
// 设置医疗机构代码,后续查询只显示当前医疗机构下的查询结果
info.setHospitalCode(hospitalCode);
return info;
}
@Override
public boolean saveDto(UserDTO dto) {
if(NumberUtil.isNotNullOrZero(dto.getUser().getId())){
if (NumberUtil.isNotNullOrZero(dto.getUser().getId())) {
hpUserRoleService.saveBatch(dto.getUser().getId(), dto.getRoleList());
}
return true;
}
@Override
public boolean exist(SysUserBase user) {
if (StrUtil.isBlank(user.getUserName())) {
return false;
}
LambdaQueryWrapper<SysUserBase> wrapper = Wrappers.lambdaQuery();
wrapper.ne(NumberUtil.isNotNullOrZero(user.getId()), SysUserBase::getId, user.getId())
.eq(SysUserBase::getUserName, user.getUserName());
return this.count(wrapper) > 0;
}
@Override
public void initRedisByUserName(String userName) {
String key = RedisCacheConstant.USER_DETAILS + "::" + userName + ":*";
stringRedisTemplate.delete(stringRedisTemplate.keys(key));
}
private UserInfo getByPhone(String phone) {
LambdaQueryWrapper<SysUserBase> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUserBase::getPhone, phone);
......@@ -77,7 +394,8 @@ public class SysUserBaseServiceImpl extends ServiceImpl<SysUserBaseMapper, SysUs
user = new SysUserBase();
user.setOpenId(phone);
user.setStatus(Constant.BYTE_NO);
user.setPasswd(Constant.DEFAULT_PASSWORD);
user.setSource(UserConstant.USER_SOURCE_MOBILE);
user.setPasswd(ENCODER.encode(Constant.DEFAULT_PASSWORD));
user.setPhone(phone);
this.save(user);
}
......
package cn.sh.stc.sict.cloud.upms.service.impl;
import cn.sh.stc.sict.cloud.upms.dao.SysWxLogMapper;
import cn.sh.stc.sict.cloud.upms.model.SysWxLog;
import cn.sh.stc.sict.cloud.upms.service.SysWxLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
@Service("sysWxLogService")
@AllArgsConstructor
public class SysWxLogServiceImpl extends ServiceImpl<SysWxLogMapper, SysWxLog> implements SysWxLogService {
private final SysWxLogMapper sysWxLogMapper;
}
......@@ -11,9 +11,9 @@ spring:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7
namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
config:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7
namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
profiles:
......
server:
port: 12256
spring:
application:
name: @artifactId@
main:
allow-bean-definition-overriding: true
# nacos
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
config:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
profiles:
active: dev
......@@ -16,7 +16,10 @@
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-data</artifactId>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-log</artifactId>
</dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-minio</artifactId>
......@@ -32,6 +35,15 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!--undertow容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
......
......@@ -4,13 +4,17 @@ import cn.sh.stc.sict.cloud.common.security.annotation.EnableSictFeignClients;
import cn.sh.stc.sict.cloud.common.security.annotation.EnableSictResourceServer;
import cn.sh.stc.sict.cloud.common.swagger.annotation.EnableSictSwagger2;
import org.springframework.boot.SpringApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @author F_xh
*/
@EnableAsync
@EnableCaching
@EnableScheduling
@EnableSictSwagger2
@SpringCloudApplication
......
package cn.sh.stc.sict.theme.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author gao
* @date 2023/05/30 13:50
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SecurityParameter {
/**
* 入参是否解密,默认解密
*/
boolean inDecode() default true;
/**
* 出参是否加密,默认加密
*/
boolean outEncode() default true;
}
package cn.sh.stc.sict.theme.common.crypto;
import lombok.Data;
/**
* @author gao
* @date 2023/05/30 13:49
*/
@Data
public class EncryptionRequest {
/**
* rsa加密后的aes秘钥
*/
private String encryptionKey;
/**
*aes加密后的数据内容
*/
private String encryptionData;
}
package cn.sh.stc.sict.theme.common.crypto;
/**
* @author gao
* @date 2023/05/30 13:59
*/
public class EncryptionResponse {
}
package cn.sh.stc.sict.theme.common.crypto;
import cn.hutool.core.io.IoUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.AES;
import cn.sh.stc.sict.cloud.common.core.util.CryptUtil;
import java.io.InputStream;
/**
* @author gao
* @date 2023/05/30 13:48
*/
public class EncryptionUtil {
private static final String SIGN_TYPE_RSA = "RSA";
private static final int DEFAULT_RSA_KEY_SIZE = 1024;
private static final String DEFAULT_AES_KEY = "1qaz@WSX3edc$RFV";
public static final String PRIVATE_KEY = "MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAjQnqX7O3S6eDLzw4tw9K2IsWUuS9WCptg32AmaNMN+1YawmqDVOtrnkOyECZleuir62Y6ptw8yN0cyYzMFezDQIDAQABAkB9c5Jr6flia+/+Nfzkp8+VabJDrX7WS3b5/MpE3sHPBBQ/9HhAyg7k/MHTFZ8wScziFLPQ/wb6+szacNvA1RrpAiEA2Ei7JY6L/dv9hQ+YKYblCeGIQG8FUi4Uy7xheg1M/ZMCIQCm7/xBJCMubyyKHgRXr6MonqPdu2IE51IqmerXQV/w3wIgZ9jMGuVNrC8zk+7/5XiCgnMKg72KtYGwtH4X4419WQcCIExumHpix1DdSfE66RYUrolMiQ5eWvSPzMkAi8tefUTVAiB6F4fXbtKbqpJxW5dQttJl0RsEB39HGgOjy4mLaYZgvg==";
public static final String PUBLIC_KEY = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI0J6l+zt0ungy88OLcPStiLFlLkvVgqbYN9gJmjTDftWGsJqg1Tra55DshAmZXroq+tmOqbcPMjdHMmMzBXsw0CAwEAAQ==";
// 创建rsa加密对象 服务端公钥是不需要的,公钥提供给前端就行
private final static cn.hutool.crypto.asymmetric.RSA RSA = new RSA(PRIVATE_KEY, PUBLIC_KEY);
/**
* 获取加密返回
*/
public static String getEncodeResponse(String encryptionData) {
// return Base64.encode(encryptionData);
return CryptUtil.toAES(encryptionData, DEFAULT_AES_KEY);
}
/**
* 获取解密返回流
*/
public static InputStream getDecodeInputStream(EncryptionRequest request) {
String encryptionKey = request.getEncryptionKey();
// rsa解密 获取aes秘钥
byte[] decryptKey = RSA.decrypt(encryptionKey, KeyType.PrivateKey);
// aes进行解密内容 获取输入流(方便整合springMVC)
AES aes = SecureUtil.aes(decryptKey);
byte[] decryptData = aes.decrypt(request.getEncryptionData());
return IoUtil.toStream(decryptData);
}
// public static void main(String[] args) {
// KeyPair kp = SecureUtil.generateKeyPair(SIGN_TYPE_RSA, DEFAULT_RSA_KEY_SIZE);
// PublicKey pbkey = kp.getPublic();
// PrivateKey prkey = kp.getPrivate();
// String pubkey = (new BASE64Encoder()).encode(pbkey.getEncoded());
// String prikey = (new BASE64Encoder()).encode(prkey.getEncoded());
// //logger.info("{}生成秘钥成功,公钥:{},私钥:{}",appkey,pubkey,prikey);
// Map map = new HashMap();
// map.put("pub", pubkey);
// map.put("pri", prikey);
//
// }
}
package cn.sh.stc.sict.theme.common.rsa;
import lombok.Data;
/**
* @author gao
* @date 2023/05/30 11:16
*/
@Data
public class RSADecodeData {
/**
* Aes密钥
*/
private String key;
/**
* 偏移量
*/
private String keyVI;
/**
* 时间
*/
private String time;
}
package cn.sh.stc.sict.theme.config;
import cn.sh.stc.sict.theme.common.crypto.EncryptionRequest;
import cn.sh.stc.sict.theme.common.crypto.EncryptionUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
/**
* @author gao
* @date 2023/05/30 13:55
*/
@Slf4j
@ControllerAdvice
@RequiredArgsConstructor
public class DecodeRequestAdvice implements RequestBodyAdvice {
private final ObjectMapper objectMapper;
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
// 判断方法是否需要进行解密
return true;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
// 读取body对象,获取EncryptionRequest对象
InputStream body = httpInputMessage.getBody();
EncryptionRequest encryptionRequest = objectMapper.readValue(body, EncryptionRequest.class);
if (encryptionRequest.getEncryptionKey() == null) {
throw new IllegalArgumentException("encryption error,request is null");
}
// 转换成解密后的HttpInputMessage对象
return new HttpInputMessage() {
@Override
public HttpHeaders getHeaders() {
return httpInputMessage.getHeaders();
}
// 解密后的输入流
@Override
public InputStream getBody() {
return EncryptionUtil.getDecodeInputStream(encryptionRequest);
}
};
}
@Override
public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return o;
}
@Override
public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return o;
}
}
package cn.sh.stc.sict.theme.config;
import cn.sh.stc.sict.theme.annotation.SecurityParameter;
import cn.sh.stc.sict.theme.common.crypto.EncryptionUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* @author gao
* @date 2023/05/30 13:52
*/
@Slf4j
@ControllerAdvice
public class EncodeResponseAdvice implements ResponseBodyAdvice {
@Autowired
private ObjectMapper objectMapper;
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
// 方法上有SecurityParameter注解的进行加密 根据需求可以在判断SecurityParameter注解中的outEncode是否为true
// 这里返回true对所有接口返回结果加密,可能影响swagger显示
return true;
}
@Override
public Object beforeBodyWrite(Object o,
MethodParameter methodParameter,
MediaType mediaType,
Class aClass,
ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse) {
try {
// 要支持接口返回string的话,response需要序列化成string对象,因为接口返回string和对象使用消息转换器不是一样的
// 把返回结果序列化成json
String dataJson = objectMapper.writeValueAsString(o);
// 进行加密返回
return EncryptionUtil.getEncodeResponse(dataJson);
} catch (JsonProcessingException e) {
log.error("json processing error", e);
}
return o;
}
}
package cn.sh.stc.sict.theme.hpgp.controller.mobile;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.hpgp.model.HpAppointmentEva;
import cn.sh.stc.sict.theme.hpgp.service.HpAppointmentEvaService;
import cn.sh.stc.sict.theme.hphy.model.HpAppointment;
import cn.sh.stc.sict.theme.hphy.service.HpAppointmentService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
@Slf4j
@RestController
@AllArgsConstructor
@Api(tags = "[C]预约评价")
@RequestMapping("/hp/app/eva")
public class HpAppointmentEvaController {
/**
* 1. 已评价 page
* 2. 待评价 page
* 3. 评价
*/
private final HpAppointmentService hpAppointmentService;
private final HpAppointmentEvaService hpAppointmentEvaService;
@ApiOperation("已评价 分页")
@GetMapping("/eaved/page")
public R hasEavedPage(Page page, @RequestParam("patientId") Long patientId) {
LambdaQueryWrapper<HpAppointmentEva> wrapper = Wrappers.lambdaQuery();
wrapper.eq(HpAppointmentEva::getPatientId, patientId);
return new R(hpAppointmentEvaService.page(page, wrapper));
}
@ApiOperation("待评价 分页")
@GetMapping("/todo/eav/page")
public R toBeEavPage(Page page, @RequestParam("patientId") Long patientId) {
page = hpAppointmentEvaService.toBeEavPage(page, patientId);
return new R(page);
}
@SysLog
@ApiOperation("评价")
@PostMapping("/eva")
@Transactional(rollbackFor = Exception.class)
public R eav(@RequestBody HpAppointmentEva eva) {
if(NumberUtil.isNullOrZero(eva.getAppId())){
return new R().error("appId 不可为空!");
}
if(NumberUtil.isNullOrZero(eva.getPatientId())){
return new R().error("patientId 不可为空!");
}
HpAppointment app = hpAppointmentService.getById(eva.getAppId());
if(ObjectUtil.isNull(app)){
return new R().error("未找到预约记录!");
}
if(!Constant.BYTE_NO.equals(app.getEvaStatus())){
return new R().error("该预约记录已评价!");
}
CurrentUser current = SecurityUtils.getCurrentUser();
eva.setUserId(current.getId());
eva.setPatientName(app.getPatientName());
eva.setHospCode(app.getHosOrgCode());
eva.setHospName(app.getHosOrgName());
eva.setDeptCode(app.getDeptCode());
eva.setDeptName(app.getDeptName());
eva.setDoctorCode(app.getDoctorId());
eva.setDoctorName(app.getDoctorName());
eva.setCreateTime(DateUtil.date());
hpAppointmentEvaService.save(eva);
HpAppointment update = new HpAppointment();
update.setId(eva.getAppId());
update.setEvaStatus(Constant.BYTE_YES);
hpAppointmentService.updateById(update);
return new R();
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.controller.mobile;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.hpgp.vo.IntelligentAnswerVO;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.google.api.client.util.Lists;
import com.google.common.collect.Sets;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* @author F_xh
*/
@Slf4j
@RestController
@Api(tags = "[C]黄浦精准预约——智能问答")
@RequestMapping("/hpgp/c/intelligent/qa")
@RequiredArgsConstructor
public class HpGpIntelligentQAController {
private final static String CONTENT = "Content";
@Value("${hpgp-guide.qa-url:http://180.169.131.147:8000/}")
private String qaUrl;
@Value("${hpgp-guide.qa-history-limit:3}")
private Integer qaHistoryLimit;
private final static String QA_RESULT_FLAG = "Helper: ";
// 报告查询、医疗知识问答、医疗分诊、预约挂号
private static final Set<String> QA_TYPE= Sets.newHashSet("报告查询","预约挂号");
/**
* 打浦桥科室
*/
private final static Set<String> DPQ_DEPARTMENT = Sets.newHashSet("皮肤性病科", "中医科", "儿保科", "全科医疗科");
private final static Set<String> XDM_DEPARTMENT = Sets.newHashSet("全科", "全科名医", "中医", "针伤科", "齿科");
@SysLog
@ApiOperation("智能问答")
@PostMapping
public R<?> qa(String question) {
CurrentUser current = SecurityUtils.getCurrentUser();
String from = StrUtil.isNotBlank(current.getOpenId()) ? current.getOpenId() : current.getId().toString();
String xml = "<xml>\n" +
" <ToUserName><![CDATA[huangpurobot]]></ToUserName>\n" +
" <FromUserName><![CDATA[" + from + "]]></FromUserName>\n" +
" <CreateTime>" + DateUtil.now() + "</CreateTime>\n" +
" <MsgType><![CDATA[text]]></MsgType>\n" +
" <Content><![CDATA[" + question + "]]></Content>\n" +
" <MsgId>" + IdWorker.getId() + "</MsgId>\n" +
"</xml>";
// 162 为黄浦高血压专病导医机器人
// 51 黄浦高血压全科导诊机器人
String body = HttpRequest.post("http://30.30.5.74:9988/qa/jqrsvr.ashx?Command=talk_51")
.body(xml)
.execute()
.body();
log.error("孙总接口请求 xml = {}", xml);
log.error("孙总接口返回 body = {}", body);
IntelligentAnswerVO answerVO = new IntelligentAnswerVO();
Map<String, Object> result = XmlUtil.xmlToMap(body);
if (result.containsKey(CONTENT)) {
answerVO.setAnswer(MapUtil.getStr(result, CONTENT));
// 打浦桥单独处理
if (StrUtil.isNotBlank(current.getHospitalCode())
&& "42502942300".equals(current.getHospitalCode())) {
if (StrUtil.isNotBlank(answerVO.getDeptName())
&& !DPQ_DEPARTMENT.contains(answerVO.getDeptName())) {
String oldDeptName = answerVO.getDeptName();
answerVO.setAnswer(answerVO.getAnswer().replace(oldDeptName, "全科医疗科"));
answerVO.setDeptName("全科医疗科");
}
}
// 小东门单独处理
if (StrUtil.isNotBlank(current.getHospitalCode())
&& "42507025800".equals(current.getHospitalCode())) {
if (StrUtil.isNotBlank(answerVO.getDeptName())
&& !XDM_DEPARTMENT.contains(answerVO.getDeptName())) {
String oldDeptName = answerVO.getDeptName();
answerVO.setAnswer(answerVO.getAnswer().replace(oldDeptName, "全科"));
answerVO.setDeptName("全科");
}
}
}
return new R<>(answerVO);
}
// @SysLog
// @ApiOperation("智能问答")
// @PostMapping
// public R qaV2(String question) {
// if (StrUtil.isNotBlank(question) && question.contains("上周的血检报告出了")) {
// IntelligentAnswerVO answerVO = new IntelligentAnswerVO();
// answerVO.setAnswer("<a href=\"https://www.sh-sict.com/healthExam\">https://www.sh-sict.com/healthExam</a>");
// return new R(answerVO);
// }
// CurrentUser current = SecurityUtils.getCurrentUser();
// List<String> qaHistory = JSON.parseArray(current.getQaHistory(), String.class);
// String from = current.getId().toString();
//
// JSONObject jsonObject = new JSONObject();
// jsonObject.put("username", from);
// if (CollUtil.isEmpty(qaHistory)) {
// qaHistory = Lists.newArrayListWithCapacity(1);
// }
//
// if (qaHistory.size() > qaHistoryLimit) {
// qaHistory = qaHistory.subList(0, qaHistoryLimit - 1);
// }
//
// List<String> currentQa = Lists.newArrayList();
// currentQa.add(question);
// currentQa.add(null);
// qaHistory.add(JSON.toJSONString(currentQa));
//
// List<List<String>> reqList = new ArrayList<>();
// for (Object item : qaHistory) {
// if (item instanceof String) {
// List<String> itemList = JSONArray.parseArray((String) item, String.class);
// reqList.add(itemList);
// }
// }
// jsonObject.put("history", reqList);
// String req = JSON.toJSONString(jsonObject);
//
// // 162 为黄浦高血压专病导医机器人
// // 51 黄浦高血压全科导诊机器人
// HttpResponse response = HttpRequest.post(qaUrl)
// .body(req, "application/json")
// .execute();
// String body = response.body();
// log.error("接口请求 req = {}", req);
// log.error("接口返回 body = {}", body);
// if (response.getStatus() != 200 || StrUtil.isBlank(body)) {
// return new R();
// }
//
// JSONObject bodyJson = JSON.parseObject(body);
// String chat = bodyJson.getString("Chat");
// JSONArray departmentArray = bodyJson.getJSONArray("Department");
// String medicalType = bodyJson.getString("Medical_type");
// if(StrUtil.isNotBlank(medicalType) && QA_TYPE.contains(medicalType)){
// IntelligentAnswerVO answerVO = new IntelligentAnswerVO();
// answerVO.setAnswer("<a href=\"https://www.sh-sict.com/healthExam\">https://www.sh-sict.com/healthExam</a>");
// return new R(answerVO);
// }
// if (StrUtil.isBlank(chat)) {
// return new R();
// }
//
// chat = chat.replaceAll(QA_RESULT_FLAG, "");
// if (chat.startsWith("\"") && chat.endsWith("\"")) {
// chat = chat.substring(1, chat.length() - 1);
// }
// currentQa.set(1, chat);
// current.setQaHistory(JSON.toJSONString(qaHistory));
// SecurityUtils.updateCurrent(current);
//
// IntelligentAnswerVO answerVO = new IntelligentAnswerVO();
// answerVO.setAnswer(chat);
// if (CollUtil.isNotEmpty(departmentArray)) {
// answerVO.setDeptName(departmentArray.getString(0));
// }
// return new R(answerVO);
// }
/**
* post方式,可以解决特殊符号,过长的文本等问题
*
* @return
*/
// @PostMapping(value = "/completions/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
// public Flux<String> streamCompletionsPost(@RequestBody Map<String, String> param) {
// CurrentUser current = SecurityUtils.getCurrentUser();
// String user = param.get("user");
// String prompt = param.get("prompt");
//
// Assert.hasLength(user, "user不能为空");
// Assert.hasLength(prompt, "prompt不能为空");
// try {
// return getChatResponse(param.get("question"), current);
// } catch (RuntimeException e) {
// log.warn("e:{}", e.getMessage());
// return getErrorRes(e.getMessage());
// } catch (Exception e) {
// log.error("e:{}", e.getMessage(), e);
// return getErrorRes(ERROR_MSG);
// }
// }
//
// public Flux<String> getChatResponse(String question, CurrentUser current) {
// JSONObject params = new JSONObject();
//
// params.put("username", current.getId());
// List<String> currentQuestionList = Lists.newArrayListWithCapacity(2);
// currentQuestionList.add(question);
// currentQuestionList.add(null);
// params.put("history", Collections.singletonList(currentQuestionList));
//
// return webClient.post()
// .uri("http://localhost:12998/theme-schema/hpStatistics/hos-org-mg-status?endTime=2023-07-23&startTime=2023-07-17")
// //.header(HttpHeaders.AUTHORIZATION, "Bearer " + "")
// .syncBody(params.toJSONString())
// .retrieve()
// .bodyToFlux(String.class)
// .onErrorResume(WebClientResponseException.class, ex -> {
// HttpStatus status = ex.getStatusCode();
// String res = ex.getResponseBodyAsString();
// log.error("小欣AI API error: {} {}", status, res);
// return Mono.error(new RuntimeException(res));
// });
//
// }
//
// /**
// * 对sse接口的异常处理
// * 我这里的建议是不要直接抛出异常中断sse链接,因为这样前端无法获取错误信息,只能获取到链接断开了
// * 所以建议正常返回数据,把返回的数据中的code设置为非0的值,前端根据code来判断是否是错误信息,参考 @see org.chatgptstream.openai.util.R
// *
// * @param msg
// * @return
// */
// private Flux<String> getErrorRes(String msg) {
// return Flux.create(emitter -> {
// emitter.next(" ");
// emitter.next(" ");
// EXECUTOR.execute(() -> {
// try {
// int time = RANDOM.nextInt(200);
// // 请注意!这里加线程池休眠是为了解决一个问题,如果你不需要则删除掉这里线程池就行
// // 问题:假如系统使用了nginx负载均衡,然后后端这个接口遇到异常立即断开sse会导致nginx重连,进而重复请求后端
// // 所以休眠一下再断开让nginx知道正常连接了,不要重连
//
// //不延迟的话nginx会重连sse,导致nginx重复请求后端
// Thread.sleep(Math.max(time, 100));
// } catch (InterruptedException e) {
// log.info("e:", e);
// }
// emitter.next(JSON.toJSONString(new R<>().error(msg)));
// emitter.complete();
// });
// });
// }
}
package cn.sh.stc.sict.theme.hpgp.controller.mobile;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.hpgp.model.HpgpBusyIdlePrediction;
import cn.sh.stc.sict.theme.hpgp.service.HpHzjlService;
import cn.sh.stc.sict.theme.hphy.model.HpDocInfo;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import cn.sh.stc.sict.theme.hphy.service.HphyPatientBaseService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* (HpHzjl)表控制层
*
* @author F_xh
* @since 2022-08-15 14:14:33
*/
@Slf4j
@RestController
@AllArgsConstructor
@Api(tags = "[C]患者就诊记录")
@RequestMapping("/hpHzjl")
public class HpHzjlController {
/**
* 服务对象
*/
private final HpHzjlService hpHzjlService;
private final HphyPatientBaseService hphyPatientBaseService;
@ApiOperation("历史科室 list")
@GetMapping("/history/dept/list")
public R historyDeptList() {
CurrentUser current = SecurityUtils.getCurrentUser();
if (ObjectUtil.isEmpty(current) || StrUtil.isBlank(current.getOpenId())) {
log.error("current = {}", JSONUtil.toJsonStr(current));
return new R().error("当前的登录人信息异常");
}
HphyPatientBase patient = hphyPatientBaseService.getByOpenId(current.getOpenId());
if (ObjectUtil.isEmpty(patient) || StrUtil.isBlank(patient.getCertId())) {
log.error("patient = {}", JSONUtil.toJsonStr(patient));
return new R().error("患者信息异常!");
}
List<HpgpBusyIdlePrediction> result = hpHzjlService.listByCertIdAndHosCode(patient.getCertId(), current.getHospitalCode());
return new R(result);
}
@ApiOperation("历史医生 list")
@GetMapping("/history/doctor/list")
public R historyDoctorList() {
CurrentUser current = SecurityUtils.getCurrentUser();
if (ObjectUtil.isEmpty(current) || StrUtil.isBlank(current.getOpenId())) {
log.error("current = {}", JSONUtil.toJsonStr(current));
return new R().error("当前的登录人信息异常");
}
HphyPatientBase patient = hphyPatientBaseService.getByOpenId(current.getOpenId());
if (ObjectUtil.isEmpty(patient) || StrUtil.isBlank(patient.getCertId())) {
log.error("patient = {}", JSONUtil.toJsonStr(patient));
return new R().error("患者信息异常!");
}
List<HpDocInfo> result = hpHzjlService.listDoctorByCertIdAndHosCode(patient.getCertId(), current.getHospitalCode());
return new R(result);
}
}
package cn.sh.stc.sict.theme.hpgp.controller.mobile;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.theme.hpgp.service.HpgpBusyIdlePredictionService;
import com.baomidou.mybatisplus.extension.api.ApiController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 黄浦全科导诊——忙闲预测(HpgpBusyIdlePrediction)维护接口
*
* @author zhangly
* @since 2022-01-14 09:56:44
*/
@Slf4j
@Api(value = "[C] 黄浦全科导诊——忙闲预测维护接口", tags = "[C] 黄浦全科导诊——忙闲预测维护接口")
@RestController
@RequestMapping("/hpgp/c/busyidleprediction")
@AllArgsConstructor
public class HpgpBusyIdlePredictionController extends ApiController {
/**
* 服务对象
*/
private final HpgpBusyIdlePredictionService hpgpBusyIdlePredictionService;
@GetMapping
public R<?> busyIdlePrediction(@ApiParam("标准科室名称") @RequestParam("deptName") String deptName) {
return new R<>().success(hpgpBusyIdlePredictionService.busyIdlePrediction(SecurityUtils.getCurrentUser().getHospitalCode(), deptName));
}
}
package cn.sh.stc.sict.theme.hpgp.controller.mobile;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.theme.hpgp.model.HpgpDiagnosticExperience;
import cn.sh.stc.sict.theme.hpgp.service.HpgpDiagnosticExperienceService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.api.ApiController;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
/**
* 黄浦全科导诊——诊断经验云词(HpgpDiagnosticExperience)维护接口
*
* @author zhangly
* @since 2022-01-14 09:56:49
*/
@Api(value = "[C] 黄浦全科导诊——诊断经验云词维护接口", tags = "[C] 黄浦全科导诊——诊断经验云词维护接口")
@RestController
@RequestMapping("/hpgp/c/dia/exp")
@AllArgsConstructor
public class HpgpDiagnosticExperienceController extends ApiController {
/**
* 服务对象
*/
private final HpgpDiagnosticExperienceService hpgpDiagnosticExperienceService;
/**
* 分页查询
*
* @param page 分页对象
* @param experience 黄浦全科导诊——诊断经验云词
* @return
*/
@ApiOperation("分页查询")
@GetMapping("/page")
public R<?> getHpgpDiagnosticExperiencePage(Page page, HpgpDiagnosticExperience experience) {
page = hpgpDiagnosticExperienceService.page(page, Wrappers.query(experience));
return new R<>(page);
}
/**
* 新增机构信息表
* 黄浦全科导诊——诊断经验云词
* @param hpgpDiagnosticExperience
* @return R
*/
@ApiOperation("新增/修改")
@PostMapping
public R<?> save(@RequestBody HpgpDiagnosticExperience hpgpDiagnosticExperience) {
hpgpDiagnosticExperienceService.saveOrUpdate(hpgpDiagnosticExperience);
return new R<>(hpgpDiagnosticExperience);
}
}
package cn.sh.stc.sict.theme.hpgp.controller.mobile;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.theme.hpgp.model.HpgpLabExperience;
import cn.sh.stc.sict.theme.hpgp.service.HpgpLabExperienceService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.io.Serializable;
import java.util.List;
/**
* 医院科室-检验-词云(HpgpLabExperience)表控制层
*
* @author makejava
* @since 2022-06-23 11:38:14
*/
@Slf4j
@RestController
@AllArgsConstructor
@Api(tags = "[C]医院科室-检验-词云")
@RequestMapping("/hpgp/lab/experience")
public class HpgpLabExperienceController {
/**
* 服务对象
*/
private final HpgpLabExperienceService hpgpLabExperienceService;
@ApiOperation("分页")
@GetMapping("/page")
public R selectAll(Page<HpgpLabExperience> page, HpgpLabExperience hpgpLabExperience) {
return new R().success(this.hpgpLabExperienceService.page(page, new QueryWrapper<>(hpgpLabExperience)));
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.controller.mobile;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.hpgp.model.HpgpLumbarAnswer;
import cn.sh.stc.sict.theme.hpgp.service.HpgpLumbarAnswerService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.io.Serializable;
import java.util.List;
@Slf4j
@RestController
@AllArgsConstructor
@Api(tags = "[C]腰椎问卷")
@RequestMapping("/hpgp/lumbar")
public class HpgpLumbarAnswerController {
private final HpgpLumbarAnswerService hpgpLumbarAnswerService;
@ApiOperation("分页")
@GetMapping("/page")
public R selectAll(Page<HpgpLumbarAnswer> page, HpgpLumbarAnswer hpgpLumbarAnswer) {
return new R().success(this.hpgpLumbarAnswerService.page(page, new QueryWrapper<>(hpgpLumbarAnswer)));
}
@SysLog
@ApiOperation("腰椎问卷-新增")
@PostMapping
public R insert(@RequestBody HpgpLumbarAnswer lumbar) {
CurrentUser current = SecurityUtils.getCurrentUser();
lumbar.setUserId(current.getId());
return new R().success(this.hpgpLumbarAnswerService.save(lumbar));
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.dao;
import cn.sh.stc.sict.theme.hpgp.model.HpAppointmentEva;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
/**
* 预约评价(HpAppointmentEva)表数据库访问层
*
* @author F_xh
* @since 2022-06-23 10:46:03
*/
public interface HpAppointmentEvaMapper extends BaseMapper<HpAppointmentEva> {
Page<HpAppointmentEva> toBeEavPage(Page page,
@Param("patientId") Long patientId);
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpHzjl;
/**
* (HpHzjl)表数据库访问层
*
* @author F_xh
* @since 2022-08-15 14:14:33
*/
public interface HpHzjlMapper extends BaseMapper<HpHzjl> {
}
package cn.sh.stc.sict.theme.hpgp.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpgpBusyIdlePrediction;
/**
* 黄浦全科导诊——忙闲预测(HpgpBusyIdle_ prediction)表数据库访问层
*
* @author zhangly
* @since 2022-01-14 09:56:41
*/
public interface HpgpBusyIdlePredictionMapper extends BaseMapper<HpgpBusyIdlePrediction> {
}
package cn.sh.stc.sict.theme.hpgp.dao;
import cn.sh.stc.sict.theme.hpgp.model.HpgpDepartmentRank;
import cn.sh.stc.sict.theme.hpgp.vo.DeptRankVO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* 黄浦全科导诊——科室排名(HpgpDepartmentRank)表数据库访问层
*
* @author zhangly
* @since 2022-01-14 09:56:47
*/
public interface HpgpDepartmentRankMapper extends BaseMapper<HpgpDepartmentRank> {
/**
* 根据标准科室名称查询医院科室排名
*
* @param hospitalCode 医疗机构代码
* @param deptName 标准科室名称
* @param size 查询记录数 默认3条
* @return
*/
List<DeptRankVO> getRankByHosAndStandardDept(@Param("hospitalCode") String hospitalCode,
@Param("deptName") String deptName,
@Param("size") int size);
List<Map<String,List<Map<String,String>>>> getStandardDeptDic(@Param("hospitalCode") String hospitalCode);
}
package cn.sh.stc.sict.theme.hpgp.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpgpDiagnosticExperience;
/**
* 黄浦全科导诊——诊断经验云词(HpgpDiagnosticExperience)表数据库访问层
*
* @author zhangly
* @since 2022-01-14 09:56:48
*/
public interface HpgpDiagnosticExperienceMapper extends BaseMapper<HpgpDiagnosticExperience> {
}
package cn.sh.stc.sict.theme.hpgp.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpgpInspectionCheck;
/**
* 黄浦全科导诊——检验检查云词(HpgpInspectionCheck)表数据库访问层
*
* @author zhangly
* @since 2022-01-14 09:56:49
*/
public interface HpgpInspectionCheckMapper extends BaseMapper<HpgpInspectionCheck> {
}
package cn.sh.stc.sict.theme.hpgp.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpgpKsHot;
/**
* (HpgpKsHot)表数据库访问层
*
* @author gao
* @since 2022-11-07 10:33:21
*/
public interface HpgpKsHotMapper extends BaseMapper<HpgpKsHot> {
}
package cn.sh.stc.sict.theme.hpgp.dao;
import cn.sh.stc.sict.theme.hpgp.model.HpgpLabExperience;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 医院科室-检验-词云(HpgpLabExperience)表数据库访问层
*
* @author makejava
* @since 2022-06-23 11:38:13
*/
public interface HpgpLabExperienceMapper extends BaseMapper<HpgpLabExperience> {
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.dao;
import cn.sh.stc.sict.theme.hpgp.model.HpgpLumbarAnswer;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 腰椎问卷(HpgpLumbarAnswer)表数据库访问层
*
* @author makejava
* @since 2022-06-23 10:43:15
*/
public interface HpgpLumbarAnswerMapper extends BaseMapper<HpgpLumbarAnswer> {
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.model;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
/**
* 预约评价(HpAppointmentEva)表实体类
*
* @author makejava
* @since 2022-06-23 10:46:03
*/
@Data
@SuppressWarnings("serial")
@EqualsAndHashCode(callSuper = true)
public class HpAppointmentEva extends Model<HpAppointmentEva> {
private Long id;
private Long userId;
private Long patientId;
private String patientName;
private Long appId;
private String hospCode;
private String hospName;
private String deptCode;
private String deptName;
private String doctorCode;
private String doctorName;
/**
* 综合评价
**/
@ApiModelProperty(value = "综合评价")
private String comprehensiveEva;
/**
* 疗效评价
**/
@ApiModelProperty(value = "疗效评价")
private String efficacyEva;
/**
* 态度评价
**/
@ApiModelProperty(value = "态度评价")
private String attitudeEva;
private Date appTime;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
/**
* 获取主键值
*
* @return 主键值
*/
@Override
protected Serializable pkVal() {
return this.id;
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.model;
import java.util.Date;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import io.swagger.annotations.Api;
/**
* (HpHzjl)表实体类
*
* @author F_xh
* @since 2022-08-15 14:14:33
*/
@Data
@SuppressWarnings("serial")
@EqualsAndHashCode(callSuper = true)
public class HpHzjl extends Model<HpHzjl> {
private String zjhm;
private String zjlx;
private String xm;
private String yljgdm;
private String jzlx;
private String txbz;
private String jzksbm;
private String jzksmc;
private Date jzksrq;
private String zzysgh;
private String zzysxm;
private String jzzdsm;
}
package cn.sh.stc.sict.theme.hpgp.model;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
/**
* 黄浦全科导诊——忙闲预测(HpgpBusyIdle_ prediction)表实体类
*
* @author zhangly
* @since 2022-01-14 09:56:39
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class HpgpBusyIdlePrediction extends Model<HpgpBusyIdlePrediction> {
private Long id;
//医院代码
@ApiModelProperty( value = "医院代码")
private String hospitalCode;
//医院名称
@ApiModelProperty(value = "医院名称")
private String hospitalName;
private String oneDeptCode;
//科室代码
@ApiModelProperty(value = "科室代码")
private String deptCode;
//科室名称
@ApiModelProperty(value = "科室名称")
private String deptName;
//预测日期
@ApiModelProperty(value = "预测日期")
private Date predictionDate;
// 总号源数量
private Integer reserveOrderNum;
// 可预约号源数量
private Integer remainNum;
//忙闲评分
@ApiModelProperty(value = "忙闲评分")
private Integer score;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
/**
* 获取主键值
*
* @return 主键值
*/
@Override
protected Serializable pkVal() {
return this.id;
}
// 可用号源 / 号源
// >=0.5 0- 闲 -绿色
// 0.2-0.5 1-忙碌-黄色
// <=0.2 2-非常忙碌-红色
// 无号院 -1 灰色
public void setScoreByNum() {
if (NumberUtil.isNotNullOrZero(this.reserveOrderNum)) {
double roate = this.remainNum * 1.0 / this.reserveOrderNum;
if (roate >= 0.5) {
this.setScore(0);
} else if (roate > 0.2 && roate < 0.5) {
this.setScore(1);
} else {
this.setScore(2);
}
} else {
this.setScore(-1);
}
}
}
package cn.sh.stc.sict.theme.hpgp.model;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* 黄浦全科导诊——科室排名(HpgpDepartmentRank)表实体类
*
* @author zhangly
* @since 2022-01-14 09:56:47
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class HpgpDepartmentRank extends Model<HpgpDepartmentRank> {
private Integer id;
@ApiModelProperty(hidden = false, value = "标准科室所属分类")
private String standardDeptCategory;
//标准科室
@ApiModelProperty(hidden = false, value = "标准科室")
private String standardDept;
//医院代码
@ApiModelProperty(hidden = false, value = "医院代码")
private String hospitalCode;
//医院名称
@ApiModelProperty(hidden = false, value = "医院名称")
private String hospitalName;
@ApiModelProperty(hidden = false, value = "一级科室代码")
private String oneDeptCode;
//科室代码
@ApiModelProperty(hidden = false, value = "科室代码")
private String deptCode;
//科室名称
@ApiModelProperty(hidden = false, value = "科室名称")
private String deptName;
//科室排名
@ApiModelProperty(hidden = false, value = "科室排名")
private Integer rankScore;
private String tag;
private String resourceOutPatInfo;
private String resourceDoctInfo;
/**
* 获取主键值
*
* @return 主键值
*/
@Override
protected Serializable pkVal() {
return this.id;
}
}
package cn.sh.stc.sict.theme.hpgp.model;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* 黄浦全科导诊——诊断经验云词(HpgpDiagnosticExperience)表实体类
*
* @author zhangly
* @since 2022-01-14 09:56:48
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class HpgpDiagnosticExperience extends Model<HpgpDiagnosticExperience> {
//医院代码
@ApiModelProperty(hidden = false, value = "医院代码")
private String hospitalCode;
//医院名称
@ApiModelProperty(hidden = false, value = "医院名称")
private String hospitalName;
@ApiModelProperty(hidden = false, value = "一级科室代码")
private String oneDeptCode;
//科室代码
@ApiModelProperty(hidden = false, value = "科室代码")
private String deptCode;
//科室名称
@ApiModelProperty(hidden = false, value = "科室名称")
private String deptName;
//诊断名称
@ApiModelProperty(hidden = false, value = "诊断名称")
private String diagnoses;
//诊断总数
@ApiModelProperty(hidden = false, value = "诊断总数")
private Integer total;
}
package cn.sh.stc.sict.theme.hpgp.model;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* 黄浦全科导诊——检验检查云词(HpgpInspectionCheck)表实体类
*
* @author zhangly
* @since 2022-01-14 09:56:49
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class HpgpInspectionCheck extends Model<HpgpInspectionCheck> {
//医院代码
@ApiModelProperty(hidden = false, value = "医院代码")
private String hospitalCode;
//医院名称
@ApiModelProperty(hidden = false, value = "医院名称")
private String hospitalName;
@ApiModelProperty(hidden = false, value = "一级科室代码")
private String oneDeptCode;
//科室代码
@ApiModelProperty(hidden = false, value = "科室代码")
private String deptCode;
//科室名称
@ApiModelProperty(hidden = false, value = "科室名称")
private String deptName;
//检验检查项目名称
@ApiModelProperty(hidden = false, value = "检验检查项目名称")
private String itemName;
}
package cn.sh.stc.sict.theme.hpgp.model;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* (HpgpKsHot)表实体类
*
* @author makejava
* @since 2022-11-07 10:33:21
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class HpgpKsHot extends Model<HpgpKsHot> {
//医疗结构代码(ALL表示全区)
@ApiModelProperty(hidden=false, value="医疗结构代码(ALL表示全区)")
private String gzh;
@ApiModelProperty(hidden=false, value="标准科室")
private String standardDept;
@ApiModelProperty(hidden=false, value="医院代码")
private String hospitalCode;
@ApiModelProperty(hidden=false, value="医院名称")
private String hospitalName;
@ApiModelProperty(hidden=false, value="一级科室代码")
private String oneDeptCode;
@ApiModelProperty(hidden=false, value="科室代码")
private String deptCode;
@ApiModelProperty(hidden=false, value="科室名称")
private String deptName;
//科室排名
@ApiModelProperty(hidden=false, value="科室排名")
private byte rankScore;
}
package cn.sh.stc.sict.theme.hpgp.model;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* 医院科室-检验-词云(HpgpLabExperience)表实体类
*
* @author makejava
* @since 2022-06-23 11:38:13
*/
@Data
@SuppressWarnings("serial")
@EqualsAndHashCode(callSuper = true)
public class HpgpLabExperience extends Model<HpgpLabExperience> {
private Integer id;
private String hospCode;
private String hospName;
private String oneDeptCode;
private String deptCode;
private String deptName;
private String itemName;
/**
* 获取主键值
*
* @return 主键值
*/
@Override
protected Serializable pkVal() {
return this.id;
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.model;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
/**
* 腰椎问卷(HpgpLumbarAnswer)表实体类
*
* @author makejava
* @since 2022-06-23 10:43:10
*/
@Data
@SuppressWarnings("serial")
@EqualsAndHashCode(callSuper = true)
public class HpgpLumbarAnswer extends Model<HpgpLumbarAnswer> {
private Long id;
private Long userId;
private Long patientId;
private String answerJson;
private Integer age;
private String score;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
/**
* 获取主键值
*
* @return 主键值
*/
@Override
protected Serializable pkVal() {
return this.id;
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.service;
import cn.sh.stc.sict.theme.hpgp.model.HpAppointmentEva;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* 预约评价(HpAppointmentEva)表服务接口
*
* @author makejava
* @since 2022-06-23 10:46:03
*/
public interface HpAppointmentEvaService extends IService<HpAppointmentEva> {
Page<HpAppointmentEva> toBeEavPage(Page page, Long patientId);
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.service;
import cn.sh.stc.sict.theme.hpgp.model.HpHzjl;
import cn.sh.stc.sict.theme.hpgp.model.HpgpBusyIdlePrediction;
import cn.sh.stc.sict.theme.hphy.model.HpDocInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* (HpHzjl)表服务接口
*
* @author F_xh
* @since 2022-08-15 14:14:33
*/
public interface HpHzjlService extends IService<HpHzjl> {
/**
* 根据身份证号和医院查找最后三次不同科室就诊记录,并计算忙闲
* 如果未找到,则推送三个热门科室
*
* @param certId 身份证号
* @param hospCode 医疗机构代码(医院编码)
* @return
*/
List<HpgpBusyIdlePrediction> listByCertIdAndHosCode(String certId,
String hospCode);
/**
* @param certId 身份证号
* @param hospCode 医疗机构代码(医院编码)
* @return
*/
List<HpDocInfo> listDoctorByCertIdAndHosCode(String certId,
String hospCode);
}
package cn.sh.stc.sict.theme.hpgp.service;
import cn.hutool.core.date.DateTime;
import cn.sh.stc.sict.theme.hpgp.model.HpgpBusyIdlePrediction;
import cn.sh.stc.sict.theme.hpgp.model.HpgpDepartmentRank;
import cn.sh.stc.sict.theme.hphy.model.HpDeptInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.Date;
import java.util.List;
/**
* 黄浦全科导诊——忙闲预测(HpgpBusyIdle_ prediction)表服务接口
*
* @author zhangly
* @since 2022-01-14 09:56:42
*/
public interface HpgpBusyIdlePredictionService extends IService<HpgpBusyIdlePrediction> {
/**
* 忙闲预测
* 按科室名称查询全区排名前3的科室
* 查询当前医院有号的3个科室
*
* @param hospitalCode 医疗结构代码(医院编码)
* @param deptName 标准科室名称
* @return 忙闲医院科室
*/
List<HpgpBusyIdlePrediction> busyIdlePrediction(String hospitalCode, String deptName);
void statisticResourceInfo(HpDeptInfo dept, Date startDate, Date endDate, Byte flag);
List<HpgpBusyIdlePrediction> listByDept(HpDeptInfo dept, DateTime startTime, DateTime endTime);
}
package cn.sh.stc.sict.theme.hpgp.service;
import cn.sh.stc.sict.theme.hpgp.model.HpgpDepartmentRank;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
import java.util.Map;
/**
* 黄浦全科导诊——科室排名(HpgpDepartmentRank)表服务接口
*
* @author zhangly
* @since 2022-01-14 09:56:47
*/
public interface HpgpDepartmentRankService extends IService<HpgpDepartmentRank> {
void updateResource();
HpgpDepartmentRank getByCode(String hospCode, String oneDeptCode, String deptCode);
List<HpgpDepartmentRank> listHotDept();
/**
* 医院标准科室字典
*
* @param hospitalCode 医院编码
* @return
*/
List<Map<String, List<Map<String, String>>>> getStandardDeptDic(String hospitalCode);
}
package cn.sh.stc.sict.theme.hpgp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import cn.sh.stc.sict.theme.hpgp.model.HpgpDiagnosticExperience;
/**
* 黄浦全科导诊——诊断经验云词(HpgpDiagnosticExperience)表服务接口
*
* @author zhangly
* @since 2022-01-14 09:56:48
*/
public interface HpgpDiagnosticExperienceService extends IService<HpgpDiagnosticExperience> {
}
package cn.sh.stc.sict.theme.hpgp.service;
import com.baomidou.mybatisplus.extension.service.IService;
import cn.sh.stc.sict.theme.hpgp.model.HpgpInspectionCheck;
/**
* 黄浦全科导诊——检验检查云词(HpgpInspectionCheck)表服务接口
*
* @author zhangly
* @since 2022-01-14 09:56:49
*/
public interface HpgpInspectionCheckService extends IService<HpgpInspectionCheck> {
}
package cn.sh.stc.sict.theme.hpgp.service;
import cn.sh.stc.sict.theme.hpgp.model.HpgpKsHot;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* (HpgpKsHot)表服务接口
*
* @author gao
* @since 2022-11-07 10:33:21
*/
public interface HpgpKsHotService extends IService<HpgpKsHot> {
/**
* 根据医疗机构代码查询热门科室
*
* @param yljgdm 医疗机构代码
* @param size 科室数量
* @return
*/
List<HpgpKsHot> listHotDept(String yljgdm, int size);
}
package cn.sh.stc.sict.theme.hpgp.service;
import cn.sh.stc.sict.theme.hpgp.model.HpgpLabExperience;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* 医院科室-检验-词云(HpgpLabExperience)表服务接口
*
* @author makejava
* @since 2022-06-23 11:38:13
*/
public interface HpgpLabExperienceService extends IService<HpgpLabExperience> {
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.service;
import cn.sh.stc.sict.theme.hpgp.model.HpgpLumbarAnswer;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* 腰椎问卷(HpgpLumbarAnswer)表服务接口
*
* @author makejava
* @since 2022-06-23 10:43:15
*/
public interface HpgpLumbarAnswerService extends IService<HpgpLumbarAnswer> {
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.service.impl;
import cn.sh.stc.sict.theme.hpgp.dao.HpAppointmentEvaMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpAppointmentEva;
import cn.sh.stc.sict.theme.hpgp.service.HpAppointmentEvaService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
/**
* 预约评价(HpAppointmentEva)表服务实现类
*
* @author makejava
* @since 2022-06-23 10:46:03
*/
@AllArgsConstructor
@Service("hpAppointmentEvaService")
public class HpAppointmentEvaServiceImpl extends ServiceImpl<HpAppointmentEvaMapper, HpAppointmentEva> implements HpAppointmentEvaService {
private final HpAppointmentEvaMapper hpAppointmentEvaMapper;
@Override
public Page<HpAppointmentEva> toBeEavPage(Page page, Long patientId) {
return hpAppointmentEvaMapper.toBeEavPage(page, patientId);
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.theme.hpgp.dao.HpHzjlMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpHzjl;
import cn.sh.stc.sict.theme.hpgp.model.HpgpBusyIdlePrediction;
import cn.sh.stc.sict.theme.hpgp.model.HpgpKsHot;
import cn.sh.stc.sict.theme.hpgp.service.HpHzjlService;
import cn.sh.stc.sict.theme.hpgp.service.HpgpBusyIdlePredictionService;
import cn.sh.stc.sict.theme.hpgp.service.HpgpDepartmentRankService;
import cn.sh.stc.sict.theme.hpgp.service.HpgpKsHotService;
import cn.sh.stc.sict.theme.hphy.model.HpDeptInfo;
import cn.sh.stc.sict.theme.hphy.model.HpDocInfo;
import cn.sh.stc.sict.theme.hphy.service.HpDeptInfoService;
import cn.sh.stc.sict.theme.hphy.service.HpDocInfoService;
import cn.sh.stc.sict.theme.hphy.util.BusyIdlePredictionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* (HpHzjl)表服务实现类
*
* @author F_xh
* @since 2022-08-15 14:14:33
*/
@AllArgsConstructor
@Service("hpHzjlService")
public class HpHzjlServiceImpl extends ServiceImpl<HpHzjlMapper, HpHzjl> implements HpHzjlService {
private final HpgpDepartmentRankService hpgpDepartmentRankService;
private final HpgpBusyIdlePredictionService hpgpBusyIdlePredictionService;
private final HpDocInfoService hpDocInfoService;
private final HpgpKsHotService hpgpKsHotService;
private final HpDeptInfoService hpDeptInfoService;
private static final Integer MAX_DEPT_SIZE = 3;
/**
* 根据身份证号查找最后三次不同科室就诊记录,并计算忙闲
* 如果未找到,则推送三个热门科室
*
* @param certId 身份证号
* @param hospitalCode 医疗机构代码(医院编码)
* @return
*/
@Override
public List<HpgpBusyIdlePrediction> listByCertIdAndHosCode(String certId,
String hospitalCode) {
List<HpgpBusyIdlePrediction> result = new ArrayList<>();
int resultDeptSize = 0;
DateTime startTime = DateUtil.tomorrow();
DateTime endTime = DateUtil.offsetDay(startTime, 6);
LambdaQueryWrapper<HpHzjl> wrapper = Wrappers.lambdaQuery();
wrapper.eq(HpHzjl::getZjhm, certId)
.eq(StrUtil.isNotBlank(hospitalCode), HpHzjl::getYljgdm, hospitalCode)
.groupBy(HpHzjl::getJzksbm)
.orderByDesc(HpHzjl::getJzksrq)
.last("limit " + MAX_DEPT_SIZE);
List<HpHzjl> recordList = this.list(wrapper);
if (CollUtil.isNotEmpty(recordList)) {
for (HpHzjl record : recordList) {
// 查找科室
LambdaQueryWrapper<HpDeptInfo> deptWrapper = Wrappers.<HpDeptInfo>lambdaQuery();
deptWrapper.eq(HpDeptInfo::getHosOrgCode, record.getYljgdm())
.eq(HpDeptInfo::getDeptCode, record.getJzksbm())
.eq(HpDeptInfo::getDeptLevel, 2);
HpDeptInfo dept = hpDeptInfoService.getOne(deptWrapper);
if (ObjectUtil.isNull(dept)) {
continue;
}
// 忙闲预测
List<HpgpBusyIdlePrediction> hasRemainNum = BusyIdlePredictionUtil.getHasRemainNum(hpgpBusyIdlePredictionService.listByDept(dept, startTime, endTime));
if (CollUtil.isNotEmpty(hasRemainNum)) {
result.addAll(hasRemainNum);
resultDeptSize++;
}
}
}
// 历史科室查询结果少于3个时,采用热点科室数据补充
if (resultDeptSize < MAX_DEPT_SIZE) {
List<HpgpKsHot> hotList = hpgpKsHotService.listHotDept(hospitalCode, 3);
hotList.forEach(hot -> {
HpDeptInfo dept = new HpDeptInfo();
dept.setHosOrgCode(hot.getHospitalCode());
dept.setHosName(hot.getHospitalName());
dept.setOneDeptCode(hot.getOneDeptCode());
dept.setDeptCode(hot.getDeptCode());
dept.setDeptName(hot.getDeptName());
// 忙闲预测
List<HpgpBusyIdlePrediction> hasRemainNum = BusyIdlePredictionUtil.getHasRemainNum(hpgpBusyIdlePredictionService.listByDept(dept, startTime, endTime));
if (CollUtil.isNotEmpty(hasRemainNum)) {
result.addAll(hasRemainNum);
}
});
}
return BusyIdlePredictionUtil.getHasRemainNum(result);
}
@Override
public List<HpDocInfo> listDoctorByCertIdAndHosCode(String certId,
String hospitalCode) {
LambdaQueryWrapper<HpHzjl> wrapper = Wrappers.lambdaQuery();
wrapper.eq(HpHzjl::getZjhm, certId)
.eq(StrUtil.isNotBlank(hospitalCode), HpHzjl::getYljgdm, hospitalCode)
.groupBy(HpHzjl::getYljgdm, HpHzjl::getJzksbm, HpHzjl::getZzysgh)
.orderByDesc(HpHzjl::getJzksrq)
.last("limit 10");
List<HpHzjl> recordList = this.list(wrapper);
List<HpDocInfo> doctorList = new ArrayList<>();
if (CollUtil.isNotEmpty(recordList)) {
recordList.forEach(r -> {
LambdaQueryWrapper<HpDocInfo> dw = Wrappers.lambdaQuery();
dw.eq(HpDocInfo::getHosOrgCode, r.getYljgdm())
.eq(HpDocInfo::getResourceCode, r.getZzysgh())
.eq(HpDocInfo::getResourceName, r.getZzysxm())
.last("limit 1");
HpDocInfo one = hpDocInfoService.getOne(dw);
if (ObjectUtil.isNotNull(one)) {
doctorList.add(one);
}
});
}
return doctorList;
}
}
package cn.sh.stc.sict.theme.hpgp.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.theme.hpgp.dao.HpgpBusyIdlePredictionMapper;
import cn.sh.stc.sict.theme.hpgp.dao.HpgpDepartmentRankMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpgpBusyIdlePrediction;
import cn.sh.stc.sict.theme.hpgp.model.HpgpDepartmentRank;
import cn.sh.stc.sict.theme.hpgp.service.HpgpBusyIdlePredictionService;
import cn.sh.stc.sict.theme.hpgp.vo.DeptRankVO;
import cn.sh.stc.sict.theme.hphy.model.HpDeptInfo;
import cn.sh.stc.sict.theme.hphy.model.HpDocInfo;
import cn.sh.stc.sict.theme.hphy.service.HpDocInfoService;
import cn.sh.stc.sict.theme.hphy.wd.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
* 黄浦全科导诊——忙闲预测(HpgpBusyIdle_ prediction)表服务实现类
*
* @author zhangly
* @since 2022-01-14 09:56:43
*/
@Slf4j
@AllArgsConstructor
@Service("hpgpBusyIdlPredictionService")
public class HpgpBusyIdlePredictionServiceImpl extends ServiceImpl<HpgpBusyIdlePredictionMapper, HpgpBusyIdlePrediction> implements HpgpBusyIdlePredictionService {
private final HpgpDepartmentRankMapper departmentRankMapper;
private final HpDocInfoService hpDocInfoService;
@Override
public List<HpgpBusyIdlePrediction> busyIdlePrediction(String hospitalCode,
String deptName) {
// 查询当前医院有号的三个科室
if (StrUtil.isNotBlank(hospitalCode)) {
return busyIdlePredictionByHosCodeAndDeptName(hospitalCode, deptName);
}
// 在科室排名表中查询排名前三的科室展示
return busyIdlePredictionByDeptName(deptName);
}
/**
* 按科室名称查询全区排名前3的科室
*
* @param deptName 科室名称
* @return HpgpBusyIdlePrediction {@link HpgpBusyIdlePrediction}
*/
private List<HpgpBusyIdlePrediction> busyIdlePredictionByDeptName(String deptName) {
List<DeptRankVO> rankList = departmentRankMapper.getRankByHosAndStandardDept(null, deptName, 3);
if (CollectionUtil.isEmpty(rankList)) {
return null;
}
return busyIdlePrediction(rankList);
}
/**
* 查询当前医院有号的三个科室
*
* @param hospitalCode 医院编码
* @param deptName 部门名称
* @return HpgpBusyIdlePrediction {@link HpgpBusyIdlePrediction}
*/
private List<HpgpBusyIdlePrediction> busyIdlePredictionByHosCodeAndDeptName(String hospitalCode,
String deptName) {
List<DeptRankVO> rankList = departmentRankMapper.getRankByHosAndStandardDept(hospitalCode, deptName, 0);
if (CollectionUtil.isEmpty(rankList)) {
return null;
}
List<HpgpBusyIdlePrediction> hpgpBusyIdlePredictionList = busyIdlePrediction(rankList);
// 当前医院近七天有号的三个科室
List<String> deptCodeList = hpgpBusyIdlePredictionList.stream()
// 按科室分组,并统计每个科室可预约号源总量
.collect(Collectors.groupingBy(HpgpBusyIdlePrediction::getDeptCode,
Collectors.summingInt(item -> Optional.ofNullable(item.getRemainNum()).orElse(0))))
.entrySet().stream()
// 按可预约号源进行排序,取排名前三的科室
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
.map(Map.Entry::getKey)
.limit(3)
.collect(Collectors.toList());
return hpgpBusyIdlePredictionList.stream().filter(item -> deptCodeList.contains(item.getDeptCode())).collect(Collectors.toList());
}
/**
* 按医院和科室详情查询近一周各科室忙闲情况
*
* @param deptList 科室集
* @return HpgpBusyIdlePrediction {@link HpgpBusyIdlePrediction}
*/
private List<HpgpBusyIdlePrediction> busyIdlePrediction(List<DeptRankVO> deptList) {
DateTime startTime = DateUtil.tomorrow();
DateTime endTime = DateUtil.offsetDay(startTime, 6);
List<HpgpBusyIdlePrediction> result = new ArrayList<>();
deptList.forEach(rank -> {
HpDeptInfo dept = new HpDeptInfo();
dept.setHosOrgCode(rank.getHospitalCode());
dept.setHosName(rank.getHospitalName());
dept.setOneDeptCode(rank.getOneDeptCode());
dept.setDeptCode(rank.getDeptCode());
dept.setDeptName(rank.getDeptName());
// 查询医院忙闲
result.addAll(this.listByDept(dept, startTime, endTime));
});
return result;
}
private HpgpBusyIdlePrediction getNoneSourcePredictionInfo(HpDeptInfo dept, Date i) {
HpgpBusyIdlePrediction vo = new HpgpBusyIdlePrediction();
vo.setOneDeptCode(dept.getOneDeptCode());
vo.setDeptCode(dept.getDeptCode());
vo.setDeptName(dept.getDeptName());
vo.setHospitalName(dept.getHosName());
vo.setHospitalCode(dept.getHosOrgCode());
vo.setPredictionDate(i);
vo.setScoreByNum();
return vo;
}
// @Async
@Override
public void statisticResourceInfo(HpDeptInfo dept, Date startDate, Date endDate, Byte flag) {
try {
DeptInfo deptInfo = new DeptInfo();
deptInfo.setHosOrgCode(dept.getHosOrgCode());
deptInfo.setOneDeptCode(dept.getOneDeptCode());
deptInfo.setDeptCode(dept.getDeptCode());
List<OutPatInfo> outList = WanDaHttpUtil.getOutPatInfo(deptInfo);
List<DoctInfo> docList = WanDaHttpUtil.getDoctInfo(deptInfo);
List<HpDocInfo> hpDocList = hpDocInfoService.listByDeptInfo(deptInfo);
if (CollUtil.isEmpty(outList) && CollUtil.isEmpty(docList) && CollUtil.isEmpty(hpDocList)) {
return;
}
Map<String, HpgpBusyIdlePrediction> dateResultMap = new HashMap<>();
this.getOutResourceInfo(dept, outList, dateResultMap, startDate, endDate);
this.getDocResourceInfo(dept, docList, dateResultMap, startDate, endDate);
if (Constant.BYTE_YES.equals(flag)) {
this.getHpDocResourceInfo(dept, hpDocList, docList, dateResultMap, startDate, endDate);
}
if (CollUtil.isNotEmpty(dateResultMap)) {
dateResultMap.forEach((k, v) -> {
LambdaQueryWrapper<HpgpBusyIdlePrediction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HpgpBusyIdlePrediction::getHospitalCode, v.getHospitalCode())
.eq(HpgpBusyIdlePrediction::getOneDeptCode, v.getOneDeptCode())
.eq(HpgpBusyIdlePrediction::getDeptCode, v.getDeptCode())
.eq(HpgpBusyIdlePrediction::getPredictionDate, v.getPredictionDate());
this.saveOrUpdate(v, wrapper);
});
}
} catch (Exception e) {
log.error("统计号源异常, dept = {}", JSONUtil.toJsonStr(dept));
log.error(e.getMessage(), e);
}
}
@Override
public List<HpgpBusyIdlePrediction> listByDept(HpDeptInfo dept, DateTime startTime, DateTime endTime) {
List<HpgpBusyIdlePrediction> result = new ArrayList<>();
LambdaQueryWrapper<HpgpBusyIdlePrediction> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HpgpBusyIdlePrediction::getHospitalCode, dept.getHosOrgCode())
.eq(HpgpBusyIdlePrediction::getOneDeptCode, dept.getOneDeptCode())
.eq(HpgpBusyIdlePrediction::getDeptCode, dept.getDeptCode())
.between(HpgpBusyIdlePrediction::getPredictionDate, DateUtil.format(startTime, DatePattern.NORM_DATE_FORMAT), DateUtil.format(endTime, DatePattern.NORM_DATE_FORMAT))
.orderByAsc(HpgpBusyIdlePrediction::getPredictionDate);
List<HpgpBusyIdlePrediction> list = this.list(wrapper);
if (CollUtil.isNotEmpty(list)) {
Map<Date, HpgpBusyIdlePrediction> dateMap = list.stream().collect(Collectors.groupingBy(HpgpBusyIdlePrediction::getPredictionDate, Collectors.collectingAndThen(Collectors.toList(), x -> x.get(0))));
// 生成无号源信息
for (Date i = startTime; DateUtil.compare(i, endTime) < 1; i = DateUtil.offsetDay(i, 1)) {
Date key = DateUtil.beginOfDay(i);
if (dateMap.containsKey(key)) {
HpgpBusyIdlePrediction data = dateMap.get(key);
data.setHospitalCode(dept.getHosOrgCode());
data.setHospitalName(dept.getHosName());
data.setOneDeptCode(dept.getOneDeptCode());
data.setDeptCode(dept.getDeptCode());
data.setDeptName(dept.getDeptName());
result.add(data);
} else {
result.add(this.getNoneSourcePredictionInfo(dept, i));
}
}
} else {
// 生成无号源信息
for (Date i = startTime; DateUtil.compare(i, endTime) < 1; i = DateUtil.offsetDay(i, 1)) {
result.add(this.getNoneSourcePredictionInfo(dept, i));
}
}
return result;
}
private void getDocResourceInfo(HpDeptInfo dept,
List<DoctInfo> docList,
Map<String, HpgpBusyIdlePrediction> dateResultMap,
Date startDate,
Date endDate) {
if (CollUtil.isNotEmpty(docList)) {
docList.forEach(doc -> {
NumSourceInfo numSourceInfo = new NumSourceInfo();
numSourceInfo.setHosOrgCode(dept.getHosOrgCode());
numSourceInfo.setOneDeptCode(dept.getOneDeptCode());
numSourceInfo.setDeptCode(dept.getDeptCode());
numSourceInfo.setStartTime(DateUtil.format(startDate, DatePattern.NORM_DATE_FORMAT));
numSourceInfo.setEndTime(DateUtil.format(endDate, DatePattern.NORM_DATE_FORMAT));
numSourceInfo.setOrderType(WanDaConstant.ORDER_TYPE_OUTP);
numSourceInfo.setPatient_type(WanDaConstant.PATIENT_TYPE_NORMAL);
numSourceInfo.setResourceCode(doc.getResourceCode());
List<NumSourceInfo> orderNumInfo = WanDaHttpUtil.getOrderNumInfo(numSourceInfo);
if (CollUtil.isNotEmpty(orderNumInfo)) {
hpDocInfoService.updateResource(numSourceInfo, Constant.BYTE_YES);
Map<String, List<NumSourceInfo>> dateMap = orderNumInfo.stream().collect(Collectors.groupingBy(NumSourceInfo::getScheduleDate));
dateMap.forEach((date, numList) -> {
HpgpBusyIdlePrediction vo = dateResultMap.getOrDefault(date, new HpgpBusyIdlePrediction());
vo.setDeptCode(dept.getDeptCode());
vo.setDeptName(dept.getDeptName());
vo.setHospitalName(dept.getHosName());
vo.setHospitalCode(dept.getHosOrgCode());
vo.setPredictionDate(DateUtil.parseDate(date));
vo.setOneDeptCode(dept.getOneDeptCode());
// 计算号源信息
int reserveOrderNum = numList.stream()
// 按最小粒度的预约时段分组,并取出分组后第一条号源信息
.collect(Collectors.groupingBy(n -> n.getNumSourceId() + n.getScheduleId(), Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))))
.values().stream().mapToInt(NumSourceInfo::getReserveOrderNum).sum();
vo.setReserveOrderNum(NumberUtil.isNullOrZero(vo.getReserveOrderNum()) ? reserveOrderNum : vo.getReserveOrderNum() + reserveOrderNum);
int remain = numList.stream()
// 按最小粒度的预约时段分组,并取出分组后第一条号源信息
.collect(Collectors.groupingBy(n -> n.getNumSourceId() + n.getScheduleId(), Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))))
.values().stream().mapToInt(NumSourceInfo::getRemainNum).sum();
vo.setRemainNum(NumberUtil.isNullOrZero(vo.getRemainNum()) ? remain : vo.getRemainNum() + remain);
vo.setScoreByNum();
dateResultMap.put(date, vo);
});
} else {
hpDocInfoService.updateResource(numSourceInfo, Constant.BYTE_NO);
}
});
}
}
private void getHpDocResourceInfo(HpDeptInfo dept,
List<HpDocInfo> hpDocList, List<DoctInfo> docList,
Map<String, HpgpBusyIdlePrediction> dateResultMap,
Date startDate,
Date endDate) {
Set<String> resourceCodeSet = CollUtil.isEmpty(docList) ? new HashSet<>() : docList.stream().map(DoctInfo::getResourceCode).collect(Collectors.toSet());
if (CollUtil.isNotEmpty(hpDocList)) {
hpDocList.forEach(doc -> {
if (StrUtil.isEmpty(doc.getResourceCode()) || resourceCodeSet.contains(doc.getResourceCode())) {
return;
}
NumSourceInfo numSourceInfo = new NumSourceInfo();
numSourceInfo.setHosOrgCode(dept.getHosOrgCode());
numSourceInfo.setOneDeptCode(dept.getOneDeptCode());
numSourceInfo.setDeptCode(dept.getDeptCode());
numSourceInfo.setStartTime(DateUtil.format(startDate, DatePattern.NORM_DATE_FORMAT));
numSourceInfo.setEndTime(DateUtil.format(endDate, DatePattern.NORM_DATE_FORMAT));
numSourceInfo.setOrderType(WanDaConstant.ORDER_TYPE_OUTP);
numSourceInfo.setPatient_type(WanDaConstant.PATIENT_TYPE_NORMAL);
numSourceInfo.setResourceCode(doc.getResourceCode());
List<NumSourceInfo> orderNumInfo = WanDaHttpUtil.getOrderNumInfo(numSourceInfo);
if (CollUtil.isNotEmpty(orderNumInfo)) {
hpDocInfoService.updateResource(numSourceInfo, Constant.BYTE_YES);
Map<String, List<NumSourceInfo>> dateMap = orderNumInfo.stream().collect(Collectors.groupingBy(NumSourceInfo::getScheduleDate));
dateMap.forEach((date, numList) -> {
HpgpBusyIdlePrediction vo = dateResultMap.getOrDefault(date, new HpgpBusyIdlePrediction());
vo.setDeptCode(dept.getDeptCode());
vo.setDeptName(dept.getDeptName());
vo.setHospitalName(dept.getHosName());
vo.setHospitalCode(dept.getHosOrgCode());
vo.setPredictionDate(DateUtil.parseDate(date));
vo.setOneDeptCode(dept.getOneDeptCode());
// 计算号源信息
int reserveOrderNum = numList.stream()
// 按最小粒度的预约时段分组,并取出分组后第一条号源信息
.collect(Collectors.groupingBy(n -> n.getNumSourceId() + n.getScheduleId(), Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))))
.values().stream().mapToInt(NumSourceInfo::getReserveOrderNum).sum();
vo.setReserveOrderNum(NumberUtil.isNullOrZero(vo.getReserveOrderNum()) ? reserveOrderNum : vo.getReserveOrderNum() + reserveOrderNum);
int remain = numList.stream()
// 按最小粒度的预约时段分组,并取出分组后第一条号源信息
.collect(Collectors.groupingBy(n -> n.getNumSourceId() + n.getScheduleId(), Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))))
.values().stream().mapToInt(NumSourceInfo::getRemainNum).sum();
vo.setRemainNum(NumberUtil.isNullOrZero(vo.getRemainNum()) ? remain : vo.getRemainNum() + remain);
vo.setScoreByNum();
dateResultMap.put(date, vo);
});
} else {
hpDocInfoService.updateResource(numSourceInfo, Constant.BYTE_NO);
}
});
}
}
private void getOutResourceInfo(HpDeptInfo
dept, List<OutPatInfo> outList, Map<String, HpgpBusyIdlePrediction> dateResultMap, Date startDate, Date
endDate) {
if (CollUtil.isNotEmpty(outList)) {
outList.forEach(pat -> {
NumSourceInfo numSourceInfo = new NumSourceInfo();
numSourceInfo.setHosOrgCode(dept.getHosOrgCode());
numSourceInfo.setOneDeptCode(dept.getOneDeptCode());
numSourceInfo.setDeptCode(dept.getDeptCode());
numSourceInfo.setStartTime(DateUtil.format(startDate, DatePattern.NORM_DATE_FORMAT));
numSourceInfo.setEndTime(DateUtil.format(endDate, DatePattern.NORM_DATE_FORMAT));
numSourceInfo.setOrderType(WanDaConstant.ORDER_TYPE_CLINC);
numSourceInfo.setPatient_type(WanDaConstant.PATIENT_TYPE_NORMAL);
numSourceInfo.setResourceCode(pat.getResourceCode());
List<NumSourceInfo> orderNumInfo = WanDaHttpUtil.getOrderNumInfo(numSourceInfo);
if (CollUtil.isNotEmpty(orderNumInfo)) {
Map<String, List<NumSourceInfo>> dateMap = orderNumInfo.stream().collect(Collectors.groupingBy(NumSourceInfo::getScheduleDate));
dateMap.forEach((date, numList) -> {
HpgpBusyIdlePrediction vo = dateResultMap.getOrDefault(date, new HpgpBusyIdlePrediction());
vo.setDeptCode(dept.getDeptCode());
vo.setDeptName(dept.getDeptName());
vo.setHospitalName(dept.getHosName());
vo.setHospitalCode(dept.getHosOrgCode());
vo.setPredictionDate(DateUtil.parseDate(date));
vo.setOneDeptCode(dept.getOneDeptCode());
// 计算号源信息
int reserveOrderNum = numList.stream()
// 按最小粒度的预约时段分组,并取出分组后第一条号源信息
.collect(Collectors.groupingBy(n -> n.getNumSourceId() + n.getScheduleId(), Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))))
.values().stream().mapToInt(NumSourceInfo::getReserveOrderNum).sum();
vo.setReserveOrderNum(NumberUtil.isNullOrZero(vo.getReserveOrderNum()) ? reserveOrderNum : vo.getReserveOrderNum() + reserveOrderNum);
int remain = numList.stream()
// 按最小粒度的预约时段分组,并取出分组后第一条号源信息
.collect(Collectors.groupingBy(n -> n.getNumSourceId() + n.getScheduleId(), Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))))
.values().stream().mapToInt(NumSourceInfo::getRemainNum).sum();
vo.setRemainNum(NumberUtil.isNullOrZero(vo.getRemainNum()) ? remain : vo.getRemainNum() + remain);
vo.setScoreByNum();
dateResultMap.put(date, vo);
});
}
});
}
}
}
package cn.sh.stc.sict.theme.hpgp.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.theme.hpgp.model.HpgpBusyIdlePrediction;
import cn.sh.stc.sict.theme.hpgp.service.HpgpBusyIdlePredictionService;
import cn.sh.stc.sict.theme.hphy.wd.*;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.sh.stc.sict.theme.hpgp.dao.HpgpDepartmentRankMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpgpDepartmentRank;
import cn.sh.stc.sict.theme.hpgp.service.HpgpDepartmentRankService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* 黄浦全科导诊——科室排名(HpgpDepartmentRank)表服务实现类
*
* @author zhangly
* @since 2022-01-14 09:56:47
*/
@Slf4j
@AllArgsConstructor
@Service("hpgpDepartmentRankService")
public class HpgpDepartmentRankServiceImpl extends ServiceImpl<HpgpDepartmentRankMapper, HpgpDepartmentRank> implements HpgpDepartmentRankService {
@Override
public void updateResource() {
List<HpgpDepartmentRank> deptList = this.list();
deptList.forEach(dept -> {
if (dept.getOneDeptCode().equals(dept.getDeptCode())) {
return;
}
this.asyncUpdateRank(dept);
});
}
@Override
public HpgpDepartmentRank getByCode(String hospCode, String oneDeptCode, String deptCode) {
LambdaQueryWrapper<HpgpDepartmentRank> wrapper = Wrappers.lambdaQuery();
wrapper.eq(HpgpDepartmentRank::getHospitalCode, hospCode)
.eq(StrUtil.isNotEmpty(oneDeptCode), HpgpDepartmentRank::getOneDeptCode, oneDeptCode)
.eq(StrUtil.isNotEmpty(deptCode), HpgpDepartmentRank::getDeptCode, deptCode)
.last("limit 1");
return this.getOne(wrapper);
}
@Override
public List<HpgpDepartmentRank> listHotDept() {
LambdaQueryWrapper<HpgpDepartmentRank> wrapper = Wrappers.lambdaQuery();
wrapper.eq(HpgpDepartmentRank::getTag, Constant.STRING_YES);
return this.list(wrapper);
}
@Override
public List<Map<String, List<Map<String, String>>>> getStandardDeptDic(String hospitalCode) {
return this.getStandardDeptDic(hospitalCode);
}
@Async
void asyncUpdateRank(HpgpDepartmentRank dept) {
DeptInfo deptInfo = new DeptInfo();
deptInfo.setHosOrgCode(dept.getHospitalCode());
deptInfo.setOneDeptCode(dept.getOneDeptCode());
deptInfo.setDeptCode(dept.getDeptCode());
List<OutPatInfo> resourceOutPatInfo = WanDaHttpUtil.getOutPatInfo(deptInfo);
List<DoctInfo> resourceDoctInfo = WanDaHttpUtil.getDoctInfo(deptInfo);
if (CollUtil.isEmpty(resourceDoctInfo) && CollUtil.isEmpty(resourceOutPatInfo)) {
return;
}
HpgpDepartmentRank update = new HpgpDepartmentRank();
update.setId(dept.getId());
update.setResourceDoctInfo(JSONUtil.toJsonStr(resourceDoctInfo));
update.setResourceOutPatInfo(JSONUtil.toJsonStr(resourceOutPatInfo));
this.updateById(update);
}
}
package cn.sh.stc.sict.theme.hpgp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.sh.stc.sict.theme.hpgp.dao.HpgpDiagnosticExperienceMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpgpDiagnosticExperience;
import cn.sh.stc.sict.theme.hpgp.service.HpgpDiagnosticExperienceService;
import org.springframework.stereotype.Service;
/**
* 黄浦全科导诊——诊断经验云词(HpgpDiagnosticExperience)表服务实现类
*
* @author zhangly
* @since 2022-01-14 09:56:48
*/
@Service("hpgpDiagnosticExperienceService")
public class HpgpDiagnosticExperienceServiceImpl extends ServiceImpl<HpgpDiagnosticExperienceMapper, HpgpDiagnosticExperience> implements HpgpDiagnosticExperienceService {
}
package cn.sh.stc.sict.theme.hpgp.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.sh.stc.sict.theme.hpgp.dao.HpgpInspectionCheckMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpgpInspectionCheck;
import cn.sh.stc.sict.theme.hpgp.service.HpgpInspectionCheckService;
import org.springframework.stereotype.Service;
/**
* 黄浦全科导诊——检验检查云词(HpgpInspectionCheck)表服务实现类
*
* @author zhangly
* @since 2022-01-14 09:56:49
*/
@Service("hpgpInspectionCheckService")
public class HpgpInspectionCheckServiceImpl extends ServiceImpl<HpgpInspectionCheckMapper, HpgpInspectionCheck> implements HpgpInspectionCheckService {
}
package cn.sh.stc.sict.theme.hpgp.service.impl;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.theme.hpgp.dao.HpgpKsHotMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpgpKsHot;
import cn.sh.stc.sict.theme.hpgp.service.HpgpKsHotService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* (HpgpKsHot)表服务实现类
*
* @author gao
* @since 2022-11-07 10:33:21
*/
@Service("hpgpKsHotService")
public class HpgpKsHotServiceImpl extends ServiceImpl<HpgpKsHotMapper, HpgpKsHot> implements HpgpKsHotService {
@Override
public List<HpgpKsHot> listHotDept(String yljgdm, int size) {
LambdaQueryWrapper<HpgpKsHot> wrapper = Wrappers.lambdaQuery();
wrapper.eq(HpgpKsHot::getGzh, StrUtil.isBlank(yljgdm) ? "ALL" : yljgdm)
.orderByAsc(HpgpKsHot::getRankScore)
.last("limit " + size);
return this.list(wrapper);
}
}
package cn.sh.stc.sict.theme.hpgp.service.impl;
import cn.sh.stc.sict.theme.hpgp.dao.HpgpLabExperienceMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpgpLabExperience;
import cn.sh.stc.sict.theme.hpgp.service.HpgpLabExperienceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* 医院科室-检验-词云(HpgpLabExperience)表服务实现类
*
* @author makejava
* @since 2022-06-23 11:38:13
*/
@Service("hpgpLabExperienceService")
public class HpgpLabExperienceServiceImpl extends ServiceImpl<HpgpLabExperienceMapper, HpgpLabExperience> implements HpgpLabExperienceService {
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.service.impl;
import cn.sh.stc.sict.theme.hpgp.dao.HpgpLumbarAnswerMapper;
import cn.sh.stc.sict.theme.hpgp.model.HpgpLumbarAnswer;
import cn.sh.stc.sict.theme.hpgp.service.HpgpLumbarAnswerService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* 腰椎问卷(HpgpLumbarAnswer)表服务实现类
*
* @author makejava
* @since 2022-06-23 10:43:15
*/
@Service("hpgpLumbarAnswerService")
public class HpgpLumbarAnswerServiceImpl extends ServiceImpl<HpgpLumbarAnswerMapper, HpgpLumbarAnswer> implements HpgpLumbarAnswerService {
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.vo;
import cn.sh.stc.sict.theme.hpgp.model.HpgpDepartmentRank;
import lombok.Data;
@Data
public class DeptRankVO extends HpgpDepartmentRank {
private String oneDeptCode;
private String subDeptCode;
}
package cn.sh.stc.sict.theme.hpgp.vo;
import cn.hutool.core.util.StrUtil;
import lombok.Data;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author zhangly
* @Description
* @Date 2022/1/14 10:50
**/
@Data
public class IntelligentAnswerVO {
public void setAnswer(String answer) {
this.answer = answer;
if (StrUtil.isNotBlank(answer)){
parseDept();
}
}
public IntelligentAnswerVO(String answer) {
this.answer = answer;
if (StrUtil.isNotBlank(answer)){
parseDept();
}
}
public IntelligentAnswerVO(String answer, String deptName) {
this.answer = answer;
this.deptName = deptName;
}
public IntelligentAnswerVO() {
}
private String answer;
private String deptName;
private void parseDept() {
String reg = "分析和推荐的就诊科室为:(.*)\\n?(";
Pattern p = Pattern.compile(reg);
Matcher m = p.matcher(answer);
if(m.find()){
deptName = m.group(1);
}
}
}
package cn.sh.stc.sict.theme.hphy.constant;
/**
* @author zhangly
* @Description
* @Date 2022/1/14 14:13
**/
public class DataConstant {
public static final Byte TOP_DEPT = 1;
public static final Byte TWO_DEPT = 2;
}
package cn.sh.stc.sict.theme.hphy.controller.mp;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.net.Ipv4Util;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.core.util.WebUtils;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.hphy.constant.PatientConstant;
import cn.sh.stc.sict.theme.hphy.model.HpAppointment;
import cn.sh.stc.sict.theme.hphy.model.HpDocInfo;
import cn.sh.stc.sict.theme.hphy.model.HpHosInfo;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import cn.sh.stc.sict.theme.hphy.service.HpAppointmentService;
import cn.sh.stc.sict.theme.hphy.service.HpDocInfoService;
import cn.sh.stc.sict.theme.hphy.service.HpHosInfoService;
import cn.sh.stc.sict.theme.hphy.service.HphyPatientBaseService;
import cn.sh.stc.sict.theme.hphy.model.*;
import cn.sh.stc.sict.theme.hphy.service.*;
import cn.sh.stc.sict.theme.hphy.wd.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.netty.util.internal.MacAddressUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import org.springframework.web.bind.annotation.*;
/**
......@@ -45,6 +38,8 @@ public class AppointmentController {
private HpDocInfoService hpDocInfoService;
private HphyPatientBaseService hphyPatientBaseService;
private HpHosInfoService hosInfoService;
private HpDeptInfoService hpDeptInfoService;
private HpPatientCardService hpPatientCardService;
@ApiOperation("预约须知")
@GetMapping("/app/rule")
......@@ -53,38 +48,80 @@ public class AppointmentController {
return new R(cfg);
}
@SysLog
@ApiOperation("预约")
@PostMapping("/app")
public R appointment(@RequestBody OrderInfo order) throws Exception {
log.error("预约 order = {}", JSONUtil.toJsonStr(order));
CurrentUser current = SecurityUtils.getCurrentUser();
HpAppointment app = new HpAppointment();
if (StrUtil.isBlank(current.getOpenId())) {
return new R().error("患者信息异常!");
}
if (StrUtil.isBlank(order.getHosOrgCode())) {
return new R().error("预约医院信息不可为空!");
}
if (StrUtil.isBlank(order.getDoctorId())) {
if (WanDaConstant.ORDER_TYPE_OUTP.equals(order.getOrderType()) && StrUtil.isBlank(order.getDoctorId())) {
return new R().error("预约医生信息不可为空!");
}
if (WanDaConstant.ORDER_TYPE_CLINC.equals(order.getOrderType()) && StrUtil.isBlank(order.getDeptId())) {
return new R().error("预约门诊信息不可为空!");
}
if (StrUtil.isBlank(order.getScheduleId()) || StrUtil.isBlank(order.getNumSourceId())) {
return new R().error("预约排班号源信息不可为空!");
}
// HpHosInfo hos = hosInfoService.getById(order.getHosOrgCode());
// if (null == hos) {
// return new R().error("未找到医院信息!");
// }
HpHosInfo hos = hosInfoService.getById(order.getHosOrgCode());
if (null == hos) {
return new R().error("未找到医院信息!");
}
HphyPatientBase patient = hphyPatientBaseService.getByOpenId(current.getOpenId());
if (null == patient) {
return new R().error("未找到患者信息!");
}
HpDocInfo docInfo = hpDocInfoService.getById(order.getDoctorId());
if (null == docInfo) {
return new R().error("未找到医生信息!");
boolean isNullCard = (StrUtil.isBlank(order.getMediCardId()) || StrUtil.isBlank(order.getMediCardType()))
&& (StrUtil.isBlank(patient.getMediCardId()) || StrUtil.isBlank(patient.getMediCardType()));
// 有卡预约时检查就诊卡信息
if (WanDaConstant.ORDER_MODEL_1.equals(hos.getOrderMode()) && isNullCard) {
log.error("患者信息:{},预约信息:{}", JSONUtil.toJsonStr(patient), JSONUtil.toJsonStr(order));
return new R().error("请补充患者就诊卡信息!");
}
String deptName = "";
String doctorName = "";
String resourceName = "";
if (WanDaConstant.ORDER_TYPE_OUTP.equals(order.getOrderType())) {
HpDocInfo docInfo = hpDocInfoService.getById(order.getDoctorId());
if (null == docInfo) {
return new R().error("未找到医生信息!");
}
order.setOneDeptCode(docInfo.getOneDeptCode());
order.setDeptCode(docInfo.getDeptCode());
order.setResourceCode(docInfo.getResourceCode());
order.setDeptName(docInfo.getDeptName());
app.setDoctorId(docInfo.getId().toString());
app.setResourceCertId(docInfo.getPersonId());
app.setHosOrgName(docInfo.getHosName());
app.setDeptName(docInfo.getDeptName());
app.setResourceName(docInfo.getResourceName());
app.setDoctorName(docInfo.getResourceName());
deptName = docInfo.getDeptName();
doctorName = docInfo.getResourceName();
resourceName = docInfo.getResourceName();
} else {
HpDeptInfo deptInfo = hpDeptInfoService.getById(order.getDeptId());
if (null == deptInfo) {
return new R().error("未找到门诊信息!");
}
order.setOneDeptCode(deptInfo.getOneDeptCode());
order.setDeptCode(deptInfo.getDeptCode());
order.setResourceCode(deptInfo.getDeptCode());
order.setDeptName(deptInfo.getDeptName());
app.setHosOrgName(deptInfo.getHosName());
app.setDeptName(deptInfo.getDeptName());
app.setResourceName(deptInfo.getDeptName());
deptName = deptInfo.getDeptName();
resourceName = deptInfo.getDeptName();
}
order.setOneDeptCode(docInfo.getOneDeptCode());
order.setDeptCode(docInfo.getDeptCode());
order.setOrderType(WanDaConstant.ORDER_TYPE_OUTP);
order.setResourceCode(docInfo.getResourceCode());
// order.setOrderType(WanDaConstant.ORDER_TYPE_OUTP);
order.setChannelCode(WanDaConstant.CHANNEL_CODE_OTHER);
order.setPayMode(WanDaConstant.PAY_MODE_HOSP);
order.setUserCardType(WanDaConstant.USER_CARD_TYPE_ID);
......@@ -102,34 +139,46 @@ public class AppointmentController {
order.setChannelName(WanDaConstant.CHANNEL_NAME);
order.setNumSourceFrom(WanDaConstant.NUM_SOURCE_FROM);
order.setPatient_type(WanDaConstant.PATIENT_TYPE_NORMAL);
order.setMediCardId("");
order.setMediCardType("");
if (StrUtil.isBlank(order.getMediCardId()) || StrUtil.isBlank(order.getMediCardType())) {
log.error("自动设置卡类型");
order.setMediCardId("");
order.setMediCardType("");
if (StrUtil.isAllNotBlank(patient.getMediCardId(), patient.getMediCardType())
&& WanDaConstant.ORDER_MODEL_1.equals(hos.getOrderMode())) {
log.error("卡号= {},卡类型={}", patient.getMediCardId(), patient.getMediCardType());
order.setMediCardId(patient.getMediCardId());
order.setMediCardType(patient.getMediCardType());
}
}
order.setUserBD(DateUtil.format(IdcardUtil.getBirthDate(patient.getCertId()), DatePattern.NORM_DATE_PATTERN));
AppResult result = WanDaHttpUtil.submitOrderByUserInfo(order);
if (null != result) {
MapperFactory factory = new DefaultMapperFactory.Builder().build();
HpAppointment app = factory.getMapperFacade().map(order, HpAppointment.class);
// MapperFactory factory = new DefaultMapperFactory.Builder().build();
// HpAppointment app = factory.getMapperFacade().map(order, HpAppointment.class);
BeanUtil.copyProperties(order, app);
app.setOrderId(result.getOrderId());
app.setPatientId(patient.getId().toString());
app.setDoctorId(docInfo.getId().toString());
app.setResourceCertId(docInfo.getPersonId());
app.setNumSourceDetailId(result.getNumSourceDetailId());
app.setNumPassword(result.getNumPassword());
app.setRoom(result.getRoom());
app.setHosNumSourceId(result.getHosNumSourceId());
app.setStatus(Constant.STRING_NO);
app.setHosOrgName(docInfo.getHosName());
app.setDeptName(docInfo.getDeptName());
app.setOrderNumType(order.getOrderNumType());
app.setPatientName(patient.getName());
app.setResourceName(docInfo.getResourceName());
app.setDeptName(deptName);
app.setDoctorName(doctorName);
app.setResourceName(resourceName);
app.setStatus(Constant.STRING_NO);
app.setEvaStatus(Constant.BYTE_NO);
hpAppointmentService.save(app);
hpPatientCardService.updateByApp(patient, order);
return new R().success(result);
}
return new R().error("预约失败!");
}
@SysLog
@ApiOperation("取消预约")
@PostMapping("/cancel/app")
public R cancelAppointment(@RequestBody CancelOrderInfo order) throws Exception {
......@@ -180,7 +229,7 @@ public class AppointmentController {
@ApiOperation("预约详情")
@GetMapping("/app/info")
public R appInfo(@RequestParam("appId")String appId) {
public R appInfo(@RequestParam("appId") String appId) {
HpAppointment app = hpAppointmentService.getById(appId);
return new R(app);
}
......
package cn.sh.stc.sict.theme.hphy.controller.mp;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author zhangly
* @Description
* @Date 2022/1/11 16:44
**/
@RestController
@RequestMapping("/c/guide")
public class AppointmentGuideController {
}
package cn.sh.stc.sict.theme.hphy.controller.mp;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.theme.hpgp.model.HpgpDepartmentRank;
import cn.sh.stc.sict.theme.hpgp.service.HpgpBusyIdlePredictionService;
import cn.sh.stc.sict.theme.hpgp.service.HpgpDepartmentRankService;
import cn.sh.stc.sict.theme.hphy.model.HpDeptInfo;
import cn.sh.stc.sict.theme.hphy.service.HpDeptInfoService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.api.ApiController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* (HpDeptInfo)维护接口
*
* @author makejava
* @since 2021-01-28 10:35:58
*/
@Api(value = "[C] 黄浦预约——科室信息接口", tags = "[C] 黄浦预约——科室信息接口")
@RestController
@RequestMapping("/hphy/c/dept")
@AllArgsConstructor
@Slf4j
public class HpDeptInfoController extends ApiController {
/**
* 服务对象
*/
private final HpDeptInfoService hpDeptInfoService;
private final HpgpDepartmentRankService hpgpDepartmentRankService;
private final HpgpBusyIdlePredictionService hpgpBusyIdlePredictionService;
@ApiOperation("科室医生查询接口")
@GetMapping
public R<?> getDeptDoctors(@ApiParam("医院代码") @RequestParam("hospitalCode") String hospitalCode,
@ApiParam("科室代码") @RequestParam("deptCode") String deptCode) {
return new R<>(hpDeptInfoService.getDeptDoctors(hospitalCode, deptCode));
}
@ApiOperation("更新科室号源信息")
@PostMapping("/wd/resource")
public R updateDeptResource() {
List<HpDeptInfo> deptList = hpDeptInfoService.list();
deptList.forEach(dept -> {
if (StrUtil.isEmpty(dept.getOneDeptCode()) || StrUtil.isEmpty(dept.getDeptCode())) {
return;
}
hpDeptInfoService.asyncUpdate(dept);
});
return new R();
}
@ApiOperation("更新科室排行表号源信息")
@PostMapping("/rank/wd/resource")
public R updateRankDeptResource() {
hpgpDepartmentRankService.updateResource();
return new R();
}
@ApiOperation("定时统计排行科室的号源信息")
@PostMapping("/statistic/rank/wd/resource")
public R statisticRankDeptResourceInfo(@RequestParam(value = "hospCode", required = false) String hospCode,
@RequestParam(value = "oneDeptCode", required = false) String oneDeptCode,
@RequestParam(value = "dept", required = false) String deptCode,
@RequestParam(value = "flag", required = false, defaultValue = Constant.STRING_NO) Byte flag) {
LambdaQueryWrapper<HpDeptInfo> wrapper = Wrappers.<HpDeptInfo>lambdaQuery();
wrapper.eq(HpDeptInfo::getDeptLevel, 2)
.eq(StrUtil.isNotEmpty(hospCode), HpDeptInfo::getHosOrgCode, hospCode)
.eq(StrUtil.isNotEmpty(oneDeptCode), HpDeptInfo::getOneDeptCode, oneDeptCode)
.eq(StrUtil.isNotEmpty(deptCode), HpDeptInfo::getDeptCode, deptCode);;
List<HpDeptInfo> deptList = hpDeptInfoService.list(wrapper);
log.error("医院科室查询结果deptList = {}", deptList);
deptList.forEach(dept -> {
if (StrUtil.isEmpty(dept.getOneDeptCode()) || StrUtil.isEmpty(dept.getDeptCode())) {
return;
}
Date startDate = DateUtil.date();
Date endDate = DateUtil.offsetDay(startDate, 10);
hpgpBusyIdlePredictionService.statisticResourceInfo(dept, startDate, endDate, flag);
});
return new R();
}
@GetMapping("/standard-dic")
public R<?> standardDeptDic(@ApiParam("医院编码") @RequestParam(value = "hospitalCode", required = false) String hospitalCode) {
return new R<>().success(hpgpDepartmentRankService.getStandardDeptDic(hospitalCode));
}
}
......@@ -5,6 +5,7 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.HttpRequest;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
......@@ -22,16 +23,17 @@ import java.util.Map;
@Slf4j
@RestController
@AllArgsConstructor
@Api(tags = "[C]智能问答")
@Api(tags = "[C]黄浦高血压专病导医——智能问答")
@RequestMapping("/c/intelligent/qa")
public class IntelligentQAController {
public class HpHyIntelligentQAController {
private final static String CONTENT = "Content";
@SysLog
@ApiOperation("智能问答")
@PostMapping
public R qa(String question) {
CurrentUser current = SecurityUtils.getCurrentUser();
String from = null != current ? (StrUtil.isNotBlank(current.getOpenId()) ? current.getOpenId() : current.getId().toString()) : IdWorker.getIdStr();
String from = StrUtil.isNotBlank(current.getOpenId()) ? current.getOpenId() : current.getId().toString();
String xml = "<xml>\n" +
" <ToUserName><![CDATA[gh_fe5b36b12c61]]></ToUserName>\n" +
......@@ -41,6 +43,8 @@ public class IntelligentQAController {
" <Content><![CDATA[" + question + "]]></Content>\n" +
" <MsgId>" + IdWorker.getId() + "</MsgId>\n" +
"</xml>";
// 162 为黄浦高血压专病导医机器人
// 51 黄浦高血压全科导诊机器人
String body = HttpRequest.post("http://30.30.5.74:9988/qa/jqrsvr.ashx?Command=talk_162")
.body(xml)
.execute()
......
......@@ -7,6 +7,7 @@ import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.theme.common.dto.SocketMsg;
import cn.sh.stc.sict.theme.handler.WebSocketServer;
......@@ -108,6 +109,7 @@ public class HphyEvaController {
*
* @return
*/
@SysLog
@ApiOperation("提交答案并获取下一题")
@PostMapping("/next")
@Transactional(rollbackFor = Exception.class)
......
package cn.sh.stc.sict.theme.hphy.controller.mp;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.enums.LoginTypeEnum;
import cn.sh.stc.sict.cloud.common.core.dto.*;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.core.util.ValidateCodeUtil;
import cn.sh.stc.sict.cloud.common.core.util.SsbUtil;
import cn.sh.stc.sict.cloud.common.core.util.WoaUtil;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.cloud.upms.model.SysUserBase;
import cn.sh.stc.sict.theme.annotation.SecurityParameter;
import cn.sh.stc.sict.theme.hphy.constant.PatientConstant;
import cn.sh.stc.sict.theme.hphy.model.HpPatientCard;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import cn.sh.stc.sict.theme.hphy.service.HpPatientCardService;
import cn.sh.stc.sict.theme.hphy.service.HphyPatientBaseService;
import cn.sh.stc.sict.theme.hphy.wd.WanDaHttpUtil;
import io.swagger.annotations.Api;
......@@ -19,6 +28,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 患者基本信息
......@@ -35,6 +46,7 @@ public class HphyPatientBaseController {
private HphyPatientBaseService hphyPatientBaseService;
private StringRedisTemplate redisTemplate;
private HpPatientCardService hpPatientCardService;
/**
* 注册并关联登录信息
......@@ -42,18 +54,24 @@ public class HphyPatientBaseController {
* @param patient
* @return
*/
@SysLog
@ApiOperation("注册")
@PostMapping("/register")
@SecurityParameter(outEncode = false)
public R register(@RequestBody HphyPatientBase patient) {
CurrentUser current = SecurityUtils.getCurrentUser();
HphyPatientBase base = hphyPatientBaseService.getByOpenId(current.getOpenId());
HphyPatientBase base = hphyPatientBaseService.getCurrentBase();
patient.setOpenId(current.getOpenId());
// if(!ValidateCodeUtil.validateCode(redisTemplate, patient.getPhone(), patient.getRandomCode(), Constant.BYTE_YES)){
// return new R().error("验证码错误!");
// }
// 根据手机号去重
if (base == null || NumberUtil.isNullOrZero(base.getId())) {
base = hphyPatientBaseService.getByPhone(current.getPhone(), true);
}
if (base != null) {
if (base != null && NumberUtil.isNotNullOrZero(base.getId())) {
patient.setId(base.getId());
} else {
patient.setPhone(current.getPhone());
patient.setUserId(current.getId());
}
// 身份证验证
if (StrUtil.isBlank(patient.getCertId())) {
......@@ -66,16 +84,16 @@ public class HphyPatientBaseController {
patient.setAge(String.valueOf(IdcardUtil.getAgeByIdCard(patient.getCertId())));
patient.setGender(IdcardUtil.getGenderByIdCard(patient.getCertId()) == 1 ? "男" : "女");
// 手机号redis验证
// 根据手机号去重
// 获取家庭医生签约信息
try {
String familyDocHos = WanDaHttpUtil.getContractInfo(patient.getCertId());
if(StrUtil.isNotBlank(familyDocHos)){
if (StrUtil.isNotBlank(familyDocHos)) {
patient.setFamilyDocHos(familyDocHos);
}
}catch (Exception e){
} catch (Exception e) {
log.error(e.getMessage(), e);
}
patient.setVerifyStatus(Constant.STRING_YES);
hphyPatientBaseService.saveOrUpdate(patient);
return new R(patient.getId());
......@@ -92,8 +110,11 @@ public class HphyPatientBaseController {
* @return
*/
@GetMapping
@SecurityParameter(inDecode = false)
public R getInfo() {
log.error("获取患者信息1");
CurrentUser current = SecurityUtils.getCurrentUser();
log.error("获取患者信息2, current = {}", JSONUtil.toJsonStr(current));
if (StrUtil.isBlank(current.getOpenId())) {
log.error("openId 为空");
......@@ -105,7 +126,105 @@ public class HphyPatientBaseController {
current.setGender(PatientConstant.getGender(base.getGender()));
SecurityUtils.updateCurrent(current);
}
log.error("获取患者信息2, base = {}", JSONUtil.toJsonStr(base));
return new R(base);
}
@ApiOperation("第三方公众号进入系统时,获取患者信息")
@GetMapping("/third-party")
@SecurityParameter(inDecode = false)
public R getInfoByToken(@RequestParam("source") String source,
@RequestParam("token") String token) {
log.error("source = {}, token = {}", source, token);
CurrentUser current = SecurityUtils.getCurrentUser();
if (StrUtil.isBlank(current.getOpenId())) {
log.error("openId 为空");
}
// 获取患者信息
HphyPatientBase base = hphyPatientBaseService.getByOpenId(current.getOpenId());
log.error("获取患者信息 = {}", JSONUtil.toJsonStr(base));
// 根据手机号去重
if (ObjectUtil.isNull(base) || NumberUtil.isNullOrZero(base.getId())) {
base = hphyPatientBaseService.getByPhone(current.getPhone(), true);
if (ObjectUtil.isNotNull(base) && NumberUtil.isNotNullOrZero(base.getId())) {
HphyPatientBase update = new HphyPatientBase();
update.setOpenId(current.getOpenId());
update.setId(base.getId());
hphyPatientBaseService.updateById(update);
}
}
if (ObjectUtil.isNull(base) || NumberUtil.isNullOrZero(base.getId())) {
// 随身办
if (LoginTypeEnum.SSB.getType().equals(source)) {
WDUserInfo userInfo = SsbUtil.getUserInfo(token);
log.error("wdUser = {}", userInfo);
List<WDUserCardInfo> cardList = SsbUtil.getUserCardInfoList(token);
base = hphyPatientBaseService.saveSSbInfo(current, userInfo, cardList);
hpPatientCardService.save(base, cardList);
}
// 纳里用户系统公众号
if (LoginTypeEnum.WOA_NL.getType().equals(source)) {
XSZYUserInfo xszyUserInfo = JSONUtil.toBean(current.getXszyUserInfo(), XSZYUserInfo.class);
log.error("woaXszyUser = {}", xszyUserInfo);
base = hphyPatientBaseService.saveWoaXszyInfo(current, xszyUserInfo);
}
// 中智用户系统公众号
if (LoginTypeEnum.WOA_ZZ.getType().equals(source)) {
WOAZzUserInfo zzUserInfo = WoaUtil.getZzUserInfo(current.getAppId(), token);
log.error("zzUser = {}", zzUserInfo);
base = hphyPatientBaseService.saveWoaZzInfo(current, zzUserInfo);
}
// 万达微信公众后
if (LoginTypeEnum.WOA_WD.getType().equals(source)) {
WOAWDUserInfo wdUserInfo = WoaUtil.getWoaWDUserInfo(token);
log.error("wdUserInfo = {}", wdUserInfo);
base = hphyPatientBaseService.saveWoaWdInfo(current, wdUserInfo);
}
// 万达南东社区公众后
if (LoginTypeEnum.WOA_ND.getType().equals(source)) {
WOAWDUserInfo wdUserInfo = WoaUtil.getThirdPartyUserInfo(token);
log.error("wdndUserInfo = {}", wdUserInfo);
base = hphyPatientBaseService.saveWoaWdInfo(current, wdUserInfo);
}
}
if (ObjectUtil.isNull(base) || NumberUtil.isNullOrZero(base.getId())) {
return new R().error("患者未实名!");
}
if (StrUtil.isNotBlank(base.getGender())) {
current.setGender(PatientConstant.getGender(base.getGender()));
SecurityUtils.updateCurrent(current);
}
// 更新卡号卡类型
if (LoginTypeEnum.WOA_NL.getType().equals(source)) {
log.error("woaXszyUser = {}", current.getXszyUserInfo());
XSZYUserInfo xszyUserInfo = JSONUtil.toBean(current.getXszyUserInfo(), XSZYUserInfo.class);
base.setMediCardType(xszyUserInfo.getMediCardType());
base.setMediCardId(xszyUserInfo.getMediCardId());
hphyPatientBaseService.updateById(base);
}
return new R(base);
}
@ApiOperation("获取患者就诊卡list")
@GetMapping("/card/list")
public R listPatientCard() {
CurrentUser current = SecurityUtils.getCurrentUser();
List<HpPatientCard> cardList = hpPatientCardService.listByUserId(current.getId());
return new R(cardList);
}
@ApiOperation("第三方公众号进入系统时,获取患者信息")
@GetMapping("/third-party/woa")
public R getwoa(@RequestParam("source") String source,
@RequestParam("token") String token) {
log.error("source = {}, token = {}", source, token);
XSZYUserInfo xszyUserInfo = WoaUtil.getXszyUserInfo(token);
return new R(xszyUserInfo);
}
}
package cn.sh.stc.sict.theme.hphy.controller.mp;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientRelation;
import cn.sh.stc.sict.theme.hphy.service.HphyPatientBaseService;
import cn.sh.stc.sict.theme.hphy.service.HphyPatientRelationService;
import cn.sh.stc.sict.theme.hphy.vo.PatientRelationDTO;
import cn.sh.stc.sict.theme.hphy.vo.PatientRelationVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.io.Serializable;
import java.util.List;
/**
* 患者-家庭成员关系表(HphyPatientRelation)表控制层
*
* @author F_xh
* @since 2022-10-10 14:41:04
*/
@Slf4j
@RestController
@AllArgsConstructor
@Api(tags = "[C]患者-家庭成员关系表")
@RequestMapping("/hphyPatientRelation")
public class HphyPatientRelationController {
/**
* 服务对象
*/
private final HphyPatientRelationService hphyPatientRelationService;
private final HphyPatientBaseService hphyPatientBaseService;
@ApiOperation("获取自己的家庭成员")
@GetMapping("/list")
public R list() {
CurrentUser current = SecurityUtils.getCurrentUser();
HphyPatientBase base = hphyPatientBaseService.getByOpenId(current.getOpenId());
if (ObjectUtil.isNull(base) || NumberUtil.isNullOrZero(base.getId())) {
return new R();
}
List<PatientRelationVO> result = hphyPatientRelationService.listPatientRelation(base.getId());
return new R(result);
}
@ApiOperation("新增家庭成员")
@PostMapping
@Transactional(rollbackFor = Exception.class)
public R insert(@RequestBody PatientRelationDTO dto) {
HphyPatientBase base = hphyPatientBaseService.getCurrentBase();
if (ObjectUtil.isNull(base) || NumberUtil.isNullOrZero(base.getId())) {
return new R().error("当前登陆人信息异常");
}
if (StrUtil.isBlank(dto.getPatient().getName())) {
return new R().error("姓名不可为空!");
}
if (StrUtil.isBlank(dto.getPatient().getCertId())) {
return new R().error("身份证号不可为空!");
}
if (StrUtil.isBlank(dto.getRelation().getRelationName())) {
return new R().error("关系不可为空!");
}
if (StrUtil.isBlank(dto.getPatient().getPhone())) {
return new R().error("手机号不可为空!");
}
hphyPatientBaseService.savePatient(dto.getPatient());
dto.getRelation().setSourcePatientId(base.getId());
dto.getRelation().setTargetPatientId(dto.getPatient().getId());
LambdaQueryWrapper<HphyPatientRelation> wrapper = Wrappers.lambdaQuery();
wrapper.and(i -> i.eq(HphyPatientRelation::getSourcePatientId, base.getId()).eq(HphyPatientRelation::getTargetPatientId, dto.getPatient().getId()))
.or().and(i -> i.eq(HphyPatientRelation::getSourcePatientId, dto.getPatient().getId()).eq(HphyPatientRelation::getTargetPatientId, base.getId()));
hphyPatientRelationService.saveOrUpdate(dto.getRelation(), wrapper);
return new R();
}
@ApiOperation("删除关系")
@DeleteMapping("/{relationId}")
public R delete(@PathVariable Long relationId) {
HphyPatientRelation relation = hphyPatientRelationService.getById(relationId);
if (ObjectUtil.isNull(relation) || NumberUtil.isNullOrZero(relation.getId())) {
return new R().error("未找到待删除项!");
}
hphyPatientRelationService.removeById(relationId);
return new R();
}
}
\ No newline at end of file
......@@ -4,10 +4,7 @@ import cn.sh.stc.sict.cloud.common.core.util.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
/**
* @author F_xh
......
......@@ -3,10 +3,15 @@ package cn.sh.stc.sict.theme.hphy.controller.mp;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.core.util.ValidateCodeUtil;
import cn.sh.stc.sict.theme.hpgp.model.HpgpDepartmentRank;
import cn.sh.stc.sict.theme.hpgp.service.HpgpDepartmentRankService;
import cn.sh.stc.sict.theme.hphy.service.HpDeptInfoService;
import cn.sh.stc.sict.theme.hphy.wd.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
......@@ -17,6 +22,7 @@ import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author F_xh
......@@ -29,6 +35,10 @@ public class WDController {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private HpgpDepartmentRankService hpgpDepartmentRankService;
@Autowired
private HpDeptInfoService hpDeptInfoService;
/**
* 0. 发短信
......@@ -64,25 +74,42 @@ public class WDController {
@GetMapping("/num/info")
public R getOrderNumberInfo(NumSourceInfo numSourceInfo) {
// 医生查询所有号源能查到,查询指定类型号源差不多,20220715处理:查询所有,过滤
// String orderNumType = numSourceInfo.getOrderNumType();
// if(WanDaConstant.ORDER_TYPE_OUTP.equals(numSourceInfo.getOrderType())){
// numSourceInfo.setOrderNumType(null);
// }
numSourceInfo.setOrderNumType(null);
List<NumSourceInfo> list = WanDaHttpUtil.getOrderNumInfo(numSourceInfo);
if (CollUtil.isNotEmpty(list)) {
return R.builder().code(Constant.BYTE_YES).data(list).bizCode(Constant.INT_NO).build();
if(CollUtil.isEmpty(list)){
return new R();
}
DeptInfo deptInfo = new DeptInfo();
deptInfo.setHosOrgCode(numSourceInfo.getHosOrgCode());
deptInfo.setOneDeptCode(numSourceInfo.getOneDeptCode());
deptInfo.setDeptCode(numSourceInfo.getDeptCode());
List<OutPatInfo> outPatInfo = WanDaHttpUtil.getResourceOutPatInfo(deptInfo);
if (CollUtil.isNotEmpty(outPatInfo)) {
numSourceInfo.setOrderType(WanDaConstant.ORDER_TYPE_CLINC);
numSourceInfo.setResourceCode(outPatInfo.get(0).getResourceCode());
list = WanDaHttpUtil.getOrderNumInfo(numSourceInfo);
return new R(list);
// if(WanDaConstant.ORDER_TYPE_OUTP.equals(numSourceInfo.getOrderType())){
// List<NumSourceInfo> result = list.stream().filter(i -> orderNumType.equals(i.getOrderNumType())).collect(Collectors.toList());
// return new R(result);
// }else{
// return new R(list);
// }
return new R(list);
}
return new R().success(list);
// if (CollUtil.isNotEmpty(list)) {
// return R.builder().code(Constant.BYTE_YES).data(list).bizCode(Constant.INT_NO).build();
// }
//
// DeptInfo deptInfo = new DeptInfo();
// deptInfo.setHosOrgCode(numSourceInfo.getHosOrgCode());
// deptInfo.setOneDeptCode(numSourceInfo.getOneDeptCode());
// deptInfo.setDeptCode(numSourceInfo.getDeptCode());
// List<OutPatInfo> outPatInfo = WanDaHttpUtil.getResourceOutPatInfo(deptInfo);
// if (CollUtil.isNotEmpty(outPatInfo)) {
// numSourceInfo.setOrderType(WanDaConstant.ORDER_TYPE_CLINC);
// numSourceInfo.setResourceCode(outPatInfo.get(0).getResourceCode());
// list = WanDaHttpUtil.getOrderNumInfo(numSourceInfo);
//
// return new R(list);
// }
// return new R().success(list);
}
@ApiOperation("获取测压亭列表")
......@@ -90,4 +117,5 @@ public class WDController {
public R getPressureStationList(){
return new R();
}
}
package cn.sh.stc.sict.theme.hphy.controller.web;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.theme.hpgp.model.HpAppointmentEva;
import cn.sh.stc.sict.theme.hpgp.service.HpAppointmentEvaService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@AllArgsConstructor
@Api(tags = "[B]预约评价")
@RequestMapping("/app/eva")
public class AppEvaController {
private final HpAppointmentEvaService hpAppointmentEvaService;
@ApiOperation("分页")
@GetMapping("/page")
public R hasEavedPage(Page page, HpAppointmentEva eva) {
LambdaQueryWrapper<HpAppointmentEva> wrapper = Wrappers.lambdaQuery();
wrapper.like(StrUtil.isNotBlank(eva.getPatientName()), HpAppointmentEva::getPatientName, eva.getPatientName())
.like(StrUtil.isNotBlank(eva.getHospName()), HpAppointmentEva::getHospName, eva.getHospName())
.like(StrUtil.isNotBlank(eva.getDeptName()), HpAppointmentEva::getDeptName, eva.getDeptName())
.like(StrUtil.isNotBlank(eva.getDoctorName()), HpAppointmentEva::getDoctorName, eva.getDoctorName())
.orderByDesc(HpAppointmentEva::getCreateTime);
return new R(hpAppointmentEvaService.page(page, wrapper));
}
}
package cn.sh.stc.sict.theme.hphy.controller.web;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.hphy.model.HphyGuideRecord;
import cn.sh.stc.sict.theme.hphy.service.HphyGuideQuestionService;
import cn.sh.stc.sict.theme.hphy.service.HphyGuideRecordService;
import cn.sh.stc.sict.theme.hphy.vo.DiseaseAnalysisDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
......@@ -35,20 +34,32 @@ public class GuideRecordController {
@ApiOperation("分页查询")
@GetMapping("/page")
public R<HphyGuideRecord> page(Page page, String patientName, String disease){
public R<HphyGuideRecord> page(Page<HphyGuideRecord> page,
String patientName,
String disease,
String hospName,
String deptName,
String doctorName) {
LambdaQueryWrapper<HphyGuideRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StrUtil.isNotBlank(patientName), HphyGuideRecord::getPatientName, patientName)
.like(StrUtil.isNotBlank(disease), HphyGuideRecord::getDisease, disease)
// .like(StrUtil.isNotBlank(hospName), HphyGuideRecord)
.orderByDesc(HphyGuideRecord::getUpdateTime, HphyGuideRecord::getCreateTime);
page = hphyGuideRecordService.page(page, wrapper);
if (CollUtil.isNotEmpty(page.getRecords())) {
page.getRecords().forEach(i -> {
i.setPatientName(DesensitizedUtil.chineseName(i.getPatientName()));
});
}
return new R(page);
}
@ApiOperation("获取详情")
@GetMapping("/info")
public R info(@RequestParam("guideId")Long guideId){
public R info(@RequestParam("guideId") Long guideId) {
HphyGuideRecord guide = hphyGuideRecordService.getById(guideId);
if (guide == null) {
......
package cn.sh.stc.sict.theme.hphy.controller.web;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.theme.hphy.model.HpAppointment;
import cn.sh.stc.sict.theme.hphy.service.HpAppointmentService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.api.ApiController;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
......@@ -23,4 +34,49 @@ public class HpAppointmentController extends ApiController {
* 服务对象
*/
private final HpAppointmentService hpAppointmentService;
@ApiOperation("分页查询 - 预约记录")
@GetMapping("/app/page")
public R appPage(Page<HpAppointment> page,
@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "hospName", required = false) String hospName,
@RequestParam(value = "deptName", required = false) String deptName,
@RequestParam(value = "doctorName", required = false) String doctorName) {
LambdaQueryWrapper<HpAppointment> wrapper = new LambdaQueryWrapper<>();
wrapper.like(StrUtil.isNotBlank(name), HpAppointment::getPatientName, name)
.like(StrUtil.isNotBlank(hospName), HpAppointment::getHosOrgName, hospName)
.like(StrUtil.isNotBlank(doctorName), HpAppointment::getDoctorName, doctorName)
.like(StrUtil.isNotBlank(deptName), HpAppointment::getDeptName, deptName)
.orderByDesc(HpAppointment::getCreateTime);
page = hpAppointmentService.page(page, wrapper);
if(CollUtil.isNotEmpty(page.getRecords())){
page.getRecords().forEach(i->{
i.setPatientName(DesensitizedUtil.chineseName(i.getPatientName()));
i.setUserPhone(DesensitizedUtil.mobilePhone(i.getUserPhone()));
});
}
return new R(page);
}
@ApiOperation("分页查询 - 取消预约记录")
@GetMapping("/cancel/page")
public R cancelPage(Page page,
@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "hospName", required = false) String hospName,
@RequestParam(value = "deptName", required = false) String deptName,
@RequestParam(value = "doctorName", required = false) String doctorName) {
LambdaQueryWrapper<HpAppointment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HpAppointment::getStatus, Constant.BYTE_YES)
.like(StrUtil.isNotBlank(name), HpAppointment::getPatientName, name)
.like(StrUtil.isNotBlank(hospName), HpAppointment::getHosOrgName, hospName)
.like(StrUtil.isNotBlank(doctorName), HpAppointment::getDoctorName, doctorName)
.like(StrUtil.isNotBlank(deptName), HpAppointment::getDeptName, deptName)
.orderByDesc(HpAppointment::getCreateTime);
page = hpAppointmentService.page(page, wrapper);
return new R(page);
}
}
\ No newline at end of file
......@@ -23,4 +23,5 @@ public class HpDocInfoController extends ApiController {
* 服务对象
*/
private final HpDocInfoService hpDocInfoService;
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hphy.controller.web;
import cn.sh.stc.sict.theme.hphy.service.HpDeptInfoService;
import com.baomidou.mybatisplus.extension.api.ApiController;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.theme.common.crypto.EncryptionUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* (HpDeptInfo)维护接口
*
* @author makejava
* @since 2021-01-28 10:35:58
* @author gao
* @date 2023/05/30 14:30
*/
@Api(value = "维护接口", tags = "维护接口")
@Api(value = "[黄浦]安全密钥", tags = "[黄浦]安全密钥")
@RestController
@RequestMapping("hpDeptInfo")
@RequestMapping("hpSecurity")
@AllArgsConstructor
public class HpDeptInfoController extends ApiController {
/**
* 服务对象
*/
private final HpDeptInfoService hpDeptInfoService;
}
\ No newline at end of file
@Slf4j
public class HpSecurityController {
@ApiOperation("获取公钥")
@GetMapping("/public-key")
public R<String> getPublicKey() {
log.info("获取公钥");
return new R<>(EncryptionUtil.PUBLIC_KEY);
}
}
package cn.sh.stc.sict.theme.hphy.controller.web;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.common.crypto.EncryptionUtil;
import cn.sh.stc.sict.theme.hphy.service.HpStatisticsService;
import cn.sh.stc.sict.theme.hphy.service.HpThirdInterfaceStatusService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
/**
* 黄埔医导统计
*
* @author gao
* @date 2023/01/06 10:43
*/
@Api(value = "[黄浦]统计使用情况", tags = "[黄浦]统计使用情况")
@RestController
@RequestMapping("hpStatistics")
@AllArgsConstructor
@Slf4j
public class HpStatisticsController {
private final HpStatisticsService hpStatisticsService;
private final HpThirdInterfaceStatusService hpThirdInterfaceStatusService;
@ApiOperation("统计用户使用情况")
@GetMapping("/usage-overview")
public R statisticsUsage(@RequestParam("startTime") String startTime,
@RequestParam("endTime") String endTime) {
log.error("统计用户使用情况:startTime = {}, token = {}", startTime, endTime);
return new R(hpStatisticsService.getUsageOverviewStatistics(startTime, endTime));
}
@ApiOperation("获取公钥")
@GetMapping("/public-key")
public R<String> getPublicKey() {
log.info("获取公钥");
return new R<>(EncryptionUtil.PUBLIC_KEY);
}
@ApiOperation("第三方提供统计用户使用情况")
@GetMapping("/third/usage-overview")
@SysLog
public R statisticsUsage4Third(@RequestParam("startTime") String startTime,
@RequestParam("endTime") String endTime) {
CurrentUser currentUser = SecurityUtils.getCurrentUser();
log.error("统计用户使用情况:startTime = {}, token = {}, currentUser = {}", startTime, endTime, currentUser.getName());
return new R(hpStatisticsService.countAll4Third(startTime, endTime));
}
@ApiOperation("更新医疗机构对接公众号状态")
@PutMapping("/hos-org-mg-status")
@SysLog
public R updateHosOrgMgStatus(@RequestParam("hosOrgCode") String hosOrgCode,
@RequestParam("status") Integer status) {
hpThirdInterfaceStatusService.updateHosOrgStatus(hosOrgCode, status);
return new R();
}
}
package cn.sh.stc.sict.theme.hphy.controller.web;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.theme.hphy.model.HphyGuideMatch;
import cn.sh.stc.sict.theme.hphy.service.HphyGuideMatchService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
......@@ -34,13 +38,25 @@ public class HphyGuideMatchController {
* 分页查询
*
* @param page 分页对象
* @param hphyGuideMatch 导医推荐记录
* @return
*/
@ApiOperation("分页查询 导医推荐记录")
@GetMapping("/page")
public R<HphyGuideMatch> getHphyGuideMatchPage(Page page, HphyGuideMatch hphyGuideMatch) {
page = hphyGuideMatchService.page(page, Wrappers.query(hphyGuideMatch));
public R<HphyGuideMatch> getHphyGuideMatchPage(Page<HphyGuideMatch> page, HphyGuideMatch guide) {
LambdaQueryWrapper<HphyGuideMatch> wrapper = Wrappers.lambdaQuery();
wrapper.like(StrUtil.isNotBlank(guide.getPatientName()), HphyGuideMatch::getPatientName, guide.getPatientName())
.like(StrUtil.isNotBlank(guide.getHospName()), HphyGuideMatch::getHospName, guide.getHospName())
.like(StrUtil.isNotBlank(guide.getDeptName()), HphyGuideMatch::getDeptName, guide.getDeptName())
.like(StrUtil.isNotBlank(guide.getDoctorName()), HphyGuideMatch::getDoctorName, guide.getDoctorName())
.orderByDesc(HphyGuideMatch::getCreateTime);
page = hphyGuideMatchService.page(page, wrapper);
if(CollUtil.isNotEmpty(page.getRecords())){
page.getRecords().forEach(i->{
i.setPatientName(DesensitizedUtil.chineseName(i.getPatientName()));
});
}
return new R(page);
}
}
package cn.sh.stc.sict.theme.hphy.dao;
import cn.sh.stc.sict.theme.hphy.model.HpPatientCard;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 黄浦-患者-卡号(HpPatientCard)表数据库访问层
*
* @author F_xh
* @since 2022-07-14 11:00:02
*/
public interface HpPatientCardMapper extends BaseMapper<HpPatientCard> {
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hphy.dao;
import cn.sh.stc.sict.theme.hphy.vo.StatisticsUsageVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* @author gao
* @date 2023/01/06 11:09
*/
@Mapper
public interface HpStatisticsMapper {
/**
* 按时间统计各医院预约人数
*
* @param startTime 开始时间
* @param endTime 结束时间
* @return
*/
List<StatisticsUsageVO.HosUsageStatistics> queryAppointmentUserGroupByHos(@Param("startTime") String startTime,
@Param("endTime") String endTime);
/**
* 统计新增用户
*
* @param startTime
* @param endTime
* @return
*/
Long countNewUser(@Param("startTime") String startTime,
@Param("endTime") String endTime);
/**
* 统计登录用户
*
* @param startTime
* @param endTime
* @return
*/
Long countLoginUser(@Param("startTime") String startTime,
@Param("endTime") String endTime,
@Param("appId") String appId);
/**
* 统计卫管中心预约人数
*
* @return
*/
Map<String, Long> countHealthManagementCenter();
/**
* 查询预约指标信息
*
* @param startTime 开始时间
* @param endTime 结束时间
* @return
*/
List<Map<String, Object>> countAll4Third(@Param("startTime") String startTime,
@Param("endTime") String endTime);
}
package cn.sh.stc.sict.theme.hphy.dao;
import java.util.List;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import cn.sh.stc.sict.theme.hphy.model.HpThirdInterfaceStatus;
/**
* (HpThirdInterfaceStatus)表数据库访问层
*
* @author gao
* @since 2023-07-19 14:17:01
*/
public interface HpThirdInterfaceStatusMapper extends BaseMapper<HpThirdInterfaceStatus> {
/**
* 批量新增数据(MyBatis原生foreach方法)
*
* @param entities List<HpThirdInterfaceStatus> 实例对象列表
* @return 影响行数
*/
int insertBatch(@Param("entities") List<HpThirdInterfaceStatus> entities);
/**
* 批量新增或按主键更新数据(MyBatis原生foreach方法)
*
* @param entities List<HpThirdInterfaceStatus> 实例对象列表
* @return 影响行数
* @throws org.springframework.jdbc.BadSqlGrammarException 入参是空List的时候会抛SQL语句错误的异常,请自行校验入参
*/
int insertOrUpdateBatch(@Param("entities") List<HpThirdInterfaceStatus> entities);
void updateStatusByHosCode(@Param("hosOrgCode")String hosOrgCode,
@Param("status")Integer status);
}
package cn.sh.stc.sict.theme.hphy.dao;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientRelation;
import cn.sh.stc.sict.theme.hphy.vo.PatientRelationVO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 患者-家庭成员关系表(HphyPatientRelation)表数据库访问层
*
* @author F_xh
* @since 2022-10-10 14:41:03
*/
public interface HphyPatientRelationMapper extends BaseMapper<HphyPatientRelation> {
List<PatientRelationVO> listPatientRelation(@Param("patientId") Long patientId);
}
\ No newline at end of file
......@@ -140,6 +140,7 @@ public class HpAppointment extends Model<HpAppointment> {
private String orderNumType;
private String doctorId;
private String doctorName;
private String orderId;
private String visitNo;
private String numSourceDetailId;
......@@ -147,9 +148,8 @@ public class HpAppointment extends Model<HpAppointment> {
private String room;
private String hosNumSourceId;
/**
*
*/
private Byte evaStatus;
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(hidden = true, value = "")
private Date createTime;
......
......@@ -43,6 +43,10 @@ public class HpDeptInfo extends Model<HpDeptInfo> {
@ApiModelProperty(hidden = false, value = "显示次序")
private String indexNo;
private String resourceOutPatInfo;
private String resourceDoctInfo;
/**
* 获取主键值
......
......@@ -55,6 +55,8 @@ public class HpDocInfo extends Model<HpDocInfo> {
@ApiModelProperty(hidden = false, value = "是否有资源(0有,1无)")
private String isResource;
private Byte hasResource;
/**
* 获取主键值
......
package cn.sh.stc.sict.theme.hphy.model;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
/**
* 黄浦-患者-卡号(HpPatientCard)表实体类
*
* @author F_xh
* @since 2022-07-14 11:00:02
*/
@Data
@SuppressWarnings("serial")
@EqualsAndHashCode(callSuper = true)
public class HpPatientCard extends Model<HpPatientCard> {
private String id;
private Long patientId;
private Long userId;
private String cardNo;
private String cardType;
private String hospitalId;
/**
* 获取主键值
*
* @return 主键值
*/
@Override
protected Serializable pkVal() {
return this.id;
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hphy.model;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* (HpThirdInterfaceStatus)表实体类
*
* @author gao
* @since 2023-07-19 14:17:02
*/
@SuppressWarnings("serial")
@Data
public class HpThirdInterfaceStatus extends Model<HpThirdInterfaceStatus> {
private Integer id;
//机构名称
private String hosOrgCode;
//机构代码
private String hosOrgName;
//对接状态(1-未对接;2-对接中;3-已对接)
private Integer interStatus;
private String interDes;
private Date createTime;
private Date updateTime;
/**
* 获取主键值
*
* @return 主键值
*/
@Override
protected Serializable pkVal() {
return this.id;
}
}
......@@ -28,57 +28,57 @@ public class HphyGuideMatch extends Model<HphyGuideMatch> {
* id
*/
@TableId
@ApiModelProperty(hidden = false, value = "id")
@ApiModelProperty(value = "id")
private Long id;
/**
* 患者id
*/
@ApiModelProperty(hidden = false, value = "患者id")
@ApiModelProperty(value = "患者id")
private Long patientId;
/**
* 患者name
*/
@ApiModelProperty(hidden = false, value = "患者name")
@ApiModelProperty(value = "患者name")
private String patientName;
/**
* 导医id
*/
@ApiModelProperty(hidden = false, value = "导医id")
@ApiModelProperty(value = "导医id")
private Long guideId;
/**
* 医院id
*/
@ApiModelProperty(hidden = false, value = "医院id")
@ApiModelProperty(value = "医院id")
private String hospId;
/**
* 医院name
*/
@ApiModelProperty(hidden = false, value = "医院name")
@ApiModelProperty(value = "医院name")
private String hospName;
/**
* 科室id
*/
@ApiModelProperty(hidden = false, value = "科室id")
@ApiModelProperty(value = "科室id")
private String deptId;
/**
* 科室name
*/
@ApiModelProperty(hidden = false, value = "科室name")
@ApiModelProperty(value = "科室name")
private String deptName;
/**
* 医生id
*/
@ApiModelProperty(hidden = false, value = "医生id")
@ApiModelProperty(value = "医生id")
private String doctorId;
/**
* 医生name
*/
@ApiModelProperty(hidden = false, value = "医生name")
@ApiModelProperty(value = "医生name")
private String doctorName;
/**
* 匹配度(%)
*/
@ApiModelProperty(hidden = false, value = "匹配度(%)")
@ApiModelProperty(value = "匹配度(%)")
private String matchScore;
/**
* 创建时间
......
......@@ -31,6 +31,8 @@ public class HphyPatientBase extends Model<HphyPatientBase> {
@ApiModelProperty(value = "id")
private Long id;
private Long userId;
@ApiModelProperty(value = "微信openid")
private String openId;
/**
......@@ -130,6 +132,9 @@ public class HphyPatientBase extends Model<HphyPatientBase> {
private String familyDocHos;
@ApiModelProperty("实名状态:0.未实名 1.已实名")
private String verifyStatus;
@TableField(exist = false)
private String randomCode;
......
package cn.sh.stc.sict.theme.hphy.model;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
/**
* 患者-家庭成员关系表(HphyPatientRelation)表实体类
*
* @author F_xh
* @since 2022-10-10 14:41:03
*/
@Data
@SuppressWarnings("serial")
@EqualsAndHashCode(callSuper = true)
public class HphyPatientRelation extends Model<HphyPatientRelation> {
private Long id;
private Long sourcePatientId;
private Long targetPatientId;
private String relationCode;
private String relationName;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT)
private String createUserName;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
@TableField(fill = FieldFill.INSERT)
private String updateUserName;
/**
* 获取主键值
*
* @return 主键值
*/
@Override
protected Serializable pkVal() {
return this.id;
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hphy.schedule;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.theme.hpgp.service.HpgpBusyIdlePredictionService;
import cn.sh.stc.sict.theme.hpgp.service.HpgpDepartmentRankService;
import cn.sh.stc.sict.theme.hphy.constant.DataConstant;
import cn.sh.stc.sict.theme.hphy.model.HpDeptInfo;
import cn.sh.stc.sict.theme.hphy.model.HpDocInfo;
import cn.sh.stc.sict.theme.hphy.model.HpHosInfo;
......@@ -12,6 +18,7 @@ import cn.sh.stc.sict.theme.hphy.wd.DoctInfo;
import cn.sh.stc.sict.theme.hphy.wd.HosInfo;
import cn.sh.stc.sict.theme.hphy.wd.WanDaHttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFactory;
......@@ -20,6 +27,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
......@@ -37,9 +45,8 @@ public class RefreshJob {
private final HpHosInfoService hpHosInfoService;
private final HpDeptInfoService deptInfoService;
private final HpDocInfoService docInfoService;
private static final byte TOP_DEPT = 1;
private static final byte TWO_DEPT = 2;
private final HpgpDepartmentRankService hpgpDepartmentRankService;
private final HpgpBusyIdlePredictionService hpgpBusyIdlePredictionService;
/**
* 每月一日0点 更新医院信息
......@@ -83,7 +90,7 @@ public class RefreshJob {
/**
* 每周一 2点 更新医生信息
*
* <p>
* 1、调用接口获取医生列表
* 2、删除现有医生信息
* 3、插入新的医生信息
......@@ -102,6 +109,25 @@ public class RefreshJob {
}
}
/**
* 每天中午12点,晚上12点,统计号源信息
*/
// @Scheduled(cron = "0 50 12 * * ? ")
@Scheduled(cron = "0 0 12,0 * * ? ")
public void statisticRankDeptResourceInfo() {
LambdaQueryWrapper<HpDeptInfo> wrapper = Wrappers.<HpDeptInfo>lambdaQuery();
wrapper.eq(HpDeptInfo::getDeptLevel, 2);
List<HpDeptInfo> deptList = deptInfoService.list(wrapper);
deptList.forEach(dept -> {
if (StrUtil.isEmpty(dept.getOneDeptCode()) || StrUtil.isEmpty(dept.getDeptCode())) {
return;
}
Date startDate = DateUtil.date();
Date endDate = DateUtil.offsetDay(startDate, 10);
hpgpBusyIdlePredictionService.statisticResourceInfo(dept, startDate, endDate, Constant.BYTE_NO);
});
}
private void saveDoctor(String hosOrgCode, MapperFactory factory) {
List<DoctInfo> doctInfos = WanDaHttpUtil.getDoctInfo(new DeptInfo(hosOrgCode));
......@@ -113,7 +139,7 @@ public class RefreshJob {
List<HpDocInfo> docInfos = factory.getMapperFacade().mapAsList(doctInfos, HpDocInfo.class);
try {
docInfoService.saveDoctor(docInfos, hosOrgCode);
}catch (Exception e){
} catch (Exception e) {
log.error("医院 {} 医生信息保存出错", hosOrgCode);
log.error(e.getMessage(), e);
}
......@@ -150,7 +176,7 @@ public class RefreshJob {
new LambdaQueryWrapper<HpDeptInfo>()
.eq(HpDeptInfo::getHosOrgCode, hpDeptInfo.getHosOrgCode())
.eq(HpDeptInfo::getOneDeptCode, hpDeptInfo.getOneDeptCode())
.eq(HpDeptInfo::getDeptLevel, TOP_DEPT)
.eq(HpDeptInfo::getDeptLevel, DataConstant.TOP_DEPT)
);
if (deptInfo != null) {
hpDeptInfo.setId(deptInfo.getId());
......@@ -172,7 +198,7 @@ public class RefreshJob {
List<HpDeptInfo> hpDeptInfos = factory.getMapperFacade().mapAsList(deptInfos, HpDeptInfo.class);
for (HpDeptInfo hpDeptInfo : hpDeptInfos) {
hpDeptInfo.setDeptLevel(TWO_DEPT);
hpDeptInfo.setDeptLevel(DataConstant.TWO_DEPT);
saveOrUpdateTwoDept(hpDeptInfo);
}
}
......@@ -183,7 +209,7 @@ public class RefreshJob {
new LambdaQueryWrapper<HpDeptInfo>()
.eq(HpDeptInfo::getHosOrgCode, hpDeptInfo.getHosOrgCode())
.eq(HpDeptInfo::getDeptCode, hpDeptInfo.getDeptCode())
.eq(HpDeptInfo::getDeptLevel, TWO_DEPT)
.eq(HpDeptInfo::getDeptLevel, DataConstant.TWO_DEPT)
);
if (deptInfo != null) {
hpDeptInfo.setId(deptInfo.getId());
......@@ -208,7 +234,7 @@ public class RefreshJob {
hpDeptInfo.setNormdeptCode(deptInfo.getNormdeptCode());
hpDeptInfo.setNormdeptName(deptInfo.getNormdeptName());
hpDeptInfo.setDeptDesc(deptInfo.getDeptDesc());
hpDeptInfo.setDeptLevel(TOP_DEPT);
hpDeptInfo.setDeptLevel(DataConstant.TOP_DEPT);
hpDeptInfo.setIndexNo(deptInfo.getIndexNo());
hpDeptInfos.add(hpDeptInfo);
......
package cn.sh.stc.sict.theme.hphy.service;
import cn.sh.stc.sict.theme.hphy.model.HpDeptInfo;
import cn.sh.stc.sict.theme.hphy.vo.DeptDoctorsVO;
import com.baomidou.mybatisplus.extension.service.IService;
/**
......@@ -11,6 +12,17 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface HpDeptInfoService extends IService<HpDeptInfo> {
/**
* 根据医院代码和科室代码查询医生信息
* @param hospitalCode
* @param deptCode
* @return
*/
DeptDoctorsVO getDeptDoctors(String hospitalCode, String deptCode);
void asyncUpdate(HpDeptInfo dept);
}
\ No newline at end of file
}
......@@ -4,6 +4,8 @@ import cn.sh.stc.sict.theme.hphy.model.HpDocInfo;
import cn.sh.stc.sict.theme.hphy.model.HphyGuideRecord;
import cn.sh.stc.sict.theme.hphy.vo.DoctorMatchVO;
import cn.sh.stc.sict.theme.hphy.vo.PythonResult;
import cn.sh.stc.sict.theme.hphy.wd.DeptInfo;
import cn.sh.stc.sict.theme.hphy.wd.NumSourceInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
......@@ -26,4 +28,8 @@ public interface HpDocInfoService extends IService<HpDocInfo> {
List<DoctorMatchVO> getRecommendList(HphyGuideRecord guide, List<PythonResult> pythonList);
void saveDoctor(List<HpDocInfo> docInfos, String hosOrgCode);
List<HpDocInfo> listByDeptInfo(DeptInfo deptInfo);
void updateResource(NumSourceInfo numSourceInfo, Byte hasResource);
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hphy.service;
import cn.sh.stc.sict.cloud.common.core.dto.WDUserCardInfo;
import cn.sh.stc.sict.theme.hphy.model.HpPatientCard;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import cn.sh.stc.sict.theme.hphy.wd.OrderInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* 黄浦-患者-卡号(HpPatientCard)表服务接口
*
* @author F_xh
* @since 2022-07-14 11:00:02
*/
public interface HpPatientCardService extends IService<HpPatientCard> {
void save(HphyPatientBase base, List<WDUserCardInfo> cardList);
List<HpPatientCard> listByUserId(Long userId);
void updateByApp(HphyPatientBase patient, OrderInfo order);
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hphy.service;
import cn.sh.stc.sict.theme.hphy.vo.StatisticsUsageVO;
import java.util.List;
import java.util.Map;
/**
* @author gao
* @date 2023/01/06 11:03
*/
public interface HpStatisticsService {
/**
* 获取使用情况概览统计信息
*
* @param startTime 开始时间
* @param endTime 结束时间
* @return
*/
StatisticsUsageVO getUsageOverviewStatistics(String startTime,
String endTime);
/**
* 统计时间内的指标信息
*
* @param startTime 开始时间
* @param endTime 结束时间
* @return
*/
List<Map<String,Object>> countAll4Third(String startTime,
String endTime);
}
package cn.sh.stc.sict.theme.hphy.service;
import com.baomidou.mybatisplus.extension.service.IService;
import cn.sh.stc.sict.theme.hphy.model.HpThirdInterfaceStatus;
import org.springframework.web.bind.annotation.RequestParam;
/**
* (HpThirdInterfaceStatus)表服务接口
*
* @author gao
* @since 2023-07-19 14:17:06
*/
public interface HpThirdInterfaceStatusService extends IService<HpThirdInterfaceStatus> {
void updateHosOrgStatus(String hosOrgCode,
Integer status);
}
package cn.sh.stc.sict.theme.hphy.service;
import com.baomidou.mybatisplus.extension.service.IService;
import cn.sh.stc.sict.cloud.common.core.dto.*;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* 患者基本信息
......@@ -11,5 +15,40 @@ import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
*/
public interface HphyPatientBaseService extends IService<HphyPatientBase> {
HphyPatientBase getByOpenId(String openId);
HphyPatientBase getByPhone(String phone, Boolean flag);
HphyPatientBase saveSSbInfo(CurrentUser current, WDUserInfo userInfo, List<WDUserCardInfo> cardList);
/**
* 保存香山中医医院公众号用户
*
* @param current 当前用户
* @param userInfo 公众号用户详情
* @return XSZYUserInfo {@link XSZYUserInfo}
*/
HphyPatientBase saveWoaXszyInfo(CurrentUser current, XSZYUserInfo userInfo);
/**
* 保存中智公众号用户信息
*
* @param current 当前用户
* @param userInfo 公众号用户详情
* @return XSZYUserInfo {@link WOAZzUserInfo}
*/
HphyPatientBase saveWoaZzInfo(CurrentUser current, WOAZzUserInfo userInfo);
/**
* 保存万达公众号用户信息
*
* @param current 当前用户
* @param userInfo 公众号用户详情
* @return XSZYUserInfo {@link WOAWDUserInfo}
*/
HphyPatientBase saveWoaWdInfo(CurrentUser current, WOAWDUserInfo userInfo);
void savePatient(HphyPatientBase patient);
HphyPatientBase getCurrentBase();
}
package cn.sh.stc.sict.theme.hphy.service;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientRelation;
import cn.sh.stc.sict.theme.hphy.vo.PatientRelationVO;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* 患者-家庭成员关系表(HphyPatientRelation)表服务接口
*
* @author F_xh
* @since 2022-10-10 14:41:04
*/
public interface HphyPatientRelationService extends IService<HphyPatientRelation> {
List<PatientRelationVO> listPatientRelation(Long patientId);
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hphy.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.theme.hphy.constant.DataConstant;
import cn.sh.stc.sict.theme.hphy.dao.HpDeptInfoMapper;
import cn.sh.stc.sict.theme.hphy.model.HpDeptInfo;
import cn.sh.stc.sict.theme.hphy.model.HpDocInfo;
import cn.sh.stc.sict.theme.hphy.model.HpHosInfo;
import cn.sh.stc.sict.theme.hphy.service.HpDeptInfoService;
import cn.sh.stc.sict.theme.hphy.service.HpDocInfoService;
import cn.sh.stc.sict.theme.hphy.service.HpHosInfoService;
import cn.sh.stc.sict.theme.hphy.vo.DeptDoctorsVO;
import cn.sh.stc.sict.theme.hphy.wd.DeptInfo;
import cn.sh.stc.sict.theme.hphy.wd.DoctInfo;
import cn.sh.stc.sict.theme.hphy.wd.OutPatInfo;
import cn.sh.stc.sict.theme.hphy.wd.WanDaHttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* (HpDeptInfo)表服务实现类
*
* @author makejava
* @since 2021-01-28 10:35:58
*/
@Slf4j
@AllArgsConstructor
@Service("hpDeptInfoService")
public class HpDeptInfoServiceImpl extends ServiceImpl<HpDeptInfoMapper, HpDeptInfo> implements HpDeptInfoService {
private final HpDocInfoService hpDocInfoService;
private final HpHosInfoService hpHosInfoService;
@Override
public DeptDoctorsVO getDeptDoctors(String hospitalCode, String deptCode) {
HpHosInfo hosInfo = hpHosInfoService.getById(hospitalCode);
// 查询科室信息
// 查询医生信息
HpDeptInfo deptInfo = this.getOne(
new LambdaQueryWrapper<HpDeptInfo>()
.eq(HpDeptInfo::getHosOrgCode, hospitalCode)
.and(i -> i.eq(HpDeptInfo::getOneDeptCode, deptCode)
.or().eq(HpDeptInfo::getDeptCode, deptCode))
.orderByDesc(HpDeptInfo::getDeptLevel)
.last("limit 1")
);
if (deptInfo == null) {
log.error("根据医院编码:{} 和科室编码:{} 未查出科室信息", hospitalCode, deptCode);
return null;
}
LambdaQueryWrapper<HpDocInfo> docWrapper = new LambdaQueryWrapper<>();
docWrapper.eq(HpDocInfo::getHosOrgCode, hospitalCode)
.eq(HpDocInfo::getOneDeptCode, deptInfo.getOneDeptCode())
.eq(HpDocInfo::getHasResource, Constant.BYTE_YES);
if (DataConstant.TWO_DEPT.equals(deptInfo.getDeptLevel())) {
docWrapper.eq(HpDocInfo::getDeptCode, deptInfo.getDeptCode());
}
docWrapper.orderByAsc(HpDocInfo::getIndexNo);
List<HpDocInfo> doctors = hpDocInfoService.list(docWrapper);
DeptInfo info = new DeptInfo();
info.setHosOrgCode(deptInfo.getHosOrgCode());
info.setOneDeptCode(deptInfo.getOneDeptCode());
info.setDeptCode(deptInfo.getDeptCode());
List<OutPatInfo> resourceOutPatInfo = WanDaHttpUtil.getOutPatInfo(info);
List<DoctInfo> resourceDoctInfo = WanDaHttpUtil.getDoctInfo(info);
List<HpDocInfo> remainDoctors = this.getRemainDoctList(doctors, resourceDoctInfo);
return new DeptDoctorsVO(hosInfo, deptInfo, resourceOutPatInfo, remainDoctors);
}
@Async
@Override
public void asyncUpdate(HpDeptInfo dept) {
DeptInfo deptInfo = new DeptInfo();
deptInfo.setHosOrgCode(dept.getHosOrgCode());
deptInfo.setOneDeptCode(dept.getOneDeptCode());
deptInfo.setDeptCode(dept.getDeptCode());
List<OutPatInfo> resourceOutPatInfo = WanDaHttpUtil.getOutPatInfo(deptInfo);
List<DoctInfo> resourceDoctInfo = WanDaHttpUtil.getDoctInfo(deptInfo);
if (CollUtil.isEmpty(resourceDoctInfo) && CollUtil.isEmpty(resourceOutPatInfo)) {
return;
}
HpDeptInfo update = new HpDeptInfo();
update.setId(dept.getId());
update.setResourceDoctInfo(JSONUtil.toJsonStr(resourceDoctInfo));
update.setResourceOutPatInfo(JSONUtil.toJsonStr(resourceOutPatInfo));
this.updateById(update);
}
private List<HpDocInfo> getRemainDoctList(List<HpDocInfo> doctors, List<DoctInfo> resourceDoctInfo) {
Map<String, HpDocInfo> doctorMap = doctors.stream().collect(Collectors.groupingBy(HpDocInfo::getResourceCode, Collectors.collectingAndThen(Collectors.toList(), x -> x.get(0))));
List<HpDocInfo> remainDoctors = new ArrayList<>();
remainDoctors.addAll(doctors);
resourceDoctInfo.forEach(res -> {
if (!doctorMap.containsKey(res.getResourceCode())) {
HpDocInfo doctor = BeanUtil.toBean(res, HpDocInfo.class);
hpDocInfoService.save(doctor);
remainDoctors.add(doctor);
}
});
return remainDoctors;
}
// public static void main(String[] args) {
//
// DeptInfo info = new DeptInfo();
// info.setHosOrgCode("Y0180100700");
// info.setOneDeptCode("293");
// info.setDeptCode("3");
// List<OutPatInfo> resourceOutPatInfo = WanDaHttpUtil.getResourceOutPatInfo(info);
// List<DoctInfo> resourceDoctInfo = WanDaHttpUtil.getResourceDoctInfo(info);
// log.error("OutPatInfo = {}", JSONUtil.toJsonStr(resourceOutPatInfo));
// log.error("=========================");
// log.error("DoctInfo = {}", JSONUtil.toJsonStr(resourceDoctInfo));
//
// DoctInfo doctInfo = resourceDoctInfo.get(0);
// NumSourceInfo numSourceInfo = new NumSourceInfo();
// numSourceInfo.setHosOrgCode(doctInfo.getHosOrgCode());
// numSourceInfo.setOneDeptCode(doctInfo.getOneDeptCode());
// numSourceInfo.setDeptCode(doctInfo.getDeptCode());
// numSourceInfo.setOrderType(WanDaConstant.ORDER_TYPE_OUTP);
// numSourceInfo.setResourceCode(doctInfo.getResourceCode());
// numSourceInfo.setPatient_type(WanDaConstant.PATIENT_TYPE_NORMAL);
// numSourceInfo.setStartTime("2022-07-25");
// numSourceInfo.setEndTime("2022-08-08");
//
// List<NumSourceInfo> orderNumInfo = WanDaHttpUtil.getOrderNumInfo(numSourceInfo);
// log.error("=========================");
// log.error("numInfo = {}", JSONUtil.toJsonStr(orderNumInfo));
// }
// public static void main(String[] args) {
// NumSourceInfo numSourceInfo = new NumSourceInfo();
// numSourceInfo.setHosOrgCode("E7880343800");
// numSourceInfo.setOneDeptCode("50");
// numSourceInfo.setDeptCode("2006");
// numSourceInfo.setOrderType(WanDaConstant.ORDER_TYPE_OUTP);
// numSourceInfo.setResourceCode("0085");
// numSourceInfo.setPatient_type(WanDaConstant.PATIENT_TYPE_NORMAL);
// Date startDate = DateUtil.date();
// Date endDate = DateUtil.offsetDay(startDate, 10);
// numSourceInfo.setStartTime(DateUtil.format(startDate, DatePattern.NORM_DATE_FORMAT));
// numSourceInfo.setEndTime(DateUtil.format(endDate, DatePattern.NORM_DATE_FORMAT));
//
// List<NumSourceInfo> list = WanDaHttpUtil.getOrderNumInfo(numSourceInfo);
//
// log.error("list = {}", JSONUtil.toJsonStr(list));
// NumSourceInfo numSourceInfo = new NumSourceInfo();
// numSourceInfo.setHosOrgCode(orgCode);
// numSourceInfo.setOneDeptCode(oneDeptCode);
// numSourceInfo.setDeptCode(deptCode);
// numSourceInfo.setOrderType(WanDaConstant.ORDER_TYPE_DOCT);
// numSourceInfo.setResourceCode(docResourceCode);
// numSourceInfo.setPatient_type(WanDaConstant.PATIENT_TYPE_NORMAL);
// numSourceInfo.setStartTime("2022-08-20");
// numSourceInfo.setEndTime("2022-09-03");
// List<NumSourceInfo> result = WanDaHttpUtil.getOrderNumInfo(numSourceInfo);
// log.error("numSourceInfo = {}", JSONUtil.toJsonStr(result));
// NumSourceInfo numSourceInfo = new NumSourceInfo();
// numSourceInfo.setHosOrgCode(orgCode);
// numSourceInfo.setOneDeptCode(oneDeptCode);
// numSourceInfo.setDeptCode(deptCode);
// numSourceInfo.setOrderType(WanDaConstant.ORDER_TYPE_CLINC);
// numSourceInfo.setResourceCode(deptCode);
// numSourceInfo.setPatient_type(WanDaConstant.PATIENT_TYPE_NORMAL);
// numSourceInfo.setStartTime("2022-08-20");
// numSourceInfo.setEndTime("2022-09-03");
// List<NumSourceInfo> result = WanDaHttpUtil.getOrderNumInfo(numSourceInfo);
// log.error("numSourceInfo = {}", JSONUtil.toJsonStr(result));
// }
/**
* Y0180100700 293 3 上海交通大学医学院附属第九人民医院黄浦分院 内科 消化内科 03.02 消化内科
* Y0180100700 293 6 上海交通大学医学院附属第九人民医院黄浦分院 内科 心血管内科 03.04 心血管内科
* @param args
*/
// public static void main(String[] args) {
// String orgCode = "Y0180100700";
// String oneDeptCode = "293";
// String deptCode = "2";
// String docResourceCode = "175"; // 陈芳
//
// NumSourceInfo numSourceInfo = new NumSourceInfo();
// numSourceInfo.setHosOrgCode(orgCode);
// numSourceInfo.setOneDeptCode(oneDeptCode);
// numSourceInfo.setDeptCode(deptCode);
// numSourceInfo.setOrderType(WanDaConstant.ORDER_TYPE_DOCT);
// numSourceInfo.setResourceCode(docResourceCode);
// numSourceInfo.setPatient_type(WanDaConstant.PATIENT_TYPE_NORMAL);
// numSourceInfo.setStartTime("2022-08-20");
// numSourceInfo.setEndTime("2022-09-03");
// List<NumSourceInfo> result = WanDaHttpUtil.getOrderNumInfo(numSourceInfo);
// log.error("numSourceInfo = {}", JSONUtil.toJsonStr(result));
}
\ No newline at end of file
// HosInfo hosInfo = new HosInfo();
// hosInfo.setHosOrgCode(orgCode);
// List<DeptInfo> oneDeptInfo = WanDaHttpUtil.getDeptInfoTop(hosInfo);
// log.error("oneDeptInfo = {}", JSONUtil.toJsonStr(oneDeptInfo));
// DeptInfo deptInfo = new DeptInfo();
// deptInfo.setHosOrgCode(orgCode);
// deptInfo.setOneDeptCode(oneDeptCode);
// List<DeptInfo> deptInfoTwo = WanDaHttpUtil.getDeptInfoTwo(deptInfo);
// log.error("deptInfoTwo = {}", JSONUtil.toJsonStr(deptInfoTwo));
// deptInfo.setDeptCode(deptCode);
// List<OutPatInfo> resourceOutPatInfo = WanDaHttpUtil.getResourceOutPatInfo(deptInfo);
// log.error("resourceOutPatInfo = {}", JSONUtil.toJsonStr(resourceOutPatInfo));
// List<DoctInfo> resourceDoctInfo = WanDaHttpUtil.getResourceDoctInfo(deptInfo);
// log.error("resourceDoctInfo = {}", JSONUtil.toJsonStr(resourceDoctInfo));
// }
}
package cn.sh.stc.sict.theme.hphy.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.theme.hphy.dao.HpDocInfoMapper;
import cn.sh.stc.sict.theme.hphy.model.HpDocInfo;
import cn.sh.stc.sict.theme.hphy.model.HphyGuideMatch;
......@@ -9,7 +10,11 @@ import cn.sh.stc.sict.theme.hphy.service.HpDocInfoService;
import cn.sh.stc.sict.theme.hphy.service.HphyGuideMatchService;
import cn.sh.stc.sict.theme.hphy.vo.DoctorMatchVO;
import cn.sh.stc.sict.theme.hphy.vo.PythonResult;
import cn.sh.stc.sict.theme.hphy.wd.DeptInfo;
import cn.sh.stc.sict.theme.hphy.wd.HosInfo;
import cn.sh.stc.sict.theme.hphy.wd.NumSourceInfo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
......@@ -41,7 +46,7 @@ public class HpDocInfoServiceImpl extends ServiceImpl<HpDocInfoMapper, HpDocInfo
@Override
public List<DoctorMatchVO> getRecommendList(HphyGuideRecord guide, List<PythonResult> pythonList) {
List<DoctorMatchVO> result = new ArrayList<>();
if(CollUtil.isNotEmpty(pythonList)){
if (CollUtil.isNotEmpty(pythonList)) {
Map<String, Double> matchMap = pythonList.stream().collect(Collectors.toMap(PythonResult::getDoctorId, PythonResult::getMatchScore));
List<String> doctorIdList = pythonList.stream().map(PythonResult::getDoctorId).collect(Collectors.toList());
LambdaQueryWrapper<HpDocInfo> wrapper = new LambdaQueryWrapper<>();
......@@ -82,4 +87,25 @@ public class HpDocInfoServiceImpl extends ServiceImpl<HpDocInfoMapper, HpDocInfo
this.remove(new LambdaQueryWrapper<HpDocInfo>().eq(HpDocInfo::getHosOrgCode, hosOrgCode));
this.saveBatch(docInfos);
}
@Override
public List<HpDocInfo> listByDeptInfo(DeptInfo deptInfo) {
LambdaQueryWrapper<HpDocInfo> wrapper = Wrappers.lambdaQuery();
wrapper.eq(HpDocInfo::getHosOrgCode, deptInfo.getHosOrgCode())
.eq(HpDocInfo::getOneDeptCode, deptInfo.getOneDeptCode())
.eq(StrUtil.isNotEmpty(deptInfo.getDeptCode()), HpDocInfo::getDeptCode, deptInfo.getDeptCode());
return this.list(wrapper);
}
@Override
public void updateResource(NumSourceInfo num, Byte hasResource) {
LambdaQueryWrapper<HpDocInfo> wrapper = Wrappers.lambdaQuery();
wrapper.eq(HpDocInfo::getHosOrgCode, num.getHosOrgCode())
.eq(HpDocInfo::getOneDeptCode, num.getOneDeptCode())
.eq(StrUtil.isNotEmpty(num.getDeptCode()), HpDocInfo::getDeptCode, num.getDeptCode())
.eq(HpDocInfo::getResourceCode, num.getResourceCode());
HpDocInfo update = new HpDocInfo();
update.setHasResource(hasResource);
this.update(update, wrapper);
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hphy.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.dto.WDUserCardInfo;
import cn.sh.stc.sict.theme.hphy.dao.HpPatientCardMapper;
import cn.sh.stc.sict.theme.hphy.model.HpPatientCard;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import cn.sh.stc.sict.theme.hphy.service.HpPatientCardService;
import cn.sh.stc.sict.theme.hphy.wd.OrderInfo;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 黄浦-患者-卡号(HpPatientCard)表服务实现类
*
* @author F_xh
* @since 2022-07-14 11:00:02
*/
@Service("hpPatientCardService")
public class HpPatientCardServiceImpl extends ServiceImpl<HpPatientCardMapper, HpPatientCard> implements HpPatientCardService {
@Override
public void save(HphyPatientBase base, List<WDUserCardInfo> cardList) {
if (CollUtil.isNotEmpty(cardList)) {
cardList.forEach(wdCard -> {
HpPatientCard card = BeanUtil.toBean(wdCard, HpPatientCard.class);
card.setUserId(base.getUserId());
card.setPatientId(base.getId());
this.save(card);
});
}
}
@Override
public List<HpPatientCard> listByUserId(Long userId) {
LambdaQueryWrapper<HpPatientCard> wrapper = Wrappers.lambdaQuery();
wrapper.eq(HpPatientCard::getUserId, userId);
return this.list(wrapper);
}
@Override
public void updateByApp(HphyPatientBase patient, OrderInfo order) {
if (StrUtil.isNotBlank(order.getMediCardId()) && StrUtil.isNotBlank(order.getMediCardType())) {
HpPatientCard card = new HpPatientCard();
card.setCardNo(order.getMediCardId());
card.setCardType(order.getMediCardType());
card.setUserId(patient.getUserId());
card.setPatientId(patient.getId());
LambdaQueryWrapper<HpPatientCard> wrapper = Wrappers.lambdaQuery();
wrapper.eq(HpPatientCard::getUserId, patient.getUserId())
.eq(HpPatientCard::getPatientId, patient.getId())
.eq(HpPatientCard::getCardType, order.getMediCardType());
this.saveOrUpdate(card, wrapper);
}
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hphy.service.impl;
import cn.sh.stc.sict.theme.hphy.dao.HpAppointmentMapper;
import cn.sh.stc.sict.theme.hphy.dao.HpStatisticsMapper;
import cn.sh.stc.sict.theme.hphy.service.HpStatisticsService;
import cn.sh.stc.sict.theme.hphy.vo.StatisticsUsageVO;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* 黄埔医导用户使用情况查询
*
* @author gao
* @date 2023/01/06 11:04
*/
@Service("hpStatisticsService")
@AllArgsConstructor
public class HpStatisticsServiceImpl implements HpStatisticsService {
@Autowired
private final HpStatisticsMapper hpStatisticsMapper;
@Autowired
private final HpAppointmentMapper hpAppointmentMapper;
/**
* 获取使用情况概览统计信息
*
* @param startTime 开始时间
* @param endTime 结束时间
* @return
*/
@Override
public StatisticsUsageVO getUsageOverviewStatistics(String startTime, String endTime) {
Long loginUserCount = hpStatisticsMapper.countLoginUser(startTime, endTime, null);
Long newUserCount = hpStatisticsMapper.countNewUser(startTime, endTime);
List<StatisticsUsageVO.HosUsageStatistics> hosUsageStatisticsList = hpStatisticsMapper.queryAppointmentUserGroupByHos(startTime, endTime);
// 统计卫管中心数据
Map<String, Long> hmcStatistics = hpStatisticsMapper.countHealthManagementCenter();
Long hmcloginUserCount = hpStatisticsMapper.countLoginUser(startTime, endTime, "wx24c55f38b535cd96");
hmcStatistics.put("卫管中心登录人数", hmcloginUserCount);
return StatisticsUsageVO.builder()
.newUserCount(newUserCount)
.loginUserCount(loginUserCount)
.hosAppointmentStatistics(hosUsageStatisticsList)
.healthManagementCenterStatistics(hmcStatistics)
.build();
}
/**
* 统计时间内的指标信息
*
* @param startTime 开始时间
* @param endTime 结束时间
* @return
*/
@Override
public List<Map<String, Object>> countAll4Third(String startTime, String endTime) {
return hpStatisticsMapper.countAll4Third(startTime, endTime);
}
}
package cn.sh.stc.sict.theme.hphy.service.impl;
import cn.sh.stc.sict.theme.hphy.dao.HpThirdInterfaceStatusMapper;
import cn.sh.stc.sict.theme.hphy.model.HpThirdInterfaceStatus;
import cn.sh.stc.sict.theme.hphy.service.HpThirdInterfaceStatusService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* (HpThirdInterfaceStatus)表服务实现类
*
* @author gao
* @since 2023-07-19 14:17:09
*/
@Service("hpThirdInterfaceStatusService")
public class HpThirdInterfaceStatusServiceImpl extends ServiceImpl<HpThirdInterfaceStatusMapper, HpThirdInterfaceStatus> implements HpThirdInterfaceStatusService {
@Override
public void updateHosOrgStatus(String hosOrgCode, Integer status) {
this.baseMapper.updateStatusByHosCode(hosOrgCode, status);
}
}
package cn.sh.stc.sict.theme.hphy.service.impl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.dto.*;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.hphy.dao.HphyPatientBaseMapper;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import cn.sh.stc.sict.theme.hphy.service.HphyPatientBaseService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import cn.sh.stc.sict.theme.hphy.dao.HphyPatientBaseMapper;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import cn.sh.stc.sict.theme.hphy.service.HphyPatientBaseService;
import java.util.List;
@Service("hphyPatientBaseService")
......@@ -24,4 +32,170 @@ public class HphyPatientBaseServiceImpl extends ServiceImpl<HphyPatientBaseMappe
return this.getOne(wrapper);
}
@Override
public HphyPatientBase getByPhone(String phone, Boolean flag) {
LambdaQueryWrapper<HphyPatientBase> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HphyPatientBase::getPhone, phone)
.isNull(flag, HphyPatientBase::getOpenId)
.orderByDesc(HphyPatientBase::getUpdateTime)
.last("limit 1");
return this.getOne(wrapper);
}
@Override
public HphyPatientBase saveSSbInfo(CurrentUser current, WDUserInfo userInfo, List<WDUserCardInfo> cardList) {
if (ObjectUtil.isNotNull(userInfo)) {
HphyPatientBase base = new HphyPatientBase();
base.setUserId(current.getId());
base.setOpenId(current.getOpenId());
base.setPhone(userInfo.getMobile());
base.setName(userInfo.getName());
base.setCertId(userInfo.getPersoncard());
base.setAge(String.valueOf(IdcardUtil.getAgeByIdCard(userInfo.getPersoncard())));
base.setGender(Constant.BYTE_YES.equals(userInfo.getGender()) ? "男" : "女");
base.setVerifyStatus(userInfo.getVerifyStatus());
if (CollUtil.isNotEmpty(cardList)) {
WDUserCardInfo card = cardList.get(0);
base.setMediCardId(card.getCardNo());
base.setMediCardType(card.getCardType());
}
this.save(base);
return base;
}
return null;
}
/**
* 保存香山中医医院公众号用户
*
* @param current 当前用户
* @param userInfo 公众号用户详情
* @return XSZYUserInfo {@link XSZYUserInfo}
*/
@Override
public HphyPatientBase saveWoaXszyInfo(CurrentUser current, XSZYUserInfo userInfo) {
if (ObjectUtil.isNotNull(userInfo)) {
HphyPatientBase base = new HphyPatientBase();
base.setUserId(current.getId());
base.setOpenId(current.getOpenId());
base.setPhone(userInfo.getMobile());
base.setName(userInfo.getPatientName());
if (Constant.STRING_YES.equals(userInfo.getCertificateType())) {
base.setCertId(userInfo.getCertificate());
}
base.setVerifyStatus(Constant.STRING_NO);
// 身份证号合法,设置年龄、性别、实名认证标志
if (IdcardUtil.isValidCard(base.getCertId())) {
String certId = base.getCertId();
base.setAge(String.valueOf(IdcardUtil.getAgeByIdCard(certId)));
base.setGender(Constant.INT_YES.equals(IdcardUtil.getGenderByIdCard(certId)) ? "男" : "女");
base.setVerifyStatus(Constant.STRING_YES);
}
// 卡号卡类型
base.setMediCardType(userInfo.getMediCardType());
base.setMediCardId(userInfo.getMediCardType());
this.save(base);
return base;
}
return null;
}
/**
* 保存中智公众号用户信息
*
* @param current 当前用户
* @param userInfo 公众号用户详情
* @return XSZYUserInfo {@link WOAZzUserInfo}
*/
@Override
public HphyPatientBase saveWoaZzInfo(CurrentUser current, WOAZzUserInfo userInfo) {
if (ObjectUtil.isNotNull(userInfo)) {
HphyPatientBase base = new HphyPatientBase();
base.setUserId(current.getId());
base.setOpenId(current.getOpenId());
base.setPhone(userInfo.getMobile());
base.setName(userInfo.getUsername());
base.setCertId(userInfo.getPersoncard());
base.setGender(Constant.BYTE_YES.equals(userInfo.getGender()) ? "男" : "女");
base.setVerifyStatus(Constant.STRING_NO);
// 身份证号合法,设置年龄、性别、实名认证标志
if (IdcardUtil.isValidCard(base.getCertId())) {
String certId = base.getCertId();
base.setAge(String.valueOf(IdcardUtil.getAgeByIdCard(certId)));
base.setVerifyStatus(Constant.STRING_YES);
}
this.save(base);
return base;
}
return null;
}
/**
* 保存万达公众号用户信息
*
* @param current 当前用户
* @param userInfo 公众号用户详情
* @return XSZYUserInfo {@link WOAWDUserInfo}
*/
@Override
public HphyPatientBase saveWoaWdInfo(CurrentUser current, WOAWDUserInfo userInfo) {
if (ObjectUtil.isNotNull(userInfo)) {
HphyPatientBase base = new HphyPatientBase();
base.setUserId(current.getId());
base.setOpenId(current.getOpenId());
base.setPhone(userInfo.getMobile());
base.setName(userInfo.getUsername());
base.setCertId(userInfo.getPersoncard());
base.setGender(Constant.BYTE_YES.equals(userInfo.getGender()) ? "男" : "女");
base.setVerifyStatus(Constant.STRING_NO);
// 身份证号合法,设置年龄、性别、实名认证标志
if (IdcardUtil.isValidCard(base.getCertId())) {
String certId = base.getCertId();
base.setAge(String.valueOf(IdcardUtil.getAgeByIdCard(certId)));
base.setVerifyStatus(Constant.STRING_YES);
}
if (CollUtil.isNotEmpty(userInfo.getCards())) {
WOAWDUserInfo.Card card = userInfo.getCards().get(0);
base.setMediCardId(card.getCardNo());
base.setMediCardType(card.getCardType());
}
this.save(base);
return base;
}
return null;
}
@Override
public void savePatient(HphyPatientBase patient) {
HphyPatientBase base = this.getByCertId(patient.getCertId());
if (ObjectUtil.isNull(base) || NumberUtil.isNullOrZero(base.getId())) {
base = this.getByPhone(patient.getPhone(), false);
}
if (ObjectUtil.isNotNull(base) && NumberUtil.isNotNullOrZero(base.getId())) {
patient.setId(base.getId());
this.updateById(patient);
} else {
this.save(patient);
}
}
private HphyPatientBase getByCertId(String certId) {
LambdaQueryWrapper<HphyPatientBase> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(HphyPatientBase::getCertId, certId)
.orderByDesc(HphyPatientBase::getUpdateTime)
.last("limit 1");
return this.getOne(wrapper);
}
@Override
public HphyPatientBase getCurrentBase() {
CurrentUser current = SecurityUtils.getCurrentUser();
return this.getByOpenId(current.getOpenId());
}
}
package cn.sh.stc.sict.theme.hphy.service.impl;
import cn.sh.stc.sict.theme.hphy.dao.HphyPatientRelationMapper;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientRelation;
import cn.sh.stc.sict.theme.hphy.service.HphyPatientRelationService;
import cn.sh.stc.sict.theme.hphy.vo.PatientRelationVO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 患者-家庭成员关系表(HphyPatientRelation)表服务实现类
*
* @author F_xh
* @since 2022-10-10 14:41:04
*/
@AllArgsConstructor
@Service("hphyPatientRelationService")
public class HphyPatientRelationServiceImpl extends ServiceImpl<HphyPatientRelationMapper, HphyPatientRelation> implements HphyPatientRelationService {
private final HphyPatientRelationMapper hphyPatientRelationMapper;
@Override
public List<PatientRelationVO> listPatientRelation(Long patientId) {
return hphyPatientRelationMapper.listPatientRelation(patientId);
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hphy.util;
import cn.hutool.core.collection.CollUtil;
import cn.sh.stc.sict.theme.hpgp.model.HpgpBusyIdlePrediction;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* @author gao
* @date 2023/03/21 17:27
*/
@Slf4j
@UtilityClass
public class BusyIdlePredictionUtil {
/**
* 获取有号源的三个科室
* @param hpgpBusyIdlePredictionList
* @return
*/
public static List<HpgpBusyIdlePrediction> getHasRemainNum(List<HpgpBusyIdlePrediction> hpgpBusyIdlePredictionList) {
if (CollUtil.isEmpty(hpgpBusyIdlePredictionList)) {
return Collections.emptyList();
}
// 当前医院近七天有号的三个科室
List<String> deptCodeList = hpgpBusyIdlePredictionList.stream()
// 按科室分组,并统计每个科室可预约号源总量
.collect(Collectors.groupingBy(HpgpBusyIdlePrediction::getDeptCode,
Collectors.summingInt(item -> Optional.ofNullable(item.getRemainNum()).orElse(0))))
.entrySet().stream()
// 按可预约号源进行排序,取排名前三的科室
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
.map(Map.Entry::getKey)
.limit(3)
.collect(Collectors.toList());
return hpgpBusyIdlePredictionList.stream().filter(item -> deptCodeList.contains(item.getDeptCode())).collect(Collectors.toList());
}
}
package cn.sh.stc.sict.theme.hphy.vo;
import cn.sh.stc.sict.theme.hphy.model.HpDeptInfo;
import cn.sh.stc.sict.theme.hphy.model.HpDocInfo;
import cn.sh.stc.sict.theme.hphy.model.HpHosInfo;
import cn.sh.stc.sict.theme.hphy.wd.OutPatInfo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author zhangly
* @Description
* @Date 2022/1/14 14:43
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeptDoctorsVO {
private HpHosInfo hosInfo;
private HpDeptInfo deptInfo;
private List<OutPatInfo> resourceOutPatInfoList;
private List<HpDocInfo> doctors;
}
package cn.sh.stc.sict.theme.hphy.vo;
import lombok.Data;
/**
* 卫管中心统计结果数据
*
* @author gao
* @date 2023/07/19 10:27
*/
@Data
public class HealthManagementStatisticVO {
/**
* 机构编码
*/
private String hospitalCode;
/**
* 机构名称
*/
private String hospitalName;
/**
* 导诊数
*/
private String consultationCount;
/**
* 对接状态
* 1-未对接
* 2-对接中
* 3-已对接
*/
private Byte status;
}
package cn.sh.stc.sict.theme.hphy.vo;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientRelation;
import lombok.Data;
@Data
public class PatientRelationDTO {
private HphyPatientRelation relation;
private HphyPatientBase patient;
}
package cn.sh.stc.sict.theme.hphy.vo;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import lombok.Data;
@Data
public class PatientRelationVO extends HphyPatientBase {
private Long relationId;
private String relationCode;
private String relationName;
}
package cn.sh.stc.sict.theme.hphy.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* 统计用户使用详情
*
* @author gao
* @date 2023/01/06 10:58
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class StatisticsUsageVO implements Serializable {
private static final long serialVersionUID = -279866011612238581L;
@ApiModelProperty(value = "登录总人数")
private Long loginUserCount;
@ApiModelProperty(value = "新增用户总人数")
private Long newUserCount;
@ApiModelProperty(value = "医院预约人数")
private List<HosUsageStatistics> hosAppointmentStatistics;
@ApiModelProperty(value = "卫管中心入口数据统计")
private Map<String, Long> healthManagementCenterStatistics;
@Data
public static class HosUsageStatistics implements Serializable {
private static final long serialVersionUID = -1088663393589514198L;
@ApiModelProperty(value = "医院编码")
private String hospitalCode;
@ApiModelProperty(value = "医院名称")
private String hospitalName;
@ApiModelProperty(value = "医院预约人数")
private Long appointmentUserCount;
}
}
......@@ -31,6 +31,6 @@ public class NumSourceInfo {
private String visitCost;
private String scheduleDate;
private String timeRange;
private String remainNum;
private String reserveOrderNum;
private Integer remainNum;
private Integer reserveOrderNum;
}
......@@ -7,6 +7,7 @@ import lombok.Data;
@XStreamAlias("OrderInfo")
public class OrderInfo {
private String doctorId;
private String deptId;
private String hosOrgCode;
private String oneDeptCode;
private String deptCode;
......
......@@ -3,8 +3,9 @@ package cn.sh.stc.sict.theme.hphy.wd;
public class WanDaConstant {
/**
* 预约类型:医生
* 预约类型:1-医生 2-门诊
*/
public static final String ORDER_TYPE_DOCT = "1";
public static final String ORDER_TYPE_OUTP = "1";
public static final String ORDER_TYPE_CLINC = "2";
......@@ -40,4 +41,9 @@ public class WanDaConstant {
public static final String PATIENT_TYPE_NORMAL = "1";
public static final String CANCELOBJ_PATIENT = "1";
/**
* 医院预约方式:有卡预约
*/
public static final String ORDER_MODEL_1 = "1";
}
package cn.sh.stc.sict.theme.hphy.wd;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.HttpRequest;
......@@ -8,15 +9,16 @@ import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import javax.print.DocFlavor;
import javax.xml.xpath.XPathConstants;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Slf4j
@UtilityClass
......@@ -30,7 +32,7 @@ public class WanDaHttpUtil {
/**
* 获取家庭医生签约信息
*/
public static String getContractInfo(String idNo){
public static String getContractInfo(String idNo) {
ContractParam param = new ContractParam(idNo);
String body = HttpRequest.post(CONTRACT_INFO_URL)
.body(JSONUtil.toJsonStr(param))
......@@ -39,7 +41,7 @@ public class WanDaHttpUtil {
System.out.println(body);
JSON parse = JSONUtil.parse(body);
Object obj = parse.getByPath("data.pageInfo.totals");
if(null!=obj&& Integer.valueOf(obj.toString())>0){
if (null != obj && Integer.valueOf(obj.toString()) > 0) {
JSONArray arr = parse.getByPath("data.data", JSONArray.class);
return ((JSONObject) arr.get(0)).get("SQJGMC").toString();
}
......@@ -48,6 +50,7 @@ public class WanDaHttpUtil {
/**
* 发送短信
*
* @param phone
* @param msg
* @param appName
......@@ -116,7 +119,7 @@ public class WanDaHttpUtil {
log.error("获取一级科室信息失败");
return null;
}
log.info("获取一级科室信息:body = {}", body);
// log.info("获取一级科室信息:body = {}", body);
String returnXml = getReturn(body, "GetDeptInfoTopService");
return serialDeptInfos(returnXml);
}
......@@ -139,7 +142,7 @@ public class WanDaHttpUtil {
log.error("获取二级科室信息失败");
return null;
}
log.info("获取二级科室信息:body = {}", body);
// log.info("获取二级科室信息:body = {}", body);
String returnXml = getReturn(body, "GetDeptInfoTwoService");
return serialDeptInfos(returnXml);
}
......@@ -197,29 +200,44 @@ public class WanDaHttpUtil {
*/
public List<NumSourceInfo> getOrderNumInfo(NumSourceInfo numSourceInfo) {
String xml = WanDaUtil.GetOrderNumInfoServiceXML(numSourceInfo);
System.out.println(xml);
String body = HttpRequest.post(URL)
.body(xml)
.execute()
.body();
log.error("号源查询:xml = {}", xml);
String body = "";
try {
body = HttpRequest.post(URL)
.body(xml)
.execute()
.body();
if (StrUtil.isBlank(body)) {
log.error("号源查询 失败");
return null;
}
String returnXml = getReturn(body, "GetOrderNumInfoService");
if (Constant.STRING_NO.equals(getCode(returnXml))) {
Document document = XmlUtil.readXML(returnXml);
NodeList nodeList = document.getElementsByTagName("NumSourceInfo");
List<NumSourceInfo> list = new ArrayList<>();
if (null != nodeList && nodeList.getLength() > 0) {
for (int i = 0; i < nodeList.getLength(); i++) {
if (StrUtil.isBlank(body)) {
log.error("号源查询 失败");
return null;
}
log.info("号源查询:body = {}", body);
String returnXml = getReturn(body, "GetOrderNumInfoService");
if (Constant.STRING_NO.equals(getCode(returnXml))) {
Document document = XmlUtil.readXML(returnXml);
NodeList nodeList = document.getElementsByTagName("NumSourceInfo");
List<NumSourceInfo> list = new ArrayList<>();
if (null != nodeList && nodeList.getLength() > 0) {
for (int i = 0; i < nodeList.getLength(); i++) {
list.add(XmlUtil.xmlToBean(nodeList.item(i), NumSourceInfo.class));
try {
// 外层异常只处理查询号源、解析xml的问题
// 号源数据出现异常,不再处理(大概率是医院数据质量低,造成号源数字解析问题)
list.add(XmlUtil.xmlToBean(nodeList.item(i), NumSourceInfo.class));
} catch (Exception e) {
// ignore exception
}
}
}
return list;
} else {
return null;
}
return list;
} else {
} catch (Exception e) {
log.error("号源查询失败,num = {}", JSONUtil.toJsonStr(numSourceInfo));
log.error("号源查询失败,body = {}", body);
log.error(e.getMessage(), e);
return null;
}
}
......@@ -417,7 +435,7 @@ public class WanDaHttpUtil {
*/
public List<DoctInfo> getResourceDoctInfo(DeptInfo deptInfo) {
String xml = WanDaUtil.GetResourceDoctInfoServiceXML(deptInfo);
log.error("获取可预约医生信息 xml = {}", xml);
String body = HttpRequest.post(URL)
.body(xml)
.execute()
......@@ -427,7 +445,7 @@ public class WanDaHttpUtil {
log.error("获取可预约医生信息 失败");
return null;
}
log.info("获取可预约医生信息:body = {}", body);
log.error("获取可预约医生信息:body = {}", body);
String returnXml = getReturn(body, "GetResourceDoctInfoService");
return serialDoctInfo(returnXml);
}
......@@ -440,7 +458,7 @@ public class WanDaHttpUtil {
*/
public List<OutPatInfo> getResourceOutPatInfo(DeptInfo deptInfo) {
String xml = WanDaUtil.GetResourceOutPatInfoServiceXML(deptInfo);
log.error("获取可预约门诊信息 xml = {}", xml);
String body = HttpRequest.post(URL)
.body(xml)
.execute()
......@@ -450,7 +468,7 @@ public class WanDaHttpUtil {
log.error("查询门诊信息失败");
return null;
}
log.info("查询门诊信息:body = {}", body);
log.error("查询门诊信息:body = {}", body);
String returnXml = getReturn(body, "GetResourceOutPatInfoService");
return serialOutPatInfo(returnXml);
}
......@@ -481,7 +499,11 @@ public class WanDaHttpUtil {
List<DoctInfo> list = new ArrayList<>();
if (null != nodeList && nodeList.getLength() > 0) {
for (int i = 0; i < nodeList.getLength(); i++) {
list.add(XmlUtil.xmlToBean(nodeList.item(i), DoctInfo.class));
try {
list.add(XmlUtil.xmlToBean(nodeList.item(i), DoctInfo.class));
}catch (Exception e){
// ignore exception
}
}
}
return list;
......@@ -499,7 +521,11 @@ public class WanDaHttpUtil {
List<OutPatInfo> list = new ArrayList<>();
if (null != nodeList && nodeList.getLength() > 0) {
for (int i = 0; i < nodeList.getLength(); i++) {
list.add(XmlUtil.xmlToBean(nodeList.item(i), OutPatInfo.class));
try {
list.add(XmlUtil.xmlToBean(nodeList.item(i), OutPatInfo.class));
}catch (Exception e){
// ignore exception
}
}
}
return list;
......
......@@ -11,8 +11,13 @@ spring:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7
namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
config:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7
namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
\ No newline at end of file
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
logging:
level:
cn.sh.stc.sict.theme.hpgp.dao: DEBUG
cn.sh.stc.sict.theme.hphy.dao: DEBUG
server:
port: 12253
spring:
application:
name: @artifactId@
main:
allow-bean-definition-overriding: true
# nacos
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
config:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
......@@ -63,7 +63,7 @@
<appender-ref ref="error"/>
</logger>
<!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 -->
<root level="INFO">
<root level="ERROR">
<appender-ref ref="console"/>
<appender-ref ref="debug"/>
</root>
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.dao.HpPatientCardMapper">
<resultMap type="cn.sh.stc.sict.theme.model.HpPatientCard" id="HpPatientCardMap">
<result property="id" column="id"/>
<result property="patientId" column="patient_id"/>
<result property="userId" column="user_id"/>
<result property="cardNo" column="card_no"/>
<result property="cardType" column="card_type"/>
<result property="hospitalId" column="hospital_id"/>
</resultMap>
</mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.hpgp.dao.HpgpLabExperienceMapper">
<resultMap type="cn.sh.stc.sict.theme.hpgp.model.HpgpLabExperience" id="HpgpLabExperienceMap">
<result property="id" column="id"/>
<result property="hospCode" column="hosp_code"/>
<result property="hospName" column="hosp_name"/>
<result property="deptCode" column="dept_code"/>
<result property="deptName" column="dept_name"/>
<result property="itemName" column="item_name"/>
</resultMap>
</mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.hpgp.dao.HpgpLumbarAnswerMapper">
<resultMap type="cn.sh.stc.sict.theme.hpgp.model.HpgpLumbarAnswer" id="HpgpLumbarAnswerMap">
<result property="id" column="id"/>
<result property="userId" column="user_id"/>
<result property="patientId" column="patient_id"/>
<result property="answerJson" column="answer_json"/>
<result property="age" column="age"/>
<result property="score" column="score"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
</mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.hpgp.dao.HpAppointmentEvaMapper">
<resultMap type="cn.sh.stc.sict.theme.hpgp.model.HpAppointmentEva" id="HpAppointmentEvaMap">
<result property="id" column="id"/>
<result property="userId" column="user_id"/>
<result property="patientId" column="patient_id"/>
<result property="appId" column="app_id"/>
<result property="hospCode" column="hosp_code"/>
<result property="hospName" column="hosp_name"/>
<result property="deptCode" column="dept_code"/>
<result property="deptName" column="dept_name"/>
<result property="doctorCode" column="doctor_code"/>
<result property="doctorName" column="doctor_name"/>
<result property="comprehensiveEva" column="comprehensive_eva"/>
<result property="efficacyEva" column="efficacy_eva"/>
<result property="attitudeEva" column="attitude_eva"/>
<result property="appTime" column="app_time"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<select id="toBeEavPage" resultType="cn.sh.stc.sict.theme.hpgp.model.HpAppointmentEva">
select patient_id patientId,
id appId,
hos_org_code hospCode,
hos_org_name hospName,
dept_code deptCode,
dept_name deptName,
doctor_id doctorCode,
doctor_name doctorName,
num_source_date appTime
from hp_appointment
where patient_id = #{patientId}
and eva_status = 0
order by num_source_date desc
</select>
</mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.hpgp.dao.HpHzjlMapper">
<resultMap type="cn.sh.stc.sict.theme.hpgp.model.HpHzjl" id="HpHzjlMap">
<result property="zjhm" column="ZJHM"/>
<result property="zjlx" column="ZJLX"/>
<result property="xm" column="XM"/>
<result property="yljgdm" column="YLJGDM"/>
<result property="jzlx" column="JZLX"/>
<result property="txbz" column="TXBZ"/>
<result property="jzksbm" column="JZKSBM"/>
<result property="jzksmc" column="JZKSMC"/>
<result property="jzksrq" column="JZKSRQ"/>
<result property="zzysgh" column="ZZYSGH"/>
<result property="zzysxm" column="ZZYSXM"/>
<result property="jzzdsm" column="JZZDSM"/>
</resultMap>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.hpgp.dao.HpgpBusyIdlePredictionMapper">
<resultMap type="cn.sh.stc.sict.theme.hpgp.model.HpgpBusyIdlePrediction" id="HpgpBusyIdle_ predictionMap">
<result property="hospitalCode" column="hospital_code"/>
<result property="hospitalName" column="hospital_name"/>
<result property="deptCode" column="dept_code"/>
<result property="deptName" column="dept_name"/>
<result property="predictionDate" column="prediction_date"/>
<result property="score" column="score"/>
</resultMap>
<sql id="Base_Column_List">
hospital_code
, hospital_name, dept_code, dept_name, prediction_date, score
</sql>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.hpgp.dao.HpgpDepartmentRankMapper">
<resultMap type="cn.sh.stc.sict.theme.hpgp.model.HpgpDepartmentRank" id="HpgpDepartmentRankMap">
<result property="standardDeptCategory" column="standard_dept_category"/>
<result property="standardDept" column="standard_dept"/>
<result property="hospitalCode" column="hospital_code"/>
<result property="hospitalName" column="hospital_name"/>
<result property="deptCode" column="dept_code"/>
<result property="deptName" column="dept_name"/>
<result property="rankScore" column="rank_score"/>
</resultMap>
<resultMap id="StandardDeptDicMap" type="java.util.LinkedHashMap">
<result property="standardDeptCategory" column="standard_dept_category"/>
<collection property="children" javaType="java.lang.String" ofType="java.util.LinkedHashMap">
<result property="standardDept" column="standard_dept"/>
</collection>
</resultMap>
<sql id="Base_Column_List">standard_dept_category, standard_dept , hospital_code, hospital_name, dept_code, dept_name, rank_score </sql>
<select id="getRankByHosAndStandardDept" resultType="cn.sh.stc.sict.theme.hpgp.vo.DeptRankVO">
select dr.standard_dept standardDept,
dr.hospital_code hospitalCode,
dr.hospital_name hospitalName,
dr.dept_code deptCode,
dr.dept_name deptName,
dr.rank_score rankScore,
d.one_dept_code oneDeptCode,
d.dept_code subDeptCode
from hpgp_department_rank dr
join hp_dept_info d on (dr.hospital_code = d.hos_org_code and dr.one_dept_code = d.one_dept_code and dr.dept_code = d.dept_code)
<where>
<choose>
<when test="hospitalCode != null and hospitalCode != ''">
AND dr.hospital_code = #{hospitalCode}
AND dr.rank_score = 0
</when>
<otherwise>
AND dr.rank_score != 0
</otherwise>
</choose>
<if test="deptName != null and deptName != ''">
AND dr.standard_dept = #{deptName}
</if>
</where>
order by dr.rank_score asc
<if test="size != null and size != 0">
limit #{size}
</if>
</select>
<select id="getStandardDeptDic" resultType="java.util.LinkedHashMap">
SELECT distinct standard_dept_category,standard_dept
FROM hpgp_department_rank
<where>
delete_flag = 0
AND standard_dept_category IS NOT NULL
AND standard_dept IS NOT NULL
<if test="hospitalCode != null and hospitalCode != ''">
AND hospital_code = #{hospitalCode}
</if>
ORDER BY show_category_sort_idx ASC,
show_standard_dept_sort_idx ASC
</where>
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.hpgp.dao.HpgpDiagnosticExperienceMapper">
<resultMap type="cn.sh.stc.sict.theme.hpgp.model.HpgpDiagnosticExperience" id="HpgpDiagnosticExperienceMap">
<result property="hospitalCode" column="hospital_code"/>
<result property="hospitalName" column="hospital_name"/>
<result property="deptCode" column="dept_code"/>
<result property="deptName" column="dept_name"/>
<result property="diagnoses" column="diagnoses"/>
<result property="total" column="total"/>
</resultMap>
<sql id="Base_Column_List">
hospital_code
, hospital_name, dept_code, dept_name, diagnoses, total </sql>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.hpgp.dao.HpgpInspectionCheckMapper">
<resultMap type="cn.sh.stc.sict.theme.hpgp.model.HpgpInspectionCheck" id="HpgpInspectionCheckMap">
<result property="hospitalCode" column="hospital_code"/>
<result property="hospitalName" column="hospital_name"/>
<result property="deptCode" column="dept_code"/>
<result property="deptName" column="dept_name"/>
<result property="itemName" column="item_name"/>
</resultMap>
<sql id="Base_Column_List">hospital_code, hospital_name, dept_code, dept_name, item_name</sql>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.hpgp.dao.HpgpKsHotMapper">
<resultMap type="cn.sh.stc.sict.theme.hpgp.model.HpgpKsHot" id="HpgpKsHotMap">
<result property="gzh" column="gzh"/>
<result property="standardDept" column="standard_dept"/>
<result property="hospitalCode" column="hospital_code"/>
<result property="hospitalName" column="hospital_name"/>
<result property="oneDeptCode" column="one_dept_code"/>
<result property="deptCode" column="dept_code"/>
<result property="deptName" column="dept_name"/>
<result property="rankScore" column="rank_score"/>
</resultMap>
<sql id="Base_Column_List">
gzh, standard_dept, hospital_code, hospital_name, one_dept_code, dept_code, dept_name, rank_score </sql>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.hphy.dao.HpStatisticsMapper">
<resultMap type="cn.sh.stc.sict.theme.hphy.vo.StatisticsUsageVO$HosUsageStatistics" id="AppointmentHosCountMap">
<result property="appointmentUserCount" column="appointment_count" jdbcType="INTEGER"/>
<result property="hospitalCode" column="hos_org_code" jdbcType="VARCHAR"/>
<result property="hospitalName" column="hos_name" jdbcType="VARCHAR"/>
</resultMap>
<select id="queryAppointmentUserGroupByHos" resultMap="AppointmentHosCountMap">
SELECT
c.appointment_count,
c.hos_org_code,
h.hos_name
FROM (
SELECT count(1) AS appointment_count, hos_org_code
FROM `hp_appointment`
<where>
<if test="startTime != null and startTime != '' ">
AND create_time >= #{startTime}
</if>
<if test="endTime != null and endTime != '' ">
AND create_time &lt;= #{endTime}
</if>
</where>
GROUP BY hos_org_code
) c
LEFT JOIN hp_hos_info h ON c.hos_org_code = h.hos_org_code
</select>
<select id="countNewUser" resultType="java.lang.Long">
SELECT count(1)
FROM hp_user_base
<where>
<if test="startTime != null and startTime != '' ">
AND create_time >= #{startTime}
</if>
<if test="endTime != null and endTime != '' ">
AND create_time &lt;= #{endTime}
</if>
</where>
</select>
<select id="countLoginUser" resultType="java.lang.Long">
SELECT
count( DISTINCT create_by )
FROM
`sys_log`
<where>
<if test="startTime != null and startTime != '' ">
AND create_time >= #{startTime}
</if>
<if test="endTime != null and endTime != '' ">
AND create_time &lt;= #{endTime}
</if>
<if test="appId != null and appId != '' ">
AND create_by like concat('%',#{appId},'%')
</if>
AND `title` LIKE '%用户登录%'
AND `exception` = ''
</where>
</select>
<select id="countHealthManagementCenter" resultType="java.util.Map">
SELECT
COUNT(1) AS '卫管中心总预约次' ,
COUNT(IF(length(exception) = 0 OR exception IS NULL ,TRUE,NULL) ) AS '卫管中心成功预约次' ,
COUNT(IF(length(exception) >0,TRUE,NULL) ) AS '卫管中心失败预约次'
FROM `sys_log`
WHERE title = '预约' AND create_by like '%wx24c55f38b535cd96%'
</select>
<select id="countAll4Third" resultType="java.util.LinkedHashMap">
SELECT * FROM
(
-- 统计各家医院预约人数
SELECT
IFNULL(c.appointment_count,0) AS '导诊数',
h.hos_org_code AS '医疗机构代码',
h.hos_name AS '医疗机构名称',
t.inter_des AS '对接状态',
DATE_FORMAT(c.create_time,'%Y-%m-%d') AS '导诊时间'
FROM (
SELECT count(1) AS appointment_count,
hos_org_code,
create_time
FROM `hp_appointment`
<where>
<if test="startTime != null and startTime != '' ">
AND create_time >= #{startTime}
</if>
<if test="endTime != null and endTime != '' ">
AND create_time &lt;= #{endTime}
</if>
</where>
GROUP BY hos_org_code,DATE_FORMAT(create_time,'%Y-%m-%d')
) c
RIGHT JOIN hp_hos_info h ON c.hos_org_code = h.hos_org_code
RIGHT JOIN hp_third_interface_status t ON h.hos_org_code = t.hos_org_code
UNION ALL
-- 统计卫管中心预约人数
SELECT
COUNT(1) AS '导诊数' ,
1 AS '医疗机构代码' ,
'卫管中心' AS '医疗机构名称',
'已对接' AS '对接状态',
DATE_FORMAT(create_time,'%Y-%m-%d') AS '导诊时间'
FROM `sys_log`
WHERE title = '预约' AND create_by like '%wx24c55f38b535cd96%'
<if test="startTime != null and startTime != '' ">
AND create_time >= #{startTime}
</if>
<if test="endTime != null and endTime != '' ">
AND create_time &lt;= #{endTime}
</if>
GROUP BY DATE_FORMAT(create_time,'%Y-%m-%d')
) t
WHERE 导诊时间 IS not null
order by `医疗机构代码`,`导诊时间`
</select>
</mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.hphy.dao.HpThirdInterfaceStatusMapper">
<resultMap type="cn.sh.stc.sict.theme.hphy.model.HpThirdInterfaceStatus" id="HpThirdInterfaceStatusMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="hosOrgCode" column="hos_org_code" jdbcType="VARCHAR"/>
<result property="hosOrgName" column="hos_org_name" jdbcType="VARCHAR"/>
<result property="interStatus" column="inter_status" jdbcType="INTEGER"/>
<result property="interDes" column="inter_des" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
</resultMap>
<!-- 批量插入 -->
<insert id="insertBatch" keyProperty="id" useGeneratedKeys="true">
insert into hp_third_interface_status(hos_org_code, hos_org_name, inter_status, inter_des, create_time, update_time)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.hosOrgCode}, #{entity.hosOrgName}, #{entity.interStatus}, #{entity.interDes}, #{entity.createTime}, #{entity.updateTime})
</foreach>
</insert>
<!-- 批量插入或按主键更新 -->
<insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true">
insert into hp_third_interface_status(hos_org_code, hos_org_name, inter_status, inter_des, create_time, update_time)
values
<foreach collection="entities" item="entity" separator=",">
(#{entity.hosOrgCode}, #{entity.hosOrgName}, #{entity.interStatus}, #{entity.interDes}, #{entity.createTime}, #{entity.updateTime})
</foreach>
on duplicate key update
hos_org_code = values(hos_org_code) , hos_org_name = values(hos_org_name) , inter_status = values(inter_status) , inter_des = values(inter_des) , create_time = values(create_time) , update_time = values(update_time) </insert>
<update id="updateStatusByHosCode">
UPDATE hp_third_interface_status set inter_status = #{status}
<choose>
<when test="hosOrgCode == 1">
,inter_des = '未对接'
</when>
<when test="hosOrgCode == 2">
,inter_des = '正在对接'
</when>
<when test="hosOrgCode == 3">
,inter_des = '已对接'
</when>
</choose>
WHERE hos_org_code = #{hosOrgCode}
</update>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.sh.stc.sict.theme.hphy.dao.HphyPatientRelationMapper">
<resultMap type="cn.sh.stc.sict.theme.hphy.model.HphyPatientRelation" id="HphyPatientRelationMap">
<result property="id" column="id"/>
<result property="sourcePatientId" column="source_patient_id"/>
<result property="targetPatientId" column="target_patient_id"/>
<result property="relationCode" column="relation_code"/>
<result property="relationName" column="relation_name"/>
<result property="createTime" column="create_time"/>
<result property="createUserName" column="create_user_name"/>
<result property="updateTime" column="update_time"/>
<result property="updateUserName" column="update_user_name"/>
</resultMap>
<select id="listPatientRelation" resultType="cn.sh.stc.sict.theme.hphy.vo.PatientRelationVO">
select r.id relationId,
r.relation_code relationCode,
r.relation_name relationName,
p.id,
p.user_id userId,
p.open_id openId,
p.patient_id patientId,
p.name,
p.gender,
p.age,
p.education,
p.current_address currentAddress,
p.marriage_status marriageStatus
, p.`avg_hospitalized_days` avgHospitalizedDays
, p.`insurance_type` insuranceType
, p.`nation`
, p.`blood_type` bloodType
, p.`resident_address` residentAddress
, p.`occupation`
, p.`cert_id` certId
, p.`update_time` updateTime
, p.`disease`
, p.`tag`
, p.`condition`
, p.`phone`
, p.`medi_card_id` mediCardId
, p.`medi_card_type` mediCardType
, p.`enterprise_name` enterpriseName
, p.`family_doc_hos` familyDocHos
, p.`verify_status` verifyStatus
from hphy_patient_relation r
join hphy_patient_base p on r.target_patient_id = p.id or r.source_patient_id = p.id
where (r.source_patient_id = #{patientId} or r.target_patient_id = #{patientId})
and p.id &lt;&gt; #{patientId}
</select>
</mapper>
\ No newline at end of file