Quellcode durchsuchen

Merge remote-tracking branch 'origin/ScrmStores' into ScrmStores

yjwang vor 5 Tagen
Ursprung
Commit
880bd8b038
23 geänderte Dateien mit 1387 neuen und 5 gelöschten Zeilen
  1. 214 0
      fs-service/src/main/java/com/fs/common/AesGcm256Utils.java
  2. 15 0
      fs-service/src/main/java/com/fs/lotus/config/LotusSignatureConfigurer.java
  3. 23 0
      fs-service/src/main/java/com/fs/lotus/config/LotusSignatureProperties.java
  4. 70 0
      fs-service/src/main/java/com/fs/lotus/domain/LotusActivationUser.java
  5. 21 0
      fs-service/src/main/java/com/fs/lotus/domain/LotusClaimRecord.java
  6. 119 0
      fs-service/src/main/java/com/fs/lotus/domain/LotusEntinementActivation.java
  7. 45 0
      fs-service/src/main/java/com/fs/lotus/domain/LotusInquiryOrderMsg.java
  8. 72 0
      fs-service/src/main/java/com/fs/lotus/domain/LotusPaymentConfig.java
  9. 18 0
      fs-service/src/main/java/com/fs/lotus/mapper/LotusActivationUserMapper.java
  10. 38 0
      fs-service/src/main/java/com/fs/lotus/mapper/LotusEntinementActivationMapper.java
  11. 88 0
      fs-service/src/main/java/com/fs/lotus/mapper/LotusHealthMapper.java
  12. 22 0
      fs-service/src/main/java/com/fs/lotus/mapper/LotusInquiryOrderMsgMapper.java
  13. 42 0
      fs-service/src/main/java/com/fs/lotus/param/ActivateInfoDTO.java
  14. 18 0
      fs-service/src/main/java/com/fs/lotus/param/ActivateUserDTO.java
  15. 31 0
      fs-service/src/main/java/com/fs/lotus/param/InitUserDto.java
  16. 29 0
      fs-service/src/main/java/com/fs/lotus/param/LoginDto.java
  17. 142 0
      fs-service/src/main/java/com/fs/lotus/param/LotusClaimParam.java
  18. 27 0
      fs-service/src/main/java/com/fs/lotus/param/LotusHealthPayParam.java
  19. 29 0
      fs-service/src/main/java/com/fs/lotus/param/OpenApiRequest.java
  20. 95 0
      fs-service/src/main/java/com/fs/lotus/utils/LotusSignUtil.java
  21. 189 0
      fs-service/src/main/java/com/fs/lotus/utils/SignatureUtil.java
  22. 34 5
      fs-user-app/src/main/java/com/fs/app/controller/AppLoginController.java
  23. 6 0
      fs-user-app/src/main/java/com/fs/app/param/FsUserLoginParam.java

+ 214 - 0
fs-service/src/main/java/com/fs/common/AesGcm256Utils.java

