From 2d2fd991826837d7189cc488aee6f309a6f5e216 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期一, 09 三月 2026 22:48:46 +0800
Subject: [PATCH] #

---
 src/main/java/com/zy/asrs/controller/BasDualCrnpOptController.java    |    7 
 src/main/java/com/zy/asrs/controller/ApiLogController.java            |    7 
 src/main/java/com/zy/asrs/controller/LocMastController.java           |   11 
 src/main/java/com/zy/common/web/BaseController.java                   |    2 
 src/main/java/com/zy/asrs/controller/BasDualCrnpController.java       |    7 
 src/main/java/com/zy/asrs/controller/WrkMastLogController.java        |   11 
 src/main/java/com/zy/asrs/controller/BasMapController.java            |    7 
 src/main/java/com/zy/asrs/controller/BasCrnpErrController.java        |    7 
 src/main/java/com/zy/asrs/controller/BasWrkStatusController.java      |    7 
 src/main/java/com/zy/asrs/controller/WrkMastController.java           |    7 
 src/main/java/com/zy/asrs/controller/BasCrnpController.java           |    7 
 src/main/java/com/zy/asrs/controller/BasStationController.java        |    7 
 src/main/resources/templates/Js.txt                                   |  963 ++++++++++++++++++++------
 src/main/java/com/zy/asrs/controller/BasCrnpErrLogController.java     |    7 
 src/main/java/com/zy/asrs/controller/BasCrnpOptController.java        |    7 
 src/main/java/com/zy/asrs/controller/BasRgvErrLogController.java      |    7 
 src/main/java/com/zy/asrs/controller/BasStationOptController.java     |    7 
 src/main/java/com/zy/asrs/controller/BasDualCrnpErrController.java    |    7 
 src/main/java/com/zy/asrs/controller/BasRgvErrController.java         |    7 
 src/main/java/com/zy/asrs/controller/HttpRequestLogController.java    |    7 
 src/main/java/com/zy/asrs/controller/BasLocStsController.java         |    7 
 src/main/java/com/zy/asrs/controller/BasDevpController.java           |    7 
 src/main/resources/templates/Controller.txt                           |    7 
 src/main/java/com/zy/asrs/controller/BasDualCrnpErrLogController.java |    7 
 src/main/java/com/zy/asrs/controller/BasRgvController.java            |    7 
 src/main/java/com/zy/common/CodeBuilder.java                          |    1 
 /dev/null                                                             |   48 -
 src/main/java/com/core/generators/CoolGenerator.java                  |  233 ++++--
 src/main/java/com/zy/asrs/controller/BasRgvOptController.java         |    7 
 src/main/java/com/zy/asrs/controller/BasWrkIotypeController.java      |    7 
 src/main/java/com/zy/asrs/controller/DeviceConfigController.java      |    7 
 src/main/resources/templates/Html.txt                                 |  701 ++++++++++++++++++-
 src/main/java/com/zy/asrs/controller/WrkLastnoController.java         |    7 
 33 files changed, 1,644 insertions(+), 501 deletions(-)

diff --git a/src/main/java/com/core/generators/CoolGenerator.java b/src/main/java/com/core/generators/CoolGenerator.java
index 6e4ebfd..250c174 100644
--- a/src/main/java/com/core/generators/CoolGenerator.java
+++ b/src/main/java/com/core/generators/CoolGenerator.java
@@ -31,7 +31,7 @@
 
     private static final String[] ALL_TEMPLATES = {
             "Controller", "Service", "ServiceImpl", "Mapper", "Entity",
-            "Xml", "Html", "HtmlDetail", "Js", "Sql"
+            "Xml", "Html", "Js", "Sql"
     };
     private static final Set<String> SYSTEM_MODEL = new LinkedHashSet<>(Arrays.asList("User", "Host"));
 
@@ -46,7 +46,6 @@
     public boolean entity = true;
     public boolean xml = true;
     public boolean html = true;
-    public boolean htmlDetail = false;
     public boolean js = true;
     public boolean sql = true;
     public SqlOsType sqlOsType;
@@ -61,9 +60,11 @@
     private String xmlContent;
     private String htmlSearchContent;
     private String htmlDialogContent;
-    private String htmlDetailContent;
     private String jsTableContent;
     private String jsDateContent;
+    private String vueFieldMetaContent;
+    private String vueSearchRangeField;
+    private String vueSearchRangeLabel;
     private String primaryKeyColumn;
     private String primaryKeyType;
     private String majorColumn;
@@ -115,11 +116,6 @@
                     enabled = html;
                     fileDir = frontendPrefixPath + "src/main/webapp//views/" + simpleEntityName + "/";
                     fileName = simpleEntityName + ".html";
-                    break;
-                case "HtmlDetail":
-                    enabled = htmlDetail;
-                    fileDir = frontendPrefixPath + "src/main/webapp//views/" + simpleEntityName + "/";
-                    fileName = simpleEntityName + "_detail.html";
                     break;
                 case "Js":
                     enabled = js;
@@ -182,9 +178,12 @@
         xmlContent = buildXmlContent();
         htmlSearchContent = buildHtmlSearchContent();
         htmlDialogContent = buildHtmlDialogContent();
-        htmlDetailContent = buildHtmlDetailContent();
         jsTableContent = buildJsTableContent();
         jsDateContent = buildJsDateContent();
+        vueFieldMetaContent = buildVueFieldMetaContent();
+        Column rangeColumn = resolveRangeSearchColumn();
+        vueSearchRangeField = rangeColumn == null ? "" : rangeColumn.getName();
+        vueSearchRangeLabel = rangeColumn == null ? "" : GeneratorUtils.supportHtmlName(rangeColumn.getComment());
     }
 
     private void validate() {
@@ -559,39 +558,6 @@
         return trimTrailingBlankLines(builder.toString());
     }
 
-    private String buildHtmlDetailContent() {
-        StringBuilder builder = new StringBuilder();
-        for (Column column : columns) {
-            String field = column.getHumpName();
-            String label = GeneratorUtils.supportHtmlName(column.getComment());
-            if (column.isPrimaryKey()) {
-                builder.append("        <div class=\"layui-inline\" style=\"display: none\">\n");
-                builder.append("            <label class=\"layui-form-label\">").append(label).append("锛�</label>\n");
-                builder.append("            <div class=\"layui-input-inline\">\n");
-                builder.append("                <input id=\"").append(field).append("\" class=\"layui-input\" type=\"text\" placeholder=\"")
-                        .append(column.getComment()).append("\">\n");
-                builder.append("            </div>\n");
-                builder.append("        </div>\n");
-                continue;
-            }
-            builder.append("        <div class=\"layui-inline\">\n");
-            builder.append("            <label class=\"layui-form-label\">");
-            if (column.isNotNull()) {
-                builder.append("<span class=\"not-null\">*</span>");
-            }
-            builder.append(label).append("锛�</label>\n");
-            builder.append("            <div class=\"layui-input-inline");
-            if (!Cools.isEmpty(column.getForeignKeyMajor())) {
-                builder.append(" cool-auto-complete");
-            }
-            builder.append("\">\n");
-            appendDetailFormField(builder, column, "                ");
-            builder.append("            </div>\n");
-            builder.append("        </div>\n");
-        }
-        return trimTrailingBlankLines(builder.toString());
-    }
-
     private String buildJsTableContent() {
         StringBuilder builder = new StringBuilder();
         for (Column column : columns) {
@@ -631,6 +597,140 @@
             builder.append("            });\n");
         }
         return trimTrailingBlankLines(builder.toString());
+    }
+
+    private String buildVueFieldMetaContent() {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < columns.size(); i++) {
+            Column column = columns.get(i);
+            builder.append("    {\n");
+            builder.append("        field: '").append(column.getHumpName()).append("',\n");
+            builder.append("        columnName: '").append(column.getName()).append("',\n");
+            builder.append("        label: '").append(escapeJs(GeneratorUtils.supportHtmlName(column.getComment()))).append("',\n");
+            builder.append("        tableProp: '").append(resolveDisplayField(column)).append("',\n");
+            builder.append("        exportField: '").append(resolveDisplayField(column)).append("',\n");
+            builder.append("        kind: '").append(resolveVueFieldKind(column)).append("',\n");
+            builder.append("        valueType: '").append(resolveVueValueType(column)).append("',\n");
+            builder.append("        required: ").append(column.isNotNull()).append(",\n");
+            builder.append("        primaryKey: ").append(column.isPrimaryKey()).append(",\n");
+            builder.append("        sortable: ").append(column.isPrimaryKey()).append(",\n");
+            builder.append("        textarea: ").append(isLongTextField(column)).append(",\n");
+            builder.append("        minWidth: ").append(resolveVueMinWidth(column)).append(",\n");
+            builder.append("        enumOptions: ").append(buildVueEnumOptions(column)).append(",\n");
+            builder.append("        foreignQuery: '")
+                    .append(Cools.isEmpty(column.getForeignKey()) ? "" : escapeJs(GeneratorUtils.firstCharConvert(column.getForeignKey())))
+                    .append("',\n");
+            builder.append("        checkboxActiveRaw: '").append(resolveCheckboxActiveRaw(column)).append("',\n");
+            builder.append("        checkboxInactiveRaw: '").append(resolveCheckboxInactiveRaw(column)).append("'\n");
+            builder.append("    }");
+            if (i < columns.size() - 1) {
+                builder.append(",");
+            }
+            builder.append("\n");
+        }
+        return trimTrailingBlankLines(builder.toString());
+    }
+
+    private String resolveVueFieldKind(Column column) {
+        if (column.isImage()) {
+            return "image";
+        }
+        if (column.isCheckBox()) {
+            return "checkbox";
+        }
+        if ("Date".equals(column.getType())) {
+            return "date";
+        }
+        if (!Cools.isEmpty(column.getEnums())) {
+            return "enum";
+        }
+        if (!Cools.isEmpty(column.getForeignKeyMajor())) {
+            return "foreign";
+        }
+        return "text";
+    }
+
+    private String resolveVueValueType(Column column) {
+        return isNumericType(column.getType()) ? "number" : "string";
+    }
+
+    private boolean isNumericType(String type) {
+        return "Integer".equals(type)
+                || "Long".equals(type)
+                || "Double".equals(type)
+                || "Float".equals(type)
+                || "Short".equals(type)
+                || "BigDecimal".equals(type)
+                || "Byte".equals(type);
+    }
+
+    private String buildVueEnumOptions(Column column) {
+        if (Cools.isEmpty(column.getEnums())) {
+            return "[]";
+        }
+        StringBuilder builder = new StringBuilder("[");
+        boolean first = true;
+        for (Map<String, Object> map : column.getEnums()) {
+            for (Map.Entry<String, Object> entry : map.entrySet()) {
+                if (!first) {
+                    builder.append(", ");
+                }
+                builder.append("{ rawValue: '").append(escapeJs(String.valueOf(entry.getKey())))
+                        .append("', label: '").append(escapeJs(String.valueOf(entry.getValue()))).append("' }");
+                first = false;
+            }
+        }
+        builder.append("]");
+        return builder.toString();
+    }
+
+    private boolean isLongTextField(Column column) {
+        if (column.isImage()) {
+            return false;
+        }
+        if (column.getLength() != null && column.getLength() >= 120) {
+            return true;
+        }
+        String name = column.getName() == null ? "" : column.getName().toLowerCase();
+        String comment = column.getComment() == null ? "" : column.getComment();
+        return name.contains("memo")
+                || name.contains("remark")
+                || name.contains("response")
+                || name.contains("request")
+                || name.contains("content")
+                || comment.contains("澶囨敞")
+                || comment.contains("鍝嶅簲")
+                || comment.contains("鎶ユ枃")
+                || comment.contains("鎻忚堪")
+                || comment.contains("鍐呭");
+    }
+
+    private int resolveVueMinWidth(Column column) {
+        if (column.isPrimaryKey()) {
+            return 90;
+        }
+        if ("Date".equals(column.getType())) {
+            return 168;
+        }
+        if (column.isImage()) {
+            return 140;
+        }
+        if (isLongTextField(column)) {
+            return 180;
+        }
+        if (!Cools.isEmpty(column.getEnums()) || column.isCheckBox()) {
+            return 120;
+        }
+        int base = GeneratorUtils.supportHtmlName(column.getComment()).length() * 18 + 26;
+        return Math.max(110, Math.min(base, 180));
+    }
+
+    private String resolveCheckboxActiveRaw(Column column) {
+        return isNumericType(column.getType()) ? "1" : "Y";
+    }
+
+    private String resolveCheckboxInactiveRaw(Column column) {
+        return isNumericType(column.getType()) ? "0" : "N";
     }
 
     private String resolveDisplayField(Column column) {
@@ -716,51 +816,6 @@
         builder.append(inputIndent).append("</select>\n");
     }
 
