现场需求修改
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/dao/CardDao.java b/payapi/src/main/java/com/supwisdom/dlpay/api/dao/CardDao.java
index 7781be6..4b3ace3 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/dao/CardDao.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/dao/CardDao.java
@@ -24,4 +24,12 @@
 
   @Query("from TCard t where cardtype='citizencard' and t.lastsaved>?1 and t.lastsaved<=?2 ")
   List<TCard> findCitizencardByLastsaved(String startdate, String enddate);
+
+  @Query("from TCard t where t.cardtype='citizencard' and t.cardphyid=?1 order by t.cardno")
+  List<TCard> findCitizencardByCardphyid(String cardphyid);
+
+  @Query("from TCard t where t.cardtype='citizencard' and t.cardphyid=?1 and t.id<>?2 order by t.cardno")
+  List<TCard> findCitizencardByCardphyidWithoutOldId(String cardphyid, String oldId);
+
+  TCard getById(String id);
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TAccount.java b/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TAccount.java
index 150f0cd..56e0cae 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TAccount.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/api/domain/TAccount.java
@@ -264,7 +264,7 @@
         + MoneyUtil.YuanToFen(this.availbal)
         + MoneyUtil.YuanToFen(this.balance)
         + MoneyUtil.YuanToFen(this.frozebal);
-    System.out.println("accno="+this.accno+",data="+data);
+//    System.out.println("accno="+this.accno+",data="+data);
     return Signature.generateTac(this.accno, data);
   }
 
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/util/Signature.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/util/Signature.java
index 184130f..a0173a0 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/util/Signature.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/util/Signature.java
@@ -16,7 +16,7 @@
     if (tenant == null) {
       throw new IllegalArgumentException("TenantID 未定义");
     }
-    System.out.println("factor="+factor+",data="+data+",tenant="+tenant);
+//    System.out.println("factor="+factor+",data="+data+",tenant="+tenant);
     return HMACUtil.sha256HMAC(deliveryKey(tenant, factor), data).substring(0, 24);
   }
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/framework/util/StringUtil.java b/payapi/src/main/java/com/supwisdom/dlpay/framework/util/StringUtil.java
index 628137b..adc71b5 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/framework/util/StringUtil.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/framework/util/StringUtil.java
@@ -221,4 +221,55 @@
     }
     return false;
   }