@@ -0,0 +1,214 @@
+package com.fs.common;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
+import java.util.Base64;
+
+/**
+ * AES-256-GCM 加解密工具类
+ * <p>
+ * GCM(Galois/Counter Mode)同时提供机密性和完整性保护,自带认证标签(Auth Tag),
+ * 相比 CBC/ECB 模式可同时防篡改和防重放,是当前推荐的对称加密模式。
+ * </p>
+ * <p>
+ * 密文格式(Base64):IV(12字节) + 密文 + AuthTag(16字节)
+ * </p>
+ *
+ * <h3>使用示例</h3>
+ * <pre>{@code
+ * // 1. 生成密钥(一次性,妥善保存)
+ * String key = AesGcm256Utils.generateKey();
+ *
+ * // 2. 加密
+ * String cipher = AesGcm256Utils.encrypt("敏感数据", key);
+ *
+ * // 3. 解密
+ * String plain = AesGcm256Utils.decrypt(cipher, key);
+ *
+ * // 4. 带 AAD(附加认证数据)加解密——AAD 不加密,但参与认证,防止密文被挪用
+ * String cipher2 = AesGcm256Utils.encrypt("敏感数据", key, "orderId=123");
+ * String plain2 = AesGcm256Utils.decrypt(cipher2, key, "orderId=123");
+ * }</pre>
+ *
+ * @author fs
+ */
+public class AesGcm256Utils {
+
+    /** AES 密钥位数:256 位(32 字节) */
+    private static final int KEY_BIT_LENGTH = 256;
+
+    /** GCM 模式 IV(Nonce)长度:12 字节(96 位),GCM 规范推荐值 */
+    private static final int IV_BYTE_LENGTH = 12;
+
+    /** GCM 认证标签长度:128 位(16 字节),GCM 规范推荐的最大值 */
+    private static final int AUTH_TAG_BIT_LENGTH = 128;
+
+    /** 加密算法完整标识:AES/GCM/NoPadding */
+    private static final String TRANSFORMATION = "AES/GCM/NoPadding";
+
+    /** 密钥算法:AES */
+    private static final String KEY_ALGORITHM = "AES";
+
+    /** 安全随机数生成器(线程安全) */
+    private static final SecureRandom SECURE_RANDOM = new SecureRandom();
+
+    private AesGcm256Utils() {
+    }
+
+    /**
+     * 生成 256 位 AES 密钥,返回 Base64 编码字符串
+     * <p>生成后请妥善保存,加解密需使用同一密钥。</p>
+     *
+     * @return Base64 编码的密钥
+     */
+    public static String generateKey() {
+        try {
+            KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
+            keyGenerator.init(KEY_BIT_LENGTH, SECURE_RANDOM);
+            SecretKey secretKey = keyGenerator.generateKey();
+            return Base64.getEncoder().encodeToString(secretKey.getEncoded());
+        } catch (Exception e) {
+            throw new RuntimeException("生成 AES-256 密钥失败", e);
+        }
+    }
+
+    /**
+     * 从 Base64 编码字符串加载密钥
+     *
+     * @param keyBase64 Base64 编码的密钥
+     * @return SecretKey 对象
+     */
+    public static SecretKey loadKey(String keyBase64) {
+        byte[] keyBytes = Base64.getDecoder().decode(keyBase64);
+        if (keyBytes.length != 32) {
+            throw new IllegalArgumentException("AES-256 密钥必须为 32 字节,当前长度:" + keyBytes.length);
+        }
+        return new SecretKeySpec(keyBytes, KEY_ALGORITHM);
+    }
+
+    /**
+     * 加密(无 AAD)
+     *
+     * @param plainText 明文
+     * @param keyBase64 Base64 编码的密钥
+     * @return Base64 编码的密文(格式:IV + 密文 + AuthTag)
+     */
+    public static String encrypt(String plainText, String keyBase64) {
+        return encrypt(plainText, keyBase64, null);
+    }
+
+    /**
+     * 加密(带 AAD 附加认证数据)
+     * <p>AAD 不被加密,但会参与认证标签计算,解密时需传入相同 AAD 才能通过认证。</p>
+     *
+     * @param plainText 明文
+     * @param keyBase64 Base64 编码的密钥
+     * @param aad 附加认证数据(可为 null)
+     * @return Base64 编码的密文(格式:IV + 密文 + AuthTag)
+     */
+    public static String encrypt(String plainText, String keyBase64, String aad) {
+        try {
+            byte[] plainBytes = plainText.getBytes(StandardCharsets.UTF_8);
+            byte[] ivBytes = new byte[IV_BYTE_LENGTH];
+            SECURE_RANDOM.nextBytes(ivBytes);
+
+            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
+            GCMParameterSpec parameterSpec = new GCMParameterSpec(AUTH_TAG_BIT_LENGTH, ivBytes);
+            cipher.init(Cipher.ENCRYPT_MODE, loadKey(keyBase64), parameterSpec);
+
+            if (aad != null && !aad.isEmpty()) {
+                cipher.updateAAD(aad.getBytes(StandardCharsets.UTF_8));
+            }
+
+            byte[] cipherTextWithTag = cipher.doFinal(plainBytes);
+
+            // 拼接:IV(12) + 密文+AuthTag
+            byte[] output = new byte[IV_BYTE_LENGTH + cipherTextWithTag.length];
+            System.arraycopy(ivBytes, 0, output, 0, IV_BYTE_LENGTH);
+            System.arraycopy(cipherTextWithTag, 0, output, IV_BYTE_LENGTH, cipherTextWithTag.length);
+
+            return Base64.getEncoder().encodeToString(output);
+        } catch (Exception e) {
+            throw new RuntimeException("AES-256-GCM 加密失败", e);
+        }
+    }
+
+    /**
+     * 解密(无 AAD)
+     *
+     * @param cipherTextBase64 Base64 编码的密文(格式:IV + 密文 + AuthTag)
+     * @param keyBase64 Base64 编码的密钥
+     * @return 明文
+     */
+    public static String decrypt(String cipherTextBase64, String keyBase64) {
+        return decrypt(cipherTextBase64, keyBase64, null);
+    }
+
+    /**
+     * 解密(带 AAD 附加认证数据)
+     *
+     * @param cipherTextBase64 Base64 编码的密文(格式:IV + 密文 + AuthTag)
+     * @param keyBase64 Base64 编码的密钥
+     * @param aad 附加认证数据(需与加密时一致,可为 null)
+     * @return 明文
+     * @throws RuntimeException 认证失败(密钥错误、密文被篡改、AAD 不一致)时抛出
+     */
+    public static String decrypt(String cipherTextBase64, String keyBase64, String aad) {
+        try {
+            byte[] input = Base64.getDecoder().decode(cipherTextBase64);
+            if (input.length < IV_BYTE_LENGTH) {
+                throw new IllegalArgumentException("密文长度非法,少于 IV 长度");
+            }
+
+            byte[] ivBytes = new byte[IV_BYTE_LENGTH];
+            byte[] cipherTextWithTag = new byte[input.length - IV_BYTE_LENGTH];
+            System.arraycopy(input, 0, ivBytes, 0, IV_BYTE_LENGTH);
+            System.arraycopy(input, IV_BYTE_LENGTH, cipherTextWithTag, 0, cipherTextWithTag.length);
+
+            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
+            GCMParameterSpec parameterSpec = new GCMParameterSpec(AUTH_TAG_BIT_LENGTH, ivBytes);
+            cipher.init(Cipher.DECRYPT_MODE, loadKey(keyBase64), parameterSpec);
+
+            if (aad != null && !aad.isEmpty()) {
+                cipher.updateAAD(aad.getBytes(StandardCharsets.UTF_8));
+            }
+
+            byte[] plainBytes = cipher.doFinal(cipherTextWithTag);
+            return new String(plainBytes, StandardCharsets.UTF_8);
+        } catch (Exception e) {
+            throw new RuntimeException("AES-256-GCM 解密失败(密钥错误、密文被篡改或 AAD 不一致)", e);
+        }
+    }
+
+    /**
+     * 自测主方法
+     */
+    public static void main(String[] args) {
+        String key = generateKey();
+        System.out.println("生成的密钥:" + key);
+
+        String plain = "医健宝敏感数据-test-123456";
+        String cipher = encrypt(plain, key);
+        System.out.println("加密结果:" + cipher);
+        System.out.println("解密结果:" + decrypt(cipher, key));
+
+        // 带 AAD 测试
+        String aad = "orderId=888";
+        String cipher2 = encrypt(plain, key, aad);
+        System.out.println("带 AAD 加密结果:" + cipher2);
+        System.out.println("带 AAD 解密结果:" + decrypt(cipher2, key, aad));
+
+        // AAD 不一致应抛异常
+        try {
+            decrypt(cipher2, key, "orderId=999");
+            System.out.println("【错误】AAD 不一致却解密成功!");
+        } catch (RuntimeException e) {
+            System.out.println("【正确】AAD 不一致解密失败:" + e.getMessage());
+        }
+    }
+}

