From cb9461de538c19e57955d3cab4d166f864d3a5df Mon Sep 17 00:00:00 2001 From: gaozhaochen Date: Sun, 13 Nov 2022 16:08:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20->=20=E9=A6=99=E5=B1=B1?= =?UTF-8?q?=E5=8C=BB=E9=99=A2=E5=85=AC=E4=BC=97=E5=8F=B7=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=201.=E5=9C=A8=E6=9D=8E=E5=A4=84=E7=90=86?= =?UTF-8?q?=E7=9A=84=E4=B8=80=E5=B9=B4=E5=86=85=E5=8E=86=E5=8F=B2=E5=B0=B1?= =?UTF-8?q?=E8=AF=8A=E8=AE=B0=E5=BD=95=E7=9A=84=E8=A1=A8=E4=B8=AD=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E2=80=9C=E5=85=AC=E4=BC=97=E5=8F=B7=E5=8C=BB=E9=99=A2?= =?UTF-8?q?=E2=80=9D=E7=9A=84=E4=B8=89=E4=B8=AA=E5=8E=86=E5=8F=B2=E7=A7=91?= =?UTF-8?q?=E5=AE=A4=E5=B1=95=E7=A4=BA=202.=E4=BB=8E=E2=80=9Chpgp=5Fks=5Fh?= =?UTF-8?q?ot=E2=80=9D=E8=A1=A8=E4=B8=AD=E6=9F=A5=E8=AF=A2=E5=B1=95?= =?UTF-8?q?=E7=A4=BA=E2=80=9C=E5=85=AC=E4=BC=97=E5=8F=B7=E5=8C=BB=E9=99=A2?= =?UTF-8?q?=E2=80=9D=E7=9A=84=E7=A7=91=E5=AE=A4=EF=BC=88=E7=83=AD=E9=97=A8?= =?UTF-8?q?=E7=A7=91=E5=AE=A4=E7=94=B1=E5=8C=BB=E9=99=A2=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=EF=BC=8C=E7=9B=AE=E5=89=8D=E6=9A=82=E6=97=B6=E7=94=A8=E9=97=A8?= =?UTF-8?q?=E8=AF=8A=E9=87=8F=E6=9C=80=E5=A4=A7=E7=9A=84=E4=B8=89=E4=B8=AA?= =?UTF-8?q?=E7=A7=91=E5=AE=A4=E4=BB=A3=E6=9B=BF=EF=BC=89=203.=E6=8C=89?= =?UTF-8?q?=E7=85=A7standard=5Fdept=EF=BC=88=3D=E9=80=89=E6=8B=A9/?= =?UTF-8?q?=E6=9C=BA=E5=99=A8=E4=BA=BA=E6=8E=A8=E8=8D=90=E7=9A=84=E7=A7=91?= =?UTF-8?q?=E5=AE=A4=EF=BC=89=E3=80=81hospital=5Fcode=EF=BC=88=3D=E5=85=AC?= =?UTF-8?q?=E4=BC=97=E5=8F=B7=E5=8C=BB=E9=99=A2=EF=BC=89=E3=80=81rank=5Fsc?= =?UTF-8?q?ore=EF=BC=88=3D0=EF=BC=89=E6=9F=A5=E8=AF=A2=E7=A7=91=E5=AE=A4?= =?UTF-8?q?=EF=BC=8C=E9=80=89=E6=8B=A9=E6=9C=89=E5=8F=B7=E7=9A=84=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E5=B1=95=E7=A4=BA=EF=BC=88=E4=B8=80=E4=B8=AA=E5=8C=BB?= =?UTF-8?q?=E9=99=A2=E4=B8=AD=E6=9C=89=E5=A4=9A=E4=B8=AA=E5=90=8C=E5=90=8D?= =?UTF-8?q?=E7=A7=91=E5=AE=A4=EF=BC=8C=E5=A6=82=E6=9E=9C=E6=9C=89=E5=8F=B7?= =?UTF-8?q?=E7=9A=84=E8=B6=85=E8=BF=873=E4=B8=AA=E9=82=A3=E4=B9=9F?= =?UTF-8?q?=E5=8F=AA=E5=B1=95=E7=A4=BA3=E4=B8=AA=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../libs/openapi-sdk-java-1.0-RELEASE.jar | Bin 0 -> 45479 bytes cloud-common/cloud-common-core/pom.xml | 8 ++ .../core/constant/SecurityConstants.java | 4 + .../core/constant/enums/LoginTypeEnum.java | 14 +++ .../cloud/common/core/dto/XSZYUserInfo.java | 48 +++++++++ .../sict/cloud/common/core/util/WoaUtil.java | 76 ++++++++++++++ .../SictUserAuthenticationConverter.java | 97 +++++++++--------- .../common/security/service/SictUser.java | 10 ++ .../service/SictUserDetailsServiceImpl.java | 4 +- .../common/security/util/SecurityUtils.java | 1 + pom.xml | 3 + .../stc/sict/cloud/upms/dto/CurrentUser.java | 4 + .../sh/stc/sict/cloud/upms/dto/UserInfo.java | 5 + .../service/impl/SysUserBaseServiceImpl.java | 80 +++++++++++++-- .../controller/mobile/HpHzjlController.java | 21 ++-- .../HpgpBusyIdlePredictionController.java | 7 +- .../hpgp/dao/HpgpDepartmentRankMapper.java | 10 +- .../sict/theme/hpgp/dao/HpgpKsHotMapper.java | 14 +++ .../stc/sict/theme/hpgp/model/HpgpKsHot.java | 46 +++++++++ .../theme/hpgp/service/HpHzjlService.java | 21 +++- .../HpgpBusyIdlePredictionService.java | 8 +- .../theme/hpgp/service/HpgpKsHotService.java | 24 +++++ .../hpgp/service/impl/HpHzjlServiceImpl.java | 33 ++++-- .../HpgpBusyIdlePredictionServiceImpl.java | 74 +++++++++++-- .../service/impl/HpgpKsHotServiceImpl.java | 31 ++++++ .../mp/HphyPatientBaseController.java | 11 +- .../hphy/service/HphyPatientBaseService.java | 10 ++ .../impl/HphyPatientBaseServiceImpl.java | 34 ++++++ .../mapper/hpgp/HpgpDepartmentRankMapper.xml | 25 ++++- .../resources/mapper/hpgp/HpgpKsHotMapper.xml | 18 ++++ 30 files changed, 639 insertions(+), 102 deletions(-) create mode 100644 cloud-common/cloud-common-core/libs/openapi-sdk-java-1.0-RELEASE.jar create mode 100644 cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/dto/XSZYUserInfo.java create mode 100644 cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/util/WoaUtil.java create mode 100644 smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/dao/HpgpKsHotMapper.java create mode 100644 smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/model/HpgpKsHot.java create mode 100644 smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/HpgpKsHotService.java create mode 100644 smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/impl/HpgpKsHotServiceImpl.java create mode 100644 smart-health-modules/theme-schema/src/main/resources/mapper/hpgp/HpgpKsHotMapper.xml diff --git a/cloud-common/cloud-common-core/libs/openapi-sdk-java-1.0-RELEASE.jar b/cloud-common/cloud-common-core/libs/openapi-sdk-java-1.0-RELEASE.jar new file mode 100644 index 0000000000000000000000000000000000000000..07d3838522ac7af1d5e452c12e8801407c7b4807 GIT binary patch literal 45479 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