-    private void appendDetailFormField(StringBuilder builder, Column column, String inputIndent) {
-        String field = column.getHumpName();
-        if (Cools.isEmpty(column.getEnums())) {
-            if (!Cools.isEmpty(column.getForeignKeyMajor())) {
-                String queryKey = GeneratorUtils.firstCharConvert(column.getForeignKey()) + "QueryBy" + field;
-                builder.append(inputIndent).append("<input id=\"").append(field)
-                        .append("\" class=\"layui-input\" type=\"text\" style=\"display: none\">\n");
-                builder.append(inputIndent).append("<input id=\"").append(field).append("$\" class=\"layui-input cool-auto-complete-div\" onclick=\"autoShow(this.id)\" type=\"text\" placeholder=\"璇疯緭鍏�")
-                        .append(column.getComment()).append("\" onfocus=this.blur() autocomplete=\"off\">\n");
-                builder.append(inputIndent).append("<div class=\"cool-auto-complete-window\">\n");
-                builder.append(inputIndent).append("    <input class=\"cool-auto-complete-window-input\" data-key=\"")
-                        .append(queryKey).append("\" onkeyup=\"autoLoad(this.getAttribute('data-key'))\">\n");
-                builder.append(inputIndent).append("    <select class=\"cool-auto-complete-window-select\" data-key=\"")
-                        .append(queryKey).append("Select\" onchange=\"confirmed(this.getAttribute('data-key'))\" multiple=\"multiple\">\n");
-                builder.append(inputIndent).append("    </select>\n");
-                builder.append(inputIndent).append("</div>\n");
-                return;
-            }
-            builder.append(inputIndent).append("<input id=\"").append(field);
-            if ("Date".equals(column.getType())) {
-                builder.append("$");
-            }
-            builder.append("\" class=\"layui-input\" type=\"text\" placeholder=\"").append(column.getComment())
-                    .append("\" autocomplete=\"off\"");
-            if (column.isNotNull()) {
-                builder.append(" lay-verify=\"required\"");
-            }
-            builder.append(">\n");
-            return;
-        }
-        builder.append(inputIndent).append("<select id=\"").append(field).append("\"");
-        if (column.isNotNull()) {
-            builder.append(" lay-verify=\"required\"");
-        }
-        builder.append(">\n");
-        builder.append(inputIndent).append("    <option value=\"\">璇烽�夋嫨").append(column.getComment()).append("</option>\n");
-        for (Map<String, Object> map : column.getEnums()) {
-            for (Map.Entry<String, Object> entry : map.entrySet()) {
-                builder.append(inputIndent).append("    <option value=\"").append(entry.getKey()).append("\">")
-                        .append(entry.getValue()).append("</option>\n");
-            }
-        }
-        builder.append(inputIndent).append("</select>\n");
-    }
-
     private String renderTemplate(String template) {
         Map<String, String> values = new LinkedHashMap<>();
         values.put("COMPANYNAME", packagePath);
@@ -773,9 +828,11 @@
         values.put("XMLCONTENT", xmlContent);
         values.put("HTMLSEARCHCONTENT", htmlSearchContent);
         values.put("HTMLDIALOGCONTENT", htmlDialogContent);
-        values.put("HTMLDETAILCONTENT", htmlDetailContent);
         values.put("JSTABLECONTENT", jsTableContent);
         values.put("JSDATECONTENT", jsDateContent);
+        values.put("VUEFIELDMETA", vueFieldMetaContent);
+        values.put("VUESEARCHRANGEFIELD", vueSearchRangeField);
+        values.put("VUESEARCHRANGELABEL", vueSearchRangeLabel);
         values.put("PRIMARYKEYCOLUMN", GeneratorUtils.firstCharConvert(primaryKeyColumn, false));
         values.put("PRIMARYKEYCOLUMN0", primaryKeyColumn);
         values.put("PRIMARYKEYTYPE", primaryKeyType);
diff --git a/src/main/java/com/zy/asrs/controller/ApiLogController.java b/src/main/java/com/zy/asrs/controller/ApiLogController.java
index 837ff43..43a65a4 100644
--- a/src/main/java/com/zy/asrs/controller/ApiLogController.java
+++ b/src/main/java/com/zy/asrs/controller/ApiLogController.java
@@ -53,12 +53,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasCrnpController.java b/src/main/java/com/zy/asrs/controller/BasCrnpController.java
index 6e96010..477452a 100644
--- a/src/main/java/com/zy/asrs/controller/BasCrnpController.java
+++ b/src/main/java/com/zy/asrs/controller/BasCrnpController.java
@@ -49,12 +49,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasCrnpErrController.java b/src/main/java/com/zy/asrs/controller/BasCrnpErrController.java
index 583eb18..998a7ec 100644
--- a/src/main/java/com/zy/asrs/controller/BasCrnpErrController.java
+++ b/src/main/java/com/zy/asrs/controller/BasCrnpErrController.java
@@ -49,12 +49,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasCrnpErrLogController.java b/src/main/java/com/zy/asrs/controller/BasCrnpErrLogController.java
index 895059b..ed3186c 100644
--- a/src/main/java/com/zy/asrs/controller/BasCrnpErrLogController.java
+++ b/src/main/java/com/zy/asrs/controller/BasCrnpErrLogController.java
@@ -49,12 +49,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasCrnpOptController.java b/src/main/java/com/zy/asrs/controller/BasCrnpOptController.java
index 72ffa87..8e41208 100644
--- a/src/main/java/com/zy/asrs/controller/BasCrnpOptController.java
+++ b/src/main/java/com/zy/asrs/controller/BasCrnpOptController.java
@@ -50,12 +50,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasDevpController.java b/src/main/java/com/zy/asrs/controller/BasDevpController.java
index 6ddbc6d..709a6ee 100644
--- a/src/main/java/com/zy/asrs/controller/BasDevpController.java
+++ b/src/main/java/com/zy/asrs/controller/BasDevpController.java
@@ -52,12 +52,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasDualCrnpController.java b/src/main/java/com/zy/asrs/controller/BasDualCrnpController.java
index c21a25c..00b2ecb 100644
--- a/src/main/java/com/zy/asrs/controller/BasDualCrnpController.java
+++ b/src/main/java/com/zy/asrs/controller/BasDualCrnpController.java
@@ -48,12 +48,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasDualCrnpErrController.java b/src/main/java/com/zy/asrs/controller/BasDualCrnpErrController.java
index f901732..5d455df 100644
--- a/src/main/java/com/zy/asrs/controller/BasDualCrnpErrController.java
+++ b/src/main/java/com/zy/asrs/controller/BasDualCrnpErrController.java
@@ -49,12 +49,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasDualCrnpErrLogController.java b/src/main/java/com/zy/asrs/controller/BasDualCrnpErrLogController.java
index 72c0e98..6d18ebc 100644
--- a/src/main/java/com/zy/asrs/controller/BasDualCrnpErrLogController.java
+++ b/src/main/java/com/zy/asrs/controller/BasDualCrnpErrLogController.java
@@ -49,12 +49,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasDualCrnpOptController.java b/src/main/java/com/zy/asrs/controller/BasDualCrnpOptController.java
index 3ac3060..a4c7dc7 100644
--- a/src/main/java/com/zy/asrs/controller/BasDualCrnpOptController.java
+++ b/src/main/java/com/zy/asrs/controller/BasDualCrnpOptController.java
@@ -50,12 +50,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasLocStsController.java b/src/main/java/com/zy/asrs/controller/BasLocStsController.java
index e1ced37..e9d3eb1 100644
--- a/src/main/java/com/zy/asrs/controller/BasLocStsController.java
+++ b/src/main/java/com/zy/asrs/controller/BasLocStsController.java
@@ -47,12 +47,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasMapController.java b/src/main/java/com/zy/asrs/controller/BasMapController.java
index 4b81688..1d8b4b2 100644
--- a/src/main/java/com/zy/asrs/controller/BasMapController.java
+++ b/src/main/java/com/zy/asrs/controller/BasMapController.java
@@ -74,12 +74,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasRgvController.java b/src/main/java/com/zy/asrs/controller/BasRgvController.java
index aeb1d71..ece7f7e 100644
--- a/src/main/java/com/zy/asrs/controller/BasRgvController.java
+++ b/src/main/java/com/zy/asrs/controller/BasRgvController.java
@@ -49,12 +49,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasRgvErrController.java b/src/main/java/com/zy/asrs/controller/BasRgvErrController.java
index 2b53deb..06f647e 100644
--- a/src/main/java/com/zy/asrs/controller/BasRgvErrController.java
+++ b/src/main/java/com/zy/asrs/controller/BasRgvErrController.java
@@ -49,12 +49,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasRgvErrLogController.java b/src/main/java/com/zy/asrs/controller/BasRgvErrLogController.java
index 16a4629..3641663 100644
--- a/src/main/java/com/zy/asrs/controller/BasRgvErrLogController.java
+++ b/src/main/java/com/zy/asrs/controller/BasRgvErrLogController.java
@@ -49,12 +49,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasRgvOptController.java b/src/main/java/com/zy/asrs/controller/BasRgvOptController.java
index 386c2d7..6fdc3d7 100644
--- a/src/main/java/com/zy/asrs/controller/BasRgvOptController.java
+++ b/src/main/java/com/zy/asrs/controller/BasRgvOptController.java
@@ -50,12 +50,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasStationController.java b/src/main/java/com/zy/asrs/controller/BasStationController.java
index 855a2d7..cd62d56 100644
--- a/src/main/java/com/zy/asrs/controller/BasStationController.java
+++ b/src/main/java/com/zy/asrs/controller/BasStationController.java
@@ -49,12 +49,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasStationOptController.java b/src/main/java/com/zy/asrs/controller/BasStationOptController.java
index 00a5909..2f0a728 100644
--- a/src/main/java/com/zy/asrs/controller/BasStationOptController.java
+++ b/src/main/java/com/zy/asrs/controller/BasStationOptController.java
@@ -50,12 +50,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasWrkIotypeController.java b/src/main/java/com/zy/asrs/controller/BasWrkIotypeController.java
index 8a35a55..cf25284 100644
--- a/src/main/java/com/zy/asrs/controller/BasWrkIotypeController.java
+++ b/src/main/java/com/zy/asrs/controller/BasWrkIotypeController.java
@@ -47,12 +47,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/BasWrkStatusController.java b/src/main/java/com/zy/asrs/controller/BasWrkStatusController.java
index 58cae40..7aff1f9 100644
--- a/src/main/java/com/zy/asrs/controller/BasWrkStatusController.java
+++ b/src/main/java/com/zy/asrs/controller/BasWrkStatusController.java
@@ -47,12 +47,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/DeviceConfigController.java b/src/main/java/com/zy/asrs/controller/DeviceConfigController.java
index 2892e5b..debd5a4 100644
--- a/src/main/java/com/zy/asrs/controller/DeviceConfigController.java
+++ b/src/main/java/com/zy/asrs/controller/DeviceConfigController.java
@@ -48,12 +48,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/HttpRequestLogController.java b/src/main/java/com/zy/asrs/controller/HttpRequestLogController.java
index f96a9b0..0163ac6 100644
--- a/src/main/java/com/zy/asrs/controller/HttpRequestLogController.java
+++ b/src/main/java/com/zy/asrs/controller/HttpRequestLogController.java
@@ -50,12 +50,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/LocMastController.java b/src/main/java/com/zy/asrs/controller/LocMastController.java
index 4929264..0cd5cd0 100644
--- a/src/main/java/com/zy/asrs/controller/LocMastController.java
+++ b/src/main/java/com/zy/asrs/controller/LocMastController.java
@@ -62,15 +62,16 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                if (entry.getKey().equals("loc_no") || entry.getKey().equals("row1") ||  entry.getKey().equals("bay1") || entry.getKey().equals("lev1")) {
-                    wrapper.eq(entry.getKey(), val);
+                if ("loc_no".equals(column) || "row1".equals(column) || "bay1".equals(column) || "lev1".equals(column)) {
+                    wrapper.eq(column, val);
                 }else {
-                    wrapper.like(entry.getKey(), val);
+                    wrapper.like(column, val);
                 }
             }
         }