+ 15 - 0
fs-service/src/main/java/com/fs/lotus/config/LotusSignatureConfigurer.java

@@ -0,0 +1,15 @@
+package com.fs.lotus.config;
+
+import com.fs.lotus.utils.SignatureUtil;
+import org.springframework.stereotype.Component;
+
+/**
+ * Inject lotus.signature into SignatureUtil on startup.
+ */
+@Component
+public class LotusSignatureConfigurer {
+
+    public LotusSignatureConfigurer(LotusSignatureProperties properties) {
+        SignatureUtil.init(properties);
+    }
+}

+ 23 - 0
fs-service/src/main/java/com/fs/lotus/config/LotusSignatureProperties.java

@@ -0,0 +1,23 @@
+package com.fs.lotus.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * Lotus open API signature config (override per env; keep secrets out of hardcode).
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "lotus.signature")
+public class LotusSignatureProperties {
+
+    /** app id */
+    private String appId;
+
+    /** app secret */
+    private String appSecret;
+
+    /** request expire seconds */
+    private long expireSeconds;
+}

+ 70 - 0
fs-service/src/main/java/com/fs/lotus/domain/LotusActivationUser.java

@@ -0,0 +1,70 @@
+package com.fs.lotus.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+* <p>
+* lotus_activation_user 实体类
+* </p>
+*
+* @author Administrator
+* @since 2026-06-18 16:33:15
+*/
+@Getter
+@Setter
+@TableName("lotus_activation_user")
+public class LotusActivationUser implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键ID
+    */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+    * 权益激活主表ID (外键关联)
+    */
+    private Long activationId;
+
+    private Long userId;
+
+    /**
+    * 证件号码
+    */
+    private String certNo;
+
+    /**
+    * 证件类型  0: 居民身份证;1: 户口簿;2: 港澳居民来往内地通行证;3: 台湾居民来往大陆通行证;4: 外国人永久居留身份证;5: 中国人民解放军军官证;6: 中国人民解放军士兵证;7: 临时居民身份证;8: 普通护照;9: 中国人民武装警察部队警官证;10: 中国人民武装警察部队士兵证;11: 大陆居民来往台湾通行证;12: 前往港澳通行证;13: 来往港澳通行证;14: 人民警察证;15: 其他
+    */
+    private String certType;
+
+    /**
+    * 创建时间
+    */
+    private LocalDateTime createTime;
+
+    /**
+    * 状态: 0-正常/激活成功, 1-已注销
+    */
+    private Integer status;
+
+    /**
+    * 更新时间
+    */
+    private LocalDateTime updateTime;
+
+    /**
+    * 激活使用人姓名
+    */
+    private String userName;
+
+
+}

+ 21 - 0
fs-service/src/main/java/com/fs/lotus/domain/LotusClaimRecord.java

@@ -0,0 +1,21 @@
+package com.fs.lotus.domain;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class LotusClaimRecord {
+    private Long id;
+    private Long orderId;
+    private String thirdPartyReceiveId;
+    private String activationCode;
+    private String orderNo;
+    private Integer claimStatus;
+    private Integer errorCode;
+    private String errorMsg;
+    private String requestData;
+    private String responseData;
+    private LocalDateTime createTime;
+    private LocalDateTime updateTime;
+}

+ 119 - 0
fs-service/src/main/java/com/fs/lotus/domain/LotusEntinementActivation.java

@@ -0,0 +1,119 @@
+package com.fs.lotus.domain;
+
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+* <p>
+* lotus_entinement_activation 实体类
+* </p>
+*
+* @author Administrator
+* @since 2026-06-18 16:28:41
+*/
+@Getter
+@Setter
+@TableName("lotus_entinement_activation")
+public class LotusEntinementActivation implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键ID
+    */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+    * 激活唯一编码(业务主键)
+    */
+    private String activateBizCode;
+
+    /**
+    * 激活唯一码
+    */
+    private String activationCode;
+
+    /**
+    * 创建时间
+    */
+    private LocalDateTime createTime;
+
+    /**
+    * 结束时间
+    */
+    private LocalDateTime endTime;
+
+    /**
+    * 请求流水号
+    */
+    private String requestSerialNo;
+
+    /**
+    * 开始时间
+    */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startTime;
+
+    /**
+    * 状态: 0-正常/激活成功, 1-已注销/整单回滚
+    */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Integer status;
+
+    /**
+    * 三方产品ID
+    */
+    private String thirdPartyProductId;
+
+    /**
+    * 更新时间
+    */
+    private LocalDateTime updateTime;
+
+    /**
+    * 用户ID
+    */
+    private Long userId;
+
+    /**
+     * 总保险金额,单位:分
+     */
+    private Long totalInsuredAmount;
+
+    /**
+     * 每月剩余赔付次数
+     */
+    private Integer remainMonthClaimTimes;
+
+    /**
+     * 全年剩余赔付次数
+     */
+    private Integer remainYearClaimTimes;
+
+    /**
+     * 单次赔付上限,单位:分
+     */
+    private Long singleMaxLimit;
+
+    /**
+     * 赔付标准
+     */
+    private String claimCondition;
+
+    /**
+     * 剩余额度
+     */
+    private Long remainQuota;
+
+    private String lastResetMonth;
+
+
+}

