增加医疗对接接口
diff --git a/backend/src/main/java/com/supwisdom/dlpay/medicine/domain/TBMedicalCard.java b/backend/src/main/java/com/supwisdom/dlpay/medicine/domain/TBMedicalCard.java
index cbc0f83..7c6466c 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/medicine/domain/TBMedicalCard.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/medicine/domain/TBMedicalCard.java
@@ -26,8 +26,8 @@
   /**
    * 证件类型
    */
-  @Column(name = "cardtype", nullable = false, length = 2)
-  private Integer cardtype;
+  @Column(name = "cardtype", nullable = false)
+  private String cardtype;
   /**
    * 患者id
    */
@@ -42,7 +42,7 @@
    * 性别
    */
   @Column(name = "patientsex", length = 2)
-  private String patientsex;
+  private Integer patientsex;
   /**
    * 出生日期(yyyy-MM-dd HH:mm:ss)
    */
@@ -93,11 +93,11 @@
     this.cardnumber = cardnumber;
   }
 
-  public Integer getCardtype() {
+  public String getCardtype() {
     return cardtype;
   }
 
-  public void setCardtype(Integer cardtype) {
+  public void setCardtype(String cardtype) {
     this.cardtype = cardtype;
   }
 
@@ -117,11 +117,11 @@
     this.patientname = patientname;
   }
 
-  public String getPatientsex() {
+  public Integer getPatientsex() {
     return patientsex;
   }
 
-  public void setPatientsex(String patientsex) {
+  public void setPatientsex(Integer patientsex) {
     this.patientsex = patientsex;
   }
 
diff --git a/backend/src/main/java/com/supwisdom/dlpay/medicine/domain/TBMedicalDtl.java b/backend/src/main/java/com/supwisdom/dlpay/medicine/domain/TBMedicalDtl.java
new file mode 100644
index 0000000..ad1fecc
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/medicine/domain/TBMedicalDtl.java
@@ -0,0 +1,183 @@
+package com.supwisdom.dlpay.medicine.domain;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "tb_medicaldtl",indexes = {@Index(name = "medicaldtl_idx",columnList = "admnumber,organizationid,feeno")})
+public class TBMedicalDtl {
+  @Id
+  @Column(name = "billno", length = 32)
+  private String billno;
+  @Column(name = "refno", length = 32)
+  private String refno;
+  @Column(name = "uid", length = 32)
+  private String uid;
+  /**
+   * 付款金额;付款金额 = 总金额 + 加收费用
+   */
+  @Column(name = "payamount", precision = 10, scale = 3)
+  private Double payamount;
+  /**
+   * 总金额
+   */
+  @Column(name = "totalfee", precision = 10, scale = 3)
+  private Double totalfee;
+  /**
+   * 加收费用描述
+   */
+  @Column(name = "extrafeedesc", length = 200)
+  private String extrafeedesc;
+  /**
+   * 医院收费单据标识
+   */
+  @Column(name = "feeno", length = 32)
+  private String feeno;
+  /**
+   * 患者就诊序号
+   */
+  @Column(name = "admnumber", length = 64)
+  private String admnumber;
+  /**
+   * 医院code
+   */
+  @Column(name = "organizationid", length = 30)
+  private String organizationid;
+  /**
+   * 医院发票号
+   */
+  @Column(name = "invoiceno", length = 30)
+  private String invoiceno;
+  @Column(name = "paystatus", length = 15)
+  private String paystatus;
+  @Column(name = "transdate", length = 14)
+  private String transdate;
+  @Column(name = "transtime", length = 6)
+  private String transtime;
+  @Column(name = "citizencardno", length = 32)
+  private String citizencardno;
+  /**
+   * HIS结算标识
+   */
+  @Column(name = "resultid", length = 64)
+  private String resultid;
+
+  public String getBillno() {
+    return billno;
+  }
+
+  public void setBillno(String billno) {
+    this.billno = billno;
+  }
+
+  public String getRefno() {
+    return refno;
+  }
+
+  public void setRefno(String refno) {
+    this.refno = refno;
+  }
+
+  public String getUid() {
+    return uid;
+  }
+
+  public void setUid(String uid) {
+    this.uid = uid;
+  }
+
+  public Double getPayamount() {
+    return payamount;
+  }
+
+  public void setPayamount(Double payamount) {
+    this.payamount = payamount;
+  }
+
+  public Double getTotalfee() {
+    return totalfee;
+  }
+
+  public void setTotalfee(Double totalfee) {
+    this.totalfee = totalfee;
+  }
+
+  public String getExtrafeedesc() {
+    return extrafeedesc;
+  }
+
+  public void setExtrafeedesc(String extrafeedesc) {
+    this.extrafeedesc = extrafeedesc;
+  }
+
+  public String getOrganizationid() {
+    return organizationid;
+  }
+
+  public void setOrganizationid(String organizationid) {
+    this.organizationid = organizationid;
+  }
+
+  public String getFeeno() {
+    return feeno;
+  }
+
+  public void setFeeno(String feeno) {
+    this.feeno = feeno;
+  }
+
+  public String getAdmnumber() {
+    return admnumber;
+  }
+
+  public void setAdmnumber(String admnumber) {
+    this.admnumber = admnumber;
+  }
+
+  public String getInvoiceno() {
+    return invoiceno;
+  }
+
+  public void setInvoiceno(String invoiceno) {
+    this.invoiceno = invoiceno;
+  }
+
+  public String getPaystatus() {
+    return paystatus;
+  }
+
+  public void setPaystatus(String paystatus) {
+    this.paystatus = paystatus;
+  }
+
+  public String getTransdate() {
+    return transdate;
+  }
+
+  public void setTransdate(String transdate) {
+    this.transdate = transdate;
+  }
+
+  public String getTranstime() {
+    return transtime;
+  }
+
+  public void setTranstime(String transtime) {
+    this.transtime = transtime;
+  }
+
+  public String getCitizencardno() {
+    return citizencardno;
+  }
+
+  public void setCitizencardno(String citizencardno) {
+    this.citizencardno = citizencardno;
+  }
+
+  public String getResultid() {
+    return resultid;
+  }
+
+  public void setResultid(String resultid) {
+    this.resultid = resultid;
+  }
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/medicine/util/MedicalClient.java b/backend/src/main/java/com/supwisdom/dlpay/medicine/util/MedicalClient.java
index e6d8b7c..801fe76 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/medicine/util/MedicalClient.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/medicine/util/MedicalClient.java
@@ -6,6 +6,9 @@
 import com.supwisdom.dlpay.framework.util.StringUtil;
 import com.supwisdom.dlpay.medicine.bean.*;
 import com.supwisdom.dlpay.medicine.exception.MedicineException;
+import com.supwisdom.dlpay.portal.util.PortalConstant;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.*;
 import org.springframework.stereotype.Component;
@@ -21,8 +24,17 @@
   private RestTemplate restTemplate;
   @Autowired
   private SystemUtilService systemUtilService;
+  private Logger logger = LoggerFactory.getLogger(MedicalClient.class);
 
   public PatientInfoResponse getPatientMedicalCardList(AddPatientBean bean) {
+    return queryOrRegisterPatientInfo(bean, MedicalConstant.PATIENTINFO_TYPE_QUERY);
+  }
+
+  public PatientInfoResponse registerPatientInfo(AddPatientBean bean) {
+    return queryOrRegisterPatientInfo(bean, MedicalConstant.PATIENTINFO_TYPE_REGISTER);
+  }
+
+  private PatientInfoResponse queryOrRegisterPatientInfo(AddPatientBean bean, String operationType) {
     String url = getMedicalUrl();
     Map<String, Object> param = new HashMap<>(8);
     param.put("organizationId", bean.getHospitalcode());
@@ -30,9 +42,20 @@
     param.put("cardNumber", bean.getCardno());
     param.put("patientName", bean.getName());
     param.put("patientSex", bean.getSex());
+    param.put("operationType", operationType);
+    param.put("patientMobile", bean.getMobile());
     String response = httpPost(url + "register/getPhoneAndCards", JSON.toJSONString(param));
-    return JSON.parseObject(response, new TypeReference<MedicalResponse<PatientInfoResponse>>() {
-    }).getData();
+    MedicalResponse<List<PatientInfoResponse>> result = JSON.parseObject(response, new TypeReference<MedicalResponse<List<PatientInfoResponse>>>() {
+    });
+    if (result.getCode() != MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
+      logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
+      throw new MedicineException("请求医疗系统异常");
+    }
+    List<PatientInfoResponse> list = result.getData();
+    if (list != null && list.size() > 0) {
+      return list.get(0);
+    }
+    return null;
   }
 
   public MedicalCardInfoResponse getMedicalCardDetail(String organizationId, String patientId) {
@@ -41,17 +64,27 @@
     param.put("organizationId", organizationId);
     param.put("patientId", patientId);
     String response = httpPost(url + "register/queryBusCards", JSON.toJSONString(param));
-    return JSON.parseObject(response, new TypeReference<MedicalResponse<MedicalCardInfoResponse>>() {
-    }).getData();
+    MedicalResponse<MedicalCardInfoResponse> result = JSON.parseObject(response, new TypeReference<MedicalResponse<MedicalCardInfoResponse>>() {
+    });
+    if (result.getCode() != MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
+      logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
+      throw new MedicineException("请求医疗系统异常");
+    }
+    return result.getData();
   }
 
   public List<ArrangeInfoResponse> getArrangeInfo(String organizationId, String date) {
     String url = getMedicalUrl();
     Map<String, Object> param = new HashMap<>(2);
     param.put("organizationId", organizationId);
-    String response = httpPost(url + "appointment/listArrange", JSON.toJSONString(param));
-    return JSON.parseObject(response, new TypeReference<MedicalResponse<List<ArrangeInfoResponse>>>() {
-    }).getData();
+    String response = httpPost(url + "framework/appointment/listArrange", JSON.toJSONString(param));
+    MedicalResponse<List<ArrangeInfoResponse>> result = JSON.parseObject(response, new TypeReference<MedicalResponse<List<ArrangeInfoResponse>>>() {
+    });
+    if (result.getCode() != MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
+      logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
+      throw new MedicineException("请求医疗系统异常");
+    }
+    return result.getData();
   }
 
   public AppointmentResponse confirmAppointment(ConfirmRequestBean bean) {
@@ -64,14 +97,93 @@
     param.put("patientId", bean.getPatientid());
     param.put("patientName", bean.getPatientname());
     param.put("patientMobile", bean.getPatientmobile());
-    String response = httpPost(url + "appointment/confirmAppointment", JSON.toJSONString(param));
-    return JSON.parseObject(response, new TypeReference<MedicalResponse<AppointmentResponse>>() {
-    }).getData();
+    String response = httpPost(url + "framework/appointment/confirmAppointment", JSON.toJSONString(param));
+    MedicalResponse<AppointmentResponse> result = JSON.parseObject(response, new TypeReference<MedicalResponse<AppointmentResponse>>() {
+    });
+    if (result.getCode() != MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
+      logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
+      throw new MedicineException("请求医疗系统异常");
+    }
+    return result.getData();
   }
 
+  public UnPayedResponse getUnPayedList(UnPayedRequest bean) {
+    String url = getMedicalUrl();
+    Map<String, Object> param = new HashMap<>(4);
+    param.put("organizationId", bean.getOrganizationId());
+    param.put("queryType", bean.getQueryType());
+    param.put("patientIdList", bean.getPatientIdList());
+    String response = httpPost(url + "getUnpayedList", JSON.toJSONString(param));
+    MedicalResponse<UnPayedResponse> result = JSON.parseObject(response, new TypeReference<MedicalResponse<UnPayedResponse>>() {
+    });
+    if (result.getCode() != MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
+      logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
+      throw new MedicineException("请求医疗系统异常");
+    }
+    return result.getData();
+  }
+
+  public PayedResponse getPayedList(PayedRequest bean) {
+    String url = getMedicalUrl();
+    Map<String, Object> param = new HashMap<>(8);
+    param.put("organizationId", bean.getOrganizationId());
+    param.put("queryType", bean.getQueryType());
+    param.put("patientIdList", bean.getPatientIdList());
+    param.put("executeFlag", bean.getExecuteFlag());
+    param.put("outpatientType", bean.getOutpatientType());
+    String response = httpPost(url + "getPayedList", JSON.toJSONString(param));
+    MedicalResponse<PayedResponse> result = JSON.parseObject(response, new TypeReference<MedicalResponse<PayedResponse>>() {
+    });
+    if (result.getCode() != MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
+      logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
+      throw new MedicineException("请求医疗系统异常");
+    }
+    return result.getData();
+  }
+
+  public PreFeeResponse getPreCalculatedFee(PreFeeRequest bean) {
+    String url = getMedicalUrl();
+    Map<String, Object> param = new HashMap<>(8);
+    param.put("organizationId", bean.getOrganizationId());
+    param.put("boilSign", bean.getBoilSign());
+    param.put("feeRecords", bean.getFeeRecords());
+    String response = httpPost(url + "getPrecalculatedFee", JSON.toJSONString(param));
+    MedicalResponse<PreFeeResponse> result = JSON.parseObject(response, new TypeReference<MedicalResponse<PreFeeResponse>>() {
+    });
+    if (result.getCode() != MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
+      logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
+      throw new MedicineException("请求医疗系统异常");
+    }
+    return result.getData();
+  }
+
+  public NotifyPayedResponse notifyPayed(NotifyPayedRequest bean) {
+    String url = getMedicalUrl();
+    Map<String, Object> param = new HashMap<>(8);
+    param.put("organizationId", bean.getOrganizationId());
+    param.put("patientId", bean.getPatientId());
+    param.put("invoiceNumber", bean.getInvoiceNumber());
+    param.put("payMode", bean.getPayMode());
+    param.put("payState", bean.getPayState());
+    param.put("agtOrderNumber", bean.getAgtOrderNumber());
+    param.put("payAmount", bean.getPayAmount());
+    param.put("outOrderNumber", bean.getOutOrderNumber());
+    param.put("payer", bean.getPayer());
+    param.put("totalFee ", bean.getTotalFee());
+    param.put("brid ", bean.getBrid());
+    param.put("feeRecords ", bean.getFeeRecords());
+    String response = httpPost(url + "getPrecalculatedFee", JSON.toJSONString(param));
+    MedicalResponse<NotifyPayedResponse> result = JSON.parseObject(response, new TypeReference<MedicalResponse<NotifyPayedResponse>>() {
+    });
+    if (result.getCode() != MedicalConstant.MEDICAL_RESPONSE_SUCCESS) {
+      logger.error("调用医疗接口异常,code:" + result.getCode() + ";message:" + result.getMessage());
+      throw new MedicineException("请求医疗系统异常");
+    }
+    return result.getData();
+  }
 
   private String getMedicalUrl() {
-    String url = systemUtilService.getBusinessValue(MedicalConstant.SYSPARA_MEDICAL_URL);
+    String url = systemUtilService.getBusinessValue(PortalConstant.SYSPARA_MEDICAL_URL);
     if (StringUtil.isEmpty(url)) {
       throw new MedicineException("医疗系统地址未配置");
     }
diff --git a/backend/src/main/java/com/supwisdom/dlpay/medicine/util/MedicalConstant.java b/backend/src/main/java/com/supwisdom/dlpay/medicine/util/MedicalConstant.java
index 1f5e7a8..d0ad509 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/medicine/util/MedicalConstant.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/medicine/util/MedicalConstant.java
@@ -4,12 +4,42 @@
   /**
    * 证件类型
    */
-  public final static int CARD_TYPE_IDCAED = 1;//身份证
+  public final static String CARD_TYPE_IDCAED = "1";//身份证
   /**
-   *
+   * 患者信息认证模式
    */
-  public final static int UNPAYED_QUERYTYPE_MEDICALCARD = 3;//按诊疗卡类型查询
+  public final static String PATIENTINFO_TYPE_QUERY = "1";//查询
+  public final static String PATIENTINFO_TYPE_REGISTER = "2";//建档
+  /**
+   * 订单查询模式
+   */
+  public final static int ORDER_QUERYTYPE_PATIENTID = 1;//按患者id查询
+  public final static int ORDER_QUERYTYPE_MEDICALCARD = 3;//按诊疗卡类型查询
+  /**
+   * 支付列表执行标志
+   */
+  public final static int PAYED_EXECUTEFLAG_INVALID = 0;//本参数无效
+  /**
+   * 支付列表门诊类型
+   */
+  public final static int PAYED_OUTPATIENTTYPE_NORMAL = 1;//普通
+  /**
+   * 医疗系统响应状态码
+   */
+  public final static int MEDICAL_RESPONSE_SUCCESS = 200;//成功
+  /**
+   * 本地流水状态
+   */
+  public final static String DTL_STATUS_INIT = "init";
+  public final static String DTL_STATUS_WIP = "wip";
+  public final static String DTL_STATUS_SUCCESS = "sucess";
+  /**
+   * 子系统代码
+   */
+  public final static String DTLTYPE_MEDICAL = "medical";
+  /**
+   * payapi成功响应代码
+   */
+  public final static Integer PAYAPI_SUCCESS_RETCODE = 0;
 
-
-  public static final String SYSPARA_MEDICAL_URL = "medical.url";
 }
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBOutlets.java b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBOutlets.java
index 23467b1..3cb8524 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBOutlets.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBOutlets.java
@@ -16,10 +16,10 @@
   @Column(name = "id", nullable = false, length = 32)
   private String id;
 
-  @Column(name = "outletsno")
+  @Column(name = "outletsno", length = 20)
   private String outletsno;
 
-  @Column(name = "name",length = 100)
+  @Column(name = "name", length = 100)
   private String name;
 
   @Column(name = "address", length = 200)
@@ -31,19 +31,19 @@
   @Column(name = "endtime", length = 6)
   private String endtime;
 
-  @Column(name = "location",length = 30)
+  @Column(name = "location", length = 30)
   private String location;
 
-  @Column(name = "createtime",length = 14)
+  @Column(name = "createtime", length = 14)
   private String createtime;
 
   @Column(name = "businescope", length = 100)
   private String businescope;
 
-  @Column(name = "tel",length = 50)
+  @Column(name = "tel", length = 50)
   private String tel;
 
-  @Column(name = "isopen",length = 1)
+  @Column(name = "isopen", length = 1)
   private String isopen;
 
   @Transient
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java b/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java
index d738d2a..e0a12ca 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java
@@ -18,6 +18,8 @@
   public static final String SYSPARA_PORTAL_SECRET = "portal.secret";
   public static final String SYSPARA_PORTAL_AMAPKEY = "portal.amapkey";
   public static final String SYSPARA_PORTAL_AMAPURL = "portal.amapurl";
+  public static final String SYSPARA_MEDICAL_URL = "medical.url";
+  public static final String SYSPARA_MEDICAL_SHOPACCNO = "medical.shopaccno";
 
   public static final String ARTICLE_STATUS_SAVE = "save";
   public static final String ARTICLE_STATUS_PASS = "pass";
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/MedicineApi.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/MedicineApi.kt
index 5635ee4..c56a6e9 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/MedicineApi.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/MedicineApi.kt
@@ -1,11 +1,18 @@
 package com.supwisdom.dlpay.medicine
 
 import com.supwisdom.dlpay.api.bean.JsonResult
+import com.supwisdom.dlpay.api.bean.QueryCardParam
+import com.supwisdom.dlpay.api.bean.QueryUserParam
+import com.supwisdom.dlpay.framework.util.TradeDict
 import com.supwisdom.dlpay.medicine.bean.AddPatientBean
 import com.supwisdom.dlpay.medicine.bean.ConfirmRequestBean
+import com.supwisdom.dlpay.medicine.bean.PaymentRequestBean
 import com.supwisdom.dlpay.medicine.exception.MedicineException
 import com.supwisdom.dlpay.medicine.service.MedicineService
+import com.supwisdom.dlpay.mobile.domain.TBMobileUser
 import com.supwisdom.dlpay.mobile.service.MobileApiService
+import com.supwisdom.dlpay.paysdk.proxy.UserProxy
+import com.supwisdom.dlpay.util.ConstantUtil
 import mu.KotlinLogging
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.security.core.context.SecurityContextHolder
@@ -18,6 +25,8 @@
     lateinit var medicineService: MedicineService
     @Autowired
     lateinit var mobileApiService: MobileApiService
+    @Autowired
+    lateinit var userProxy: UserProxy
 
     val logger = KotlinLogging.logger { }
 
@@ -73,6 +82,7 @@
             val p = SecurityContextHolder.getContext().authentication
             val user = mobileApiService.findUserById(p.name)
                     ?: return JsonResult.error("用户不存在,请注册")
+            bean.checkParam()
             bean.uid = user.uid
             medicineService.addPatient(bean)
             return JsonResult.ok()
@@ -101,12 +111,17 @@
      */
     @PostMapping("/appointment/confirm")
     fun confirmAppointment(@RequestBody bean: ConfirmRequestBean): JsonResult? {
-        val p = SecurityContextHolder.getContext().authentication
-        val user = mobileApiService.findUserById(p.name)
-                ?: return JsonResult.error("用户不存在,请注册")
-        bean.uid = user.uid
-        medicineService.confirmAppointment(bean)
-        return JsonResult.ok()
+        try {
+            val p = SecurityContextHolder.getContext().authentication
+            val user = mobileApiService.findUserById(p.name)
+                    ?: return JsonResult.error("用户不存在,请注册")
+            bean.uid = user.uid
+            medicineService.confirmAppointment(bean)
+            return JsonResult.ok()
+        } catch (e: Exception) {
+            logger.error(e.message)
+            return JsonResult.error("系统异常,请稍后重试")
+        }
     }
 
     /**
@@ -142,12 +157,81 @@
      * 获取待支付列表
      */
     @GetMapping("/unpayed/list")
-    fun getUnpayedList(): JsonResult? {
+    fun getUnPayedList(organizationid: String, cardid: String): JsonResult? {
+        try {
+            val p = SecurityContextHolder.getContext().authentication
+            val user = mobileApiService.findUserById(p.name)
+                    ?: return JsonResult.error("用户不存在,请注册")
+            val data = medicineService.getUnPayedList(user.uid, organizationid, cardid)
+            return JsonResult.ok().put("data", data)
+        } catch (e: Exception) {
+            logger.error(e.message)
+            return JsonResult.error("系统异常,请稍后重试")
+        }
+    }
+
+    /**
+     * 获取已支付列表
+     */
+    @GetMapping("/payed/list")
+    fun getPayedList(organizationid: String, cardid: String): JsonResult? {
+        try {
+            val p = SecurityContextHolder.getContext().authentication
+            val user = mobileApiService.findUserById(p.name)
+                    ?: return JsonResult.error("用户不存在,请注册")
+            val data = medicineService.getPayedList(user.uid, organizationid, cardid)
+            return JsonResult.ok().put("data", data)
+        } catch (e: Exception) {
+            logger.error(e.message)
+            return JsonResult.error("系统异常,请稍后重试")
+        }
+    }
+
+    /**
+     * 支付接口
+     */
+    @PostMapping("/pay")
+    fun medicalPayment(@RequestBody bean: PaymentRequestBean): JsonResult? {
         val p = SecurityContextHolder.getContext().authentication
         val user = mobileApiService.findUserById(p.name)
                 ?: return JsonResult.error("用户不存在,请注册")
-        medicineService.getUnpayedList(user.uid)
+        val checkResult = checkUserConsume(user)
+        if (checkResult?.get("code") != 200) {
+            return checkResult
+        }
+        val cardNo = checkResult["data"] as String
+        medicineService.medicalPayInit(user.uid, bean,cardNo)
         return JsonResult.ok()
     }
 
+    fun checkUserConsume(user: TBMobileUser): JsonResult? {
+        if (TradeDict.STATUS_NORMAL != user.status) {
+            return JsonResult.error("用户状态异常")
+        }
+        if (user.userid.isNullOrEmpty()) {
+            return JsonResult.error("请绑定银行卡")
+        }
+        val userInfo = userProxy.querybycardno(QueryUserParam().apply {
+            this.userid = user.userid
+        })
+        if (userInfo.retcode != 0) {
+            logger.error { "获取userid为${user.userid}的用户信息失败,错误信息:${userInfo.retmsg}" }
+            return JsonResult.error("获取用户信息失败")
+        }
+        if (userInfo.cardstatus != TradeDict.STATUS_NORMAL || userInfo.transstatus != TradeDict.STATUS_NORMAL) {
+            return JsonResult.error("消费状态异常")
+        }
+        val cardResponse = userProxy.queryCard(QueryCardParam().apply {
+            this.cardno = userInfo.bankcardno
+            this.cardtype = ConstantUtil.CARDTYPE_BANKCARD
+        })
+        if (cardResponse.retcode != 0) {
+            logger.error { "查询卡片[${userInfo.bankcardno}]信息失败:${cardResponse.retmsg}" }
+            return JsonResult.error("银行卡信息异常")
+        }
+        if (!cardResponse.card.signed) {
+            return JsonResult.error("请签约银行卡")
+        }
+        return JsonResult.ok().put("data",userInfo.cardno)
+    }
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/AddPatientBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/AddPatientBean.kt
index 5891c12..a9c6670 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/AddPatientBean.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/AddPatientBean.kt
@@ -1,10 +1,26 @@
 package com.supwisdom.dlpay.medicine.bean
 
-class AddPatientBean {
+import com.supwisdom.dlpay.api.APIRequestParam
+import com.supwisdom.dlpay.api.exception.RequestParamCheckException
+import com.supwisdom.dlpay.framework.util.StringUtil
+
+class AddPatientBean: APIRequestParam() {
     var name = ""
-    var sex = ""
+    var sex = 0
     var cardno = ""
-    var tel = ""
+    var mobile = ""
     var hospitalcode = ""
     var uid = ""
+    override fun checkParam(): Boolean {
+        if (StringUtil.isEmpty(name)) {
+            throw RequestParamCheckException("请求参数错误[name为空]")
+        }
+        if (StringUtil.isEmpty(cardno)) {
+            throw RequestParamCheckException("请求参数错误[cardno为空]")
+        }
+        if (StringUtil.isEmpty(cardno)) {
+            throw RequestParamCheckException("请求参数错误[hospitalcode为空]")
+        }
+        return true
+    }
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/ConfirmRequestBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/ConfirmRequestBean.kt
index b8ccbcc..ab28c78 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/ConfirmRequestBean.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/ConfirmRequestBean.kt
@@ -10,4 +10,5 @@
     var patientname = ""
     var patientmobile = ""
     var uid = ""
+    var cardid = ""
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/MedicalCardInfoResponse.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/MedicalCardInfoResponse.kt
index 62a566f..48f84b1 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/MedicalCardInfoResponse.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/MedicalCardInfoResponse.kt
@@ -5,7 +5,7 @@
 class MedicalCardInfoResponse {
     var patientName = ""
     var patientId = ""
-    var patientSex = ""
+    var patientSex = 0
     var patientBirthday = Date()
     var patientMobile = ""
     var patientMedicalCardType = 0
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/NotifyPayedBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/NotifyPayedBean.kt
new file mode 100644
index 0000000..6cf98ea
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/NotifyPayedBean.kt
@@ -0,0 +1,24 @@
+package com.supwisdom.dlpay.medicine.bean
+
+class NotifyPayedRequest {
+    var organizationId = ""
+    var patientId = ""
+    var invoiceNumber = ""
+    var payMode = ""
+    var payState = ""
+    var agtOrderNumber = ""
+    var payAmount = 0.0
+    var outOrderNumber = ""
+    var payer = ""
+    var totalFee  = 0.0
+    var brid  = ""
+    var feeRecords  = ArrayList<FeeRecordItem>()
+}
+
+class NotifyPayedResponse {
+    var agtOrderNumber = ""
+    var resultId = ""
+    var invoiceNumber = ""
+    var paymentBudgetNumber = ""
+    var feeRecords = ArrayList<FeeRecordItem>()
+}
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/PayedBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/PayedBean.kt
new file mode 100644
index 0000000..523b7ca
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/PayedBean.kt
@@ -0,0 +1,42 @@
+package com.supwisdom.dlpay.medicine.bean
+
+class PayedRequest {
+    var organizationId = ""
+    var outpatientType = 0
+    var executeFlag = 0
+    var queryType = 0
+    var patientIdList = ArrayList<String>()
+}
+
+class PayedResponse {
+    var patientId = ""
+    var patientMedicalCardType = 0
+    var patientMedicalCardNumber = ""
+    var invoiceList = ArrayList<InvoiceItem>()
+}
+
+class InvoiceItem {
+    var invoiceNumber = ""
+    var medicalDate = ""
+    var admNumber = ""
+    var costList = ArrayList<costItem>()
+}
+
+class costItem {
+    var mergingCode = 0
+    var mergingName = ""
+    var executionStatus = 0 //执行判别: 0、已付款/未执行/待执行,1、表示已取药2、表示已执行3、标志已退费
+    var execute = ""    //执行科室
+    var feeNo = ""
+    var feeTypeCode = ""
+    var totalFee = 0.0
+}
+
+class PayedDTO {
+    var medicalDate = ""
+    var mergingName = ""
+    var executionStatus = 0
+    var execute = ""
+    var totalFee = 0.0
+    var admNumber = ""
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/PaymentRequestBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/PaymentRequestBean.kt
new file mode 100644
index 0000000..7371a5c
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/PaymentRequestBean.kt
@@ -0,0 +1,8 @@
+package com.supwisdom.dlpay.medicine.bean
+
+class PaymentRequestBean {
+    var organizationid = ""
+    var cardid = ""
+    var feeno = ""
+    var admnumber = ""
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/PrecalculatedFeeBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/PrecalculatedFeeBean.kt
new file mode 100644
index 0000000..360dc28
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/PrecalculatedFeeBean.kt
@@ -0,0 +1,22 @@
+package com.supwisdom.dlpay.medicine.bean
+
+class PreFeeRequest {
+    var organizationId = ""
+    var boilSign = 0
+    var feeRecords = ArrayList<FeeRecordItem>()
+}
+
+class FeeRecordItem {
+    var feeNo = ""
+    var feeTypeCode = ""
+    var feeTypeName = ""
+    var totalFee = 0.0
+}
+
+class PreFeeResponse {
+    var payAmount = 0.0
+    var invoiceNumber = ""
+    var totalFee = 0.0
+    var paymentBudgetNumber = ""    //预结算标识
+    var extraFeeDesc = ""   //加收费费用描述
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/UnPayedBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/UnPayedBean.kt
new file mode 100644
index 0000000..4db7c2f
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/bean/UnPayedBean.kt
@@ -0,0 +1,51 @@
+package com.supwisdom.dlpay.medicine.bean
+
+import kotlin.collections.ArrayList
+
+class UnPayedRequest {
+    var organizationId = ""
+    var queryType = 0
+    var patientIdList = ArrayList<String>()
+}
+
+class UnPayedResponse {
+    var patientId = ""
+    var patientMedicalCardType = 0
+    var patientMedicalCardNumber = ""
+    var patientName = ""
+    var patientSex = ""
+    var patientAge = ""
+    var medicalInformation = ArrayList<MedicalInformation>()
+}
+
+class MedicalInformation {
+    var medicalDate = ""
+    var doctorName = ""
+    var doctorCode = ""
+    var departmentName = ""
+    var departmentCode = ""
+    var totalFee = 0.0
+    var admNumber = ""  //就诊序号
+    var mergingItems = ArrayList<MergingItems>()
+}
+
+class MergingItems {
+    var mergingCode = 0
+    var mergingName = ""
+    var mergingSubtotal = 0.0
+    var feeNo = ""
+    var feeTypeCode = ""
+    var feeTypeName = ""
+    var feeDate = ""
+    var boilSign = 0    //代煎标志,0-不代煎,1-代煎
+}
+
+class UnPayedDTO {
+    var medicalDate = ""
+    var doctorName = ""
+    var subjectName = ""
+    var admNumber = ""
+    var mergingSubtotal = 0.0
+    var feeNo = ""
+}
+
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/dao/MedicalCardDao.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/dao/MedicalCardDao.kt
index 5d43e44..e22d068 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/dao/MedicalCardDao.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/dao/MedicalCardDao.kt
@@ -8,5 +8,5 @@
 interface MedicalCardDao : JpaRepository<TBMedicalCard, String> {
     fun findByUidAndOrganizationid(uid: String, organizationid: String): List<TBMedicalCard>?
     fun findByCardidAndUid(cardid: String, uid: String): TBMedicalCard?
-    fun findByUidAndOrganizationidAndCardnumberAndCardtype(uid: String, organizationid: String, cardnumber: String, cardtype: Int): List<TBMedicalCard>?
+    fun findByUidAndOrganizationidAndCardnumberAndCardtype(uid: String, organizationid: String, cardnumber: String, cardtype: String): List<TBMedicalCard>?
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/dao/MedicalDtlDao.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/dao/MedicalDtlDao.kt
new file mode 100644
index 0000000..95f0acb
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/dao/MedicalDtlDao.kt
@@ -0,0 +1,20 @@
+package com.supwisdom.dlpay.medicine.dao
+
+import com.supwisdom.dlpay.medicine.domain.TBMedicalDtl
+import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.data.jpa.repository.Lock
+import org.springframework.data.jpa.repository.Query
+import org.springframework.data.jpa.repository.QueryHints
+import org.springframework.stereotype.Repository
+import javax.persistence.LockModeType
+import javax.persistence.QueryHint
+
+@Repository
+interface MedicalDtlDao : JpaRepository<TBMedicalDtl, String> {
+    @Lock(LockModeType.PESSIMISTIC_WRITE)
+    @Query("select t from TBMedicalDtl t where t.billno=?1")
+    @QueryHints(QueryHint(name = "javax.persistence.lock.timeout", value = "0"))
+    fun findByBillnoForUpdate(billno: String?): TBMedicalDtl
+
+    fun findByAdmnumberAndOrganizationidAndFeeno(admNumber: String, organizationId: String, feeNo: String): TBMedicalDtl?
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/service/MedicineService.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/service/MedicineService.kt
index bdf627d..5cf9537 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/service/MedicineService.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/service/MedicineService.kt
@@ -1,9 +1,8 @@
 package com.supwisdom.dlpay.medicine.service
 
+import com.supwisdom.dlpay.api.bean.JsonResult
 import com.supwisdom.dlpay.framework.jpa.page.Pagination
-import com.supwisdom.dlpay.medicine.bean.AddPatientBean
-import com.supwisdom.dlpay.medicine.bean.ArrangeInfoResponse
-import com.supwisdom.dlpay.medicine.bean.ConfirmRequestBean
+import com.supwisdom.dlpay.medicine.bean.*
 import com.supwisdom.dlpay.medicine.domain.TBMedicalCard
 import org.springframework.transaction.annotation.Transactional
 
@@ -32,6 +31,15 @@
     @Transactional
     fun deleteAppointment(appointmentId: String, uid: String)
 
-    @Transactional(readOnly = true)
-    fun getUnpayedList(uid: String)
+    @Transactional
+    fun getUnPayedList(uid: String, organizationId: String, cardId: String): List<UnPayedDTO>
+
+    @Transactional
+    fun getPayedList(uid: String, organizationId: String, cardId: String): ArrayList<PayedDTO>
+
+    @Transactional
+    fun medicalPayInit(uid: String, bean: PaymentRequestBean, cardNo: String): JsonResult?
+
+    @Transactional
+    fun medicalPayConfirm(billno: String): JsonResult?
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/service/impl/MedicineServiceImpl.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/service/impl/MedicineServiceImpl.kt
index 488bc9c..da9370c 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/service/impl/MedicineServiceImpl.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/medicine/service/impl/MedicineServiceImpl.kt
@@ -1,18 +1,27 @@
 package com.supwisdom.dlpay.medicine.service.impl
 
+import com.supwisdom.dlpay.api.bean.CitizenCardPayfinishParam
+import com.supwisdom.dlpay.api.bean.CitizenCardPayinitParam
+import com.supwisdom.dlpay.api.bean.JsonResult
 import com.supwisdom.dlpay.framework.jpa.page.Pagination
 import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.util.Constants
+import com.supwisdom.dlpay.framework.util.MoneyUtil
 import com.supwisdom.dlpay.framework.util.StringUtil
 import com.supwisdom.dlpay.medicine.bean.*
 import com.supwisdom.dlpay.medicine.dao.AppointmentDtlDao
 import com.supwisdom.dlpay.medicine.dao.HospitalDao
 import com.supwisdom.dlpay.medicine.dao.MedicalCardDao
+import com.supwisdom.dlpay.medicine.dao.MedicalDtlDao
 import com.supwisdom.dlpay.medicine.domain.TBAppointmentDtl
 import com.supwisdom.dlpay.medicine.domain.TBMedicalCard
+import com.supwisdom.dlpay.medicine.domain.TBMedicalDtl
 import com.supwisdom.dlpay.medicine.exception.MedicineException
 import com.supwisdom.dlpay.medicine.service.MedicineService
 import com.supwisdom.dlpay.medicine.util.MedicalClient
 import com.supwisdom.dlpay.medicine.util.MedicalConstant
+import com.supwisdom.dlpay.paysdk.proxy.CitizenCardPayProxy
+import com.supwisdom.dlpay.portal.util.PortalConstant
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Service
 
@@ -28,6 +37,10 @@
     lateinit var appointmentDtlDao: AppointmentDtlDao
     @Autowired
     lateinit var medicalClient: MedicalClient
+    @Autowired
+    lateinit var medicalDtlDao: MedicalDtlDao
+    @Autowired
+    lateinit var citizenCardPayProxy: CitizenCardPayProxy
 
     override fun getHospitalList(pageno: Int, pageSize: Int, name: String?): Pagination {
         return hospitalDao.getHospitalList(pageno, pageSize, name)
@@ -46,10 +59,10 @@
     override fun addPatient(bean: AddPatientBean) {
         //  查询当前就诊人在该医院的就诊卡列表
         val response = medicalClient.getPatientMedicalCardList(bean)
-        val list = response.listMedicalCard
-        if (!list.isNullOrEmpty()) {
+        if (null != response && !response.listMedicalCard.isNullOrEmpty()) {
             //  已有就诊卡:查询详情后本地保存
             //  删除本地该患者原有就诊卡
+            val list = response.listMedicalCard
             val localCard = medicalCardDao.findByUidAndOrganizationidAndCardnumberAndCardtype(
                     bean.uid, bean.hospitalcode, bean.cardno, MedicalConstant.CARD_TYPE_IDCAED)
             if (!localCard.isNullOrEmpty()) {
@@ -78,10 +91,10 @@
             }
         } else {
             //  无就诊卡,在HIS中新建,成功后本地保存
-            val addResponse = medicalClient.getPatientMedicalCardList(bean)
-            val addList = addResponse.listMedicalCard
-            if (!addList.isNullOrEmpty()) {
+            val addResponse = medicalClient.registerPatientInfo(bean)
+            if (null != addResponse && !addResponse.listMedicalCard.isNullOrEmpty()) {
                 //  删除本地该患者原有就诊卡
+                val addList = addResponse.listMedicalCard
                 val localCard = medicalCardDao.findByUidAndOrganizationidAndCardnumberAndCardtype(
                         bean.uid, bean.hospitalcode, bean.cardno, MedicalConstant.CARD_TYPE_IDCAED)
                 if (!localCard.isNullOrEmpty()) {
@@ -111,6 +124,13 @@
     }
 
     override fun confirmAppointment(bean: ConfirmRequestBean) {
+        val medicalCard = medicalCardDao.findByCardidAndUid(bean.cardid, bean.uid)
+                ?: throw MedicineException("未找到该就诊卡")
+        bean.apply {
+            this.patientid = medicalCard.patientid
+            this.patientname = medicalCard.patientname
+            this.patientmobile = medicalCard.patientmobile
+        }
         val appointmentResponse = medicalClient.confirmAppointment(bean)
         val appointmentDtl = TBAppointmentDtl()
         appointmentDtl.uid = bean.uid
@@ -139,7 +159,175 @@
         appointmentDtlDao.save(appointmentDtl)
     }
 
-    override fun getUnpayedList(uid: String) {
-        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+    fun getUnPayedResponse(organizationId: String, petientId: String): UnPayedResponse {
+        val unPayedPatientIdList = ArrayList<String>()
+        unPayedPatientIdList.add(petientId)
+        val upPayedRequest = UnPayedRequest()
+        upPayedRequest.organizationId = organizationId
+        upPayedRequest.queryType = MedicalConstant.ORDER_QUERYTYPE_PATIENTID
+        upPayedRequest.patientIdList = unPayedPatientIdList
+        //根据患者id查询未支付账单
+        return medicalClient.getUnPayedList(upPayedRequest)
+    }
+
+    override fun getUnPayedList(uid: String, organizationId: String, cardId: String): List<UnPayedDTO> {
+        val medicalCard = medicalCardDao.findByCardidAndUid(cardId, uid)
+                ?: throw MedicineException("未找到该就诊卡")
+        //根据患者id查询未支付账单
+        val unPayedResponse = getUnPayedResponse(organizationId, medicalCard.patientid)
+        val unPayedDTOList = ArrayList<UnPayedDTO>()
+        //拆分每次就诊下的每个项目为一条展示数据
+        unPayedResponse.medicalInformation.forEach { medicalInformation ->
+            medicalInformation.mergingItems.forEach { mergingItems ->
+                val unPayedDTO = UnPayedDTO().apply {
+                    this.medicalDate = medicalInformation.medicalDate
+                    this.subjectName = medicalInformation.departmentName
+                    this.doctorName = medicalInformation.doctorName
+                    this.admNumber = medicalInformation.admNumber
+                    this.feeNo = mergingItems.feeNo
+                    this.mergingSubtotal = mergingItems.mergingSubtotal
+                }
+                unPayedDTOList.add(unPayedDTO)
+            }
+        }
+        return unPayedDTOList
+    }
+
+    override fun getPayedList(uid: String, organizationId: String, cardId: String): ArrayList<PayedDTO> {
+        val medicalCard = medicalCardDao.findByCardidAndUid(cardId, uid)
+                ?: throw MedicineException("未找到该就诊卡")
+        val payedPatientIdList = ArrayList<String>()
+        payedPatientIdList.add(medicalCard.patientid)
+        val payedRequest = PayedRequest()
+        payedRequest.organizationId = organizationId
+        payedRequest.queryType = MedicalConstant.ORDER_QUERYTYPE_PATIENTID
+        payedRequest.patientIdList = payedPatientIdList
+        payedRequest.executeFlag = MedicalConstant.PAYED_EXECUTEFLAG_INVALID
+        payedRequest.outpatientType = MedicalConstant.PAYED_OUTPATIENTTYPE_NORMAL
+        val payedResponse = medicalClient.getPayedList(payedRequest)
+        val payedDTOList = ArrayList<PayedDTO>()
+        //拆分每次就诊下的每个项目为一条展示数据
+        payedResponse.invoiceList.forEach { invoiceItem ->
+            invoiceItem.costList.forEach { costItem ->
+                val payedDTO = PayedDTO().apply {
+                    this.totalFee = costItem.totalFee
+                    this.medicalDate = invoiceItem.medicalDate
+                    this.executionStatus = costItem.executionStatus
+                    this.execute = costItem.execute
+                    this.mergingName = costItem.mergingName
+                    this.admNumber = invoiceItem.admNumber
+                }
+                payedDTOList.add(payedDTO)
+            }
+        }
+        return payedDTOList
+    }
+
+    override fun medicalPayInit(uid: String, bean: PaymentRequestBean, cardNo: String): JsonResult? {
+        val medicalCard = medicalCardDao.findByCardidAndUid(bean.cardid, uid)
+                ?: throw MedicineException("未找到该就诊卡")
+        //1.从HIS中找到待支付流水
+        //1.1 根据患者id查询未支付账单
+        val unPayedResponse = getUnPayedResponse(bean.organizationid, medicalCard.patientid)
+        var mergingItems: MergingItems? = null
+        unPayedResponse.medicalInformation.forEach { medicalInformation ->
+            if (medicalInformation.admNumber == bean.admnumber) {
+                medicalInformation.mergingItems.forEach { queryMergingItems ->
+                    if (queryMergingItems.feeNo == bean.feeno) {
+                        mergingItems = queryMergingItems
+                    }
+                }
+            }
+        }
+        if (mergingItems == null) {
+            throw MedicineException("未找到该条待缴费记录")
+        }
+        //2.向HIS预结算
+        val feeRecords = ArrayList<FeeRecordItem>()
+        feeRecords.add(FeeRecordItem().apply {
+            this.feeNo = mergingItems!!.feeNo
+            this.feeTypeCode = mergingItems!!.feeTypeCode
+            this.feeTypeName = mergingItems!!.mergingName
+        })
+
+        val preFeeRequest = PreFeeRequest().apply {
+            this.boilSign = mergingItems!!.boilSign
+            this.organizationId = bean.organizationid
+            this.feeRecords = feeRecords
+        }
+        val preFeeResponse = medicalClient.getPreCalculatedFee(preFeeRequest)
+        //查看本地是否有该条流水记录
+        val localMedicalDtl = medicalDtlDao.findByAdmnumberAndOrganizationidAndFeeno(bean.admnumber, bean.organizationid, mergingItems!!.feeNo)
+        if (localMedicalDtl != null) {
+            //锁住该条流水
+            medicalDtlDao.findByBillnoForUpdate(localMedicalDtl.billno)
+            if (localMedicalDtl.paystatus == MedicalConstant.DTL_STATUS_SUCCESS) {
+                return JsonResult.ok("该缴费已成功支付")
+            } else if (localMedicalDtl.paystatus == MedicalConstant.DTL_STATUS_WIP) {
+
+            }
+        }
+        //3.本地新建一条支付流水
+        val medicalDtl = TBMedicalDtl().apply {
+            this.billno = systemUtilService.refno
+            this.admnumber = bean.admnumber
+            this.feeno = mergingItems!!.feeNo
+            this.uid = uid
+            this.paystatus = MedicalConstant.DTL_STATUS_INIT
+            this.transdate = systemUtilService.sysdatetime.hostdate
+            this.transtime = systemUtilService.sysdatetime.hosttime
+            this.citizencardno = cardNo
+            this.payamount = preFeeResponse.payAmount
+            this.totalfee = preFeeResponse.totalFee
+            this.extrafeedesc = preFeeResponse.extraFeeDesc
+            this.invoiceno = preFeeResponse.invoiceNumber
+        }
+        medicalDtlDao.save(medicalDtl)
+        return JsonResult.ok()
+    }
+
+    override fun medicalPayConfirm(billno: String): JsonResult? {
+        //4.本地向payapi扣费
+        //4.1 payapi扣费初始化
+        val medicalDtl = medicalDtlDao.findByBillnoForUpdate(billno)
+        val initParam = CitizenCardPayinitParam().apply {
+            this.billno = medicalDtl.billno
+            this.cardNo = medicalDtl.citizencardno
+            this.amount = MoneyUtil.YuanToFen(medicalDtl.payamount)
+            this.dtltype = MedicalConstant.DTLTYPE_MEDICAL
+            this.transdate = medicalDtl.transdate
+            this.transtime = medicalDtl.transtime
+            this.shopaccno = systemUtilService.getBusinessValue(PortalConstant.SYSPARA_MEDICAL_SHOPACCNOm)
+        }
+        val payInit = citizenCardPayProxy.citizencardPayinit(initParam)
+        if (payInit.retcode == 0) {
+            throw MedicineException("向payapi请求异常:${payInit.retcode}-${payInit.retmsg}")
+        }
+        medicalDtl.refno = payInit.refno
+        medicalDtl.paystatus = MedicalConstant.DTL_STATUS_WIP
+        medicalDtlDao.save(medicalDtl)
+        //4.2 paypai扣费确认
+        val confirmParam = CitizenCardPayfinishParam().apply {
+            this.refno = medicalDtl.refno
+        }
+        val payConfirm = citizenCardPayProxy.citizencardPayFinish(confirmParam)
+        if (payConfirm.retcode != MedicalConstant.PAYAPI_SUCCESS_RETCODE) {
+            throw MedicineException("向payapi请求异常:${payConfirm.retcode}-${payConfirm.retmsg}")
+        }
+
+        //6.修改本地流水状态
+
+        medicalDtl.paystatus = MedicalConstant.DTL_STATUS_SUCCESS
+        medicalDtlDao.save(medicalDtl)
+        return JsonResult.ok()
+    }
+
+    fun notifyHIS() {
+
+        //5.向HIS支付确认
+        val notifyPayedRequest = NotifyPayedRequest().apply {
+
+        }
+        val notifyPayedResponse = medicalClient.notifyPayed(notifyPayedRequest)
     }
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
index fba92f8..e29742f 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
@@ -1032,7 +1032,7 @@
         }
         val card = cardResponse.card
         if (card.transStatus != TradeDict.STATUS_NORMAL) {
-            return JsonResult.error("卡状态非正常,不能挂失")
+            return JsonResult.error("您已挂失该卡,无须重复挂失")
         }
         card.transStatus = TradeDict.STATUS_LOST
         val response = userProxy.updateCardTransStatus(card.cardno, TradeDict.STATUS_LOST)
diff --git a/backend/src/main/resources/data-postgresql.sql b/backend/src/main/resources/data-postgresql.sql
index 9880a3d..06cac44 100644
--- a/backend/src/main/resources/data-postgresql.sql
+++ b/backend/src/main/resources/data-postgresql.sql
@@ -22,6 +22,9 @@
 INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('aes.cfb.iv', '55b6f5b3287c535f8274b99354676d0e', '{tenantid}');
 INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('portal.amapkey', 'd69cdfdc1711fc7c318eb7e1a0664976', '{tenantid}');
 INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('portal.amapurl', 'https://webapi.amap.com/maps?v=1.4.15&key=', '{tenentid}');
+INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('medical.url', 'http://1.10.10.252:8380/phis/', '{tenentid}');
+INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('medical.shopaccno', '462078377', '{tenentid}');
+
 
 
 INSERT INTO "tb_column"("columnid", "isleaf", "name", "needreview", "parentid", "code", "ispublic", "publishable", "ordernum") VALUES ('2c9cab947451988c017451a737b10000', '0', '线上活动', '0', '', 'OnlineActivities', '1', '1', 12);
diff --git a/frontend/src/utils/auth.js b/frontend/src/utils/auth.js
index 08a43d6..a851609 100644
--- a/frontend/src/utils/auth.js
+++ b/frontend/src/utils/auth.js
@@ -1,15 +1,14 @@
-import Cookies from 'js-cookie'
 
 const TokenKey = 'Admin-Token'
 
 export function getToken() {
-  return Cookies.get(TokenKey)
+  return sessionStorage.getItem(TokenKey)
 }
 
 export function setToken(token) {
-  return Cookies.set(TokenKey, token)
+  return sessionStorage.setItem(TokenKey, token)
 }
 
 export function removeToken() {
-  return Cookies.remove(TokenKey)
+  return sessionStorage.removeItem(TokenKey)
 }