验证码功能修复,角色编辑修复,授权勾选框修复,关键字段添加*,导入添加错误条目信息,日志简化,设备注册404修复
diff --git a/build.gradle b/build.gradle
index 904d15f..c3e92ce 100644
--- a/build.gradle
+++ b/build.gradle
@@ -57,7 +57,10 @@
     compile group: 'org.apache.poi', name: 'poi-ooxml-schemas', version: '3.10.1'
     compile group: 'org.apache.poi', name: 'poi-scratchpad', version: '3.10.1'
     compile 'com.supwisdom:payapi-sdk:e4bf762'
+    compile group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version: '2.3.4.RELEASE'
 
+
+    implementation 'com.github.penggle:kaptcha:2.3.2'
     implementation 'org.springframework.boot:spring-boot-devtools'
     implementation 'org.springframework.boot:spring-boot-starter-tomcat'
     implementation 'org.springframework.boot:spring-boot-starter-data-redis'
diff --git a/config/application-devel-pg.properties b/config/application-devel-pg.properties
index 77d4185..84dffed 100644
--- a/config/application-devel-pg.properties
+++ b/config/application-devel-pg.properties
@@ -8,7 +8,7 @@
 #logging.level.org.hibernate.SQL=DEBUG
 # Postgresql settings
 spring.datasource.platform=postgresql
-spring.datasource.url=jdbc:postgresql://172.28.201.101:25432/restauranttest
+spring.datasource.url=jdbc:postgresql://172.28.201.70:15432/restaurantdev
 spring.datasource.username=payapi
 spring.datasource.password=123456
 database.dbtype=postgresql
diff --git a/src/main/java/com/supwisdom/dlpay/framework/KaptchaConfig.java b/src/main/java/com/supwisdom/dlpay/framework/KaptchaConfig.java
new file mode 100644
index 0000000..c69dc38
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/KaptchaConfig.java
@@ -0,0 +1,29 @@
+package com.supwisdom.dlpay.framework;
+
+import com.google.code.kaptcha.impl.DefaultKaptcha;
+import com.google.code.kaptcha.util.Config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Properties;
+
+@Configuration
+public class KaptchaConfig {
+  @Bean
+  public DefaultKaptcha getDefaultKaptcha(){
+    DefaultKaptcha captchaProducer = new DefaultKaptcha();
+    Properties properties = new Properties();
+    properties.setProperty("kaptcha.border", "yes");
+    properties.setProperty("kaptcha.border.color", "105,179,90");
+    properties.setProperty("kaptcha.textproducer.font.color", "blue");
+    properties.setProperty("kaptcha.image.width", "110");
+    properties.setProperty("kaptcha.image.height", "40");
+    properties.setProperty("kaptcha.textproducer.font.size", "30");
+    properties.setProperty("kaptcha.session.key", "code");
+    properties.setProperty("kaptcha.textproducer.char.length", "4");
+    properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
+    Config config = new Config(properties);
+    captchaProducer.setConfig(config);
+    return captchaProducer;
+  }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/dao/TenantConfigDao.java b/src/main/java/com/supwisdom/dlpay/framework/dao/TenantConfigDao.java
new file mode 100644
index 0000000..b52710e
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/dao/TenantConfigDao.java
@@ -0,0 +1,12 @@
+package com.supwisdom.dlpay.framework.dao;
+
+import com.supwisdom.dlpay.framework.domain.TTenantConfig;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface TenantConfigDao extends CrudRepository<TTenantConfig, String> {
+  @Query("select t from TTenantConfig  t where t.cfgid='main'")
+  TTenantConfig getDefault();
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/domain/ApiClientRedis.java b/src/main/java/com/supwisdom/dlpay/framework/domain/ApiClientRedis.java
index d7bb016..2904156 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/domain/ApiClientRedis.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/domain/ApiClientRedis.java
@@ -15,6 +15,8 @@
 
   String loginTimestamp;
 
+  String tenantId;
+
   public String getId() {
     return id;
   }
@@ -46,4 +48,12 @@
   public void setRoles(String roles) {
     this.roles = roles;
   }
+
+  public String getTenantId() {
+    return tenantId;
+  }
+
+  public void setTenantId(String tenantId) {
+    this.tenantId = tenantId;
+  }
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java b/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java
index 77242b9..1be683f 100755
--- a/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/filter/ValidateCodeFilter.java
@@ -1,16 +1,13 @@
 package com.supwisdom.dlpay.framework.filter;

 

 

-import com.fasterxml.jackson.databind.ObjectMapper;

-import com.supwisdom.dlpay.api.bean.JsonResult;

 import com.supwisdom.dlpay.exception.ValidateCodeException;

+import com.supwisdom.dlpay.framework.security.CodeUtil;

+import com.supwisdom.dlpay.framework.security.MyAuthenticationFailureHandler;

 import com.supwisdom.dlpay.framework.security.validate.ImageCodeUtil;

 import com.supwisdom.dlpay.framework.security.validate.VerifyCode;

 import com.supwisdom.dlpay.framework.util.StringUtil;

 import org.springframework.beans.factory.annotation.Autowired;

-import org.springframework.http.HttpStatus;

-import org.springframework.security.web.authentication.AuthenticationFailureHandler;

-import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

 import org.springframework.stereotype.Component;

 import org.springframework.web.filter.OncePerRequestFilter;

 

@@ -22,37 +19,41 @@
 

 

 @Component("validateCodeFilter")

-public class ValidateCodeFilter extends OncePerRequestFilter{

+public class ValidateCodeFilter extends OncePerRequestFilter {

 

 	/**

 	 * 校验失败处理器

 	 */

 	@Autowired

-	private AuthenticationFailureHandler myAuthenticationFailureHandler;

-

-	/**

-	 * 校验成功处理器

-	 */

-	@Autowired

-	private AuthenticationSuccessHandler myAuthenticationSuccessHandler;

-	@Autowired

-	private ObjectMapper objectMapper;

+	private MyAuthenticationFailureHandler myAuthenticationFailureHandler;

 

 

 	@Override

 	protected void doFilterInternal(HttpServletRequest request,

-																	HttpServletResponse response, FilterChain filterChain)

+									HttpServletResponse response, FilterChain filterChain)

 			throws ServletException, IOException {

-		if (StringUtil.equals("/login/form", request.getRequestURI())

+		String context = request.getContextPath();

+		if (context == null || "" == context.trim()) {

+			context = "/";

+		}

+		if (request.getRequestURI().isEmpty()) {

+			filterChain.doFilter(request, response);

+			return;

+		}

+		String url = request.getRequestURI();

+		if (!"/".equals(context)) {

+			url = url.replace(context, "");

+		}

+		if (StringUtil.equals("/login/form", url)

 				&& StringUtil.equalsIgnoreCase(request.getMethod(), "post")) {

 			try {

 				validate(request);

 			} catch (ValidateCodeException e) {

-				response.setStatus(HttpStatus.OK.value());

-				response.setContentType("application/json;charset=UTF-8");

-				response.getWriter().write(objectMapper.writeValueAsString(JsonResult.error(400, e.getMessage())));

+				//response.setStatus(HttpStatus.OK.value());

+				//response.setContentType("application/json;charset=UTF-8");

+				//response.getWriter().write(objectMapper.writeValueAsString(JsonResult.error(400, e.getMessage())));

 				//response.sendError(HttpStatus.UNAUTHORIZED.value(),e.getMessage());

-				//myAuthenticationFailureHandler.onAuthenticationFailure(request, response, e);

+				myAuthenticationFailureHandler.onAuthenticationFailure(request, response, e);

 				return;

 			}

 		}

@@ -60,27 +61,32 @@
 	}

 

 	private void validate(HttpServletRequest request) throws ValidateCodeException {

-		VerifyCode imageCode = (VerifyCode) request.getSession().getAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY);

-		String inputCode;

-		try {

-			inputCode = request.getParameter("imageCode");

-		} catch (Exception e) {

-			throw new ValidateCodeException("获取验证码的值失败");

-		}

-		if (StringUtil.isEmpty(inputCode)) {

-			throw new ValidateCodeException("验证码不能为空");

-		}

-		if (null == imageCode) {

-			throw new ValidateCodeException("验证码不存在");

-		}

-		if (imageCode.isExpired()) {

-			request.getSession().removeAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY);

-			throw new ValidateCodeException("验证码已过期");

-		}

-		if (!StringUtil.equalsIgnoreCase(imageCode.getText(), inputCode)) {

+		if (!CodeUtil.checkVerifyCode(request)) {

 			throw new ValidateCodeException("验证码不匹配");

+		} else {

+			request.getSession().removeAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);

 		}

-		request.getSession().removeAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY);

+//    VerifyCode imageCode = (VerifyCode) request.getSession().getAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY);

+//    String inputCode;

+//    try {

+//      inputCode = request.getParameter("imageCode");

+//    } catch (Exception e) {

+//      throw new ValidateCodeException("获取验证码的值失败");

+//    }

+//    if (StringUtil.isEmpty(inputCode)) {

+//      throw new ValidateCodeException("验证码不能为空");

+//    }

+//    if (null == imageCode) {

+//      throw new ValidateCodeException("验证码不存在");

+//    }

+//    if (imageCode.isExpired()) {

+//      request.getSession().removeAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY);

+//      throw new ValidateCodeException("验证码已过期");

+//    }

+//    if (!StringUtil.equalsIgnoreCase(imageCode.getText(), inputCode)) {

+//      throw new ValidateCodeException("验证码不匹配");

+//    }

+//    request.getSession().removeAttribute(ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY);

 	}

 

 }