+ 45 - 0
fs-service/src/main/java/com/fs/lotus/domain/LotusInquiryOrderMsg.java

@@ -0,0 +1,45 @@
+package com.fs.lotus.domain;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * lotus保单咨询消息对象 lotus_inquiry_order_msg
+ */
+@Data
+public class LotusInquiryOrderMsg {
+
+    /** ID */
+    private Long msgId;
+
+    /** 消息类型 1会员消息 2医生消息 */
+    private String msgType;
+
+    /** 会员ID */
+    private String fromAccount;
+
+    /** 医生ID */
+    private String toAccount;
+
+    /** 消息内容 */
+    private String content;
+
+    /** 创建时间 */
+    private Date createTime;
+
+    /** 订单ID */
+    private Long orderId;
+
+    /** 消息key */
+    private String msgKey;
+
+    /** 1 文本 2语音 3图像 4 视频 */
+    private Integer msgContentType;
+
+    /** 销售ID */
+    private String companyUserAccount;
+
+    /** app_customer_role_id */
+    private String appCustomerRoleAccount;
+}

+ 72 - 0
fs-service/src/main/java/com/fs/lotus/domain/LotusPaymentConfig.java

@@ -0,0 +1,72 @@
+package com.fs.lotus.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 保险公司支付配置表
+ * @author YourName
+ * @date 2026-07-07
+ */
+@Data
+public class LotusPaymentConfig implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * insurance_company主键
+     */
+    private Long insuranceId;
+
+    /**
+     * 支付类型:WX-微信
+     */
+    private String payType;
+
+    /**
+     * 小程序appid
+     */
+    private String appid;
+
+    /**
+     * 微信商户号
+     */
+    private String wxMerchantNo;
+
+    /**
+     * 微信Key
+     */
+    private String wxKey;
+
+    /**
+     * 回调地址
+     */
+    private String notifyUrl;
+
+    /**
+     * 证书
+     */
+    private String keyPath;
+
+    /**
+     * 状态,1启用,0禁用
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 18 - 0
fs-service/src/main/java/com/fs/lotus/mapper/LotusActivationUserMapper.java

@@ -0,0 +1,18 @@
+package com.fs.lotus.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.lotus.domain.LotusActivationUser;
+
+/**
+* <p>
+* lotus_activation_user Mapper 接口
+* </p>
+*
+* @author Administrator
+* @since 2026-06-18 17:04:58
+*/
+public interface LotusActivationUserMapper extends BaseMapper<LotusActivationUser> {
+
+
+}

+ 38 - 0
fs-service/src/main/java/com/fs/lotus/mapper/LotusEntinementActivationMapper.java

@@ -0,0 +1,38 @@
+package com.fs.lotus.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsPatient;
+import com.fs.lotus.domain.LotusEntinementActivation;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+* <p>
+* lotus_entinement_activation Mapper 接口
+* </p>
+*
+* @author Administrator
+* @since 2026-06-18 17:06:30
+*/
+@Mapper
+public interface LotusEntinementActivationMapper extends BaseMapper<LotusEntinementActivation> {
+    Map<String, Object> selectBythirdPartyProductId(String thirdPartyProductId);
+
+    List<FsPatient> selectPatientByCertNo(@Param("certNoList") List<String> certNoList);
+
+    LotusEntinementActivation selectActivation(Long userId);
+
+    /**
+     * 查询保险产品配置
+     */
+    Map<String, Object> selectInsuranceCoverage();
+
+    /**
+     * 批量重置月度剩余次数
+     */
+    int batchResetMonthlyClaimTimes(@Param("currentMonth") String currentMonth, @Param("maxMonthClaimTimes") int maxMonthClaimTimes);
+}

+ 88 - 0
fs-service/src/main/java/com/fs/lotus/mapper/LotusHealthMapper.java

@@ -0,0 +1,88 @@
+package com.fs.lotus.mapper;
+
+import com.fs.his.domain.FsInquiryOrder;
+import com.fs.his.domain.FsPatient;
+import com.fs.his.domain.FsStoreOrder;
+import com.fs.his.domain.FsUser;
+import com.fs.lotus.domain.LotusClaimRecord;
+import com.fs.lotus.domain.LotusEntinementActivation;
+import com.fs.lotus.domain.LotusPaymentConfig;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+@Mapper
+public interface LotusHealthMapper {
+    /**
+     * 根据诊断名称查询icd (精准)
+     * @param diagnosisName
+     * @return
+     */
+    String selectIcdBydiagnosisName(String diagnosisName);
+
+    /**
+     * 根据诊断名称查询icd (模糊)
+     * @param diagnosisName
+     * @return
+     */
+    String searchByDiagnosisName(String diagnosisName);
+
+    FsPatient selectUserByIdCard(@Param("idCard") String idCard, @Param("activateBizCode") String activateBizCode);
+
+    int updatePatient(FsPatient fsPatient);
+
+    int updateFsUser(FsUser fsUser);
+
+    List<FsPatient> getPatientList(long userId);
+
+    List<FsInquiryOrder> getInquiryOrder(long userId);
+
+    LotusPaymentConfig selectPayConfig();
+
+    LotusPaymentConfig selectPayConfigByMchId(@Param("mchId") String mchId);
+
+    int insertClaimRecord(LotusClaimRecord record);
+
+    String selectOpenid(Long userId);
+
+    Map<String, Object> selectInfo(Long orderId);
+
+    Map<String, Object> selectReport(String orderId);
+
+    Map<String, Object> selectInquiry(String orderId);
+
+    Map<String, Object> selectPrescribe(String prescribeId);
+
+    Map<String, Object> selectIcd(String inquiryResult);
+
+    List<Map<String, Object>> selectBillLog(Long orderId);
+
+    String selectIcdByName(String diagnose);
+
+    /**
+     * 查询lotus聊天记录
+     */
+    List<Map<String, Object>> selectLotusMsgList(@Param("orderId") Long orderId);
+
+    /**
+     * 查询医生姓名
+     */
+    String selectDoctorNameById(@Param("doctorId") String doctorId);
+
+    /**
+     * 查询用户昵称
+     */
+    String selectUserNickNameById(@Param("userId") String userId);
+
+    LotusEntinementActivation selectByUserId(String userId);
+
+    List<FsInquiryOrder> selectInquiryList();
+
+    List<FsStoreOrder> selectStoreOrderList(List<FsInquiryOrder> inquiryOrders);
+
+    String getPrescribe(Long prescribeId);
+
+    String getBill(Long orderId);
+}

