| | |
| | | import com.ruoyi.system.utils.util.RsaSimpleUtil; |
| | | import com.ruoyi.system.utils.wx.model.WeixinProperties; |
| | | import com.ruoyi.system.utils.wx.tools.WxAppletTools; |
| | | import com.ruoyi.system.utils.xiMaUtil.AesUtil; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | |
| | | return "success"; |
| | | } |
| | | |
| | | |
| | | |
| | | @PostMapping("/xiMaReportPush") |
| | | public String xiMaReportPush(JSONObject jsonObject) throws Exception { |
| | | TSysAiConfig sysAiConfig = sysAiConfigService.getById(1); |
| | | // 应用AES秘钥 |
| | | String clientKey = sysAiConfig.getClientKey(); |
| | | // 平台RSA公钥 |
| | | String clientIV = sysAiConfig.getClientIV(); |
| | | |
| | | String data = jsonObject.getString("data"); |
| | | // 解密 |
| | | String raw = AesUtil.decrypt(clientKey, clientIV , data); |
| | | log.info("H5舌面报告推送,解密后:{}",raw); |
| | | |
| | | return "success"; |
| | | } |
| | | |
| | | @PostMapping("/xiMaDoubleScreenReportPush") |
| | | public JSONObject xiMaDoubleScreenReportPush(JSONObject jsonObject) throws Exception { |
| | | log.info("双屏仪报告推送:{}",jsonObject); |
| | | |
| | | JSONObject response = new JSONObject(); |
| | | response.put("error_code",0); |
| | | return response; |
| | | } |
| | | |
| | | } |
| | |
| | | package com.ruoyi.web.controller.api; |
| | | |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.ruoyi.common.annotation.Log; |
| | | import com.ruoyi.common.basic.PageInfo; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.common.core.redis.RedisCache; |
| | | import com.ruoyi.common.enums.BusinessType; |
| | | import com.ruoyi.common.utils.StringUtils; |
| | | import com.ruoyi.framework.web.service.TokenService; |
| | | import com.ruoyi.system.model.TSysAppUser; |
| | |
| | | import com.ruoyi.system.service.TSysChronicDiseaseService; |
| | | import com.ruoyi.system.service.TSysInspectionService; |
| | | import com.ruoyi.system.service.TSysOrderService; |
| | | import com.ruoyi.system.utils.xiMaUtil.XimaAIUtil; |
| | | import com.ruoyi.system.vo.TSysAppUserVO; |
| | | import com.ruoyi.system.vo.TSysOrderVO; |
| | | import io.swagger.annotations.Api; |
| | |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.UUID; |
| | | |
| | | /** |
| | | * <p> |
| | |
| | | private final TSysChronicDiseaseService sysChronicDiseaseService; |
| | | private final TokenService tokenService; |
| | | private final RedisCache redisCache; |
| | | private final XimaAIUtil ximaAIUtil; |
| | | @Autowired |
| | | public TSysAppUserController(TSysAppUserService sysAppUserService, TSysInspectionService sysInspectionService, TSysOrderService sysOrderService, TSysChronicDiseaseService sysChronicDiseaseService, TokenService tokenService, RedisCache redisCache) { |
| | | public TSysAppUserController(TSysAppUserService sysAppUserService, TSysInspectionService sysInspectionService, TSysOrderService sysOrderService, TSysChronicDiseaseService sysChronicDiseaseService, TokenService tokenService, RedisCache redisCache, XimaAIUtil ximaAIUtil) { |
| | | this.sysAppUserService = sysAppUserService; |
| | | this.sysInspectionService = sysInspectionService; |
| | | this.sysOrderService = sysOrderService; |
| | | this.sysChronicDiseaseService = sysChronicDiseaseService; |
| | | this.tokenService = tokenService; |
| | | this.redisCache = redisCache; |
| | | this.ximaAIUtil = ximaAIUtil; |
| | | } |
| | | |
| | | /** |
| | |
| | | return R.ok(); |
| | | } |
| | | |
| | | /** |
| | | * 获取AI检测页面 |
| | | */ |
| | | @ApiOperation(value = "获取AI检测页面",notes = "设备类型 deviceType: android ios") |
| | | @GetMapping(value = "/getXiMaAiDetection") |
| | | public R<JSONObject> getXiMaAiDetection(@RequestParam String deviceType) { |
| | | String userId = tokenService.getLoginUserApplet().getUserId(); |
| | | TSysAppUser sysAppUser = sysAppUserService.getById(userId); |
| | | |
| | | if(StringUtils.isBlank(sysAppUser.getNickName()) || StringUtils.isBlank(sysAppUser.getPhone()) || Objects.isNull(sysAppUser.getSex()) ||Objects.isNull(sysAppUser.getUserHeight()) || Objects.isNull(sysAppUser.getUserWeight())){ |
| | | return R.fail("请先完善用户信息"); |
| | | } |
| | | |
| | | if(StringUtils.isBlank(sysAppUser.getIdentifierNumber())){ |
| | | sysAppUser.setIdentifierNumber(UUID.randomUUID().toString().replace("-", "")); |
| | | sysAppUserService.updateById(sysAppUser); |
| | | } |
| | | JSONObject authorizationH5 = ximaAIUtil.getAuthorizationH5(sysAppUser.getIdentifierNumber(), sysAppUser.getNickName(), sysAppUser.getPhone(), sysAppUser.getSex() == 1 ? "0" : "1", sysAppUser.getUserHeight(), sysAppUser.getUserWeight(), deviceType); |
| | | return R.ok(authorizationH5); |
| | | } |
| | | |
| | | } |
| | | |
| | |
| | | @TableField("loginPassword") |
| | | private String loginPassword; |
| | | |
| | | @ApiModelProperty(value = "喜马客户端id") |
| | | @TableField("clientId") |
| | | private String clientId; |
| | | |
| | | @ApiModelProperty(value = "喜马客户端密钥") |
| | | @TableField("clientSecret") |
| | | private String clientSecret; |
| | | |
| | | @ApiModelProperty(value = "喜马key") |
| | | @TableField("clientKey") |
| | | private String clientKey; |
| | | |
| | | @ApiModelProperty(value = "喜马IV") |
| | | @TableField("clientIV") |
| | | private String clientIV; |
| | | |
| | | } |
| | |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import java.io.Serializable; |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | |
| | |
| | | @TableField("sex") |
| | | private Integer sex; |
| | | |
| | | @ApiModelProperty(value = "身高cm") |
| | | @TableField("user_height") |
| | | private Integer userHeight; |
| | | |
| | | @ApiModelProperty(value = "体重kg") |
| | | @TableField("user_weight") |
| | | private Integer userWeight; |
| | | |
| | | @ApiModelProperty(value = "微信openid") |
| | | @TableField("open_id") |
| | | private String openId; |
| | | |
| | | @ApiModelProperty(value = "用户AI唯一标识") |
| | | @TableField("identifier_number") |
| | | private String identifierNumber; |
| | | |
| | | @ApiModelProperty(value = "公众号openId") |
| | | @TableField("office_open_id") |
| | | private String officeOpenId; |
| | |
| | | try { |
| | | return registRequest(request); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | log.error("<<<<<<<<<<<<<<<请求失败:{}", e.getMessage()); |
| | | throw new ServiceException("<<<<<<<<<<<http请求失败<<<<<<<<<<<<<<"+e.getMessage()); |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | package com.ruoyi.system.utils.xiMaUtil; |
| | | |
| | | import java.security.Security; |
| | | |
| | | import javax.crypto.Cipher; |
| | | import javax.crypto.spec.IvParameterSpec; |
| | | import javax.crypto.spec.SecretKeySpec; |
| | | |
| | | import org.bouncycastle.jce.provider.BouncyCastleProvider; |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * |
| | | * 加密方式:AES CBC模式 |
| | | * Key:ciicciicciicciic |
| | | * IV:ciic2022ciic2022 |
| | | * 例: |
| | | * 加密前:1234567890 |
| | | * 加密后:10ed567b9d42a385926d6166f97008ce |
| | | * |
| | | * 测试地址参考:http://tool.chacuo.net/cryptaes/ |
| | | * AES加密模式:CBC 填充:pkcs7padding 数据块:128位 密码:ciicciicciicciic 偏移量:ciic2022ciic2022 输出:hex 字符集:utf8编码(unicode编码) |
| | | * |
| | | */ |
| | | public class AesUtil { |
| | | |
| | | static { |
| | | Security.addProvider(new BouncyCastleProvider()); |
| | | } |
| | | |
| | | public static void main(String[] args) { |
| | | try { |
| | | //根据指定字符串生成秘钥 |
| | | /*KeyGenerator kg = KeyGenerator.getInstance("AES"); |
| | | kg.init(128,new SecureRandom("ceshi".getBytes())); |
| | | SecretKey sk = kg.generateKey(); |
| | | String keyStr = Base64.getEncoder().encodeToString(sk.getEncoded()); |
| | | byte[] iv = Base64.getDecoder().decode(keyStr); |
| | | byte[] key = Base64.getDecoder().decode(keyStr); */ |
| | | |
| | | String key = "ciicciicciicciic"; |
| | | String iv = "ciic2022ciic2022"; |
| | | String content = "1234567890"; |
| | | String encrypted = encrypt(key, iv, content); |
| | | System.out.println("加密后: " + encrypted); |
| | | |
| | | String raw = decrypt(key, iv , encrypted); |
| | | System.out.println("解密后: " + raw); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | public static String encrypt(String key, String iv, String content) { |
| | | try { |
| | | SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES"); |
| | | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");//"算法/模式/补码方式" |
| | | IvParameterSpec ips = new IvParameterSpec(iv.getBytes()); |
| | | cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ips); |
| | | return Hex.byteToHex(cipher.doFinal(content.getBytes())); |
| | | } catch (Exception e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | |
| | | public static String decrypt(String key,String iv, String content) { |
| | | |
| | | try { |
| | | SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES"); |
| | | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); |
| | | IvParameterSpec ips = new IvParameterSpec(iv.getBytes()); |
| | | cipher.init(Cipher.DECRYPT_MODE, skeySpec, ips); |
| | | return new String(cipher.doFinal(Hex.hexToByte(content)) ); |
| | | } catch (Exception e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | } |
| New file |
| | |
| | | package com.ruoyi.system.utils.xiMaUtil; |
| | | |
| | | public class Hex { |
| | | |
| | | |
| | | public static String byteToHex(byte[] bytes){ |
| | | String strHex = ""; |
| | | StringBuilder sb = new StringBuilder(""); |
| | | for (int n = 0; n < bytes.length; n++) { |
| | | strHex = Integer.toHexString(bytes[n] & 0xFF); |
| | | sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每个字节由两个字符表示,位数不够,高位补0 |
| | | } |
| | | return sb.toString().trim(); |
| | | } |
| | | |
| | | public static byte[] hexToByte(String hex){ |
| | | int m = 0, n = 0; |
| | | int byteLen = hex.length() / 2; // 每两个字符描述一个字节 |
| | | byte[] ret = new byte[byteLen]; |
| | | for (int i = 0; i < byteLen; i++) { |
| | | m = i * 2 + 1; |
| | | n = m + 1; |
| | | int intVal = Integer.decode("0x" + hex.substring(i * 2, m) + hex.substring(m, n)); |
| | | ret[i] = Byte.valueOf((byte)intVal); |
| | | } |
| | | return ret; |
| | | } |
| | | |
| | | |
| | | |
| | | } |
| New file |
| | |
| | | package com.ruoyi.system.utils.xiMaUtil; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.ruoyi.common.core.exception.ServiceException; |
| | | import com.ruoyi.system.model.TSysAiConfig; |
| | | import com.ruoyi.system.service.TSysAiConfigService; |
| | | import com.ruoyi.system.utils.util.HttpClientUtils; |
| | | import com.ruoyi.system.utils.util.JsonUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | @Slf4j |
| | | @Component |
| | | public class XimaAIUtil { |
| | | |
| | | @Autowired |
| | | private TSysAiConfigService sysAiConfigService; |
| | | |
| | | /** |
| | | * 获取舌面授权H5页面链接接口 |
| | | */ |
| | | public static final String AUTHORIZATION_H5_URL_TEST = "http://61.169.68.85:6008/open/web/auth/tongue_face"; |
| | | public static final String AUTHORIZATION_H5_URL_PROD = "http://rest.ximalife.com:6008/open/web/auth/tongue_face"; |
| | | |
| | | /** |
| | | * 获取舌面授权H5页面链接接口 |
| | | * @param out_user_id 外部用户唯一标志 |
| | | * @param nickname 用户昵称,也可用“真实姓名” |
| | | * @param phone 手机号码 |
| | | * @param sex 性别(0 男 1 女) |
| | | * @param height 身高(cm) |
| | | * @param weight 体重(kg) |
| | | * @param device_type 设备类型:android ios |
| | | * @return |
| | | */ |
| | | public JSONObject getAuthorizationH5(String out_user_id,String nickname,String phone,String sex,Integer height,Integer weight,String device_type) { |
| | | TSysAiConfig sysAiConfig = sysAiConfigService.getById(1); |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("client_id", sysAiConfig.getClientId()); |
| | | jsonObject.put("client_secret", sysAiConfig.getClientSecret()); |
| | | jsonObject.put("out_user_id", out_user_id); |
| | | jsonObject.put("nickname", nickname); |
| | | jsonObject.put("phone", phone); |
| | | jsonObject.put("sex", sex); |
| | | jsonObject.put("height", height); |
| | | jsonObject.put("weight", weight); |
| | | jsonObject.put("device_type", device_type); |
| | | |
| | | String result = HttpClientUtils.postFrom(AUTHORIZATION_H5_URL_TEST, JsonUtils.toJsonString(jsonObject)); |
| | | log.info("获取舌面授权H5页面链接接口:{}", result); |
| | | JSONObject object = JSONObject.parseObject(result); |
| | | if(!object.getBoolean("ok")){ |
| | | JSONObject error = object.getJSONObject("error"); |
| | | throw new ServiceException(error.getString("err_msg")); |
| | | } |
| | | JSONObject data = object.getJSONObject("data"); |
| | | String accessToken = data.getString("access_token"); |
| | | Integer expiresIn = data.getInteger("expires_in"); |
| | | String requestUrl = data.getString("request_url"); |
| | | JSONObject response = new JSONObject(); |
| | | response.put("access_token", accessToken); |
| | | response.put("expires_in", expiresIn); |
| | | response.put("request_url", requestUrl); |
| | | log.info("获取舌面授权H5页面返回信息:{}", response); |
| | | return response; |
| | | } |
| | | |
| | | public static void main(String[] args) { |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("client_id", "xima_0003"); |
| | | jsonObject.put("client_secret", "7987dfafafaf8798dfafadfadff"); |
| | | jsonObject.put("out_user_id", "5f68e822-72bb-42cd-ad11-4c2102942dd2"); |
| | | jsonObject.put("nickname", "周帅"); |
| | | jsonObject.put("phone", "19983174515"); |
| | | jsonObject.put("sex", "0"); |
| | | jsonObject.put("height", 170); |
| | | jsonObject.put("weight", 65); |
| | | jsonObject.put("device_type", "android"); |
| | | |
| | | String result = HttpClientUtils.postFrom(AUTHORIZATION_H5_URL_TEST, JsonUtils.toJsonString(jsonObject)); |
| | | log.info("获取舌面授权H5页面链接接口:{}", result); |
| | | JSONObject object = JSONObject.parseObject(result); |
| | | if(!object.getBoolean("ok")){ |
| | | JSONObject error = object.getJSONObject("error"); |
| | | throw new ServiceException(error.getString("err_msg")); |
| | | } |
| | | JSONObject data = object.getJSONObject("data"); |
| | | String accessToken = data.getString("access_token"); |
| | | Integer expiresIn = data.getInteger("expires_in"); |
| | | String requestUrl = data.getString("request_url"); |
| | | JSONObject response = new JSONObject(); |
| | | response.put("access_token", accessToken); |
| | | response.put("expires_in", expiresIn); |
| | | response.put("request_url", requestUrl); |
| | | log.info("获取舌面授权H5页面返回信息:{}", response); |
| | | } |
| | | |
| | | } |
| | |
| | | <result column="devRsaPublicKey" property="devRsaPublicKey" /> |
| | | <result column="rsaPublicKey" property="rsaPublicKey" /> |
| | | <result column="aesKey" property="aesKey" /> |
| | | <result column="devRsaPrivateKey" property="devRsaPrivateKey" /> |
| | | <result column="loginName" property="loginName" /> |
| | | <result column="loginPassword" property="loginPassword" /> |
| | | <result column="clientId" property="clientId" /> |
| | | <result column="clientSecret" property="clientSecret" /> |
| | | <result column="clientKey" property="clientKey" /> |
| | | <result column="clientIV" property="clientIV" /> |
| | | </resultMap> |
| | | |
| | | <!-- 通用查询结果列 --> |
| | | <sql id="Base_Column_List"> |
| | | id, devId, devSecret, devRsaPublicKey, rsaPublicKey,aesKey |
| | | id, devId, devSecret, devRsaPublicKey, rsaPublicKey,aesKey, |
| | | devRsaPrivateKey, loginName, loginPassword, clientId, clientSecret, clientKey, clientIV |
| | | </sql> |
| | | |
| | | </mapper> |
| | |
| | | <result column="phone" property="phone" /> |
| | | <result column="birth_time" property="birthTime" /> |
| | | <result column="sex" property="sex" /> |
| | | <result column="user_height" property="userHeight" /> |
| | | <result column="user_weight" property="userWeight" /> |
| | | <result column="identifier_number" property="identifierNumber" /> |
| | | <result column="open_id" property="openId" /> |
| | | <result column="office_open_id" property="officeOpenId" /> |
| | | <result column="chronic_disease_id" property="chronicDiseaseId" /> |
| | |
| | | |
| | | <!-- 通用查询结果列 --> |
| | | <sql id="Base_Column_List"> |
| | | id, nick_name,avatar, phone, birth_time, sex, open_id,chronic_disease_id,status,last_reminder_time, |
| | | id, nick_name,avatar, phone, birth_time, sex,user_height, user_weight, identifier_number, |
| | | open_id,chronic_disease_id,status,last_reminder_time, |
| | | office_open_id,clinic_id, create_time, update_time, create_by, update_by, disabled |
| | | </sql> |
| | | <select id="pageList" resultType="com.ruoyi.system.vo.TSysAppUserVO"> |
| | | select tsau.id, tsau.nick_name,tsau.avatar, tsau.phone, tsau.birth_time, tsau.sex, tsau.open_id,tsau.office_open_id, |
| | | tsau.chronic_disease_id,tsau.status,tsau.last_reminder_time,tsau.clinic_id, tsau.create_time, |
| | | tsau.update_time, tsau.create_by,tsau.update_by, tsau.disabled, tsi.lastInspectionTime |
| | | select tsau.id, tsau.nick_name,tsau.avatar, tsau.phone, tsau.birth_time, tsau.sex, tsau.user_height, |
| | | tsau.user_weight, tsau.identifier_number,tsau.open_id,tsau.office_open_id, |
| | | tsau.chronic_disease_id,tsau.status,tsau.last_reminder_time,tsau.clinic_id, tsau.create_time, |
| | | tsau.update_time, tsau.create_by,tsau.update_by, tsau.disabled, tsi.lastInspectionTime |
| | | from t_sys_app_user tsau |
| | | left join (select app_user_id, max(check_time) as lastInspectionTime from t_sys_inspection group by app_user_id) tsi on tsi.app_user_id = tsau.id |
| | | <where> |
| | |
| | | ORDER BY tsau.create_time DESC |
| | | </select> |
| | | <select id="pageChronicDiseaseUserList" resultType="com.ruoyi.system.vo.TSysAppUserVO"> |
| | | select tsau.id, tsau.nick_name,tsau.avatar, tsau.phone, tsau.birth_time, tsau.sex, tsau.open_id,tsau.office_open_id, |
| | | select tsau.id, tsau.nick_name,tsau.avatar, tsau.phone, tsau.birth_time, tsau.sex, tsau.user_height, |
| | | tsau.user_weight, tsau.identifier_number,tsau.open_id,tsau.office_open_id, |
| | | tsau.chronic_disease_id,tsau.status,tsau.last_reminder_time,tsau.clinic_id, tsau.create_time, |
| | | tsau.update_time, tsau.create_by,tsau.update_by, tsau.disabled |
| | | from t_sys_app_user tsau |
| | |
| | | ORDER BY tsau.create_time DESC |
| | | </select> |
| | | <select id="exportList" resultType="com.ruoyi.system.export.TSysAppUserListExport"> |
| | | select tsau.id, tsau.nick_name,tsau.avatar, tsau.phone, tsau.birth_time, tsau.sex, tsau.open_id,tsau.office_open_id, |
| | | select tsau.id, tsau.nick_name,tsau.avatar, tsau.phone, tsau.birth_time, tsau.sex, tsau.user_height, |
| | | tsau.user_weight, tsau.identifier_number,tsau.open_id,tsau.office_open_id, |
| | | tsau.chronic_disease_id,tsau.status,tsau.last_reminder_time,tsau.clinic_id, tsau.create_time, |
| | | tsau.update_time, tsau.create_by,tsau.update_by, tsau.disabled |
| | | from t_sys_app_user tsau |
| | |
| | | ORDER BY tsau.create_time DESC |
| | | </select> |
| | | <select id="exportListClinic" resultType="com.ruoyi.system.export.TSysAppUserClinicExport"> |
| | | select tsau.id, tsau.nick_name,tsau.avatar, tsau.phone, tsau.birth_time, tsau.sex, tsau.open_id,tsau.office_open_id, |
| | | select tsau.id, tsau.nick_name,tsau.avatar, tsau.phone, tsau.birth_time, tsau.sex, tsau.user_height, |
| | | tsau.user_weight, tsau.identifier_number,tsau.open_id,tsau.office_open_id, |
| | | tsau.chronic_disease_id,tsau.status,tsau.last_reminder_time,tsau.clinic_id, tsau.create_time, |
| | | tsau.update_time, tsau.create_by,tsau.update_by, tsau.disabled |
| | | from t_sys_app_user tsau |
| | |
| | | ORDER BY tsau.create_time DESC |
| | | </select> |
| | | <select id="exportListAppUser" resultType="com.ruoyi.system.export.TSysAppUserExport"> |
| | | select tsau.id, tsau.nick_name,tsau.avatar, tsau.phone, tsau.birth_time, tsau.sex, tsau.open_id,tsau.office_open_id, |
| | | select tsau.id, tsau.nick_name,tsau.avatar, tsau.phone, tsau.birth_time, tsau.sex, tsau.user_height, |
| | | tsau.user_weight, tsau.identifier_number,tsau.open_id,tsau.office_open_id, |
| | | tsau.chronic_disease_id,tsau.status,tsau.last_reminder_time,tsau.clinic_id, tsau.create_time, |
| | | tsau.update_time, tsau.create_by,tsau.update_by, tsau.disabled, tsi.lastInspectionTime |
| | | from t_sys_app_user tsau |