diff --git a/src/main/java/com/supwisdom/dlpay/framework/security/CodeUtil.java b/src/main/java/com/supwisdom/dlpay/framework/security/CodeUtil.java
new file mode 100644
index 0000000..ecfb7c9
--- /dev/null
+++ b/src/main/java/com/supwisdom/dlpay/framework/security/CodeUtil.java
@@ -0,0 +1,47 @@
+package com.supwisdom.dlpay.framework.security;
+
+import javax.servlet.http.HttpServletRequest;
+
+public class CodeUtil {
+  /**
+   * 将获取到的前端参数转为string类型
+   *
+   * @param request
+   * @param key
+   * @return
+   */
+  public static String getString(HttpServletRequest request, String key) {
+    try {
+      String result = request.getParameter(key);
+      if (result != null) {
+        result = result.trim();
+      }
+      if ("".equals(result)) {
+        result = null;
+      }
+      return result;
+    } catch (Exception e) {
+      return null;
+    }
+  }
+
+  /**
+   * 验证码校验
+   *
+   * @param request
+   * @return
+   */
+  public static boolean checkVerifyCode(HttpServletRequest request) {
+    //获取生成的验证码
+    String verifyCodeExpected = (String) request.getSession()
+        .getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
+    System.out.println(verifyCodeExpected);
+    //获取用户输入的验证码
+    String verifyCodeActual = CodeUtil.getString(request, "imageCode");
+    System.out.println(verifyCodeActual);
+    if (verifyCodeActual == null || !verifyCodeActual.equals(verifyCodeExpected)) {
+      return false;
+    }
+    return true;
+  }
+}
diff --git a/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationFailureHandler.java b/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationFailureHandler.java
index f18d092..28e09ae 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationFailureHandler.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationFailureHandler.java
@@ -37,11 +37,11 @@
     } else if (exception instanceof ValidateCodeException) {
       errmsg = exception.getMessage();
     }
-    setDefaultFailureUrl("/login");
-    super.onAuthenticationFailure(request, response, new ValidateCodeException(errmsg));
-    /*response.setTransStatus(HttpStatus.OK.value());
+  /*  setDefaultFailureUrl("/login");*/
+  /*  super.onAuthenticationFailure(request, response, new ValidateCodeException(errmsg));*/
+    response.setStatus(HttpStatus.OK.value());
     response.setContentType("application/json;charset=UTF-8");
-    response.getWriter().write(objectMapper.writeValueAsString(JsonResult.error(400, errmsg)));*/
+    response.getWriter().write(objectMapper.writeValueAsString(JsonResult.error(400, errmsg)));
   }
 
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationSuccessHandler.java b/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationSuccessHandler.java
index abaa46a..52388f1 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationSuccessHandler.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/security/MyAuthenticationSuccessHandler.java
@@ -2,9 +2,16 @@
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.supwisdom.dlpay.api.bean.JsonResult;
+import com.supwisdom.dlpay.framework.domain.TFunction;
+import com.supwisdom.dlpay.framework.domain.TOperLog;
+import com.supwisdom.dlpay.framework.domain.TOperator;
+import com.supwisdom.dlpay.framework.util.DateUtil;
+import com.supwisdom.dlpay.system.service.FunctionService;
+import com.supwisdom.dlpay.system.service.OperatorService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
 import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
 import org.springframework.stereotype.Component;
@@ -16,17 +23,36 @@
 
 @Component("myAuthenctiationSuccessHandler")
 public class MyAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
-  @Autowired
-  private ObjectMapper objectMapper;
+    @Autowired
+    private ObjectMapper objectMapper;
+    @Autowired
+    private OperatorService operatorService;
+    @Autowired
+    private FunctionService functionService;
 
-  @Override
-  public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
-                                      Authentication authentication) throws IOException, ServletException {
+    @Override
+    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
+                                        Authentication authentication) throws IOException, ServletException {
 
-    logger.info("登录成功");
-    //TODO:记录日志
-    response.setStatus(HttpStatus.OK.value());
-    response.setContentType("application/json;charset=UTF-8");
-    response.getWriter().write(objectMapper.writeValueAsString(JsonResult.ok("登录成功")));
-  }
+        logger.info("登录成功");
+        //TODO:记录日志
+        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
+        if (userDetails != null) {
+            TOperator operator = operatorService.getOperatorByCode(userDetails.getUsername());
+            TOperLog log = new TOperLog();
+            log.setLogdate(DateUtil.getNow());
+            log.setOperid(operator.getOperid());
+            log.setOpername(operator.getOpercode());
+            log.setResname("登录成功");
+            log.setRespath("/login");
+            log.setFunctionname("登录成功");
+            operatorService.saveOperLog(log);
+        }
+        response.setStatus(HttpStatus.OK.value());
+        response.setContentType("application/json;charset=UTF-8");
+        response.getWriter().write(objectMapper.writeValueAsString(JsonResult.ok("登录成功")));
+    }
+
+
+
 }