+
+  public static boolean isNumber(String inputStr) {
+    char[] ch = inputStr.toCharArray();
+    for (int i = 0; i < ch.length; i++) {
+      if ((ch[i] < '0') || (ch[i] > '9')) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  public static boolean isCardphyid(String str) {
+    if (null != str && str.matches("^[A-F0-9]+$")) {
+      return true;
+    }
+    return false;
+  }
+
+  private static char getBankCardCheckCode(String nonCheckCodeBankCard) {
+    if (nonCheckCodeBankCard == null || nonCheckCodeBankCard.trim().length() == 0 || !nonCheckCodeBankCard.matches("\\d+")) {
+      //如果传的不是数字返回N
+      return 'N';
+    }
+    char[] chs = nonCheckCodeBankCard.trim().toCharArray();
+    int luhmSum = 0;
+    for (int i = chs.length - 1, j = 0; i >= 0; i--, j++) {
+      int k = chs[i] - '0';
+      if (j % 2 == 0) {
+        k *= 2;
+        k = k / 10 + k % 10;
+      }
+      luhmSum += k;
+    }
+    return (luhmSum % 10 == 0) ? '0' : (char) ((10 - luhmSum % 10) + '0');
+  }
+
+  /**
+   * 判断是否是银行卡号
+   * */
+  public static boolean isBankcardno(String bankCard) {
+    if (bankCard.length() < 15 || bankCard.length() > 19) {
+      return false;
+    }
+    char bit = getBankCardCheckCode(bankCard.substring(0, bankCard.length() - 1));
+    if (bit == 'N') {
+      return false;
+    }
+    return bankCard.charAt(bankCard.length() - 1) == bit;
+  }
+
+
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/system/bean/CitizenCardShowBean.java b/payapi/src/main/java/com/supwisdom/dlpay/system/bean/CitizenCardShowBean.java
index b5c095d..5f4961b 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/system/bean/CitizenCardShowBean.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/system/bean/CitizenCardShowBean.java
@@ -17,6 +17,7 @@
   private String idno;
   private String mobile;
   private String email;
+  private String sex;
 
   public String getCid() {
     return cid;
@@ -145,4 +146,12 @@
   public void setEmail(String email) {
     this.email = email;
   }
+
+  public String getSex() {
+    return sex;
+  }
+
+  public void setSex(String sex) {
+    this.sex = sex;
+  }
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/system/controller/UserController.java b/payapi/src/main/java/com/supwisdom/dlpay/system/controller/UserController.java
index fe353a1..eb36de9 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/system/controller/UserController.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/system/controller/UserController.java
@@ -3,27 +3,22 @@
 import com.supwisdom.dlpay.api.bean.JsonResult;
 import com.supwisdom.dlpay.api.domain.TAccount;
 import com.supwisdom.dlpay.api.domain.TPerson;
-import com.supwisdom.dlpay.api.domain.TPersonIdentity;
 import com.supwisdom.dlpay.api.domain.TPointsAccount;
-import com.supwisdom.dlpay.framework.domain.TOperator;
-import com.supwisdom.dlpay.framework.util.Dictionary;
-import com.supwisdom.dlpay.framework.util.PageResult;
-import com.supwisdom.dlpay.framework.util.StringUtil;
-import com.supwisdom.dlpay.framework.util.WebConstant;
+import com.supwisdom.dlpay.framework.util.*;
 import com.supwisdom.dlpay.system.bean.CitizenCardSearchBean;
 import com.supwisdom.dlpay.system.bean.CitizenCardShowBean;
-import com.supwisdom.dlpay.system.bean.IdTypeBean;
 import com.supwisdom.dlpay.system.bean.PersonParamBean;
 import com.supwisdom.dlpay.system.service.DictionaryProxy;
 import com.supwisdom.dlpay.system.service.UserDataService;
+import com.supwisdom.dlpay.util.WebCheckException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.ModelMap;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.ArrayList;
-import java.util.List;
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
 
 @Controller
 public class UserController {
@@ -177,7 +172,7 @@
   @GetMapping("/user/cardlist")
   @PreAuthorize("hasPermission('/user/card','')")
   @ResponseBody
-  public PageResult<CitizenCardShowBean> getBusinessDataList(@RequestParam("page") Integer pageNo,
+  public PageResult<CitizenCardShowBean> getCitizenCardList(@RequestParam("page") Integer pageNo,
                                                              @RequestParam("limit") Integer pageSize,
                                                              @RequestParam(value = "cardno", required = false) String cardno,
                                                              @RequestParam(value = "cardphyid", required = false) String cardphyid,
@@ -194,4 +189,93 @@
       return new PageResult<>(99, "系统查询错误");
     }
   }
+
+  @GetMapping("/user/load4addcard")
+  @PreAuthorize("hasPermission('/user/load4addcard','')")
+  public String addCitizenCard() {
+    return "system/user/addcard";
+  }
+
+  @PostMapping("/user/cardadd")
+  @PreAuthorize("hasPermission('/user/cardadd','')")
+  @ResponseBody
+  public JsonResult addCitizencard(@RequestParam(value = "cardno", required = false) String cardno,
+                                   @RequestParam(value = "cardphyid", required = false) String cardphyid,
+                                   @RequestParam(value = "expiredate", required = false) String expiredate,
+                                   @RequestParam(value = "cardstatus", required = false) String cardstatus,
+                                   @RequestParam(value = "bankcardno", required = false) String bankcardno,
+                                   @RequestParam(value = "signstatus", required = false) String signstatus,
+                                   @RequestParam(value = "username", required = false) String username,
+                                   @RequestParam(value = "sex", required = false) String sex,
+                                   @RequestParam(value = "idtype", required = false) String idtype,
+                                   @RequestParam(value = "idno", required = false) String idno,
+                                   @RequestParam(value = "mobile", required = false) String mobile,
+                                   @RequestParam(value = "email", required = false) String email) {
+    try {
+      if (userDataService.doSaveNewCitizenCard(cardno, cardphyid, expiredate, cardstatus, bankcardno, signstatus, username, sex, idtype, idno, mobile, email)) {
+        return JsonResult.ok("新增成功!");
+      } else {
+        return JsonResult.error("新增失败!");
+      }
+    } catch (WebCheckException wce) {
+      return JsonResult.error(wce.getMessage());
+    } catch (Exception e) {
+      return dealViolationException(e, "新增异常!!");
+    }
+  }
+
+  private JsonResult dealViolationException(Exception e, String defaultErrmsg) {
+    String errmsg = "";
+    if (e instanceof ConstraintViolationException) {
+      ConstraintViolationException cve = (ConstraintViolationException) e;
+      if (null != cve.getConstraintViolations()) {
+        for (ConstraintViolation v : cve.getConstraintViolations()) {
+          errmsg += v.getMessage() + " ";
+        }
+      }
+    }
+    if (!StringUtil.isEmpty(errmsg)) {
+      return JsonResult.error(errmsg);
+    } else {
+      e.printStackTrace();
+      return JsonResult.error(defaultErrmsg);
+    }
+  }
+
+  @GetMapping("/user/load4modifycard")
+  @PreAuthorize("hasPermission('/user/load4modifycard','')")
+  public String load4UpdateCitizenCard() {
+    return "system/user/updatecard";
+  }
+
+  @PostMapping("/user/cardupdate")
+  @PreAuthorize("hasPermission('/user/cardupdate','')")
+  @ResponseBody
+  public JsonResult addCitizencard(@RequestParam(value = "cid") String cid,
+                                   @RequestParam(value = "bkid") String bkid,
+                                   @RequestParam(value = "cardno", required = false) String cardno,
+                                   @RequestParam(value = "cardphyid", required = false) String cardphyid,
+                                   @RequestParam(value = "expiredate", required = false) String expiredate,
+                                   @RequestParam(value = "cardstatus", required = false) String cardstatus,
+                                   @RequestParam(value = "bankcardno", required = false) String bankcardno,
+                                   @RequestParam(value = "signstatus", required = false) String signstatus,
+                                   @RequestParam(value = "username", required = false) String username,
+                                   @RequestParam(value = "sex", required = false) String sex,
+                                   @RequestParam(value = "idtype", required = false) String idtype,
+                                   @RequestParam(value = "idno", required = false) String idno,
+                                   @RequestParam(value = "mobile", required = false) String mobile,
+                                   @RequestParam(value = "email", required = false) String email) {
+    try {
+      if (userDataService.doUpdateCitizenCard(cid, bkid, cardno, cardphyid, expiredate, cardstatus, bankcardno, signstatus, username, sex, idtype, idno, mobile, email)) {
+        return JsonResult.ok("修改成功!");
+      } else {
+        return JsonResult.error("修改失败!");
+      }
+    } catch (WebCheckException wce) {
+      return JsonResult.error(wce.getMessage());
+    } catch (Exception e) {
+      return dealViolationException(e, "修改异常!!!");
+    }
+  }
+
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/system/service/UserDataService.java b/payapi/src/main/java/com/supwisdom/dlpay/system/service/UserDataService.java
index 3140f79..8cc7a5b 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/system/service/UserDataService.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/system/service/UserDataService.java
@@ -1,14 +1,12 @@
 package com.supwisdom.dlpay.system.service;
 
 import com.supwisdom.dlpay.api.bean.JsonResult;
-import com.supwisdom.dlpay.api.domain.TAccount;
-import com.supwisdom.dlpay.api.domain.TPerson;
-import com.supwisdom.dlpay.api.domain.TPersonIdentity;
-import com.supwisdom.dlpay.api.domain.TPointsAccount;
+import com.supwisdom.dlpay.api.domain.*;
 import com.supwisdom.dlpay.framework.util.PageResult;
 import com.supwisdom.dlpay.system.bean.CitizenCardSearchBean;
 import com.supwisdom.dlpay.system.bean.CitizenCardShowBean;
 import com.supwisdom.dlpay.system.bean.PersonParamBean;
+import com.supwisdom.dlpay.util.WebCheckException;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -48,4 +46,16 @@
      * */
     @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class,readOnly = true)
     PageResult<CitizenCardShowBean> getUserCitizenCardPage(CitizenCardSearchBean param, int pageNo, int pageSize);
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
+    boolean doSaveNewCitizenCard(String cardno, String cardphyid, String expiredate, String cardstatus, String bankcardno,
+                                 String signstatus, String username, String sex, String idtype, String idno, String mobile,
+                                 String email) throws Exception;
+
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
+    boolean doUpdateCitizenCard(String cid, String bkid, String cardno, String cardphyid, String expiredate, String cardstatus,
+                                String bankcardno, String signstatus, String username, String sex, String idtype, String idno,
+                                String mobile, String email) throws Exception;
+
 }
diff --git a/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/UserDataServiceImpl.java b/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/UserDataServiceImpl.java
index a42e636..01105f8 100644
--- a/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/UserDataServiceImpl.java
+++ b/payapi/src/main/java/com/supwisdom/dlpay/system/service/impl/UserDataServiceImpl.java
@@ -1,14 +1,10 @@
 package com.supwisdom.dlpay.system.service.impl;
 
 import com.supwisdom.dlpay.api.bean.JsonResult;
-import com.supwisdom.dlpay.api.dao.AccountDao;
-import com.supwisdom.dlpay.api.dao.PersonDao;
-import com.supwisdom.dlpay.api.dao.PersonIdentityDao;
-import com.supwisdom.dlpay.api.dao.PointsAccountDao;
-import com.supwisdom.dlpay.api.domain.TAccount;
-import com.supwisdom.dlpay.api.domain.TPerson;
-import com.supwisdom.dlpay.api.domain.TPersonIdentity;
-import com.supwisdom.dlpay.api.domain.TPointsAccount;
+import com.supwisdom.dlpay.api.dao.*;
+import com.supwisdom.dlpay.api.domain.*;
+import com.supwisdom.dlpay.api.types.IDTypes;
+import com.supwisdom.dlpay.api.types.SexTypes;
 import com.supwisdom.dlpay.framework.data.SystemDateTime;
 import com.supwisdom.dlpay.framework.service.SystemUtilService;
 import com.supwisdom.dlpay.framework.tenant.TenantContext;
@@ -17,6 +13,8 @@
 import com.supwisdom.dlpay.system.bean.CitizenCardShowBean;
 import com.supwisdom.dlpay.system.bean.PersonParamBean;
 import com.supwisdom.dlpay.system.service.UserDataService;
+import com.supwisdom.dlpay.util.ConstantUtil;
+import com.supwisdom.dlpay.util.WebCheckException;
 import org.hibernate.query.internal.NativeQueryImpl;
 import org.hibernate.transform.Transformers;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -29,6 +27,7 @@
 import javax.persistence.PersistenceContext;
 import javax.persistence.Query;
 import java.math.BigInteger;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
 
@@ -44,6 +43,8 @@
   private SystemUtilService systemUtilService;
   @Autowired
   private PersonIdentityDao personIdentityDao;
+  @Autowired
+  private CardDao cardDao;
 
   @PersistenceContext
   private EntityManager entityManager;
@@ -195,7 +196,7 @@
 
   @Override
   public PageResult<CitizenCardShowBean> getUserCitizenCardPage(CitizenCardSearchBean param, int pageNo, int pageSize) {
-    StringBuffer querySql = new StringBuffer("select t.id as cid,t.cardno,t.cardtype,t.cardphyid,case when t.status='closed' then 'closed' else t.trans_status end as status,t.expiredate,a.id as bkid,a.cardno as bankcardno,a.signed,t.lastsaved,t.userid,p.name as username,p.idtype,p.idno,p.mobile,p.email \n" +
+    StringBuffer querySql = new StringBuffer("select t.id as cid,t.cardno,t.cardtype,t.cardphyid,case when t.status='closed' then 'closed' else t.trans_status end as status,t.expiredate,a.id as bkid,a.cardno as bankcardno,a.signed,t.lastsaved,t.userid,p.name as username,p.idtype,p.idno,p.mobile,p.email,p.sex \n" +
         "from tb_card t left join tb_card a on a.cardtype='bankcard' and a.cardphyid=t.cardphyid and a.userid=t.userid left join tb_person p on p.userid=t.userid \n" +
         "where t.cardtype='citizencard' ");
     StringBuffer countSql = new StringBuffer("select count(t.id) as cnt \n" +
@@ -251,4 +252,331 @@
     BigInteger cnt = (BigInteger) countQuery.getSingleResult();
     return new PageResult<>(cnt.longValue(), list);
   }
+
+  private boolean checkCitizenCardData(String cardno, String cardphyid, String expiredate, String cardstatus, String bankcardno,
+                                       String signstatus, String username, String sex, String idtype, String idno, String mobile,
+                                       String email) throws WebCheckException {
+    if (StringUtil.isEmpty(cardno)) throw new WebCheckException("市民卡号不能为空");
+    if (!StringUtil.isNumber(cardno.trim())) throw new WebCheckException("请正确填写市民卡号");
+
+    if (StringUtil.isEmpty(cardphyid)) throw new WebCheckException("物理卡号不能为空");
+    if (!StringUtil.isCardphyid(cardphyid.trim()) || cardphyid.trim().length() != 8)
+      throw new WebCheckException("请正确填写八位物理卡号(八位十六进制数,字母大写)");
+
+    if (StringUtil.isEmpty(expiredate)) throw new WebCheckException("请填写卡有效期");
+    if (!DateUtil.checkDatetimeValid(expiredate.trim(), "yyyy-MM-dd")) throw new WebCheckException("请正确填写卡有效期");
+
+    if (StringUtil.isEmpty(cardstatus)) throw new WebCheckException("请选择卡状态");
+    if (!Arrays.asList(TradeDict.STATUS_NORMAL, TradeDict.STATUS_CLOSED, TradeDict.STATUS_ABNORMAL, TradeDict.STATUS_UNUSE).contains(cardstatus.trim()))
+      throw new WebCheckException("请正确选择卡状态");
+
+    if (StringUtil.isEmpty(bankcardno)) throw new WebCheckException("请填写银行卡号");
+    if (!StringUtil.isBankcardno(bankcardno.trim())) throw new WebCheckException("请正确填写银行卡号");
+
+    if (StringUtil.isEmpty(signstatus)) throw new WebCheckException("请选择银行卡签约状态");
+    if (!"0".equals(signstatus.trim()) && !"1".equals(signstatus.trim())) throw new WebCheckException("请选择银行卡签约状态");
+
+    if (StringUtil.isEmpty(username)) throw new WebCheckException("请填写姓名");
+
+    if (StringUtil.isEmpty(sex)) throw new WebCheckException("请选择性别");
+    if (Arrays.asList(SexTypes.ALL).contains(sex.trim())) throw new WebCheckException("请正确选择性别");
+
+    if (StringUtil.isEmpty(idtype)) throw new WebCheckException("请选择证件类别");
+    if (-999 == IDTypes.findByValue(idtype.trim())) throw new WebCheckException("请正确选择证件类别");
+
+    if (StringUtil.isEmpty(idno)) throw new WebCheckException("请填写证件号");
+    if (IDTypes.IDCARD.value().equals(idtype.trim()) && !StringUtil.isIdentity(idno.trim()))
+      throw new WebCheckException("请正确填写身份证号");
+
+    if (!StringUtil.isEmpty(mobile) && !StringUtil.isMobile(mobile.trim())) throw new WebCheckException("请正确填写手机号");
+    if (!StringUtil.isEmpty(email) && !StringUtil.isEmail(email.trim())) throw new WebCheckException("请正确填写电子邮箱");
+    return true;
+  }
+
+  @Override
+  public boolean doSaveNewCitizenCard(String cardno, String cardphyid, String expiredate, String cardstatus, String bankcardno,
+                                      String signstatus, String username, String sex, String idtype, String idno, String mobile,
+                                      String email) throws Exception {
+    if (checkCitizenCardData(cardno, cardphyid, expiredate, cardstatus, bankcardno, signstatus, username, sex, idtype, idno, mobile, email)) {
+      double maxbal = systemUtilService.getSysparaValueAsDouble(SysparaUtil.BALANCE_LIMIT, SysparaUtil.DEFAULT_BALANCE_LIMIT);
+      double lowfreeLimit = systemUtilService.getSysparaValueAsDouble(SysparaUtil.NOPASS_LIMIT, SysparaUtil.DEFAULT_NOPASS_LIMIT);
+      double daylimit = systemUtilService.getSysparaValueAsDouble(SysparaUtil.DAY_PAY_LIMIT, SysparaUtil.DEFAULT_DAY_PAY_LIMIT);
+
+      TCard cityCard = cardDao.findCardByCardnoAndCardtype(cardno.trim(), ConstantUtil.CARDTYPE_CITIZENCARD);
+      if (null != cityCard) throw new WebCheckException("市民卡号已经存在!");
+
+      TCard bankCard = cardDao.findCardByCardnoAndCardtype(bankcardno.trim(), ConstantUtil.CARDTYPE_BANKCARD);
+      if (null != bankCard) throw new WebCheckException("银行卡号已经存在!");
+
+      List<TCard> cardList = cardDao.findCitizencardByCardphyid(cardphyid.trim());
+      if (!StringUtil.isEmpty(cardList)) throw new WebCheckException("物理卡号已经存在!");
+
+      TPerson person = personDao.findByIdentity(idtype.trim(), idno.trim());
+      if (null != person && username.trim().equals(person.getName()))
+        throw new WebCheckException("证件号对应的用户已经存在,且姓名不匹配!");
+
+      SystemDateTime dt = systemUtilService.getSysdatetime();
+      if (null != person) {
+        boolean needUpdate = false;
+        if (!sex.trim().equals(person.getSex())) {
+          person.setSex(sex.trim());
+          needUpdate = true;
+        }
+        if (!StringUtil.isEmpty(mobile) && !mobile.trim().equals(person.getMobile())) {
+          person.setMobile(mobile.trim());
+          needUpdate = true;
+        }
+        if (!StringUtil.isEmpty(email) && !email.trim().equals(person.getEmail())) {
+          person.setEmail(email.trim());
+          needUpdate = true;
+        }
+        if (needUpdate) {
+          person.setLastsaved(dt.getHostdatetime());
+          personDao.save(person);
+        }
+      } else {
+        person = new TPerson();
+        person.setName(username.trim());
+        person.setSex(sex.trim());
+        person.setStatus(TradeDict.STATUS_NORMAL);
+        person.setIdtype(idtype.trim());
+        person.setIdno(idno.trim());
+        person.setEmail(null == email ? null : email.trim());
+        person.setMobile(null == mobile ? null : mobile.trim());
+        person.setLastsaved(dt.getHostdatetime());
+        person.setTenantid(TenantContext.getTenantSchema());
+        person = personDao.save(person);
+
+        TAccount account = new TAccount();
+        account.setAccname(person.getName());
+        account.setSubjno(Subject.SUBJNO_PERSONAL_DEPOSIT);
+        account.setUserid(person.getUserid());
+        account.setTransStatus(person.getStatus());
+        account.setBalance(0D);
+        account.setAvailbal(0D);
+        account.setFrozebal(0D);
+        account.setLowfreeFlag(false);
+        account.setLowfreeLimit(lowfreeLimit);
+        account.setDaylimit(daylimit);
+        account.setMaxbal(maxbal);
+        account.setLasttranstime(dt.getSysdate());
+        account.setLastdayDpsamt(0D);
+        account.setLastdayTransamt(0D);
+        account.setOpendate(dt.getHostdate());
+        account.setTac(Signature.SPY_TAC);
+        account.setTenantid(person.getTenantid());
+        account = accountDao.save(account);
+        account.setTac(account.generateTac());
+        accountDao.save(account);
+      }
+
+      cityCard = new TCard(); //新增市民卡
+      cityCard.setCardno(cardno.trim());
+      cityCard.setCardtype(ConstantUtil.CARDTYPE_CITIZENCARD);
+      cityCard.setCardphyid(cardphyid.trim());
+      cityCard.setStatus(TradeDict.STATUS_NORMAL);
+      cityCard.setTransStatus(cardstatus.trim());
+      if (TradeDict.STATUS_CLOSED.equals(cardstatus.trim())) {
+        cityCard.setStatus(TradeDict.STATUS_CLOSED);
+        cityCard.setTransStatus(TradeDict.STATUS_ABNORMAL);
+      }
+      cityCard.setExpiredate(DateUtil.unParseToDateFormat(expiredate.trim()));
+      cityCard.setSigned(false);
+      cityCard.setUserid(person.getUserid());
+      cityCard.setLastsaved(dt.getHostdatetime());
+      cityCard.setTenantid(person.getTenantid());
+      cardDao.save(cityCard);
+
+      bankCard = new TCard(); //新增银行卡
+      bankCard.setCardno(bankcardno.trim());
+      bankCard.setCardtype(ConstantUtil.CARDTYPE_BANKCARD);
+      bankCard.setCardphyid(cardphyid.trim());
+      bankCard.setStatus(TradeDict.STATUS_NORMAL);
+      bankCard.setTransStatus(TradeDict.STATUS_NORMAL);
+      if (TradeDict.STATUS_CLOSED.equals(cardstatus.trim())) {
+        bankCard.setStatus(TradeDict.STATUS_CLOSED);
+      }
+      bankCard.setExpiredate("21991231");
+      bankCard.setSigned("1".equals(signstatus.trim()));
+      bankCard.setUserid(person.getUserid());
+      bankCard.setLastsaved(dt.getHostdatetime());
+      bankCard.setTenantid(person.getTenantid());
+      if (TradeDict.STATUS_NORMAL.equals(bankCard.getStatus())) {
+        cardDao.closedBankcardStatusByUserid(bankCard.getUserid());  //注销其他银行卡
+      }
+      cardDao.save(bankCard);
+      return true;
+    }
+    return false;
+  }
+
+  private TCard findCardById(String id) {
+    if (!StringUtil.isEmpty(id)) return cardDao.getById(id.trim());
+    return null;
+  }
+
+  @Override
+  public boolean doUpdateCitizenCard(String cid, String bkid, String cardno, String cardphyid, String expiredate, String cardstatus,
+                                     String bankcardno, String signstatus, String username, String sex, String idtype, String idno,
+                                     String mobile, String email) throws Exception {
+    TCard cityCard = findCardById(cid);
+    TCard bankCard = findCardById(bkid);
+    if (null == cityCard || null == bankCard ||
+        !ConstantUtil.CARDTYPE_CITIZENCARD.equals(cityCard.getCardtype()) ||
+        !ConstantUtil.CARDTYPE_BANKCARD.equals(bankCard.getCardtype()) ||
+        !cityCard.getUserid().equals(bankCard.getUserid()) ||
+        !cityCard.getCardphyid().equals(bankCard.getCardphyid())) {
+      throw new WebCheckException("请求参数错误,请重新查询!");
+    }
+    TPerson person = personDao.findByUserid(cityCard.getUserid());
+    if(null==person) throw new WebCheckException("请求参数错误,请重新查询!");
+
+    if (checkCitizenCardData(cardno, cardphyid, expiredate, cardstatus, bankcardno, signstatus, username, sex, idtype, idno, mobile, email)) {
+      TPerson owner = null; //市民卡拥有者
+      SystemDateTime dt = systemUtilService.getSysdatetime();
+      if(idtype.trim().equals(person.getIdtype()) && idno.trim().equals(person.getIdno())){
+        //同一用户
+        if(!username.trim().equals(person.getName())) throw new WebCheckException("数据异常!证件号对应的用户已经存在,但姓名不匹配!");
+        owner = person;
+      }else{
+        //改变了所有者
+        TPerson newPerson = personDao.findByIdentity(idtype.trim(), idno.trim());
+        if(null!=newPerson && !username.trim().equals(newPerson.getName())) throw new WebCheckException("数据异常!证件号对应的用户已经存在,但姓名不匹配!");
+        if(null==newPerson){
+          //新增
+          double maxbal = systemUtilService.getSysparaValueAsDouble(SysparaUtil.BALANCE_LIMIT, SysparaUtil.DEFAULT_BALANCE_LIMIT);
+          double lowfreeLimit = systemUtilService.getSysparaValueAsDouble(SysparaUtil.NOPASS_LIMIT, SysparaUtil.DEFAULT_NOPASS_LIMIT);
+          double daylimit = systemUtilService.getSysparaValueAsDouble(SysparaUtil.DAY_PAY_LIMIT, SysparaUtil.DEFAULT_DAY_PAY_LIMIT);
+
+          newPerson = new TPerson();
+          newPerson.setName(username.trim());
+          newPerson.setSex(sex.trim());
+          newPerson.setStatus(TradeDict.STATUS_NORMAL);
+          newPerson.setIdtype(idtype.trim());
+          newPerson.setIdno(idno.trim());
+          newPerson.setEmail(null == email ? null : email.trim());
+          newPerson.setMobile(null == mobile ? null : mobile.trim());
+          newPerson.setLastsaved(dt.getHostdatetime());
+          newPerson.setTenantid(TenantContext.getTenantSchema());
+          newPerson = personDao.save(newPerson);
+
+          TAccount account = new TAccount();
+          account.setAccname(newPerson.getName());
+          account.setSubjno(Subject.SUBJNO_PERSONAL_DEPOSIT);
+          account.setUserid(newPerson.getUserid());
+          account.setTransStatus(newPerson.getStatus());
+          account.setBalance(0D);
+          account.setAvailbal(0D);
+          account.setFrozebal(0D);
+          account.setLowfreeFlag(false);
+          account.setLowfreeLimit(lowfreeLimit);
+          account.setDaylimit(daylimit);
+          account.setMaxbal(maxbal);
+          account.setLasttranstime(dt.getSysdate());
+          account.setLastdayDpsamt(0D);
+          account.setLastdayTransamt(0D);
+          account.setOpendate(dt.getHostdate());
+          account.setTac(Signature.SPY_TAC);
+          account.setTenantid(person.getTenantid());
+          account = accountDao.save(account);
+          account.setTac(account.generateTac());
+          accountDao.save(account);
+        }
+        owner = newPerson;
+      }
+      if(null== owner) throw new WebCheckException("业务处理异常!");
+
+      boolean needUpdate = false;
+      if (!sex.trim().equals(owner.getSex())) {
+        owner.setSex(sex.trim());
+        needUpdate = true;
+      }
+      if (!StringUtil.isEmpty(mobile) && !mobile.trim().equals(owner.getMobile())) {
+        owner.setMobile(mobile.trim());
+        needUpdate = true;
+      }
+      if (!StringUtil.isEmpty(email) && !email.trim().equals(owner.getEmail())) {
+        owner.setEmail(email.trim());
+        needUpdate = true;
+      }
+      if (needUpdate) {
+        owner.setLastsaved(dt.getHostdatetime());
+        personDao.save(owner);
+      }
+
+      boolean cardUpdate = false;
+      if(!cardno.trim().equals(cityCard.getCardno())){
+        //市民卡号变更
+        if (null != cardDao.findCardByCardnoAndCardtype(cardno.trim(), ConstantUtil.CARDTYPE_CITIZENCARD)) throw new WebCheckException("市民卡号已经存在");
+
+        cityCard.setCardno(cardno.trim());
+        cardUpdate = true;
+      }
+      if(!cardphyid.trim().equals(cityCard.getCardphyid())){
+        List<TCard> cardList = cardDao.findCitizencardByCardphyidWithoutOldId(cardphyid.trim(), cityCard.getId());
+        if (!StringUtil.isEmpty(cardList)) throw new WebCheckException("物理卡号已经存在!");
+
+        cityCard.setCardphyid(cardphyid.trim());
+        cardUpdate = true;
+      }
+
+      String newExpiredate = DateUtil.unParseToDateFormat(expiredate);
+      if(!newExpiredate.equals(cityCard.getExpiredate())){
+        cityCard.setExpiredate(newExpiredate);
+        cardUpdate = true;
+      }
+
+      if (TradeDict.STATUS_CLOSED.equals(cardstatus.trim())) {
+        if (!TradeDict.STATUS_CLOSED.equals(cityCard.getStatus())) {
+          cityCard.setStatus(TradeDict.STATUS_CLOSED);
+          cardUpdate = true;
+        }
+      } else if (!cardstatus.trim().equals(cityCard.getTransStatus())) {
+        cityCard.setTransStatus(cardstatus.trim());
+        cardUpdate = true;
+      }
+      if(!cityCard.getUserid().equals(owner.getUserid())){
+        cityCard.setUserid(owner.getUserid());
+        cardUpdate = true;
+      }
+
+      if(cardUpdate){
+        cityCard.setLastsaved(dt.getHostdatetime());
+        cardDao.save(cityCard);
+      }
+
+      boolean bankcardUpdate = false;
+      if(!bankcardno.trim().equals(bankCard.getCardno())){
+        if (null != cardDao.findCardByCardnoAndCardtype(bankcardno.trim(), ConstantUtil.CARDTYPE_BANKCARD)) throw new WebCheckException("银行卡号已经存在");
+        bankCard.setCardno(bankcardno.trim());
+        bankCard.setSigned("1".equals(signstatus));
+        bankcardUpdate = true;
+      }
+      if(!cardphyid.trim().equals(bankCard.getCardphyid())){
+        bankCard.setCardphyid(cityCard.getCardphyid());
+        bankcardUpdate = true;
+      }
+      if(TradeDict.STATUS_CLOSED.equals(cardstatus.trim()) && !TradeDict.STATUS_CLOSED.equals(bankCard.getStatus())){
+        bankCard.setStatus(TradeDict.STATUS_CLOSED);
+        bankcardUpdate = true;
+      }
+      if(!bankCard.getSigned().equals("1".equals(signstatus.trim()))){
+        bankCard.setSigned("1".equals(signstatus.trim()));
+        bankcardUpdate = true;
+      }
+
+      if(!bankCard.getUserid().equals(owner.getUserid())){
+        bankCard.setUserid(cityCard.getUserid());
+        bankcardUpdate = true;
+      }
+
+      if(bankcardUpdate){
+        bankCard.setLastsaved(dt.getHostdatetime());
+        cardDao.save(bankCard);
+      }
+
+      return true;
+    }
+    return false;
+  }
 }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/card_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/card_service_impl.kt
index 4981023..210c331 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/card_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/card_service_impl.kt
@@ -55,6 +55,7 @@
         var resp = UserInforResponse()
         var cityCard: TCard?
         if (!citizencardno.isNullOrEmpty()) {
+            //根据市民卡号查询
             cityCard = cardDao.findCardByCardnoAndCardtype(citizencardno, ConstantUtil.CARDTYPE_CITIZENCARD)
             if (cityCard == null) {
                 resp.retcode = 1
@@ -65,6 +66,21 @@
             if (bankcard != null) {
                 resp.bankcardno = bankcard.cardno
             }
+        } else if (!bankcardno.isNullOrEmpty()) {
+            //根据银行卡号查询
+            val bankcard = cardDao.findCardByCardnoAndCardtype(bankcardno?.trim(), ConstantUtil.CARDTYPE_BANKCARD)
+            if (bankcard == null) {
+                resp.retcode = 1
+                resp.retmsg = "银行卡不存在"
+                return resp
+            }
+            resp.bankcardno = bankcard.cardno
+            cityCard = cardDao.findBankcardByCitizencard(bankcard.userid, ConstantUtil.CARDTYPE_CITIZENCARD, bankcard.cardphyid)
+            if (cityCard == null) {
+                resp.retcode = 1
+                resp.retmsg = "市民卡不存在"
+                return resp
+            }
         } else {
             resp.retcode = 1
             resp.retmsg = "参数错误"
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/shop_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/shop_service_impl.kt
index fde2ac5..b0dbb6b 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/shop_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/shop_service_impl.kt
@@ -14,6 +14,7 @@
 import com.supwisdom.dlpay.framework.domain.TShop
 import com.supwisdom.dlpay.framework.domain.TShopacc
 import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.tenant.TenantContext
 import com.supwisdom.dlpay.framework.util.*
 import com.supwisdom.dlpay.util.EnumCheck
 import org.springframework.beans.factory.annotation.Autowired
@@ -111,8 +112,8 @@
 
     override fun checkDownloadShopBillParam(param: DownloadShopBillParam): Boolean {
         if (!StringUtil.isEmpty(param.checkdate)) {
-            val ctl = settleCtlDao.findByTenantId(param.tenantid)
-                    ?: throw TransactionProcessException(TradeErrorCode.BUSINESS_DEAL_ERROR, "[tenantid=${param.tenantid}]未找到结算状态表")
+            val ctl = settleCtlDao.findByTenantId(TenantContext.getTenantSchema())
+                    ?: throw TransactionProcessException(TradeErrorCode.BUSINESS_DEAL_ERROR, "[tenantid=${TenantContext.getTenantSchema()}]未找到结算状态表")
             if (DateUtil.compareDatetime(param.checkdate, "${ctl.settledate}", "yyyyMMdd") >= 0) {
                 throw TransactionProcessException(TradeErrorCode.INPUT_DATA_ERROR, "对账单未生成") //未结算,不返回对账单
             }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_reconciliation_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_reconciliation_service_impl.kt
index b368d5a..9937a31 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_reconciliation_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/api/service/impl/transaction_reconciliation_service_impl.kt
@@ -185,7 +185,7 @@
             //需要补账
             chkdtl.chkresult = ConstantUtil.CHKDTL_CHKRESULT_NOCHARGE
             chkdtl.resolved = ConstantUtil.CHKDTL_RESOLVED_ADD
-            chkdtl.remark = "本地未入账,需要补助"
+            chkdtl.remark = "本地未入账,需要补帐"
             transactionChkdtlDao.save(chkdtl) //对账明细表更新
         }
     }
diff --git a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt
index 38f1499..b997a61 100644
--- a/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt
+++ b/payapi/src/main/kotlin/com/supwisdom/dlpay/framework/service/impl/framework_service_impl.kt
@@ -34,7 +34,7 @@
             ver += Manifests.read("Payapi-Buildtime") ?: "no"
             ver
         } catch (ex: Exception) {
-            ex.printStackTrace()
+//            ex.printStackTrace()
             "unknown"
         }
     }
diff --git a/payapi/src/main/resources/data.sql b/payapi/src/main/resources/data.sql
index cefb007..bcdf83c 100644
--- a/payapi/src/main/resources/data.sql
+++ b/payapi/src/main/resources/data.sql
@@ -303,7 +303,14 @@
 VALUES (90, '', 37, '查询', '/user/card', '{tenantid}');
 INSERT INTO "tb_resource" ("id", "code", "function_id", "name", "uri", tenantid)
 VALUES (91, '', 38, '查询', '/report/shoptodaybusiness', '{tenantid}');
-
+INSERT INTO "tb_resource" ("id", "code", "function_id", "name", "uri", tenantid)
+VALUES (92, '', 37, '新增跳转', '/user/load4addcard', '{tenantid}');
+INSERT INTO "tb_resource" ("id", "code", "function_id", "name", "uri", tenantid)
+VALUES (93, '', 37, '新增', '/user/cardadd', '{tenantid}');
+INSERT INTO "tb_resource" ("id", "code", "function_id", "name", "uri", tenantid)
+VALUES (94, '', 37, '修改跳转', '/user/load4modifycard', '{tenantid}');
+INSERT INTO "tb_resource" ("id", "code", "function_id", "name", "uri", tenantid)
+VALUES (95, '', 37, '修改', '/user/cardupdate', '{tenantid}');
 
 INSERT INTO "tb_permission" ("id", "resid", "role_func_id", "roleid", tenantid)
 VALUES ('ff8080816b7947ed016b795577300036', 16, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs', '{tenantid}');
@@ -461,6 +468,15 @@
 VALUES ('ff8080816db87e27016db9446fda008b', 90, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs', '{tenantid}');
 INSERT INTO  "tb_permission" ("id", "resid", "role_func_id", "roleid", "tenantid")
 VALUES ('4028ee9f6e5d95d8016e5d99e8dd0013', 91, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs', '{tenantid}');
+INSERT INTO  "tb_permission" ("id", "resid", "role_func_id", "roleid", "tenantid")
+VALUES ('ff8080816ec5cfd5016ec5d16d470006', 92, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs', '{tenantid}');
+INSERT INTO  "tb_permission" ("id", "resid", "role_func_id", "roleid", "tenantid")
+VALUES ('ff8080816ec5cfd5016ec5d16d470007', 93, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs', '{tenantid}');
+INSERT INTO  "tb_permission" ("id", "resid", "role_func_id", "roleid", "tenantid")
+VALUES ('ff8080816ecaebf8016ecaeedcec0004', 94, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs', '{tenantid}');
+INSERT INTO  "tb_permission" ("id", "resid", "role_func_id", "roleid", "tenantid")
+VALUES ('ff8080816ecafb4e016ecafd58400005', 95, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs', '{tenantid}');
+
 
 
 INSERT INTO "tb_subject" ("subjid","subjno", "balflag", "displayflag", "endflag", "fsubjno", "opendate", "subjlevel", "subjname", "subjtype", "tenantid")
diff --git a/payapi/src/main/resources/templates/system/user/addcard.html b/payapi/src/main/resources/templates/system/user/addcard.html
new file mode 100644
index 0000000..0151106
--- /dev/null
+++ b/payapi/src/main/resources/templates/system/user/addcard.html
@@ -0,0 +1,175 @@
+<form id="citizencard-add-form" lay-filter="citizencard-add-form" class="layui-form model-form">
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>市民卡号</label>
+            <div class="layui-input-inline">
+                <input name="cardno" placeholder="请输入市民卡号" type="text" class="layui-input" maxlength="10"
+                       autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>物理卡号</label>
+            <div class="layui-input-inline">
+                <input name="cardphyid" placeholder="请输入电子物理卡号" type="text" class="layui-input" maxlength="8"
+                       autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>卡有效期</label>
+            <div class="layui-input-inline">
+                <input name="expiredate" placeholder="请选择卡有效期" type="text" class="layui-input" maxlength="10"
+                       id="citizencard-add-expiredate" autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>卡状态</label>
+            <div class="layui-input-inline">
+                <select name="cardstatus" class="layui-input layui-select" lay-verify="required">
+                    <option value="normal" selected>1_正常</option>
+                    <option value="closed">9_注销</option>
+                    <option value="abnormal">2_异常</option>
+                    <option value="unuse">0_未启用</option>
+                </select>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>银行卡号</label>
+            <div class="layui-input-inline">
+                <input name="bankcardno" placeholder="请填写银行卡号" type="text" class="layui-input" maxlength="19"
+                       autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>签约状态</label>
+            <div class="layui-input-inline">
+                <select name="signstatus" class="layui-input layui-select" lay-verify="required">
+                    <option value="0" selected>未签约</option>
+                    <option value="1">已签约</option>
+                </select>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>姓名</label>
+            <div class="layui-input-inline">
+                <input name="username" placeholder="请填写姓名" type="text" class="layui-input" maxlength="20"
+                       autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>性别</label>
+            <div class="layui-input-inline">
+                <select name="sex" class="layui-input layui-select" lay-verify="required">
+                    <option value="male" selected>男</option>
+                    <option value="female">女</option>
+                    <option value="unknown">未知</option>
+                </select>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>证件类型</label>
+            <div class="layui-input-inline">
+                <select name="idtype" class="layui-input layui-select" lay-verify="required">
+                    <option value="idcard" selected>0_身份证</option>
+                    <option value="residence_booklet">1_户口簿</option>
+                    <option value="passport">2_护照</option>
+                    <option value="hk_macau_pass">3_港澳居民来往内地通行证</option>
+                    <option value="taiwan_pass">4_台湾同胞来往内地通行证</option>
+                    <option value="foreigner_residence_permit">5_外国人居留证</option>
+                    <option value="military_idcard">6_军官证</option>
+                    <option value="soldier_idcard">7_士兵证</option>
+                    <option value="unknown">9_其他</option>
+                </select>
+            </div>
+        </div>
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>证件号</label>
+            <div class="layui-input-inline">
+                <input name="idno" placeholder="请输入证件号" type="text" class="layui-input" maxlength="18"
+                       autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label">手机号</label>
+            <div class="layui-input-inline">
+                <input name="mobile" placeholder="请输入手机号" type="text" class="layui-input" maxlength="11"
+                       autocomplete="off"/>
+            </div>
+        </div>
+        <div class="layui-inline">
+            <label class="layui-form-label">邮箱</label>
+            <div class="layui-input-inline">
+                <input name="email" placeholder="请输入邮箱" type="text" class="layui-input" maxlength="60" autocomplete="off"/>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item model-form-footer">
+        <button class="layui-btn" lay-filter="citizencard-add-form-submit" lay-submit  id="citizencard-add-ok">保存</button>
+        <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button>
+    </div>
+</form>
+
+<script>
+    layui.use(['layer', 'admin', 'form', 'laydate'], function () {
+        var layer = layui.layer;
+        var admin = layui.admin;
+        var form = layui.form;
+        var laydate = layui.laydate;
+
+        form.render('select');
+        laydate.render({
+            elem: '#citizencard-add-expiredate',
+            trigger: 'click'
+        });
+
+        // 表单提交事件
+        form.on('submit(citizencard-add-form-submit)', function (data) {
+            layer.load(2);
+            var token_name = $("meta[name='_csrf_token']").attr("content");
+            var token = $("meta[name='_csrf_token']").attr("value");
+            data.field[token_name] = token;
+            $.ajax({
+                type : "POST",
+                dataType : "json",
+                url : '[[@{/user/cardadd}]]',
+                data : data.field,
+                success : function(result) {
+                    layer.closeAll('loading');
+                    if (result.code === 200) {
+                        layer.msg(result.msg, {icon: 1});
+                        admin.putTempData('t_addCityNo', data.field.cardno);
+                        admin.finishPopupCenter();
+                    } else if (result.code === 401) {
+                        layer.msg(result.msg, {icon: 2, time: 1500}, function () {
+                            location.replace('[[@{/login}]]');
+                        }, 1000);
+                    } else {
+                        console.log('err:' + result.code);
+                        layer.msg(result.msg, {icon: 2});
+                    }
+                },
+                error : function(err) {
+                    admin.errorBack(err);
+                }
+            });
+            return false;
+        });
+    });
+</script>
\ No newline at end of file
diff --git a/payapi/src/main/resources/templates/system/user/card.html b/payapi/src/main/resources/templates/system/user/card.html
index 138d2b9..251daa4 100644
--- a/payapi/src/main/resources/templates/system/user/card.html
+++ b/payapi/src/main/resources/templates/system/user/card.html
@@ -44,6 +44,13 @@
                                autocomplete="off" class="layui-input"/>
                     </div>
                 </div>
+                <div class="layui-inline" style="margin-right: 20px;margin-top: 10px;">
+                    <label class="layui-form-label">&nbsp;</label>
+                    <div class="layui-input-block" style="width: 265px;">
+                        <button id="citizencard-search-btn" class="layui-btn icon-btn"><i class="layui-icon">&#xe615;</i>搜 索</button>
+                        <button id="citizencard-search-btn-reset" class="layui-btn layui-btn-primary">清 空</button>
+                    </div>
+                </div>
             </div>
         </div>
     </div>
@@ -54,10 +61,10 @@
 
 <script type="text/html" id="citizencard-table-toolbar">
     <div class="layui-btn-container">
-        <button class="layui-btn layui-btn-sm" id="btn-citizencard-search-ok" lay-event="search"><i
-                class="layui-icon">&#xe615;</i>搜 索</button>
-        <button class="layui-btn layui-btn-sm" id="btn-citizencard-search-clear" lay-event="clear"><i
-                class="layui-icon"></i>清 空</button>
+        <button class="layui-btn layui-btn-sm" id="btn-citizencard-add" lay-event="add"><i
+                class="layui-icon">&#xe654;</i>新 增</button>
+        <button class="layui-btn layui-btn-sm layui-btn-normal" id="btn-citizencard-modify" lay-event="modify"><i
+                class="layui-icon">&#xe642;</i>修 改</button>
     </div>
 </script>
 
@@ -76,6 +83,7 @@
             toolbar: '#citizencard-table-toolbar',
             cols: [
                 [
+                    {type:'radio', align: 'center', width: 35, fixed: 'left'},
                     {field:'cardno',title:'市民卡号', align: 'center', width: 120, fixed: 'left', sort: true},
                     {field:'cardphyid',title:'物理卡号', align: 'center', width: 120, fixed: 'left'},
                     {
@@ -137,25 +145,64 @@
             ]
         });
 
+        $("#citizencard-search-btn").click(function(){
+            table.reload('citizencardSearchTable', {
+                where: {
+                    cardno: $("#citizencard-search-cardno").val(),
+                    cardphyid: $("#citizencard-search-cardphyid").val(),
+                    bankcardno: $("#citizencard-search-bankcardno").val(),
+                    username: $("#citizencard-search-username").val(),
+                    idno: $("#citizencard-search-idno").val()
+                }, page: {curr: 1}
+            });
+        });
+
+        $("#citizencard-search-btn-reset").click(function(){
+            $("#citizencard-search-cardno").val("");
+            $("#citizencard-search-cardphyid").val("");
+            $("#citizencard-search-bankcardno").val("");
+            $("#citizencard-search-username").val("");
+            $("#citizencard-search-idno").val("");
+        });
+
         table.on('toolbar(citizencardSearchTable-filter)', function (obj) {
             switch (obj.event) {
-                case 'search':
-                    table.reload('citizencardSearchTable', {
-                        where: {
-                            cardno: $("#citizencard-search-cardno").val(),
-                            cardphyid: $("#citizencard-search-cardphyid").val(),
-                            bankcardno: $("#citizencard-search-bankcardno").val(),
-                            username: $("#citizencard-search-username").val(),
-                            idno: $("#citizencard-search-idno").val()
-                        }, page: {curr: 1}
+                case 'add':
+                    admin.popupCenter({
+                        title: '添加市民卡',
+                        area: '700px',
+                        path: '[[@{/user/load4addcard}]]',
+                        finish: function () {
+                            var tmpNo = admin.getTempData('t_addCityNo');
+                            if(undefined !=tmpNo && !isempty(tmpNo)){
+                                table.reload('citizencardSearchTable', { where: {cardno: tmpNo}, page: {curr: 1} });
+                            }else{
+                                table.reload('citizencardSearchTable', {});
+                            }
+                        }
                     });
                     break;
-                case 'clear':
-                    $("#citizencard-search-cardno").val("");
-                    $("#citizencard-search-cardphyid").val("");
-                    $("#citizencard-search-bankcardno").val("");
-                    $("#citizencard-search-username").val("");
-                    $("#citizencard-search-idno").val("");
+                case 'modify':
+                    var checkStatus = table.checkStatus('citizencardSearchTable');
+                    if(checkStatus.data.length ==0){
+                        layer.msg("请先选中要修改的市民卡", {icon: 2, time: 1500});
+                        return;
+                    }
+                    admin.putTempData('t_citycard', checkStatus.data[0]);
+                    admin.popupCenter({
+                        title: '修改市民卡',
+                        area: '700px',
+                        path: '[[@{/user/load4modifycard}]]',
+                        finish: function () {
+                            var tmpUpNo = admin.getTempData('t_updateCityNo');
+                            console.log("xx",tmpUpNo);
+                            if(undefined !=tmpUpNo && !isempty(tmpUpNo)){
+                                table.reload('citizencardSearchTable', { where: {cardno: tmpUpNo}, page: {curr: 1} });
+                            }else{
+                                table.reload('citizencardSearchTable', {});
+                            }
+                        }
+                    });
                     break;
             }
         });
diff --git a/payapi/src/main/resources/templates/system/user/updatecard.html b/payapi/src/main/resources/templates/system/user/updatecard.html
new file mode 100644
index 0000000..7e1cb74
--- /dev/null
+++ b/payapi/src/main/resources/templates/system/user/updatecard.html
@@ -0,0 +1,208 @@
+<form id="citizencard-modify-form" lay-filter="citizencard-modify-form" class="layui-form model-form">
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>市民卡号</label>
+            <div class="layui-input-inline">
+                <input type="hidden" name="cid" class="layui-input"/>
+                <input type="hidden" name="bkid" class="layui-input"/>
+                <input name="cardno" placeholder="请输入市民卡号" type="text" class="layui-input" maxlength="10"
+                       autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>物理卡号</label>
+            <div class="layui-input-inline">
+                <input name="cardphyid" placeholder="请输入电子物理卡号" type="text" class="layui-input" maxlength="8"
+                       autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>卡有效期</label>
+            <div class="layui-input-inline">
+                <input name="expiredate" placeholder="请选择卡有效期" type="text" class="layui-input" maxlength="10"
+                       id="citizencard-modify-expiredate" autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>卡状态</label>
+            <div class="layui-input-inline">
+                <select name="cardstatus" class="layui-input layui-select" lay-verify="required">
+                    <option value="normal" selected>1_正常</option>
+                    <option value="closed">9_注销</option>
+                    <option value="abnormal">2_异常</option>
+                    <option value="unuse">0_未启用</option>
+                </select>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>银行卡号</label>
+            <div class="layui-input-inline">
+                <input name="bankcardno" placeholder="请填写银行卡号" type="text" class="layui-input" maxlength="19"
+                       autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>签约状态</label>
+            <div class="layui-input-inline">
+                <select name="signstatus" class="layui-input layui-select" lay-verify="required">
+                    <option value="0" selected>未签约</option>
+                    <option value="1">已签约</option>
+                </select>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>姓名</label>
+            <div class="layui-input-inline">
+                <input name="username" placeholder="请填写姓名" type="text" class="layui-input" maxlength="20"
+                       autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>性别</label>
+            <div class="layui-input-inline">
+                <select name="sex" class="layui-input layui-select" lay-verify="required">
+                    <option value="male" selected>男</option>
+                    <option value="female">女</option>
+                    <option value="unknown">未知</option>
+                </select>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>证件类型</label>
+            <div class="layui-input-inline">
+                <select name="idtype" class="layui-input layui-select" lay-verify="required">
+                    <option value="idcard" selected>0_身份证</option>
+                    <option value="residence_booklet">1_户口簿</option>
+                    <option value="passport">2_护照</option>
+                    <option value="hk_macau_pass">3_港澳居民来往内地通行证</option>
+                    <option value="taiwan_pass">4_台湾同胞来往内地通行证</option>
+                    <option value="foreigner_residence_permit">5_外国人居留证</option>
+                    <option value="military_idcard">6_军官证</option>
+                    <option value="soldier_idcard">7_士兵证</option>
+                    <option value="unknown">9_其他</option>
+                </select>
+            </div>
+        </div>
+        <div class="layui-inline">
+            <label class="layui-form-label"><span style="color: red;">*</span>证件号</label>
+            <div class="layui-input-inline">
+                <input name="idno" placeholder="请输入证件号" type="text" class="layui-input" maxlength="18"
+                       autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label">手机号</label>
+            <div class="layui-input-inline">
+                <input name="mobile" placeholder="请输入手机号" type="text" class="layui-input" maxlength="11"
+                       autocomplete="off"/>
+            </div>
+        </div>
+        <div class="layui-inline">
+            <label class="layui-form-label">邮箱</label>
+            <div class="layui-input-inline">
+                <input name="email" placeholder="请输入邮箱" type="text" class="layui-input" maxlength="60" autocomplete="off"/>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item model-form-footer">
+        <button class="layui-btn" lay-filter="citizencard-modify-form-submit" lay-submit  id="citizencard-modify-ok">保存</button>
+        <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button>
+    </div>
+</form>
+
+<script>
+    layui.use(['layer', 'admin', 'form', 'laydate'], function () {
+        var layer = layui.layer;
+        var admin = layui.admin;
+        var form = layui.form;
+        var laydate = layui.laydate;
+
+        form.render('select');
+        laydate.render({
+            elem: '#citizencard-modify-expiredate',
+            trigger: 'click'
+        });
+
+        //回显数据
+        var cardBean = admin.getTempData('t_citycard');
+        if (cardBean) {
+            console.log("修改市民卡回显:",cardBean);
+            form.val('citizencard-modify-form', {
+                cid:cardBean.cid,
+                bkid:cardBean.bkid,
+                cardno:cardBean.cardno,
+                cardphyid:cardBean.cardphyid,
+                expiredate:dateFormat(cardBean.expiredate),
+                cardstatus:updateCardStatus(cardBean.status),
+                bankcardno:cardBean.bankcardno,
+                signstatus: cardBean.signed?'1':'0',
+                username:cardBean.username,
+                sex:cardBean.sex,
+                idtype:cardBean.idtype,
+                idno:cardBean.idno,
+                mobile:cardBean.mobile,
+                email:cardBean.email
+            });
+        }
+
+        function updateCardStatus(stat){
+            if('normal' == stat || 'closed' == stat || 'abnormal'==stat || 'unuse' == stat){
+                return stat;
+            }
+            return 'abnormal';
+        }
+
+        // 表单提交事件
+        form.on('submit(citizencard-modify-form-submit)', function (data) {
+            layer.confirm("卡管系统同步数据,请谨慎修改!确定要保存修改吗?", function () {
+                layer.load(2);
+                var token_name = $("meta[name='_csrf_token']").attr("content");
+                var token = $("meta[name='_csrf_token']").attr("value");
+                data.field[token_name] = token;
+                $.ajax({
+                    type : "POST",
+                    dataType : "json",
+                    url : '[[@{/user/cardupdate}]]',
+                    data : data.field,
+                    success : function(result) {
+                        layer.closeAll('loading');
+                        if (result.code === 200) {
+                            layer.msg(result.msg, {icon: 1});
+                            admin.putTempData('t_updateCityNo', data.field.cardno);
+                            admin.finishPopupCenter();
+                        } else if (result.code === 401) {
+                            layer.msg(result.msg, {icon: 2, time: 1500}, function () {
+                                location.replace('[[@{/login}]]');
+                            }, 1000);
+                        } else {
+                            console.log('err:' + result.code);
+                            layer.msg(result.msg, {icon: 2});
+                        }
+                    },
+                    error : function(err) {
+                        admin.errorBack(err);
+                    }
+                });
+            });
+            return false;
+        });
+    });
+</script>
\ No newline at end of file