+ 22 - 0
fs-service/src/main/java/com/fs/lotus/mapper/LotusInquiryOrderMsgMapper.java

@@ -0,0 +1,22 @@
+package com.fs.lotus.mapper;
+
+import com.fs.lotus.domain.LotusInquiryOrderMsg;
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * lotus保单咨询消息Mapper接口
+ */
+public interface LotusInquiryOrderMsgMapper {
+
+    /**
+     * 新增消息
+     */
+    int insertLotusInquiryOrderMsg(LotusInquiryOrderMsg msg);
+
+    /**
+     * 根据msgKey删除消息
+     */
+    @Delete("delete from lotus_inquiry_order_msg where msg_key = #{msgKey}")
+    void deleteByMsgKey(@Param("msgKey") String msgKey);
+}

+ 42 - 0
fs-service/src/main/java/com/fs/lotus/param/ActivateInfoDTO.java

@@ -0,0 +1,42 @@
+package com.fs.lotus.param;
+
+
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Data
+public class ActivateInfoDTO {
+
+//    @NotBlank(message = "三方产品ID不能为空")
+    private String thirdPartyProductId;
+
+    @NotBlank(message = "请求流水号不能为空")
+    private String requestSerialNo;
+
+//    @NotBlank(message = "开始时间不能为空")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startTime;
+
+//    @NotBlank(message = "结束时间不能为空")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime endTime;
+
+    @NotNull(message = "用户ID不能为空")
+    private Long userId;
+
+    @NotBlank(message = "激活唯一码不能为空")
+    private String activationCode;
+
+
+    private List<ActivateUserDTO> activateUser;
+    private List<ActivateUserDTO> cancelUser;
+}
+
+
+

+ 18 - 0
fs-service/src/main/java/com/fs/lotus/param/ActivateUserDTO.java

@@ -0,0 +1,18 @@
+package com.fs.lotus.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class ActivateUserDTO {
+    // 针对文档中的 useName 字段名,如果实际代码叫 userName 请自行替换
+    @NotBlank(message = "激活使用人姓名不能为空")
+    private String userName;
+
+    @NotBlank(message = "证件类型不能为空")
+    private String certType;
+
+    @NotBlank(message = "证件号码不能为空")
+    private String certNo;
+}

+ 31 - 0
fs-service/src/main/java/com/fs/lotus/param/InitUserDto.java

@@ -0,0 +1,31 @@
+package com.fs.lotus.param;
+
+import com.baidu.dev2.thirdparty.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.util.Date;
+
+@Data
+public class InitUserDto {
+    @NotBlank(message = "用户姓名不能为空")
+    private String userName;
+    @NotBlank(message = "手机号不能为空")
+    private String phone;
+    @NotBlank(message = "身份证号不能为空")
+    private String idCard;
+
+    @NotBlank(message = "出生日期不能为空")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date birthday;
+
+    @NotBlank(message = "性别不能为空")
+    private Integer sex;
+
+    @NotBlank(message = "类型不能为空")
+    private String entranceType;
+
+    private String activateBizCode;
+
+    private String openId;
+}

+ 29 - 0
fs-service/src/main/java/com/fs/lotus/param/LoginDto.java

@@ -0,0 +1,29 @@
+package com.fs.lotus.param;
+
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+public class LoginDto {
+    /**
+     * 应用ID
+     */
+    private String appId;
+
+    /**
+     * 时间戳
+     */
+    private Long timestamp;
+
+    /**
+     * 签名
+     */
+    private String sign;
+
+    /**
+     * 业务数据
+     */
+    private Map<String,Object> data;
+
+}

+ 142 - 0
fs-service/src/main/java/com/fs/lotus/param/LotusClaimParam.java

