diff --git a/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js b/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js
new file mode 100644
index 0000000..5a394bf
--- /dev/null
+++ b/assets/bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js
@@ -0,0 +1,589 @@
+/* ==========================================================
+ * bootstrap-maxlength.js v1.9.0
+ *
+ * Copyright (c) 2013-2020 Maurizio Napoleoni;
+ *
+ * Licensed under the terms of the MIT license.
+ * See: https://github.com/mimo84/bootstrap-maxlength/blob/master/LICENSE
+ * ========================================================== */
+/*global jQuery*/
+
+(function ($) {
+ 'use strict';
+ /**
+ * We need an event when the elements are destroyed
+ * because if an input is removed, we have to remove the
+ * maxlength object associated (if any).
+ * From:
+ * http://stackoverflow.com/questions/2200494/jquery-trigger-event-when-an-element-is-removed-from-the-dom
+ */
+ if (!$.event.special.destroyed) {
+ $.event.special.destroyed = {
+ remove: function (o) {
+ if (o.handler) {
+ o.handler();
+ }
+ }
+ };
+ }
+
+
+ $.fn.extend({
+ maxlength: function (options, callback) {
+ var documentBody = $('body'),
+ defaults = {
+ showOnReady: false, // true to always show when indicator is ready
+ alwaysShow: true, // if true the indicator it's always shown.
+ threshold: 0, // Represents how many chars left are needed to show up the counter
+ warningClass: 'small form-text text-muted',
+ limitReachedClass: 'small form-text text-danger',
+ separator: ' / ',
+ preText: '',
+ postText: '',
+ showMaxLength: true,
+ placement: 'bottom-right-inside',
+ message: null, // an alternative way to provide the message text
+ showCharsTyped: true, // show the number of characters typed and not the number of characters remaining
+ validate: false, // if the browser doesn't support the maxlength attribute, attempt to type more than the indicated chars, will be prevented.
+ utf8: false, // counts using bytesize rather than length. eg: '£' is counted as 2 characters.
+ appendToParent: false, // append the indicator to the input field's parent instead of body
+ twoCharLinebreak: true, // count linebreak as 2 characters to match IE/Chrome textarea validation. As well as DB storage.
+ customMaxAttribute: null, // null = use maxlength attribute and browser functionality, string = use specified attribute instead.
+ allowOverMax: false, // Form submit validation is handled on your own. when maxlength has been exceeded 'overmax' class added to element
+ zIndex: 1099
+ };
+
+ if ($.isFunction(options) && !callback) {
+ callback = options;
+ options = {};
+ }
+ options = $.extend(defaults, options);
+
+
+ /**
+ * Return the byte count of the specified character in UTF8 encoding.
+ * Note: This won't cover UTF-8 characters that are 4 bytes long.
+ *
+ * @param input
+ * @return {number}
+ */
+ function utf8CharByteCount(character) {
+ var c = character.charCodeAt();
+ // Not c then 0, else c < 128 then 1, else c < 2048 then 2, else 3
+ return !c ? 0 : c < 128 ? 1 : c < 2048 ? 2 : 3;
+ }
+
+ /**
+ * Return the length of the specified input in UTF8 encoding.
+ *
+ * @param input
+ * @return {number}
+ */
+ function utf8Length(string) {
+ return string.split("")
+ .map(utf8CharByteCount)
+ // Prevent reduce from throwing an error if the string is empty.
+ .concat(0)
+ .reduce(function (sum, val) {
+ return sum + val;
+ });
+ }
+
+ /**
+ * Return the length of the specified input.
+ *
+ * @param input
+ * @return {number}
+ */
+ function inputLength(input) {
+ var text = input.val();
+
+ if (options.twoCharLinebreak) {
+ // Count all line breaks as 2 characters
+ text = text.replace(/\r(?!\n)|\n(?!\r)/g, '\r\n');
+ } else {
+ // Remove all double-character (\r\n) linebreaks, so they're counted only once.
+ text = text.replace(/(?:\r\n|\r|\n)/g, '\n');
+ }
+
+ var currentLength = 0;
+
+ if (options.utf8) {
+ currentLength = utf8Length(text);
+ } else {
+ currentLength = text.length;
+ }
+
+ // Remove "C:\fakepath\" from counter when using file input
+ // Fix https://github.com/mimo84/bootstrap-maxlength/issues/146
+ if (input.prop("type") === "file" && input.val() !== "") {
+ currentLength -= 12;
+ }
+
+ return currentLength;
+ }
+
+ /**
+ * Truncate the text of the specified input.
+ *
+ * @param input
+ * @param limit
+ */
+ function truncateChars(input, maxlength) {
+ var text = input.val();
+
+ if (options.twoCharLinebreak) {
+ text = text.replace(/\r(?!\n)|\n(?!\r)/g, '\r\n');
+
+ if (text[text.length - 1] === '\n') {
+ maxlength -= text.length % 2;
+ }
+ }
+
+ if (options.utf8) {
+ var indexedSize = text.split("").map(utf8CharByteCount);
+ for (
+ var removedBytes = 0,
+ bytesPastMax = utf8Length(text) - maxlength; removedBytes < bytesPastMax; removedBytes += indexedSize.pop()
+ );
+ maxlength -= (maxlength - indexedSize.length);
+ }
+
+ input.val(text.substr(0, maxlength));
+ }
+
+ /**
+ * Return true if the indicator should be showing up.
+ *
+ * @param input
+ * @param threshold
+ * @param maxlength
+ * @return {number}
+ */
+ function charsLeftThreshold(input, threshold, maxlength) {
+ var output = true;
+ if (!options.alwaysShow && (maxlength - inputLength(input) > threshold)) {
+ output = false;
+ }
+ return output;
+ }
+
+ /**
+ * Returns how many chars are left to complete the fill up of the form.
+ *
+ * @param input
+ * @param maxlength
+ * @return {number}
+ */
+ function remainingChars(input, maxlength) {
+ var length = maxlength - inputLength(input);
+ return length;
+ }
+
+ /**
+ * When called displays the indicator.
+ *
+ * @param indicator
+ */
+ function showRemaining(currentInput, indicator) {
+ indicator.css({
+ display: 'block'
+ });
+ currentInput.trigger('maxlength.shown');
+ }
+
+ /**
+ * When called shows the indicator.
+ *
+ * @param indicator
+ */
+ function hideRemaining(currentInput, indicator) {
+
+ if (options.alwaysShow) {
+ return;
+ }
+
+ indicator.css({
+ display: 'none'
+ });
+ currentInput.trigger('maxlength.hidden');
+ }
+
+ /**
+ * This function updates the value in the indicator
+ *
+ * @param maxLengthThisInput
+ * @param typedChars
+ * @return String
+ */
+ function updateMaxLengthHTML(currentInputText, maxLengthThisInput, typedChars) {
+ var output = '';
+ if (options.message) {
+ if (typeof options.message === 'function') {
+ output = options.message(currentInputText, maxLengthThisInput);
+ } else {
+ output = options.message.replace('%charsTyped%', typedChars)
+ .replace('%charsRemaining%', maxLengthThisInput - typedChars)
+ .replace('%charsTotal%', maxLengthThisInput);
+ }
+ } else {
+ if (options.preText) {
+ output += options.preText;
+ }
+ if (!options.showCharsTyped) {
+ output += maxLengthThisInput - typedChars;
+ } else {
+ output += typedChars;
+ }
+ if (options.showMaxLength) {
+ output += options.separator + maxLengthThisInput;
+ }
+ if (options.postText) {
+ output += options.postText;
+ }
+ }
+ return output;
+ }
+
+ /**
+ * This function updates the value of the counter in the indicator.
+ * Wants as parameters: the number of remaining chars, the element currently managed,
+ * the maxLength for the current input and the indicator generated for it.
+ *
+ * @param remaining
+ * @param currentInput
+ * @param maxLengthCurrentInput
+ * @param maxLengthIndicator
+ */
+ function manageRemainingVisibility(remaining, currentInput, maxLengthCurrentInput, maxLengthIndicator) {
+ if (maxLengthIndicator) {
+ maxLengthIndicator.html(updateMaxLengthHTML(currentInput.val(), maxLengthCurrentInput, (maxLengthCurrentInput - remaining)));
+
+ if (remaining > 0) {
+ if (charsLeftThreshold(currentInput, options.threshold, maxLengthCurrentInput)) {
+ showRemaining(currentInput, maxLengthIndicator.removeClass(options.limitReachedClass).addClass(options.warningClass));
+ } else {
+ hideRemaining(currentInput, maxLengthIndicator);
+ }
+ } else {
+ showRemaining(currentInput, maxLengthIndicator.removeClass(options.warningClass).addClass(options.limitReachedClass));
+ }
+ }
+
+ if (options.customMaxAttribute) {
+ // class to use for form validation on custom maxlength attribute
+ if (remaining < 0) {
+ currentInput.addClass('overmax');
+ } else {
+ currentInput.removeClass('overmax');
+ }
+ }
+ }
+
+ /**
+ * This function returns an object containing all the
+ * informations about the position of the current input
+ *
+ * @param currentInput
+ * @return object {bottom height left right top width}
+ *
+ */
+ function getPosition(currentInput) {
+ var el = currentInput[0];
+ return $.extend({}, (typeof el.getBoundingClientRect === 'function') ? el.getBoundingClientRect() : {
+ width: el.offsetWidth,
+ height: el.offsetHeight
+ }, currentInput.offset());
+ }
+
+ /**
+ * This function places the maxLengthIndicator based on placement config object.
+ *
+ * @param {object} placement
+ * @param {$} maxLengthIndicator
+ * @return null
+ *
+ */
+ function placeWithCSS(placement, maxLengthIndicator) {
+ if (!placement || !maxLengthIndicator) {
+ return;
+ }
+
+ var POSITION_KEYS = [
+ 'top',
+ 'bottom',
+ 'left',
+ 'right',
+ 'position'
+ ];
+
+ var cssPos = {};
+
+ // filter css properties to position
+ $.each(POSITION_KEYS, function (i, key) {
+ var val = options.placement[key];
+ if (typeof val !== 'undefined') {
+ cssPos[key] = val;
+ }
+ });
+
+ maxLengthIndicator.css(cssPos);
+
+ return;
+ }
+
+
+ /**
+ * This function places the maxLengthIndicator at the
+ * top / bottom / left / right of the currentInput
+ *
+ * @param currentInput
+ * @param maxLengthIndicator
+ * @return null
+ *
+ */
+ function place(currentInput, maxLengthIndicator) {
+ var pos = getPosition(currentInput);
+
+ // Supports custom placement handler
+ if ($.type(options.placement) === 'function') {
+ options.placement(currentInput, maxLengthIndicator, pos);
+ return;
+ }
+
+ // Supports custom placement via css positional properties
+ if ($.isPlainObject(options.placement)) {
+ placeWithCSS(options.placement, maxLengthIndicator);
+ return;
+ }
+
+ var inputOuter = currentInput.outerWidth(),
+ outerWidth = maxLengthIndicator.outerWidth(),
+ actualWidth = maxLengthIndicator.width(),
+ actualHeight = maxLengthIndicator.height();
+
+ // get the right position if the indicator is appended to the input's parent
+ if (options.appendToParent) {
+ pos.top -= currentInput.parent().offset().top;
+ pos.left -= currentInput.parent().offset().left;
+ }
+
+ switch (options.placement) {
+ case 'bottom':
+ maxLengthIndicator.css({
+ top: pos.top + pos.height,
+ left: pos.left + pos.width / 2 - actualWidth / 2
+ });
+ break;
+ case 'top':
+ maxLengthIndicator.css({
+ top: pos.top - actualHeight,
+ left: pos.left + pos.width / 2 - actualWidth / 2
+ });
+ break;
+ case 'left':
+ maxLengthIndicator.css({
+ top: pos.top + pos.height / 2 - actualHeight / 2,
+ left: pos.left - actualWidth
+ });
+ break;
+ case 'right':
+ maxLengthIndicator.css({
+ top: pos.top + pos.height / 2 - actualHeight / 2,
+ left: pos.left + pos.width
+ });
+ break;
+ case 'bottom-right':
+ maxLengthIndicator.css({
+ top: pos.top + pos.height,
+ left: pos.left + pos.width
+ });
+ break;
+ case 'top-right':
+ maxLengthIndicator.css({
+ top: pos.top - actualHeight,
+ left: pos.left + inputOuter
+ });
+ break;
+ case 'top-left':
+ maxLengthIndicator.css({
+ top: pos.top - actualHeight,
+ left: pos.left - outerWidth
+ });
+ break;
+ case 'bottom-left':
+ maxLengthIndicator.css({
+ top: pos.top + currentInput.outerHeight(),
+ left: pos.left - outerWidth
+ });
+ break;
+ case 'centered-right':
+ maxLengthIndicator.css({
+ top: pos.top + (actualHeight / 2),
+ left: pos.left + inputOuter - outerWidth - 3
+ });
+ break;
+
+ // Some more options for placements
+ case 'bottom-right-inside':
+ maxLengthIndicator.css({
+ top: pos.top + pos.height,
+ left: pos.left + pos.width - outerWidth
+ });
+ break;
+ case 'top-right-inside':
+ maxLengthIndicator.css({
+ top: pos.top - actualHeight,
+ left: pos.left + inputOuter - outerWidth
+ });
+ break;
+ case 'top-left-inside':
+ maxLengthIndicator.css({
+ top: pos.top - actualHeight,
+ left: pos.left
+ });
+ break;
+ case 'bottom-left-inside':
+ maxLengthIndicator.css({
+ top: pos.top + currentInput.outerHeight(),
+ left: pos.left
+ });
+ break;
+ }
+ }
+
+ /**
+ * This function returns true if the indicator position needs to
+ * be recalculated when the currentInput changes
+ *
+ * @return {boolean}
+ *
+ */
+ function isPlacementMutable() {
+ return options.placement === 'bottom-right-inside' || options.placement === 'top-right-inside' || typeof options.placement === 'function' || (options.message && typeof options.message === 'function');
+ }
+
+ /**
+ * This function retrieves the maximum length of currentInput
+ *
+ * @param currentInput
+ * @return {number}
+ *
+ */
+ function getMaxLength(currentInput) {
+ var max = currentInput.attr('maxlength') || options.customMaxAttribute;
+
+ if (options.customMaxAttribute && !options.allowOverMax) {
+ var custom = currentInput.attr(options.customMaxAttribute);
+ if (!max || custom < max) {
+ max = custom;
+ }
+ }
+
+ if (!max) {
+ max = currentInput.attr('size');
+ }
+ return max;
+ }
+
+ return this.each(function () {
+
+ var currentInput = $(this),
+ maxLengthCurrentInput,
+ maxLengthIndicator;
+
+ $(window).resize(function () {
+ if (maxLengthIndicator) {
+ place(currentInput, maxLengthIndicator);
+ }
+ });
+
+ function firstInit() {
+ var maxlengthContent = updateMaxLengthHTML(currentInput.val(), maxLengthCurrentInput, '0');
+ maxLengthCurrentInput = getMaxLength(currentInput);
+
+ if (!maxLengthIndicator) {
+ maxLengthIndicator = $('').css({
+ display: 'none',
+ position: 'absolute',
+ whiteSpace: 'nowrap',
+ zIndex: options.zIndex
+ }).html(maxlengthContent);
+ }
+
+ // We need to detect resizes if we are dealing with a textarea:
+ if (currentInput.is('textarea')) {
+ currentInput.data('maxlenghtsizex', currentInput.outerWidth());
+ currentInput.data('maxlenghtsizey', currentInput.outerHeight());
+
+ currentInput.mouseup(function () {
+ if (currentInput.outerWidth() !== currentInput.data('maxlenghtsizex') || currentInput.outerHeight() !== currentInput.data('maxlenghtsizey')) {
+ place(currentInput, maxLengthIndicator);
+ }
+
+ currentInput.data('maxlenghtsizex', currentInput.outerWidth());
+ currentInput.data('maxlenghtsizey', currentInput.outerHeight());
+ });
+ }
+
+ if (options.appendToParent) {
+ currentInput.parent().append(maxLengthIndicator);
+ currentInput.parent().css('position', 'relative');
+ } else {
+ documentBody.append(maxLengthIndicator);
+ }
+
+ var remaining = remainingChars(currentInput, getMaxLength(currentInput));
+ manageRemainingVisibility(remaining, currentInput, maxLengthCurrentInput, maxLengthIndicator);
+ place(currentInput, maxLengthIndicator);
+ }
+
+ if (options.showOnReady) {
+ currentInput.ready(function () {
+ firstInit();
+ });
+ } else {
+ currentInput.focus(function () {
+ firstInit();
+ });
+ }
+
+ currentInput.on('maxlength.reposition', function () {
+ place(currentInput, maxLengthIndicator);
+ });
+
+
+ currentInput.on('destroyed', function () {
+ if (maxLengthIndicator) {
+ maxLengthIndicator.remove();
+ }
+ });
+
+ currentInput.on('blur', function () {
+ if (maxLengthIndicator && !options.showOnReady) {
+ maxLengthIndicator.remove();
+ }
+ });
+
+ currentInput.on('input', function () {
+ var maxlength = getMaxLength(currentInput),
+ remaining = remainingChars(currentInput, maxlength),
+ output = true;
+
+ if (options.validate && remaining < 0) {
+ truncateChars(currentInput, maxlength);
+ output = false;
+ } else {
+ manageRemainingVisibility(remaining, currentInput, maxLengthCurrentInput, maxLengthIndicator);
+ }
+
+ if (isPlacementMutable()) {
+ place(currentInput, maxLengthIndicator);
+ }
+
+ return output;
+ });
+ });
+ }
+ });
+}(jQuery));
\ No newline at end of file
diff --git a/assets/bootstrap/js/index.min.js b/assets/bootstrap/js/index.min.js
index 49884cb..b85f6bd 100644
--- a/assets/bootstrap/js/index.min.js
+++ b/assets/bootstrap/js/index.min.js
@@ -113,7 +113,7 @@
// 选项卡
$('#iframe-content').multitabs({
iframe : true,
- refresh : 'no', // iframe中页面是否刷新,'no':'从不刷新','nav':'点击菜单刷新','all':'菜单和tab点击都刷新'
+ refresh : 'nav', // iframe中页面是否刷新,'no':'从不刷新','nav':'点击菜单刷新','all':'菜单和tab点击都刷新'
nav: {
backgroundColor: '#ffffff',
maxTabs : 35, // 选项卡最大值
diff --git a/assets/bootstrap/js/jquery.pagination.js b/assets/bootstrap/js/jquery.pagination.js
new file mode 100644
index 0000000..771e816
--- /dev/null
+++ b/assets/bootstrap/js/jquery.pagination.js
@@ -0,0 +1,292 @@
+/**
+ * pagination.js 1.5.1
+ * A jQuery plugin to provide simple yet fully customisable pagination.
+ * @version 1.5.1
+ * @author mss
+ * @url https://github.com/Maxiaoxiang/jQuery-plugins
+ *
+ * @调用方法
+ * $(selector).pagination(option, callback);
+ * -此处callback是初始化调用,option里的callback是点击页码后调用
+ *
+ * -- example --
+ * $(selector).pagination({
+ * ... // 配置参数
+ * callback: function(api) {
+ * console.log('点击页码调用该回调'); //切换页码时执行一次回调
+ * }
+ * }, function(){
+ * console.log('初始化'); //插件初始化时调用该方法,比如请求第一次接口来初始化分页配置
+ * });
+ */
+;
+(function (factory) {
+ if (typeof define === "function" && (define.amd || define.cmd) && !jQuery) {
+ // AMD或CMD
+ define(["jquery"], factory);
+ } else if (typeof module === 'object' && module.exports) {
+ // Node/CommonJS
+ module.exports = function (root, jQuery) {
+ if (jQuery === undefined) {
+ if (typeof window !== 'undefined') {
+ jQuery = require('jquery');
+ } else {
+ jQuery = require('jquery')(root);
+ }
+ }
+ factory(jQuery);
+ return jQuery;
+ };
+ } else {
+ //Browser globals
+ factory(jQuery);
+ }
+}(function ($) {
+
+ //配置参数
+ var defaults = {
+ totalData: 0, //数据总条数
+ showData: 0, //每页显示的条数
+ pageCount: 9, //总页数,默认为9
+ current: 1, //当前第几页
+ prevCls: 'prev', //上一页class
+ nextCls: 'next', //下一页class
+ prevContent: '<', //上一页内容
+ nextContent: '>', //下一页内容
+ activeCls: 'active', //当前页选中状态
+ coping: false, //首页和尾页
+ isHide: false, //当前页数为0页或者1页时不显示分页
+ homePage: '', //首页节点内容
+ endPage: '', //尾页节点内容
+ keepShowPN: false, //是否一直显示上一页下一页
+ mode: 'unfixed', //分页模式,unfixed:不固定页码数量,fixed:固定页码数量
+ count: 4, //mode为unfixed时显示当前选中页前后页数,mode为fixed显示页码总数
+ jump: false, //跳转到指定页数
+ jumpIptCls: 'jump-ipt', //文本框内容
+ jumpBtnCls: 'jump-btn', //跳转按钮
+ jumpBtn: '跳转', //跳转按钮文本
+ callback: function () {} //回调
+ };
+
+ var Pagination = function (element, options) {
+ //全局变量
+ var opts = options, //配置
+ current, //当前页
+ $document = $(document),
+ $obj = $(element); //容器
+
+ /**
+ * 设置总页数
+ * @param {int} page 页码
+ * @return opts.pageCount 总页数配置
+ */
+ this.setPageCount = function (page) {
+ return opts.pageCount = page;
+ };
+
+ /**
+ * 获取总页数
+ * 如果配置了总条数和每页显示条数,将会自动计算总页数并略过总页数配置,反之
+ * @return {int} 总页数
+ */
+ this.getPageCount = function () {
+ return opts.totalData && opts.showData ? Math.ceil(parseInt(opts.totalData) / opts.showData) : opts.pageCount;
+ };
+
+ /**
+ * 获取当前页
+ * @return {int} 当前页码
+ */
+ this.getCurrent = function () {
+ return current;
+ };
+
+ /**
+ * 填充数据
+ * @param {int} 页码
+ */
+ this.filling = function (index) {
+ var html = '';
+ current = parseInt(index) || parseInt(opts.current); //当前页码
+ var pageCount = this.getPageCount(); //获取的总页数
+ switch (opts.mode) { //配置模式
+ case 'fixed': //固定按钮模式
+ html += '
注意:请在 Mac 或 Linux 环境执行。
初始化项目所需信息:
-
MySQL 数据表:user_demo ;
-
+
MySQL 数据表:authorized ;
+
MySQL 数据表:authorized_api ;