Sfoglia il codice sorgente

升级bootstrap-suggest到最新版本v0.1.29

RuoYi 3 anni fa
parent
commit
e4b8b0c30c

+ 1089 - 951
ruoyi-admin/src/main/resources/static/ajax/libs/suggest/bootstrap-suggest.js

@@ -1,1042 +1,1180 @@
 /**
- * Bootstrap Search Suggest
- * @desc    这是一个基于 bootstrap 按钮式下拉菜单组件的搜索建议插件,必须使用于按钮式下拉菜单组件上。
- * @author  renxia <lzwy0820#qq.com>
- * @github  https://github.com/lzwme/bootstrap-suggest-plugin.git
- * @since   2014-10-09
- *===============================================================================
- * (c) Copyright 2014-2019 http://lzw.me All Rights Reserved.
- ********************************************************************************/
-(function (factory) {
-    if (typeof define === "function" && define.amd) {
-        define(['jquery'], factory);
-    } else if (typeof exports === 'object' && typeof module === 'object') {
-        factory(require('jquery'));
-    } else if (window.jQuery) {
-        factory(window.jQuery);
-    } else {
-        throw new Error('Not found jQuery.');
-    }
+ * bootstrap-suggest-plugin - v0.1.29
+ * @description 这是一个基于 bootstrap 按钮式下拉菜单组件的搜索建议插件,必须使用于按钮式下拉菜单组件上。
+ * @author lzwme - https://lzw.me
+ * @GitHub https://github.com/lzwme/bootstrap-suggest-plugin.git
+ * @since 2019-11-18 09:30:06
+ */
+(function(factory) {
+  if (typeof define === "function" && define.amd) {
+    define(["jquery"], factory);
+  } else if (typeof exports === "object" && typeof module === "object") {
+    factory(require("jquery"));
+  } else if (window.jQuery) {
+    factory(window.jQuery);
+  } else {
+    throw new Error("Not found jQuery.");
+  }
 })(function($) {
-    var VERSION = 'VERSION_PLACEHOLDER';
-    var $window = $(window);
-    var isIe = 'ActiveXObject' in window; // 用于对 IE 的兼容判断
-    var inputLock; // 用于中文输入法输入时锁定搜索
-
-    // ie 下和 chrome 51 以上浏览器版本,出现滚动条时不计算 padding
-    var chromeVer = navigator.userAgent.match(/Chrome\/(\d+)/);
-    if (chromeVer) {
-        chromeVer = +chromeVer[1];
-    }
-    var notNeedCalcPadding = isIe || chromeVer > 51;
-
-    // 一些常量
-    var BSSUGGEST = 'bsSuggest';
-    var onDataRequestSuccess = 'onDataRequestSuccess';
-    var DISABLED = 'disabled';
-    var TRUE = true;
-    var FALSE = false;
-
-    function isUndefined(val) {
-        return val === void(0);
+  var VERSION = "VERSION_PLACEHOLDER";
+  var $window = $(window);
+  var isIe = "ActiveXObject" in window; // 用于对 IE 的兼容判断
+  var inputLock; // 用于中文输入法输入时锁定搜索
+
+  // ie 下和 chrome 51 以上浏览器版本,出现滚动条时不计算 padding
+  var chromeVer = navigator.userAgent.match(/Chrome\/(\d+)/);
+  if (chromeVer) {
+    chromeVer = +chromeVer[1];
+  }
+  var notNeedCalcPadding = isIe || chromeVer > 51;
+
+  // 一些常量
+  var BSSUGGEST = "bsSuggest";
+  var onDataRequestSuccess = "onDataRequestSuccess";
+  var DISABLED = "disabled";
+  var TRUE = true;
+  var FALSE = false;
+
+  function isUndefined(val) {
+    return val === void 0;
+  }
+
+  /**
+   * 错误处理
+   */
+  function handleError(e1, e2) {
+    if (!window.console || !window.console.trace) {
+      return;
     }
-
-    /**
-     * 错误处理
-     */
-    function handleError(e1, e2) {
-        if (!window.console || !window.console.trace) {
-            return;
-        }
-        console.trace(e1);
-        if (e2) {
-            console.trace(e2);
-        }
+    console.trace(e1);
+    if (e2) {
+      console.trace(e2);
     }
-    /**
-     * 获取当前 tr 列的关键字数据
-     */
-    function getPointKeyword($list) {
-        return $list.data();
+  }
+  /**
+   * 获取当前 tr 列的关键字数据
+   */
+  function getPointKeyword($list) {
+    return $list.data();
+  }
+  /**
+   * 设置或获取输入框的 alt 值
+   */
+  function setOrGetAlt($input, val) {
+    return isUndefined(val) ? $input.attr("alt") : $input.attr("alt", val);
+  }
+  /**
+   * 设置或获取输入框的 data-id 值
+   */
+  function setOrGetDataId($input, val) {
+    return val !== void 0
+      ? $input.attr("data-id", val)
+      : $input.attr("data-id");
+  }
+  /**
+   * 设置选中的值
+   */
+  function setValue($input, keywords, options) {
+    if (!keywords || !keywords.key) {
+      return;
     }
-    /**
-     * 设置或获取输入框的 alt 值
-     */
-    function setOrGetAlt($input, val) {
-        return isUndefined(val) ? $input.attr('alt') : $input.attr('alt', val);
-    }
-    /**
-     * 设置或获取输入框的 data-id 值
-     */
-    function setOrGetDataId($input, val) {
-        return val !== (void 0) ? $input.attr('data-id', val) : $input.attr('data-id');
+
+    var separator = options.separator || ",",
+      inputValList,
+      inputIdList,
+      dataId = setOrGetDataId($input);
+
+    if (options && options.multiWord) {
+      inputValList = $input.val().split(separator);
+      inputValList[inputValList.length - 1] = keywords.key;
+
+      //多关键字检索支持设置id --- 存在 bug,不建议使用
+      if (!dataId) {
+        inputIdList = [keywords.id];
+      } else {
+        inputIdList = dataId.split(separator);
+        inputIdList.push(keywords.id);
+      }
+
+      setOrGetDataId($input, inputIdList.join(separator))
+        .val(inputValList.join(separator))
+        .focus();
+    } else {
+      setOrGetDataId($input, keywords.id || "")
+        .val(keywords.key)
+        .focus();
     }
-    /**
-     * 设置选中的值
-     */
-    function setValue($input, keywords, options) {
-        if (!keywords || !keywords.key) {
-            return;
-        }
 
-        var separator = options.separator || ',',
-            inputValList,
-            inputIdList,
-            dataId = setOrGetDataId($input);
+    $input
+      .data("pre-val", $input.val())
+      .trigger("onSetSelectValue", [
+        keywords,
+        (options.data.value || options._lastData.value)[keywords.index]
+      ]);
+  }
+  /**
+   * 调整选择菜单位置
+   * @param {Object} $input
+   * @param {Object} $dropdownMenu
+   * @param {Object} options
+   */
+  function adjustDropMenuPos($input, $dropdownMenu, options) {
+    if (!$dropdownMenu.is(":visible")) {
+      return;
+    }
 
-        if (options && options.multiWord) {
-            inputValList = $input.val().split(separator);
-            inputValList[inputValList.length - 1] = keywords.key;
+    var $parent = $input.parent();
+    var parentHeight = $parent.height();
+    var parentWidth = $parent.width();
 
-            //多关键字检索支持设置id --- 存在 bug,不建议使用
-            if (!dataId) {
-                inputIdList = [keywords.id];
-            } else {
-                inputIdList = dataId.split(separator);
-                inputIdList.push(keywords.id);
-            }
+    if (options.autoDropup) {
+      setTimeout(function() {
+        var offsetTop = $input.offset().top;
+        var winScrollTop = $window.scrollTop();
+        var menuHeight = $dropdownMenu.height();
 
-            setOrGetDataId($input, inputIdList.join(separator))
-                .val(inputValList.join(separator))
-                .focus();
+        if (
+          // 自动判断菜单向上展开
+          $window.height() + winScrollTop - offsetTop < menuHeight && // 假如向下会撑长页面
+          offsetTop > menuHeight + winScrollTop // 而且向上不会撑到顶部
+        ) {
+          $parent.addClass("dropup");
         } else {
-            setOrGetDataId($input, keywords.id || '').val(keywords.key).focus();
+          $parent.removeClass("dropup");
         }
-
-        $input.data('pre-val', $input.val())
-            .trigger('onSetSelectValue', [keywords, (options.data.value || options._lastData.value)[keywords.index]]);
+      }, 10);
     }
-    /**
-     * 调整选择菜单位置
-     * @param {Object} $input
-     * @param {Object} $dropdownMenu
-     * @param {Object} options
-     */
-    function adjustDropMenuPos($input, $dropdownMenu, options) {
-        if (!$dropdownMenu.is(':visible')) {
-            return;
-        }
 
-        var $parent = $input.parent();
-        var parentHeight = $parent.height();
-        var parentWidth = $parent.width();
-
-        if (options.autoDropup) {
-            setTimeout(function() {
-                var offsetTop = $input.offset().top;
-                var winScrollTop = $window.scrollTop();
-                var menuHeight = $dropdownMenu.height();
-
-                if ( // 自动判断菜单向上展开
-                    ($window.height() + winScrollTop - offsetTop) < menuHeight && // 假如向下会撑长页面
-                    offsetTop > (menuHeight + winScrollTop) // 而且向上不会撑到顶部
-                ) {
-                    $parent.addClass('dropup');
-                } else {
-                    $parent.removeClass('dropup');
-                }
-            }, 10);
-        }
-
-        // 列表对齐方式
-        var dmcss = {};
-        if (options.listAlign === 'left') {
-            dmcss = {
-                'left': $input.siblings('div').width() - parentWidth,
-                'right': 'auto'
-            };
-        } else if (options.listAlign === 'right') {
-            dmcss = {
-                'left': 'auto',
-                'right': 0
-            };
-        }
+    // 列表对齐方式
+    var dmcss = {};
+    if (options.listAlign === "left") {
+      dmcss = {
+        left: $input.siblings("div").width() - parentWidth,
+        right: "auto"
+      };
+    } else if (options.listAlign === "right") {
+      dmcss = {
+        left: "auto",
+        right: 0
+      };
+    }
 
-        // ie 下,不显示按钮时的 top/bottom
-        if (isIe && !options.showBtn) {
-            if (!$parent.hasClass('dropup')) {
-                dmcss.top = parentHeight;
-                dmcss.bottom = 'auto';
-            } else {
-                dmcss.top = 'auto';
-                dmcss.bottom = parentHeight;
-            }
-        }
+    // ie 下,不显示按钮时的 top/bottom
+    if (isIe && !options.showBtn) {
+      if (!$parent.hasClass("dropup")) {
+        dmcss.top = parentHeight;
+        dmcss.bottom = "auto";
+      } else {
+        dmcss.top = "auto";
+        dmcss.bottom = parentHeight;
+      }
+    }
 
-        // 是否自动最小宽度
-        if (!options.autoMinWidth) {
-            dmcss.minWidth = parentWidth;
-        }
-        /* else {
+    // 是否自动最小宽度
+    if (!options.autoMinWidth) {
+      dmcss.minWidth = parentWidth;
+    }
+    /* else {
             dmcss['width'] = 'auto';
         }*/
 
-        $dropdownMenu.css(dmcss);
-
-        return $input;
+    $dropdownMenu.css(dmcss);
+
+    return $input;
+  }
+  /**
+   * 设置输入框背景色
+   * 当设置了 indexId,而输入框的 data-id 为空时,输入框加载警告色
+   */
+  function setBackground($input, options) {
+    var inputbg, bg, warnbg;
+    if ((options.indexId === -1 && !options.idField) || options.multiWord) {
+      return $input;
     }
-    /**
-     * 设置输入框背景色
-     * 当设置了 indexId,而输入框的 data-id 为空时,输入框加载警告色
-     */
-    function setBackground($input, options) {
-        var inputbg, bg, warnbg;
-        if ((options.indexId === -1 && !options.idField) || options.multiWord) {
-            return $input;
-        }
 
-        bg = options.inputBgColor;
-        warnbg = options.inputWarnColor;
+    bg = options.inputBgColor;
+    warnbg = options.inputWarnColor;
 
-        var curVal = $input.val();
-        var preVal = $input.data('pre-val');
+    var curVal = $input.val();
+    var preVal = $input.data("pre-val");
 
-        if (setOrGetDataId($input) || !curVal) {
-            $input.css('background', bg || '');
+    if (setOrGetDataId($input) || !curVal) {
+      $input.css("background", bg || "");
 
-            if (!curVal && preVal) {
-                $input.trigger('onUnsetSelectValue').data('pre-val', '');
-            }
-
-            return $input;
-        }
+      if (!curVal && preVal) {
+        $input.trigger("onUnsetSelectValue").data("pre-val", "");
+      }
 
-        inputbg = $input.css('backgroundColor').replace(/ /g, '').split(',', 3).join(',');
-        // 自由输入的内容,设置背景色
-        if (!~warnbg.indexOf(inputbg)) {
-            $input.trigger('onUnsetSelectValue') // 触发取消data-id事件
-                .data('pre-val', '')
-                .css('background', warnbg);
-        }
+      return $input;
+    }
 
-        return $input;
+    inputbg = $input
+      .css("backgroundColor")
+      .replace(/ /g, "")
+      .split(",", 3)
+      .join(",");
+    // 自由输入的内容,设置背景色
+    if (!~warnbg.indexOf(inputbg)) {
+      $input
+        .trigger("onUnsetSelectValue") // 触发取消data-id事件
+        .data("pre-val", "")
+        .css("background", warnbg);
     }
-    /**
-     * 调整滑动条
-     */
-    function adjustScroll($input, $dropdownMenu, options) {
-        // 控制滑动条
-        var $hover = $input.parent().find('tbody tr.' + options.listHoverCSS),
-            pos, maxHeight;
-
-        if ($hover.length) {
-            pos = ($hover.index() + 3) * $hover.height();
-            maxHeight = +$dropdownMenu.css('maxHeight').replace('px', '');
-
-            if (pos > maxHeight || $dropdownMenu.scrollTop() > maxHeight) {
-                pos = pos - maxHeight;
-            } else {
-                pos = 0;
-            }
 
-            $dropdownMenu.scrollTop(pos);
-        }
+    return $input;
+  }
+  /**
+   * 调整滑动条
+   */
+  function adjustScroll($input, $dropdownMenu, options) {
+    // 控制滑动条
+    var $hover = $input.parent().find("tbody tr." + options.listHoverCSS),
+      pos,
+      maxHeight;
+
+    if ($hover.length) {
+      pos = ($hover.index() + 3) * $hover.height();
+      maxHeight = +$dropdownMenu.css("maxHeight").replace("px", "");
+
+      if (pos > maxHeight || $dropdownMenu.scrollTop() > maxHeight) {
+        pos = pos - maxHeight;
+      } else {
+        pos = 0;
+      }
+
+      $dropdownMenu.scrollTop(pos);
     }
-    /**
-     * 解除所有列表 hover 样式
-     */
-    function unHoverAll($dropdownMenu, options) {
-        $dropdownMenu.find('tr.' + options.listHoverCSS).removeClass(options.listHoverCSS);
+  }
+  /**
+   * 解除所有列表 hover 样式
+   */
+  function unHoverAll($dropdownMenu, options) {
+    $dropdownMenu
+      .find("tr." + options.listHoverCSS)
+      .removeClass(options.listHoverCSS);
+  }
+  /**
+   * 验证 $input 对象是否符合条件
+   *   1. 必须为 bootstrap 下拉式菜单
+   *   2. 必须未初始化过
+   */
+  function checkInput($input, $dropdownMenu, options) {
+    if (
+      !$dropdownMenu.length || // 过滤非 bootstrap 下拉式菜单对象
+      $input.data(BSSUGGEST) // 是否已经初始化的检测
+    ) {
+      return FALSE;
     }
-    /**
-     * 验证 $input 对象是否符合条件
-     *   1. 必须为 bootstrap 下拉式菜单
-     *   2. 必须未初始化过
-     */
-    function checkInput($input, $dropdownMenu, options) {
-        if (
-            !$dropdownMenu.length || // 过滤非 bootstrap 下拉式菜单对象
-            $input.data(BSSUGGEST) // 是否已经初始化的检测
-        ) {
-            return FALSE;
-        }
 
-        $input.data(BSSUGGEST, {
-            options: options
-        });
-
-        return TRUE;
+    $input.data(BSSUGGEST, {
+      options: options
+    });
+
+    return TRUE;
+  }
+  /**
+   * 数据格式检测
+   * 检测 ajax 返回成功数据或 data 参数数据是否有效
+   * data 格式:{"value": [{}, {}...]}
+   */
+  function checkData(data) {
+    var isEmpty = TRUE,
+      o;
+
+    for (o in data) {
+      if (o === "value") {
+        isEmpty = FALSE;
+        break;
+      }
+    }
+    if (isEmpty) {
+      handleError("返回数据格式错误!");
+      return FALSE;
+    }
+    if (!data.value.length) {
+      // handleError('返回数据为空!');
+      return FALSE;
     }
-    /**
-     * 数据格式检测
-     * 检测 ajax 返回成功数据或 data 参数数据是否有效
-     * data 格式:{"value": [{}, {}...]}
-     */
-    function checkData(data) {
-        var isEmpty = TRUE, o;
-
-        for (o in data) {
-            if (o === 'value') {
-                isEmpty = FALSE;
-                break;
-            }
-        }
-        if (isEmpty) {
-            handleError('返回数据格式错误!');
-            return FALSE;
-        }
-        if (!data.value.length) {
-            // handleError('返回数据为空!');
-            return FALSE;
-        }
 
-        return data;
+    return data;
+  }
+  /**
+   * 判断字段名是否在 options.effectiveFields 配置项中
+   * @param  {String} field   要判断的字段名
+   * @param  {Object} options
+   * @return {Boolean}        effectiveFields 为空时始终返回 true
+   */
+  function inEffectiveFields(field, options) {
+    var effectiveFields = options.effectiveFields;
+
+    return !(
+      field === "__index" ||
+      (effectiveFields.length && !~$.inArray(field, effectiveFields))
+    );
+  }
+  /**
+   * 判断字段名是否在 options.searchFields 搜索字段配置中
+   */
+  function inSearchFields(field, options) {
+    return ~$.inArray(field, options.searchFields);
+  }
+  /**
+   * 通过下拉菜单显示提示文案
+   */
+  function showTip(tip, $input, $dropdownMenu, options) {
+    $dropdownMenu
+      .html('<div style="padding:10px 5px 5px">' + tip + "</div>")
+      .show();
+    adjustDropMenuPos($input, $dropdownMenu, options);
+  }
+  /**
+   * 显示下拉列表
+   */
+  function showDropMenu($input, options) {
+    var $dropdownMenu = $input.parent().find("ul:eq(0)");
+    if (!$dropdownMenu.is(":visible")) {
+      // $dropdownMenu.css('display', 'block');
+      $dropdownMenu.show();
+      $input.trigger("onShowDropdown", [options ? options.data.value : []]);
     }
-    /**
-     * 判断字段名是否在 options.effectiveFields 配置项中
-     * @param  {String} field   要判断的字段名
-     * @param  {Object} options
-     * @return {Boolean}        effectiveFields 为空时始终返回 true
-     */
-    function inEffectiveFields(field, options) {
-        var effectiveFields = options.effectiveFields;
-
-        return !(field === '__index' ||
-            effectiveFields.length &&
-            !~$.inArray(field, effectiveFields));
+  }
+  /**
+   * 隐藏下拉列表
+   */
+  function hideDropMenu($input, options) {
+    var $dropdownMenu = $input.parent().find("ul:eq(0)");
+    if ($dropdownMenu.is(":visible")) {
+      // $dropdownMenu.css('display', '');
+      $dropdownMenu.hide();
+      $input.trigger("onHideDropdown", [options ? options.data.value : []]);
     }
-    /**
-     * 判断字段名是否在 options.searchFields 搜索字段配置中
-     */
-    function inSearchFields(field, options) {
-        return ~$.inArray(field, options.searchFields);
+  }
+  /**
+   * 下拉列表刷新
+   * 作为 fnGetData 的 callback 函数调用
+   */
+  function refreshDropMenu($input, data, options) {
+    var $dropdownMenu = $input.parent().find("ul:eq(0)"),
+      len,
+      i,
+      field,
+      index = 0,
+      tds,
+      html = [
+        '<table class="table table-condensed table-sm" style="margin:0">'
+      ],
+      idValue,
+      keyValue; // 作为输入框 data-id 和内容的字段值
+    var dataList = data.value;
+
+    if (!data || !(len = dataList.length)) {
+      if (options.emptyTip) {
+        showTip(options.emptyTip, $input, $dropdownMenu, options);
+      } else {
+        $dropdownMenu.empty();
+        hideDropMenu($input, options);
+      }
+      return $input;
     }
-    /**
-     * 通过下拉菜单显示提示文案
-     */
-    function showTip(tip, $input, $dropdownMenu, options) {
-        $dropdownMenu.html('<div style="padding:10px 5px 5px">' + tip + '</div>').show();
-        adjustDropMenuPos($input, $dropdownMenu, options);
+
+    // 相同数据,不用继续渲染了
+    if (
+      options._lastData &&
+      JSON.stringify(options._lastData) === JSON.stringify(data) &&
+      $dropdownMenu.find("tr").length === len
+    ) {
+      showDropMenu($input, options);
+      return adjustDropMenuPos($input, $dropdownMenu, options);
     }
-    /**
-     * 显示下拉列表
-     */
-    function showDropMenu($input, options) {
-        var $dropdownMenu = $input.parent().find('ul:eq(0)');
-        if (!$dropdownMenu.is(':visible')) {
-            // $dropdownMenu.css('display', 'block');
-            $dropdownMenu.show();
-            $input.trigger('onShowDropdown', [options ? options.data.value : []]);
-        }
+    options._lastData = data;
+
+    /** 显示于列表中的字段 */
+    var columns = options.effectiveFields.length
+      ? options.effectiveFields
+      : $.map(dataList[0], function(val, key) {
+          return key;
+        });
+
+    // 生成表头
+    if (options.showHeader) {
+      html.push("<thead><tr>");
+      $.each(columns, function(index, field) {
+        if (!inEffectiveFields(field, options)) return;
+
+        html.push(
+          "<th>",
+          options.effectiveFieldsAlias[field] || field,
+          index === 0 ? "(" + len + ")" : "", // 表头第一列记录总数
+          "</th>"
+        );
+
+        index++;
+      });
+      html.push("</tr></thead>");
     }
-    /**
-     * 隐藏下拉列表
-     */
-    function hideDropMenu($input, options) {
-        var $dropdownMenu = $input.parent().find('ul:eq(0)');
-        if ($dropdownMenu.is(':visible')) {
-            // $dropdownMenu.css('display', '');
-            $dropdownMenu.hide();
-            $input.trigger('onHideDropdown', [options ? options.data.value : []]);
+    html.push("<tbody>");
+
+    // console.log(data, len);
+    // 按列加数据
+    var dataI;
+    var maxOptionCount = Math.min(options.maxOptionCount, len);
+    for (i = 0; i < maxOptionCount; i++) {
+      index = 0;
+      tds = [];
+      dataI = dataList[i];
+      idValue = dataI[options.idField];
+      keyValue = dataI[options.keyField];
+
+      for (field in dataI) {
+        // 标记作为 value 和 作为 id 的值
+        if (isUndefined(keyValue) && options.indexKey === index) {
+          keyValue = dataI[field];
         }
-    }
-    /**
-     * 下拉列表刷新
-     * 作为 fnGetData 的 callback 函数调用
-     */
-    function refreshDropMenu($input, data, options) {
-        var $dropdownMenu = $input.parent().find('ul:eq(0)'),
-            len, i, field, index = 0,
-            tds,
-            html = ['<table class="table table-condensed table-sm" style="margin:0">'],
-            idValue, keyValue; // 作为输入框 data-id 和内容的字段值
-        var dataList = data.value;
-
-        if (!data || !(len = dataList.length)) {
-            if (options.emptyTip) {
-                showTip(options.emptyTip, $input, $dropdownMenu, options);
-            } else {
-                $dropdownMenu.empty();
-                hideDropMenu($input, options);
-            }
-            return $input;
+        if (isUndefined(idValue) && options.indexId === index) {
+          idValue = dataI[field];
         }
+        index++;
+      }
 
-        // 相同数据,不用继续渲染了
-        if (
-            options._lastData &&
-            JSON.stringify(options._lastData) === JSON.stringify(data) &&
-            $dropdownMenu.find('tr').length === len
-        ) {
-            showDropMenu($input, options);
-            return adjustDropMenuPos($input, $dropdownMenu, options);
+      $.each(columns, function(index, field) {
+        // 列表中只显示有效的字段
+        if (inEffectiveFields(field, options)) {
+          tds.push('<td data-name="', field, '">', dataI[field], "</td>");
         }
-        options._lastData = data;
-
-        // 生成表头
-        if (options.showHeader) {
-            html.push('<thead><tr>');
-            for (field in dataList[0]) {
-                if (!inEffectiveFields(field, options)) {
-                    continue;
-                }
+      });
+
+      html.push(
+        '<tr data-index="',
+        dataI.__index || i,
+        '" data-id="',
+        idValue,
+        '" data-key="',
+        keyValue,
+        '">',
+        tds.join(""),
+        "</tr>"
+      );
+    }
+    html.push("</tbody></table>");
+
+    $dropdownMenu.html(html.join(""));
+    showDropMenu($input, options);
+    //.show();
+
+    // scrollbar 存在时,延时到动画结束时调整 padding
+    setTimeout(function() {
+      if (notNeedCalcPadding) {
+        return;
+      }
+
+      var $table = $dropdownMenu.find("table:eq(0)"),
+        pdr = 0,
+        mgb = 0;
+
+      if (
+        $dropdownMenu.height() < $table.height() &&
+        +$dropdownMenu.css("minWidth").replace("px", "") < $dropdownMenu.width()
+      ) {
+        pdr = 18;
+        mgb = 20;
+      }
+
+      $dropdownMenu.css("paddingRight", pdr);
+      $table.css("marginBottom", mgb);
+    }, 301);
+
+    adjustDropMenuPos($input, $dropdownMenu, options);
+
+    return $input;
+  }
+  /**
+   * ajax 获取数据
+   * @param  {Object} options
+   * @return {Object}         $.Deferred
+   */
+  function ajax(options, keyword) {
+    keyword = keyword || "";
+
+    var preAjax = options._preAjax;
+
+    if (preAjax && preAjax.abort && preAjax.readyState !== 4) {
+      // console.log('abort pre ajax');
+      preAjax.abort();
+    }
 
-                html.push('<th>', (options.effectiveFieldsAlias[field] || field),
-                    index === 0 ? ('(' + len + ')') : '' , // 表头第一列记录总数
-                    '</th>');
+    var ajaxParam = {
+      type: "GET",
+      dataType: options.jsonp ? "jsonp" : "json",
+      timeout: 5000
+    };
 
-                index++;
-            }
-            html.push('</tr></thead>');
-        }
-        html.push('<tbody>');
-
-        // console.log(data, len);
-        // 按列加数据
-        var dataI;
-        for (i = 0; i < len; i++) {
-            index = 0;
-            tds = [];
-            dataI = dataList[i];
-            idValue = dataI[options.idField];
-            keyValue = dataI[options.keyField];
-
-            for (field in dataI) {
-                // 标记作为 value 和 作为 id 的值
-                if (isUndefined(keyValue) && options.indexKey === index) {
-                    keyValue = dataI[field];
-                }
-                if (isUndefined(idValue) && options.indexId === index) {
-                    idValue = dataI[field];
-                }
+    // jsonp
+    if (options.jsonp) {
+      ajaxParam.jsonp = options.jsonp;
+    }
 
-                index++;
+    // 自定义 ajax 请求参数生成方法
+    var adjustAjaxParam,
+      fnAdjustAjaxParam = options.fnAdjustAjaxParam;
 
-                // 列表中只显示有效的字段
-                if (inEffectiveFields(field, options)) {
-                    tds.push('<td data-name="', field, '">', dataI[field], '</td>');
-                }
-            }
+    if ($.isFunction(fnAdjustAjaxParam)) {
+      adjustAjaxParam = fnAdjustAjaxParam(keyword, options);
 
-            html.push('<tr data-index="', (dataI.__index || i),
-                '" data-id="', idValue,
-                '" data-key="', keyValue, '">',
-                tds.join(''), '</tr>');
-        }
-        html.push('</tbody></table>');
+      // options.fnAdjustAjaxParam 返回false,则终止 ajax 请求
+      if (FALSE === adjustAjaxParam) {
+        return;
+      }
 
-        $dropdownMenu.html(html.join(''));
-        showDropMenu($input, options);
-        //.show();
+      $.extend(ajaxParam, adjustAjaxParam);
+    }
 
-        // scrollbar 存在时,延时到动画结束时调整 padding
-        setTimeout(function() {
-            if (notNeedCalcPadding) {
-                return;
-            }
+    // url 调整
+    ajaxParam.url = (function() {
+      if (!keyword || ajaxParam.data) {
+        return ajaxParam.url || options.url;
+      }
+
+      var type = "?";
+      if (/=$/.test(options.url)) {
+        type = "";
+      } else if (/\?/.test(options.url)) {
+        type = "&";
+      }
+
+      return options.url + type + encodeURIComponent(keyword);
+    })();
+
+    return (options._preAjax = $.ajax(ajaxParam)
+      .done(function(result) {
+        options.data = options.fnProcessData(result);
+      })
+      .fail(function(err) {
+        if (options.fnAjaxFail) {
+          options.fnAjaxFail(err, options);
+        }
+      }));
+  }
+  /**
+   * 检测 keyword 与 value 是否存在互相包含
+   * @param  {String}  keyword 用户输入的关键字
+   * @param  {String}  key     匹配字段的 key
+   * @param  {String}  value   key 字段对应的值
+   * @param  {Object}  options
+   * @return {Boolean}         包含/不包含
+   */
+  function isInWord(keyword, key, value, options) {
+    value = $.trim(value);
+
+    if (options.ignorecase) {
+      keyword = keyword.toLocaleLowerCase();
+      value = value.toLocaleLowerCase();
+    }
 
-            var $table = $dropdownMenu.find('table:eq(0)'),
-                pdr = 0,
-                mgb = 0;
+    return (
+      value &&
+      (inEffectiveFields(key, options) || inSearchFields(key, options)) && // 必须在有效的搜索字段中
+      (~value.indexOf(keyword) || // 匹配值包含关键字
+        (options.twoWayMatch && ~keyword.indexOf(value))) // 关键字包含匹配值
+    );
+  }
+  /**
+   * 通过 ajax 或 json 参数获取数据
+   */
+  function getData(keyword, $input, callback, options) {
+    var data,
+      validData,
+      filterData = {
+        value: []
+      },
+      i,
+      key,
+      len,
+      fnPreprocessKeyword = options.fnPreprocessKeyword;
+
+    keyword = keyword || "";
+    // 获取数据前对关键字预处理方法
+    if ($.isFunction(fnPreprocessKeyword)) {
+      keyword = fnPreprocessKeyword(keyword, options);
+    }
 
-            if (
-                $dropdownMenu.height() < $table.height() &&
-                +$dropdownMenu.css('minWidth').replace('px', '') < $dropdownMenu.width()
-            ) {
-                pdr = 18;
-                mgb = 20;
+    // 给了url参数,则从服务器 ajax 请求
+    // console.log(options.url + keyword);
+    if (options.url) {
+      var timer;
+      if (options.searchingTip) {
+        timer = setTimeout(function() {
+          showTip(
+            options.searchingTip,
+            $input,
+            $input.parent().find("ul"),
+            options
+          );
+        }, 600);
+      }
+
+      ajax(options, keyword)
+        .done(function(result) {
+          callback($input, options.data, options); // 为 refreshDropMenu
+          $input.trigger(onDataRequestSuccess, result);
+          if (options.getDataMethod === "firstByUrl") {
+            options.url = null;
+          }
+        })
+        .always(function() {
+          timer && clearTimeout(timer);
+        });
+    } else {
+      // 没有给出 url 参数,则从 data 参数获取
+      data = options.data;
+      validData = checkData(data);
+      // 本地的 data 数据,则在本地过滤
+      if (validData) {
+        if (keyword) {
+          // 输入不为空时则进行匹配
+          len = data.value.length;
+          for (i = 0; i < len; i++) {
+            for (key in data.value[i]) {
+              if (
+                data.value[i][key] &&
+                isInWord(keyword, key, data.value[i][key] + "", options)
+              ) {
+                filterData.value.push(data.value[i]);
+                filterData.value[filterData.value.length - 1].__index = i;
+                break;
+              }
             }
-
-            $dropdownMenu.css('paddingRight', pdr);
-            $table.css('marginBottom', mgb);
-        }, 301);
-
-        adjustDropMenuPos($input, $dropdownMenu, options);
-
-        return $input;
+          }
+        } else {
+          filterData = data;
+        }
+      }
+
+      callback($input, filterData, options);
+    } // else
+  }
+  /**
+   * 数据处理
+   * url 获取数据时,对数据的处理,作为 fnGetData 之后的回调处理
+   */
+  function processData(data) {
+    return checkData(data);
+  }
+  /**
+   * 取得 clearable 清除按钮
+   */
+  function getIClear($input, options) {
+    var $iClear = $input.prev("i.clearable");
+
+    // 是否可清除已输入的内容(添加清除按钮)
+    if (options.clearable && !$iClear.length) {
+      $iClear = $(
+        '<i class="clearable glyphicon glyphicon-remove fa fa-plus"></i>'
+      ).prependTo($input.parent());
     }
-    /**
-     * ajax 获取数据
-     * @param  {Object} options
-     * @return {Object}         $.Deferred
-     */
-    function ajax(options, keyword) {
-        keyword = keyword || '';
-
-        var preAjax = options._preAjax;
-
-        if (preAjax && preAjax.abort && preAjax.readyState !== 4) {
-            // console.log('abort pre ajax');
-            preAjax.abort();
+
+    return $iClear
+      .css({
+        position: "absolute",
+        top: "calc(50% - 6px)",
+        transform: "rotate(45deg)",
+        // right: options.showBtn ? Math.max($input.next('.input-group-btn').width(), 33) + 2 : 12,
+        zIndex: 4,
+        cursor: "pointer",
+        width: "14px",
+        lineHeight: "14px",
+        textAlign: "center",
+        fontSize: 12
+      })
+      .hide();
+  }
+  /**
+   * 默认的配置选项
+   * @type {Object}
+   */
+  var defaultOptions = {
+    url: null, // 请求数据的 URL 地址
+    jsonp: null, // 设置此参数名,将开启jsonp功能,否则使用json数据结构
+    data: {
+      value: []
+    }, // 提示所用的数据,注意格式
+    indexId: 0, // 每组数据的第几个数据,作为input输入框的 data-id,设为 -1 且 idField 为空则不设置此值
+    indexKey: 0, // 每组数据的第几个数据,作为input输入框的内容
+    idField: "", // 每组数据的哪个字段作为 data-id,优先级高于 indexId 设置(推荐)
+    keyField: "", // 每组数据的哪个字段作为输入框内容,优先级高于 indexKey 设置(推荐)
+
+    /* 搜索相关 */
+    autoSelect: TRUE, // 键盘向上/下方向键时,是否自动选择值
+    allowNoKeyword: TRUE, // 是否允许无关键字时请求数据
+    getDataMethod: "firstByUrl", // 获取数据的方式,url:一直从url请求;data:从 options.data 获取;firstByUrl:第一次从Url获取全部数据,之后从options.data获取
+    delayUntilKeyup: FALSE, // 获取数据的方式 为 firstByUrl 时,是否延迟到有输入时才请求数据
+    ignorecase: FALSE, // 前端搜索匹配时,是否忽略大小写
+    effectiveFields: [], // 有效显示于列表中的字段,非有效字段都会过滤,默认全部有效。
+    effectiveFieldsAlias: {}, // 有效字段的别名对象,用于 header 的显示
+    searchFields: [], // 有效搜索字段,从前端搜索过滤数据时使用,但不一定显示在列表中。effectiveFields 配置字段也会用于搜索过滤
+    twoWayMatch: TRUE, // 是否双向匹配搜索。为 true 即输入关键字包含或包含于匹配字段均认为匹配成功,为 false 则输入关键字包含于匹配字段认为匹配成功
+    multiWord: FALSE, // 以分隔符号分割的多关键字支持
+    separator: ",", // 多关键字支持时的分隔符,默认为半角逗号
+    delay: 300, // 搜索触发的延时时间间隔,单位毫秒
+    emptyTip: "", // 查询为空时显示的内容,可为 html
+    searchingTip: "搜索中...", // ajax 搜索时显示的提示内容,当搜索时间较长时给出正在搜索的提示
+    hideOnSelect: FALSE, // 鼠标从列表单击选择了值时,是否隐藏选择列表
+    maxOptionCount: 200, // 选择列表最多显示的可选项数量,默认为 200
+
+    /* UI */
+    autoDropup: FALSE, // 选择菜单是否自动判断向上展开。设为 true,则当下拉菜单高度超过窗体,且向上方向不会被窗体覆盖,则选择菜单向上弹出
+    autoMinWidth: FALSE, // 是否自动最小宽度,设为 false 则最小宽度不小于输入框宽度
+    showHeader: FALSE, // 是否显示选择列表的 header。为 true 时,有效字段大于一列则显示表头
+    showBtn: TRUE, // 是否显示下拉按钮
+    inputBgColor: "", // 输入框背景色,当与容器背景色不同时,可能需要该项的配置
+    inputWarnColor: "rgba(255,0,0,.1)", // 输入框内容不是下拉列表选择时的警告色
+    listStyle: {
+      "padding-top": 0,
+      "max-height": "375px",
+      "max-width": "800px",
+      overflow: "auto",
+      width: "auto",
+      transition: "0.3s",
+      "-webkit-transition": "0.3s",
+      "-moz-transition": "0.3s",
+      "-o-transition": "0.3s",
+      "word-break": "keep-all",
+      "white-space": "nowrap"
+    }, // 列表的样式控制
+    listAlign: "left", // 提示列表对齐位置,left/right/auto
+    listHoverStyle: "background: #07d; color:#fff", // 提示框列表鼠标悬浮的样式
+    listHoverCSS: "jhover", // 提示框列表鼠标悬浮的样式名称
+    clearable: FALSE, // 是否可清除已输入的内容
+
+    /* key */
+    keyLeft: 37, // 向左方向键,不同的操作系统可能会有差别,则自行定义
+    keyUp: 38, // 向上方向键
+    keyRight: 39, // 向右方向键
+    keyDown: 40, // 向下方向键
+    keyEnter: 13, // 回车键
+
+    /* methods */
+    fnProcessData: processData, // 格式化数据的方法,返回数据格式参考 data 参数
+    fnGetData: getData, // 获取数据的方法,无特殊需求一般不作设置
+    fnAdjustAjaxParam: null, // 调整 ajax 请求参数方法,用于更多的请求配置需求。如对请求关键字作进一步处理、修改超时时间等
+    fnPreprocessKeyword: null, // 搜索过滤数据前,对输入关键字作进一步处理方法。注意,应返回字符串
+    fnAjaxFail: null // ajax 失败时回调方法
+  };
+
+  var methods = {
+    init: function(options) {
+      // 参数设置
+      var self = this;
+      options = options || {};
+
+      // 默认配置有效显示字段多于一个,则显示列表表头,否则不显示
+      if (
+        isUndefined(options.showHeader) &&
+        options.effectiveFields &&
+        options.effectiveFields.length > 1
+      ) {
+        options.showHeader = TRUE;
+      }
+
+      options = $.extend(TRUE, {}, defaultOptions, options);
+
+      // 旧的方法兼容
+      if (options.processData) {
+        options.fnProcessData = options.processData;
+      }
+
+      if (options.getData) {
+        options.fnGetData = options.getData;
+      }
+
+      if (
+        options.getDataMethod === "firstByUrl" &&
+        options.url &&
+        !options.delayUntilKeyup
+      ) {
+        ajax(options).done(function(result) {
+          options.url = null;
+          self.trigger(onDataRequestSuccess, result);
+        });
+      }
+
+      // 鼠标滑动到条目样式
+      if (!$("#" + BSSUGGEST).length) {
+        $("head:eq(0)").append(
+          '<style id="' +
+            BSSUGGEST +
+            '">.' +
+            options.listHoverCSS +
+            "{" +
+            options.listHoverStyle +
+            "}</style>"
+        );
+      }
+
+      return self.each(function() {
+        var $input = $(this),
+          $parent = $input.parent(),
+          $iClear = getIClear($input, options),
+          isMouseenterMenu,
+          keyupTimer, // keyup 与 input 事件延时定时器
+          $dropdownMenu = $parent.find("ul:eq(0)");
+
+        // 兼容 bs4
+        $dropdownMenu.parent().css("position", "relative");
+
+        // 验证输入框对象是否符合条件
+        if (!checkInput($input, $dropdownMenu, options)) {
+          console.warn(
+            "不是一个标准的 bootstrap 下拉式菜单或已初始化:",
+            $input
+          );
+          return;
         }
 
-        var ajaxParam = {
-            type: 'GET',
-            dataType: options.jsonp ? 'jsonp' : 'json',
-            timeout: 5000,
-        };
+        // 是否显示 button 按钮
+        if (!options.showBtn) {
+          $input.css("borderRadius", 4);
+          $parent
+            .css("width", "100%")
+            .find(".btn:eq(0)")
+            .hide();
+        }
 
-        // jsonp
-        if (options.jsonp) {
-            ajaxParam.jsonp = options.jsonp;
+        // 移除 disabled 类,并禁用自动完成
+        $input
+          .removeClass(DISABLED)
+          .prop(DISABLED, FALSE)
+          .attr("autocomplete", "off");
+        // dropdown-menu 增加修饰
+        $dropdownMenu.css(options.listStyle);
+
+        // 默认背景色
+        if (!options.inputBgColor) {
+          options.inputBgColor = $input.css("backgroundColor");
         }
 
-        // 自定义 ajax 请求参数生成方法
-        var adjustAjaxParam,
-            fnAdjustAjaxParam = options.fnAdjustAjaxParam;
+        // 开始事件处理
+        $input
+          .on("keydown.bs", function(event) {
+            var currentList, tipsKeyword; // 提示列表上被选中的关键字
 
-        if ($.isFunction(fnAdjustAjaxParam)) {
-            adjustAjaxParam = fnAdjustAjaxParam(keyword, options);
+            // 当提示层显示时才对键盘事件处理
+            if (!$dropdownMenu.is(":visible")) {
+              setOrGetDataId($input, "");
+              return;
+            }
 
-            // options.fnAdjustAjaxParam 返回false,则终止 ajax 请求
-            if (FALSE === adjustAjaxParam) {
+            currentList = $dropdownMenu.find("." + options.listHoverCSS);
+            tipsKeyword = ""; // 提示列表上被选中的关键字
+
+            unHoverAll($dropdownMenu, options);
+
+            if (event.keyCode === options.keyDown) {
+              // 如果按的是向下方向键
+              if (!currentList.length) {
+                // 如果提示列表没有一个被选中,则将列表第一个选中
+                tipsKeyword = getPointKeyword(
+                  $dropdownMenu.find("tbody tr:first").mouseover()
+                );
+              } else if (!currentList.next().length) {
+                // 如果是最后一个被选中,则取消选中,即可认为是输入框被选中,并恢复输入的值
+                if (options.autoSelect) {
+                  setOrGetDataId($input, "").val(setOrGetAlt($input));
+                }
+              } else {
+                // 选中下一行
+                tipsKeyword = getPointKeyword(currentList.next().mouseover());
+              }
+              // 控制滑动条
+              adjustScroll($input, $dropdownMenu, options);
+
+              if (!options.autoSelect) {
                 return;
-            }
+              }
+            } else if (event.keyCode === options.keyUp) {
+              // 如果按的是向上方向键
+              if (!currentList.length) {
+                tipsKeyword = getPointKeyword(
+                  $dropdownMenu.find("tbody tr:last").mouseover()
+                );
+              } else if (!currentList.prev().length) {
+                if (options.autoSelect) {
+                  setOrGetDataId($input, "").val(setOrGetAlt($input));
+                }
+              } else {
+                // 选中前一行
+                tipsKeyword = getPointKeyword(currentList.prev().mouseover());
+              }
 
-            $.extend(ajaxParam, adjustAjaxParam);
-        }
+              // 控制滑动条
+              adjustScroll($input, $dropdownMenu, options);
 
-        // url 调整
-        ajaxParam.url = function() {
-            if (!keyword || ajaxParam.data) {
-                return ajaxParam.url || options.url;
+              if (!options.autoSelect) {
+                return;
+              }
+            } else if (event.keyCode === options.keyEnter) {
+              tipsKeyword = getPointKeyword(currentList);
+              hideDropMenu($input, options);
+            } else {
+              setOrGetDataId($input, "");
             }
 
-            var type = '?';
-            if (/=$/.test(options.url)) {
-                type = '';
-            } else if (/\?/.test(options.url)) {
-                type = '&';
+            // 设置值 tipsKeyword
+            // console.log(tipsKeyword);
+            setValue($input, tipsKeyword, options);
+          })
+          .on("compositionstart.bs", function(event) {
+            // 中文输入开始,锁定
+            // console.log('compositionstart');
+            inputLock = TRUE;
+          })
+          .on("compositionend.bs", function(event) {
+            // 中文输入结束,解除锁定
+            // console.log('compositionend');
+            inputLock = FALSE;
+          })
+          .on("keyup.bs input.bs paste.bs", function(event) {
+            var word;
+
+            if (event.keyCode) {
+              setBackground($input, options);
             }
 
-            return options.url + type + encodeURIComponent(keyword);
-        }();
-
-        return options._preAjax = $.ajax(ajaxParam).done(function(result) {
-            options.data = options.fnProcessData(result);
-        }).fail(function(err) {
-            if (options.fnAjaxFail) {
-                options.fnAjaxFail(err, options);
+            // 如果弹起的键是回车、向上或向下方向键则返回
+            if (
+              ~$.inArray(event.keyCode, [
+                options.keyDown,
+                options.keyUp,
+                options.keyEnter
+              ])
+            ) {
+              $input.val($input.val()); // 让鼠标输入跳到最后
+              return;
             }
-        });
-    }
-    /**
-     * 检测 keyword 与 value 是否存在互相包含
-     * @param  {String}  keyword 用户输入的关键字
-     * @param  {String}  key     匹配字段的 key
-     * @param  {String}  value   key 字段对应的值
-     * @param  {Object}  options
-     * @return {Boolean}         包含/不包含
-     */
-    function isInWord(keyword, key, value, options) {
-        value = $.trim(value);
-
-        if (options.ignorecase) {
-            keyword = keyword.toLocaleLowerCase();
-            value = value.toLocaleLowerCase();
-        }
 
-        return value &&
-            (inEffectiveFields(key, options) || inSearchFields(key, options)) && // 必须在有效的搜索字段中
-            (
-                ~value.indexOf(keyword) || // 匹配值包含关键字
-                options.twoWayMatch && ~keyword.indexOf(value) // 关键字包含匹配值
-            );
-    }
-    /**
-     * 通过 ajax 或 json 参数获取数据
-     */
-    function getData(keyword, $input, callback, options) {
-        var data, validData, filterData = {
-                value: []
-            },
-            i, key, len,
-            fnPreprocessKeyword = options.fnPreprocessKeyword;
-
-        keyword = keyword || '';
-        // 获取数据前对关键字预处理方法
-        if ($.isFunction(fnPreprocessKeyword)) {
-            keyword = fnPreprocessKeyword(keyword, options);
-        }
+            clearTimeout(keyupTimer);
+            keyupTimer = setTimeout(function() {
+              // console.log('input keyup', event);
 
-        // 给了url参数,则从服务器 ajax 请求
-        // console.log(options.url + keyword);
-        if (options.url) {
-            var timer;
-            if (options.searchingTip) {
-                timer = setTimeout(function() {
-                    showTip(options.searchingTip, $input, $input.parent().find('ul'), options);
-                }, 600);
-            }
+              // 锁定状态,返回
+              if (inputLock) {
+                return;
+              }
 
-            ajax(options, keyword).done(function(result) {
-                callback($input, options.data, options); // 为 refreshDropMenu
-                $input.trigger(onDataRequestSuccess, result);
-                if (options.getDataMethod === 'firstByUrl') {
-                    options.url = null;
-                }
-            }).always(function() {
-                timer && clearTimeout(timer);
-            });
-        } else {
-            // 没有给出 url 参数,则从 data 参数获取
-            data = options.data;
-            validData = checkData(data);
-            // 本地的 data 数据,则在本地过滤
-            if (validData) {
-                if (keyword) {
-                    // 输入不为空时则进行匹配
-                    len = data.value.length;
-                    for (i = 0; i < len; i++) {
-                        for (key in data.value[i]) {
-                            if (
-                                data.value[i][key] &&
-                                isInWord(keyword, key, data.value[i][key] + '', options)
-                            ) {
-                                filterData.value.push(data.value[i]);
-                                filterData.value[filterData.value.length - 1].__index = i;
-                                break;
-                            }
-                        }
-                    }
-                } else {
-                    filterData = data;
-                }
-            }
+              word = $input.val();
 
-            callback($input, filterData, options);
-        } // else
-    }
-    /**
-     * 数据处理
-     * url 获取数据时,对数据的处理,作为 fnGetData 之后的回调处理
-     */
-    function processData(data) {
-        return checkData(data);
-    }
-    /**
-     * 取得 clearable 清除按钮
-     */
-    function getIClear($input, options) {
-        var $iClear = $input.prev('i.clearable');
-
-        // 是否可清除已输入的内容(添加清除按钮)
-        if (options.clearable && !$iClear.length) {
-                $iClear = $('<i class="clearable glyphicon glyphicon-remove fa fa-plus"></i>')
-                    .prependTo($input.parent());
-        }
+              // 若输入框值没有改变则返回
+              if ($.trim(word) && word === setOrGetAlt($input)) {
+                return;
+              }
 
-        return $iClear.css({
-            position: 'absolute',
-            top: 'calc(50% - 6px)',
-            transform: 'rotate(45deg)',
-            // right: options.showBtn ? Math.max($input.next('.input-group-btn').width(), 33) + 2 : 12,
-            zIndex: 4,
-            cursor: 'pointer',
-            width: '14px',
-            lineHeight: '14px',
-            textAlign: 'center',
-            fontSize: 12
-        }).hide();
-    }
-    /**
-     * 默认的配置选项
-     * @type {Object}
-     */
-    var defaultOptions = {
-        url: null,                      // 请求数据的 URL 地址
-        jsonp: null,                    // 设置此参数名,将开启jsonp功能,否则使用json数据结构
-        data: {
-            value: []
-        },                              // 提示所用的数据,注意格式
-        indexId: 0,                     // 每组数据的第几个数据,作为input输入框的 data-id,设为 -1 且 idField 为空则不设置此值
-        indexKey: 0,                    // 每组数据的第几个数据,作为input输入框的内容
-        idField: '',                    // 每组数据的哪个字段作为 data-id,优先级高于 indexId 设置(推荐)
-        keyField: '',                   // 每组数据的哪个字段作为输入框内容,优先级高于 indexKey 设置(推荐)
-
-        /* 搜索相关 */
-        autoSelect: TRUE,               // 键盘向上/下方向键时,是否自动选择值
-        allowNoKeyword: TRUE,           // 是否允许无关键字时请求数据
-        getDataMethod: 'firstByUrl',    // 获取数据的方式,url:一直从url请求;data:从 options.data 获取;firstByUrl:第一次从Url获取全部数据,之后从options.data获取
-        delayUntilKeyup: FALSE,         // 获取数据的方式 为 firstByUrl 时,是否延迟到有输入时才请求数据
-        ignorecase: FALSE,              // 前端搜索匹配时,是否忽略大小写
-        effectiveFields: [],            // 有效显示于列表中的字段,非有效字段都会过滤,默认全部有效。
-        effectiveFieldsAlias: {},       // 有效字段的别名对象,用于 header 的显示
-        searchFields: [],               // 有效搜索字段,从前端搜索过滤数据时使用,但不一定显示在列表中。effectiveFields 配置字段也会用于搜索过滤
-        twoWayMatch: TRUE,              // 是否双向匹配搜索。为 true 即输入关键字包含或包含于匹配字段均认为匹配成功,为 false 则输入关键字包含于匹配字段认为匹配成功
-        multiWord: FALSE,               // 以分隔符号分割的多关键字支持
-        separator: ',',                 // 多关键字支持时的分隔符,默认为半角逗号
-        delay: 300,                     // 搜索触发的延时时间间隔,单位毫秒
-        emptyTip: '',                   // 查询为空时显示的内容,可为 html
-        searchingTip: '搜索中...',       // ajax 搜索时显示的提示内容,当搜索时间较长时给出正在搜索的提示
-        hideOnSelect: FALSE,            // 鼠标从列表单击选择了值时,是否隐藏选择列表
-
-        /* UI */
-        autoDropup: FALSE,              // 选择菜单是否自动判断向上展开。设为 true,则当下拉菜单高度超过窗体,且向上方向不会被窗体覆盖,则选择菜单向上弹出
-        autoMinWidth: FALSE,            // 是否自动最小宽度,设为 false 则最小宽度不小于输入框宽度
-        showHeader: FALSE,              // 是否显示选择列表的 header。为 true 时,有效字段大于一列则显示表头
-        showBtn: TRUE,                  // 是否显示下拉按钮
-        inputBgColor: '',               // 输入框背景色,当与容器背景色不同时,可能需要该项的配置
-        inputWarnColor: 'rgba(255,0,0,.1)', // 输入框内容不是下拉列表选择时的警告色
-        listStyle: {
-            'padding-top': 0,
-            'max-height': '375px',
-            'max-width': '800px',
-            'overflow': 'auto',
-            'width': 'auto',
-            'transition': '0.3s',
-            '-webkit-transition': '0.3s',
-            '-moz-transition': '0.3s',
-            '-o-transition': '0.3s',
-            'word-break': 'keep-all',
-            'white-space': 'nowrap'
-        },                              // 列表的样式控制
-        listAlign: 'left',              // 提示列表对齐位置,left/right/auto
-        listHoverStyle: 'background: #07d; color:#fff', // 提示框列表鼠标悬浮的样式
-        listHoverCSS: 'jhover',         // 提示框列表鼠标悬浮的样式名称
-        clearable: FALSE,               // 是否可清除已输入的内容
-
-        /* key */
-        keyLeft: 37,                    // 向左方向键,不同的操作系统可能会有差别,则自行定义
-        keyUp: 38,                      // 向上方向键
-        keyRight: 39,                   // 向右方向键
-        keyDown: 40,                    // 向下方向键
-        keyEnter: 13,                   // 回车键
-
-        /* methods */
-        fnProcessData: processData,     // 格式化数据的方法,返回数据格式参考 data 参数
-        fnGetData: getData,             // 获取数据的方法,无特殊需求一般不作设置
-        fnAdjustAjaxParam: null,        // 调整 ajax 请求参数方法,用于更多的请求配置需求。如对请求关键字作进一步处理、修改超时时间等
-        fnPreprocessKeyword: null,      // 搜索过滤数据前,对输入关键字作进一步处理方法。注意,应返回字符串
-        fnAjaxFail: null,               // ajax 失败时回调方法
-    };
+              // 当按下键之前记录输入框值,以方便查看键弹起时值有没有变
+              setOrGetAlt($input, word);
 
-    var methods = {
-        init: function(options) {
-            // 参数设置
-            var self = this;
-            options = options || {};
+              if (options.multiWord) {
+                word = word.split(options.separator).reverse()[0];
+              }
 
-            // 默认配置有效显示字段多于一个,则显示列表表头,否则不显示
-            if (isUndefined(options.showHeader) && options.effectiveFields && options.effectiveFields.length > 1) {
-                options.showHeader = TRUE;
+              // 是否允许空数据查询
+              if (!word.length && !options.allowNoKeyword) {
+                return;
+              }
+
+              options.fnGetData($.trim(word), $input, refreshDropMenu, options);
+            }, options.delay || 300);
+          })
+          .on("focus.bs", function() {
+            // console.log('input focus');
+            adjustDropMenuPos($input, $dropdownMenu, options);
+          })
+          .on("blur.bs", function() {
+            if (!isMouseenterMenu) {
+              // 不是进入下拉列表状态,则隐藏列表
+              hideDropMenu($input, options);
+              inputLock = true;
+              setTimeout(function() {
+                inputLock = FALSE;
+              });
             }
+          })
+          .on("click.bs", function() {
+            // console.log('input click');
+            var word = $input.val();
 
-            options = $.extend(TRUE, {}, defaultOptions, options);
-
-            // 旧的方法兼容
-            if (options.processData) {
-                options.fnProcessData = options.processData;
+            if (
+              $.trim(word) &&
+              word === setOrGetAlt($input) &&
+              $dropdownMenu.find("table tr").length
+            ) {
+              return showDropMenu($input, options);
             }
 
-            if (options.getData) {
-                options.fnGetData = options.getData;
+            if ($dropdownMenu.is(":visible")) {
+              return;
             }
 
-            if (options.getDataMethod === 'firstByUrl' && options.url && !options.delayUntilKeyup) {
-                ajax(options).done(function(result) {
-                    options.url = null;
-                    self.trigger(onDataRequestSuccess, result);
-                });
+            if (options.multiWord) {
+              word = word.split(options.separator).reverse()[0];
             }
 
-            // 鼠标滑动到条目样式
-            if (!$('#' + BSSUGGEST).length) {
-                $('head:eq(0)').append('<style id="' + BSSUGGEST + '">.' + options.listHoverCSS + '{' + options.listHoverStyle + '}</style>');
+            // 是否允许空数据查询
+            if (!word.length && !options.allowNoKeyword) {
+              return;
             }
 
-            return self.each(function() {
-                var $input = $(this),
-                    $parent = $input.parent(),
-                    $iClear = getIClear($input, options),
-                    isMouseenterMenu,
-                    keyupTimer, // keyup 与 input 事件延时定时器
-                    $dropdownMenu = $parent.find('ul:eq(0)');
-
-                // 兼容 bs4
-                $dropdownMenu.parent().css('position', 'relative');
-
-                // 验证输入框对象是否符合条件
-                if (!checkInput($input, $dropdownMenu, options)) {
-                    console.warn('不是一个标准的 bootstrap 下拉式菜单或已初始化:', $input);
-                    return;
-                }
-
-                // 是否显示 button 按钮
-                if (!options.showBtn) {
-                    $input.css('borderRadius', 4);
-                    $parent.css('width', '100%')
-                        .find('.btn:eq(0)').hide();
-                }
-
-                // 移除 disabled 类,并禁用自动完成
-                $input.removeClass(DISABLED).prop(DISABLED, FALSE).attr('autocomplete', 'off');
-                // dropdown-menu 增加修饰
-                $dropdownMenu.css(options.listStyle);
-
-                // 默认背景色
-                if (!options.inputBgColor) {
-                    options.inputBgColor = $input.css('backgroundColor');
-                }
-
-                // 开始事件处理
-                $input.on('keydown', function(event) {
-                    var currentList, tipsKeyword; // 提示列表上被选中的关键字
-
-                    // 当提示层显示时才对键盘事件处理
-                    if (!$dropdownMenu.is(':visible')) {
-                        setOrGetDataId($input, '');
-                        return;
-                    }
-
-                    currentList = $dropdownMenu.find('.' + options.listHoverCSS);
-                    tipsKeyword = ''; // 提示列表上被选中的关键字
-
-                    unHoverAll($dropdownMenu, options);
-
-                    if (event.keyCode === options.keyDown) { // 如果按的是向下方向键
-                        if (!currentList.length) {
-                            // 如果提示列表没有一个被选中,则将列表第一个选中
-                            tipsKeyword = getPointKeyword($dropdownMenu.find('tbody tr:first').mouseover());
-                        } else if (!currentList.next().length) {
-                            // 如果是最后一个被选中,则取消选中,即可认为是输入框被选中,并恢复输入的值
-                            if (options.autoSelect) {
-                                setOrGetDataId($input, '').val(setOrGetAlt($input));
-                            }
-                        } else {
-                            // 选中下一行
-                            tipsKeyword = getPointKeyword(currentList.next().mouseover());
-                        }
-                        // 控制滑动条
-                        adjustScroll($input, $dropdownMenu, options);
-
-                        if (!options.autoSelect) {
-                            return;
-                        }
-                    } else if (event.keyCode === options.keyUp) { // 如果按的是向上方向键
-                        if (!currentList.length) {
-                            tipsKeyword = getPointKeyword($dropdownMenu.find('tbody tr:last').mouseover());
-                        } else if (!currentList.prev().length) {
-                            if (options.autoSelect) {
-                                setOrGetDataId($input, '').val(setOrGetAlt($input));
-                            }
-                        } else {
-                            // 选中前一行
-                            tipsKeyword = getPointKeyword(currentList.prev().mouseover());
-                        }
-
-                        // 控制滑动条
-                        adjustScroll($input, $dropdownMenu, options);
-
-                        if (!options.autoSelect) {
-                            return;
-                        }
-                    } else if (event.keyCode === options.keyEnter) {
-                        tipsKeyword = getPointKeyword(currentList);
-                        hideDropMenu($input, options);
-                    } else {
-                        setOrGetDataId($input, '');
-                    }
-
-                    // 设置值 tipsKeyword
-                    // console.log(tipsKeyword);
-                    setValue($input, tipsKeyword, options);
-                }).on('compositionstart', function(event) {
-                    // 中文输入开始,锁定
-                    // console.log('compositionstart');
-                    inputLock = TRUE;
-                }).on('compositionend', function(event) {
-                    // 中文输入结束,解除锁定
-                    // console.log('compositionend');
-                    inputLock = FALSE;
-                }).on('keyup input paste', function(event) {
-                    var word;
-
-                    if (event.keyCode) {
-                        setBackground($input, options);
-                    }
-
-                    // 如果弹起的键是回车、向上或向下方向键则返回
-                    if (~$.inArray(event.keyCode, [options.keyDown, options.keyUp, options.keyEnter])) {
-                        $input.val($input.val()); // 让鼠标输入跳到最后
-                        return;
-                    }
-
-                    clearTimeout(keyupTimer);
-                    keyupTimer = setTimeout(function() {
-                        // console.log('input keyup', event);
-
-                        // 锁定状态,返回
-                        if (inputLock) {
-                            return;
-                        }
-
-                        word = $input.val();
-
-                        // 若输入框值没有改变则返回
-                        if ($.trim(word) && word === setOrGetAlt($input)) {
-                            return;
-                        }
-
-                        // 当按下键之前记录输入框值,以方便查看键弹起时值有没有变
-                        setOrGetAlt($input, word);
-
-                        if (options.multiWord) {
-                            word = word.split(options.separator).reverse()[0];
-                        }
-
-                        // 是否允许空数据查询
-                        if (!word.length && !options.allowNoKeyword) {
-                            return;
-                        }
-
-                        options.fnGetData($.trim(word), $input, refreshDropMenu, options);
-                    }, options.delay || 300);
-                }).on('focus', function() {
-                    // console.log('input focus');
-                    adjustDropMenuPos($input, $dropdownMenu, options);
-                }).on('blur', function() {
-                    if (!isMouseenterMenu) { // 不是进入下拉列表状态,则隐藏列表
-                        hideDropMenu($input, options);
-                    }
-                }).on('click', function() {
-                    // console.log('input click');
-                    var word = $input.val();
-
-                    if (
-                        $.trim(word) &&
-                        word === setOrGetAlt($input) &&
-                        $dropdownMenu.find('table tr').length
-                    ) {
-                        return showDropMenu($input, options);
-                    }
-
-                    if ($dropdownMenu.is(':visible')) {
-                        return;
-                    }
-
-                    if (options.multiWord) {
-                        word = word.split(options.separator).reverse()[0];
-                    }
-
-                    // 是否允许空数据查询
-                    if (!word.length && !options.allowNoKeyword) {
-                        return;
-                    }
-
-                    // console.log('word', word);
-                    options.fnGetData($.trim(word), $input, refreshDropMenu, options);
-                });
-
-                // 下拉按钮点击时
-                $parent.find('.btn:eq(0)').attr('data-toggle', '').click(function() {
-                    if (!$dropdownMenu.is(':visible')) {
-                        if (options.url) {
-                            $input.click().focus();
-                            if (!$dropdownMenu.find('tr').length) {
-                                return FALSE;
-                            }
-                        } else {
-                            // 不以 keyword 作为过滤,展示所有的数据
-                            refreshDropMenu($input, options.data, options);
-                        }
-                        showDropMenu($input, options);
-                    } else {
-                        hideDropMenu($input, options);
-                    }
-
-                    return FALSE;
-                });
-
-                // 列表中滑动时,输入框失去焦点
-                $dropdownMenu.mouseenter(function() {
-                        // console.log('mouseenter')
-                        isMouseenterMenu = 1;
-                        $input.blur();
-                    }).mouseleave(function() {
-                        // console.log('mouseleave')
-                        isMouseenterMenu = 0;
-                        $input.focus();
-                    }).on('mouseenter', 'tbody tr', function() {
-                        // 行上的移动事件
-                        unHoverAll($dropdownMenu, options);
-                        $(this).addClass(options.listHoverCSS);
-
-                        return FALSE; // 阻止冒泡
-                    })
-                    .on('mousedown', 'tbody tr', function() {
-                        var keywords = getPointKeyword($(this));
-                        setValue($input, keywords, options);
-                        setOrGetAlt($input, keywords.key);
-                        setBackground($input, options);
-
-                        if (options.hideOnSelect) {
-                            hideDropMenu($input, options);
-                        }
-                    });
-
-                // 存在清空按钮
-                if ($iClear.length) {
-                    $iClear.click(function () {
-                        setOrGetDataId($input, '').val('');
-                        setBackground($input, options);
-                    });
-
-                    $parent.mouseenter(function() {
-                        if (!$input.prop(DISABLED)) {
-                            $iClear.css('right', options.showBtn ? Math.max($input.next().width(), 33) + 2 : 12)
-                                .show();
-                        }
-                    }).mouseleave(function() {
-                        $iClear.hide();
-                    });
+            // console.log('word', word);
+            options.fnGetData($.trim(word), $input, refreshDropMenu, options);
+          });
+
+        // 下拉按钮点击时
+        $parent
+          .find(".btn:eq(0)")
+          .attr("data-toggle", "")
+          .click(function() {
+            if (!$dropdownMenu.is(":visible")) {
+              if (options.url) {
+                $input.click().focus();
+                if (!$dropdownMenu.find("tr").length) {
+                  return FALSE;
                 }
+              } else {
+                // 不以 keyword 作为过滤,展示所有的数据
+                refreshDropMenu($input, options.data, options);
+              }
+              showDropMenu($input, options);
+            } else {
+              hideDropMenu($input, options);
+            }
 
+            return FALSE;
+          });
+
+        // 列表中滑动时,输入框失去焦点
+        $dropdownMenu
+          .mouseenter(function() {
+            // console.log('mouseenter')
+            isMouseenterMenu = 1;
+            $input.blur();
+          })
+          .mouseleave(function() {
+            // console.log('mouseleave')
+            isMouseenterMenu = 0;
+            $input.focus();
+          })
+          .on("mouseenter", "tbody tr", function() {
+            // 行上的移动事件
+            unHoverAll($dropdownMenu, options);
+            $(this).addClass(options.listHoverCSS);
+
+            return FALSE; // 阻止冒泡
+          })
+          .on("mousedown", "tbody tr", function() {
+            var keywords = getPointKeyword($(this));
+            setValue($input, keywords, options);
+            setOrGetAlt($input, keywords.key);
+            setBackground($input, options);
+
+            if (options.hideOnSelect) {
+              hideDropMenu($input, options);
+            }
+          });
+
+        // 存在清空按钮
+        if ($iClear.length) {
+          $iClear.click(function() {
+            setOrGetDataId($input, "").val("");
+            setBackground($input, options);
+          });
+
+          $parent
+            .mouseenter(function() {
+              if (!$input.prop(DISABLED)) {
+                $iClear
+                  .css(
+                    "right",
+                    options.showBtn
+                      ? Math.max($input.next().width(), 33) + 2
+                      : 12
+                  )
+                  .show();
+              }
+            })
+            .mouseleave(function() {
+              $iClear.hide();
             });
-        },
-        show: function() {
-            return this.each(function() {
-                $(this).click();
-            });
-        },
-        hide: function() {
-            return this.each(function() {
-                hideDropMenu($(this));
-            });
-        },
-        disable: function() {
-            return this.each(function() {
-                $(this).attr(DISABLED, TRUE)
-                    .parent().find('.btn:eq(0)').prop(DISABLED, TRUE);
-            });
-        },
-        enable: function() {
-            return this.each(function() {
-                $(this).attr(DISABLED, FALSE)
-                    .parent().find('.btn:eq(0)').prop(DISABLED, FALSE);
-            });
-        },
-        destroy: function() {
-            return this.each(function() {
-                $(this).off().removeData(BSSUGGEST).removeAttr('style')
-                    .parent().find('.btn:eq(0)').off().show().attr('data-toggle', 'dropdown').prop(DISABLED, FALSE) // .addClass(DISABLED);
-                    .next().css('display', '').off();
-            });
-        },
-        version: function() {
-            return VERSION;
         }
-    };
-
-    $.fn[BSSUGGEST] = function(options) {
-        // 方法判断
-        if (typeof options === 'string' && methods[options]) {
-            var inited = TRUE;
-            this.each(function() {
-                if (!$(this).data(BSSUGGEST)) {
-                    return inited = FALSE;
-                }
-            });
-            // 只要有一个未初始化,则全部都不执行方法,除非是 init 或 version
-            if (!inited && 'init' !== options && 'version' !== options) {
-                return this;
-            }
-
-            // 如果是方法,则参数第一个为函数名,从第二个开始为函数参数
-            return methods[options].apply(this, [].slice.call(arguments, 1));
-        } else {
-            // 调用初始化方法
-            return methods.init.apply(this, arguments);
+      });
+    },
+    show: function() {
+      return this.each(function() {
+        $(this).click();
+      });
+    },
+    hide: function() {
+      return this.each(function() {
+        hideDropMenu($(this));
+      });
+    },
+    disable: function() {
+      return this.each(function() {
+        $(this)
+          .attr(DISABLED, TRUE)
+          .parent()
+          .find(".btn:eq(0)")
+          .prop(DISABLED, TRUE);
+      });
+    },
+    enable: function() {
+      return this.each(function() {
+        $(this)
+          .attr(DISABLED, FALSE)
+          .parent()
+          .find(".btn:eq(0)")
+          .prop(DISABLED, FALSE);
+      });
+    },
+    destroy: function() {
+      return this.each(function() {
+        var evNameList =
+          "click.bs keydown.bs compositionstart.bs compositionend.bs keyup.bs input.bs paste.bs focus.bs click.bs";
+        $(this)
+          .off(evNameList)
+          .removeData(BSSUGGEST)
+          .removeAttr("style")
+          .parent()
+          .find(".btn:eq(0)")
+          .off()
+          .show()
+          .attr("data-toggle", "dropdown")
+          .prop(DISABLED, FALSE) // .addClass(DISABLED);
+          .next()
+          .css("display", "")
+          .off();
+      });
+    },
+    version: function() {
+      return VERSION;
+    }
+  };
+
+  $.fn[BSSUGGEST] = function(options) {
+    // 方法判断
+    if (typeof options === "string" && methods[options]) {
+      var inited = TRUE;
+      this.each(function() {
+        if (!$(this).data(BSSUGGEST)) {
+          return (inited = FALSE);
         }
+      });
+      // 只要有一个未初始化,则全部都不执行方法,除非是 init 或 version
+      if (!inited && "init" !== options && "version" !== options) {
+        return this;
+      }
+
+      // 如果是方法,则参数第一个为函数名,从第二个开始为函数参数
+      return methods[options].apply(this, [].slice.call(arguments, 1));
+    } else {
+      // 调用初始化方法
+      return methods.init.apply(this, arguments);
     }
-});
+  };
+});

File diff suppressed because it is too large
+ 2 - 2
ruoyi-admin/src/main/resources/static/ajax/libs/suggest/bootstrap-suggest.min.js


+ 4 - 4
ruoyi-admin/src/main/resources/templates/demo/form/autocomplete.html

@@ -18,7 +18,7 @@
                                 <div class="input-group">
                                     <input type="text" class="form-control" id="suggest-demo-1">
                                     <div class="input-group-btn">
-                                        <button type="button" class="btn btn-white dropdown-toggle" data-toggle="dropdown">
+                                        <button type="button" class="btn btn-white dropdown-toggle" style="height: 31px" data-toggle="dropdown">
                                             <span class="caret"></span>
                                         </button>
                                         <ul class="dropdown-menu dropdown-menu-right" role="menu">
@@ -50,7 +50,7 @@
                                 <div class="input-group">
                                     <input type="text" class="form-control" id="suggest-demo-3">
                                     <div class="input-group-btn">
-                                        <button type="button" class="btn btn-white dropdown-toggle" data-toggle="dropdown">
+                                        <button type="button" class="btn btn-white dropdown-toggle" style="height: 31px" data-toggle="dropdown">
                                             <span class="caret"></span>
                                         </button>
                                         <ul class="dropdown-menu dropdown-menu-right" role="menu">
@@ -68,7 +68,7 @@
                                 <div class="input-group" style="width: 300px;">
                                     <input type="text" class="form-control" id="baidu">
                                     <div class="input-group-btn">
-                                        <button type="button" class="btn btn-white dropdown-toggle" data-toggle="dropdown">
+                                        <button type="button" class="btn btn-white dropdown-toggle" style="height: 31px" data-toggle="dropdown">
                                             <span class="caret"></span>
                                         </button>
                                         <ul class="dropdown-menu dropdown-menu-right" role="menu">
@@ -86,7 +86,7 @@
                                 <div class="input-group" style="width: 400px;">
                                     <input type="text" class="form-control" id="taobao">
                                     <div class="input-group-btn">
-                                        <button type="button" class="btn btn-white dropdown-toggle" data-toggle="dropdown">
+                                        <button type="button" class="btn btn-white dropdown-toggle" style="height: 31px" data-toggle="dropdown">
                                             <span class="caret"></span>
                                         </button>
                                         <ul class="dropdown-menu dropdown-menu-right" role="menu">

+ 1 - 1
ruoyi-admin/src/main/resources/templates/include.html

@@ -124,7 +124,7 @@
 
 <!-- suggest搜索自动补全 -->
 <div th:fragment="bootstrap-suggest-js">
-    <script th:src="@{/ajax/libs/suggest/bootstrap-suggest.min.js}"></script>
+    <script th:src="@{/ajax/libs/suggest/bootstrap-suggest.min.js?v=0.1.29}"></script>
 </div>
 
 <!-- typeahead搜索自动补全 -->

Some files were not shown because too many files changed in this diff