@@ -0,0 +1,142 @@
+package com.fs.lotus.param;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 荷叶接口 - 三方理赔数据回传 参数
+ */
+@Data
+public class LotusClaimParam {
+    /** 操作类型:ADD-新增(目前只支持新增) */
+    private String operationType = "ADD";
+
+    /** 三方权益 ID,与 receiveId、orderNo 做新增唯一性校验 */
+    private String thirdPartyReceiveId;
+
+    /** 荷叶权益 激活码,用于校验权益关系是否存在 */
+    private String activationCode;
+
+    /** 三方订单号 */
+    private String orderNo;
+
+    /** 订单状态:50-已完成 */
+    private Integer orderStatus = 50;
+
+    /** 订单总金额,单位元,精确到小数点后 2 位 */
+    private BigDecimal orderTotalAmount;
+
+    /** 商品总金额,单位元,精确到小数点后 2 位 (必须等于发票金额 invoiceAmt) */
+    private BigDecimal productTotalAmount;
+
+    /** 订单优惠金额,单位元,不包含其他优惠,权益优惠金额 */
+    private BigDecimal channelProductDiscountAmount;
+
+    /** 运费/实付运费,单位元,免运费传 0 */
+    private BigDecimal deliveryAmount;
+
+    /** 运费原价,单位元,免运费传 0 */
+    private BigDecimal deliveryOriginAmount;
+
+    /** 优惠券金额,单位元,无优惠传 0 */
+    private BigDecimal couponAmount;
+
+    /** 实付金额,单位元 (商品总金额 + 运费 - 订单优惠金额 - 优惠券金额) */
+    private BigDecimal payAmount;
+
+    /** 订单创建时间,格式:yyyy-MM-dd HH:mm:ss */
+    private String orderCreateTime;
+
+    /** 订单完成时间,格式:yyyy-MM-dd HH:mm:ss */
+    private String orderCompletedTime;
+
+    /** 问诊单号 */
+    private String inquiryNo;
+
+    /** 处方单号 */
+    private String prescriptionNo;
+
+    /** 诊断名称,按荷叶提供的 ICD 编码对应名称回传 */
+    private String icdName;
+
+    /** 诊断编码,按荷叶提供的 ICD 编码回传 */
+    private String icd;
+
+    /** 开方时间,格式:yyyy-MM-dd HH:mm:ss */
+    private String prescriptionTime;
+
+    /** 问诊开始时间,格式:yyyy-MM-dd HH:mm:ss */
+    private String visitStartTime;
+
+    /** 问诊结束时间,格式:yyyy-MM-dd HH:mm:ss */
+    private String visitEndTime;
+
+    /** 互联网医院名称/就诊医院 */
+    private String hospital = "御君方互联网医院";
+
+    /** 互联网医院地址/出险地点详情 */
+    private String address = "四川省成都市温江区";
+
+    /** 医院所属省编码 */
+    private String provinceCode = "510000";
+
+    /** 医院所属省名称 */
+    private String provinceName = "四川省";
+
+    /** 医院所属市编码 */
+    private String cityCode = "510100";
+
+    /** 医院所属市名称 */
+    private String cityName = "成都市";
+
+    /** 医院所属区/县编码 */
+    private String countryCode = "510115";
+
+    /** 医院所属区/县名称 */
+    private String countryName = "温江区";
+
+    /** 门诊-医疗费票据-发票号码 */
+    private String receiptNumber;
+
+    /** 门诊-医疗费票据-发票金额,单位元 (须等于 productTotalAmount) */
+    private BigDecimal invoiceAmt;
+
+    /** 门诊-医疗费票据-发票类型,固定传 "1"(电子发票) */
+    private String invoiceTypeCd = "1";
+
+    /** 门诊-医疗费票据-电子票据代码,已废弃,默认传空字符串 */
+    private String electronicBillCode = "";
+
+    /** 门诊-医疗费票据-开票日期,格式:yyyy-MM-dd */
+    private String invoiceDate;
+
+    /** 门诊-医疗费票据-校验码,已废弃,默认传空字符串 */
+    private String verificationCode = "";
+
+    /** 理赔影像资料列表 (必须包含处方笺、问诊聊天记录、发票影像) */
+    private List<ClaimDocument> claimDocuments;
+
+    /**
+     * 内部类:理赔影像资料对象
+     */
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class ClaimDocument {
+        /** 文件类型:1-图片、2-pdf、3-excel */
+        private Integer type;
+
+        /** 影像类型:PRESCRIPTION-处方笺、CHAT_RECORD-问诊聊天记录、PRODUCT_INVOICE-发票影像 */
+        private String imageType;
+
+        /** 文件链接,可公网访问的 URL */
+        private String fileLink;
+
+        /** 文件名称 */
+        private String fileName;
+    }
+}

+ 27 - 0
fs-service/src/main/java/com/fs/lotus/param/LotusHealthPayParam.java

@@ -0,0 +1,27 @@
+package com.fs.lotus.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * 荷叶健康-支付请求参数
+ */
+@Data
+public class LotusHealthPayParam implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 商城订单ID */
+    @NotNull(message = "订单ID不能为空")
+    private Long orderId;
+
+    private Long userId;
+
+    /** 保险公司小程序用户的openid */
+    private String openid;
+
+    /** 支付完成后跳转地址 */
+    private String redirectUrl = "https://userapp.his.cdwjyyh.com/lotusUI/";
+}

+ 29 - 0
fs-service/src/main/java/com/fs/lotus/param/OpenApiRequest.java

@@ -0,0 +1,29 @@
+package com.fs.lotus.param;
+
+import lombok.Data;
+
+@Data
+public class OpenApiRequest {
+
+    /**
+     * 应用ID
+     */
+    private String appId;
+
+    /**
+     * 时间戳
+     */
+    private Long timestamp;
+
+    /**
+     * 签名
+     */
+    private String sign;
+
+    private String  data;
+
+    /**
+     * 业务数据
+     */
+//    private InitUserDto data;
+}

+ 95 - 0
fs-service/src/main/java/com/fs/lotus/utils/LotusSignUtil.java