diff --git a/src/main/java/com/zy/asrs/controller/WrkLastnoController.java b/src/main/java/com/zy/asrs/controller/WrkLastnoController.java
index f6a8d15..ebfe324 100644
--- a/src/main/java/com/zy/asrs/controller/WrkLastnoController.java
+++ b/src/main/java/com/zy/asrs/controller/WrkLastnoController.java
@@ -47,12 +47,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/WrkMastController.java b/src/main/java/com/zy/asrs/controller/WrkMastController.java
index 7bb2d16..1ba2be4 100644
--- a/src/main/java/com/zy/asrs/controller/WrkMastController.java
+++ b/src/main/java/com/zy/asrs/controller/WrkMastController.java
@@ -50,12 +50,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/java/com/zy/asrs/controller/WrkMastLogController.java b/src/main/java/com/zy/asrs/controller/WrkMastLogController.java
index f0238c8..5d89021 100644
--- a/src/main/java/com/zy/asrs/controller/WrkMastLogController.java
+++ b/src/main/java/com/zy/asrs/controller/WrkMastLogController.java
@@ -59,15 +59,16 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                if (entry.getKey().equals("manu_type")) {
-                    wrapper.like(entry.getKey(), val);
+                if ("manu_type".equals(column)) {
+                    wrapper.like(column, val);
                 } else {
-                    wrapper.eq(entry.getKey(), val);
+                    wrapper.eq(column, val);
                 }
             }
         }
diff --git a/src/main/java/com/zy/common/CodeBuilder.java b/src/main/java/com/zy/common/CodeBuilder.java
index b670cfa..01fba80 100644
--- a/src/main/java/com/zy/common/CodeBuilder.java
+++ b/src/main/java/com/zy/common/CodeBuilder.java
@@ -27,7 +27,6 @@
         generator.controller = true;
         generator.html = true;
         generator.js = true;
-        generator.htmlDetail = true;
         generator.sql = true;
         generator.build();
     }
diff --git a/src/main/java/com/zy/common/web/BaseController.java b/src/main/java/com/zy/common/web/BaseController.java
index 46c2845..6a18a1f 100644
--- a/src/main/java/com/zy/common/web/BaseController.java
+++ b/src/main/java/com/zy/common/web/BaseController.java
@@ -76,7 +76,7 @@
             if (Cools.isEmpty(column)) {
                 column = field.getName();
             }
-            if (!set.contains(column)) {
+            if (!set.contains(column) && !set.contains(field.getName())) {
                 columns.add(column);
             }
         }
diff --git a/src/main/resources/templates/Controller.txt b/src/main/resources/templates/Controller.txt
index abf4d8f..6c94c39 100644
--- a/src/main/resources/templates/Controller.txt
+++ b/src/main/resources/templates/Controller.txt
@@ -50,12 +50,13 @@
     private <T> void convert(Map<String, Object> map, QueryWrapper<T> wrapper){
         for (Map.Entry<String, Object> entry : map.entrySet()){
             String val = String.valueOf(entry.getValue());
+            String column = humpToLine(entry.getKey());
             if (val.contains(RANGE_TIME_LINK)){
                 String[] dates = val.split(RANGE_TIME_LINK);
-                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
-                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
+                wrapper.ge(column, DateUtils.convert(dates[0]));
+                wrapper.le(column, DateUtils.convert(dates[1]));
             } else {
-                wrapper.like(entry.getKey(), val);
+                wrapper.like(column, val);
             }
         }
     }
diff --git a/src/main/resources/templates/Html.txt b/src/main/resources/templates/Html.txt
index e804af2..4f8e5de 100644
--- a/src/main/resources/templates/Html.txt
+++ b/src/main/resources/templates/Html.txt
@@ -1,70 +1,669 @@
 <!DOCTYPE html>
-<html lang="en">
+<html lang="zh-CN">
 <head>
     <meta charset="utf-8">