>>6j%N0bo}3jOhuYjx&%vj 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 OJ;8*7OUya<`Tqb$1qwv~ literal 0 HcmV?d00001 diff --git a/cloud-common/cloud-common-core/pom.xml b/cloud-common/cloud-common-core/pom.xml index ff0d896..32d6091 100644 --- a/cloud-common/cloud-common-core/pom.xml +++ b/cloud-common/cloud-common-core/pom.xml @@ -80,5 +80,13 @@ org.springframework.boot spring-boot-starter-data-redis + + + com.ngarihealth + openapi-sdk-java + 1.0-RELEASE + system + ${project.basedir}/libs/openapi-sdk-java-1.0-RELEASE.jar + \ No newline at end of file diff --git a/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/constant/SecurityConstants.java b/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/constant/SecurityConstants.java index ba5a761..ff18d8b 100644 --- a/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/constant/SecurityConstants.java +++ b/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/constant/SecurityConstants.java @@ -136,6 +136,10 @@ public interface SecurityConstants { * openid */ String DETAILS_APPID = "appid"; + /** + * 医院代码 + */ + String HOSPITAL_CODE = "hospitalCode"; /** * 租户ID 字段 */ diff --git a/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/constant/enums/LoginTypeEnum.java b/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/constant/enums/LoginTypeEnum.java index 4059a58..7b32898 100644 --- a/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/constant/enums/LoginTypeEnum.java +++ b/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/constant/enums/LoginTypeEnum.java @@ -27,6 +27,11 @@ public enum LoginTypeEnum { */ SSB("ssb", "随申办token"), + /** + * 公众号香山中医医院 + */ + WOA_XSZY("woa_xszy", "香山中医医院公众号"), + /** * H5登录 */ @@ -51,4 +56,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; + } } diff --git a/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/dto/XSZYUserInfo.java b/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/dto/XSZYUserInfo.java new file mode 100644 index 0000000..95a0b28 --- /dev/null +++ b/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/dto/XSZYUserInfo.java @@ -0,0 +1,48 @@ +package cn.sh.stc.sict.cloud.common.core.dto; + + +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; + + +} diff --git a/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/util/WoaUtil.java b/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/util/WoaUtil.java new file mode 100644 index 0000000..fc5649b --- /dev/null +++ b/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/util/WoaUtil.java @@ -0,0 +1,76 @@ +package cn.sh.stc.sict.cloud.common.core.util; + +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.convert.Convert; +import cn.sh.stc.sict.cloud.common.core.constant.Constant; +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; + +/** + * 医院公众号工具类 + *

+ * 注意事项: + * 1.医院编码是否传递 + * 2.手机号必须有,作为用户身份的唯一标识 + */ +@Slf4j +@UtilityClass +public class WoaUtil { + + // 香山中医医院公众号用户信息获取接口地址(纳里) + private final static String XSZY_USER_URL = "https://openapi.ngarihealth.com/openapi/gateway"; + + // 接口授权信息 + 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-Request-Id"; + + // 香山中医医院编码 + private final static String XSZY_HOSPITAL_CODE = "42502905200"; + + /** + * 获取用户信息 + * + * @param ngCode 纳里授权码 + * @return + */ + public XSZYUserInfo getXszyUserInfo(String ngCode) { + + //如果开启加密,则必填 + String encodingAesKey = ""; + Client client = new Client(XSZY_USER_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()); + // 设置医院编码 + xszyUserInfo.setHospitalCode(XSZY_HOSPITAL_CODE); + return xszyUserInfo; + } else { + log.error("香山中医医院公众号token获取用户信息异常-1,requestId = [{}],caError = [{}],error = [{}]", response.getHeader(RESPONSE_HEADER_REQUEST_ID), response.getCaErrorMsg(), response.getErrorMessage()); + return null; + } + } catch (Exception ex) { + log.error("香山中医医院公众号token获取用户信息异-2!"); + log.error(ex.getMessage(), ex); + return null; + } + } + +} diff --git a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/component/SictUserAuthenticationConverter.java b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/component/SictUserAuthenticationConverter.java index 5f972c0..c773919 100644 --- a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/component/SictUserAuthenticationConverter.java +++ b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/component/SictUserAuthenticationConverter.java @@ -19,56 +19,57 @@ 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 convertUserAuthentication(Authentication authentication) { - Map 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 convertUserAuthentication(Authentication authentication) { + Map 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 map) { - if (map.containsKey(USERNAME)) { - Collection 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 map) { + if (map.containsKey(USERNAME)) { + Collection 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); + SictUser user = new SictUser(id, "", openid, appid, hospitalCode, username, N_A, true + , true, true, true, authorities); + return new UsernamePasswordAuthenticationToken(user, N_A, authorities); + } + return null; + } - private Collection getAuthorities(Map 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 getAuthorities(Map 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"); + } } diff --git a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUser.java b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUser.java index dc4a258..e0f1dd0 100644 --- a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUser.java +++ b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUser.java @@ -35,6 +35,13 @@ public class SictUser extends User { @Setter private String appId; + /** + * 医院公众号登陆的用户包含医院代码 + */ + @Getter + @Setter + private String hospitalCode; + @Getter @Setter private transient String token; @@ -44,6 +51,7 @@ public class SictUser extends User { * {@link DaoAuthenticationProvider}. * * @param id 用户ID + * @param hospitalCode 医院代码 * @param username the username presented to the * DaoAuthenticationProvider * @param password the password that should be presented to the @@ -62,6 +70,7 @@ public class SictUser extends User { String phone, String openId, String appId, + String hospitalCode, String username, String password, boolean enabled, @@ -74,5 +83,6 @@ public class SictUser extends User { this.phone = phone; this.openId = openId; this.appId = appId; + this.hospitalCode = hospitalCode; } } diff --git a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUserDetailsServiceImpl.java b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUserDetailsServiceImpl.java index 0e72e0b..1bf5b4c 100644 --- a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUserDetailsServiceImpl.java +++ b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUserDetailsServiceImpl.java @@ -129,15 +129,15 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService { if (StrUtil.isBlank(user.getUserName())) { user.setUserName(user.getId().toString()); } - String userName = user.getUserName() + StringPool.COLON + info.getAppId(); 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(), userName, password, enabled, + return new SictUser(user.getId(), user.getPhone(), info.getOpenId(), info.getAppId(), info.getHospitalCode(), userName, password, enabled, true, true, nonLockd, authorities); } + private static String getAppId() { String appId = ""; try { diff --git a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/util/SecurityUtils.java b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/util/SecurityUtils.java index e1850c6..fcc3f5c 100644 --- a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/util/SecurityUtils.java +++ b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/util/SecurityUtils.java @@ -179,6 +179,7 @@ public class SecurityUtils { current.setOpenId(user.getOpenId()); current.setAppId(user.getAppId()); current.setPhone(user.getPhone()); + current.setHospitalCode(user.getHospitalCode()); } current.setToken(token); return current; diff --git a/pom.xml b/pom.xml index c3be02b..cec714b 100644 --- a/pom.xml +++ b/pom.xml @@ -171,6 +171,9 @@ org.springframework.boot spring-boot-maven-plugin ${spring-boot.version} + + true + diff --git a/smart-health-modules/cloud-upms/cloud-upms-api/src/main/java/cn/sh/stc/sict/cloud/upms/dto/CurrentUser.java b/smart-health-modules/cloud-upms/cloud-upms-api/src/main/java/cn/sh/stc/sict/cloud/upms/dto/CurrentUser.java index 5f25a56..27ccefc 100644 --- a/smart-health-modules/cloud-upms/cloud-upms-api/src/main/java/cn/sh/stc/sict/cloud/upms/dto/CurrentUser.java +++ b/smart-health-modules/cloud-upms/cloud-upms-api/src/main/java/cn/sh/stc/sict/cloud/upms/dto/CurrentUser.java @@ -19,6 +19,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; diff --git a/smart-health-modules/cloud-upms/cloud-upms-api/src/main/java/cn/sh/stc/sict/cloud/upms/dto/UserInfo.java b/smart-health-modules/cloud-upms/cloud-upms-api/src/main/java/cn/sh/stc/sict/cloud/upms/dto/UserInfo.java index 1d5407f..64834bc 100644 --- a/smart-health-modules/cloud-upms/cloud-upms-api/src/main/java/cn/sh/stc/sict/cloud/upms/dto/UserInfo.java +++ b/smart-health-modules/cloud-upms/cloud-upms-api/src/main/java/cn/sh/stc/sict/cloud/upms/dto/UserInfo.java @@ -14,6 +14,11 @@ public class UserInfo { private String openId; private String appId; + /** + * 医院公众号登陆的用户包含医院代码 + */ + private String hospitalCode; + /** * 用户基本信息 */ diff --git a/smart-health-modules/cloud-upms/cloud-upms-biz/src/main/java/cn/sh/stc/sict/cloud/upms/service/impl/SysUserBaseServiceImpl.java b/smart-health-modules/cloud-upms/cloud-upms-biz/src/main/java/cn/sh/stc/sict/cloud/upms/service/impl/SysUserBaseServiceImpl.java index 3d533ee..ca00fe8 100644 --- a/smart-health-modules/cloud-upms/cloud-upms-biz/src/main/java/cn/sh/stc/sict/cloud/upms/service/impl/SysUserBaseServiceImpl.java +++ b/smart-health-modules/cloud-upms/cloud-upms-biz/src/main/java/cn/sh/stc/sict/cloud/upms/service/impl/SysUserBaseServiceImpl.java @@ -10,8 +10,10 @@ 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.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; @@ -35,6 +37,7 @@ 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 @@ -77,18 +80,81 @@ public class SysUserBaseServiceImpl extends ServiceImpl 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 if (LoginTypeEnum.SSB.getType().equals(split[0])) { - return this.getBySSBToken(split[0], split[2]); - } else { + case SMS: + return this.getByPhone(split[2]); + // 随身办登陆 + case SSB: + return this.getBySSBToken(split[0], split[2]); + // 香山中医院公众号登陆 + // inStr = 公众号标识符@公众号appId@token@hospitalCode + case WOA_XSZY: + return this.getByXszyWoa(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 token = infoArray[2]; + + XSZYUserInfo xszyUserInfo = WoaUtil.getXszyUserInfo(token); + log.error("woa.login.xszyUser = {}", JSONUtil.toJsonStr(xszyUserInfo)); + if (ObjectUtil.isNull(xszyUserInfo) || StrUtil.isBlank(xszyUserInfo.getUserId())) { + return null; + } + + // 根据用户ID和手机号查询当前用户是否已注册过 + LambdaQueryWrapper 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()); + + this.save(user); + } + + UserInfo info = new UserInfo(); + info.setSysUserBase(user); + info.setOpenId(xszyUserInfo.getUserId()); + + // 设置香山中医医院医疗机构代码,后续查询只显示当前医疗机构下的查询结果 + info.setHospitalCode(xszyUserInfo.getHospitalCode()); + return info; + } + + private UserInfo getBySSBToken(String source, String token) { WDUserInfo wdUser = SsbUtil.getUserInfo(token); log.error("ssb.login.wdUser = {}", JSONUtil.toJsonStr(wdUser)); diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/controller/mobile/HpHzjlController.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/controller/mobile/HpHzjlController.java index a581f81..d1d827f 100644 --- a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/controller/mobile/HpHzjlController.java +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/controller/mobile/HpHzjlController.java @@ -4,25 +4,22 @@ 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 lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import cn.sh.stc.sict.cloud.common.core.util.R; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import cn.sh.stc.sict.theme.hpgp.model.HpHzjl; -import cn.sh.stc.sict.theme.hpgp.service.HpHzjlService; -import org.springframework.web.bind.annotation.*; 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 javax.annotation.Resource; -import java.io.Serializable; import java.util.List; /** @@ -56,7 +53,7 @@ public class HpHzjlController { log.error("patient = {}", JSONUtil.toJsonStr(patient)); return new R().error("患者信息异常!"); } - List result = hpHzjlService.listByCertId(patient.getCertId()); + List result = hpHzjlService.listByCertIdAndHosCode(patient.getCertId(), current.getHospitalCode()); return new R(result); } @@ -75,7 +72,7 @@ public class HpHzjlController { return new R().error("患者信息异常!"); } - List result = hpHzjlService.listDoctorByCertId(patient.getCertId()); + List result = hpHzjlService.listDoctorByCertIdAndHosCode(patient.getCertId(), current.getHospitalCode()); return new R(result); } } diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/controller/mobile/HpgpBusyIdlePredictionController.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/controller/mobile/HpgpBusyIdlePredictionController.java index e331af2..e75aa9c 100644 --- a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/controller/mobile/HpgpBusyIdlePredictionController.java +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/controller/mobile/HpgpBusyIdlePredictionController.java @@ -2,11 +2,13 @@ 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; @@ -18,6 +20,7 @@ import org.springframework.web.bind.annotation.RestController; * @author zhangly * @since 2022-01-14 09:56:44 */ +@Slf4j @Api(value = "[C] 黄浦全科导诊——忙闲预测维护接口", tags = "[C] 黄浦全科导诊——忙闲预测维护接口") @RestController @RequestMapping("/hpgp/c/busyidleprediction") @@ -29,8 +32,8 @@ public class HpgpBusyIdlePredictionController extends ApiController { private final HpgpBusyIdlePredictionService hpgpBusyIdlePredictionService; @GetMapping - public R busyIdlePrediction(@ApiParam("标准科室名称") @RequestParam("deptName") String deptName){ - return new R<>().success(hpgpBusyIdlePredictionService.busyIdlePrediction(deptName)); + public R busyIdlePrediction(@ApiParam("标准科室名称") @RequestParam("deptName") String deptName) { + return new R<>().success(hpgpBusyIdlePredictionService.busyIdlePrediction(SecurityUtils.getCurrentUser().getHospitalCode(), deptName)); } } diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/dao/HpgpDepartmentRankMapper.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/dao/HpgpDepartmentRankMapper.java index 597e714..6b4189c 100644 --- a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/dao/HpgpDepartmentRankMapper.java +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/dao/HpgpDepartmentRankMapper.java @@ -16,9 +16,13 @@ import java.util.List; public interface HpgpDepartmentRankMapper extends BaseMapper { /** * 根据标准科室名称查询医院科室排名 - * @param deptName 标准科室名称 - * @param size 查询记录数 默认3条 + * + * @param hospitalCode 医疗机构代码 + * @param deptName 标准科室名称 + * @param size 查询记录数 默认3条 * @return */ - List getRankByStandardDept(@Param("deptName") String deptName, @Param("size") int size); + List getRankByHosAndStandardDept(@Param("hospitalCode") String hospitalCode, + @Param("deptName") String deptName, + @Param("size") int size); } diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/dao/HpgpKsHotMapper.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/dao/HpgpKsHotMapper.java new file mode 100644 index 0000000..f5aefab --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/dao/HpgpKsHotMapper.java @@ -0,0 +1,14 @@ +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 { + +} diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/model/HpgpKsHot.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/model/HpgpKsHot.java new file mode 100644 index 0000000..817a54a --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/model/HpgpKsHot.java @@ -0,0 +1,46 @@ +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 { + //医疗结构代码(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; + + + +} diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/HpHzjlService.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/HpHzjlService.java index 2f256bc..48e6543 100644 --- a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/HpHzjlService.java +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/HpHzjlService.java @@ -1,9 +1,9 @@ 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 cn.sh.stc.sict.theme.hpgp.model.HpHzjl; import java.util.List; @@ -15,7 +15,22 @@ import java.util.List; */ public interface HpHzjlService extends IService { - List listByCertId(String certId); + /** + * 根据身份证号和医院查找最后三次不同科室就诊记录,并计算忙闲 + * 如果未找到,则推送三个热门科室 + * + * @param certId 身份证号 + * @param hospCode 医疗机构代码(医院编码) + * @return + */ + List listByCertIdAndHosCode(String certId, + String hospCode); - List listDoctorByCertId(String certId); + /** + * @param certId 身份证号 + * @param hospCode 医疗机构代码(医院编码) + * @return + */ + List listDoctorByCertIdAndHosCode(String certId, + String hospCode); } diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/HpgpBusyIdlePredictionService.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/HpgpBusyIdlePredictionService.java index 99176c3..498ef15 100644 --- a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/HpgpBusyIdlePredictionService.java +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/HpgpBusyIdlePredictionService.java @@ -19,10 +19,14 @@ public interface HpgpBusyIdlePredictionService extends IService busyIdlePrediction(String deptName); + List busyIdlePrediction(String hospitalCode, String deptName); void statisticResourceInfo(HpgpDepartmentRank dept, Date startDate, Date endDate, Byte flag); diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/HpgpKsHotService.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/HpgpKsHotService.java new file mode 100644 index 0000000..e2677e5 --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/HpgpKsHotService.java @@ -0,0 +1,24 @@ +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 { + + /** + * 根据医疗机构代码查询热门科室 + * + * @param yljgdm 医疗机构代码 + * @return + */ + List listHotDept(String yljgdm); + +} diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/impl/HpHzjlServiceImpl.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/impl/HpHzjlServiceImpl.java index 8541888..7179aa5 100644 --- a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/impl/HpHzjlServiceImpl.java +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/impl/HpHzjlServiceImpl.java @@ -4,20 +4,23 @@ 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.HpgpDepartmentRank; +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.HpDocInfo; -import cn.sh.stc.sict.theme.hphy.model.HphyDoctor; import cn.sh.stc.sict.theme.hphy.service.HpDocInfoService; 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.HpHzjlMapper; -import cn.sh.stc.sict.theme.hpgp.model.HpHzjl; -import cn.sh.stc.sict.theme.hpgp.service.HpHzjlService; import lombok.AllArgsConstructor; +import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import java.util.ArrayList; @@ -36,22 +39,26 @@ public class HpHzjlServiceImpl extends ServiceImpl impleme private final HpgpDepartmentRankService hpgpDepartmentRankService; private final HpgpBusyIdlePredictionService hpgpBusyIdlePredictionService; private final HpDocInfoService hpDocInfoService; + private final HpgpKsHotService hpgpKsHotService; /** * 根据身份证号查找最后三次不同科室就诊记录,并计算忙闲 * 如果未找到,则推送三个热门科室 * - * @param certId + * @param certId 身份证号 + * @param hospitalCode 医疗机构代码(医院编码) * @return */ @Override - public List listByCertId(String certId) { + public List listByCertIdAndHosCode(String certId, + String hospitalCode) { List result = new ArrayList<>(); DateTime startTime = DateUtil.tomorrow(); DateTime endTime = DateUtil.offsetDay(startTime, 6); LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); wrapper.eq(HpHzjl::getZjhm, certId) + .eq(StrUtil.isNotBlank(hospitalCode), HpHzjl::getYljgdm, hospitalCode) .groupBy(HpHzjl::getJzksbm) .orderByDesc(HpHzjl::getJzksrq) .last("limit 10"); @@ -70,9 +77,13 @@ public class HpHzjlServiceImpl extends ServiceImpl impleme result.addAll(hpgpBusyIdlePredictionService.listByDeptRank(dept, startTime, endTime)); } } + + // 历史科室查询结果为空时,采用热点科室数据 if (CollUtil.isEmpty(result)) { - List rankList = hpgpDepartmentRankService.listHotDept(); - rankList.forEach(rank -> { + List hotList = hpgpKsHotService.listHotDept(hospitalCode); + hotList.forEach(hot -> { + HpgpDepartmentRank rank = new HpgpDepartmentRank(); + BeanUtils.copyProperties(hot, rank); result.addAll(hpgpBusyIdlePredictionService.listByDeptRank(rank, startTime, endTime)); }); } @@ -81,9 +92,11 @@ public class HpHzjlServiceImpl extends ServiceImpl impleme } @Override - public List listDoctorByCertId(String certId) { + public List listDoctorByCertIdAndHosCode(String certId, + String hospitalCode) { LambdaQueryWrapper 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"); @@ -97,7 +110,7 @@ public class HpHzjlServiceImpl extends ServiceImpl impleme .eq(HpDocInfo::getResourceName, r.getZzysxm()) .last("limit 1"); HpDocInfo one = hpDocInfoService.getOne(dw); - if(ObjectUtil.isNotNull(one)){ + if (ObjectUtil.isNotNull(one)) { doctorList.add(one); } }); diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/impl/HpgpBusyIdlePredictionServiceImpl.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/impl/HpgpBusyIdlePredictionServiceImpl.java index 9afa8b3..4ff1a84 100644 --- a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/impl/HpgpBusyIdlePredictionServiceImpl.java +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/impl/HpgpBusyIdlePredictionServiceImpl.java @@ -22,7 +22,6 @@ 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.*; @@ -42,24 +41,85 @@ public class HpgpBusyIdlePredictionServiceImpl extends ServiceImpl busyIdlePrediction(String deptName) { - // 查询科室排名 - // 组装医院代码、科室代码 - // 查询医院忙闲 - List rankList = departmentRankMapper.getRankByStandardDept(deptName, 3); + public List 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 busyIdlePredictionByDeptName(String deptName) { + List 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 busyIdlePredictionByHosCodeAndDeptName(String hospitalCode, + String deptName) { + List rankList = departmentRankMapper.getRankByHosAndStandardDept(hospitalCode, deptName, 0); + if (CollectionUtil.isEmpty(rankList)) { + return null; + } + + List hpgpBusyIdlePredictionList = busyIdlePrediction(rankList); + + // 当前医院近七天有号的三个科室 + List 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 busyIdlePrediction(List deptList) { DateTime startTime = DateUtil.tomorrow(); DateTime endTime = DateUtil.offsetDay(startTime, 6); List result = new ArrayList<>(); - rankList.forEach(rank -> { + deptList.forEach(rank -> { + // 查询医院忙闲 result.addAll(this.listByDeptRank(rank, startTime, endTime)); }); return result; } + private HpgpBusyIdlePrediction getNoneSourcePredictionInfo(HpgpDepartmentRank rank, Date i) { HpgpBusyIdlePrediction vo = new HpgpBusyIdlePrediction(); vo.setDeptCode(rank.getDeptCode()); diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/impl/HpgpKsHotServiceImpl.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/impl/HpgpKsHotServiceImpl.java new file mode 100644 index 0000000..f82b9ae --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hpgp/service/impl/HpgpKsHotServiceImpl.java @@ -0,0 +1,31 @@ +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 implements HpgpKsHotService { + + @Override + public List listHotDept(String yljgdm) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(HpgpKsHot::getGzh, StrUtil.isBlank(yljgdm) ? "ALL" : yljgdm) + .orderByAsc(HpgpKsHot::getRankScore) + .last("limit 3"); + return this.list(wrapper); + } +} diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/mp/HphyPatientBaseController.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/mp/HphyPatientBaseController.java index 200fd21..11daa84 100644 --- a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/mp/HphyPatientBaseController.java +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/controller/mp/HphyPatientBaseController.java @@ -8,9 +8,11 @@ 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.WDUserCardInfo; import cn.sh.stc.sict.cloud.common.core.dto.WDUserInfo; +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.R; 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; @@ -143,7 +145,7 @@ public class HphyPatientBaseController { // 根据手机号去重 if (ObjectUtil.isNull(base) || NumberUtil.isNullOrZero(base.getId())) { base = hphyPatientBaseService.getByPhone(current.getPhone(), true); - if(NumberUtil.isNotNullOrZero(base.getId())){ + if (ObjectUtil.isNotNull(base) && NumberUtil.isNotNullOrZero(base.getId())) { HphyPatientBase update = new HphyPatientBase(); update.setOpenId(current.getOpenId()); update.setId(base.getId()); @@ -151,6 +153,7 @@ public class HphyPatientBaseController { } } if (ObjectUtil.isNull(base) || NumberUtil.isNullOrZero(base.getId())) { + // 随身办 if (LoginTypeEnum.SSB.getType().equals(source)) { WDUserInfo userInfo = SsbUtil.getUserInfo(token); log.error("wdUser = {}", userInfo); @@ -158,6 +161,12 @@ public class HphyPatientBaseController { base = hphyPatientBaseService.saveSSbInfo(current, userInfo, cardList); hpPatientCardService.save(base, cardList); } + // 香山中医医院公众号 + if (LoginTypeEnum.WOA_XSZY.getType().equals(source)) { + XSZYUserInfo xszyUserInfo = WoaUtil.getXszyUserInfo(token); + log.error("woaXszyUser = {}", xszyUserInfo); + base = hphyPatientBaseService.saveWoaXszyInfo(current, xszyUserInfo); + } } if (ObjectUtil.isNull(base) || NumberUtil.isNullOrZero(base.getId())) { diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/service/HphyPatientBaseService.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/service/HphyPatientBaseService.java index 4f0b9ba..f312b30 100644 --- a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/service/HphyPatientBaseService.java +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/service/HphyPatientBaseService.java @@ -2,6 +2,7 @@ package cn.sh.stc.sict.theme.hphy.service; import cn.sh.stc.sict.cloud.common.core.dto.WDUserCardInfo; import cn.sh.stc.sict.cloud.common.core.dto.WDUserInfo; +import cn.sh.stc.sict.cloud.common.core.dto.XSZYUserInfo; import cn.sh.stc.sict.cloud.upms.dto.CurrentUser; import com.baomidou.mybatisplus.extension.service.IService; import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase; @@ -21,6 +22,15 @@ public interface HphyPatientBaseService extends IService { HphyPatientBase saveSSbInfo(CurrentUser current, WDUserInfo userInfo, List cardList); + /** + * 保存香山中医医院公众号用户 + * + * @param current 当前用户 + * @param userInfo 公众号用户详情 + * @return XSZYUserInfo {@link XSZYUserInfo} + */ + HphyPatientBase saveWoaXszyInfo(CurrentUser current, XSZYUserInfo userInfo); + void savePatient(HphyPatientBase patient); HphyPatientBase getCurrentBase(); diff --git a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/service/impl/HphyPatientBaseServiceImpl.java b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/service/impl/HphyPatientBaseServiceImpl.java index 7973dd2..7560ba8 100644 --- a/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/service/impl/HphyPatientBaseServiceImpl.java +++ b/smart-health-modules/theme-schema/src/main/java/cn/sh/stc/sict/theme/hphy/service/impl/HphyPatientBaseServiceImpl.java @@ -6,6 +6,7 @@ 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.WDUserCardInfo; import cn.sh.stc.sict.cloud.common.core.dto.WDUserInfo; +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.security.util.SecurityUtils; import cn.sh.stc.sict.cloud.upms.dto.CurrentUser; @@ -69,6 +70,39 @@ public class HphyPatientBaseServiceImpl extends ServiceImpl standard_dept , hospital_code, hospital_name, dept_code, dept_name, rank_score - select dr.standard_dept standardDept, dr.hospital_code hospitalCode, dr.hospital_name hospitalName, @@ -22,10 +22,25 @@ 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 dr.standard_dept = #{deptName} + from hpgp_department_rank_1028 dr + join hp_dept_info_copy1 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) + + + + AND dr.hospital_code = #{hospitalCode} + AND dr.rank_score = 0 + + + AND dr.rank_score != 0 + + + + AND dr.standard_dept = #{deptName} + + order by dr.rank_score asc - limit #{size} + + limit #{size} + diff --git a/smart-health-modules/theme-schema/src/main/resources/mapper/hpgp/HpgpKsHotMapper.xml b/smart-health-modules/theme-schema/src/main/resources/mapper/hpgp/HpgpKsHotMapper.xml new file mode 100644 index 0000000..def6d99 --- /dev/null +++ b/smart-health-modules/theme-schema/src/main/resources/mapper/hpgp/HpgpKsHotMapper.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + gzh, standard_dept, hospital_code, hospital_name, one_dept_code, dept_code, dept_name, rank_score + -- 2.22.0