@@ -0,0 +1,95 @@
+package com.fs.lotus.utils;
+
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.fs.lotus.param.LotusClaimParam;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.util.DigestUtils;
+
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+@Slf4j
+public class LotusSignUtil {
+
+    private LotusSignUtil(){}
+    // 测试环境
+    private static final String APPID = "ykqzhonghuacaiRdhlFlDS";
+    private static final String APPSECRET = "9c1814fad5959d3511e346b4e659925f";
+    private static final String LOTUSURL = "https://openapi-ykq.test.ybm100.com";
+
+    // 正式环境
+//    private static final String appId = "ykqtaipingcaisuicheKXH5rsci";
+//    private static final String appSecret = "c2b16086e63d2d0c69e633405a63c9f6";
+//    private static final String lotusUrl = "https://openapi-ykq.ybm100.com";
+    private static final String SIGN = "sign";
+    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'").withZone(ZoneOffset.UTC);
+    /**
+     * 生成sign
+     *
+     * @param 请求体参数
+     * @param secretKey 密钥,也就是appSecret
+     * @return sign
+     */
+    public static String generateSign(Map<String, Object> params, String secretKey) {
+        String encodeString = getEncodeString(params, secretKey);
+        return generateSign(encodeString);
+    }
+
+    private static String getEncodeString(Map<String, Object> params, String secretKey) {
+        Iterator<String> iterator = params.keySet().iterator();
+        Set<String> sortedParams = new TreeSet<>();
+        while (iterator.hasNext()) {
+            sortedParams.add(iterator.next());
+        }
+        StringBuilder stringBuilder = new StringBuilder(secretKey);
+        for (String key : sortedParams) {
+            if (SIGN.equals(key)) {
+                continue;
+            }
+            String value = params.get(key).toString();
+            if (StringUtils.isNotEmpty(value)) {
+                stringBuilder.append(key).append(value);
+            }
+        }
+        return stringBuilder.toString();
+    }
+
+    private static String generateSign(String content) {
+        return DigestUtils.md5DigestAsHex(content.getBytes());
+    }
+
+
+    /**
+     * 发送理赔同步请求的主入口
+     */
+    public static String executeSyncClaim(LotusClaimParam claimParam) {
+        try {
+
+            JSONObject reqParams = new JSONObject();
+            reqParams.put("appId", APPID);
+            reqParams.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
+            reqParams.put("paramJson", JSONObject.toJSONString(claimParam));
+            String sign = generateSign(reqParams, APPSECRET);
+            reqParams.put("sign", sign);
+            log.info("荷叶健康 理赔同步请求入参:{}", reqParams);
+            String responseStr = HttpUtil.createPost(LOTUSURL + "/openapi/zhonghuacai/channel/claim/sync/info")
+                    .header("Content-Type", "application/json")
+                    .body(reqParams.toJSONString())
+                    .execute()
+                    .body();
+            log.info("荷叶健康 理赔同步请求回参:{}", responseStr);
+            return responseStr;
+
+        } catch (Exception e) {
+            System.err.println("调用荷叶数据回传接口发生异常!");
+            e.printStackTrace();
+            return null;
+        }
+    }
+}

+ 189 - 0
fs-service/src/main/java/com/fs/lotus/utils/SignatureUtil.java

@@ -0,0 +1,189 @@
+package com.fs.lotus.utils;
+
+
+import com.alibaba.fastjson.JSON;
+import com.fs.lotus.config.LotusSignatureProperties;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 开放接口签名工具
+ */
+@Slf4j
+public class SignatureUtil {
+
+    /**
+     * HMAC算法
+     */
+    private static final String ALGORITHM = "HmacSHA256";
+
+    private static volatile LotusSignatureProperties properties;
+
+    private SignatureUtil() {}
+
+    /**
+     * 由 Spring 启动时注入配置
+     */
+    public static void init(LotusSignatureProperties lotusSignatureProperties) {
+        properties = lotusSignatureProperties;
+    }
+
+    private static String appId() {
+        return properties.getAppId();
+    }
+
+    private static String appSecret() {
+        return properties.getAppSecret();
+    }
+
+    private static long expireSeconds() {
+        return properties.getExpireSeconds();
+    }
+
+    /**
+     * 生成签名
+     *
+     * @param appId 应用ID
+     * @param timestamp 秒级时间戳
+     * @param data 业务数据对象
+     * @param secret 密钥
+     */
+    public static String generateSignature(String appId, Long timestamp, String data, String secret) {
+        try {
+
+            String content = buildContent(appId, timestamp, data, secret);
+
+            Mac mac = Mac.getInstance(ALGORITHM);
+
+            SecretKeySpec key = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), ALGORITHM);
+
+            mac.init(key);
+
+            byte[] result = mac.doFinal(content.getBytes(StandardCharsets.UTF_8));
+
+            return bytesToHex(result).toUpperCase();
+
+        } catch (Exception e) {
+            log.error("生成签名失败", e);
+            throw new RuntimeException("生成签名失败", e);
+        }
+    }
+
+    /**
+     * 验签
+     */
+    public static boolean verifySignature(Long timestamp, String data,String clientSign) {
+
+        if (isExpired(timestamp)) {
+
+            log.warn("请求已过期,timestamp={}", timestamp);
+
+            return false;
+        }
+
+        String serverSign = generateSignature(appId(), timestamp, data, appSecret());
+
+        return serverSign.equalsIgnoreCase(clientSign);
+    }
+
+    /**
+     * 构建签名原文
+     */
+    private static String buildContent(String appId, Long timestamp, String data, String secret) {
+
+        String dataJson = data == null ? "{}" : data;
+
+        return new StringBuilder()
+                .append("appId:")
+                .append(appId)
+                .append("|timestamp:")
+                .append(timestamp)
+                .append("|data:")
+                .append(dataJson)
+                .append("|secret:")
+                .append(secret)
+                .toString();
+    }
+
+    /**
+     * 获取当前时间戳(秒)
+     */
+    public static long currentTimestamp() {
+        return System.currentTimeMillis() / 1000;
+    }
+
+    /**
+     * 判断请求是否过期
+     */
+    private static boolean isExpired(Long timestamp) {
+        if (timestamp == null) {
+            return true;
+        }
+        return Math.abs(currentTimestamp() - timestamp) > expireSeconds();
+    }
+
+    /**
+     * byte转16进制
+     */
+    private static String bytesToHex(byte[] bytes) {
+
+        StringBuilder sb = new StringBuilder();
+
+        for (byte b : bytes) {
+
+            String hex =
+                    Integer.toHexString(b & 0xff);
+
+            if (hex.length() == 1) {
+                sb.append('0');
+            }
+            sb.append(hex);
+        }
+
+        return sb.toString();
+    }
+
+    public static void main(String[] args) {
+        // 平台分配(演示用,正式请读配置 lotus.signature)
+        String appId = "default";
+        String appSecret = "default";
+
+        // 当前时间戳(秒)
+        Long timestamp = System.currentTimeMillis() / 1000;
+
+        // 业务参数
+        Map<String, Object> data = new HashMap<>();
+//        data.put("birthday", "1997-12-23");
+//        data.put("entranceType", "inquiry");
+//        data.put("phone", "13579246810");
+//        data.put("idCard", "440106198811205419");
+//        data.put("sex", 0);
+//        data.put("userName", "王五");
+//        data.put("activateBizCode", "LOTUS07254d7e705e429591a84b551cafe036");
+//        data.put("openId", "oS8Z768qv2cLQsYBLmPvrmON01uj");
+//        data.put("userId", 4057364113L);
+
+        String jsonString = JSON.toJSONString(data);
+
+        // 生成签名
+        String sign = generateSignature(appId, timestamp, jsonString, appSecret);
+
+        // 构建请求参数
+        Map<String, Object> request = new HashMap<>();
+        request.put("appId", appId);
+        request.put("timestamp", timestamp);
+        request.put("data", jsonString);
+        request.put("sign", sign);
+
+        // 请求报文
+        String requestJson = JSON.toJSONString(request);
+
+        System.out.println("请求报文:");
+        System.out.println(requestJson);
+    }
+}