diff --git a/src/main/java/com/supwisdom/dlpay/framework/security/MyPermissionEvaluator.java b/src/main/java/com/supwisdom/dlpay/framework/security/MyPermissionEvaluator.java
index f19c136..4e96995 100644
--- a/src/main/java/com/supwisdom/dlpay/framework/security/MyPermissionEvaluator.java
+++ b/src/main/java/com/supwisdom/dlpay/framework/security/MyPermissionEvaluator.java
@@ -42,18 +42,21 @@
               if (resource != null) {
                 TPermission permission1 = roleService.findByRoleIdAndResid(role.getRoleId(), resource.getId());
                 if (permission1 != null) {
-                  TOperLog log = new TOperLog();
-                  log.setLogdate(DateUtil.getNow());
-                  log.setOperid(operator.getOperid());
-                  log.setOpername(operator.getOpercode());
-                  log.setResname(resource.getName());
-                  log.setRespath(resource.getUri());
-                  TFunction function = functionService.getFunctionById(resource.getFunctionId());
-                  if (function != null) {
-                    log.setFunctionid(function.getId());
-                    log.setFunctionname(function.getName());
+                  if(resource.getUri().indexOf("operator")!=-1){
+                    TOperLog log = new TOperLog();
+                    log.setLogdate(DateUtil.getNow());
+                    log.setOperid(operator.getOperid());
+                    log.setOpername(operator.getOpercode());
+                    log.setResname(resource.getName());
+                    log.setRespath(resource.getUri());
+                    TFunction function = functionService.getFunctionById(resource.getFunctionId());
+                    if (function != null) {
+                      log.setFunctionid(function.getId());
+                      log.setFunctionname(function.getName());
+                    }
+                    operatorService.saveOperLog(log);
                   }
-                  operatorService.saveOperLog(log);
+
                   return true;
                 }
               }
diff --git a/src/main/java/com/supwisdom/dlpay/restaurant/service/impl/CustomerServiceImpl.java b/src/main/java/com/supwisdom/dlpay/restaurant/service/impl/CustomerServiceImpl.java
index ef9dc20..0d6e626 100644
--- a/src/main/java/com/supwisdom/dlpay/restaurant/service/impl/CustomerServiceImpl.java
+++ b/src/main/java/com/supwisdom/dlpay/restaurant/service/impl/CustomerServiceImpl.java
@@ -55,8 +55,12 @@
     }
     @Override
     public JsonResult saveCustomer(TCustomer customer) {
+        List<TCustomer> cus=customerDao.findAllByCardno(customer.getCardno());
+        if(cus.size()!=0){
+            return JsonResult.error("用户"+cus.get(0).getCustname()+"已拥有该卡");
+        }
         customer.setLastsaved(DateUtil.getNow("yyyyMMddHHmmss"));
-        TCustomer cus=customerDao.save(customer);
+        customerDao.save(customer);
        /* if(null !=cus){
             String cardverno= systemUtilService.getCardverno();
             String date=DateUtil.getNow("yyyyMMdd");
@@ -129,15 +133,18 @@
         }
 
         String msg = "";
+        Integer successCnt=0;
+        Integer failCnt=0;
         for (Object[][] data : oList) {
             for (int i = 1; i < data.length; i++) {
 
                 if (StringUtil.isEmpty((String) data[i][0]) || StringUtil.isEmpty((String) data[i][1]) || StringUtil.isEmpty((String) data[i][2])) {
                     msg = msg + "第" + i + "行,关键字段缺失。<br/>";
+                    failCnt+=1;
                 } else if (customerDao.countByCardno((String) data[i][1]) >0) {
                     msg = msg + "第" + i + "行,该市名卡已存在。<br/>";
-                }
-                else{
+                    failCnt+=1;
+                } else{
                     TCustomer d=new TCustomer();
                     d.setCustname((String) data[i][0]);
                     String cardno=(String) data[i][1];
@@ -147,6 +154,7 @@
                         d.setPhone((String) data[i][3]);
                     }
                     sList.add(d);
+                    successCnt+=1;
                 }
             }
         }
@@ -163,6 +171,8 @@
 
             return JsonResult.ok("成功导入"+sList.size()+"条信息");
         }
+        msg="导入成功"+successCnt+"条,导入失败"+failCnt+"条<br/>"+msg;
+
         return JsonResult.error(String.format(Locale.CHINESE, msg));
     }
 
diff --git a/src/main/kotlin/com/supwisdom/dlpay/RestaurantApplication.kt b/src/main/kotlin/com/supwisdom/dlpay/RestaurantApplication.kt
index 46f5548..fdbdb46 100644
--- a/src/main/kotlin/com/supwisdom/dlpay/RestaurantApplication.kt
+++ b/src/main/kotlin/com/supwisdom/dlpay/RestaurantApplication.kt
@@ -2,9 +2,15 @@
 
 import io.lettuce.core.ReadFrom
 import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.SpringApplication
 import org.springframework.boot.autoconfigure.SpringBootApplication
 import org.springframework.boot.autoconfigure.data.redis.RedisProperties
+import org.springframework.boot.builder.SpringApplicationBuilder
 import org.springframework.boot.runApplication
+import org.springframework.boot.web.servlet.ServletComponentScan
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
+import org.springframework.cache.annotation.EnableCaching
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient
 import org.springframework.context.annotation.Bean
 import org.springframework.context.annotation.Configuration
 import org.springframework.data.redis.connection.RedisConnectionFactory
@@ -16,7 +22,7 @@
 import org.springframework.data.redis.repository.configuration.EnableRedisRepositories
 import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer
 import org.springframework.data.redis.serializer.StringRedisSerializer
-
+import org.springframework.scheduling.annotation.EnableScheduling
 
 @Configuration
 @EnableRedisRepositories
@@ -54,10 +60,13 @@
     }
 }
 
-
+@EnableDiscoveryClient
+@ServletComponentScan
 @SpringBootApplication
 class RestaurantApplication
 
 fun main(args: Array<String>) {
     runApplication<RestaurantApplication>(*args)
 }
+
+
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 10f6603..088c74d 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
@@ -1,9 +1,12 @@
 package com.supwisdom.dlpay.framework.controller
 
+import com.google.code.kaptcha.Producer
+import com.supwisdom.dlpay.exception.TransactionCheckException
 import com.supwisdom.dlpay.framework.ResponseBodyBuilder
 import com.supwisdom.dlpay.framework.core.JwtConfig
 import com.supwisdom.dlpay.framework.core.JwtTokenUtil
 import com.supwisdom.dlpay.framework.dao.ApiClientDao
+import com.supwisdom.dlpay.framework.dao.TenantConfigDao
 import com.supwisdom.dlpay.framework.domain.ApiClientRedis
 import com.supwisdom.dlpay.framework.domain.JwtRedis
 import com.supwisdom.dlpay.framework.domain.TOperator
@@ -13,26 +16,28 @@
 import com.supwisdom.dlpay.framework.security.validate.VerifyCode
 import com.supwisdom.dlpay.framework.service.CommonService
 import com.supwisdom.dlpay.framework.service.SystemUtilService
-import com.supwisdom.dlpay.framework.util.DateUtil
-import com.supwisdom.dlpay.framework.util.HmacUtil
-import com.supwisdom.dlpay.framework.util.TradeDict
+import com.supwisdom.dlpay.framework.util.*
 import com.supwisdom.dlpay.system.service.FunctionService
 import mu.KotlinLogging
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.HttpStatus
 import org.springframework.http.ResponseEntity
+import org.springframework.security.core.Authentication
 import org.springframework.security.core.annotation.AuthenticationPrincipal
 import org.springframework.security.core.context.SecurityContextHolder
 import org.springframework.security.core.userdetails.UserDetails
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer
+import org.springframework.security.oauth2.provider.OAuth2Authentication
 import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler
 import org.springframework.social.connect.web.HttpSessionSessionStrategy
 import org.springframework.stereotype.Controller
 import org.springframework.ui.Model
-import org.springframework.web.bind.annotation.GetMapping
-import org.springframework.web.bind.annotation.PathVariable
-import org.springframework.web.bind.annotation.RequestMapping
-import org.springframework.web.bind.annotation.RestController
+import org.springframework.web.bind.annotation.*
 import org.springframework.web.context.request.ServletWebRequest
+import java.awt.image.BufferedImage
+import java.io.IOException
+import java.lang.Exception
+import java.security.Principal
 import java.util.*
 import javax.imageio.ImageIO
 import javax.servlet.http.HttpServletRequest
@@ -57,25 +62,37 @@
     @Autowired
     lateinit var jwtConfig: JwtConfig
 
+
     @GetMapping(value = ["/gettoken", "/gettoken/{clientid}"])
-    fun loginInit(appid: String, @PathVariable clientid: String?): ResponseEntity<Any> {
+    fun loginInit(appid: String, @PathVariable clientid: String?,
+                  @RequestHeader(Constants.HEADER_TETANTID) tetantId: 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 != "normal") {
+            if (get().status != TradeDict.STATUS_NORMAL) {
                 return ResponseEntity.ok(ResponseBodyBuilder.create()
-                        .fail(1, "API状态错误"))
+                        .fail(TradeErrorCode.BUSINESS_DEAL_ERROR, "API状态错误"))
             }
             get()
-        }.let {
+        }.let { api ->
             val token = generateRandomToken()
             val now = systemUtil.sysdatetime.hostdatetime
-            ApiClientRedis().apply {
-                id = if (clientid == null) appid else "$appid-$clientid"
-                loginTimestamp = now
-                roles = it.roles
-                this.token = HmacUtil.HMACSHA256(token, it.secret)
+            ApiClientRedis().also {
+                it.id = if (clientid == null) appid else "$appid-$clientid"
+                it.loginTimestamp = now
+                it.roles = api.roles
+                it.tenantId = tetantId
+                it.token = HmacUtil.HMACSHA256(token, api.secret)
             }.also {
                 apiClientRepository.save(it)
             }
@@ -103,9 +120,11 @@
             if (it.isPresent && checkSecretToken(it.get(), secret)) {
                 apiClientRepository.deleteById(requestId)
                 val token = JwtTokenUtil(jwtConfig).generateToken(
-                        mapOf("uid" to appid, "issuer" to "payapi",
+                        mapOf(Constants.JWT_CLAIM_UID to appid,
+                                "issuer" to "payapi",
                                 "audience" to (clientid ?: appid),
-                                "authorities" to it.get().roles.split(";")))
+                                Constants.JWT_CLAIM_TENANTID to it.get().tenantId,
+                                Constants.JWT_CLAIM_AUTHORITIES to it.get().roles.split(";")))
                 JwtRedis().apply {
                     jti = token.jti
                     uid = appid
@@ -138,9 +157,10 @@
             if (it.isPresent && it.get().status == TradeDict.STATUS_NORMAL) {
                 // 新证书
                 val token = JwtTokenUtil(jwtConfig).generateToken(
-                        mapOf("uid" to appid, "issuer" to "payapi",
+                        mapOf(Constants.JWT_CLAIM_UID to appid,
+                                "issuer" to "payapi",
                                 "audience" to jwt["audience"],
-                                "authorities" to it.get().roles.split(";")))
+                                Constants.JWT_CLAIM_AUTHORITIES to it.get().roles.split(";")))
                 JwtRedis().apply {
                     jti = token.jti
                     uid = appid
@@ -165,11 +185,40 @@
 @RestController
 class ValidateCodeController {
 
+    @Autowired
+    private lateinit var captchaProducer: Producer
+
     @GetMapping("/code/image")
     fun createCode(request: HttpServletRequest, response: HttpServletResponse) {
         val imageCode = VerifyCode(60)
         HttpSessionSessionStrategy().setAttribute(ServletWebRequest(request), ImageCodeUtil.LOGIN_IMAGECODE_SESSIONKEY, imageCode)
-        ImageIO.write(imageCode.image, "JPEG", response.outputStream)
+        val session = request.session
+        response.setDateHeader("Expires", 0)
+        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate")
+        response.addHeader("Cache-Control", "post-check=0, pre-check=0")
+        response.setHeader("Pragma", "no-cache")
+        response.contentType = "image/jpeg"
+        //生成验证码
+        val capText = captchaProducer.createText()
+        session.setAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY, capText)
+        //向客户端写出
+        val bi = captchaProducer.createImage(capText);
+        ImageIO.write(bi, "JPEG", response.outputStream)
+        try {
+            response.outputStream.flush()
+        } catch (ex: Exception) {
+            response.outputStream.close()
+        }
+    }
+}
+
+@RestController
+class UserInforController {
+
+    @RequestMapping("/api/userinfor")
+    fun user(user: Principal): Principal {
+        System.out.println(user)
+        return user
     }
 }
 
@@ -186,6 +235,23 @@
     @GetMapping("/login")
     fun loginView() = "login"
 
+    @RequestMapping("/third/logout")
+    fun oauthLogout(request: HttpServletRequest, response: HttpServletResponse) {
+        val back = request.getParameter("redirect_uri")
+        SecurityContextLogoutHandler().logout(request, null, null);
+        try {
+            SecurityContextHolder.getContext().authentication = null
+            if (back != null) {
+                response.sendRedirect(back)
+            } else {
+                logger.debug { request.getHeader("referer") }
+                response.sendRedirect(request.getHeader("referer"))
+            }
+        } catch (e: IOException) {
+            e.printStackTrace()
+        }
+    }
+
     @GetMapping("/logout")
     fun logout(request: HttpServletRequest, response: HttpServletResponse): String {
         SecurityContextHolder.getContext().authentication?.also {
@@ -203,6 +269,7 @@
         model.addAttribute("payapiVersion", commonService.getSystemVersion())
         return "index"
     }
+
 }
 
 @Controller
@@ -212,7 +279,7 @@
      * 控制台
      */
     @GetMapping("/console")
-    fun console() :String{
+    fun console(): String {
         return "home/console"
     }
 
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
index ce82feb..f761b5c 100644
--- a/src/main/resources/data.sql
+++ b/src/main/resources/data.sql
@@ -37,42 +37,43 @@
 INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('truss_time1', 1, '2359', '0000', '扎帐时间点1(HHmm)', '1001', 'TS');
 INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('truss_time2', 1, '2359', '0000', '扎帐时间点2(HHmm)', '1531', 'TS');
 INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('truss_time3', 1, '2359', '0000', '扎帐时间点3(HHmm)', '2131', 'TS');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('breakfast_price', 7, NULL, NULL, '免费就餐-早餐价格(单位:分)', '30', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('buscar_amt_interval', 7, NULL, NULL, '车载机调价单价(单位:分)', '50', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('buscar_banner', 7, NULL, NULL, '车载机欢迎标语', '测试大学', 'S');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('buscar_base_amt', 7, NULL, NULL, '车载机基本价(单位:分)', '30', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('buscar_period_pay_not_wice', 7, NULL, NULL, '车载机同卡消费时间间隔(单位:分)', '1', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('buscar_price_adjust', 7, NULL, NULL, '车载机是否调价(0不启用,1启用)', '1', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('communicate_time', 7, '255', '0', '终端请求超时时间(单位:秒)', '3', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('consume_fail_show_time', 7, '255', '0', '消费失败显示时间([0-255] 单位:秒)', '1', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('consume_show_time', 7, '255', '0', '消费结果显示时间([0-255] 单位:秒)', '1', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('control_flag', 7, '255', '0', '控制开关字节(8bit):[支付宝卡代扣][正扫][NFC][反扫][营业额] 例如:27为[11011] (NFC消费为关闭,其他功能都是启用) ', '15', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('credit_low_limit', 7, NULL, NULL, '卡授信额度阀值(单位:分)', '2000', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('day_sum_limit_amt', 7, '999999', '1', '日累计消费限额 ([1-999999] 单位:分)', '2000', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('dinner_price', 7, NULL, NULL, '免费就餐-晚餐价格(单位:分)', '25', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('dtl_query_mode', 7, NULL, NULL, '流水查询方式(0后台,1-本地)', '0', 'B');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('dtl_show_way', 7, NULL, NULL, '流水显示方式(0优化,1-详细)', '1', 'B');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('fixpay_consume_gap', 7, '255', '0', '定额消费同一张卡连续消费间隔时间([0-255] 单位:秒)', '30', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('heat_beat', 7, '3600', '1', '心跳间隔 ([1-3600] 单位:秒)', '20', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('limit_switch', 7, NULL, NULL, '卡限开关 (0-关闭,1-开启)', '1', 'B');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('lunch_price', 7, NULL, NULL, '免费就餐-午餐价格(单位:分)', '20', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('manage_passwd', 7, NULL, NULL, '终端维护密码(默认914387)', '914387', 'S');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('max_cardbal', 7, '99999999', '1', '最大卡余额 ([1-99999999] 单位:分)', '99999', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('max_offline_days', 7, '90', '0', '脱机使用最大天数 ([1-90] 单位:天)', '7', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('max_pay_cnt', 7, '999999', '1', '卡最大使用次数 ([1-999999])', '65535', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('min_cardbal', 7, '99999', '0', '最小卡余额 ([0-99999] 单位:分)', '1', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('offline_flag', 7, NULL, NULL, '脱机消费时限开关 (0-关闭, 1-开启)', '0', 'B');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('once_limit_amt', 7, NULL, NULL, '单笔消费限额 ([1-9999] 单位:分)', '1000', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('qrcode_url', 7, NULL, NULL, '二维码消费地址', 'http://ykt.supwisdom.com:9116/epay/wxpage/qrscan', 'S');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('qr_offline_enable', 7, NULL, NULL, '二维码脱机支持 0--不支持脱机扫码 1--支持脱机扫码', '1', 'B');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('return_flag', 7, NULL, NULL, '消费撤销开关 (0-关闭, 1-开启)', '1', 'B');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('revenue_way', 7, NULL, NULL, '营业额查询方式(0-按天查询,1-餐次查询)', '0', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('socket_switch', 7, NULL, NULL, '长连接是否启用(0不启用,1启用)', '1', 'B');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('submeal_consume_enable', 7, '255', '0', '免费就餐次数([0-255] )', '0', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('timeout', 7, '9999', '10', '超时时间 ([10-9999] 单位:秒)', '90', 'N');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('truss_time1', 7, '2359', '0000', '扎帐时间点1(HHmm)', '1001', 'TS');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('truss_time2', 7, '2359', '0000', '扎帐时间点2(HHmm)', '1531', 'TS');
-INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('truss_time3', 7, '2359', '0000', '扎帐时间点3(HHmm)', '2131', 'TS');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('breakfast_price', 0, NULL, NULL, '免费就餐-早餐价格(单位:分)', '30', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('buscar_amt_interval', 0, NULL, NULL, '车载机调价单价(单位:分)', '50', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('buscar_banner', 0, NULL, NULL, '车载机欢迎标语', '测试大学', 'S');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('buscar_base_amt', 0, NULL, NULL, '车载机基本价(单位:分)', '30', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('buscar_period_pay_not_wice', 0, NULL, NULL, '车载机同卡消费时间间隔(单位:分)', '1', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('buscar_price_adjust', 0, NULL, NULL, '车载机是否调价(0不启用,1启用)', '1', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('communicate_time', 0, '255', '0', '终端请求超时时间(单位:秒)', '3', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('consume_fail_show_time', 0, '255', '0', '消费失败显示时间([0-255] 单位:秒)', '1', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('consume_show_time', 0, '255', '0', '消费结果显示时间([0-255] 单位:秒)', '1', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('control_flag', 0, '255', '0', '控制开关字节(8bit):[支付宝卡代扣][正扫][NFC][反扫][营业额] 例如:27为[11011] (NFC消费为关闭,其他功能都是启用) ', '15', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('credit_low_limit', 0, NULL, NULL, '卡授信额度阀值(单位:分)', '2000', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('day_sum_limit_amt', 0, '999999', '1', '日累计消费限额 ([1-999999] 单位:分)', '2000', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('dinner_price', 0, NULL, NULL, '免费就餐-晚餐价格(单位:分)', '25', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('dtl_query_mode', 0, NULL, NULL, '流水查询方式(0后台,1-本地)', '0', 'B');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('dtl_show_way', 0, NULL, NULL, '流水显示方式(0优化,1-详细)', '1', 'B');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('fixpay_consume_gap', 0, '255', '0', '定额消费同一张卡连续消费间隔时间([0-255] 单位:秒)', '30', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('heat_beat', 0, '3600', '1', '心跳间隔 ([1-3600] 单位:秒)', '20', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('limit_switch', 0, NULL, NULL, '卡限开关 (0-关闭,1-开启)', '1', 'B');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('lunch_price', 0, NULL, NULL, '免费就餐-午餐价格(单位:分)', '20', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('manage_passwd', 0, NULL, NULL, '终端维护密码(默认914387)', '914387', 'S');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('max_cardbal', 0, '99999999', '1', '最大卡余额 ([1-99999999] 单位:分)', '99999', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('max_offline_days', 0, '90', '0', '脱机使用最大天数 ([1-90] 单位:天)', '7', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('max_pay_cnt', 0, '999999', '1', '卡最大使用次数 ([1-999999])', '65535', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('min_cardbal', 0, '99999', '0', '最小卡余额 ([0-99999] 单位:分)', '1', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('offline_flag', 0, NULL, NULL, '脱机消费时限开关 (0-关闭, 1-开启)', '0', 'B');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('once_limit_amt', 0, NULL, NULL, '单笔消费限额 ([1-9999] 单位:分)', '1000', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('qrcode_url', 0, NULL, NULL, '二维码消费地址', 'http://ykt.supwisdom.com:9116/epay/wxpage/qrscan', 'S');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('qr_offline_enable', 0, NULL, NULL, '二维码脱机支持 0--不支持脱机扫码 1--支持脱机扫码', '1', 'B');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('return_flag', 0, NULL, NULL, '消费撤销开关 (0-关闭, 1-开启)', '1', 'B');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('revenue_way', 0, NULL, NULL, '营业额查询方式(0-按天查询,1-餐次查询)', '0', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('socket_switch', 0, NULL, NULL, '长连接是否启用(0不启用,1启用)', '1', 'B');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('submeal_consume_enable', 0, '255', '0', '免费就餐次数([0-255] )', '0', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('timeout', 0, '9999', '10', '超时时间 ([10-9999] 单位:秒)', '90', 'N');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('truss_time1', 0, '2359', '0000', '扎帐时间点1(HHmm)', '1001', 'TS');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('truss_time2', 0, '2359', '0000', '扎帐时间点2(HHmm)', '1531', 'TS');
+INSERT INTO "tb_devpara" (paraname,groupid,maxval,minval,paradesc,paraval,valtype) VALUES ('truss_time3', 0, '2359', '0000', '扎帐时间点3(HHmm)', '2131', 'TS');
+insert into "tb_devpara_group"(groupid,globalflag,groupname,lastsaved,verno) values(1,'t','默认参数组','',7);
 
 INSERT INTO "tb_dictionary"(dictval,dicttype,dictcaption,dicttypename) VALUES ('0', 'sexList', '女', '性别');
 INSERT INTO "tb_dictionary"(dictval,dicttype,dictcaption,dicttypename) VALUES ('1', 'sexList', '男', '性别');
@@ -91,8 +92,6 @@
 INSERT INTO "tb_function" (id,createtime,isleaf,lastsaved,menuicon,menuurl,name,ordernum,parentid) VALUES (11, NULL, 1, NULL, 'layui-icon-util', '/param/syspara', '全局参数配置', 1, 10);
 INSERT INTO "tb_function" (id,createtime,isleaf,lastsaved,menuicon,menuurl,name,ordernum,parentid) VALUES (12, NULL, 1, NULL, 'layui-icon-util', '/param/businesspara', '业务参数配置', 2, 10);
 INSERT INTO "tb_function" (id,createtime,isleaf,lastsaved,menuicon,menuurl,name,ordernum,parentid) VALUES (17, NULL, 1, NULL, 'layui-icon-util', '/param/apiclientpara', '应用参数配置', 3, 10);
-INSERT INTO "tb_function" (id,createtime,isleaf,lastsaved,menuicon,menuurl,name,ordernum,parentid) VALUES (8, NULL, 0, NULL, 'layui-icon-home', '#', '区域管理', 23, -1);
-INSERT INTO "tb_function" (id,createtime,isleaf,lastsaved,menuicon,menuurl,name,ordernum,parentid) VALUES (13, NULL, 1, NULL, 'layui-icon-home', '/area/index', '地区管理', 1, 8);
 INSERT INTO "tb_function" (id,createtime,isleaf,lastsaved,menuicon,menuurl,name,ordernum,parentid) VALUES (14, NULL, 0, NULL, 'layui-icon-app', '#', '设备管理', 8, -1);
 INSERT INTO "tb_function" (id,createtime,isleaf,lastsaved,menuicon,menuurl,name,ordernum,parentid) VALUES (15, NULL, 1, NULL, 'layui-icon-app', '/device/index', '注册设备', 1, 14);
 INSERT INTO "tb_function" (id,createtime,isleaf,lastsaved,menuicon,menuurl,name,ordernum,parentid) VALUES (16, NULL, 1, NULL, 'layui-icon-home', '/devicegroup/index', '设备组管理', 2, 14);
diff --git a/src/main/resources/templates/ologin.html b/src/main/resources/templates/ologin.html
new file mode 100644
index 0000000..8f9362e
--- /dev/null
+++ b/src/main/resources/templates/ologin.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+
+<html xmlns:th="http://www.thymeleaf.org">
+
+<head>
+    <title>统一身份认证</title>
+    <meta name="_csrf" th:content="${_csrf.token}"/>
+    <!-- default header name is X-CSRF-TOKEN -->
+    <meta name="_csrf_header" th:content="${_csrf.headerName}"/>
+    <link rel="stylesheet" type="text/css" th:href="@{/static/libs/layui/css/layui.css}"/>
+    <link rel="stylesheet" type="text/css" th:href="@{/static/custom/css/login.css}"/>
+</head>
+<body>
+<div class="login-wrapper">
+    <div class=" login-body">
+        <div class="layui-card">
+            <div class="layui-card-header">
+                <i class="layui-icon layui-icon-engine"></i>&nbsp;&nbsp;统一身份认证
+            </div>
+            <div class="layui-card-body layui-form layui-form-pane">
+                <p style="color:red;padding: 0 0 10px 0;" th:if="${session['SPRING_SECURITY_LAST_EXCEPTION']!=null and session['SPRING_SECURITY_LAST_EXCEPTION'].message!=null}" th:text="${session['SPRING_SECURITY_LAST_EXCEPTION'].message}"></p>
+                <form th:action="@{/login/form}" method="post">
+                    <div class="layui-form-item">
+                        <label class="layui-form-label"><i class="layui-icon layui-icon-username"></i></label>
+                        <div class="layui-input-block">
+                            <input name="username" type="text" lay-verify="required" placeholder="账号"
+                                   class="layui-input">
+                            <input type="hidden"
+                                   th:name="${_csrf.parameterName}"
+                                   th:value="${_csrf.token}"/>
+                        </div>
+                    </div>
+                    <div class="layui-form-item">
+                        <label class="layui-form-label"><i class="layui-icon layui-icon-password"></i></label>
+                        <div class="layui-input-block">
+                            <input name="password" type="password" lay-verify="required" placeholder="密码"
+                                   class="layui-input">
+                        </div>
+                    </div>
+                    <div class="layui-form-item">
+                        <label class="layui-form-label"><i class="layui-icon layui-icon-vercode"></i></label>
+                        <div class="layui-input-block">
+                            <div class="layui-row inline-block">
+                                <div class="layui-col-xs7">
+                                    <input name="imageCode" type="text" placeholder="验证码"
+                                           class="layui-input">
+                                </div>
+                                <div class="layui-col-xs5" style="padding-left: 10px;">
+                                    <img width="100px" height="35px" class="login-captcha" th:src="@{/code/image}">
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="layui-form-item">
+                        <!--<a href="javascript:;" class="layui-link">帐号注册</a>-->
+                        <a href="javascript:;" class="layui-link pull-right">忘记密码?</a>
+                    </div>
+                    <div class="layui-form-item">
+                        <button type="submit" lay-filter="login-submit" class="layui-btn layui-btn-fluid" lay-submit>登 录</button>
+                    </div>
+                </form>
+                <!--<div class="layui-form-item login-other">-->
+                <!--<label>第三方登录</label>-->
+                <!--<a href="javascript:;"><i class="layui-icon layui-icon-login-qq"></i></a>-->
+                <!--<a href="javascript:;"><i class="layui-icon layui-icon-login-wechat"></i></a>-->
+                <!--<a href="javascript:;"><i class="layui-icon layui-icon-login-weibo"></i></a>-->
+                <!--</div>-->
+            </div>
+        </div>
+    </div>
+
+    <div class="login-footer">
+        <p>© 2019 <a href="javascript:;" target="_blank">上海树维信息科技有限公司 版权所有</a></p>
+        <!--<p>-->
+        <!--<span><a href="javascript:;" target="_blank">前往github</a></span>-->
+        <!--<span><a href="https://gitee.com/andyzy/zy-admin.git" target="_blank">前往gitee</a></span>-->
+        <!--<span><a href="javascript:;" target="_blank">文档说明</a></span>-->
+        <!--</p>-->
+    </div>
+</div>
+
+<script type="text/javascript"  th:src="@{/static/libs/layui/layui.js}" ></script>
+<script>
+    layui.config({
+        base: 'custom/module/'
+    }).use(['form'], function () {
+        var $ = layui.jquery;
+
+        // 图形验证码
+        $('.login-captcha').click(function () {
+            this.src = this.src + '?t=' + (new Date).getTime();
+        });
+    });
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/src/main/resources/templates/restaurant/customer/form.html b/src/main/resources/templates/restaurant/customer/form.html
index 426d576..d3f2230 100644
--- a/src/main/resources/templates/restaurant/customer/form.html
+++ b/src/main/resources/templates/restaurant/customer/form.html
@@ -2,14 +2,14 @@
 <form id="customer-form" lay-filter="form" class="layui-form model-form">
     <input name="custid" id="customer-custid" type="hidden"/>
     <div class="layui-form-item">
-        <label class="layui-form-label">姓名</label>
+        <label class="layui-form-label"><span style="color: red">* </span>姓名</label>
         <div class="layui-input-block">
             <input name="custname" placeholder="请输入" type="text" class="layui-input" maxlength="20"
                    lay-verify="required|custname" required/>
         </div>
     </div>
     <div class="layui-form-item">
-        <label class="layui-form-label">市名卡号</label>
+        <label class="layui-form-label"><span style="color: red">* </span>市名卡号</label>
         <div class="layui-input-block">
             <input name="cardno" placeholder="请输入" type="text" class="layui-input" maxlength="20"
                    lay-verify="required|number" required/>
@@ -17,7 +17,7 @@
     </div>
 
     <div class="layui-form-item">
-        <label class="layui-form-label">银行卡号</label>
+        <label class="layui-form-label"><span style="color: red">* </span>银行卡号</label>
         <div class="layui-input-block">
             <input name="bankcardno" placeholder="请输入" type="text" class="layui-input" maxlength="30"
                    lay-verify="required|number" required/>
diff --git a/src/main/resources/templates/restaurant/device/form.html b/src/main/resources/templates/restaurant/device/form.html
index e5ee279..1f3d234 100644
--- a/src/main/resources/templates/restaurant/device/form.html
+++ b/src/main/resources/templates/restaurant/device/form.html
@@ -2,7 +2,7 @@
 <form id="device-form" lay-filter="form" class="layui-form model-form">
     <input name="id" id="device-id" type="hidden"/>
     <div class="layui-form-item">
-        <label class="layui-form-label">设备物理ID</label>
+        <label class="layui-form-label"><span style="color: red">* </span>设备物理ID</label>
         <div class="layui-input-block">
             <input name="devphyid" placeholder="不能重复" type="text" class="layui-input" maxlength="20"
                    lay-verify="required|devphyid" required/>
@@ -19,7 +19,7 @@
 
 
     <div class="layui-form-item">
-        <label class="layui-form-label">所属商户ID</label>
+        <label class="layui-form-label"><span style="color: red">* </span>所属商户ID</label>
         <div class="layui-input-block">
             <input name="shopid" placeholder="请输入" type="text" class="layui-input"/>
         </div>
diff --git a/src/main/resources/templates/restaurant/device/import.html b/src/main/resources/templates/restaurant/device/import.html
index 4d9f10d..6249a7a 100644
--- a/src/main/resources/templates/restaurant/device/import.html
+++ b/src/main/resources/templates/restaurant/device/import.html
@@ -58,7 +58,6 @@
             console.log(formData);
             layer.load(2);
             let token = $("meta[name='_csrf_token']").attr("value");
-            debugger
             $.ajax({
                 type: "POST",
                 url: url,
diff --git a/src/main/resources/templates/restaurant/device/index.html b/src/main/resources/templates/restaurant/device/index.html
index 26d5449..a63f279 100644
--- a/src/main/resources/templates/restaurant/device/index.html
+++ b/src/main/resources/templates/restaurant/device/index.html
@@ -16,12 +16,12 @@
             <button id="device-btn-import" class="layui-btn icon-btn" ><i class="layui-icon"></i>批量导入</button>
 
         </div>
-        <table class="layui-table" id="device-table" lay-filter="table"></table>
+        <table class="layui-table" id="device-table" lay-filter="device-table"></table>
     </div>
 </div>
 
-<script type="text/html" id="dev-tpl-state">
-    <input type="checkbox" lay-filter="dev-tpl-state" value="{{d.id}}" lay-skin="switch" lay-text="正常|注销"
+<script type="text/html" id="device-dev-tpl-state">
+    <input type="checkbox" lay-filter="device-dev-tpl-state" value="{{d.id}}" lay-skin="switch" lay-text="正常|注销"
            {{d.state=='1'?'checked':''}} />
 </script>
 <script>
@@ -44,10 +44,10 @@
                     {field: 'devphyid', sort: true, width: 200, title: '设备物理id'},
                     {field: 'shopid', sort: true, width: 200, title: '商户id'},
                     {field: 'factoryid', sort: true, width: 200, title: '设备厂商'},
-                    {field: 'state', title: '状态', sort: true, width: 100, templet: '#dev-tpl-state'},
+                    {field: 'state', title: '状态', sort: true, width: 100, templet: '#device-dev-tpl-state'},
                     {
                         field: 'id', align: 'center', title: '操作', fixed: 'right', templet: function (item) {
-                            return ' <a class="layui-btn  layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>编辑</a> ';
+                            return ' <a class="layui-btn  layui-btn-xs" lay-event="device-edit"><i class="layui-icon layui-icon-edit"></i>编辑</a> ';
                         }
                     }
                 ]
@@ -59,7 +59,7 @@
             table.reload('device-table', {where: {searchkey: key}, page: {curr: 1}});
         });
         $('#device-btn-add').click(function () {
-            showModel();
+            showDevModel();
         });
         $('#device-btn-import').click(function () {
             showDownload();
@@ -74,7 +74,7 @@
                 }
             });
         };
-        let showModel = function (data) {
+        let showDevModel = function (data) {
             let title = data ? '修改设备' : '添加设备';
             admin.putTempData('t_dev', data);
             admin.popupCenter({
@@ -88,17 +88,15 @@
 
 
         // 工具条点击事件
-        table.on('tool(table)', function (obj) {
+        table.on('tool(device-table)', function (obj) {
             let data = obj.data;
             let layEvent = obj.event;
             console.log(data);
-            if (layEvent === 'edit') {
-                showModel(data);
-            } else if (layEvent === 'del') {
-                showDelete(data);
+            if (layEvent === 'device-edit') {
+                showDevModel(data);
             }
         });
-        let showDelete = function (data) {
+      /*  let showDelete = function (data) {
             layer.confirm('确定要删除吗?', function (i) {
                 layer.close(i);
                 layer.load(2);
@@ -126,9 +124,9 @@
                     layer.msg('请求失败了,请稍后再试', {icon: 2});
                 });
             });
-        };
+        };*/
 
-        form.on('switch(dev-tpl-state)', function (obj) {
+        form.on('switch(device-dev-tpl-state)', function (obj) {
             layer.load(2);
             let token = $("meta[name='_csrf_token']").attr("value");
             admin.go('[[@{/device/updatestate}]]', {
diff --git a/src/main/resources/templates/restaurant/devicegroup/form.html b/src/main/resources/templates/restaurant/devicegroup/form.html
index a85f85e..281367a 100644
--- a/src/main/resources/templates/restaurant/devicegroup/form.html
+++ b/src/main/resources/templates/restaurant/devicegroup/form.html
@@ -2,14 +2,14 @@
 <form id="devicegroup-form" lay-filter="form" class="layui-form model-form">
     <input name="devgroupid" id="devicegroup-devgroupid" type="hidden"/>
     <div class="layui-form-item">
-        <label class="layui-form-label">设备组名称</label>
+        <label class="layui-form-label"><span style="color: red">* </span>设备组名称</label>
         <div class="layui-input-block">
             <input name="groupname"  type="text" class="layui-input" maxlength="20"
                    lay-verify="required|groupname" required/>
         </div>
     </div>
     <div class="layui-form-item">
-        <label class="layui-form-label">上级设备组</label>
+        <label class="layui-form-label"><span style="color: red">* </span>上级设备组</label>
         <div class="layui-input-block">
             <select name="pid"  lay-verify="required">
                 <option value="0">根设备</option>
diff --git a/src/main/resources/templates/restaurant/devicegroup/index.html b/src/main/resources/templates/restaurant/devicegroup/index.html
index e359ca9..dcb9d31 100644
--- a/src/main/resources/templates/restaurant/devicegroup/index.html
+++ b/src/main/resources/templates/restaurant/devicegroup/index.html
@@ -51,6 +51,7 @@
         table.render({
             elem: '#devicegroup-table',
             url: '[[@{/devicegroup/listDevice}]]',
+            where:  {searchkey:0},
             page: true,
             cols: [
                 [
@@ -65,8 +66,8 @@
         });
         // 搜索按钮点击事件
         $('#devicegroup-btn-search').click(function () {
-            let key = $('#search-value').val().trim();
-            table.reload('devicegroup-table', {where: {searchkey: key}, page: {curr: 1}});
+            let key = $('#search-value').val();
+            table.reload('devicegroup-table', {where: {searchkey: key.trim()}, page: {curr: 1}});
         });
         $('#devicegroup-btn-add').click(function () {
             showModel();
@@ -90,11 +91,6 @@
             let data = obj.data;
             let layEvent = obj.event;
             console.log(data);
-            if (layEvent === 'edit') {
-                showModel(data);
-            } else if (layEvent === 'del') {
-                showDelete(data);
-            }
         });
         let showDelete = function (data) {
             layer.confirm('确定要删除吗?', function (i) {
diff --git a/src/main/resources/templates/restaurant/devicemanage/form.html b/src/main/resources/templates/restaurant/devicemanage/form.html
index 81162e7..09d53ba 100644
--- a/src/main/resources/templates/restaurant/devicemanage/form.html
+++ b/src/main/resources/templates/restaurant/devicemanage/form.html
@@ -2,14 +2,14 @@
 <form id="form" lay-filter="form" class="layui-form model-form">
     <input name="id" id="id" type="hidden"/>
     <div class="layui-form-item">
-        <label class="layui-form-label">设备名称</label>
+        <label class="layui-form-label"><span style="color: red">* </span>设备名称</label>
         <div class="layui-input-block">
             <input name="devicename" placeholder="建议采用带有地理坐标的名称" type="text" class="layui-input" maxlength="20"
                    lay-verify="required|devphyid" required/>
         </div>
     </div>
     <div class="layui-form-item">
-        <label class="layui-form-label">设备组</label>
+        <label class="layui-form-label"><span style="color: red">* </span>设备组</label>
         <div class="layui-input-block">
             <select name="devgroupid" id="devgroupid" lay-verify="required">
                 <option value="0">无</option>
@@ -37,7 +37,7 @@
 
         var url = '[[@{/devicemanage/update}]]';
         // 回显user数据
-        var dev = admin.getTempData('t_dev');
+        var dev = admin.getTempData('t_devm');
         if (dev) {
             $('input[name="id"]').attr('readonly', 'readonly');
             form.val('form', dev);
diff --git a/src/main/resources/templates/restaurant/devicemanage/index.html b/src/main/resources/templates/restaurant/devicemanage/index.html
index 6f09bb5..283b379 100644
--- a/src/main/resources/templates/restaurant/devicemanage/index.html
+++ b/src/main/resources/templates/restaurant/devicemanage/index.html
@@ -22,12 +22,12 @@
             </button>
 
         </div>
-        <table class="layui-table" id="devicemanage-table" lay-filter="table"></table>
+        <table class="layui-table" id="devicemanage-table" lay-filter="devicemanage-table"></table>
     </div>
 </div>
 
 <script type="text/html" id="devicemanage-dev-tpl-state">
-    <input type="checkbox" lay-filter="dev-tpl-state" value="{{d.id}}" lay-skin="switch" lay-text="正常|注销"
+    <input type="checkbox" lay-filter="devicemanage-dev-tpl-state" value="{{d.id}}" lay-skin="switch" lay-text="正常|注销"
            {{d.state=='1'?'checked':''}} />
 </script>
 <script>
@@ -51,10 +51,10 @@
                     {field: 'devphyid', sort: true, width: 200, title: '设备物理id'},
                     {field: 'shopid', sort: true, width: 150, title: '商户id'},
                     {field: 'factoryid', sort: true, width: 200, title: '设备厂商'},
-                    {field: 'state', title: '状态', sort: true, width: 100, templet: '#dev-tpl-state'},
+                    {field: 'state', title: '状态', sort: true, width: 100, templet: '#devicemanage-dev-tpl-state'},
                     {
                         field: 'id', align: 'center', title: '操作', fixed: 'right', templet: function (item) {
-                            return ' <a class="layui-btn  layui-btn-xs" lay-event="edit"><i class="layui-icon layui-icon-edit"></i>修改</a> ';
+                            return ' <a class="layui-btn  layui-btn-xs" lay-event="devicemanage-edit"><i class="layui-icon layui-icon-edit"></i>修改</a> ';
                         }
                     }
                 ]
@@ -88,16 +88,16 @@
 
 
         // 工具条点击事件
-        table.on('tool(table)', function (obj) {
+        table.on('tool(devicemanage-table)', function (obj) {
             let data = obj.data;
             let layEvent = obj.event;
             console.log(data);
-            if (layEvent === 'edit') {
+            if (layEvent === 'devicemanage-edit') {
                 showModel(data);
             }
         });
 
-        form.on('switch(dev-tpl-state)', function (obj) {
+        form.on('switch(devicemanage-dev-tpl-state)', function (obj) {
             layer.load(2);
             let token = $("meta[name='_csrf_token']").attr("value");
             admin.go('[[@{/device/updatestate}]]', {
diff --git a/src/main/resources/templates/restaurant/devpara/devpara.html b/src/main/resources/templates/restaurant/devpara/devpara.html
index d460615..5525d8d 100644
--- a/src/main/resources/templates/restaurant/devpara/devpara.html
+++ b/src/main/resources/templates/restaurant/devpara/devpara.html
@@ -51,7 +51,10 @@
                         }},
                     {
                         field: 'lastsaved', title: '更新时间', align: 'center', templet: function (d) {
-                            return admin.formatDate(d.lastsaved);
+                            if(d.lastsaved!=null){
+                                return admin.formatDate(d.lastsaved);
+                            }
+                           return '';
                         }
                     },
                     {align: 'center', title: '操作', width: 250, toolbar: '#devparagroup-table-bar',  fixed: 'right'}
diff --git a/src/main/resources/templates/restaurant/discountrule/ruleform.html b/src/main/resources/templates/restaurant/discountrule/ruleform.html
index 24010a9..236edb9 100644
--- a/src/main/resources/templates/restaurant/discountrule/ruleform.html
+++ b/src/main/resources/templates/restaurant/discountrule/ruleform.html
@@ -74,12 +74,14 @@
         laydate.render({
             elem: '#form-discountrule-starttime',
             type: 'time',
-            format: 'HH:mm'
+            format: 'HH:mm',
+            trigger: 'click'
         });
         laydate.render({
             elem: '#form-discountrule-endtime',
             type: 'time',
-            format: 'HH:mm'
+            format: 'HH:mm',
+            trigger: 'click'
         });
 
         // 表单提交事件
diff --git a/src/main/resources/templates/restaurant/transdtl/index.html b/src/main/resources/templates/restaurant/transdtl/index.html
index c7298f4..a18b3ff 100644
--- a/src/main/resources/templates/restaurant/transdtl/index.html
+++ b/src/main/resources/templates/restaurant/transdtl/index.html
@@ -62,6 +62,8 @@
                             </select>
                         </div>
                     </div>
+                </div>
+                <div class="layui-form-item">
                     <div class="layui-inline" style="margin-left:5%">
                         <button id="transdtl-btn-search" class="layui-btn icon-btn" data-type="search">
                             <i class="layui-icon">&#xe615;</i>搜索
diff --git a/src/main/resources/templates/restaurant/transdtlform/index.html b/src/main/resources/templates/restaurant/transdtlform/index.html
index 0142ee2..6d872c4 100644
--- a/src/main/resources/templates/restaurant/transdtlform/index.html
+++ b/src/main/resources/templates/restaurant/transdtlform/index.html
@@ -1,191 +1,90 @@
-<div class="layui-card layui-col-xs3" style="padding-bottom: 40%">
+<div class="layui-card">
     <div class="layui-card-header">
-        <h2 class="header-title">设备组</h2>
-
+        <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">
-            <button id="btn-add" class="layui-btn icon-btn" data-type="add"><i class="layui-icon"></i>添加设备组</button>
+            <form id="transdtl-form"  >
+                <div class="layui-form-item">
+                    <div class="layui-inline">
+                        <label class="layui-form-label">交易日期:</label>
+                        <div class="layui-input-inline">
+                            <input type="text" name="startdate" class="layui-input" th:value="${startDate}"
+                                   id="transdtlform-startdate" placeholder="yyyy-MM-dd">
+                        </div>
+                        <div class="layui-input-inline">
+                            <input type="text" name="enddate" class="layui-input" th:value="${endDate}"
+                                   id="transdtlform-enddate" placeholder="yyyy-MM-dd">
+                        </div>
+                    </div>
+                </div>
+                <div class="layui-input-inline">
+                    <input id="search-devparabind-form-devgroupid" type="text"
+                           lay-filter="search-devparabind-form-devgroupid-filter" autocomplete="off"
+                           class="layui-input"/>
+                </div>
+            </form>
+
         </div>
-        <div id="menuContent" class="menuContent " style="position: absolute;">
-            <ul id="ztree-menu" class="ztree" style="margin-top:0;"></ul>
-        </div>
+        <table class="layui-table" id="transdtl-table" lay-filter="table"></table>
     </div>
 </div>
 
-
-<div class="layui-card layui-col-xs8" style="margin-left:3% ">
-    <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-value" class="layui-input search-input" type="hidden"/>&emsp;
-            <!--    <button id="btn-search" class="layui-btn icon-btn" data-type="search"><i class="layui-icon">&#xe615;</i>搜索
-                </button>-->
-
-        </div>
-        <table class="layui-table" id="table" lay-filter="table"></table>
-    </div>
-</div>
-
-<script type="text/html" id="dev-tpl-state">
-    <input type="checkbox" lay-filter="dev-tpl-state" value="{{d.id}}" lay-skin="switch" lay-text="正常|注销" disabled
-           {{d.state=='1'?'checked':''}} />
-</script>
 <script>
 
     layui.use(['form', 'table', 'layer', 'admin', 'element'], function () {
         let form = layui.form;
         let table = layui.table;
         let admin = layui.admin;
+        var treeSelect = layui.treeSelect;
 
-        form.render('select');
 
-        // 渲染表格
-        table.render({
-            elem: '#table',
-            url: '[[@{/devicegroup/listDevice}]]',
-            cols: [
-                [
-                    {field: 'id', title: '终端编号',width: 100, sort: true},
-                    {field: 'devicename', title: '设备名称',width: 160, sort: true},
-                    {field: 'devphyid', sort: true, width: 120, title: '设备物理id'},
-                    {field: 'shopid', sort: true, width: 100, title: '商户id'},
-                    {field: 'factoryid', sort: true, width: 150, title: '设备厂商'},
-                    {field: 'state', title: '状态', sort: true, width: 100, templet: '#dev-tpl-state'},
-                ]
-            ]
-        });
+
         // 搜索按钮点击事件
         $('#btn-search').click(function () {
             let key = $('#search-value').val().trim();
             table.reload('table', {where: {searchkey: key}});
         });
-        $('#btn-add').click(function () {
-            showModel();
-        });
-
-        let showModel = function (data) {
-            let title = data ? '修改设备组' : '添加设备组';
-            admin.putTempData('t_devgroup', data);
-            admin.popupCenter({
-                title: title,
-                path: '/devicegroup/loadadd',
-                finish: function () {
-                    loadTree();
+        treeSelect.render({
+            elem: '#search-devparabind-form-devgroupid',
+            data: '[[@{/device/binddevparagrouptree}]]',
+            type: 'get',
+            placeholder: '选择设备组',
+            search: false,
+            style: {
+                folder: {
+                    enable: false
+                },
+                line: {
+                    enable: true
                 }
-            });
-        };
-
-
-        // 工具条点击事件
-        table.on('tool(table)', function (obj) {
-            let data = obj.data;
-            let layEvent = obj.event;
-            console.log(data);
-            if (layEvent === 'edit') {
-                showModel(data);
-            } else if (layEvent === 'del') {
-                showDelete(data);
+            },
+            // 点击回调
+            click: function (d) {
+                var treeNode = d.current;
+                console.log(treeNode);
+                return true;
+            },
+            success: function (d) {
+                console.log(d); // 加载完成后的回调函数
             }
         });
-        let showDelete = function (data) {
-            layer.confirm('确定要删除吗?', function (i) {
-                layer.close(i);
-                layer.load(2);
-                let token = $("meta[name='_csrf_token']").attr("value");
-                admin.go('[[@{/device/delete}]]', {
-                    id: data.id,
-                    _csrf: token
-                }, function (data) {
-                    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('table', {});
-                }, function (ret) {
-                    console.log(ret);
-                    layer.closeAll('loading');
-                    layer.msg('请求失败了,请稍后再试', {icon: 2});
-                });
-            });
-        };
-
-        function OnGrpClick(e, treeId, treeNode) {
-            console.log(treeNode.id);
-            table.reload('table', {where: {searchkey: treeNode.id}});
-
-        }
-        function loadZTree(eNodes) {
-            var menuSetting = {
-                view: {
-                    dblClickExpand: true,
-                    selectedMulti: false,
-                    showLine: true,
-                    showIcon: false
-                },
-                edit: {
-                    enable: true,
-                    drag: {
-                        isMove: true,
-                        prev: true,
-                        autoOpenTime: 0
-                    },
-                },
-                data: {
-                    simpleData: {
-                        enable: true
-                    }
-                },
-                callback: {
-                    onClick: OnGrpClick
-                }
-            };
-            $.fn.zTree.init($("#ztree-menu"), menuSetting, eNodes);
-        }
-
-        $(document).ready(function () {
-            loadTree();
-        })
-
-        function loadTree() {
-            let token = $("meta[name='_csrf_token']").attr("value");
-            $.ajax({
-                type: "POST",
-                dataType: "json",
-                url: "[[@{/devicegroup/listTree}]]",
-                headers: {
-                    'Accept': 'application/json',
-                    'X-CSRF-TOKEN': token,
-                },
-                data: {},
-                success: function (result) {
-                    console.log("获取返回", result.data);
-                    if (result.code == 0) {
-                        loadZTree(result.data);
-                    } else {
-                        layer.msg('请求失败了,请稍后再试', {icon: 2});
-                    }
-                },
-                error: function (data) {
-                    layer.msg('请求失败了,请稍后再试', {icon: 2});
-                }
-            })
-        }
-
+        laydate.render({
+            elem: '#transdtlform-startdate',
+            btns: ['now', 'confirm'],
+            trigger: 'click',
+            max: enddate
+        });
+        laydate.render({
+            elem: '#transdtlform-enddate',
+            btns: ['now', 'confirm'],
+            trigger: 'click',
+            max: enddate
+        });
 
 
     });
diff --git a/src/main/resources/templates/system/operator/operator.html b/src/main/resources/templates/system/operator/operator.html
index 682e6c4..c96c14b 100644
--- a/src/main/resources/templates/system/operator/operator.html
+++ b/src/main/resources/templates/system/operator/operator.html
@@ -2,14 +2,14 @@
 <form id="oper-form" lay-filter="oper-form" class="layui-form model-form">
     <input name="operid" id="operid" type="hidden"/>
     <div class="layui-form-item">
-        <label class="layui-form-label">账号</label>
+        <label class="layui-form-label"><span style="color: red">* </span>账号</label>
         <div class="layui-input-block">
             <input name="opercode" placeholder="请输入账号" type="text" class="layui-input" maxlength="20"
                    lay-verify="required|opercode" required/>
         </div>
     </div>
     <div class="layui-form-item">
-        <label class="layui-form-label">用户名</label>
+        <label class="layui-form-label"><span style="color: red">* </span>用户名</label>
         <div class="layui-input-block">
             <input name="opername" placeholder="请输入用户名" type="text" class="layui-input" maxlength="60"
                    lay-verify="required" required/>
@@ -42,7 +42,7 @@
     </div>
 
     <div class="layui-form-item">
-        <label class="layui-form-label">角色</label>
+        <label class="layui-form-label"><span style="color: red">* </span>角色</label>
         <div class="layui-input-block">
             <select name="roleId" xm-select="roleId" lay-verify="required">
                 <option th:each="role : ${roles}" th:value="${role.roleId}">[[${role.roleName}]]</option>
@@ -65,6 +65,7 @@
         var formSelects = layui.formSelects;
 
         form.render('radio');
+        form.render('checkbox');
         form.verify({
             "mobile": function (e) {
                 if (null != e && e.length > 0 && !(/^1\d{10}$/.test(e))) {
diff --git a/src/main/resources/templates/system/role/form.html b/src/main/resources/templates/system/role/form.html
index d60bac8..d9a8358 100755
--- a/src/main/resources/templates/system/role/form.html
+++ b/src/main/resources/templates/system/role/form.html
@@ -1,6 +1,7 @@
 <!-- operator表单弹窗 -->

 <form id="form" lay-filter="form" class="layui-form model-form">

     <input name="roleId" id="roleId" type="hidden"/>

+    <input name="roleCode" id="roleCode" type="hidden"/>

     <div class="layui-form-item">

         <label class="layui-form-label">角色名称</label>

         <div class="layui-input-block">

@@ -11,7 +12,7 @@
     <div class="layui-form-item">

         <label class="layui-form-label">角色描述</label>

         <div class="layui-input-block">

-            <textarea name="roleDesc" placeholder="请输入描述" class="layui-textarea"></textarea>

+            <textarea name="roleDesc" id="roleDesc" placeholder="描述最多为60字符" class="layui-textarea"></textarea>

         </div>

     </div>

 

@@ -31,12 +32,19 @@
         var func = admin.getTempData('t_func');

         if (func) {

             $('input[name="roleId"]').attr('readonly', 'readonly');

+            $('input[name="roleCode"]').attr('readonly', 'readonly');

             form.val('form', func);

         }

         // 表单提交事件

         form.on('submit(form-submit)', function (data) {

             layer.load(2);

             let token = $("meta[name='_csrf_token']").attr("value");

+            var roleDesc=$("#roleDesc").val();

+            if(roleDesc.length>60){

+                layer.msg("角色描述字数超过上限!", {icon: 2});

+                layer.closeAll('loading');

+                return false;

+            }

             $.ajax({

                 type : "POST",

                 dataType : "json",