新增了流水查询及水控设备参数管理功能
diff --git a/src/main/java/com/supwisdom/dlpay/framework/util/WaterDeviceParam.java b/src/main/java/com/supwisdom/dlpay/framework/util/WaterDeviceParam.java
new file mode 100644
index 0000000..25df4ed
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/util/WaterDeviceParam.java
@@ -0,0 +1,10 @@
+package com.supwisdom.dlpay.framework.util;
+
+public class WaterDeviceParam {
+    //  设备最大脱机时间
+    public static final String devOfflineMaxHour = "devOfflineMaxHour";
+    //  每百毫升脉冲数
+    public static final String pulseInHML = "pulseInHML";
+    //  系统时间
+    public static final String systemTime = "systemTime";
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/bean/AreaparaSearchBean.java b/src/main/java/com/supwisdom/dlpay/water/bean/AreaparaSearchBean.java
new file mode 100644
index 0000000..92a411c
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/bean/AreaparaSearchBean.java
@@ -0,0 +1,15 @@
+package com.supwisdom.dlpay.water.bean;
+
+import com.supwisdom.dlpay.system.bean.PageBean;
+
+public class AreaparaSearchBean extends PageBean {
+    private String groupname;
+
+    public String getGroupname() {
+        return groupname;
+    }
+
+    public void setGroupname(String groupname) {
+        this.groupname = groupname;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/system/bean/DeviceSearchBean.java b/src/main/java/com/supwisdom/dlpay/water/bean/DeviceSearchBean.java
similarity index 94%
rename from src/main/java/com/supwisdom/dlpay/water/system/bean/DeviceSearchBean.java
rename to src/main/java/com/supwisdom/dlpay/water/bean/DeviceSearchBean.java
index 3fdd0a8..f278dd0 100644
--- a/src/main/java/com/supwisdom/dlpay/water/system/bean/DeviceSearchBean.java
+++ b/src/main/java/com/supwisdom/dlpay/water/bean/DeviceSearchBean.java
@@ -1,4 +1,4 @@
-package com.supwisdom.dlpay.water.system.bean;
+package com.supwisdom.dlpay.water.bean;
 
 import com.supwisdom.dlpay.system.bean.PageBean;
 
diff --git a/src/main/java/com/supwisdom/dlpay/water/system/bean/RegionSearchBean.java b/src/main/java/com/supwisdom/dlpay/water/bean/RegionSearchBean.java
similarity index 90%
rename from src/main/java/com/supwisdom/dlpay/water/system/bean/RegionSearchBean.java
rename to src/main/java/com/supwisdom/dlpay/water/bean/RegionSearchBean.java
index c5f1cdd..2eb40ee 100644
--- a/src/main/java/com/supwisdom/dlpay/water/system/bean/RegionSearchBean.java
+++ b/src/main/java/com/supwisdom/dlpay/water/bean/RegionSearchBean.java
@@ -1,4 +1,4 @@
-package com.supwisdom.dlpay.water.system.bean;
+package com.supwisdom.dlpay.water.bean;
 
 import com.supwisdom.dlpay.system.bean.PageBean;
 
diff --git a/src/main/java/com/supwisdom/dlpay/water/bean/TransdtlCountSearchBean.java b/src/main/java/com/supwisdom/dlpay/water/bean/TransdtlCountSearchBean.java
new file mode 100644
index 0000000..46e447e
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/bean/TransdtlCountSearchBean.java
@@ -0,0 +1,33 @@
+package com.supwisdom.dlpay.water.bean;
+
+import com.supwisdom.dlpay.system.bean.PageBean;
+
+public class TransdtlCountSearchBean extends PageBean {
+    private String transtime;
+    private String devicename;
+    private Integer areano;
+
+    public String getTranstime() {
+        return transtime;
+    }
+
+    public void setTranstime(String transtime) {
+        this.transtime = transtime;
+    }
+
+    public String getDevicename() {
+        return devicename;
+    }
+
+    public void setDevicename(String devicename) {
+        this.devicename = devicename;
+    }
+
+    public Integer getAreano() {
+        return areano;
+    }
+
+    public void setAreano(Integer areano) {
+        this.areano = areano;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/bean/TransdtlSearchBean.java b/src/main/java/com/supwisdom/dlpay/water/bean/TransdtlSearchBean.java
new file mode 100644
index 0000000..5b281e7
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/bean/TransdtlSearchBean.java
@@ -0,0 +1,52 @@
+package com.supwisdom.dlpay.water.bean;
+
+import com.supwisdom.dlpay.system.bean.PageBean;
+
+
+public class TransdtlSearchBean extends PageBean {
+    private String transtime;
+    private String devicename;
+    private String deviceno;
+    private String username;
+    private Integer areano;
+
+    public String getTranstime() {
+        return transtime;
+    }
+
+    public void setTranstime(String transtime) {
+        this.transtime = transtime;
+    }
+
+    public String getDevicename() {
+        return devicename;
+    }
+
+    public void setDevicename(String devicename) {
+        this.devicename = devicename;
+    }
+
+    public String getDeviceno() {
+        return deviceno;
+    }
+
+    public void setDeviceno(String deviceno) {
+        this.deviceno = deviceno;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public Integer getAreano() {
+        return areano;
+    }
+
+    public void setAreano(Integer areano) {
+        this.areano = areano;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/dao/AreaDao.java b/src/main/java/com/supwisdom/dlpay/water/dao/AreaDao.java
index 38330f6..b63207b 100644
--- a/src/main/java/com/supwisdom/dlpay/water/dao/AreaDao.java
+++ b/src/main/java/com/supwisdom/dlpay/water/dao/AreaDao.java
@@ -12,19 +12,17 @@
 @Repository
 public interface AreaDao extends JpaRepository<TArea, Integer> {
 
-    List<TArea> findByParentId(Integer parentId);
-
     List<TArea> findAllByAvailableOrderByAreano(Integer available);
 
     List<TArea> findByAvailableAndLevelNot(Integer available, Integer level);
 
     Optional<TArea> findByAvailableAndAreano(Integer available, Integer regino);
 
-    Page<TArea> findAllByAvailable(Integer available, Pageable pageable);
+    Page<TArea> findAllByAvailableOrderByAreano(Integer available, Pageable pageable);
 
     Page<TArea> findByAvailableAndParentIdOrderByAreano(Integer available, Integer parentId, Pageable pageable);
 
-    Page<TArea> findAllByAvailableAndAreaNameContaining(Integer available, String regiName, Pageable pageable);
+    Page<TArea> findAllByAvailableAndAreaNameContainingOrderByAreano(Integer available, String regiName, Pageable pageable);
 
     TArea findAllByAvailableAndAreaName(Integer available, String reiName);
 
diff --git a/src/main/java/com/supwisdom/dlpay/water/dao/AreaparaBindDao.java b/src/main/java/com/supwisdom/dlpay/water/dao/AreaparaBindDao.java
new file mode 100644
index 0000000..6b8fdc2
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/dao/AreaparaBindDao.java
@@ -0,0 +1,14 @@
+package com.supwisdom.dlpay.water.dao;
+
+import com.supwisdom.dlpay.water.domain.TAreaparaBind;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface AreaparaBindDao extends JpaRepository<TAreaparaBind,Integer> {
+    TAreaparaBind findByAreano(Integer areano);
+
+    @Query("select count(t.areano) from TAreaparaBind t where t.groupid=?1")
+    long getAreaparaBindRecordcnt(Integer groupid);
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/dao/DeviceDao.java b/src/main/java/com/supwisdom/dlpay/water/dao/DeviceDao.java
index 96b1daa..55b0051 100644
--- a/src/main/java/com/supwisdom/dlpay/water/dao/DeviceDao.java
+++ b/src/main/java/com/supwisdom/dlpay/water/dao/DeviceDao.java
@@ -3,6 +3,7 @@
 import com.supwisdom.dlpay.water.domain.TDevice;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.domain.Specification;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.stereotype.Repository;
@@ -22,5 +23,6 @@
 
   TDevice findByDeviceno(String deviceno);
 
-  Page<TDevice> findAll(Pageable pageable);
+  Page<TDevice> findAllByOrderByDeviceno(Pageable pageable);
+
 }
diff --git a/src/main/java/com/supwisdom/dlpay/water/dao/TAreaparaDao.java b/src/main/java/com/supwisdom/dlpay/water/dao/TAreaparaDao.java
new file mode 100644
index 0000000..aaefdd9
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/dao/TAreaparaDao.java
@@ -0,0 +1,24 @@
+package com.supwisdom.dlpay.water.dao;
+
+import com.supwisdom.dlpay.water.domain.TAreapara;
+import com.supwisdom.dlpay.water.domain.TAreaparaPK;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface TAreaparaDao extends JpaRepository<TAreapara, TAreaparaPK> {
+
+    @Query("from TAreapara t where t.groupid=?1 order by t.paraname")
+    List<TAreapara> findByGroupid(Integer groupid);
+
+    @Query("select t from TAreapara t,TAreaparaGroup g where t.groupid=g.groupid and g.globalflag=true order by t.paraname ")
+    List<TAreapara> findSystemDefaultAreapara();
+
+    @Query("from TAreapara t where t.groupid=?1 and t.paraname=?2")
+    TAreapara findById(Integer groupid, String paraname);
+
+    void deleteAllByGroupid(Integer groupid);
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/dao/TAreaparaGroupDao.java b/src/main/java/com/supwisdom/dlpay/water/dao/TAreaparaGroupDao.java
new file mode 100644
index 0000000..79ff9ee
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/dao/TAreaparaGroupDao.java
@@ -0,0 +1,25 @@
+package com.supwisdom.dlpay.water.dao;
+
+import com.supwisdom.dlpay.water.domain.TAreaparaGroup;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface TAreaparaGroupDao extends JpaRepository<TAreaparaGroup,Integer> {
+    Page<TAreaparaGroup> findByGroupnameIsContaining(String groupname, Pageable pageable);
+
+    TAreaparaGroup findByGroupid(Integer groupid);
+
+    List<TAreaparaGroup> findAllByOrderByGroupid();
+
+    @Query("select count(t.groupid) from TAreaparaGroup t where t.groupname=?1 ")
+    long checkGroupnameExists(String groupname);
+
+    @Query("select count(t.groupid) from TAreaparaGroup t where t.groupname=?1 and t.groupid<>?2")
+    long checkGroupnameExists(String groupname, int groupid);
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/dao/TransdtlCountDao.java b/src/main/java/com/supwisdom/dlpay/water/dao/TransdtlCountDao.java
new file mode 100644
index 0000000..131e3cb
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/dao/TransdtlCountDao.java
@@ -0,0 +1,10 @@
+package com.supwisdom.dlpay.water.dao;
+
+import com.supwisdom.dlpay.water.domain.TTransdtlCount;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface TransdtlCountDao extends JpaRepository<TTransdtlCount, String>, JpaSpecificationExecutor<TTransdtlCount> {
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/domain/TArea.java b/src/main/java/com/supwisdom/dlpay/water/domain/TArea.java
index 4df2f06..5dbc934 100644
--- a/src/main/java/com/supwisdom/dlpay/water/domain/TArea.java
+++ b/src/main/java/com/supwisdom/dlpay/water/domain/TArea.java
@@ -27,7 +27,7 @@
   @Column(name = "REMARKS")
   private String remarks;
 
-  @Column(name = "PARENTNAME")
+  @Transient
   private String parentName;
 
   @Column(name = "AVAILABLE")
diff --git a/src/main/java/com/supwisdom/dlpay/water/domain/TAreapara.java b/src/main/java/com/supwisdom/dlpay/water/domain/TAreapara.java
new file mode 100644
index 0000000..35d8e11
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/domain/TAreapara.java
@@ -0,0 +1,238 @@
+package com.supwisdom.dlpay.water.domain;
+
+import com.supwisdom.dlpay.framework.util.DateUtil;
+import com.supwisdom.dlpay.framework.util.MoneyUtil;
+import com.supwisdom.dlpay.framework.util.NumberUtil;
+import com.supwisdom.dlpay.framework.util.StringUtil;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "TB_AREAPARA")
+@IdClass(TAreaparaPK.class)
+public class TAreapara {
+    @Id
+    @Column(name="GROUPID", nullable = false, precision = 9)
+    private Integer groupid;
+
+    @Id
+    @Column(name="PARANAME", nullable = false, length = 60)
+    private String paraname;
+
+    @Column(name="PARAVAL",  length = 90)
+    private String paraval;
+
+    @Column(name="PARADESC",  length = 200)
+    private String paradesc;
+
+    @Column(name="VALTYPE",  length = 10)
+    private String valtype;
+
+    @Column(name="MINVAL",  length = 10)
+    private String minval;
+
+    @Column(name="MAXVAL",  length = 10)
+    private String maxval;
+
+    @Transient
+    private String errmsg;
+
+    public Integer getGroupid() {
+        return groupid;
+    }
+
+    public void setGroupid(Integer groupid) {
+        this.groupid = groupid;
+    }
+
+    public String getParaname() {
+        return paraname;
+    }
+
+    public void setParaname(String paraname) {
+        this.paraname = paraname;
+    }
+
+    public String getParaval() {
+        return paraval;
+    }
+
+    public void setParaval(String paraval) {
+        this.paraval = paraval;
+    }
+
+    public String getParadesc() {
+        return paradesc;
+    }
+
+    public void setParadesc(String paradesc) {
+        this.paradesc = paradesc;
+    }
+
+    public String getValtype() {
+        return valtype;
+    }
+
+    public void setValtype(String valtype) {
+        this.valtype = valtype;
+    }
+
+    public String getMinval() {
+        return minval;
+    }
+
+    public void setMinval(String minval) {
+        this.minval = minval;
+    }
+
+    public String getMaxval() {
+        return maxval;
+    }
+
+    public void setMaxval(String maxval) {
+        this.maxval = maxval;
+    }
+
+    public String getErrmsg() {
+        return errmsg;
+    }
+
+    public void setErrmsg(String errmsg) {
+        this.errmsg = errmsg;
+    }
+
+    public boolean checkValue() {
+        String paraname = this.paraname == null ? "" : this.paraname;
+
+        if (StringUtil.isEmpty(this.paraval)) {
+            this.errmsg = paraname + " 参数值为空";
+            return false;
+        }
+        this.paraval = this.paraval.trim();
+
+        //B-boolean;N-number;A-amount;S-String;DT-'yyyyMMddHHmmss';D-'yyyyMMdd';T-'HHmmss'
+        if (!StringUtil.isEmpty(this.valtype) && !"S".equals(this.valtype)) {
+            //指定了值类型
+            if ("B".equals(this.valtype)) {
+                //boolean
+                if (!"0".equals(this.paraval) && !"1".equals(this.paraval)) {
+                    this.errmsg = paraname + " 只能取0或1 ";
+                    return false;
+                }
+            }
+
+            if ("N".equals(this.valtype)) {
+                // number
+                if (!NumberUtil.isDigits(this.paraval)) {
+                    this.errmsg = paraname + " 只能取整数 ";
+                    return false;
+                }
+                if (NumberUtil.isDigits(this.minval) && Long.parseLong(this.paraval) < Long.parseLong(this.minval)) {
+                    this.errmsg = paraname + " 小于最小值(" + Long.parseLong(this.minval) + ") ";
+                    return false;
+                }
+                if (NumberUtil.isDigits(this.maxval) && Long.parseLong(this.paraval) > Long.parseLong(this.maxval)) {
+                    this.errmsg = paraname + " 大于最大值(" + Long.parseLong(this.maxval) + ") ";
+                    return false;
+                }
+            }
+
+            if ("A".equals(this.valtype)) {
+                //金额amount
+                if (!NumberUtil.isAmount(this.paraval)) {
+                    this.errmsg = paraname + " 为金额,最多两位小数 ";
+                    return false;
+                }
+                if (NumberUtil.isAmount(this.minval) && MoneyUtil.moneyCompare(Double.parseDouble(this.paraval), Double.parseDouble(this.minval)) < 0) {
+                    this.errmsg = paraname + " 小于最小值(" + MoneyUtil.formatYuan(Double.parseDouble(this.minval)) + ") ";
+                    return false;
+                }
+                if (NumberUtil.isAmount(this.maxval) && MoneyUtil.moneyCompare(Double.parseDouble(this.paraval), Double.parseDouble(this.maxval)) > 0) {
+                    this.errmsg = paraname + " 大于最大值(" + MoneyUtil.formatYuan(Double.parseDouble(this.maxval)) + ") ";
+                    return false;
+                }
+            }
+
+            if ("DT".equals(this.valtype)) {
+                //时间 yyyyMMddHHmmss
+                if (!DateUtil.checkDatetimeValid(this.paraval, "yyyyMMddHHmmss")) {
+                    this.errmsg = paraname + " 格式错误(yyyyMMddHhmmss) ";
+                    return false;
+                }
+
+                if (!StringUtil.isEmpty(this.minval) && DateUtil.compareDatetime(this.paraval, this.minval, "yyyyMMddHHmmss") < 0) {
+                    this.errmsg = paraname + " 小于最小值(" + this.minval + ") ";
+                    return false;
+                }
+                if (!StringUtil.isEmpty(this.maxval) && DateUtil.compareDatetime(this.paraval, this.maxval, "yyyyMMddHHmmss") > 0) {
+                    this.errmsg = paraname + " 大于最大值(" + this.maxval + ") ";
+                    return false;
+                }
+            }
+
+            if ("D".equals(this.valtype)) {
+                //时间 yyyyMMdd
+                if (!DateUtil.checkDatetimeValid(this.paraval, "yyyyMMdd")) {
+                    this.errmsg = paraname + " 格式错误(yyyyMMdd) ";
+                    return false;
+                }
+
+                if (!StringUtil.isEmpty(this.minval) && DateUtil.compareDatetime(this.paraval, this.minval, "yyyyMMdd") < 0) {
+                    this.errmsg = paraname + " 小于最小值(" + this.minval + ") ";
+                    return false;
+                }
+                if (!StringUtil.isEmpty(this.maxval) && DateUtil.compareDatetime(this.paraval, this.maxval, "yyyyMMdd") > 0) {
+                    this.errmsg = paraname + " 大于最大值(" + this.maxval + ") ";
+                    return false;
+                }
+            }
+
+            if ("T".equals(this.valtype)) {
+                //时间 HHmmss
+                if (!DateUtil.checkDatetimeValid(this.paraval, "HHmmss")) {
+                    this.errmsg = paraname + " 格式错误(HHmmss) ";
+                    return false;
+                }
+
+                if (!StringUtil.isEmpty(this.minval) && DateUtil.compareDatetime(this.paraval, this.minval, "HHmmss") < 0) {
+                    this.errmsg = paraname + " 小于最小值(" + this.minval + ") ";
+                    return false;
+                }
+                if (!StringUtil.isEmpty(this.maxval) && DateUtil.compareDatetime(this.paraval, this.maxval, "HHmmss") > 0) {
+                    this.errmsg = paraname + " 大于最大值(" + this.maxval + ") ";
+                    return false;
+                }
+            }
+
+            if ("TS".equals(this.valtype)){
+                //时间(时分) HHmm
+                if (!DateUtil.checkDatetimeValid(this.paraval, "HHmm")) {
+                    this.errmsg = paraname + " 格式错误(HHmm) ";
+                    return false;
+                }
+
+                if (!StringUtil.isEmpty(this.minval) && DateUtil.compareDatetime(this.paraval, this.minval, "HHmm") < 0) {
+                    this.errmsg = paraname + " 小于最小值(" + this.minval + ") ";
+                    return false;
+                }
+                if (!StringUtil.isEmpty(this.maxval) && DateUtil.compareDatetime(this.paraval, this.maxval, "HHmm") > 0) {
+                    this.errmsg = paraname + " 大于最大值(" + this.maxval + ") ";
+                    return false;
+                }
+            }
+
+        } else {
+            //字符串判断
+            if (!StringUtil.isEmpty(this.minval) && this.paraval.compareToIgnoreCase(this.minval) < 0) {
+                this.errmsg = paraname + " 小于最小值(" + this.minval + ") ";
+                return false;
+            }
+            if (!StringUtil.isEmpty(this.maxval) && this.paraval.compareToIgnoreCase(this.maxval) > 0) {
+                this.errmsg = paraname + " 大于最大值(" + this.maxval + ") ";
+                return false;
+            }
+        }
+        return true;
+    }
+}
+
diff --git a/src/main/java/com/supwisdom/dlpay/water/domain/TAreaparaBind.java b/src/main/java/com/supwisdom/dlpay/water/domain/TAreaparaBind.java
new file mode 100644
index 0000000..01441d7
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/domain/TAreaparaBind.java
@@ -0,0 +1,44 @@
+package com.supwisdom.dlpay.water.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "TB_AREAPARA_BIND")
+public class TAreaparaBind {
+    @Id
+    @Column(name = "AREANO", nullable = false, precision = 9)
+    private Integer areano;
+
+    @Column(name = "GROUPID", nullable = false, precision = 9)
+    private Integer groupid;
+
+    @Column(name = "LASTSAVED", length = 14)
+    private String lastsaved;
+
+    public Integer getAreano() {
+        return areano;
+    }
+
+    public void setAreano(Integer areano) {
+        this.areano = areano;
+    }
+
+    public Integer getGroupid() {
+        return groupid;
+    }
+
+    public void setGroupid(Integer groupid) {
+        this.groupid = groupid;
+    }
+
+    public String getLastsaved() {
+        return lastsaved;
+    }
+
+    public void setLastsaved(String lastsaved) {
+        this.lastsaved = lastsaved;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/domain/TAreaparaGroup.java b/src/main/java/com/supwisdom/dlpay/water/domain/TAreaparaGroup.java
new file mode 100644
index 0000000..fdbc7c1
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/domain/TAreaparaGroup.java
@@ -0,0 +1,67 @@
+package com.supwisdom.dlpay.water.domain;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "TB_AREAPARA_GROUP")
+public class TAreaparaGroup {
+    @Id
+    @SequenceGenerator(name = "areapara_groupid", sequenceName = "SEQ_AREAPARAGROUPID", initialValue=2, allocationSize = 1 )
+    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "areapara_groupid")
+    @Column(name="GROUPID", nullable = false, precision = 9)
+    private Integer groupid;
+
+    @Column(name="GROUPNAME", length = 200)
+    private String groupname;
+
+    @Column(name="GLOBALFLAG", nullable = false, length = 200)
+    private Boolean globalflag;
+
+    @Version
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    @Column(name="VERNO", nullable = false, precision = 9)
+    private Long verno;
+
+    @Column(name="LASTSAVED", length = 14)
+    private String lastsaved;
+
+    public Integer getGroupid() {
+        return groupid;
+    }
+
+    public void setGroupid(Integer groupid) {
+        this.groupid = groupid;
+    }
+
+    public String getGroupname() {
+        return groupname;
+    }
+
+    public void setGroupname(String groupname) {
+        this.groupname = groupname;
+    }
+
+    public Boolean getGlobalflag() {
+        return globalflag;
+    }
+
+    public void setGlobalflag(Boolean globalflag) {
+        this.globalflag = globalflag;
+    }
+
+    public Long getVerno() {
+        return verno;
+    }
+
+    public void setVerno(Long verno) {
+        this.verno = verno;
+    }
+
+    public String getLastsaved() {
+        return lastsaved;
+    }
+
+    public void setLastsaved(String lastsaved) {
+        this.lastsaved = lastsaved;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/domain/TAreaparaPK.java b/src/main/java/com/supwisdom/dlpay/water/domain/TAreaparaPK.java
new file mode 100644
index 0000000..2bf9f5a
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/domain/TAreaparaPK.java
@@ -0,0 +1,59 @@
+package com.supwisdom.dlpay.water.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+import java.io.Serializable;
+
+public class TAreaparaPK implements Serializable {
+    @Id
+    @Column(name = "GROUPID", nullable = false, precision = 9)
+    private Integer groupid;
+
+    @Id
+    @Column(name = "PARANAME", nullable = false, length = 60)
+    private String paraname;
+
+    public TAreaparaPK() {
+    }
+
+    public TAreaparaPK(Integer groupid, String paraname) {
+        this.groupid = groupid;
+        this.paraname = paraname;
+    }
+
+    public Integer getGroupid() {
+        return groupid;
+    }
+
+    public void setGroupid(Integer groupid) {
+        this.groupid = groupid;
+    }
+
+    public String getParaname() {
+        return paraname;
+    }
+
+    public void setParaname(String paraname) {
+        this.paraname = paraname;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        TAreaparaPK tAreaparaPK = (TAreaparaPK) o;
+        if (groupid != null ? !groupid.equals(tAreaparaPK.getGroupid()) : groupid != null)
+            return false;
+        if (paraname != null ? !paraname.equals(tAreaparaPK.getParaname()) : paraname != null)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = groupid != null ? groupid.hashCode() : 0;
+        result = 31 * result + (paraname != null ? paraname.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/domain/TTransdtlCount.java b/src/main/java/com/supwisdom/dlpay/water/domain/TTransdtlCount.java
new file mode 100644
index 0000000..21204c5
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/domain/TTransdtlCount.java
@@ -0,0 +1,124 @@
+package com.supwisdom.dlpay.water.domain;
+
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "tb_transdtl_count",
+        indexes = {@Index(name = "trasndtl_count_accdate", columnList = "accdate"),
+                @Index(name = "transdtl_count_areano", columnList = "areano"),
+                @Index(name = "transdtl_count_devicename", columnList = "devicename")})
+@SequenceGenerator(name = "SEQ_TRANSDTL_COUNT", sequenceName = "SEQ_TRANSDTL_COUNT", allocationSize = 1, initialValue = 1000)
+public class TTransdtlCount {
+    @Id
+    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_TRANSDTL_COUNT")
+    @Column(name = "id", length = 18)
+    private String id;
+
+    @Column(name = "accdate", length = 8)
+    private String accdate;
+
+    @Column(name = "areano", length = 32)
+    private String areano;
+
+    @Column(name = "areaname", length = 200)
+    private String areaname;
+
+    @Column(name = "deviceno", length = 8)
+    private String deviceno;
+
+    @Column(name = "devicename", length = 200)
+    private String devicename;
+
+    @Column(name = "mode", length = 20)
+    private String mode;
+
+    @Column(name = "count", length = 32)
+    private Integer count;
+
+    @Column(precision = 10, scale = 2)
+    private Double amount;
+
+    @Column(name = "water_in_100ml", precision = 10)
+    private Integer waterSumHundredLitre;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getAccdate() {
+        return accdate;
+    }
+
+    public void setAccdate(String accdate) {
+        this.accdate = accdate;
+    }
+
+    public String getAreano() {
+        return areano;
+    }
+
+    public void setAreano(String areano) {
+        this.areano = areano;
+    }
+
+    public String getAreaname() {
+        return areaname;
+    }
+
+    public void setAreaname(String areaname) {
+        this.areaname = areaname;
+    }
+
+    public String getDeviceno() {
+        return deviceno;
+    }
+
+    public void setDeviceno(String deviceno) {
+        this.deviceno = deviceno;
+    }
+
+    public String getDevicename() {
+        return devicename;
+    }
+
+    public void setDevicename(String devicename) {
+        this.devicename = devicename;
+    }
+
+    public String getMode() {
+        return mode;
+    }
+
+    public void setMode(String mode) {
+        this.mode = mode;
+    }
+
+    public Integer getCount() {
+        return count;
+    }
+
+    public void setCount(Integer count) {
+        this.count = count;
+    }
+
+    public Double getAmount() {
+        return amount;
+    }
+
+    public void setAmount(Double amount) {
+        this.amount = amount;
+    }
+
+    public Integer getWaterSumHundredLitre() {
+        return waterSumHundredLitre;
+    }
+
+    public void setWaterSumHundredLitre(Integer waterSumHundredLitre) {
+        this.waterSumHundredLitre = waterSumHundredLitre;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/pojo/TAreaparaBindAreaDTO.java b/src/main/java/com/supwisdom/dlpay/water/pojo/TAreaparaBindAreaDTO.java
new file mode 100644
index 0000000..11324cf
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/pojo/TAreaparaBindAreaDTO.java
@@ -0,0 +1,40 @@
+package com.supwisdom.dlpay.water.pojo;
+
+public class TAreaparaBindAreaDTO {
+    private Integer areano;
+    private String address;
+    private String areaname;
+    private Integer arealevel;
+
+    public Integer getAreano() {
+        return areano;
+    }
+
+    public void setAreano(Integer areano) {
+        this.areano = areano;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public String getAreaname() {
+        return areaname;
+    }
+
+    public void setAreaname(String areaname) {
+        this.areaname = areaname;
+    }
+
+    public Integer getArealevel() {
+        return arealevel;
+    }
+
+    public void setArealevel(Integer arealevel) {
+        this.arealevel = arealevel;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/pojo/TAreaparaBindDTO.java b/src/main/java/com/supwisdom/dlpay/water/pojo/TAreaparaBindDTO.java
new file mode 100644
index 0000000..9e0341a
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/pojo/TAreaparaBindDTO.java
@@ -0,0 +1,49 @@
+package com.supwisdom.dlpay.water.pojo;
+
+public class TAreaparaBindDTO {
+    private Integer groupid;
+    private String groupname;
+    private Integer areano;
+    private String areaname;
+    private String lastsaved;
+
+    public Integer getGroupid() {
+        return groupid;
+    }
+
+    public void setGroupid(Integer groupid) {
+        this.groupid = groupid;
+    }
+
+    public String getGroupname() {
+        return groupname;
+    }
+
+    public void setGroupname(String groupname) {
+        this.groupname = groupname;
+    }
+
+    public Integer getAreano() {
+        return areano;
+    }
+
+    public void setAreano(Integer areano) {
+        this.areano = areano;
+    }
+
+    public String getAreaname() {
+        return areaname;
+    }
+
+    public void setAreaname(String areaname) {
+        this.areaname = areaname;
+    }
+
+    public String getLastsaved() {
+        return lastsaved;
+    }
+
+    public void setLastsaved(String lastsaved) {
+        this.lastsaved = lastsaved;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/pojo/TTransdtlDTO.java b/src/main/java/com/supwisdom/dlpay/water/pojo/TTransdtlDTO.java
new file mode 100644
index 0000000..e107ada
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/pojo/TTransdtlDTO.java
@@ -0,0 +1,133 @@
+package com.supwisdom.dlpay.water.pojo;
+
+import lombok.Data;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+
+@Entity
+public class TTransdtlDTO {
+    @Id
+    @Column
+    private String billno;
+    @Column
+    private String deviceno;
+    @Column
+    private String devicename;
+    @Column
+    private Integer waterSumHundredLitre;
+    @Column
+    private Double amount;
+    @Column
+    private String username;
+    @Column
+    private String bankcardno;
+    @Column
+    private String transdate;
+    @Column
+    private String mode;
+    @Column
+    private String status;
+    @Column
+    private String areaname;
+    @Column
+    private Integer areano;
+
+    public String getBillno() {
+        return billno;
+    }
+
+    public void setBillno(String billno) {
+        this.billno = billno;
+    }
+
+    public String getDeviceno() {
+        return deviceno;
+    }
+
+    public void setDeviceno(String deviceno) {
+        this.deviceno = deviceno;
+    }
+
+    public String getDevicename() {
+        return devicename;
+    }
+
+    public void setDevicename(String devicename) {
+        this.devicename = devicename;
+    }
+
+    public Integer getWaterSumHundredLitre() {
+        return waterSumHundredLitre;
+    }
+
+    public void setWaterSumHundredLitre(Integer waterSumHundredLitre) {
+        this.waterSumHundredLitre = waterSumHundredLitre;
+    }
+
+    public Double getAmount() {
+        return amount;
+    }
+
+    public void setAmount(Double amount) {
+        this.amount = amount;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getBankcardno() {
+        return bankcardno;
+    }
+
+    public void setBankcardno(String bankcardno) {
+        this.bankcardno = bankcardno;
+    }
+
+    public String getTransdate() {
+        return transdate;
+    }
+
+    public void setTransdate(String transdate) {
+        this.transdate = transdate;
+    }
+
+    public String getMode() {
+        return mode;
+    }
+
+    public void setMode(String mode) {
+        this.mode = mode;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getAreaname() {
+        return areaname;
+    }
+
+    public void setAreaname(String areaname) {
+        this.areaname = areaname;
+    }
+
+    public Integer getAreano() {
+        return areano;
+    }
+
+    public void setAreano(Integer areano) {
+        this.areano = areano;
+    }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/service/AreaService.java b/src/main/java/com/supwisdom/dlpay/water/service/AreaService.java
index a7c7eec..a191204 100644
--- a/src/main/java/com/supwisdom/dlpay/water/service/AreaService.java
+++ b/src/main/java/com/supwisdom/dlpay/water/service/AreaService.java
@@ -1,7 +1,7 @@
 package com.supwisdom.dlpay.water.service;
 
 import com.supwisdom.dlpay.framework.util.PageResult;
-import com.supwisdom.dlpay.water.system.bean.RegionSearchBean;
+import com.supwisdom.dlpay.water.bean.RegionSearchBean;
 import com.supwisdom.dlpay.water.domain.TArea;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -9,33 +9,33 @@
 import java.util.Map;
 
 public interface AreaService {
-  @Transactional
+  @Transactional(rollbackFor = Exception.class)
   PageResult<TArea> queryAreasByParentId(RegionSearchBean param);
 
-  @Transactional
+  @Transactional(rollbackFor = Exception.class)
   List<Map<String, Object>> getAreaTree(List<TArea> regions, Integer parentId);
 
-  @Transactional
+  @Transactional(rollbackFor = Exception.class)
   List<TArea> queryAllAreas();
 
-  @Transactional
+  @Transactional(rollbackFor = Exception.class)
   List<TArea> queryAllNotFLevelArea();
 
-  @Transactional
+  @Transactional(rollbackFor = Exception.class)
   PageResult<TArea> queryAreasBySearchKey(RegionSearchBean param);
 
-  @Transactional
+  @Transactional(rollbackFor = Exception.class)
   boolean saveArea(TArea region);
 
-  @Transactional
+  @Transactional(rollbackFor = Exception.class)
   boolean checkAreaName(TArea region);
 
-  @Transactional
+  @Transactional(rollbackFor = Exception.class)
   boolean updateArea(TArea region);
 
-  @Transactional
+  @Transactional(rollbackFor = Exception.class)
   boolean deleteArea(Integer regino);
 
-  @Transactional
+  @Transactional(rollbackFor = Exception.class)
   boolean existSubArea(Integer regino);
 }
diff --git a/src/main/java/com/supwisdom/dlpay/water/service/DeviceService.java b/src/main/java/com/supwisdom/dlpay/water/service/DeviceService.java
index 4e87205..66e1d86 100644
--- a/src/main/java/com/supwisdom/dlpay/water/service/DeviceService.java
+++ b/src/main/java/com/supwisdom/dlpay/water/service/DeviceService.java
@@ -1,11 +1,12 @@
 package com.supwisdom.dlpay.water.service;
 
+import com.supwisdom.dlpay.framework.domain.TDictionary;
 import com.supwisdom.dlpay.framework.util.PageResult;
 import com.supwisdom.dlpay.water.DeviceLineCheckParam;
 import com.supwisdom.dlpay.water.DeviceLoginParam;
 import com.supwisdom.dlpay.water.domain.TDevice;
 import com.supwisdom.dlpay.water.domain.TFeeConfig;
-import com.supwisdom.dlpay.water.system.bean.DeviceSearchBean;
+import com.supwisdom.dlpay.water.bean.DeviceSearchBean;
 import org.springframework.data.domain.Page;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -13,30 +14,30 @@
 import java.util.Map;
 
 public interface DeviceService {
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     boolean existSubDevice(Integer areano);
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     PageResult<TDevice> queryDeviceList(DeviceSearchBean param);
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     TDevice queryDeviceById(Integer deviceid);
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     boolean updateDevice(TDevice device);
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     boolean saveDevice(TDevice device);
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     Map<String, Object> checkParams(TDevice device);
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     boolean deleteDevice(Integer deviceid);
-    @Transactional
-    List<String> groupStatus();
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
+    List<TDictionary> groupStatus();
+    @Transactional(rollbackFor = Exception.class)
     PageResult<TDevice> queryDeviceByParams(DeviceSearchBean param);
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     PageResult<TDevice> queryAreaname(Page<TDevice> devicePage);
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     Map<String,Object> deviceLogin(DeviceLoginParam param);
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     TDevice lineCheck(DeviceLineCheckParam param);
-    @Transactional
+    @Transactional(rollbackFor = Exception.class)
     TFeeConfig queryTFeeConfigByDeviceno(String deviceno);
 }
diff --git a/src/main/java/com/supwisdom/dlpay/water/service/TAreaparaService.java b/src/main/java/com/supwisdom/dlpay/water/service/TAreaparaService.java
new file mode 100644
index 0000000..34618ae
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/service/TAreaparaService.java
@@ -0,0 +1,51 @@
+package com.supwisdom.dlpay.water.service;
+
+import com.supwisdom.dlpay.framework.util.PageResult;
+import com.supwisdom.dlpay.util.WebCheckException;
+import com.supwisdom.dlpay.water.bean.AreaparaSearchBean;
+import com.supwisdom.dlpay.water.domain.TArea;
+import com.supwisdom.dlpay.water.domain.TAreapara;
+import com.supwisdom.dlpay.water.domain.TAreaparaBind;
+import com.supwisdom.dlpay.water.domain.TAreaparaGroup;
+import com.supwisdom.dlpay.water.pojo.TAreaparaBindDTO;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Map;
+
+public interface TAreaparaService {
+    @Transactional(rollbackFor = Exception.class)
+    PageResult<TAreaparaGroup> queryParaGroupByParam(AreaparaSearchBean param);
+
+    @Transactional(rollbackFor = Exception.class)
+    TAreaparaGroup getAreaparaGroupByGroupid(Integer groupid);
+
+    @Transactional(rollbackFor = Exception.class)
+    List<TAreapara> getAreaparaInfo(Integer groupid);
+
+    @Transactional(rollbackFor = Exception.class)
+    boolean saveOrUpdateAreapara(int groupid, String groupname, Map<String, String> param) throws WebCheckException;
+
+    @Transactional(rollbackFor = Exception.class)
+    PageResult<TAreaparaBindDTO> getAreaparaBindInfos(String searchkey, int pageNo, int pageSize);
+
+    @Transactional(rollbackFor = Exception.class)
+    boolean deleteAreaparaGroup(TAreaparaGroup group) throws WebCheckException;
+
+    @Transactional(rollbackFor = Exception.class, readOnly = true)
+    List<TAreaparaGroup> queryAllAreaparaGroups();
+
+    @Transactional(rollbackFor = Exception.class)
+    boolean saveBindAreapara(int groupid,List<Integer> areanos) throws WebCheckException;
+
+    @Transactional(rollbackFor = Exception.class, readOnly = true)
+    TAreaparaBind getAreaparaBindByAreano(Integer areano);
+
+    @Transactional(rollbackFor = Exception.class)
+    boolean deleteAreaparaBind(TAreaparaBind bind);
+
+    @Transactional(rollbackFor = Exception.class, readOnly = true)
+    PageResult<TArea> getAreaBySearch(String searchKey);
+}
diff --git a/src/main/java/com/supwisdom/dlpay/water/service/TransdtlService.java b/src/main/java/com/supwisdom/dlpay/water/service/TransdtlService.java
index b64a1b0..acb1a9b 100644
--- a/src/main/java/com/supwisdom/dlpay/water/service/TransdtlService.java
+++ b/src/main/java/com/supwisdom/dlpay/water/service/TransdtlService.java
@@ -1,22 +1,35 @@
 package com.supwisdom.dlpay.water.service;
 
+import com.supwisdom.dlpay.framework.util.PageResult;
 import com.supwisdom.dlpay.water.QrcodeQueryRequest;
 import com.supwisdom.dlpay.water.UploadRecordRequest;
 import com.supwisdom.dlpay.water.UserAuthRequest;
+import com.supwisdom.dlpay.water.bean.TransdtlCountSearchBean;
 import com.supwisdom.dlpay.water.domain.TTransdtl;
-import org.springframework.data.jpa.repository.Lock;
+import com.supwisdom.dlpay.water.domain.TTransdtlCount;
+import com.supwisdom.dlpay.water.pojo.TTransdtlDTO;
+import com.supwisdom.dlpay.water.bean.TransdtlSearchBean;
 import org.springframework.transaction.annotation.Transactional;
 
+
 public interface TransdtlService {
-  @Transactional
-  TTransdtl createNewTransdtl(TTransdtl dtl);
+    @Transactional(rollbackFor = Exception.class)
+    TTransdtl createNewTransdtl(TTransdtl dtl);
 
-  @Transactional
-  TTransdtl saveDeviceDtlData(UploadRecordRequest record);
+    @Transactional(rollbackFor = Exception.class)
+    TTransdtl saveDeviceDtlData(UploadRecordRequest record);
 
-  @Transactional
-  TTransdtl queryTrans(QrcodeQueryRequest param);
+    @Transactional(rollbackFor = Exception.class)
+    TTransdtl queryTrans(QrcodeQueryRequest param);
 
-  @Transactional
-  TTransdtl userAuth(UserAuthRequest param);
+    @Transactional(rollbackFor = Exception.class)
+    TTransdtl userAuth(UserAuthRequest param);
+
+    @Transactional(rollbackFor = Exception.class)
+    PageResult<TTransdtlDTO> queryTransdtlDTOByParam(TransdtlSearchBean param);
+
+    @Transactional(rollbackFor = Exception.class)
+    PageResult<TTransdtlCount> queryTransdtlCountByParam(TransdtlCountSearchBean param);
+
+
 }
diff --git a/src/main/java/com/supwisdom/dlpay/water/service/impl/AreaServiceImpl.java b/src/main/java/com/supwisdom/dlpay/water/service/impl/AreaServiceImpl.java
index cbb713f..f2ab078 100644
--- a/src/main/java/com/supwisdom/dlpay/water/service/impl/AreaServiceImpl.java
+++ b/src/main/java/com/supwisdom/dlpay/water/service/impl/AreaServiceImpl.java
@@ -2,11 +2,12 @@
 
 import com.supwisdom.dlpay.framework.util.PageResult;
 import com.supwisdom.dlpay.framework.util.StringUtil;
-import com.supwisdom.dlpay.water.system.bean.RegionSearchBean;
+import com.supwisdom.dlpay.water.bean.RegionSearchBean;
 import com.supwisdom.dlpay.water.dao.AreaDao;
 import com.supwisdom.dlpay.water.domain.TArea;
 import com.supwisdom.dlpay.water.service.AreaService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
 import org.springframework.stereotype.Service;
@@ -28,11 +29,19 @@
     @Override
     public PageResult<TArea> queryAreasByParentId(RegionSearchBean param) {
         Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize());
-        PageResult<TArea> result = new PageResult<>(regionDao.findByAvailableAndParentIdOrderByAreano(1, param.getParentId(), pageable));
+        Page<TArea> page = regionDao.findByAvailableAndParentIdOrderByAreano(1, param.getParentId(), pageable);
+        page.get().forEach(area -> {
+            Optional<TArea> optional = regionDao.findByAvailableAndAreano(1, area.getParentId());
+            optional.ifPresent(parentArea -> area.setParentName(parentArea.getAreaName()));
+        });
+        PageResult<TArea> result = new PageResult<>(page);
         List<TArea> data = result.getData();
-        if (param.getPageNo()==1) {
+        if (param.getPageNo() == 1) {
             Optional<TArea> optional = regionDao.findByAvailableAndAreano(1, param.getParentId());
             if (optional.isPresent()) {
+                regionDao.findByAvailableAndAreano(1,optional.get().getParentId()).ifPresent(
+                        parentArea -> optional.get().setParentName(parentArea.getAreaName())
+                );
                 data = new ArrayList<>(data);
                 data.add(0, optional.get());
                 result.setData(data);
@@ -69,23 +78,28 @@
     @Override
     public PageResult<TArea> queryAreasBySearchKey(RegionSearchBean param) {
         Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize());
+        Page<TArea> page;
         if (!StringUtil.isEmpty(param.getSearchKey())) {
-            return new PageResult<>(regionDao.findAllByAvailableAndAreaNameContaining(1, param.getSearchKey(), pageable));
+            page = regionDao.findAllByAvailableAndAreaNameContainingOrderByAreano(1, param.getSearchKey().trim(), pageable);
+        } else {
+            page = regionDao.findAllByAvailableOrderByAreano(1, pageable);
         }
-        return new PageResult<>(regionDao.findAllByAvailable(1, pageable));
+        page.get().forEach(area -> {
+            Optional<TArea> optional = regionDao.findByAvailableAndAreano(1, area.getParentId());
+            optional.ifPresent(parentArea -> area.setParentName(parentArea.getAreaName()));
+        });
+        return new PageResult<>(page);
     }
 
     @Override
     public boolean saveArea(TArea region) {
         if (region.getParentId() == 0) {
-            region.setParentName("无");
             region.setLevel(1);
         } else {
             Optional<TArea> optional = regionDao.findByAvailableAndAreano(1, region.getParentId());
             if (optional.isPresent()) {
-                region.setParentName(optional.get().getAreaName());
                 region.setLevel(optional.get().getLevel() + 1);
-            }else {
+            } else {
                 return false;
             }
         }
@@ -111,7 +125,7 @@
     public boolean checkAreaName(TArea region) {
         if (region.getAreano() == null) {
             return regionDao.findAllByAvailableAndAreaName(1, region.getAreaName()) == null;
-        }else {
+        } else {
             return regionDao.findByAvailableAndAreaNameAndAreanoNot(1,
                     region.getAreaName(),
                     region.getAreano()) == null;
diff --git a/src/main/java/com/supwisdom/dlpay/water/service/impl/DeviceServiceImpl.java b/src/main/java/com/supwisdom/dlpay/water/service/impl/DeviceServiceImpl.java
index 5aac203..2098022 100644
--- a/src/main/java/com/supwisdom/dlpay/water/service/impl/DeviceServiceImpl.java
+++ b/src/main/java/com/supwisdom/dlpay/water/service/impl/DeviceServiceImpl.java
@@ -1,28 +1,35 @@
 package com.supwisdom.dlpay.water.service.impl;
 
+import com.supwisdom.dlpay.framework.dao.DictionaryDao;
+import com.supwisdom.dlpay.framework.domain.TDictionary;
 import com.supwisdom.dlpay.framework.util.PageResult;
 import com.supwisdom.dlpay.framework.util.StringUtil;
+import com.supwisdom.dlpay.framework.util.WaterDeviceParam;
 import com.supwisdom.dlpay.water.DeviceLineCheckParam;
 import com.supwisdom.dlpay.water.DeviceLoginParam;
 import com.supwisdom.dlpay.water.dao.AreaDao;
 import com.supwisdom.dlpay.water.dao.DeviceDao;
 import com.supwisdom.dlpay.water.dao.DeviceFeeConfigDao;
 import com.supwisdom.dlpay.water.dao.FeeConfigDao;
-import com.supwisdom.dlpay.water.domain.TDevice;
-import com.supwisdom.dlpay.water.domain.TArea;
-import com.supwisdom.dlpay.water.domain.TDeviceFeeConfig;
-import com.supwisdom.dlpay.water.domain.TFeeConfig;
+import com.supwisdom.dlpay.water.domain.*;
 import com.supwisdom.dlpay.water.service.DeviceService;
-import com.supwisdom.dlpay.water.system.bean.DeviceSearchBean;
+import com.supwisdom.dlpay.water.bean.DeviceSearchBean;
+import org.hibernate.query.internal.NativeQueryImpl;
+import org.hibernate.transform.Transformers;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
 import org.springframework.data.jpa.domain.Specification;
 import org.springframework.stereotype.Service;
 
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
 import javax.persistence.criteria.Predicate;
 import java.util.*;
+import java.util.stream.Collectors;
 
 @Service
 public class DeviceServiceImpl implements DeviceService {
@@ -39,6 +46,16 @@
     @Autowired
     private DeviceFeeConfigDao deviceFeeConfigDao;
 
+    @Autowired
+    private DictionaryDao dictionaryDao;
+
+    @PersistenceContext
+    private EntityManager entityManager;
+
+    private static String paraSql = "select p.* from tb_device d left join " +
+            "tb_areapara_bind b on d.areano = b.areano left join " +
+            "tb_areapara p on b.groupid = p.groupid where d.deviceno = ?";
+
     @Override
     public boolean existSubDevice(Integer areano) {
         List<TDevice> devices = deviceDao.findByAreano(areano);
@@ -48,7 +65,7 @@
     @Override
     public PageResult<TDevice> queryDeviceList(DeviceSearchBean param) {
         Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize());
-        Page<TDevice> devicePage = deviceDao.findAll(pageable);
+        Page<TDevice> devicePage = deviceDao.findAllByOrderByDeviceno(pageable);
         return queryAreaname(devicePage);
     }
 
@@ -145,17 +162,13 @@
     }
 
     @Override
-    public List<String> groupStatus() {
-        List<String> list = new ArrayList<>();
-        list.add("正常");
-        list.add("注销");
-        list.add("签出");
-        return list;
+    public List<TDictionary> groupStatus() {
+        return dictionaryDao.findAllByDicttype("1");
     }
 
     @Override
     public PageResult<TDevice> queryDeviceByParams(DeviceSearchBean param) {
-        Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize());
+        Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize(), Sort.by("deviceno"));
         Specification<TDevice> specification = (Specification<TDevice>) (root, query, cb) -> {
             List<Predicate> predicates = new ArrayList<>();
             if (!StringUtil.isEmpty(param.getDeviceno())) {
@@ -198,9 +211,10 @@
             }
             device.setSoftVer(param.getHwVer());
             deviceDao.save(device);
+            Map<String, String> deviceParam = getParaMapByDeviceno(param.getDeviceno());
             result.put("flag", true);
-            result.put("devOfflineMaxHour", 168);
-            result.put("pulseInHML", 40);
+            result.put(WaterDeviceParam.devOfflineMaxHour, deviceParam.get(WaterDeviceParam.devOfflineMaxHour));
+            result.put(WaterDeviceParam.pulseInHML, deviceParam.get(WaterDeviceParam.pulseInHML));
             return result;
         }
         result.put("flag", false);
@@ -231,4 +245,15 @@
         }
         return null;
     }
+
+    private Map<String, String> getParaMapByDeviceno(String deviceno) {
+        Query query = entityManager.createNativeQuery(paraSql);
+        query.setParameter(1, deviceno);
+        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(TAreapara.class));
+        List<TAreapara> list = query.getResultList();
+        if (list == null || list.size() == 0 || list.get(0).getParaname() == null) {
+            throw new RuntimeException("该设备未绑定参数,签到失败");
+        }
+        return list.stream().collect(Collectors.toMap(TAreapara::getParaname, TAreapara::getParaval));
+    }
 }
diff --git a/src/main/java/com/supwisdom/dlpay/water/service/impl/TAreaparaServiceImpl.java b/src/main/java/com/supwisdom/dlpay/water/service/impl/TAreaparaServiceImpl.java
new file mode 100644
index 0000000..1fdd909
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/water/service/impl/TAreaparaServiceImpl.java
@@ -0,0 +1,246 @@
+package com.supwisdom.dlpay.water.service.impl;
+
+import com.supwisdom.dlpay.framework.service.SystemUtilService;
+import com.supwisdom.dlpay.framework.util.PageResult;
+import com.supwisdom.dlpay.framework.util.StringUtil;
+import com.supwisdom.dlpay.util.WebCheckException;
+import com.supwisdom.dlpay.water.bean.AreaparaSearchBean;
+import com.supwisdom.dlpay.water.dao.AreaDao;
+import com.supwisdom.dlpay.water.dao.AreaparaBindDao;
+import com.supwisdom.dlpay.water.dao.TAreaparaDao;
+import com.supwisdom.dlpay.water.dao.TAreaparaGroupDao;
+import com.supwisdom.dlpay.water.domain.TArea;
+import com.supwisdom.dlpay.water.domain.TAreapara;
+import com.supwisdom.dlpay.water.domain.TAreaparaBind;
+import com.supwisdom.dlpay.water.domain.TAreaparaGroup;
+import com.supwisdom.dlpay.water.pojo.TAreaparaBindAreaDTO;
+import com.supwisdom.dlpay.water.pojo.TAreaparaBindDTO;
+import com.supwisdom.dlpay.water.service.TAreaparaService;
+import org.hibernate.query.internal.NativeQueryImpl;
+import org.hibernate.transform.Transformers;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Service;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+@Service
+public class TAreaparaServiceImpl implements TAreaparaService {
+
+    @Autowired
+    private TAreaparaGroupDao tAreaparaGroupDao;
+
+    @Autowired
+    private TAreaparaDao tAreaparaDao;
+
+    @Autowired
+    private SystemUtilService systemUtilService;
+
+    @Autowired
+    private AreaDao areaDao;
+
+    @Autowired
+    private AreaparaBindDao areaparaBindDao;
+
+    @PersistenceContext
+    private EntityManager entityManager;
+
+    @Override
+    public PageResult<TAreaparaGroup> queryParaGroupByParam(AreaparaSearchBean param) {
+        Pageable pageable = PageRequest.of(param.getPageNo() - 1, param.getPageSize(), Sort.by("groupid"));
+        if (StringUtil.isEmpty(param.getGroupname())) {
+            return new PageResult<>(tAreaparaGroupDao.findAll(pageable));
+        }
+        return new PageResult<>(tAreaparaGroupDao.findByGroupnameIsContaining(param.getGroupname().trim(), pageable));
+    }
+
+    @Override
+    public TAreaparaGroup getAreaparaGroupByGroupid(Integer groupid) {
+        return tAreaparaGroupDao.findByGroupid(groupid);
+    }
+
+    @Override
+    public List<TAreapara> getAreaparaInfo(Integer groupid) {
+        List<TAreapara> result;
+        if (null != groupid && groupid > 0) {
+            result = tAreaparaDao.findByGroupid(groupid);
+        } else {
+            result = tAreaparaDao.findSystemDefaultAreapara(); //默认
+        }
+        if (!StringUtil.isEmpty(result)) {
+            return result;
+        } else {
+            return new ArrayList<>(0);
+        }
+    }
+
+    @Override
+    public boolean saveOrUpdateAreapara(int groupid, String groupname, Map<String, String> param) throws WebCheckException {
+        TAreaparaGroup group;
+        if (groupid == 0) {
+            if (tAreaparaGroupDao.checkGroupnameExists(groupname) > 0) {
+                throw new WebCheckException("参数名称已经存在");
+            }
+            group = new TAreaparaGroup();
+            group.setGlobalflag(false);
+            group.setGroupname(groupname);
+            group.setLastsaved(systemUtilService.getSysdatetime().getHostdatetime());
+            group.setVerno(1L);
+            group = tAreaparaGroupDao.save(group);
+
+            List<TAreapara> configList = tAreaparaDao.findSystemDefaultAreapara(); //默认
+            for (TAreapara areapara : configList) {
+                TAreapara bean = new TAreapara();
+                bean.setGroupid(group.getGroupid());
+                bean.setParaname(areapara.getParaname());
+                bean.setParaval(param.get(areapara.getParaname()));
+                bean.setParadesc(areapara.getParadesc());
+                bean.setValtype(areapara.getValtype());
+                bean.setMinval(areapara.getMinval());
+                bean.setMaxval(areapara.getMaxval());
+                if (!bean.checkValue()) {
+                    throw new WebCheckException(bean.getErrmsg());
+                }
+                tAreaparaDao.save(bean);
+            }
+        } else {
+            group = tAreaparaGroupDao.findByGroupid(groupid);
+            if (null == group) {
+                throw new WebCheckException("原设备参数组不存在");
+            }
+            if (tAreaparaGroupDao.checkGroupnameExists(groupname, groupid) > 0) {
+                throw new WebCheckException("参数名称已经存在");
+            }
+            group.setGroupname(groupname);
+            group.setLastsaved(systemUtilService.getSysdatetime().getHostdatetime());
+            tAreaparaGroupDao.save(group);
+
+            for (String key : param.keySet()) {
+                TAreapara bean = tAreaparaDao.findById(groupid, key);
+                if (null == bean) {
+                    throw new WebCheckException("设备参数[" + key + "]在参数组【" + group.getGroupname() + "】中不存在");
+                }
+                bean.setParaval(param.get(key));
+                if (!bean.checkValue()) {
+                    throw new WebCheckException(bean.getErrmsg());
+                }
+                tAreaparaDao.save(bean);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public PageResult<TAreaparaBindDTO> getAreaparaBindInfos(String searchkey, int pageNo, int pageSize) {
+        StringBuffer querySql = new StringBuffer("select b.groupid,g.groupname,b.areano,a.areaname,b.lastsaved from tb_areapara_bind b" +
+                " left join tb_areapara_group g on b.groupid = g.groupid" +
+                " left join tb_area a on b.areano = a.areano where 1=1");
+        StringBuffer countSql = new StringBuffer("select count(b.areano) from tb_areapara_bind b" +
+                " left join tb_areapara_group g on b.groupid = g.groupid" +
+                " left join tb_area a on b.areano = a.areano where 1=1");
+        if (!StringUtil.isEmpty(searchkey)) {
+            querySql.append(" and (g.groupname like :str or a.areaname like :str)");
+            countSql.append(" and (g.groupname like :str or a.areaname like :str)");
+        }
+        querySql.append(" order by b.areano ");
+        Query query = entityManager.createNativeQuery(querySql.toString());
+        Query countQuery = entityManager.createNativeQuery(countSql.toString());
+        if (!StringUtil.isEmpty(searchkey)) {
+            query.setParameter("str", "%" + searchkey.trim() + "%");
+            countQuery.setParameter("str", "%" + searchkey.trim() + "%");
+        }
+        query.setFirstResult((pageNo - 1) * pageSize);
+        query.setMaxResults(pageSize);
+        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(TAreaparaBindDTO.class));
+        List<TAreaparaBindDTO> list = query.getResultList();
+        BigInteger count = (BigInteger) countQuery.getSingleResult();
+        return new PageResult<>(count.longValue(), list);
+    }
+
+    @Override
+    public boolean deleteAreaparaGroup(TAreaparaGroup group) throws WebCheckException {
+        if (null != group) {
+            if (group.getGlobalflag()) {
+                throw new WebCheckException("默认参数组不能删除");
+            }
+            if (areaparaBindDao.getAreaparaBindRecordcnt(group.getGroupid()) > 0) {
+                throw new WebCheckException("该参数组下绑定了区域,请先解绑!");
+            }
+            tAreaparaDao.deleteAllByGroupid(group.getGroupid());
+            tAreaparaGroupDao.delete(group);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public List<TAreaparaGroup> queryAllAreaparaGroups() {
+        List<TAreaparaGroup> list = tAreaparaGroupDao.findAllByOrderByGroupid();
+        if (!StringUtil.isEmpty(list)) {
+            return list;
+        }
+        return new ArrayList<>(0);
+    }
+
+    @Override
+    public boolean saveBindAreapara(int groupid, List<Integer> areanos) throws WebCheckException {
+        TAreaparaGroup group = tAreaparaGroupDao.findByGroupid(groupid);
+        if (null == group) {
+            throw new WebCheckException("所选设备参数组不存在");
+        }
+        for (Integer areano : areanos) {
+            Optional<TArea> option = areaDao.findByAvailableAndAreano(1, areano);
+            if (!option.isPresent()) {
+                throw new WebCheckException("区域编号为[" + areano + "]的区域不存在");
+            }
+            TAreaparaBind bind = new TAreaparaBind();
+            bind.setAreano(option.get().getAreano());
+            bind.setGroupid(groupid);
+            bind.setLastsaved(systemUtilService.getSysdatetime().getHostdatetime());
+            areaparaBindDao.save(bind);
+        }
+        return true;
+    }
+
+    @Override
+    public TAreaparaBind getAreaparaBindByAreano(Integer areano) {
+        if (null != areano) {
+            return areaparaBindDao.findByAreano(areano);
+        }
+        return null;
+    }
+
+    @Override
+    public boolean deleteAreaparaBind(TAreaparaBind bind) {
+        if (null != bind) {
+            areaparaBindDao.delete(bind);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public PageResult<TArea> getAreaBySearch(String searchKey) {
+        StringBuffer sql = new StringBuffer("select a.areano,a.address,a.areaname,a.arealevel from tb_area a left join " +
+                "tb_areapara_bind b on a.areano = b.areano where a.available=1 and b.areano is null");
+        if (!StringUtil.isEmpty(searchKey)) {
+            sql.append(" and a.areaname like :str");
+        }
+        sql.append(" order by a.areano");
+        Query query = entityManager.createNativeQuery(sql.toString());
+        if (!StringUtil.isEmpty(searchKey)) {
+            query.setParameter("str", "%" + searchKey.trim() + "%");
+        }
+        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(TAreaparaBindAreaDTO.class));
+        return new PageResult<>(query.getResultList());
+    }
+}
diff --git a/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
index b1bb17c..71ec0be 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/framework/controller/security_controller.kt
@@ -56,6 +56,43 @@
     @Autowired
     lateinit var jwtConfig: JwtConfig
 
+    @GetMapping(value = ["/gettoken", "/gettoken/{clientid}"])
+    fun loginInit(appid: String, @PathVariable clientid: String?): ResponseEntity<Any> {
+
+        /*   tetantConfigDao.default?.also {
+               if (it.tenantId != tetantId) {
+                   throw TransactionCheckException(TradeErrorCode.INPUT_DATA_ERROR,
+                           "租户ID错误")
+               }
+           } ?: throw TransactionCheckException(TradeErrorCode.BUSINESS_DEAL_ERROR,
+                   "系统未配置租户信息")*/
+
+        apiClientDao.findById(appid).run {
+            if (!isPresent) {
+                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
+            }
+            if (get().status != TradeDict.STATUS_NORMAL) {
+                return ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .fail(TradeErrorCode.BUSINESS_DEAL_ERROR, "API状态错误"))
+            }
+            get()
+        }.let { api ->
+            val token = generateRandomToken()
+            val now = systemUtil.sysdatetime.hostdatetime
+            ApiClientRedis().also {
+                it.id = if (clientid == null) appid else "$appid-$clientid"
+                it.loginTimestamp = now
+                it.roles = api.roles
+                it.token = HmacUtil.HMACSHA256(token, api.secret)
+            }.also {
+                apiClientRepository.save(it)
+            }
+            return ResponseEntity.ok(ResponseBodyBuilder.create()
+                    .data("token", token)
+                    .data("timestamp", now)
+                    .success())
+        }
+    }
 
     private fun generateRandomToken(): String {
         val random = ByteArray(12) { 0x00 }
@@ -67,6 +104,37 @@
         return (api.token == secret)
     }
 
+    @GetMapping(value = ["/authentication", "/authentication/{clientid}"])
+    fun login(appid: String, sign: String, @PathVariable clientid: String?): ResponseEntity<Any> {
+        val requestId = if (clientid == null) appid else "$appid-$clientid"
+        return apiClientRepository.findById(requestId).let {
+            if (it.isPresent && checkSecretToken(it.get(), sign)) {
+                apiClientRepository.deleteById(requestId)
+                val token = JwtTokenUtil(jwtConfig).generateToken(
+                        mapOf(Constants.JWT_CLAIM_UID to appid,
+                                "issuer" to "payapi",
+                                "audience" to (clientid ?: appid),
+                                Constants.JWT_CLAIM_AUTHORITIES to it.get().roles.split(";")))
+                JwtRedis().apply {
+                    jti = token.jti
+                    uid = appid
+                    status = TradeDict.JWT_STATUS_NORMAL
+                    expiration = token.expiration.valueInMillis
+                }.apply {
+                    apiJwtRepository.save(this)
+                }
+
+                ResponseEntity.ok(ResponseBodyBuilder.create()
+                        .data("jwt", token.jwtToken)
+                        .data("appid", appid)
+                        .data("expiredAt", DateUtil.getUTCTime(token.expiration.valueInMillis))
+                        .success())
+            } else {
+                ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
+            }
+        }
+    }
+
 
     @GetMapping("/refresh")
     fun refresh(request: HttpServletRequest): ResponseEntity<Any> {
diff --git a/src/main/kotlin/com/supwisdom/dlpay/water/controller/api_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/water/controller/api_controller.kt
index 49a8b82..2545a7c 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/water/controller/api_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/water/controller/api_controller.kt
@@ -5,6 +5,7 @@
 import com.supwisdom.dlpay.framework.service.SystemUtilService
 import com.supwisdom.dlpay.framework.util.ShortURLUtil
 import com.supwisdom.dlpay.framework.util.TradeDict
+import com.supwisdom.dlpay.framework.util.WaterDeviceParam
 import com.supwisdom.dlpay.framework.util.WaterErrorCode
 import com.supwisdom.dlpay.system.service.UserDataService
 import com.supwisdom.dlpay.water.*
@@ -42,9 +43,9 @@
             val result = deviceService.deviceLogin(param)
             if (result["flag"] == true) {
                 return ResponseEntity.ok(ResponseBodyBuilder.create()
-                        .data("devOfflineMaxHour", result["devOfflineMaxHour"]!!)
-                        .data("pulseInHML", result["pulseInHML"]!!)
-                        .data("systemTime", systemUtilService.sysdatetime.hostdatetime)
+                        .data(WaterDeviceParam.devOfflineMaxHour, result[WaterDeviceParam.devOfflineMaxHour]!!)
+                        .data(WaterDeviceParam.pulseInHML, result[WaterDeviceParam.pulseInHML]!!)
+                        .data(WaterDeviceParam.systemTime, systemUtilService.sysdatetime.hostdatetime)
                         .success())
             }
             return ResponseEntity.ok(ResponseBodyBuilder.create()
@@ -114,7 +115,11 @@
 
     @PostMapping("/qrcode/init")
     fun qrcodePayInit(@RequestBody param: QrcodePayRequest): ResponseEntity<Any> {
-        try {//1. 创建并记录初始流水
+        try {
+            val feeConfig = deviceService.queryTFeeConfigByDeviceno(param.deviceno)
+                    ?: return ResponseEntity.ok(ResponseBodyBuilder.create()
+                            .fail(WaterErrorCode.DATA_NOTFOUND_ERROR, "未查询到该设备的费率信息"))
+            //1. 创建并记录初始流水
             val trans = TTransdtl().apply {
                 billno = systemUtilService.refno
                 mode = TradeDict.PAY_MODE_QRCODE
diff --git a/src/main/kotlin/com/supwisdom/dlpay/water/controller/water_controller.kt b/src/main/kotlin/com/supwisdom/dlpay/water/controller/water_controller.kt
index ca73565..fff95b0 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/water/controller/water_controller.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/water/controller/water_controller.kt
@@ -1,23 +1,25 @@
 package com.supwisdom.dlpay.water.controller
 
+import com.supwisdom.dlpay.api.bean.JsonResult
 import com.supwisdom.dlpay.framework.ResponseBodyBuilder
-import com.supwisdom.dlpay.framework.util.PageResult
-import com.supwisdom.dlpay.framework.util.StringUtil
-import com.supwisdom.dlpay.framework.util.TradeErrorCode
-import com.supwisdom.dlpay.framework.util.WaterErrorCode
+import com.supwisdom.dlpay.framework.util.*
+import com.supwisdom.dlpay.util.WebCheckException
+import com.supwisdom.dlpay.water.bean.*
 import com.supwisdom.dlpay.water.domain.TDevice
 import com.supwisdom.dlpay.water.domain.TArea
+import com.supwisdom.dlpay.water.pojo.TTransdtlDTO
 import com.supwisdom.dlpay.water.service.DeviceService
-import com.supwisdom.dlpay.water.system.bean.RegionSearchBean
 import com.supwisdom.dlpay.water.service.AreaService
-import com.supwisdom.dlpay.water.system.bean.DeviceSearchBean
+import com.supwisdom.dlpay.water.service.TransdtlService
+import com.supwisdom.dlpay.water.domain.TAreaparaGroup
+import com.supwisdom.dlpay.water.domain.TTransdtlCount
+import com.supwisdom.dlpay.water.pojo.TAreaparaBindDTO
+import com.supwisdom.dlpay.water.service.TAreaparaService
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.ResponseEntity
 import org.springframework.stereotype.Controller
+import org.springframework.ui.Model
 import org.springframework.web.bind.annotation.*
-import java.io.IOException
-import javax.servlet.http.HttpServletRequest
-import javax.servlet.http.HttpServletResponse
 
 @Controller
 class RegionController {
@@ -75,9 +77,10 @@
 
     @GetMapping("/region/search")
     @ResponseBody
-    fun queryRegions(@RequestParam(value = "searchkey", required = false) searchKey: String,
+    fun queryRegions(@RequestParam(value = "searchkey", required = false) searchKey: String?,
                      @RequestParam("page", defaultValue = "1", required = false) pageNo: Int,
                      @RequestParam("limit", defaultValue = "10", required = false) pageSize: Int): PageResult<TArea> {
+
         try {
             if (pageNo < 1 || pageSize < 1) {
                 return PageResult(WaterErrorCode.REQUEST_DATA_ERROR, "请求参数错误")
@@ -333,9 +336,262 @@
             deviceService.queryDeviceByParams(searchBean)?.let {
                 return it
             }
-            return PageResult(WaterErrorCode.DATA_NOTFOUND_ERROR, "区域未找到")
+            return PageResult(WaterErrorCode.DATA_NOTFOUND_ERROR, "设备未找到")
         } catch (ex: Exception) {
             return PageResult(WaterErrorCode.PROCESS_ERROR, "服务器繁忙,请稍后再试")
         }
     }
+}
+
+@Controller
+class TransdtlController {
+    @Autowired
+    private lateinit var transdtlService: TransdtlService
+
+    @GetMapping("/transdtl/index")
+    fun dtlIndexView() = "system/transdtl/index"
+
+    @GetMapping("/transdtl/list")
+    @ResponseBody
+    fun queryTransdtl(@RequestParam("devicename", required = false) devicename: String,
+                      @RequestParam("deviceno", required = false) deviceno: String,
+                      @RequestParam("areano", required = false) areanoStr: String,
+                      @RequestParam("transtime", required = false) transtime: String,
+                      @RequestParam("username", required = false) username: String,
+                      @RequestParam("page", defaultValue = "1", required = false) pageNo: Int,
+                      @RequestParam("limit", defaultValue = "10", required = false) pageSize: Int): PageResult<TTransdtlDTO> {
+        try {
+            if (pageNo < 1 || pageSize < 1) {
+                return PageResult(WaterErrorCode.REQUEST_DATA_ERROR, "请求参数错误")
+            }
+            val areano: Int?
+            areano = if (StringUtil.isEmpty(areanoStr)) {
+                null
+            } else {
+                areanoStr.toInt()
+            }
+            val searchBean = TransdtlSearchBean().apply {
+                this.pageNo = pageNo
+                this.pageSize = pageSize
+                this.devicename = devicename
+                this.deviceno = deviceno
+                this.areano = areano
+                this.username = username
+                this.transtime = transtime
+            }
+            transdtlService.queryTransdtlDTOByParam(searchBean)?.let {
+                return it
+            }
+            return PageResult(WaterErrorCode.DATA_NOTFOUND_ERROR, "设备未找到")
+        } catch (ex: Exception) {
+            return PageResult(WaterErrorCode.PROCESS_ERROR, "服务器繁忙,请稍后再试")
+        }
+    }
+
+    @GetMapping("/dtlcount/index")
+    fun dtlCountIndexView() = "system/dtlcount/index"
+
+    @GetMapping("/dtlcount/list")
+    @ResponseBody
+    fun queryDtlCount(@RequestParam("devicename", required = false) devicename: String,
+                      @RequestParam("areano", required = false) areanoStr: String,
+                      @RequestParam("transtime", required = false) transtime: String,
+                      @RequestParam("page", defaultValue = "1", required = false) pageNo: Int,
+                      @RequestParam("limit", defaultValue = "10", required = false) pageSize: Int): PageResult<TTransdtlCount> {
+        if (pageNo < 1 || pageSize < 1) {
+            return PageResult(WaterErrorCode.REQUEST_DATA_ERROR, "请求参数错误")
+        }
+        val areano: Int?
+        areano = if (StringUtil.isEmpty(areanoStr)) {
+            null
+        } else {
+            areanoStr.toInt()
+        }
+        val searchBean = TransdtlCountSearchBean().apply {
+            this.pageNo = pageNo
+            this.pageSize = pageSize
+            this.devicename = devicename
+            this.areano = areano
+            this.transtime = transtime
+        }
+        transdtlService.queryTransdtlCountByParam(searchBean)?.let {
+            return it
+        }
+        return PageResult(WaterErrorCode.DATA_NOTFOUND_ERROR, "流水统计未找到")
+    }
+}
+
+@Controller
+class AreaparaController {
+
+    @Autowired
+    private lateinit var tAreaparaService: TAreaparaService
+
+    @GetMapping("/areapara/index")
+    fun areaparaIndexView() = "system/areapara/index"
+
+    @GetMapping("/areapara/grouplist")
+    @ResponseBody
+    fun queryGroupList(@RequestParam("groupname", required = false) groupname: String?,
+                       @RequestParam("page", defaultValue = "1", required = false) pageNo: Int,
+                       @RequestParam("limit", defaultValue = "10", required = false) pageSize: Int): PageResult<TAreaparaGroup> {
+        try {
+            if (pageNo < 1 || pageSize < 1) {
+                return PageResult(WaterErrorCode.REQUEST_DATA_ERROR, "请求参数错误")
+            }
+            val searchBean = AreaparaSearchBean().apply {
+                this.groupname = groupname
+                this.pageNo = pageNo
+                this.pageSize = pageSize
+            }
+            tAreaparaService.queryParaGroupByParam(searchBean)?.let {
+                return it
+            }
+            return PageResult(WaterErrorCode.DATA_NOTFOUND_ERROR, "设备参数组未找到")
+        } catch (ex: Exception) {
+            return PageResult(WaterErrorCode.PROCESS_ERROR, "服务器繁忙,请稍后再试")
+        }
+    }
+
+    @GetMapping("/areapara/loadadd")
+    fun editView(@RequestParam("groupid", required = false) groupid: Int?, model: Model): String {
+        tAreaparaService.getAreaparaGroupByGroupid(groupid ?: -99)?.let {
+            model.addAttribute("areaparaGroup", it)
+            model.addAttribute("areaparaConfigList", tAreaparaService.getAreaparaInfo(it.groupid))
+            return "system/areapara/form"
+        }
+        val group = TAreaparaGroup()
+        group.groupid = 0
+        model.addAttribute("areaparaGroup", group)
+        model.addAttribute("areaparaConfigList", tAreaparaService.getAreaparaInfo(0))
+        return "system/areapara/form"
+    }
+
+    @PostMapping("/areapara/editareapara")
+    @ResponseBody
+    fun editAreapara(@RequestBody param: HashMap<String, String>?): JsonResult {
+        val groupidHtmlKey = "form_areapara_groupid"   //页面上传来groupid的KEY
+        val groupnameHtmlKey = "form_areapara_groupname" //页面上传来groupname的KEY
+        if (null == param || !NumberUtil.isDigits(param[groupidHtmlKey]) || StringUtil.isEmpty(groupnameHtmlKey)) {
+            return JsonResult.error("参数传递错误")
+        }
+        try {
+            val groupid = Integer.parseInt(param[groupidHtmlKey])
+            val groupname = param[groupnameHtmlKey]?.trim { it <= ' ' }
+            param.remove(groupidHtmlKey)
+            param.remove(groupnameHtmlKey)
+            val msg: String
+            return if (tAreaparaService.saveOrUpdateAreapara(groupid, groupname, param)) {
+                msg = if (groupid == 0) {
+                    "新增成功"
+                } else {
+                    "修改成功"
+                }
+                JsonResult.ok(msg)
+            } else {
+                msg = if (groupid == 0) {
+                    "新增失败"
+                } else {
+                    "修改失败"
+                }
+                JsonResult.ok(msg)
+            }
+        } catch (ex: WebCheckException) {
+            return JsonResult.error(ex.message)
+        } catch (ex: Exception) {
+            ex.printStackTrace()
+            return JsonResult.error("系统处理异常").put("exception", ex)!!
+        }
+    }
+
+    @PostMapping("/areapara/deleteareapara")
+    @ResponseBody
+    fun deleteAreapara(@RequestParam("groupid") groupid: Int?):JsonResult {
+        try {
+            if (null == groupid) {
+                return JsonResult.error("参数传递错误")
+            }
+            val group = tAreaparaService.getAreaparaGroupByGroupid(groupid) ?: return JsonResult.error("参数组不存在!")
+            return if (tAreaparaService.deleteAreaparaGroup(group)) {
+                JsonResult.ok("删除成功")
+            } else {
+                JsonResult.error("删除失败")
+            }
+        } catch (ex: WebCheckException) {
+            return JsonResult.error(ex.message)
+        }catch (ex: Exception) {
+            ex.printStackTrace()
+            return JsonResult.error("系统处理异常").put("exception", ex)!!
+        }
+    }
+
+    @GetMapping("/areaparabind/index")
+    fun parambindIndexView() = "/system/areaparabind/index"
+
+    @GetMapping("/areapara/areaparabindlist")
+    @ResponseBody
+    fun getAreaparaBindData(
+            @RequestParam("page", defaultValue = "1", required = false) pageNo: Int,
+            @RequestParam("limit", defaultValue = "10", required = false) pageSize: Int,
+            @RequestParam(value = "searchkey", required = false) searchkey: String?): PageResult<TAreaparaBindDTO> {
+        try {
+            if (pageNo < 1 || pageSize < 1) {
+                return PageResult(WaterErrorCode.REQUEST_DATA_ERROR, "请求参数错误")
+            }
+            return tAreaparaService.getAreaparaBindInfos(searchkey,pageNo,pageSize)
+        } catch (ex: Exception) {
+            ex.printStackTrace()
+            return PageResult(WaterErrorCode.PROCESS_ERROR,"系统繁忙,请稍后重试")
+        }
+    }
+
+    @GetMapping("/areapara/loadbindadd")
+    fun loadBindView(model: Model):String {
+        model.addAttribute("grouplist",tAreaparaService.queryAllAreaparaGroups())
+        return "/system/areaparabind/form"
+    }
+
+    @PostMapping("/areapara/addbindareapara")
+    @ResponseBody
+    fun addAreaparaBind(@RequestParam("groupid") groupid: Int,
+                        @RequestParam("areano[]") areanos: List<Int>): JsonResult? {
+        return try {
+            if (tAreaparaService.saveBindAreapara(groupid, areanos)) {
+                JsonResult.ok("绑定成功")
+            } else {
+                JsonResult.ok("绑定失败")
+            }
+        } catch (ex: WebCheckException) {
+            JsonResult.error(ex.message)
+        } catch (ex: Exception) {
+            ex.printStackTrace()
+            JsonResult.error("系统处理异常").put("exception",ex)
+        }
+    }
+
+    @PostMapping("/areapara/deleteareaparabind")
+    @ResponseBody
+    fun deleteAreaparaBind(@RequestParam("areano") areano: Int): JsonResult? {
+        try {
+            val bind = tAreaparaService.getAreaparaBindByAreano(areano) ?: return JsonResult.error("区域参数组绑定关系不存在")
+            return if (tAreaparaService.deleteAreaparaBind(bind)) {
+                JsonResult.ok("删除成功")
+            } else {
+                JsonResult.error("删除失败")
+            }
+        } catch (ex: Exception) {
+            ex.printStackTrace()
+            return JsonResult.error("系统处理异常").put("exception", ex)
+        }
+    }
+
+    @GetMapping("/areapara/arealist")
+    @ResponseBody
+    fun getAreaList(@RequestParam("searchkey") searchKey: String?):PageResult<TArea> {
+        return try {
+            tAreaparaService.getAreaBySearch(searchKey)
+        } catch (ex: Exception) {
+            PageResult(WaterErrorCode.PROCESS_ERROR, "服务器繁忙,请稍后再试")
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/com/supwisdom/dlpay/water/service/transdtl_service.kt b/src/main/kotlin/com/supwisdom/dlpay/water/service/transdtl_service.kt
index 240f03e..9320bfd 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/water/service/transdtl_service.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/water/service/transdtl_service.kt
@@ -1,21 +1,42 @@
 package com.supwisdom.dlpay.water.service
 
 import com.supwisdom.dlpay.exception.TransactionProcessException
+import com.supwisdom.dlpay.framework.util.PageResult
+import com.supwisdom.dlpay.framework.util.StringUtil
 import com.supwisdom.dlpay.framework.util.TradeDict
 import com.supwisdom.dlpay.framework.util.WaterErrorCode
 import com.supwisdom.dlpay.water.QrcodeQueryRequest
 import com.supwisdom.dlpay.water.UploadRecordRequest
 import com.supwisdom.dlpay.water.UserAuthRequest
+import com.supwisdom.dlpay.water.bean.TransdtlCountSearchBean
 import com.supwisdom.dlpay.water.dao.TransdtlDao
 import com.supwisdom.dlpay.water.domain.TTransdtl
+import com.supwisdom.dlpay.water.pojo.TTransdtlDTO
+import com.supwisdom.dlpay.water.bean.TransdtlSearchBean
+import com.supwisdom.dlpay.water.dao.TransdtlCountDao
+import com.supwisdom.dlpay.water.domain.TTransdtlCount
 import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.data.domain.PageRequest
+import org.springframework.data.jpa.domain.Specification
 import org.springframework.stereotype.Service
+import java.util.ArrayList
+import javax.persistence.EntityManager
+import javax.persistence.criteria.CriteriaBuilder
+import javax.persistence.criteria.CriteriaQuery
+import javax.persistence.criteria.Predicate
+import javax.persistence.criteria.Root
 
 @Service
 class TransdtlServiceImpl : TransdtlService {
     @Autowired
     private lateinit var transdtlDao: TransdtlDao
 
+    @Autowired
+    private lateinit var em: EntityManager
+
+    @Autowired
+    private lateinit var transdtlCountDao: TransdtlCountDao
+
     override fun createNewTransdtl(dtl: TTransdtl): TTransdtl {
         transdtlDao.save(dtl)
         return dtl
@@ -40,8 +61,8 @@
 
     override fun queryTrans(param: QrcodeQueryRequest): TTransdtl {
         return transdtlDao.findByBillnoAndDeviceno(param.billno, param.deviceno)
-            ?: throw TransactionProcessException(WaterErrorCode.DATA_NOTFOUND_ERROR,
-                    "交易订单号不存在")
+                ?: throw TransactionProcessException(WaterErrorCode.DATA_NOTFOUND_ERROR,
+                        "交易订单号不存在")
     }
 
     override fun userAuth(param: UserAuthRequest): TTransdtl {
@@ -53,4 +74,104 @@
         transdtlDao.save(dtl)
         return dtl
     }
+
+    override fun queryTransdtlDTOByParam(param: TransdtlSearchBean): PageResult<TTransdtlDTO>? {
+        var sql =StringBuffer("select t1.billno,t1.amount,t1.bankcardno,t1.deviceno,t1.mode,t1.status,t1.transdate,t1.transtime,t1.water_in_100ml water_sum_hundred_litre,t1.name username,t2.devicename,t2.areaname,t2.areano  " +
+                "from (select dtl.*,person.name from tb_transdtl dtl left join tb_person person on dtl.userid = person.userid) t1," +
+                "(select device.deviceno,device.devicename,area.areaname,area.areano from tb_device device,tb_area area where device.areano = area.areano) t2 " +
+                "where t1.deviceno = t2.deviceno")
+        var countSql =StringBuffer("select count(billno) " +
+                "from (select dtl.*,person.name from tb_transdtl dtl left join tb_person person on dtl.userid = person.userid) t1," +
+                "(select device.deviceno,device.devicename,area.areaname,area.areano from tb_device device,tb_area area where device.areano = area.areano) t2 " +
+                "where t1.deviceno = t2.deviceno")
+        val map: HashMap<String, Int> = HashMap()
+        var position = 1
+        if (!StringUtil.isEmpty(param.transtime)) {
+            sql.append(" and transdate >=?")
+            countSql.append(" and transdate >=?")
+
+            sql.append(" and transdate <=?")
+            countSql.append(" and transdate <=?")
+            map["mindate"] = position++
+            map["maxdate"] = position++
+        }
+        if (!StringUtil.isEmpty(param.username)) {
+            sql.append(" and name like ?")
+            countSql.append(" and name like ?")
+            map["username"] = position++
+        }
+        if (!StringUtil.isEmpty(param.deviceno)) {
+            sql.append(" and t1.deviceno like ?")
+            countSql.append(" and t1.deviceno like ?")
+            map["deviceno"] = position++
+        }
+        if (!StringUtil.isEmpty(param.devicename)) {
+            sql.append(" and devicename like ?")
+            countSql.append(" and devicename like ?")
+            map["devicename"] = position++
+        }
+        param.areano?.let {
+            sql.append(" and areano  =?")
+            countSql.append(" and areano  =?")
+            map.put("areano", position++)
+        }
+        sql.append(" order by billno desc limit " + param.pageSize + " offset " + (param.pageNo - 1) * param.pageSize)
+        val query = em.createNativeQuery(sql.toString(),TTransdtlDTO::class.java)
+        val countQuery = em.createNativeQuery(countSql.toString())
+        map["devicename"]?.let {
+            query.setParameter(it, "%" + param.devicename + "%")
+            countQuery.setParameter(it, "%" + param.devicename + "%")
+        }
+        map["deviceno"]?.let {
+            query.setParameter(it, "%"+param.deviceno+"%")
+            countQuery.setParameter(it, "%"+param.deviceno+"%")
+        }
+        map["areano"]?.let {
+            query.setParameter(it, param.areano)
+            countQuery.setParameter(it, param.areano)
+        }
+        map["username"]?.let {
+            query.setParameter(it, "%" + param.username + "%")
+            countQuery.setParameter(it, "%" + param.username + "%")
+        }
+        map["mindate"]?.let {
+
+            val timerange = param.transtime.replace("-","").split("  ")
+            query.setParameter(it, timerange[0])
+            query.setParameter(map["maxdate"]!!, timerange[1])
+            countQuery.setParameter(it, timerange[0])
+            countQuery.setParameter(map["maxdate"]!!, timerange[1])
+        }
+        val transdtlDTO:List<TTransdtlDTO> = query.resultList as List<TTransdtlDTO>
+        val count:Int = countQuery.singleResult.toString().toInt()
+        val result: PageResult<TTransdtlDTO> = PageResult()
+        result.apply {
+            this.data = transdtlDTO
+            this.count = count.toLong()
+            this.code = 0
+            this.msg = "成功"
+        }
+        return result
+    }
+
+    override fun queryTransdtlCountByParam(param: TransdtlCountSearchBean): PageResult<TTransdtlCount> {
+        val pageable = PageRequest.of(param.pageNo - 1, param.pageSize)
+        val specification = { root:Root<TTransdtlCount>, query:CriteriaQuery<Any>, cb:CriteriaBuilder ->
+            val predicates = ArrayList<Predicate>()
+            if (param.areano != null) {
+                predicates.add(cb.equal(root.get<Int>("areano").`as`(Int::class.java), param.areano))
+            }
+            if (!StringUtil.isEmpty(param.devicename)) {
+                predicates.add(cb.like(root.get("devicename"), "%" + param.devicename + "%"))
+            }
+            if (!StringUtil.isEmpty(param.transtime)) {
+                val timerange = param.transtime.replace("-","").split("  ")
+                predicates.add(cb.greaterThanOrEqualTo(root.get("accdate"),timerange[0]))
+                predicates.add(cb.lessThanOrEqualTo(root.get("accdate"),timerange[0]))
+            }
+            query.where(*predicates.toTypedArray()).restriction
+        } as Specification<TTransdtlCount>
+        val dtlCountPage = transdtlCountDao.findAll(specification, pageable)
+        return PageResult<TTransdtlCount>(dtlCountPage)
+    }
 }
\ No newline at end of file
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
index 679018d..7e033e6 100644
--- a/src/main/resources/data.sql
+++ b/src/main/resources/data.sql
@@ -23,13 +23,25 @@
 
 Insert into TB_FUNCTION (ID,CREATETIME,ISLEAF,LASTSAVED,MENUICON,MENUURL,NAME,ORDERNUM,PARENTID) values ('1',null,0,null,'layui-icon-home','#','主页',1,'-1');
 Insert into TB_FUNCTION (ID,CREATETIME,ISLEAF,LASTSAVED,MENUICON,MENUURL,NAME,ORDERNUM,PARENTID) values ('2',null,1,null,'layui-icon-home','/home/console','控制台',1,'1');
-
+INSERT INTO "tb_function"("id", "createtime", "isleaf", "lastsaved", "menuicon", "menuurl", "name", "ordernum", "parentid") VALUES (6, NULL, 1, NULL, 'layui-icon-set', '/region/index', '区域管理', 2, 1);
+INSERT INTO "tb_function"("id", "createtime", "isleaf", "lastsaved", "menuicon", "menuurl", "name", "ordernum", "parentid") VALUES (7, NULL, 1, NULL, 'layui-icon-set', '/device/index', '设备管理', 3, 1);
+INSERT INTO "tb_function"("id", "createtime", "isleaf", "lastsaved", "menuicon", "menuurl", "name", "ordernum", "parentid") VALUES (8, NULL, 1, NULL, 'layui-icon-set', '/transdtl/index', '流水查询', 4, 1);
+INSERT INTO "tb_function"("id", "createtime", "isleaf", "lastsaved", "menuicon", "menuurl", "name", "ordernum", "parentid") VALUES (9, NULL, 1, NULL, 'layui-icon-set', '/dtlcount/index', '流水统计', 5, 1);
+INSERT INTO "tb_function"("id", "createtime", "isleaf", "lastsaved", "menuicon", "menuurl", "name", "ordernum", "parentid") VALUES (10, NULL, 1, NULL, 'layui-icon-set', '/areapara/index', '设备参数组管理', 6, 1);
+INSERT INTO "tb_function"("id", "createtime", "isleaf", "lastsaved", "menuicon", "menuurl", "name", "ordernum", "parentid") VALUES (11, NULL, 1, NULL, 'layui-icon-set', '/areaparabind/index', '水控参数区域绑定', 7, 1);
 
 Insert into TB_ROLE_FUNCTION (ID,FUNCTIONID,ROLEID) values ('5','5','d1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
 Insert into TB_ROLE_FUNCTION (ID,FUNCTIONID,ROLEID) values ('1','1','d1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
 Insert into TB_ROLE_FUNCTION (ID,FUNCTIONID,ROLEID) values ('2','2','d1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
 Insert into TB_ROLE_FUNCTION (ID,FUNCTIONID,ROLEID) values ('3','3','d1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
 Insert into TB_ROLE_FUNCTION (ID,FUNCTIONID,ROLEID) values ('4','4','d1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
+INSERT INTO "tb_role_function"("id", "functionid", "permissions", "roleid") VALUES ('6', 6, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
+INSERT INTO "tb_role_function"("id", "functionid", "permissions", "roleid") VALUES ('7', 7, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
+INSERT INTO "tb_role_function"("id", "functionid", "permissions", "roleid") VALUES ('8', 8, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
+-- INSERT INTO "tb_role_function"("id", "functionid", "permissions", "roleid") VALUES ('9', 9, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
+INSERT INTO "tb_role_function"("id", "functionid", "permissions", "roleid") VALUES ('10', 10, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
+INSERT INTO "tb_role_function"("id", "functionid", "permissions", "roleid") VALUES ('11', 11, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
+
 
 
 -- 资产类
@@ -72,6 +84,7 @@
 Insert into TB_SUBJECT (SUBJNO,SUBJNAME,SUBJTYPE,BALFLAG,FSUBJNO,SUBJLEVEL,ENDFLAG,OPENDATE,DISPLAYFLAG) values ('660102','积分抵扣款',6,2,'6601',2,1,null,'y');
 
 Insert into TB_SUBJECT (SUBJNO,SUBJNAME,SUBJTYPE,BALFLAG,FSUBJNO,SUBJLEVEL,ENDFLAG,OPENDATE,DISPLAYFLAG) values ('6602','管理费收入',6,2,null,1,1,null,'y');
+Insert into TB_SUBJECT (SUBJNO,SUBJNAME,SUBJTYPE,BALFLAG,FSUBJNO,SUBJLEVEL,ENDFLAG,OPENDATE,DISPLAYFLAG) values ('112234','市民卡支付款',1,1,'1122',2,1,null,'y');
 -- -- oracle --
 -- update TB_SUBJECT set opendate = to_char(sysdate,'yyyyMMdd');
 
@@ -90,21 +103,31 @@
 
 -- --pg--
 
-
-Insert into TB_SUBJECT (SUBJNO,SUBJNAME,SUBJTYPE,BALFLAG,FSUBJNO,SUBJLEVEL,ENDFLAG,OPENDATE,DISPLAYFLAG) values ('112234','市民卡支付款',1,1,'1122',2,1,null,'y');
-INSERT INTO "tb_function"("id", "createtime", "isleaf", "lastsaved", "menuicon", "menuurl", "name", "ordernum", "parentid") VALUES (6, NULL, 1, NULL, 'layui-icon-set', '/region/index', '区域管理', 2, 1);
-INSERT INTO "tb_function"("id", "createtime", "isleaf", "lastsaved", "menuicon", "menuurl", "name", "ordernum", "parentid") VALUES (7, NULL, 1, NULL, 'layui-icon-set', '/device/index', '设备管理', 3, 1);
-INSERT INTO "tb_role_function"("id", "functionid", "permissions", "roleid") VALUES ('6', 6, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
-INSERT INTO "tb_role_function"("id", "functionid", "permissions", "roleid") VALUES ('7', 7, NULL, 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
-
 CREATE SEQUENCE "seq_refno" INCREMENT 1MINVALUE  1MAXVALUE 9223372036854775807 START 1 CACHE 1;
 ALTER SEQUENCE "seq_refno" OWNER TO "watermanager";
 
 
-INSERT INTO "tb_devicefeeconfig"("deviceid", "feecfgversion", "feeconfig") VALUES (1, NULL, 1);
+INSERT INTO "tb_devicefeeconfig"("areano", "feecfgversion", "feeconfig") VALUES (1, NULL, 1);
 INSERT INTO "tb_feeconfig"("id", "amount", "max_water_litre", "cfg_version") VALUES (1, 1, 50, NULL);
 INSERT INTO "tb_person_identity"("third_uid", "createtime", "lockflag", "lossflag", "status", "userid") VALUES ('1', NULL, 0, 0, '1', 'd1yctWs5+ks0iQN3m9bUvRHus6HbKbrs');
-INSERT INTO "tb_person"("userid", "addr", "country", "email", "idno", "idtype", "lastsaved", "mobile", "name", "nation", "sex", "status", "tel", "zipcode") VALUES ('d1yctWs5+ks0iQN3m9bUvRHus6HbKbrs', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '1', NULL, NULL);
+INSERT INTO "tb_person"("userid", "addr", "country", "email", "idno", "idtype", "lastsaved", "mobile", "name", "nation", "sex", "status", "tel", "zipcode") VALUES ('d1yctWs5+ks0iQN3m9bUvRHus6HbKbrs', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '王富贵', NULL, NULL, '1', NULL, NULL);
 INSERT INTO "tb_businesspara"("parakey", "paraval") VALUES ('water_auth_url', 'http://172.28.43.20:8080/water/api/confirm?billno=');
 
+INSERT INTO "tb_dictionary"("dictval", "dicttype", "dictcaption", "dicttypename") VALUES ('正常', 1, 'normal', '设备状态');
+INSERT INTO "tb_dictionary"("dictval", "dicttype", "dictcaption", "dicttypename") VALUES ('注销', 1, 'closed', '设备状态');
+INSERT INTO "tb_dictionary"("dictval", "dicttype", "dictcaption", "dicttypename") VALUES ('签出', 1, 'logout', '设备状态');
+
+INSERT INTO "tb_areapara_group"("groupid", "globalflag", "groupname", "lastsaved", "verno") VALUES (1, 't', '默认参数组', '20190628133646', 7);
+
+INSERT INTO "tb_areapara"("paraname", "groupid", "maxval", "minval", "paradesc", "paraval", "valtype") VALUES ('water_limit', 1, '500', '1', '单次用水上限(单位:百毫升)', '200', 'N');
+INSERT INTO "tb_areapara"("paraname", "groupid", "maxval", "minval", "paradesc", "paraval", "valtype") VALUES ('app_water_limit', 1, '500', '1', 'app单次用水上限(单位:百毫升)', '200', 'N');
+INSERT INTO "tb_areapara"("paraname", "groupid", "maxval", "minval", "paradesc", "paraval", "valtype") VALUES ('code_vaildtime', 1, '240', '60', '二维码有效时间(单位:秒)', '180', 'N');
+INSERT INTO "tb_areapara"("paraname", "groupid", "maxval", "minval", "paradesc", "paraval", "valtype") VALUES ('wait_water_time', 1, '180', '60', '出水等待时间(单位:秒):超出这个时间,自动关闭水阀门', '90', 'N');
+INSERT INTO "tb_areapara"("paraname", "groupid", "maxval", "minval", "paradesc", "paraval", "valtype") VALUES ('dev_offline_maxHour', 1, '168', '1', '设备最大脱机时间(单位:小时)', '72', 'N');
+INSERT INTO "tb_areapara"("paraname", "groupid", "maxval", "minval", "paradesc", "paraval", "valtype") VALUES ('amount_limit', 1, '50', '1', '单次消费金额上限(单位:元)', '30', 'N');
+INSERT INTO "tb_areapara"("paraname", "groupid", "maxval", "minval", "paradesc", "paraval", "valtype") VALUES ('month_amount_limit', 1, '1500', '30', '月累计消费金额上限(单位:元)', '900', 'N');
+INSERT INTO "tb_areapara"("paraname", "groupid", "maxval", "minval", "paradesc", "paraval", "valtype") VALUES ('fee_amount', 1, '100', '1', '单位扣费金额(单位:百毫升/分)', '10', 'N');
+
+
+
 commit;
\ No newline at end of file
diff --git a/src/main/resources/templates/system/areapara/form.html b/src/main/resources/templates/system/areapara/form.html
new file mode 100644
index 0000000..cca0af8
--- /dev/null
+++ b/src/main/resources/templates/system/areapara/form.html
@@ -0,0 +1,123 @@
+<form id="areapara-form" lay-filter="areapara-form-filter" class="layui-form model-form"
+      style="padding: 30px 25px 10px 25px;">
+    <div class="layui-form-item">
+        <div class="layui-inline">
+            <label class="layui-form-label">参数组编号</label>
+            <div class="layui-input-inline">
+                <input name="form_areapara_groupid" id="form-areapara-groupid" type="text" class="layui-input" style="background-color:#fafafa;"
+                       th:value="${areaparaGroup.groupid}" autocomplete="off" readonly="readonly"/>
+            </div>
+        </div>
+        <div class="layui-inline">
+            <label class="layui-form-label">参数组名称</label>
+            <div class="layui-input-inline">
+                <input name="form_areapara_groupname" id="form-areapara-groupname" type="text" maxlength="20" class="layui-input"
+                       th:value="${areaparaGroup.groupname}" autocomplete="off" lay-verify="required" required/>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item">
+        <table class="layui-table" lay-size="sm" style="margin-bottom: 0;">
+            <colgroup>
+                <col width="220">
+                <col width="150">
+                <col width="80">
+                <col>
+            </colgroup>
+            <thead>
+            <tr>
+                <th style="text-align: center">参数名</th>
+                <th style="text-align: center">参数值</th>
+                <th style="text-align: center">值类型</th>
+                <th style="text-align: center">参数描述</th>
+            </tr>
+            </thead>
+        </table>
+        <div style="max-height: 400px;overflow-y: auto;">
+            <table class="layui-table" lay-size="sm" style="margin-top: 0;">
+                <colgroup>
+                    <col width="220">
+                    <col width="150">
+                    <col width="80">
+                    <col>
+                </colgroup>
+                <tbody>
+                <tr th:each="config:${areaparaConfigList}">
+                    <td th:text="${config.paraname}" style="text-align: left;background-color:#fafafa;">参数名</td>
+                    <td style="text-align: center"><input type="text" class="layui-input layui-table-edit" style="border: 0;box-shadow: 0px 0px 1px rgba(0,0,0,.15);"
+                                                          th:name="${config.paraname}" th:value="${config.paraval}" /></td>
+                    <td style="text-align: center;background-color:#fafafa;" th:switch="${config.valtype}">
+                        <span th:case="N">整型</span>
+                        <span th:case="B">布尔型</span>
+                        <span th:case="A">浮点型</span>
+                        <span th:case="D">时间</span>
+                        <span th:case="T">时间</span>
+                        <span th:case="DT">时间</span>
+                        <span th:case="TS">时间</span>
+                        <span th:case="*">字符串</span>
+                    </td>
+                    <td style="text-align: left;background-color:#fafafa;" th:text="${config.paradesc}">参数描述</td>
+                </tr>
+                </tbody>
+            </table>
+        </div>
+    </div>
+
+    <div class="layui-form-item model-form-footer">
+        <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button>
+        <button class="layui-btn" lay-filter="form-submit" lay-submit id="submitbtn">保存</button>
+    </div>
+</form>
+
+<script>
+    layui.use(['layer', 'admin', 'form'], function () {
+        var layer = layui.layer;
+        var admin = layui.admin;
+        var form = layui.form;
+        // 表单提交事件
+        form.on('submit(form-submit)', function (data) {
+            layer.load(2);
+            var vdata = data.field;
+            if(JSON.stringify(vdata)=="{}"){
+                layer.closeAll('loading');
+                admin.closePopupCenter();
+                return; //无配置项,直接关闭
+            }
+            var token=$("meta[name='_csrf_token']").attr("value");
+            console.log('areapara:',vdata);
+            debugger
+            $.ajax({
+                type : "POST",
+                dataType : "json",
+                url : '[[@{/areapara/editareapara}]]',
+                headers: {
+                    'Accept': 'application/json',
+                    'Content-Type': 'application/json',
+                    'X-CSRF-TOKEN':token,
+                },
+                data : JSON.stringify(vdata),
+                success : function(result) {
+                    layer.closeAll('loading');
+                    if (result.code == 200) {
+                        layer.msg(result.msg, {icon: 1});
+                        admin.finishPopupCenter();
+                    } else if (result.code == 401) {
+                        layer.msg(result.msg, {icon: 2, time: 1500}, function () {
+                            location.replace('[[@{/login}]]');
+                        }, 1000);
+                        return;
+                    } else {
+                        console.log('err:' + result.code);
+                        layer.msg(result.msg, {icon: 2});
+                    }
+                },
+                error : function() {
+                    layer.closeAll('loading');
+                    layer.msg("请求服务器失败!", {icon: 2});
+                }
+            });
+            return false;
+        });
+    });
+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/system/areapara/index.html b/src/main/resources/templates/system/areapara/index.html
new file mode 100644
index 0000000..ae43566
--- /dev/null
+++ b/src/main/resources/templates/system/areapara/index.html
@@ -0,0 +1,132 @@
+<div class="layui-card">
+    <div class="layui-card-header">
+        <h2 class="header-title">设备参数组管理</h2>
+        <span class="layui-breadcrumb pull-right">
+          <a href="#">主页</a>
+          <a><cite>设备参数组管理</cite></a>
+        </span>
+    </div>
+    <div class="layui-card-body">
+        <div class="layui-form toolbar">
+            搜索:
+            <input id="search-areaparagroup-groupname" class="layui-input search-input" maxlength="20" type="text" placeholder="输入参数组名称"/>&emsp;
+            <button id="btn-search-areaparagroup" class="layui-btn icon-btn" data-type="search"><i class="layui-icon">&#xe615;</i>搜索
+            </button>
+            <button id="search-areaparagroup-add" class="layui-btn icon-btn" data-type="add"><i class="layui-icon">&#xe654;</i>新 增</button>
+        </div>
+        <table class="layui-table" id="areaparagroupTable" lay-filter="areaparagroupTable-filter"></table>
+    </div>
+</div>
+
+
+<!-- 表格操作列 -->
+<script type="text/html" id="areaparagroup-table-bar">
+    <a class="layui-btn layui-btn layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"/>修改</a>
+    {{# if(!d.globalflag){ }}
+    <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"/>删除</a>
+    {{# } }}
+</script>
+
+<script>
+    layui.use(['form', 'table', 'layer', 'admin', 'element'], function () {
+        var form = layui.form;
+        var table = layui.table;
+        var admin = layui.admin;
+        // 渲染表格
+        table.render({
+            elem: '#areaparagroupTable',
+            url: '[[@{/areapara/grouplist}]]',
+            page: true,
+            cols: [
+                [
+                    {field: 'groupid', title: '参数组编号', width: 150, align: 'center'},
+                    {field: 'groupname', title: '参数组名称', align: 'center'},
+                    {field: 'verno', title: '参数组版本号', align: 'center'},
+                    {field: 'globalflag', title: '默认配置', align: 'center', templet: function(d){
+                            if(d.globalflag) {
+                                return '是'
+                            }else {
+                                return '否'
+                            }
+                        }},
+                    {
+                        field: 'lastsaved', title: '更新时间', align: 'center', templet: function (d) {
+                            if(d.lastsaved!=null){
+                                return admin.formatDate(d.lastsaved);
+                            }
+                            return '';
+                        }
+                    },
+                    {align: 'center', title: '操作', width: 250, toolbar: '#areaparagroup-table-bar',  fixed: 'right'}
+                ]
+            ]
+        });
+
+        // 搜索按钮点击事件
+        $('#btn-search-areaparagroup').click(function () {
+            var paraname = $("#search-areaparagroup-groupname").val().trim();
+            table.reload('areaparagroupTable', {where: {groupname: paraname}, page: {curr: 1},text:{none:"没有符合查询条件的参数组"}});
+        });
+
+        $('#search-areaparagroup-add').click(function () {
+            admin.popupCenter({
+                title: "新增设备参数组",
+                path: '[[@{/areapara/loadadd}]]',
+                area: '1200px',
+                finish: function () {
+                    table.reload('areaparagroupTable',{
+                        where:{groupname:""},
+                        url:'[[@{/areapara/grouplist}]]',
+                        page:{
+                            curr:1
+                        }
+                    });
+                }
+            });
+        });
+
+        //监听单元格
+        table.on('tool(areaparagroupTable-filter)', function (obj) {
+            var data = obj.data;
+
+            if('del' == obj.event){
+                layer.confirm('确定要删除设备参数组【'+data.groupname+'】?', {
+                    btn: ['确定', '取消']
+                },function(){
+                    layer.closeAll('dialog');
+                    layer.load(2);
+                    admin.go('[[@{/areapara/deleteareapara}]]', {
+                        groupid: data.groupid,
+                        _csrf: $("meta[name='_csrf_token']").attr("value")
+                    }, function (data) {
+                        console.log(data.code);
+                        layer.closeAll('loading');
+                        if (data.code == 200) {
+                            layer.msg(data.msg, {icon: 1});
+                        } else if (data.code == 401) {
+                            layer.msg(data.msg, {icon: 2, time: 1500}, function () {
+                                location.replace('[[@{/login}]]');
+                            }, 1000);
+                            return;
+                        } else {
+                            layer.msg(data.msg, {icon: 2});
+                        }
+                        table.reload('areaparagroupTable');
+                    }, function (err) {
+                        admin.errorBack(err)
+                    });
+                });
+            }else if('edit' == obj.event){
+                admin.popupCenter({
+                    title: "修改参数组【" + data.groupid + "_" + data.groupname + "】",
+                    path: '[[@{/areapara/loadadd}]]?groupid=' + data.groupid,
+                    area: '1200px',
+                    finish: function () {
+                        table.reload('areaparagroupTable');
+                    }
+                });
+            }
+        });
+
+    });
+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/system/areaparabind/form.html b/src/main/resources/templates/system/areaparabind/form.html
new file mode 100644
index 0000000..a34a9d5
--- /dev/null
+++ b/src/main/resources/templates/system/areaparabind/form.html
@@ -0,0 +1,138 @@
+<div id="areaparabind-form" lay-filter="areaparabind-form-filter" class="layui-form model-form"
+     style="padding: 30px 25px 10px 25px;">
+    <div class="layui-form-item">
+        <div class="layui-input-inline" style="width: 300px;">
+            <label class="layui-form-label">参数组</label>
+            <div class="layui-input-block">
+                <select lay-verify="required" class="layui-select" id="areaparabind-form-select-groupid">
+                    <option th:each="gp:${grouplist}" th:value="${gp.groupid}"
+                            th:text="${gp.groupname}"></option>
+                </select>&emsp;
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item">
+        <label class="layui-form-label">选择区域</label>
+        <div class="layui-input-block" style="border: 1px solid #ddd;border-radius: 4px;padding: 10px;">
+            <div class="layui-card-body">
+                <div class="layui-form toolbar">
+                    区域:
+                    <input id="search-areaparabind-form-searchkey" type="text" class="layui-input search-input"
+                           maxlength="20" style="width: 200px;" placeholder="输入区域名称"/>&emsp;
+                    <button id="btn-search-areaparabind-form" class="layui-btn icon-btn"><i
+                            class="layui-icon">&#xe615;</i>搜索
+                    </button>
+
+                    <table class="layui-table" id="areaparabindformTable" lay-filter="areaparabindformTable-filter"></table>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <div class="layui-form-item model-form-footer">
+        <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button>
+        <button class="layui-btn" lay-filter="form-submit" lay-submit id="submitbtn">保存</button>
+    </div>
+</div>
+
+<style type="text/css" id="areaparabind-form-css">
+    .layui-form-item .layui-form-checkbox[lay-skin=primary] {
+        margin-top: 0;
+    }
+</style>
+
+<script>
+    layui.use(['layer', 'table', 'admin', 'form', 'treeSelect'], function () {
+        var layer = layui.layer;
+        var admin = layui.admin;
+        var form = layui.form;
+        var table = layui.table;
+        var treeSelect = layui.treeSelect;
+        var $ = layui.$
+
+        form.render("select");
+
+        // 渲染表格
+        table.render({
+            elem: '#areaparabindformTable',
+            url: '[[@{/areapara/arealist}]]',
+            where:{
+                searchkey:''
+            },
+            size: 'sm',
+            height: 350,
+            page: false,
+            cols: [
+                [
+                    {type: 'checkbox', style: "#areaparabind-form-css", fixed: 'left'},
+                    {field: 'areano', title: '区域编号', align: 'center'},
+                    {field: 'areaname', title: '区域名称', align: 'center'},
+                    {field: 'address', title: '详细地址', align: 'center'},
+                    {field: 'arealevel', title: '区域级别', align: 'center'}
+                ]
+            ],
+            text:{
+                none:'没有区域信息'
+            }
+        });
+
+        // 搜索按钮点击事件
+        $('#btn-search-areaparabind-form').click(function () {
+            var searchkey = $("#search-areaparabind-form-searchkey").val();
+            table.reload('areaparabindformTable', {where: {searchkey: searchkey}});
+        });
+
+
+        form.on('submit(form-submit)', function (el) {
+            var groupid = $("#areaparabind-form-select-groupid").val();
+            var checkStatus = table.checkStatus('areaparabindformTable');
+            var data = checkStatus.data;
+            var areanos = [];
+            if ("" == groupid) {
+                layer.msg("请选择参数组", {icon: 2, time: 1500});
+                return;
+            }
+            for (var i = 0; i < data.length; i++) {
+                areanos.push(data[i].areano);
+            }
+            if (areanos.length < 1) {
+                layer.msg("请选择设备", {icon: 2, time: 1500});
+                return;
+            }
+            debugger
+            console.log(groupid, areanos);
+            layer.load(2);
+            var token = $("meta[name='_csrf_token']").attr("value");
+            $.ajax({
+                type: "POST",
+                dataType: "json",
+                url: '[[@{/areapara/addbindareapara}]]',
+                data: {
+                    "groupid": groupid,
+                    "areano[]": areanos,
+                    "_csrf": token
+                },
+                success: function (result) {
+                    layer.closeAll('loading');
+                    if (result.code == 200) {
+                        layer.msg(result.msg, {icon: 1});
+                        table.reload('areaparabindformTable');
+                        admin.finishPopupCenter();
+                    } else if (result.code == 401) {
+                        layer.msg(result.msg, {icon: 2, time: 1500}, function () {
+                            location.replace('[[@{/login}]]');
+                        }, 1000);
+                        return;
+                    } else {
+                        console.log('err:' + result.code);
+                        layer.msg(result.msg, {icon: 2});
+                    }
+                },
+                error: function (err) {
+                    admin.errorBack(err);
+                }
+            });
+        });
+    });
+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/system/areaparabind/index.html b/src/main/resources/templates/system/areaparabind/index.html
new file mode 100644
index 0000000..1d600b0
--- /dev/null
+++ b/src/main/resources/templates/system/areaparabind/index.html
@@ -0,0 +1,112 @@
+<div class="layui-card">
+    <div class="layui-card-header">
+        <h2 class="header-title">水控区域参数绑定</h2>
+        <span class="layui-breadcrumb pull-right">
+          <a href="#">主页</a>
+          <a><cite>水控区域参数绑定</cite></a>
+        </span>
+    </div>
+    <div class="layui-card-body">
+        <div class="layui-form toolbar">
+            搜索:
+            <input id="search-areaparabind-searchkey" class="layui-input search-input" maxlength="20" type="text" style="width: 300px;" placeholder="输入参数组名称或区域名称"/>&emsp;
+            <button id="btn-search-areaparabind" class="layui-btn icon-btn" data-type="search"><i class="layui-icon">&#xe615;</i>搜索
+            </button>
+            <button id="search-areaparabind-add" class="layui-btn icon-btn" data-type="add"><i class="layui-icon">&#xe654;</i>新 增</button>
+        </div>
+        <table class="layui-table" id="areaparabindTable" lay-filter="areaparabindTable-filter"></table>
+    </div>
+</div>
+
+
+<!-- 表格操作列 -->
+<script type="text/html" id="areaparabind-table-bar">
+    <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del"><i class="layui-icon layui-icon-delete"></i>删除</a>
+</script>
+
+<script>
+    layui.use(['form', 'table', 'layer', 'admin', 'element'], function () {
+        var form = layui.form;
+        var table = layui.table;
+        var admin = layui.admin;
+        // 渲染表格
+        table.render({
+            elem: '#areaparabindTable',
+            url: '[[@{/areapara/areaparabindlist}]]',
+            page: true,
+            cols: [
+                [
+                    {field: 'groupid', title: '参数组编号', width: 150, align: 'center', sort: true},
+                    {field: 'groupname', title: '参数组名称', align: 'center'},
+                    {field: 'areano', title: '区域编号', align: 'center', sort: true},
+                    {field: 'areaname', title: '区域名称', align: 'center'},
+                    {
+                        field: 'lastsaved', title: '更新时间', align: 'center', templet: function (d) {
+                            return admin.formatDate(d.lastsaved);
+                        }
+                    },
+                    {align: 'center', title: '操作', width: 100, toolbar: '#areaparabind-table-bar', fixed: 'right'}
+                ]
+            ]
+        });
+
+        // 搜索按钮点击事件
+        $('#btn-search-areaparabind').click(function () {
+            var searchkey = $("#search-areaparabind-searchkey").val();
+            table.reload('areaparabindTable', {where: {searchkey: searchkey}, page: {curr: 1}});
+        });
+
+        $('#search-areaparabind-add').click(function () {
+            admin.popupCenter({
+                title: "新增区域参数组绑定关系",
+                path: '[[@{/areapara/loadbindadd}]]',
+                area: '900px',
+                offset: '0px',
+                finish: function () {
+                    table.reload('areaparabindTable',{
+                        where:{searchkey:""},
+                        url:'[[@{/areapara/areaparabindlist}]]',
+                        page:{
+                            curr:1
+                        }
+                    });
+                }
+            });
+        });
+
+        //监听单元格
+        table.on('tool(areaparabindTable-filter)', function (obj) {
+            var data = obj.data;
+
+            if('del' == obj.event){
+                layer.confirm('确定要删除区域绑定的参数组【'+data.groupname+'】吗?', {
+                    btn: ['确定', '取消']
+                },function(){
+                    layer.closeAll('dialog');
+                    layer.load(2);
+                    admin.go('[[@{/areapara/deleteareaparabind}]]', {
+                        areano: data.areano,
+                        _csrf: $("meta[name='_csrf_token']").attr("value")
+                    }, function (data) {
+                        console.log(data.code);
+                        layer.closeAll('loading');
+                        if (data.code == 200) {
+                            layer.msg(data.msg, {icon: 1});
+                        } else if (data.code == 401) {
+                            layer.msg(data.msg, {icon: 2, time: 1500}, function () {
+                                location.replace('[[@{/login}]]');
+                            }, 1000);
+                            return;
+                        } else {
+                            layer.msg(data.msg, {icon: 2});
+                        }
+                        table.reload('areaparabindTable');
+                    }, function (err) {
+                        admin.errorBack(err)
+                    });
+                });
+            }
+        });
+
+    });
+</script>
\ No newline at end of file
diff --git a/src/main/resources/templates/system/device/form.html b/src/main/resources/templates/system/device/form.html
index 103f7a5..e8d0b5d 100644
--- a/src/main/resources/templates/system/device/form.html
+++ b/src/main/resources/templates/system/device/form.html
@@ -1,6 +1,6 @@
 <!-- operator表单弹窗 -->
 <form id="form" lay-filter="form" class="layui-form model-form">
-    <input name="deviceid" id="deviceid" type="hidden"/>
+    <input name="areano" id="areano" type="hidden"/>
     <div class="layui-form-item">
         <label class="layui-form-label">设备名称</label>
         <div class="layui-input-block">
@@ -40,7 +40,7 @@
         //  清除admin域中的数据
         admin.putTempData('t_func', '');
         if (device_form_func) {
-            $('input[name="deviceid"]').attr('readonly', 'readonly');
+            $('input[name="areano"]').attr('readonly', 'readonly');
             form.val('form', device_form_func);
             $.ajax({
                 url: "[[@{/region/all}]]",
diff --git a/src/main/resources/templates/system/device/index.html b/src/main/resources/templates/system/device/index.html
index a210289..6e6ad25 100644
--- a/src/main/resources/templates/system/device/index.html
+++ b/src/main/resources/templates/system/device/index.html
@@ -11,15 +11,15 @@
             <div class="layui-fluid">
                 <div class="layui-row">
                     <div class="layui-col-md3">
-                        设备名称
+                        <label style="width: 60px" class="layui-form-label">设备名称</label>
                         <input id="devicename-search-value" class="layui-input search-input" type="text"/>
                     </div>
-                    <div class="layui-col-md4">
-                        设备编号
-                        <input id="deviceno-search-value" class="layui-input search-input" type="text"/>
-                    </div>
                     <div class="layui-col-md3">
-                        所在小区
+                        <label style="width: 60px" class="layui-form-label">设备编号</label>
+                        <input id="deviceno-search-value" class="layui-input search-input" type="text" maxlength="8"/>
+                    </div>
+                    <div class="layui-col-md4">
+                        <label style="width: 60px" class="layui-form-label">所在小区</label>
                         <select name="parentId" id="select-region" lay-search>
 
                         </select>
@@ -33,7 +33,7 @@
                 </div>
                 <div style="margin-top: 20px"/>
                 <div class="layui-row">
-                    设备状态
+                    <label style="width: 60px" class="layui-form-label">设备状态</label>
                     <select name="parentId" id="select-status">
 
                     </select>
@@ -90,12 +90,11 @@
             url: '[[@{device/status}]]',
             type: 'GET',
             success: function (data) {
-                console.log(data)
                 if (data.retcode == 0) {
                     var html = '<option value="">请选择状态</option>'
                     var status = data.status
                     for (var i = 0; i < status.length; i++) {
-                        html += '<option value="' + status[i] + '">' + status[i] + '</option>'
+                        html += '<option value="' + status[i].dictValue + '">' + status[i].dictKey + '</option>'
                     }
                     $("#select-status").html(html);
                     form.render('select')
@@ -156,10 +155,10 @@
             ]
         });
 
-        // 搜索按钮点击事件
-        $('#btn-search-device').click(function () {
-            var devicename = $('#devicename-search-value').val();
-            var deviceno = $('#deviceno-search-value').val();
+        // 搜索事件
+        function search() {
+            var devicename = $('#devicename-search-value').val().trim();
+            var deviceno = $('#deviceno-search-value').val().trim();
             var areano = $('#select-region').val();
             var status;
             if ($('#select-status').val() === '正常') {
@@ -178,9 +177,18 @@
                     areano: areano,
                     deviceStatus: status
                 },
-                url: "[[@{/device/search}]]"
+                page: {
+                    curr: 1
+                },
+                url: "[[@{/device/search}]]",
+                text: {
+                    none: '没有符合查询条件的设备'
+                }
             });
-        });
+        }
+        //  给搜索按钮绑定搜索事件
+        $("#btn-search-device").on('click', search)
+
         $('#btn-add-device').click(function () {
             showModel();
         });
@@ -192,8 +200,18 @@
             admin.popupCenter({
                 title: title,
                 path: '[[@{/device/loadadd}]]',
+                //  重新渲染表格
                 finish: function () {
-                    table.reload('devicetable', {});
+                    //  新增时删除搜索条件
+                    if (!data) {
+                        $('#devicename-search-value').val('');
+                        $('#deviceno-search-value').val('');
+                        $("#select-status").get(0).selectedIndex=0;
+                        $("#select-region").get(0).selectedIndex=0;
+                        //  重新渲染下拉框
+                        form.render('select')
+                    }
+                    $("#btn-search-device").click();
                 }
             });
         };
@@ -224,7 +242,7 @@
                 layer.load(2);
                 let token = $("meta[name='_csrf_token']").attr("value");
                 admin.go('[[@{/device/del}]]', {
-                    deviceid: data.deviceid,
+                    areano: data.areano,
                     _csrf: token
                 }, function (data) {
                     console.log(data.code);
@@ -239,7 +257,7 @@
                     } else {
                         layer.msg(data.retmsg, {icon: 2});
                     }
-                    table.reload('devicetable', {});
+                    $("#btn-search-device").click();
                 }, function (ret) {
                     console.log(ret);
                     layer.closeAll('loading');
diff --git a/src/main/resources/templates/system/dtlcount/index.html b/src/main/resources/templates/system/dtlcount/index.html
new file mode 100644
index 0000000..c6d8758
--- /dev/null
+++ b/src/main/resources/templates/system/dtlcount/index.html
@@ -0,0 +1,178 @@
+<div class="layui-card">
+    <div class="layui-card-header">
+        <h2 class="header-title">流水统计</h2>
+        <span class="layui-breadcrumb pull-right">
+          <a href="#">主页</a>
+          <a><cite>流水统计</cite></a>
+        </span>
+    </div>
+    <div class="layui-card-body">
+        <div class="layui-form toolbar">
+            <div class="layui-fluid">
+                <div class="layui-row">
+                    <div class="layui-col-md4">
+                        <label style="width: 60px" class="layui-form-label">交易日期</label>
+                        <input style="width: 200px" type="text" class="layui-input"
+                               id="dtlcount-transtime-search-value" readonly="readonly">
+                    </div>
+                    <div class="layui-col-md3">
+                        <label style="width: 60px" class="layui-form-label">设备名称</label>
+                        <input id="dtlcount-devicename-search-value" class="layui-input search-input" type="text"/>
+                    </div>
+                    <div class="layui-col-md3">
+                        <label style="width: 60px" class="layui-form-label">所在小区</label>
+                        <select name="parentId" id="dtlcount-select-region" lay-search>
+
+                        </select>
+                    </div>
+                    <div class="layui-col-md2">
+                        <button id="btn-search-dtlcount" class="layui-btn icon-btn" data-type="search"
+                                style="margin-left: 100px"><i
+                                class="layui-icon">&#xe615;</i>查询
+                        </button>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <hr/>
+        <!--<button id="btn-print" class="layui-btn icon-btn" data-type="print"><i class="layui-icon layui-icon-print"></i>打印-->
+        <!--</button>-->
+        <!--<button id="btn-export-excel" class="layui-btn icon-btn" data-type="export"><i class="layui-icon">&#xe62d;</i>导出excel-->
+        <!--</button>-->
+        <!--<button id="btn-add-device" class="layui-btn icon-btn" data-type="add"><i class="layui-icon ">&#xe601;</i>模板下载-->
+        <!--</button>-->
+        <!--<button id="btn-add-device" class="layui-btn icon-btn" data-type="add"><i class="layui-icon">&#xe67c;</i>批量导入-->
+        <!--</button>-->
+        <div class="layui-fluid" style="padding: 0">
+            <div class="layui-row">
+                <div>
+                    <table class="layui-table" id="dtlcounttable" lay-filter="dtlcounttable"></table>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script>
+
+    layui.use(['form', 'table', 'layer', 'admin', 'element', 'laydate'], function () {
+        let form = layui.form;
+        let table = layui.table;
+        let admin = layui.admin;
+        let laydate = layui.laydate;
+        //  渲染日期选择框
+        laydate.render({
+            elem: '#dtlcount-transtime-search-value',
+            range: true,
+            trigger:'click'
+        })
+        //  渲染区域选择框
+        $.ajax({
+            url: '[[@{/region/all}]]',
+            type: 'GET',
+            success: function (data) {
+                if (data.retcode == '0') {
+                    var html = '<option value="">请选择一个区域</option>'
+                    var regions = data.regions;
+                    for (var i = 0; i < regions.length; i++) {
+                        html += '<option value="' + regions[i].areano + '">' + regions[i].areaName + '</option>'
+                    }
+                    $("#dtlcount-select-region").html(html);
+                    form.render('select')
+                }
+            },
+            error: function (xhr) {
+                console.log(xhr)
+            }
+        });
+        // 渲染表格
+        table.render({
+            elem: '#dtlcounttable',
+            url: '[[@{/dtlcount/list}]]',
+            where: {
+                devicename: '',
+                areano: '',
+                transtime: ''
+            },
+            page: true,
+            cols: [
+                [
+                    {field: 'billno', align: 'center', title: '流水号', width: 190},
+                    {field: 'deviceno', align: 'center', title: '终端号', width: 95},
+                    {field: 'devicename', align: 'center', title: '设备名称', width: 110},
+                    {field: 'areaname', align: 'center', title: '区域'},
+                    {field: 'waterSumHundredLitre', align: 'center', title: '用水量', width: 85},
+                    {field: 'amount', align: 'center', title: '金额', width: 75},
+                    {field: 'username', align: 'center', title: '姓名', width: 75},
+                    {field: 'bankcardno', align: 'center', title: '卡号'},
+                    {
+                        field: 'transdate',
+                        align: 'center',
+                        title: '交易时间',
+                        width: 105,
+                        templet: function (item) {
+                            var date = item.transdate
+                            date = date.slice(0, 4) + '/' + date.slice(4)
+                            return date.slice(0, 7) + '/' + date.slice(7)
+                        }
+                    },
+                    {
+                        field: 'transtype',
+                        align: 'center',
+                        title: '支付方式',
+                        width: 90,
+                        templet: function (item) {
+                            if (item.mode === 'qrcode') {
+                                return '扫码'
+                            } else if (item.mode === 'card') {
+                                return '市民卡'
+                            } else {
+                                return item.mode
+                            }
+                        }
+                    },
+                    {
+                        field: 'transStatus',
+                        align: 'center',
+                        title: '状态',
+                        templet: function (item) {
+                            if (item.status === 'init') {
+                                return '初始化'
+                            } else if (item.status === 'wip') {
+                                return '处理中'
+                            } else if (item.status === 'fail') {
+                                return '失败';
+                            } else if (item.status === 'success') {
+                                return '成功';
+                            } else {
+                                return item.status
+                            }
+                        }
+                    }
+                ]
+            ]
+        });
+
+        // 搜索按钮点击事件
+        $('#btn-search-dtlcount').click(function () {
+            var devicename = $('#dtlcount-devicename-search-value').val();
+            var areano = $('#dtlcount-select-region').val();
+            var transtime = $('#dtlcount-transtime-search-value').val();
+            table.reload('dtlcounttable', {
+                where: {
+                    devicename: devicename,
+                    areano: areano,
+                    transtime: transtime
+                },
+                url: "[[@{/dtlcount/list}]]",
+                page:{
+                    curr:1
+                },
+                text: {
+                    none: '没有符合查询条件的流水'
+                }
+            });
+        });
+    });
+</script>
+
+
diff --git a/src/main/resources/templates/system/region/form.html b/src/main/resources/templates/system/region/form.html
index 3169b78..352b019 100644
--- a/src/main/resources/templates/system/region/form.html
+++ b/src/main/resources/templates/system/region/form.html
@@ -31,12 +31,12 @@
 
     <div class="layui-form-item model-form-footer">
         <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button>
-        <button class="layui-btn" lay-filter="form-submit" lay-submit  id="submitbtn">保存</button>
+        <button class="layui-btn" lay-filter="form-submit" lay-submit id="submitbtn">保存</button>
     </div>
 </form>
 
 <script>
-    layui.use(['layer','admin', 'form', 'formSelects'], function () {
+    layui.use(['layer', 'admin', 'form', 'formSelects'], function () {
         var layer = layui.layer;
         var admin = layui.admin;
         var form = layui.form;
@@ -47,32 +47,30 @@
         admin.putTempData('t_func', '');
         if (region_form_func) {
             $('input[name="areano"]').attr('readonly', 'readonly');
-            var region_form_html='<option value="'+region_form_func.parentId+'">'+region_form_func.parentName+'</option>'
+            region_form_func.parentName = region_form_func.parentName == null ? "无" : region_form_func.parentName
+            var region_form_html = '<option value="' + region_form_func.parentId + '">' + region_form_func.parentName + '</option>'
             $("#selectCity").html(region_form_html);
             form.val('form', region_form_func);
-        }
-        else {
-            var region_form_html = '<option value="0">根区域</option>'
-            $("#selectCity").html(region_form_html);
+        } else {
             form.val('form', region_form_func);
-            // $.ajax({
-            //     url:"/region/all",
-            //     type:"GET",
-            //     success: function (data) {
-            //         if (data.retcode == '0') {
-            //             var html='<option value="0">根区域</option>'
-            //             var regions = data.regions
-            //             for (var i = 0; i < regions.length; i++) {
-            //                 html+='<option value="'+regions[i].areano+'">'+regions[i].areaName+'</option>'
-            //             }
-            //             $("#selectCity").html(html);
-            //             form.render('select','form')
-            //         }
-            //     },
-            //     error: function (xhr) {
-            //         console.log(xhr)
-            //     }
-            // });
+            $.ajax({
+                url: "[[@{/region/all}]]",
+                type: "GET",
+                success: function (data) {
+                    if (data.retcode == '0') {
+                        var html = '<option value="0">根区域</option>'
+                        var regions = data.regions
+                        for (var i = 0; i < regions.length; i++) {
+                            html += '<option value="' + regions[i].areano + '">' + regions[i].areaName + '</option>'
+                        }
+                        $("#selectCity").html(html);
+                        form.render('select', 'form')
+                    }
+                },
+                error: function (xhr) {
+                    console.log(xhr)
+                }
+            });
         }
 
         // 表单提交事件
@@ -80,16 +78,16 @@
             layer.load(2);
             let token = $("meta[name='_csrf_token']").attr("value");
             $.ajax({
-                type : "POST",
-                dataType : "json",
-                url : region_form_url,
+                type: "POST",
+                dataType: "json",
+                url: region_form_url,
                 headers: {
                     'Accept': 'application/json',
                     'Content-Type': 'application/json',
-                    'X-CSRF-TOKEN':token,
+                    'X-CSRF-TOKEN': token,
                 },
-                data : JSON.stringify(data.field),
-                success : function(result) {
+                data: JSON.stringify(data.field),
+                success: function (result) {
                     console.log(result);
                     layer.closeAll('loading');
                     if (result.retcode == 0) {
@@ -105,7 +103,7 @@
                         layer.msg(result.retmsg, {icon: 2});
                     }
                 },
-                error : function() {
+                error: function () {
                     layer.closeAll('loading');
                     layer.msg("请求服务器失败!", {icon: 2});
                 }
diff --git a/src/main/resources/templates/system/region/index.html b/src/main/resources/templates/system/region/index.html
index 4f5c651..854747f 100644
--- a/src/main/resources/templates/system/region/index.html
+++ b/src/main/resources/templates/system/region/index.html
@@ -13,7 +13,8 @@
             <button id="btn-search-region" class="layui-btn icon-btn" data-type="search"><i
                     class="layui-icon">&#xe615;</i>查询
             </button>
-            <button id="btn-add-region" class="layui-btn icon-btn" data-type="add"><i class="layui-icon">&#xe654;</i>新增区域
+            <button id="btn-add-region" class="layui-btn icon-btn" data-type="add" style="float: right"><i
+                    class="layui-icon">&#xe654;</i>新增区域
             </button>
         </div>
         <hr style="margin-bottom: 0"/>
@@ -23,7 +24,7 @@
         <!--</button>-->
         <div class="layui-fluid" style="padding-top: 0">
             <div class="layui-row layui-col-space20">
-                <div class="layui-col-md2" style="border: 1px solid #e6e6e6; margin-top: 25px">
+                <div class="layui-col-md2" style="border: 1px solid #e6e6e6; margin-top: 25px" id="water-area-tree-css">
                     <div id="regiontree"></div>
                 </div>
                 <div class="layui-col-md10">
@@ -34,6 +35,14 @@
     </div>
 </div>
 <!--<script src="/static/libs/layui/layui.js"></script>-->
+<style type="text/css">
+    #water-area-tree-css {
+        position: relative;
+        max-height: 300px;
+        line-height: 24px;
+        overflow: auto; /*  新加的 */
+    }
+</style>
 <script>
     var table
     layui.use(['form', 'tree', 'table', 'layer', 'admin', 'element'], function () {
@@ -46,17 +55,24 @@
         // 渲染表格
         table.render({
             elem: '#regiontable',
-            url: '[[@{/region/list/0}]]',
+            url: '[[@{/region/search}]]',
             page: true,
             toolbar: true,
             cols: [
                 [
                     {field: 'areano', align: 'center', title: '区域号', unresize: true, width: "9%"},
-                    {field: 'areaName', align: 'center', unresize: true,title: '区域名称'},
+                    {field: 'areaName', align: 'center', unresize: true, title: '区域名称'},
                     {field: 'level', align: 'center', title: '区域级别', unresize: true, width: "12%"},
-                    {field: 'parentName', align: 'center',unresize: true, title: '父区域'},
-                    {field: 'address', align: 'center', unresize: true,title: '详细地址'},
-                    {field: 'remarks', align: 'center',unresize: true, title: '备注',width: "13%"},
+                    {
+                        field: 'parentName', align: 'center', unresize: true, title: '父区域', templet: function (item) {
+                            if (item.parentName == null) {
+                                return "无"
+                            }
+                            return item.parentName
+                        }
+                    },
+                    {field: 'address', align: 'center', unresize: true, title: '详细地址'},
+                    {field: 'remarks', align: 'center', unresize: true, title: '备注', width: "13%"},
                     {
                         field: 'regionId', align: 'center', title: '操作', unresize: true, templet: function (item) {
                             let html = ' <a class="layui-btn  layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>修改</a> ' +
@@ -77,7 +93,13 @@
             let key = $('#search-value').val();
             table.reload('regiontable', {
                 where: {searchkey: key},
-                url: "[[@{/region/search}]]"
+                url: "[[@{/region/search}]]",
+                page: {
+                    curr: 1
+                },
+                text: {
+                    none: '没有符合查询条件的区域'
+                }
             });
         });
         $('#btn-add-region').click(function () {
@@ -87,12 +109,12 @@
             let region_index_title = data ? '编辑区域' : '新增区域';
             if (data) {
                 admin.putTempData('t_func', data);
+                console.log(data)
             }
             admin.popupCenter({
                 title: region_index_title,
                 path: '[[@{/region/loadadd}]]',
                 finish: function () {
-                    table.reload('regiontable', {});
                     //  更新区域树
                     $.ajax({
                         url: '[[@{/region/tree}]]',
@@ -103,11 +125,7 @@
                                 layui.use('tree', function () {
                                     var tree = layui.tree;
                                     tree.reload('regiontree', {
-                                        data: [{
-                                            title:'根区域',
-                                            children:treeData,
-                                            id:0
-                                        }]
+                                        data: treeData
                                     })
                                 });
                             } else {
@@ -118,6 +136,18 @@
                             console.log(xhr)
                         }
                     });
+                    //  更新表格
+                    let key = data ? $('#search-value').val() : '';
+                    table.reload('regiontable', {
+                        where: {searchkey: key},
+                        url: "[[@{/region/search}]]",
+                        page: {
+                            curr: 1
+                        },
+                        text: {
+                            none: '没有符合查询条件的区域'
+                        }
+                    });
                 }
             });
         };
@@ -164,11 +194,7 @@
                                     layui.use('tree', function () {
                                         var tree = layui.tree;
                                         tree.reload('regiontree', {
-                                            data: [{
-                                                title:'根区域',
-                                                children:treeData,
-                                                id:0
-                                            }]
+                                            data: treeData
                                         })
                                     });
                                 } else {
@@ -179,6 +205,18 @@
                                 console.log(xhr)
                             }
                         });
+                        //  更新表格
+                        let key = $('#search-value').val();
+                        table.reload('regiontable', {
+                            where: {searchkey: key},
+                            url: "[[@{/region/search}]]",
+                            page: {
+                                curr: 1
+                            },
+                            text: {
+                                none: '没有符合查询条件的区域'
+                            }
+                        });
                     } else if (data.retcode == 401) {
                         layer.msg(data.msg, {icon: 2, time: 1500}, function () {
                             location.replace('[[@{/login}]]');
@@ -210,18 +248,15 @@
                     var tree = layui.tree;
                     var inst1 = tree.render({
                         elem: '#regiontree'  //绑定元素
-                        , data: [{
-                            title:'根区域',
-                            children:treeData,
-                            id:0
-                        }]
+                        , data: treeData
                         , id: 'regiontree'
                         , click: function (region) {
                             if (region.data.children.size != 0) {
                                 table.reload("regiontable", {
                                     url: "[[@{/region/list/}]]" + region.data.id
-                                    ,page: {
-                                        curr: 1
+                                    , page: {
+                                        curr: 1,
+                                        limit: 2
                                     }
                                 });
                             }
@@ -236,10 +271,12 @@
             console.log(xhr)
         }
     });
+
+    // 将区域名称显示限制在6个字
     function region_index_shortenTitle(treeData) {
         for (var i = 0; i < treeData.length; i++) {
             if (treeData[i].title.length > 6) {
-                treeData[i].title=treeData[i].title.substring(0,6)+'...'
+                treeData[i].title = treeData[i].title.substring(0, 6) + '...'
             }
         }
         return treeData
diff --git a/src/main/resources/templates/system/transdtl/index.html b/src/main/resources/templates/system/transdtl/index.html
new file mode 100644
index 0000000..d3bce23
--- /dev/null
+++ b/src/main/resources/templates/system/transdtl/index.html
@@ -0,0 +1,196 @@
+<div class="layui-card">
+    <div class="layui-card-header">
+        <h2 class="header-title">流水查询</h2>
+        <span class="layui-breadcrumb pull-right">
+          <a href="#">主页</a>
+          <a><cite>流水查询</cite></a>
+        </span>
+    </div>
+    <div class="layui-card-body">
+        <div class="layui-form toolbar">
+            <div class="layui-fluid">
+                <div class="layui-row">
+                    <div class="layui-col-md4">
+                        <label style="width: 60px" class="layui-form-label">交易日期</label>
+                        <input style="width: 200px" type="text" class="layui-input"
+                               id="waterdtl-transtime-search-value" readonly="readonly">
+                    </div>
+                    <div class="layui-col-md3">
+                        <label style="width: 60px" class="layui-form-label">设备名称</label>
+                        <input id="waterdtl-devicename-search-value" class="layui-input search-input" type="text"/>
+                    </div>
+                    <div class="layui-col-md3">
+                        <label style="width: 60px" class="layui-form-label">设备编号</label>
+                        <input id="waterdtl-deviceno-search-value" class="layui-input search-input" type="text" maxlength="8"/>
+                    </div>
+                    <div class="layui-col-md2">
+                        <button id="btn-search-waterdtl" class="layui-btn icon-btn" data-type="search"
+                                style="margin-left: 100px"><i
+                                class="layui-icon">&#xe615;</i>查询
+                        </button>
+                    </div>
+                </div>
+                <div style="margin-top: 20px"/>
+                <div class="layui-row">
+                    <div class="layui-col-md4">
+                        <label style="width: 60px" class="layui-form-label">市民姓名</label>
+                        <input style="width: 200px" id="waterdtl-username-search-value" class="layui-input search-input"
+                               type="text"/>
+                    </div>
+                    <div class="layui-col-md4">
+                        <label style="width: 60px" class="layui-form-label">所在小区</label>
+                        <select name="parentId" id="waterdtl-select-region" lay-search>
+
+                        </select>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <hr/>
+        <!--<button id="btn-print" class="layui-btn icon-btn" data-type="print"><i class="layui-icon layui-icon-print"></i>打印-->
+        <!--</button>-->
+        <!--<button id="btn-export-excel" class="layui-btn icon-btn" data-type="export"><i class="layui-icon">&#xe62d;</i>导出excel-->
+        <!--</button>-->
+        <!--<button id="btn-add-device" class="layui-btn icon-btn" data-type="add"><i class="layui-icon ">&#xe601;</i>模板下载-->
+        <!--</button>-->
+        <!--<button id="btn-add-device" class="layui-btn icon-btn" data-type="add"><i class="layui-icon">&#xe67c;</i>批量导入-->
+        <!--</button>-->
+        <div class="layui-fluid" style="padding: 0">
+            <div class="layui-row">
+                <div>
+                    <table class="layui-table" id="waterdtltable" lay-filter="waterdtltable"></table>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script>
+
+    layui.use(['form', 'table', 'layer', 'admin', 'element', 'laydate'], function () {
+        let form = layui.form;
+        let table = layui.table;
+        let admin = layui.admin;
+        let laydate = layui.laydate;
+        //  渲染日期选择框
+        laydate.render({
+            elem: '#waterdtl-transtime-search-value',
+            range: true,
+            trigger:'click'
+        })
+        //  渲染区域选择框
+        $.ajax({
+            url: '[[@{/region/all}]]',
+            type: 'GET',
+            success: function (data) {
+                if (data.retcode == '0') {
+                    var html = '<option value="">请选择一个区域</option>'
+                    var regions = data.regions;
+                    for (var i = 0; i < regions.length; i++) {
+                        html += '<option value="' + regions[i].areano + '">' + regions[i].areaName + '</option>'
+                    }
+                    $("#waterdtl-select-region").html(html);
+                    form.render('select')
+                }
+            },
+            error: function (xhr) {
+                console.log(xhr)
+            }
+        });
+        // 渲染表格
+        table.render({
+            elem: '#waterdtltable',
+            url: '[[@{/transdtl/list}]]',
+            where: {
+                devicename: '',
+                deviceno: '',
+                areano: '',
+                username: '',
+                transtime: ''
+            },
+            page: true,
+            cols: [
+                [
+                    {field: 'billno', align: 'center', title: '流水号', width: 190},
+                    {field: 'deviceno', align: 'center', title: '设备号', width: 95},
+                    {field: 'devicename', align: 'center', title: '设备名称', width: 110},
+                    {field: 'areaname', align: 'center', title: '区域'},
+                    {field: 'waterSumHundredLitre', align: 'center', title: '用水量', width: 85},
+                    {field: 'amount', align: 'center', title: '金额', width: 75},
+                    {field: 'username', align: 'center', title: '姓名', width: 75},
+                    {field: 'bankcardno', align: 'center', title: '卡号'},
+                    {
+                        field: 'transdate',
+                        align: 'center',
+                        title: '交易时间',
+                        width: 105,
+                        templet: function (item) {
+                            var date = item.transdate
+                            date = date.slice(0, 4) + '/' + date.slice(4)
+                            return date.slice(0, 7) + '/' + date.slice(7)
+                        }
+                    },
+                    {
+                        field: 'transtype',
+                        align: 'center',
+                        title: '支付方式',
+                        width: 90,
+                        templet: function (item) {
+                            if (item.mode === 'qrcode') {
+                                return '扫码'
+                            } else if (item.mode === 'card') {
+                                return '市民卡'
+                            } else {
+                                return item.mode
+                            }
+                        }
+                    },
+                    {
+                        field: 'transStatus',
+                        align: 'center',
+                        title: '状态',
+                        templet: function (item) {
+                            if (item.status === 'init') {
+                                return '初始化'
+                            } else if (item.status === 'wip') {
+                                return '处理中'
+                            } else if (item.status === 'fail') {
+                                return '失败';
+                            } else if (item.status === 'success') {
+                                return '成功';
+                            } else {
+                                return item.status
+                            }
+                        }
+                    }
+                ]
+            ]
+        });
+
+        // 搜索按钮点击事件
+        $('#btn-search-waterdtl').click(function () {
+            var devicename = $('#waterdtl-devicename-search-value').val().trim();
+            var deviceno = $('#waterdtl-deviceno-search-value').val().trim();
+            var areano = $('#waterdtl-select-region').val();
+            var username = $('#waterdtl-username-search-value').val().trim();
+            var transtime = $('#waterdtl-transtime-search-value').val();
+            table.reload('waterdtltable', {
+                where: {
+                    devicename: devicename,
+                    deviceno: deviceno,
+                    areano: areano,
+                    username: username,
+                    transtime: transtime
+                },
+                url: "[[@{/transdtl/list}]]",
+                page:{
+                    curr:1
+                },
+                text: {
+                    none: '没有符合查询条件的流水'
+                }
+            });
+        });
+    });
+</script>
+
+