-    <title></title>
+    <title>@{ENTITYNAME} 绠$悊</title>
     <meta name="renderer" content="webkit">
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
-    <link rel="stylesheet" href="../../static/layui/css/layui.css" media="all">
-    <link rel="stylesheet" href="../../static/css/admin.css?v=318" media="all">
-    <link rel="stylesheet" href="../../static/css/cool.css" media="all">
+    <link rel="stylesheet" href="../../static/vue/element/element.css">
+    <link rel="stylesheet" href="../../static/css/cool.css">
+    <style>
+        :root {
+            --card-bg: rgba(255, 255, 255, 0.94);
+            --card-border: rgba(216, 226, 238, 0.95);
+            --text-main: #243447;
+        }
+
+        [v-cloak] {
+            display: none;
+        }
+
+        html,
+        body {
+            margin: 0;
+            min-height: 100%;
+            color: var(--text-main);
+            font-family: "Avenir Next", "PingFang SC", "Microsoft YaHei", sans-serif;
+            background:
+                radial-gradient(1000px 420px at 0% -10%, rgba(44, 107, 193, 0.12), transparent 56%),
+                radial-gradient(900px 400px at 100% 0%, rgba(28, 150, 126, 0.10), transparent 58%),
+                linear-gradient(180deg, #f2f6fb 0%, #f8fafc 100%);
+        }
+
+        .page-shell {
+            max-width: 1700px;
+            margin: 0 auto;
+            padding: 14px;
+            box-sizing: border-box;
+        }
+
+        .card-shell {
+            position: relative;
+            border-radius: 24px;
+            border: 1px solid var(--card-border);
+            background:
+                radial-gradient(760px 220px at -8% 0%, rgba(43, 117, 196, 0.05), transparent 55%),
+                radial-gradient(680px 200px at 108% 10%, rgba(24, 150, 129, 0.05), transparent 58%),
+                var(--card-bg);
+            box-shadow: 0 16px 32px rgba(44, 67, 96, 0.08);
+            overflow: hidden;
+        }
+
+        .card-body {
+            position: relative;
+            z-index: 1;
+        }
+
+        .list-toolbar {
+            padding: 12px 16px 10px;
+            border-bottom: 1px solid rgba(222, 230, 239, 0.92);
+        }
+
+        .toolbar-main {
+            display: flex;
+            align-items: flex-start;
+            justify-content: space-between;
+            gap: 8px;
+            flex-wrap: wrap;
+        }
+
+        .toolbar-left {
+            flex: 1 1 960px;
+            display: flex;
+            align-items: center;
+            gap: 8px;
+            flex-wrap: wrap;
+        }
+
+        .toolbar-search {
+            flex: 1 1 auto;
+            display: flex;
+            align-items: center;
+            gap: 8px;
+            flex-wrap: wrap;
+        }
+
+        .toolbar-search-item {
+            flex: 0 0 152px;
+            min-width: 152px;
+        }
+
+        .toolbar-search-item.keyword {
+            flex: 0 0 220px;
+            min-width: 220px;
+        }
+
+        .toolbar-query-actions,
+        .toolbar-ops {
+            display: flex;
+            gap: 8px;
+            flex-wrap: wrap;
+        }
+
+        .toolbar-ops {
+            justify-content: flex-end;
+        }
+
+        .list-toolbar .el-input__inner,
+        .list-toolbar .el-range-editor.el-input__inner,
+        .advanced-panel .el-input__inner,
+        .advanced-panel .el-range-editor.el-input__inner {
+            height: 32px;
+            line-height: 32px;
+        }
+
+        .list-toolbar .el-range-editor.el-input__inner,
+        .advanced-panel .el-range-editor.el-input__inner {
+            align-items: center;
+        }
+
+        .list-toolbar .el-input__icon,
+        .advanced-panel .el-input__icon {
+            line-height: 32px;
+        }
+
+        .list-toolbar .el-range-editor .el-range__icon,
+        .list-toolbar .el-range-editor .el-range-separator,
+        .list-toolbar .el-range-editor .el-range__close-icon,
+        .advanced-panel .el-range-editor .el-range__icon,
+        .advanced-panel .el-range-editor .el-range-separator,
+        .advanced-panel .el-range-editor .el-range__close-icon {
+            display: inline-flex;
+            align-items: center;
+            justify-content: center;
+            height: 100%;
+            line-height: 1;
+        }
+
+        .list-toolbar .el-button,
+        .advanced-panel .el-button {
+            padding: 8px 12px;
+            border-radius: 8px;
+        }
+
+        .advanced-panel {
+            padding: 10px 16px 12px;
+            border-bottom: 1px solid rgba(222, 230, 239, 0.92);
+            background: rgba(248, 251, 254, 0.78);
+        }
+
+        .advanced-grid {
+            display: grid;
+            grid-template-columns: repeat(6, minmax(0, 1fr));
+            gap: 8px;
+        }
+
+        .advanced-item {
+            min-width: 0;
+        }
+
+        .advanced-item.span-2 {
+            grid-column: span 2;
+        }
+
+        .table-wrap {
+            padding: 10px 16px;
+        }
+
+        .table-shell {
+            border-radius: 20px;
+            overflow: hidden;
+            border: 1px solid rgba(217, 227, 238, 0.98);
+            background: rgba(255, 255, 255, 0.95);
+        }
+
+        .table-shell .el-table {
+            border-radius: 20px;
+            overflow: hidden;
+        }
+
+        .table-shell .el-table th {
+            background: #f7fafc;
+            color: #53677d;
+            font-weight: 700;
+        }
+
+        .payload-cell {
+            display: inline-block;
+            max-width: 280px;
+            white-space: nowrap;
+            overflow: hidden;
+            text-overflow: ellipsis;
+        }
+
+        .mono {
+            font-family: Menlo, Monaco, Consolas, "Liberation Mono", monospace;
+        }
+
+        .pager-bar {
+            padding: 0 16px 16px;
+            display: flex;
+            align-items: center;
+            justify-content: flex-end;
+        }
+
+        .column-popover {
+            max-width: 320px;
+        }
+
+        .column-popover-head {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            gap: 12px;
+            margin-bottom: 10px;
+            font-size: 13px;
+            font-weight: 700;
+            color: var(--text-main);
+        }
+
+        .column-list {
+            display: grid;
+            grid-template-columns: repeat(2, minmax(0, 1fr));
+            gap: 8px 10px;
+            max-height: 280px;
+            overflow: auto;
+            padding-right: 4px;
+        }
+
+        .dialog-panel .el-dialog {
+            border-radius: 24px;
+            overflow: hidden;
+        }
+
+        .dialog-panel .el-dialog__header {
+            padding: 22px 24px 12px;
+            background: linear-gradient(180deg, #f8fbff 0%, #f3f7fb 100%);
+            border-bottom: 1px solid rgba(224, 232, 241, 0.92);
+        }
+
+        .dialog-panel .el-dialog__title {
+            font-weight: 700;
+            color: var(--text-main);
+        }
+
+        .dialog-panel .el-dialog__body {
+            padding: 18px 24px 8px;
+        }
+
+        .dialog-footer {
+            display: flex;
+            justify-content: flex-end;
+            gap: 10px;
+        }
+
+        @media (max-width: 1520px) {
+            .advanced-grid {
+                grid-template-columns: repeat(5, minmax(0, 1fr));
+            }
+        }
+
+        @media (max-width: 1280px) {
+            .advanced-grid {
+                grid-template-columns: repeat(4, minmax(0, 1fr));
+            }
+        }
+
+        @media (max-width: 960px) {
+            .toolbar-left {
+                flex-basis: 100%;
+            }
+
+            .advanced-grid {
+                grid-template-columns: repeat(3, minmax(0, 1fr));
+            }
+
+            .advanced-item.span-2 {
+                grid-column: span 2;
+            }
+        }
+
+        @media (max-width: 720px) {
+            .page-shell {
+                padding: 12px;
+            }
+
+            .toolbar-search-item,
+            .toolbar-search-item.keyword {
+                min-width: 100%;
+                flex-basis: 100%;
+            }
+
+            .toolbar-query-actions,
+            .toolbar-ops {
+                width: 100%;
+            }
+
+            .advanced-grid {
+                grid-template-columns: repeat(2, minmax(0, 1fr));
+            }
+
+            .advanced-item.span-2 {
+                grid-column: span 2;
+            }
+        }
+
+        @media (max-width: 560px) {
+            .advanced-grid {
+                grid-template-columns: 1fr;
+            }
+
+            .advanced-item.span-2 {
+                grid-column: auto;
+            }
+
+            .list-toolbar,
+            .advanced-panel,
+            .table-wrap,
+            .pager-bar {
+                padding-left: 14px;
+                padding-right: 14px;
+            }
+
+            .column-list {
+                grid-template-columns: 1fr;
+            }
+        }
+    </style>
 </head>
 <body>
-
-<div class="layui-fluid">
-    <div class="layui-card">
-        <div class="layui-card-body">
-            <div class="layui-form toolbar" id="search-box">
-                <div class="layui-form-item">
-@{HTMLSEARCHCONTENT}
-                    <div class="layui-inline">&emsp;
-                        <button class="layui-btn icon-btn" lay-filter="search" lay-submit>
-                            <i class="layui-icon">&#xe615;</i>鎼滅储
-                        </button>
-                        <button class="layui-btn icon-btn" lay-filter="reset" lay-submit>
-                            <i class="layui-icon">&#xe666;</i>閲嶇疆
-                        </button>
+<div id="app" class="page-shell" v-cloak>
+    <section class="card-shell list-card">
+        <div class="card-body">
+            <div class="list-toolbar">
+                <div class="toolbar-main">
+                    <div class="toolbar-left">
+                        <div class="toolbar-search">
+                            <div class="toolbar-search-item keyword">
+                                <el-input
+                                    v-model.trim="searchForm.condition"
+                                    size="small"
+                                    clearable
+                                    placeholder="璇疯緭鍏�"
+                                    @keyup.enter.native="handleSearch">
+                                </el-input>
+                            </div>
+                            <div
+                                v-for="field in quickSearchableFields"
+                                :key="'quick-' + field.field"
+                                class="toolbar-search-item">
+                                <el-select
+                                    v-if="field.kind === 'enum'"
+                                    v-model="searchForm[field.field]"
+                                    size="small"
+                                    clearable
+                                    :placeholder="field.label"
+                                    style="width: 100%;">
+                                    <el-option
+                                        v-for="option in field.enumOptions"
+                                        :key="'quick-' + field.field + '-' + option.rawValue"
+                                        :label="option.label"
+                                        :value="normalizeOptionValue(field, option.rawValue)">
+                                    </el-option>
+                                </el-select>
+                                <el-autocomplete
+                                    v-else-if="field.kind === 'foreign'"
+                                    v-model="searchDisplay[field.field]"
+                                    size="small"
+                                    :fetch-suggestions="getSuggestionFetcher(field)"
+                                    :placeholder="field.label"
+                                    style="width: 100%;"
+                                    @select="handleSearchForeignSelect(field, $event)"
+                                    @input="handleSearchForeignInput(field)">
+                                    <template slot-scope="{ item }">
+                                        <div class="mono">{{ item.value }}</div>
+                                        <div style="font-size:12px;color:#8a98ac;">ID: {{ item.id }}</div>
+                                    </template>
+                                </el-autocomplete>
+                                <el-select
+                                    v-else-if="field.kind === 'checkbox'"
+                                    v-model="searchForm[field.field]"
+                                    size="small"
+                                    clearable
+                                    :placeholder="field.label"
+                                    style="width: 100%;">
+                                    <el-option label="鏄�" :value="normalizeOptionValue(field, field.checkboxActiveRaw)"></el-option>
+                                    <el-option label="鍚�" :value="normalizeOptionValue(field, field.checkboxInactiveRaw)"></el-option>
+                                </el-select>
+                                <el-input
+                                    v-else
+                                    v-model.trim="searchForm[field.field]"
+                                    size="small"
+                                    clearable
+                                    :placeholder="field.label"
+                                    @keyup.enter.native="handleSearch">
+                                </el-input>
+                            </div>
+                        </div>
+                        <div class="toolbar-query-actions">
+                            <el-button size="small" type="primary" icon="el-icon-search" @click="handleSearch">鎼滅储</el-button>
+                            <el-button size="small" icon="el-icon-refresh-left" @click="handleReset">閲嶇疆</el-button>
+                            <el-button
+                                v-if="hasAdvancedFilters"
+                                size="small"
+                                plain
+                                :icon="advancedFiltersVisible ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"
+                                @click="toggleAdvancedFilters">
+                                {{ advancedFiltersVisible ? '鏀惰捣' : '绛涢��' }}
+                            </el-button>
+                        </div>
+                    </div>
+                    <div class="toolbar-ops">
+                        <el-button size="small" type="primary" plain icon="el-icon-plus" @click="openCreateDialog">鏂板</el-button>
+                        <el-button size="small" type="danger" plain icon="el-icon-delete" :disabled="selection.length === 0" @click="removeSelection">鍒犻櫎</el-button>
+                        <el-popover
+                            placement="bottom"
+                            width="320"
+                            trigger="click"
+                            popper-class="column-popover">
+                            <div class="column-popover-head">
+                                <span>鍒楄缃�</span>
+                                <div>
+                                    <el-button type="text" @click="selectAllColumns">鍏ㄩ��</el-button>
+                                    <el-button type="text" @click="resetColumns">閲嶇疆</el-button>
+                                </div>
+                            </div>
+                            <div class="column-list">
+                                <el-checkbox
+                                    v-for="field in allColumns"
+                                    :key="'column-' + field.field"
+                                    :value="isColumnVisible(field.field)"
+                                    @change="toggleColumn(field.field, $event)">
+                                    {{ field.label }}
+                                </el-checkbox>
+                            </div>
+                            <el-button slot="reference" size="small" plain icon="el-icon-setting">鍒楄缃�</el-button>
+                        </el-popover>
+                        <el-button size="small" plain icon="el-icon-download" :loading="exporting" @click="exportRows">瀵煎嚭</el-button>
                     </div>
                 </div>
             </div>
-            <table class="layui-hide" id="@{SIMPLEENTITYNAME}" lay-filter="@{SIMPLEENTITYNAME}"></table>
+
+            <el-collapse-transition>
+                <div v-show="advancedFiltersVisible && hasAdvancedFilters" class="advanced-panel">
+                    <div class="advanced-grid">
+                        <div
+                            v-for="field in advancedSearchableFields"
+                            :key="'advanced-' + field.field"
+                            :class="['advanced-item', field.kind === 'date' ? 'span-2' : '']">
+                            <el-date-picker
+                                v-if="field.kind === 'date'"
+                                v-model="searchForm[field.field]"
+                                size="small"
+                                type="datetimerange"
+                                unlink-panels
+                                range-separator="鑷�"
+                                :start-placeholder="field.label + '寮�濮�'"
+                                :end-placeholder="field.label + '缁撴潫'"
+                                value-format="yyyy-MM-dd HH:mm:ss"
+                                style="width: 100%;">
+                            </el-date-picker>
+                            <el-select
+                                v-else-if="field.kind === 'enum'"
+                                v-model="searchForm[field.field]"
+                                size="small"
+                                clearable
+                                :placeholder="field.label"
+                                style="width: 100%;">
+                                <el-option
+                                    v-for="option in field.enumOptions"
+                                    :key="'advanced-' + field.field + '-' + option.rawValue"
+                                    :label="option.label"
+                                    :value="normalizeOptionValue(field, option.rawValue)">
+                                </el-option>
+                            </el-select>
+                            <el-autocomplete
+                                v-else-if="field.kind === 'foreign'"
+                                v-model="searchDisplay[field.field]"
+                                size="small"
+                                :fetch-suggestions="getSuggestionFetcher(field)"
+                                :placeholder="field.label"
+                                style="width: 100%;"
+                                @select="handleSearchForeignSelect(field, $event)"
+                                @input="handleSearchForeignInput(field)">
+                                <template slot-scope="{ item }">
+                                    <div class="mono">{{ item.value }}</div>
+                                    <div style="font-size:12px;color:#8a98ac;">ID: {{ item.id }}</div>
+                                </template>
+                            </el-autocomplete>
+                            <el-select
+                                v-else-if="field.kind === 'checkbox'"
+                                v-model="searchForm[field.field]"
+                                size="small"
+                                clearable
+                                :placeholder="field.label"
+                                style="width: 100%;">
+                                <el-option label="鏄�" :value="normalizeOptionValue(field, field.checkboxActiveRaw)"></el-option>
+                                <el-option label="鍚�" :value="normalizeOptionValue(field, field.checkboxInactiveRaw)"></el-option>
+                            </el-select>
+                            <el-input
+                                v-else
+                                v-model.trim="searchForm[field.field]"
+                                size="small"
+                                clearable
+                                :placeholder="field.label"
+                                @keyup.enter.native="handleSearch">
+                            </el-input>
+                        </div>
+                    </div>
+                </div>
+            </el-collapse-transition>
+
+            <div class="table-wrap">
+                <div class="table-shell">
+                    <el-table
+                        ref="dataTable"
+                        v-loading="loading"
+                        :data="tableData"
+                        border
+                        stripe
+                        :height="tableHeight"
+                        @selection-change="handleSelectionChange"
+                        @sort-change="handleSortChange">
+                        <el-table-column type="selection" width="52" align="center"></el-table-column>
+                        <el-table-column
+                            v-for="field in visibleColumns"
+                            :key="field.field"
+                            :prop="field.field"
+                            :label="field.label"
+                            :width="field.primaryKey ? 90 : null"
+                            :min-width="field.primaryKey ? null : field.minWidth"
+                            :sortable="isSortableField(field) ? 'custom' : false"
+                            :show-overflow-tooltip="field.kind !== 'image'"
+                            align="center">
+                            <template slot-scope="scope">
+                                <el-image
+                                    v-if="field.kind === 'image' && getTableValue(scope.row, field)"
+                                    :src="getTableValue(scope.row, field)"
+                                    fit="cover"
+                                    style="width: 48px; height: 48px; border-radius: 10px;">
+                                </el-image>
+                                <el-tag v-else-if="field.kind === 'enum'" size="mini" type="success">
+                                    {{ valueOrDash(getTableValue(scope.row, field)) }}
+                                </el-tag>
+                                <el-tag v-else-if="field.kind === 'checkbox'" size="mini" :type="isCheckboxChecked(scope.row, field) ? 'success' : 'info'">
+                                    {{ isCheckboxChecked(scope.row, field) ? '鏄�' : '鍚�' }}
+                                </el-tag>
+                                <span v-else-if="field.textarea" class="payload-cell mono" :title="stringValue(getTableValue(scope.row, field))">
+                                    {{ valueOrDash(getTableValue(scope.row, field)) }}
+                                </span>
+                                <span v-else>{{ valueOrDash(getTableValue(scope.row, field)) }}</span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="鎿嶄綔" width="160" fixed="right" align="center">
+                            <template slot-scope="scope">
+                                <el-button type="text" @click="openEditDialog(scope.row)">淇敼</el-button>
+                                <el-button type="text" style="color:#f56c6c;" @click="removeRows([scope.row[primaryKeyField]])">鍒犻櫎</el-button>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                </div>
+            </div>
+
+            <div class="pager-bar">
+                <el-pagination
+                    small
+                    background
+                    layout="total, sizes, prev, pager, next, jumper"
+                    :current-page="page.curr"
+                    :page-size="page.limit"
+                    :page-sizes="[15, 30, 50, 100, 200, 500]"
+                    :total="page.total"
+                    @current-change="handleCurrentChange"
+                    @size-change="handleSizeChange">
+                </el-pagination>
+            </div>
         </div>
-    </div>
+    </section>
+
+    <el-dialog
+        class="dialog-panel"
+        :title="dialog.mode === 'create' ? '鏂板 @{ENTITYNAME}' : '淇敼 @{ENTITYNAME}'"
+        :visible.sync="dialog.visible"
+        width="760px"
+        :close-on-click-modal="false">
+        <el-form
+            ref="dialogForm"
+            :model="dialogForm"
+            :rules="dialogRules"
+            label-width="110px"
+            size="small">
+            <el-row :gutter="16">
+                <el-col
+                    v-for="field in editableFields"
+                    :key="'dialog-' + field.field"
+                    :span="field.textarea || field.kind === 'image' ? 24 : 12">
+                    <el-form-item :label="field.label" :prop="field.field">
+                        <el-date-picker
+                            v-if="field.kind === 'date'"
+                            v-model="dialogForm[field.field]"
+                            type="datetime"
+                            value-format="yyyy-MM-dd HH:mm:ss"
+                            :placeholder="'璇烽�夋嫨' + field.label"
+                            style="width: 100%;">
+                        </el-date-picker>
+                        <el-select
+                            v-else-if="field.kind === 'enum'"
+                            v-model="dialogForm[field.field]"
+                            clearable
+                            :placeholder="'璇烽�夋嫨' + field.label"
+                            style="width: 100%;">
+                            <el-option
+                                v-for="option in field.enumOptions"
+                                :key="'dialog-' + field.field + '-' + option.rawValue"
+                                :label="option.label"
+                                :value="normalizeOptionValue(field, option.rawValue)">
+                            </el-option>
+                        </el-select>
+                        <el-autocomplete
+                            v-else-if="field.kind === 'foreign'"
+                            v-model="dialogDisplay[field.field]"
+                            :fetch-suggestions="getSuggestionFetcher(field)"
+                            :placeholder="'璇疯緭鍏�' + field.label"
+                            style="width: 100%;"
+                            @select="handleForeignSelect(field, $event)"
+                            @input="handleForeignInput(field)">
+                            <template slot-scope="{ item }">
+                                <div class="mono">{{ item.value }}</div>
+                                <div style="font-size:12px;color:#8a98ac;">ID: {{ item.id }}</div>
+                            </template>
+                        </el-autocomplete>
+                        <el-switch
+                            v-else-if="field.kind === 'checkbox'"
+                            v-model="dialogForm[field.field]"
+                            :active-value="normalizeOptionValue(field, field.checkboxActiveRaw)"
+                            :inactive-value="normalizeOptionValue(field, field.checkboxInactiveRaw)"
+                            active-color="#13ce66"
+                            inactive-color="#c0c4cc">
+                        </el-switch>
+                        <el-input
+                            v-else-if="field.textarea"
+                            v-model.trim="dialogForm[field.field]"
+                            type="textarea"
+                            :rows="3"
+                            :placeholder="'璇疯緭鍏�' + field.label">
+                        </el-input>
+                        <el-input
+                            v-else
+                            v-model.trim="dialogForm[field.field]"
+                            :placeholder="'璇疯緭鍏�' + field.label">
+                        </el-input>
+                    </el-form-item>
+                </el-col>
+            </el-row>
+        </el-form>
+        <div slot="footer" class="dialog-footer">
+            <el-button @click="dialog.visible = false">鍙栨秷</el-button>
+            <el-button type="primary" :loading="dialog.submitting" @click="submitDialog">淇濆瓨</el-button>
+        </div>
+    </el-dialog>
 </div>
 
-<script type="text/html" id="toolbar">
-    <div class="layui-btn-container">
-        <button class="layui-btn layui-btn-sm" id="btn-add" lay-event="addData">鏂板</button>
-        <button class="layui-btn layui-btn-sm layui-btn-danger" id="btn-delete" lay-event="deleteData">鍒犻櫎</button>
-        <button class="layui-btn layui-btn-primary layui-btn-sm" id="btn-export" lay-event="exportData" style="float: right">瀵煎嚭</button>
-    </div>
-</script>
-
-<script type="text/html" id="operate">
-    <a class="layui-btn layui-btn-primary layui-btn-xs btn-edit" lay-event="edit">淇敼</a>
-    <a class="layui-btn layui-btn-danger layui-btn-xs btn-edit" lay-event="del">鍒犻櫎</a>
-</script>
-
 <script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
-<script type="text/javascript" src="../../static/layui/layui.js" charset="utf-8"></script>
 <script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script>
-<script type="text/javascript" src="../../static/js/cool.js" charset="utf-8"></script>
+<script type="text/javascript" src="../../static/vue/js/vue.min.js"></script>
+<script type="text/javascript" src="../../static/vue/element/element.js"></script>
 <script type="text/javascript" src="../../static/js/@{SIMPLEENTITYNAME}/@{SIMPLEENTITYNAME}.js" charset="utf-8"></script>
 </body>
-<!-- 琛ㄥ崟寮圭獥 -->
-<script type="text/html" id="editDialog">
-    <form id="detail" lay-filter="detail" class="layui-form admin-form model-form">
-        <div class="layui-row">
-            <div class="layui-col-md12">
-@{HTMLDIALOGCONTENT}
-             </div>
-        </div>
-        <hr class="layui-bg-gray">
-        <div class="layui-form-item text-right">
-            <button class="layui-btn" lay-filter="editSubmit" lay-submit="">淇濆瓨</button>
-            <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">鍙栨秷</button>
-        </div>
-    </form>
-</script>
 </html>
diff --git a/src/main/resources/templates/HtmlDetail.txt b/src/main/resources/templates/HtmlDetail.txt
deleted file mode 100644
index 8df1c33..0000000
--- a/src/main/resources/templates/HtmlDetail.txt
+++ /dev/null
@@ -1,48 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="utf-8">
-    <title></title>
-    <meta name="renderer" content="webkit">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
-    <link rel="stylesheet" href="../../static/layui/css/layui.css" media="all">
-    <link rel="stylesheet" href="../../static/css/cool.css" media="all">
-    <link rel="stylesheet" href="../../static/css/common.css" media="all">
-</head>
-<body>
-
-<!-- 璇︽儏 -->
-<div id="data-detail" class="layer_self_wrap">
-    <form id="detail" class="layui-form">
-    <!--
-        <div class="layui-inline"  style="display: none">
-            <label class="layui-form-label"><span class="not-null">*</span>缂栥��銆�鍙凤細</label>
-            <div class="layui-input-inline">
-                <input id="id" class="layui-input" type="text" placeholder="缂栧彿">
-            </div>
-        </div>
-    -->
-@{HTMLDETAILCONTENT}
-
-        <hr class="layui-bg-gray">
-
-        <div id="data-detail-btn" class="layui-btn-container layui-form-item">
-            <div id="data-detail-submit-save" type="button" class="layui-btn layui-btn-normal" lay-submit lay-filter="save">淇濆瓨</div>
-            <div id="data-detail-submit-edit" type="button" class="layui-btn layui-btn-normal" lay-submit lay-filter="edit">淇敼</div>
-            <div id="data-detail-close" type="button" class="layui-btn" lay-submit lay-filter="close">鍏抽棴</div>
-        </div>
-
-        <div id="prompt">
-            娓╅Θ鎻愮ず锛氳浠旂粏濉啓鐩稿叧淇℃伅锛�<span class="extrude"><span class="not-null">*</span> 涓哄繀濉�夐」銆�</span>
-        </div>
-    </form>
-</div>
-</body>
-<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
-<script type="text/javascript" src="../../static/layui/layui.js" charset="utf-8"></script>
-<script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script>
-<script type="text/javascript" src="../../static/js/cool.js" charset="utf-8"></script>
-<script type="text/javascript" src="../../static/js/@{SIMPLEENTITYNAME}/@{SIMPLEENTITYNAME}.js" charset="utf-8"></script>
-</html>
-
diff --git a/src/main/resources/templates/Js.txt b/src/main/resources/templates/Js.txt
index 77ec15d..ca4c8d2 100644
--- a/src/main/resources/templates/Js.txt
+++ b/src/main/resources/templates/Js.txt
@@ -1,244 +1,753 @@
-var pageCurr;
-layui.config({
-    base: baseUrl + "/static/layui/lay/modules/"
-}).use(['table','laydate', 'form', 'admin'], function(){
-    var table = layui.table;
-    var $ = layui.jquery;
-    var layer = layui.layer;
-    var layDate = layui.laydate;
-    var form = layui.form;
-    var admin = layui.admin;
+(function () {
+    var simpleEntityName = '@{SIMPLEENTITYNAME}';
+    var entityName = '@{ENTITYNAME}';
+    var primaryKeyField = '@{PRIMARYKEYCOLUMN0}';
+    var fieldMeta = [
+@{VUEFIELDMETA}
+    ];
 
-    // 鏁版嵁娓叉煋
-    tableIns = table.render({
-        elem: '#@{SIMPLEENTITYNAME}',
-        headers: {token: localStorage.getItem('token')},
-        url: baseUrl+'/@{SIMPLEENTITYNAME}/list/auth',
-        page: true,
-        limit: 15,
-        limits: [15, 30, 50, 100, 200, 500],
-        toolbar: '#toolbar',
-        cellMinWidth: 50,
-        height: 'full-120',
-        cols: [[
-            {type: 'checkbox'}
-@{JSTABLECONTENT}
-            ,{fixed: 'right', title:'鎿嶄綔', align: 'center', toolbar: '#operate', width:120}
-        ]],
-        request: {
-            pageName: 'curr',
-            pageSize: 'limit'
-        },
-        parseData: function (res) {
-            return {
-                'code': res.code,
-                'msg': res.msg,
-                'count': res.data.total,
-                'data': res.data.records
-            }
-        },
-        response: {
-            statusCode: 200
-        },
-        done: function(res, curr, count) {
-            if (res.code === 403) {
-                top.location.href = baseUrl+"/";
-            }
-            pageCurr=curr;
-            limit();
+    function isEmptyValue(value) {
+        return value === null || value === undefined || value === '';
+    }
+
+    function stringValue(value) {
+        return isEmptyValue(value) ? '' : String(value);
+    }
+
+    function valueOrDash(value) {
+        return isEmptyValue(value) ? '--' : value;
+    }
+
+    function normalizeOptionValue(field, rawValue) {
+        if (rawValue === null || rawValue === undefined) {
+            return null;
         }
-    });
+        if (rawValue === '') {
+            return '';
+        }
+        if (field && field.valueType === 'number') {
+            var numberVal = Number(rawValue);
+            return isNaN(numberVal) ? rawValue : numberVal;
+        }
+        return String(rawValue);
+    }
 
-    // 鐩戝惉鎺掑簭浜嬩欢
-    table.on('sort(@{SIMPLEENTITYNAME})', function (obj) {
-        var searchData = {};
-        $.each($('#search-box [name]').serializeArray(), function() {
-            searchData[this.name] = this.value;
+    function isSearchableField(field) {
+        return !!field && field.kind !== 'image' && !field.textarea;
+    }
+
+    function isSortableField(field) {
+        if (!field) {
+            return false;
+        }
+        if (field.primaryKey) {
+            return true;
+        }
+        return field.kind !== 'image' && !field.textarea && field.kind !== 'foreign';
+    }
+
+    function defaultFieldValue(field) {
+        if (field.primaryKey) {
+            return null;
+        }
+        if (field.kind === 'checkbox') {
+            return normalizeOptionValue(field, field.checkboxInactiveRaw);
+        }
+        return '';
+    }
+
+    function defaultSearchFieldValue(field) {
+        if (field.kind === 'date') {
+            return [];
+        }
+        if (field.kind === 'enum' || field.kind === 'checkbox') {
+            return null;
+        }
+        return '';
+    }
+
+    function createSearchDefaults() {
+        var result = {
+            condition: ''
+        };
+        fieldMeta.forEach(function (field) {
+            if (!isSearchableField(field)) {
+                return;
+            }
+            result[field.field] = defaultSearchFieldValue(field);
         });
-        searchData['orderByField'] = obj.field;
-        searchData['orderByType'] = obj.type;
-        tableIns.reload({
-            where: searchData,
-            page: {curr: 1}
-        });
-    });
+        return result;
+    }
 
-    // 鐩戝惉澶村伐鍏锋爮浜嬩欢
-    table.on('toolbar(@{SIMPLEENTITYNAME})', function (obj) {
-        var checkStatus = table.checkStatus(obj.config.id).data;
-        switch(obj.event) {
-            case 'addData':
-                showEditModel();
-                break;
-            case 'deleteData':
-               if (checkStatus.length === 0) {
-                   layer.msg('璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁', {icon: 2});
-                   return;
-               }
-               del(checkStatus.map(function (d) {
-                   return d.@{PRIMARYKEYCOLUMN0};
-               }));
-               break;
-            case 'exportData':
-                admin.confirm('纭畾瀵煎嚭Excel鍚�', {shadeClose: true}, function(){
-                    var titles=[];
-                    var fields=[];
-                    obj.config.cols[0].map(function (col) {
-                        if (col.type === 'normal' && col.hide === false && col.toolbar == null) {
-                            titles.push(col.title);
-                            fields.push(col.field);
-                        }
-                    });
-                    var exportData = {};
-                    $.each($('#search-box [name]').serializeArray(), function() {
-                        exportData[this.name] = this.value;
-                    });
-                    var param = {
-                        '@{SIMPLEENTITYNAME}': exportData,
-                        'fields': fields
-                    };
-                    $.ajax({
-                        url: baseUrl+"/@{SIMPLEENTITYNAME}/export/auth",
-                        headers: {'token': localStorage.getItem('token')},
-                        data: JSON.stringify(param),
-                        dataType:'json',
-                        contentType:'application/json;charset=UTF-8',
-                        method: 'POST',
-                        success: function (res) {
-                            layer.closeAll();
-                            if (res.code === 200) {
-                                table.exportFile(titles,res.data,'xls');
-                            } else if (res.code === 403) {
-                                top.location.href = baseUrl+"/";
-                            } else {
-                                layer.msg(res.msg, {icon: 2})
-                            }
-                        }
-                    });
-                });
-                break;
-        }
-    });
-
-    // 鐩戝惉琛屽伐鍏蜂簨浠�
-    table.on('tool(@{SIMPLEENTITYNAME})', function(obj){
-        var data = obj.data;
-        switch (obj.event) {
-            case 'edit':
-                showEditModel(data);
-                break;
-            case "del":
-                del([data.@{PRIMARYKEYCOLUMN0}]);
-                break;
-        }
-    });
-
-    /* 寮圭獥 - 鏂板銆佷慨鏀� */
-    function showEditModel(mData) {
-        admin.open({
-            type: 1,
-            area: '600px',
-            title: (mData ? '淇敼' : '娣诲姞') + '',
-            content: $('#editDialog').html(),
-            success: function (layero, dIndex) {
-                form.val('detail', mData);
-                layDateRender(mData);
-                form.on('submit(editSubmit)', function (data) {
-                    var loadIndex = layer.load(2);
-                    $.ajax({
-                        url: baseUrl+"/@{SIMPLEENTITYNAME}/"+(mData?'update':'add')+"/auth",
-                        headers: {'token': localStorage.getItem('token')},
-                        data: data.field,
-                        method: 'POST',
-                        success: function (res) {
-                            layer.close(loadIndex);
-                            if (res.code === 200){
-                                layer.close(dIndex);
-                                layer.msg(res.msg, {icon: 1});
-                                tableReload();
-                            } else if (res.code === 403){
-                                top.location.href = baseUrl+"/";
-                            }else {
-                                layer.msg(res.msg, {icon: 2});
-                            }
-                        }
-                    })
-                    return false;
-                });
-                $(layero).children('.layui-layer-content').css('overflow', 'visible');
-                layui.form.render('select');
+    function createSearchDisplayDefaults() {
+        var result = {};
+        fieldMeta.forEach(function (field) {
+            if (field.kind === 'foreign' && isSearchableField(field)) {
+                result[field.field] = '';
             }
+        });
+        return result;
+    }
+
+    function createDefaultVisibleColumnKeys() {
+        return fieldMeta.map(function (field) {
+            return field.field;
         });
     }
 
-    /* 鍒犻櫎 */
-    function del(ids) {
-        layer.confirm('纭畾瑕佸垹闄ら�変腑鏁版嵁鍚楋紵', {
-            skin: 'layui-layer-admin',
-            shade: .1
-        }, function (i) {
-            layer.close(i);
-            var loadIndex = layer.load(2);
+    function createFormDefaults() {
+        var result = {};
+        fieldMeta.forEach(function (field) {
+            result[field.field] = defaultFieldValue(field);
+        });
+        return result;
+    }
+
+    function createDisplayDefaults() {
+        var result = {};
+        fieldMeta.forEach(function (field) {
+            if (field.kind === 'foreign') {
+                result[field.field] = '';
+            }
+        });
+        return result;
+    }
+
+    function createFormRules() {
+        var rules = {};
+        fieldMeta.forEach(function (field) {
+            if (field.primaryKey || !field.required) {
+                return;
+            }
+            rules[field.field] = [{
+                required: true,
+                message: (field.kind === 'date' || field.kind === 'enum' ? '璇烽�夋嫨' : '璇疯緭鍏�') + field.label,
+                trigger: (field.kind === 'date' || field.kind === 'enum') ? 'change' : 'blur'
+            }];
+        });
+        return rules;
+    }
+
+    function getTableValue(row, field) {
+        var prop = field.tableProp || field.field;
+        if (row && !isEmptyValue(row[prop])) {
+            return row[prop];
+        }
+        return row ? row[field.field] : '';
+    }
+
+    function isCheckboxChecked(row, field) {
+        var value = row ? row[field.field] : null;
+        var activeValue = normalizeOptionValue(field, field.checkboxActiveRaw);
+        return String(value) === String(activeValue);
+    }
+
+    function exportCell(value) {
+        return stringValue(value).replace(/\t/g, ' ').replace(/\r?\n/g, ' ');
+    }
+
+    function escapeHtml(value) {
+        return exportCell(value)
+            .replace(/&/g, '&amp;')
+            .replace(/</g, '&lt;')
+            .replace(/>/g, '&gt;')
+            .replace(/"/g, '&quot;')
+            .replace(/'/g, '&#39;');
+    }
+
+    function buildPayload(form) {
+        var payload = {};
+        fieldMeta.forEach(function (field) {
+            var value = form[field.field];
+            if (field.primaryKey) {
+                if (!isEmptyValue(value)) {
+                    payload[field.field] = value;
+                }
+                return;
+            }
+            if (field.kind === 'foreign' && isEmptyValue(value)) {
+                value = null;
+            }
+            if (field.kind === 'enum' && value === '') {
+                value = null;
+            }
+            if (field.kind === 'checkbox' && isEmptyValue(value)) {
+                value = normalizeOptionValue(field, field.checkboxInactiveRaw);
+            }
+            if (field.valueType === 'number' && !isEmptyValue(value)) {
+                value = Number(value);
+            }
+            if (field.valueType === 'number' && value === '') {
+                value = null;
+            }
+            payload[field.field] = value;
+        });
+        return payload;
+    }
+
+    function fillFormFromRow(row, form, display) {
+        fieldMeta.forEach(function (field) {
+            if (field.primaryKey) {
+                form[field.field] = row[field.field];
+                return;
+            }
+            if (field.kind === 'date') {
+                form[field.field] = row[field.tableProp] || row[field.field] || '';
+                return;
+            }
+            if (field.kind === 'foreign') {
+                form[field.field] = isEmptyValue(row[field.field]) ? '' : normalizeOptionValue(field, row[field.field]);
+                if (display) {
+                    display[field.field] = row[field.tableProp] || (isEmptyValue(row[field.field]) ? '' : String(row[field.field]));
+                }
+                return;
+            }
+            if (field.kind === 'enum') {
+                form[field.field] = isEmptyValue(row[field.field]) ? '' : normalizeOptionValue(field, row[field.field]);
+                return;
+            }
+            if (field.kind === 'checkbox') {
+                form[field.field] = isEmptyValue(row[field.field])
+                    ? normalizeOptionValue(field, field.checkboxInactiveRaw)
+                    : normalizeOptionValue(field, row[field.field]);
+                return;
+            }
+            form[field.field] = isEmptyValue(row[field.field])
+                ? ''
+                : (field.valueType === 'number' ? String(row[field.field]) : row[field.field]);
+        });
+    }
+
+    function resolveSearchParam(field) {
+        if (field.kind === 'date' && field.columnName) {
+            return field.columnName;
+        }
+        return field.field;
+    }
+
+    function createDownloadFile(filename, titles, rows) {
+        var html = [
+            '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">',
+            '<head><meta charset="UTF-8"></head><body><table border="1"><thead><tr>',
+            titles.map(function (title) {
+                return '<th>' + escapeHtml(title) + '</th>';
+            }).join(''),
+            '</tr></thead><tbody>',
+            (rows || []).map(function (row) {
+                return '<tr>' + (row || []).map(function (value) {
+                    return '<td style="mso-number-format:\\@;">' + escapeHtml(value) + '</td>';
+                }).join('') + '</tr>';
+            }).join(''),
+            '</tbody></table></body></html>'
+        ].join('');
+        var blob = new Blob(['\ufeff' + html], {
+            type: 'application/vnd.ms-excel;charset=utf-8;'
+        });
+        var anchor = document.createElement('a');
+        anchor.href = URL.createObjectURL(blob);
+        anchor.download = filename;
+        document.body.appendChild(anchor);
+        anchor.click();
+        setTimeout(function () {
+            URL.revokeObjectURL(anchor.href);
+            document.body.removeChild(anchor);
+        }, 0);
+    }
+
+    function buildTimestamp() {
+        var now = new Date();
+        var pad = function (num) {
+            return num < 10 ? '0' + num : String(num);
+        };
+        return now.getFullYear()
+            + pad(now.getMonth() + 1)
+            + pad(now.getDate())
+            + '_'
+            + pad(now.getHours())
+            + pad(now.getMinutes())
+            + pad(now.getSeconds());
+    }
+
+    function authHeaders() {
+        return {
+            token: localStorage.getItem('token')
+        };
+    }
+
+    function handleForbidden(res) {
+        if (res && res.code === 403) {
+            top.location.href = baseUrl + '/';
+            return true;
+        }
+        return false;
+    }
+
+    var sharedMethods = {
+        authHeaders: authHeaders,
+        handleForbidden: handleForbidden,
+        valueOrDash: valueOrDash,
+        stringValue: stringValue,
+        getTableValue: getTableValue,
+        isCheckboxChecked: isCheckboxChecked,
+        normalizeOptionValue: normalizeOptionValue,
+        isSortableField: isSortableField,
+        getSuggestionFetcher: function (field) {
+            var self = this;
+            return function (queryString, callback) {
+                self.fetchForeignSuggestions(field, queryString, callback);
+            };
+        },
+        fetchForeignSuggestions: function (field, queryString, callback) {
+            if (!field.foreignQuery || !queryString) {
+                callback([]);
+                return;
+            }
+            var self = this;
             $.ajax({
-                url: baseUrl+"/@{SIMPLEENTITYNAME}/delete/auth",
-                headers: {'token': localStorage.getItem('token')},
-                data: {ids: ids},
-                method: 'POST',
+                url: baseUrl + '/' + field.foreignQuery + 'Query/auth',
+                method: 'GET',
+                headers: self.authHeaders(),
+                data: { condition: queryString },
                 success: function (res) {
-                    layer.close(loadIndex);
-                    if (res.code === 200){
-                        layer.msg(res.msg, {icon: 1});
-                        tableReload();
-                    } else if (res.code === 403){
-                        top.location.href = baseUrl+"/";
-                    } else {
-                        layer.msg(res.msg, {icon: 2});
+                    if (self.handleForbidden(res)) {
+                        return;
                     }
+                    if (!res || res.code !== 200 || !Array.isArray(res.data)) {
+                        callback([]);
+                        return;
+                    }
+                    callback(res.data.map(function (item) {
+                        return {
+                            id: item.id,
+                            value: item.value
+                        };
+                    }));
+                },
+                error: function () {
+                    callback([]);
+                }
+            });
+        },
+        handleForeignSelect: function (field, item) {
+            this.$set(this.displayTarget, field.field, item && item.value ? item.value : '');
+            this.$set(this.formTarget, field.field, item && item.id !== undefined ? normalizeOptionValue(field, item.id) : '');
+        },
+        handleForeignInput: function (field) {
+            if (!this.displayTarget || !this.formTarget) {
+                return;
+            }
+            if (this.displayTarget[field.field]) {
+                return;
+            }
+            this.$set(this.formTarget, field.field, '');
+        }
+    };
+
+    if (document.getElementById('app')) {
+        new Vue({
+            el: '#app',
+            data: function () {
+                return {
+                    fieldMeta: fieldMeta,
+                    primaryKeyField: primaryKeyField,
+                    loading: false,
+                    exporting: false,
+                    tableData: [],
+                    selection: [],
+                    advancedFiltersVisible: false,
+                    allColumns: fieldMeta.slice(),
+                    visibleColumnKeys: createDefaultVisibleColumnKeys(),
+                    searchForm: createSearchDefaults(),
+                    searchDisplay: createSearchDisplayDefaults(),
+                    page: {
+                        curr: 1,
+                        limit: 15,
+                        total: 0
+                    },
+                    sortState: {
+                        prop: '',
+                        order: ''
+                    },
+                    dialog: {
+                        visible: false,
+                        mode: 'create',
+                        submitting: false
+                    },
+                    layoutTimer: null,
+                    tableResizeHandler: null,
+                    dialogForm: createFormDefaults(),
+                    dialogDisplay: createDisplayDefaults(),
+                    dialogRules: createFormRules()
+                };
+            },
+            computed: {
+                searchableFields: function () {
+                    return this.fieldMeta.filter(function (field) {
+                        return isSearchableField(field);
+                    });
+                },
+                quickSearchableFields: function () {
+                    var result = [];
+                    this.searchableFields.forEach(function (field) {
+                        if (result.length >= 3 || field.kind === 'date') {
+                            return;
+                        }
+                        result.push(field);
+                    });
+                    return result;
+                },
+                advancedSearchableFields: function () {
+                    var quickKeys = this.quickSearchableFields.map(function (field) {
+                        return field.field;
+                    });
+                    return this.searchableFields.filter(function (field) {
+                        return quickKeys.indexOf(field.field) === -1;
+                    });
+                },
+                hasAdvancedFilters: function () {
+                    return this.advancedSearchableFields.length > 0;
+                },
+                visibleColumns: function () {
+                    var keys = this.visibleColumnKeys;
+                    return this.allColumns.filter(function (field) {
+                        return keys.indexOf(field.field) !== -1;
+                    });
+                },
+                editableFields: function () {
+                    return this.fieldMeta.filter(function (field) {
+                        return !field.primaryKey;
+                    });
+                },
+                exportColumns: function () {
+                    return this.visibleColumns.map(function (field) {
+                        return {
+                            field: field.exportField || field.tableProp || field.field,
+                            label: field.label
+                        };
+                    });
+                },
+                tableHeight: function () {
+                    return this.advancedFiltersVisible && this.hasAdvancedFilters
+                        ? 'calc(100vh - 390px)'
+                        : 'calc(100vh - 300px)';
+                },
+                formTarget: function () {
+                    return this.dialogForm;
+                },
+                displayTarget: function () {
+                    return this.dialogDisplay;
+                }
+            },
+            created: function () {
+                this.loadTable();
+            },
+            mounted: function () {
+                var self = this;
+                self.requestTableLayout(80);
+                self.tableResizeHandler = function () {
+                    self.requestTableLayout(80);
+                };
+                window.addEventListener('resize', self.tableResizeHandler);
+            },
+            beforeDestroy: function () {
+                if (this.layoutTimer) {
+                    clearTimeout(this.layoutTimer);
+                    this.layoutTimer = null;
+                }
+                if (this.tableResizeHandler) {
+                    window.removeEventListener('resize', this.tableResizeHandler);
+                    this.tableResizeHandler = null;
+                }
+            },
+            methods: $.extend({}, sharedMethods, {
+                requestTableLayout: function (delay) {
+                    var self = this;
+                    if (self.layoutTimer) {
+                        clearTimeout(self.layoutTimer);
+                    }
+                    self.$nextTick(function () {
+                        self.layoutTimer = setTimeout(function () {
+                            var table = self.$refs.dataTable;
+                            if (table && typeof table.doLayout === 'function') {
+                                table.doLayout();
+                            }
+                        }, delay || 40);
+                    });
+                },
+                isColumnVisible: function (fieldName) {
+                    return this.visibleColumnKeys.indexOf(fieldName) !== -1;
+                },
+                toggleColumn: function (fieldName, visible) {
+                    if (visible) {
+                        if (this.visibleColumnKeys.indexOf(fieldName) === -1) {
+                            this.visibleColumnKeys.push(fieldName);
+                        }
+                        this.requestTableLayout(80);
+                        return;
+                    }
+                    if (this.visibleColumnKeys.length === 1) {
+                        this.$message.warning('鑷冲皯淇濈暀涓�鍒�');
+                        return;
+                    }
+                    this.visibleColumnKeys = this.visibleColumnKeys.filter(function (item) {
+                        return item !== fieldName;
+                    });
+                    this.requestTableLayout(80);
+                },
+                selectAllColumns: function () {
+                    this.visibleColumnKeys = createDefaultVisibleColumnKeys();
+                    this.requestTableLayout(80);
+                },
+                resetColumns: function () {
+                    this.visibleColumnKeys = createDefaultVisibleColumnKeys();
+                    this.requestTableLayout(80);
+                },
+                toggleAdvancedFilters: function () {
+                    this.advancedFiltersVisible = !this.advancedFiltersVisible;
+                    this.requestTableLayout(260);
+                },
+                handleSearchForeignSelect: function (field, item) {
+                    this.$set(this.searchDisplay, field.field, item && item.value ? item.value : '');
+                    this.$set(this.searchForm, field.field, item && item.id !== undefined ? normalizeOptionValue(field, item.id) : '');
+                },
+                handleSearchForeignInput: function (field) {
+                    if (this.searchDisplay[field.field]) {
+                        return;
+                    }
+                    this.$set(this.searchForm, field.field, '');
+                },
+                buildQueryParams: function () {
+                    var self = this;
+                    var params = {
+                        curr: self.page.curr,
+                        limit: self.page.limit
+                    };
+                    if (self.searchForm.condition) {
+                        params.condition = self.searchForm.condition;
+                    }
+                    self.searchableFields.forEach(function (field) {
+                        var value = self.searchForm[field.field];
+                        if (field.kind === 'date') {
+                            if (value && value.length === 2) {
+                                params[resolveSearchParam(field)] = value[0] + ' - ' + value[1];
+                            }
+                            return;
+                        }
+                        if (!isEmptyValue(value)) {
+                            params[resolveSearchParam(field)] = value;
+                        }
+                    });
+                    if (self.sortState.prop && self.sortState.order) {
+                        params.orderByField = self.sortState.prop;
+                        params.orderByType = self.sortState.order === 'ascending' ? 'asc' : 'desc';
+                    }
+                    return params;
+                },
+                loadTable: function () {
+                    var self = this;
+                    self.loading = true;
+                    $.ajax({
+                        url: baseUrl + '/' + simpleEntityName + '/list/auth',
+                        method: 'GET',
+                        headers: self.authHeaders(),
+                        data: self.buildQueryParams(),
+                        success: function (res) {
+                            self.loading = false;
+                            if (self.handleForbidden(res)) {
+                                return;
+                            }
+                            if (!res || res.code !== 200) {
+                                self.$message.error((res && res.msg) ? res.msg : '鍔犺浇澶辫触');
+                                return;
+                            }
+                            var payload = res.data || {};
+                            self.tableData = Array.isArray(payload.records) ? payload.records : [];
+                            self.page.total = payload.total || 0;
+                            self.requestTableLayout(80);
+                        },
+                        error: function () {
+                            self.loading = false;
+                            self.requestTableLayout(80);
+                            self.$message.error('鍔犺浇澶辫触');
+                        }
+                    });
+                },
+                handleSearch: function () {
+                    this.page.curr = 1;
+                    this.loadTable();
+                },
+                handleReset: function () {
+                    this.searchForm = createSearchDefaults();
+                    this.searchDisplay = createSearchDisplayDefaults();
+                    this.advancedFiltersVisible = false;
+                    this.page.curr = 1;
+                    this.sortState = {
+                        prop: '',
+                        order: ''
+                    };
+                    this.loadTable();
+                },
+                handleSelectionChange: function (rows) {
+                    this.selection = rows || [];
+                },
+                handleSortChange: function (payload) {
+                    this.sortState = {
+                        prop: payload && payload.prop ? payload.prop : '',
+                        order: payload && payload.order ? payload.order : ''
+                    };
+                    this.page.curr = 1;
+                    this.loadTable();
+                },
+                handleCurrentChange: function (curr) {
+                    this.page.curr = curr;
+                    this.loadTable();
+                },
+                handleSizeChange: function (limit) {
+                    this.page.limit = limit;
+                    this.page.curr = 1;
+                    this.loadTable();
+                },
+                resetDialogState: function () {
+                    this.dialogForm = createFormDefaults();
+                    this.dialogDisplay = createDisplayDefaults();
+                    if (this.$refs.dialogForm) {
+                        this.$refs.dialogForm.clearValidate();
+                    }
+                },
+                openCreateDialog: function () {
+                    this.dialog.mode = 'create';
+                    this.dialog.visible = true;
+                    this.$nextTick(this.resetDialogState);
+                },
+                openEditDialog: function (row) {
+                    var self = this;
+                    self.dialog.mode = 'edit';
+                    self.dialog.visible = true;
+                    self.$nextTick(function () {
+                        self.resetDialogState();
+                        fillFormFromRow(row, self.dialogForm, self.dialogDisplay);
+                        if (self.$refs.dialogForm) {
+                            self.$refs.dialogForm.clearValidate();
+                        }
+                    });
+                },
+                submitDialog: function () {
+                    var self = this;
+                    if (!self.$refs.dialogForm) {
+                        return;
+                    }
+                    self.$refs.dialogForm.validate(function (valid) {
+                        if (!valid) {
+                            return false;
+                        }
+                        self.dialog.submitting = true;
+                        $.ajax({
+                            url: baseUrl + '/' + simpleEntityName + '/' + (self.dialog.mode === 'create' ? 'add' : 'update') + '/auth',
+                            method: 'POST',
+                            headers: self.authHeaders(),
+                            data: buildPayload(self.dialogForm),
+                            success: function (res) {
+                                self.dialog.submitting = false;
+                                if (self.handleForbidden(res)) {
+                                    return;
+                                }
+                                if (!res || res.code !== 200) {
+                                    self.$message.error((res && res.msg) ? res.msg : '淇濆瓨澶辫触');
+                                    return;
+                                }
+                                self.$message.success(res.msg || '淇濆瓨鎴愬姛');
+                                self.dialog.visible = false;
+                                self.loadTable();
+                            },
+                            error: function () {
+                                self.dialog.submitting = false;
+                                self.$message.error('淇濆瓨澶辫触');
+                            }
+                        });
+                        return true;
+                    });
+                },
+                removeSelection: function () {
+                    var self = this;
+                    var ids = self.selection.map(function (row) {
+                        return row[self.primaryKeyField];
+                    });
+                    self.removeRows(ids);
+                },
+                removeRows: function (ids) {
+                    var self = this;
+                    if (!ids || ids.length === 0) {
+                        self.$message.warning('璇烽�夋嫨瑕佸垹闄ょ殑鏁版嵁');
+                        return;
+                    }
+                    self.$confirm('纭畾鍒犻櫎閫変腑鐨勮褰曞悧锛�', '鎻愮ず', { type: 'warning' }).then(function () {
+                        $.ajax({
+                            url: baseUrl + '/' + simpleEntityName + '/delete/auth',
+                            method: 'POST',
+                            headers: self.authHeaders(),
+                            traditional: true,
+                            data: { 'ids[]': ids },
+                            success: function (res) {
+                                if (self.handleForbidden(res)) {
+                                    return;
+                                }
+                                if (!res || res.code !== 200) {
+                                    self.$message.error((res && res.msg) ? res.msg : '鍒犻櫎澶辫触');
+                                    return;
+                                }
+                                self.$message.success(res.msg || '鍒犻櫎鎴愬姛');
+                                self.selection = [];
+                                if (self.tableData.length === ids.length && self.page.curr > 1) {
+                                    self.page.curr = self.page.curr - 1;
+                                }
+                                self.loadTable();
+                            },
+                            error: function () {
+                                self.$message.error('鍒犻櫎澶辫触');
+                            }
+                        });
+                    }).catch(function () {});
+                },
+                exportRows: function () {
+                    var self = this;
+                    self.exporting = true;
+                    var requestBody = {
+                        fields: self.exportColumns.map(function (item) {
+                            return item.field;
+                        })
+                    };
+                    requestBody[simpleEntityName] = self.buildQueryParams();
+                    $.ajax({
+                        url: baseUrl + '/' + simpleEntityName + '/export/auth',
+                        method: 'POST',
+                        headers: $.extend({ 'Content-Type': 'application/json;charset=UTF-8' }, self.authHeaders()),
+                        data: JSON.stringify(requestBody),
+                        success: function (res) {
+                            self.exporting = false;
+                            if (self.handleForbidden(res)) {
+                                return;
+                            }
+                            if (!res || res.code !== 200) {
+                                self.$message.error((res && res.msg) ? res.msg : '瀵煎嚭澶辫触');
+                                return;
+                            }
+                            createDownloadFile(
+                                simpleEntityName + '_' + buildTimestamp() + '.xls',
+                                self.exportColumns.map(function (item) {
+                                    return item.label;
+                                }),
+                                Array.isArray(res.data) ? res.data : []
+                            );
+                            self.$message.success('瀵煎嚭鎴愬姛');
+                        },
+                        error: function () {
+                            self.exporting = false;
+                            self.$message.error('瀵煎嚭澶辫触');
+                        }
+                    });
                 }
             })
         });
     }
 
-    // 鎼滅储
-    form.on('submit(search)', function (data) {
-        pageCurr = 1;
-        tableReload(false);
-    });
-
-    // 閲嶇疆
-    form.on('submit(reset)', function (data) {
-        pageCurr = 1;
-        clearFormVal($('#search-box'));
-        tableReload(false);
-    });
-
-    // 鏃堕棿閫夋嫨鍣�
-    function layDateRender(data) {
-        setTimeout(function () {
-            layDate.render({
-                elem: '.layui-laydate-range'
-                ,type: 'datetime'
-                ,range: true
-            });
-@{JSDATECONTENT}
-        }, 300);
-    }
-    layDateRender();
-
-});
-
-// 鍏抽棴鍔ㄤ綔
-$(document).on('click','#data-detail-close', function () {
-    parent.layer.closeAll();
-});
-
-function tableReload(child) {
-    var searchData = {};
-    $.each($('#search-box [name]').serializeArray(), function() {
-        searchData[this.name] = this.value;
-    });
-    tableIns.reload({
-        where: searchData,
-        page: {curr: pageCurr}
-     });
-}
+})();

--
Gitblit v1.9.1