+ 34 - 5
fs-user-app/src/main/java/com/fs/app/controller/AppLoginController.java

@@ -3,6 +3,7 @@ package com.fs.app.controller;
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.date.DateTime;
+import com.alibaba.fastjson.JSONObject;
 import com.fs.app.annotation.Login;
 import com.fs.app.param.*;
 import com.fs.app.utils.WxUtil;
@@ -25,6 +26,7 @@ import com.fs.his.service.IFsUserNewTaskService;
 import com.fs.his.service.IFsUserService;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.FsUserRegisterParam;
+import com.fs.lotus.utils.SignatureUtil;
 import com.fs.watch.domain.WatchDeviceSetup;
 import com.fs.watch.domain.WatchUser;
 import com.fs.watch.service.WatchUserService;
@@ -40,11 +42,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
-
-import java.time.LocalDateTime;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
-
 import static com.fs.his.utils.PhoneUtil.encryptPhone;
 import static com.fs.his.utils.PhoneUtil.encryptPhoneOldKey;
 
@@ -121,8 +120,10 @@ public class AppLoginController extends AppBaseController{
         switch (loginType) {
             case 1:
                 return handleLoginType1(param);
-            case 3:
-                return handleLoginType3(param);
+//            case 3:
+//                return handleLoginType3(param);
+            case 4:
+                return handleLoginType4(param);
             default:
                 return R.error("请选择正确的登陆类型!");
         }
@@ -936,4 +937,32 @@ public class AppLoginController extends AppBaseController{
         return fsUsers;
     }
 
+    private R handleLoginType4(FsUserLoginParam param) {
+        if (param.getUserId() == null || StringUtils.isEmpty(param.getSign()) || param.getTimestamp() == null) {
+            return R.error("登录参数不完整");
+        }
+        // 验签
+        JSONObject reqJson = new JSONObject();
+        reqJson.put("userId", param.getUserId());
+        if (!SignatureUtil.verifySignature(param.getTimestamp(), reqJson.toString(), param.getSign())) {
+            return R.error("签名验证失败");
+        }
+        // 签名一次性:同一 sign 5 分钟内只能换票一次,防止截包重放
+        String usedKey = "lotus:login:sign:" + param.getSign();
+        if (!redisCache.setIfAbsent(usedKey, "1", 300, TimeUnit.SECONDS)) {
+            return R.error("登录凭证已失效,请重新授权");
+        }
+        Long userId = param.getUserId();
+        FsUser fsUser = userMapper.selectFsUserByUserId(userId);
+        if (fsUser == null) {
+            return R.error("用户不存在");
+        }
+        String token = jwtUtils.generateToken(userId);
+        redisCache.setCacheObject("userToken:" + userId, token, 604800, TimeUnit.SECONDS);
+        JSONObject res = new JSONObject();
+        res.put("token", token);
+        res.put("user", fsUser);
+        return R.ok().put("data", res);
+    }
+
 }

+ 6 - 0
fs-user-app/src/main/java/com/fs/app/param/FsUserLoginParam.java

@@ -32,6 +32,12 @@ public class FsUserLoginParam implements Serializable {
 
     //登录id
     private String appId;
+    private Long userId;
+
+    /** 荷叶无感登录签名用:时间戳(秒) */
+    private Long timestamp;
+    /** 荷叶无感登录签名用:签名 */
+    private String sign;
 
     /** 业务类型:1看课 2商城 */
     private Integer bizType;