Browse Source

修复后台边框部分情况下无法滚动的BUG
优化后台刷新跳转效率
优化后台直接跳转登录
优化后台菜单搜索
优化前台变量输出

Karson 3 years ago
parent
commit
d1d3ea1dea

+ 15 - 15
application/admin/command/Install/fastadmin.sql

@@ -392,24 +392,24 @@ CREATE TABLE `fa_sms` (
 DROP TABLE IF EXISTS `fa_test`;
 CREATE TABLE `fa_test` (
   `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
-  `admin_id` int(10) NOT NULL DEFAULT '0' COMMENT '管理员ID',
-  `category_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '分类ID(单选)',
-  `category_ids` varchar(100) NOT NULL COMMENT '分类ID(多选)',
-  `week` enum('monday','tuesday','wednesday') NOT NULL COMMENT '星期(单选):monday=星期一,tuesday=星期二,wednesday=星期三',
+  `admin_id` int(10) DEFAULT '0' COMMENT '管理员ID',
+  `category_id` int(10) unsigned DEFAULT '0' COMMENT '分类ID(单选)',
+  `category_ids` varchar(100) COMMENT '分类ID(多选)',
+  `week` enum('monday','tuesday','wednesday') COMMENT '星期(单选):monday=星期一,tuesday=星期二,wednesday=星期三',
   `flag` set('hot','index','recommend') DEFAULT '' COMMENT '标志(多选):hot=热门,index=首页,recommend=推荐',
-  `genderdata` enum('male','female') NOT NULL DEFAULT 'male' COMMENT '性别(单选):male=男,female=女',
-  `hobbydata` set('music','reading','swimming') NOT NULL COMMENT '爱好(多选):music=音乐,reading=读书,swimming=游泳',
-  `title` varchar(50) DEFAULT '' COMMENT '标题',
-  `content` text NOT NULL COMMENT '内容',
+  `genderdata` enum('male','female') DEFAULT 'male' COMMENT '性别(单选):male=男,female=女',
+  `hobbydata` set('music','reading','swimming') COMMENT '爱好(多选):music=音乐,reading=读书,swimming=游泳',
+  `title` varchar(100) DEFAULT '' COMMENT '标题',
+  `content` text COMMENT '内容',
   `image` varchar(100) DEFAULT '' COMMENT '图片',
   `images` varchar(1500) DEFAULT '' COMMENT '图片组',
   `attachfile` varchar(100) DEFAULT '' COMMENT '附件',
-  `keywords` varchar(100) DEFAULT '' COMMENT '关键字',
+  `keywords` varchar(255) DEFAULT '' COMMENT '关键字',
   `description` varchar(255) DEFAULT '' COMMENT '描述',
   `city` varchar(100) DEFAULT '' COMMENT '省市',
   `json` varchar(255) DEFAULT NULL COMMENT '配置:key=名称,value=值',
-  `price` float(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '价格',
-  `views` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '点击',
+  `price` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '价格',
+  `views` int(10) unsigned DEFAULT '0' COMMENT '点击',
   `startdate` date DEFAULT NULL COMMENT '开始日期',
   `activitytime` datetime DEFAULT NULL COMMENT '活动时间(datetime)',
   `year` year(4) DEFAULT NULL COMMENT '年',
@@ -418,10 +418,10 @@ CREATE TABLE `fa_test` (
   `createtime` int(10) DEFAULT NULL COMMENT '创建时间',
   `updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
   `deletetime` int(10) DEFAULT NULL COMMENT '删除时间',
-  `weigh` int(10) NOT NULL DEFAULT '0' COMMENT '权重',
-  `switch` tinyint(1) NOT NULL DEFAULT '0' COMMENT '开关',
-  `status` enum('normal','hidden') NOT NULL DEFAULT 'normal' COMMENT '状态',
-  `state` enum('0','1','2') NOT NULL DEFAULT '1' COMMENT '状态值:0=禁用,1=正常,2=推荐',
+  `weigh` int(10) DEFAULT '0' COMMENT '权重',
+  `switch` tinyint(1) DEFAULT '0' COMMENT '开关',
+  `status` enum('normal','hidden') DEFAULT 'normal' COMMENT '状态',
+  `state` enum('0','1','2') DEFAULT '1' COMMENT '状态值:0=禁用,1=正常,2=推荐',
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT='测试表';
 

+ 2 - 4
application/admin/library/Auth.php

@@ -417,8 +417,7 @@ class Auth extends \fast\Auth
             ->where('ismenu', 0)
             ->where('name', 'like', '%/index')
             ->column('name,pid');
-        $pidArr = array_unique(array_column($ruleList, 'pid'));
-        unset($pidArr[0]);
+        $pidArr = array_unique(array_filter(array_column($ruleList, 'pid')));
         foreach ($ruleList as $k => &$v) {
             if (!in_array($v['name'], $userRule)) {
                 unset($ruleList[$k]);
@@ -439,8 +438,7 @@ class Auth extends \fast\Auth
             $selected = $v['name'] == $fixedPage ? $v : $selected;
             $referer = $v['url'] == $refererUrl ? $v : $referer;
         }
-        $lastArr = array_unique(array_column($ruleList, 'pid'));
-        unset($lastArr[0]);
+        $lastArr = array_unique(array_filter(array_column($ruleList, 'pid')));
         $pidDiffArr = array_diff($pidArr, $lastArr);
         foreach ($ruleList as $index => $item) {
             if (in_array($item['id'], $pidDiffArr)) {

+ 4 - 2
application/admin/model/AuthRule.php

@@ -44,14 +44,16 @@ class AuthRule extends Model
         return ['addtabs' => __('Addtabs'), 'dialog' => __('Dialog'), 'ajax' => __('Ajax'), 'blank' => __('Blank')];
     }
 
-    public function setPyAttr($value, $data) {
+    public function setPyAttr($value, $data)
+    {
         if (isset($data['title']) && $data['title']) {
             return self::$pinyin->abbr($data['title']);
         }
         return '';
     }
 
-    public function setPinyinAttr($value, $data) {
+    public function setPinyinAttr($value, $data)
+    {
         if (isset($data['title']) && $data['title']) {
             return self::$pinyin->permalink($data['title'], '');
         }

+ 16 - 16
application/common/controller/Backend.php

@@ -134,6 +134,21 @@ class Backend extends Controller
         // 检测IP是否允许
         check_ip_allowed();
 
+        // 非选项卡时重定向
+        if (!$this->request->isPost() && !IS_AJAX && !IS_ADDTABS && !IS_DIALOG && input("ref") == 'addtabs') {
+            $url = preg_replace_callback("/([\?|&]+)ref=addtabs(&?)/i", function ($matches) {
+                return $matches[2] == '&' ? $matches[1] : '';
+            }, $this->request->url());
+            if (Config::get('url_domain_deploy')) {
+                if (stripos($url, $this->request->server('SCRIPT_NAME')) === 0) {
+                    $url = substr($url, strlen($this->request->server('SCRIPT_NAME')));
+                }
+                $url = url($url, '', false);
+            }
+            $this->redirect('index/index', [], 302, ['referer' => $url]);
+            exit;
+        }
+
         $this->auth = Auth::instance();
 
         // 设置当前请求的URI
@@ -145,7 +160,7 @@ class Backend extends Controller
                 Hook::listen('admin_nologin', $this);
                 $url = Session::get('referer');
                 $url = $url ? $url : $this->request->url();
-                if ($url == '/') {
+                if (in_array($this->request->pathinfo(), ['/', 'index/index'])) {
                     $this->redirect('index/login', [], 302, ['referer' => $url]);
                     exit;
                 }
@@ -161,21 +176,6 @@ class Backend extends Controller
             }
         }
 
-        // 非选项卡时重定向
-        if (!$this->request->isPost() && !IS_AJAX && !IS_ADDTABS && !IS_DIALOG && input("ref") == 'addtabs') {
-            $url = preg_replace_callback("/([\?|&]+)ref=addtabs(&?)/i", function ($matches) {
-                return $matches[2] == '&' ? $matches[1] : '';
-            }, $this->request->url());
-            if (Config::get('url_domain_deploy')) {
-                if (stripos($url, $this->request->server('SCRIPT_NAME')) === 0) {
-                    $url = substr($url, strlen($this->request->server('SCRIPT_NAME')));
-                }
-                $url = url($url, '', false);
-            }
-            $this->redirect('index/index', [], 302, ['referer' => $url]);
-            exit;
-        }
-
         // 设置面包屑导航数据
         $breadcrumb = [];
         if (!IS_DIALOG && !config('fastadmin.multiplenav') && config('fastadmin.breadcrumb')) {

+ 1 - 0
application/extra/addons.php

@@ -5,4 +5,5 @@ return [
     'hooks' => [],
     'route' => [],
     'priority' => [],
+    'domain' => '',
 ];

+ 5 - 5
application/index/view/common/meta.html

@@ -1,18 +1,18 @@
 <meta charset="utf-8">
-<title>{$title|default=''} – {$site.name}</title>
+<title>{$title|default=''|htmlentities} – {$site.name|htmlentities}</title>
 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
 <meta name="renderer" content="webkit">
 
 {if isset($keywords)}
-<meta name="keywords" content="{$keywords}">
+<meta name="keywords" content="{$keywords|htmlentities}">
 {/if}
 {if isset($description)}
-<meta name="description" content="{$description}">
+<meta name="description" content="{$description|htmlentities}">
 {/if}
 
 <link rel="shortcut icon" href="__CDN__/assets/img/favicon.ico" />
 
-<link href="__CDN__/assets/css/frontend{$Think.config.app_debug?'':'.min'}.css?v={$Think.config.site.version}" rel="stylesheet">
+<link href="__CDN__/assets/css/frontend{$Think.config.app_debug?'':'.min'}.css?v={$Think.config.site.version|htmlentities}" rel="stylesheet">
 
 <!-- HTML5 shim, for IE6-8 support of HTML5 elements. All other JS at the end of file. -->
 <!--[if lt IE 9]>
@@ -23,4 +23,4 @@
     var require = {
         config: {$config|json_encode}
     };
-</script>
+</script>

+ 4 - 4
application/index/view/index/index.html

@@ -9,7 +9,7 @@
         <meta name="description" content="">
         <meta name="author" content="">
 
-        <title>{$site.name}</title>
+        <title>{$site.name|htmlentities}</title>
         <link rel="shortcut icon" href="__CDN__/assets/img/favicon.ico" />
         <!-- Bootstrap Core CSS -->
         <link href="__CDN__/assets/libs/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
@@ -33,7 +33,7 @@
                         <span class="icon-bar"></span>
                         <span class="icon-bar"></span>
                     </button>
-                    <a class="navbar-brand page-scroll" href="#page-top">{$site.name}</a>
+                    <a class="navbar-brand page-scroll" href="#page-top">{$site.name|htmlentities}</a>
                 </div>
 
                 <div class="collapse navbar-collapse" id="navbar-collapse-menu">
@@ -53,7 +53,7 @@
                     <div class="col-sm-5">
                         <div class="index-text">
                             <div>
-                                <h1>{$site.name}</h1>
+                                <h1>{$site.name|htmlentities}</h1>
                                 <p style="color:#adb9e0;line-height:30px;">网站(Website)是指在因特网上根据一定的规则,使用HTML(标准通用标记语言)等工具制作的用于展示特定内容相关网页的集合。简单地说,网站是一种沟通工具,人们可以通过网站来发布自己想要公开的资讯,或者利用网站来提供相关的网络服务。</p>
 
                                 <div>
@@ -74,7 +74,7 @@
         </main>
         <footer>
             <div class="container">
-                <p>Copyright @ 2017~{:date('Y',time())} 版权所有 <a href="https://beian.miit.gov.cn" target="_blank">{$site.beian}</a></p>
+                <p>Copyright @ 2017~{:date('Y',time())} 版权所有 <a href="https://beian.miit.gov.cn" target="_blank">{$site.beian|htmlentities}</a></p>
             </div>
         </footer>
 

+ 4 - 4
application/index/view/layout/default.html

@@ -2,7 +2,7 @@
 <html>
     <head>
         {include file="common/meta" /}
-        <link href="__CDN__/assets/css/user.css?v={$Think.config.site.version}" rel="stylesheet">
+        <link href="__CDN__/assets/css/user.css?v={$Think.config.site.version|htmlentities}" rel="stylesheet">
     </head>
 
     <body>
@@ -16,7 +16,7 @@
                         <span class="icon-bar"></span>
                         <span class="icon-bar"></span>
                     </button>
-                    <a class="navbar-brand" href="{:url('/')}">{$site.name}</a>
+                    <a class="navbar-brand" href="{:url('/')}">{$site.name|htmlentities}</a>
                 </div>
                 <div class="collapse navbar-collapse" id="header-navbar">
                     <ul class="nav navbar-nav navbar-right">
@@ -24,7 +24,7 @@
                         <li class="dropdown">
                             {if $user}
                             <a href="{:url('user/index')}" class="dropdown-toggle" data-toggle="dropdown" style="padding-top: 10px;height: 50px;">
-                                <span class="avatar-img"><img src="{$user.avatar|cdnurl}" alt=""></span>
+                                <span class="avatar-img"><img src="{$user.avatar|htmlentities|cdnurl}" alt=""></span>
                             </a>
                             {else /}
                             <a href="{:url('user/index')}" class="dropdown-toggle" data-toggle="dropdown">{:__('User center')} <b class="caret"></b></a>
@@ -52,7 +52,7 @@
         </main>
 
         <footer class="footer" style="clear:both">
-            <p class="copyright">Copyright&nbsp;©&nbsp;2017-2020 {$site.name} All Rights Reserved <a href="https://beian.miit.gov.cn" target="_blank">{$site.beian|htmlentities}</a></p>
+            <p class="copyright">Copyright&nbsp;©&nbsp;2017-2020 {$site.name|htmlentities} All Rights Reserved <a href="https://beian.miit.gov.cn" target="_blank">{$site.beian|htmlentities}</a></p>
         </footer>
 
         {include file="common/script" /}

+ 1 - 1
application/index/view/user/attachment.html

@@ -45,7 +45,7 @@
                 <div class="widget-body no-padding">
                     <div id="toolbar" class="toolbar">
                         <a href="javascript:;" class="btn btn-primary btn-refresh" title="刷新"><i class="fa fa-refresh"></i> </a>
-                        <span><button type="button" id="faupload-image" class="btn btn-success faupload" data-mimetype="{$Think.get.mimetype|default=''}" data-multiple="true"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
+                        <span><button type="button" id="faupload-image" class="btn btn-success faupload" data-mimetype="{$Think.get.mimetype|default=''|htmlentities}" data-multiple="true"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
                         {if request()->get('multiple') == 'true'}
                         <a class="btn btn-danger btn-choose-multi"><i class="fa fa-check"></i> {:__('Choose')}</a>
                         {/if}

+ 3 - 3
application/index/view/user/index.html

@@ -27,18 +27,18 @@
                     <div class="row user-baseinfo">
                         <div class="col-md-3 col-sm-3 col-xs-2 text-center user-center">
                             <a href="{:url('user/profile')}" title="{:__('Click to edit')}">
-                                <span class="avatar-img"><img src="{$user.avatar|cdnurl}" alt=""></span>
+                                <span class="avatar-img"><img src="{$user.avatar|htmlentities|cdnurl}" alt=""></span>
                             </a>
                         </div>
                         <div class="col-md-9 col-sm-9 col-xs-10">
                             <!-- Content -->
                             <div class="ui-content">
                                 <!-- Heading -->
-                                <h4><a href="{:url('user/profile')}">{$user.nickname}</a></h4>
+                                <h4><a href="{:url('user/profile')}">{$user.nickname|htmlentities}</a></h4>
                                 <!-- Paragraph -->
                                 <p>
                                     <a href="{:url('user/profile')}">
-                                        {$user.bio|default=__("This guy hasn't written anything yet")}
+                                        {$user.bio|default=__("This guy hasn't written anything yet")|htmlentities}
                                     </a>
                                 </p>
                                 <!-- Success -->

+ 1 - 1
application/index/view/user/login.html

@@ -1,6 +1,6 @@
 <div id="content-container" class="container">
     <div class="user-section login-section">
-        <div class="logon-tab clearfix"><a class="active">{:__('Sign in')}</a> <a href="{:url('user/register')}?url={$url|urlencode}">{:__('Sign up')}</a></div>
+        <div class="logon-tab clearfix"><a class="active">{:__('Sign in')}</a> <a href="{:url('user/register')}?url={$url|urlencode|htmlentities}">{:__('Sign up')}</a></div>
         <div class="login-main">
             <form name="form" id="login-form" class="form-vertical" method="POST" action="">
                 <input type="hidden" name="url" value="{$url|htmlentities}"/>

+ 1 - 1
application/index/view/user/profile.html

@@ -44,7 +44,7 @@
                             <label class="control-label col-xs-12 col-sm-2"></label>
                             <div class="col-xs-12 col-sm-4">
                                 <div class="profile-avatar-container">
-                                    <img class="profile-user-img img-responsive img-circle" src="{$user.avatar|cdnurl}" alt="">
+                                    <img class="profile-user-img img-responsive img-circle" src="{$user.avatar|htmlentities|cdnurl}" alt="">
                                     <div class="profile-avatar-text img-circle">{:__('Click to edit')}</div>
                                     <button type="button" id="faupload-avatar" class="faupload" data-mimetype="png,jpg,jpeg,gif" data-input-id="c-avatar"><i class="fa fa-upload"></i> {:__('Upload')}</button>
                                 </div>

+ 1 - 1
application/index/view/user/register.html

@@ -1,6 +1,6 @@
 <div id="content-container" class="container">
     <div class="user-section login-section">
-        <div class="logon-tab clearfix"> <a href="{:url('user/login')}?url={$url|urlencode}">{:__('Sign in')}</a> <a class="active">{:__('Sign up')}</a> </div>
+        <div class="logon-tab clearfix"> <a href="{:url('user/login')}?url={$url|urlencode|htmlentities}">{:__('Sign in')}</a> <a class="active">{:__('Sign up')}</a> </div>
         <div class="login-main">
             <form name="form1" id="register-form" class="form-vertical" method="POST" action="">
                 <input type="hidden" name="invite_user_id" value="0" />

+ 5 - 3
public/assets/css/backend.css

@@ -567,17 +567,19 @@ form.form-horizontal .control-label {
   border-top-right-radius: 0;
 }
 .main-sidebar .sidebar-form .menuresult a {
-  border-top: 1px solid #eee;
+  display: block;
   background-color: #fff;
+  border-top: 1px solid transparent;
   border-bottom: 1px solid #eee;
-  margin-bottom: -1px;
-  display: block;
   padding: 10px 15px;
   color: #222d32;
 }
 .main-sidebar .sidebar-form .menuresult a:hover {
   background: #eee;
 }
+.main-sidebar .sidebar-form .menuresult a:first-child {
+  border-top: 1px solid #eee;
+}
 .input-group .sp_result_area {
   width: 100%;
 }

File diff suppressed because it is too large
+ 1 - 1
public/assets/css/backend.min.css


+ 3 - 1
public/assets/js/adminlte.js

@@ -312,6 +312,7 @@ function _init() {
                             size: "8px"
                         });
                     }
+                    $(".sidebar").trigger("mouseover");
                 }
             }
         }
@@ -441,7 +442,8 @@ function _init() {
                         //parent.find('li.active').removeClass('active');
                         //parent_li.addClass('active');
                         //Fix the layout in case the sidebar stretches over the height of the window
-                        _this.layout.fix();
+                        // _this.layout.fix();
+                        _this.layout.fixSidebar();
                     });
                     parent_li.addClass('treeview-open');
                 } else {

+ 92 - 17
public/assets/js/require-backend.min.js

@@ -7515,10 +7515,12 @@ define('upload',['jquery', 'bootstrap', 'dropzone', 'template'], function ($, un
                                 Upload.events.onUploadError(this, ret, file);
                             },
                             uploadprogress: function (file, progress, bytesSent) {
-
+                                if (file.upload.chunked) {
+                                    $(this.element).prop("disabled", true).html("<i class='fa fa-upload'></i> " + __('Upload') + Math.floor((file.upload.bytesSent / file.size) * 100) + "%");
+                                }
                             },
                             totaluploadprogress: function (progress, bytesSent) {
-                                if (this.getActiveFiles().length > 0) {
+                                if (this.getActiveFiles().length > 0 && !this.options.chunking) {
                                     $(this.element).prop("disabled", true).html("<i class='fa fa-upload'></i> " + __('Upload') + Math.floor(progress) + "%");
                                 }
                             },
@@ -7533,13 +7535,13 @@ define('upload',['jquery', 'bootstrap', 'dropzone', 'template'], function ($, un
                                 var that = this;
                                 Fast.api.ajax({
                                     url: this.options.url,
-                                    data: {
+                                    data: $.extend({}, multipart, {
                                         action: 'merge',
                                         filesize: file.size,
                                         filename: file.name,
                                         chunkid: file.upload.uuid,
                                         chunkcount: file.upload.totalChunkCount,
-                                    }
+                                    })
                                 }, function (data, ret) {
                                     done(JSON.stringify(ret));
                                     return false;
@@ -10234,7 +10236,7 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'],
             faselect: function (form) {
                 //绑定fachoose选择附件事件
                 if ($(".faselect,.fachoose", form).size() > 0) {
-                    $(".faselect,.fachoose", form).on('click', function () {
+                    $(".faselect,.fachoose", form).off('click').on('click', function () {
                         var that = this;
                         var multiple = $(this).data("multiple") ? $(this).data("multiple") : false;
                         var mimetype = $(this).data("mimetype") ? $(this).data("mimetype") : '';
@@ -10405,6 +10407,35 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'],
                     return false;
                 });
             },
+            tagsinput: function (form) {
+                //标签输入
+                $("input[data-toggle='tagsinput']").each(function () {
+                    var setting = {
+                        width: 'auto',
+                        defaultText: '输入后空格确认',
+                        minInputWidth: 110,
+                        height: '36px',
+                        placeholderColor: '#999',
+                        onChange: function (row) {
+                            $("input", $(this).next()).parent().focus();
+                            $("input", $(this).next()).trigger("blur.autocomplete").focus();
+                        },
+                    };
+                    var autocomplete = $(this).data("tagsinput-autocomplete");
+                    if (autocomplete) {
+                        if (typeof autocomplete == 'string') {
+                            autocomplete = {url: autocomplete};
+                        }
+                        setting['autocomplete'] = $.extend({
+                            url: '',
+                            minChars: 1,
+                            menuClass: 'autocomplete-tags'
+                        }, autocomplete);
+                    }
+                    setting = $.extend(true, setting, $(this).data("tagsinput") || {});
+                    $(this).tagsInput(setting);
+                });
+            },
             bindevent: function (form) {
 
             },
@@ -10523,6 +10554,8 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'],
                 events.slider(form);
 
                 events.switcher(form);
+
+                events.tagsinput(form);
             },
             custom: {}
         },
@@ -10572,6 +10605,7 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'],
         // 重置搜索
         form.on("click", "button[type=reset]", function (event) {
             form[0].reset();
+
             setTimeout(function () {
                 that.onCommonSearch();
             }, 0);
@@ -10861,13 +10895,19 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'],
         });
 
         that.$container.on("click", "." + that.options.searchClass, function () {
-            var obj = $("form [name='" + $(this).data("field") + "']", that.$commonsearch);
+            var value = $(this).data("value");
+            var field = $(this).data("field");
+            var ul = that.$container.closest(".panel-intro").find("ul[data-field='" + field + "']");
+            if (ul.length > 0) {
+                $('li a[data-value="' + value + '"][data-toggle="tab"]', ul).trigger('click');
+                return;
+            }
+            var obj = $("form [name='" + field + "']", that.$commonsearch);
             if (obj.size() > 0) {
-                var value = $(this).data("value");
                 if (obj.is("select")) {
                     $("option[value='" + value + "']", obj).prop("selected", true);
                 } else if (obj.size() > 1) {
-                    $("form [name='" + $(this).data("field") + "'][value='" + value + "']", that.$commonsearch).prop("checked", true);
+                    $("form [name='" + field + "'][value='" + value + "']", that.$commonsearch).prop("checked", true);
                 } else {
                     obj.val(value + "");
                 }
@@ -11247,8 +11287,8 @@ define("bootstrap-table-jumpto", ["bootstrap-table"], (function (global) {
                 this.$tableBody.css("height", "100%");
                 this.$fixedColumns && this.$fixedColumns.show();
                 this.$fixedColumnsRight && this.$fixedColumnsRight.show();
-                this.$fixedHeaderRight.scrollLeft(this.$tableBody.find('table').width());
-                this.$fixedBodyRight.scrollLeft(this.$tableBody.find('table').width());
+                this.$fixedHeaderRight && this.$fixedHeaderRight.scrollLeft(this.$tableBody.find('table').width());
+                this.$fixedBodyRight && this.$fixedBodyRight.scrollLeft(this.$tableBody.find('table').width());
             }
         }
         if (!that.fixedColumnsSupported()) {
@@ -11258,11 +11298,11 @@ define("bootstrap-table-jumpto", ["bootstrap-table"], (function (global) {
             this.initFixedColumnsHeader();
         } else if (arguments[0] === 'scroll-body') {
             if (this.needFixedColumns && this.options.fixedNumber) {
-                this.$fixedBody.scrollTop(this.$tableBody.scrollTop());
+                this.$fixedBody && this.$fixedBody.scrollTop(this.$tableBody.scrollTop());
             }
 
             if (this.needFixedColumns && this.options.fixedRightNumber) {
-                this.$fixedBodyRight.scrollTop(this.$tableBody.scrollTop());
+                this.$fixedBodyRight && this.$fixedBodyRight.scrollTop(this.$tableBody.scrollTop());
             }
         } else if (arguments[0] === 'load-success') {
             this.hideLoading();
@@ -11460,6 +11500,17 @@ define("bootstrap-table-jumpto", ["bootstrap-table"], (function (global) {
                 //给鼠标滑轮绑定事件
                 updateScroll(e, that.$fixedBody[0]);
             });
+            //给固定表格的checkbox绑定事件
+            this.$fixedBody.find('input[name="' + this.options.selectItemName + '"]').off("click").on('click', function (e) {
+                e.stopImmediatePropagation();
+                var index = $(e.target).data("index");
+                $(that.$selectItem[index]).trigger("click");
+            });
+            //绑定TD点击事件
+            this.$fixedBody.find('> table > tbody > tr[data-index] > td').off('click dblclick').on('click dblclick', function (e) {
+                var index = $(this).closest("tr[data-index]").data("index");
+                $(that.$selectItem[index]).closest("tr[data-index]").find(">td:eq(" + $(this).index() + ")").trigger("click");
+            });
         }
         //给原本表格绑定scroll事件
         $('div.fixed-table-body').off('scroll'); //给所有的body解绑 scroll
@@ -11491,11 +11542,16 @@ define("bootstrap-table-jumpto", ["bootstrap-table"], (function (global) {
                 updateScroll(e, that.$fixedBodyRight[0]);
             });
             //给固定表格的checkbox绑定事件
-            this.$fixedBody && this.$fixedBody.find('input[name="' + this.options.selectItemName + '"]').off("click").on('click', function (e) {
+            this.$fixedBodyRight.find('input[name="' + this.options.selectItemName + '"]').off("click").on('click', function (e) {
                 e.stopImmediatePropagation();
                 var index = $(e.target).data("index");
                 $(that.$selectItem[index]).trigger("click");
             });
+            //绑定TD点击事件
+            this.$fixedBodyRight.find('> table > tbody > tr[data-index] > td').off('click dblclick').on('click dblclick', function (e) {
+                var index = $(this).closest("tr[data-index]").data("index");
+                $(that.$selectItem[index]).closest("tr[data-index]").find(">td:eq(" + $(this).index() + ")").trigger("click");
+            });
         }
 
         if (this.options.filterControl) {
@@ -11813,7 +11869,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                     $(Table.config.disabledbtn, toolbar).toggleClass('disabled', !options.selectedIds.length);
                 });
                 // 绑定TAB事件
-                $('.panel-heading [data-field] a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
+                $('.panel-heading [data-field] a[data-toggle="tab"]', table.closest(".panel-intro")).on('shown.bs.tab', function (e) {
                     var field = $(this).closest("[data-field]").data("field");
                     var value = $(this).data("value");
                     var object = $("[name='" + field + "']", table.closest(".bootstrap-table").find(".commonsearch-table"));
@@ -11826,6 +11882,14 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                     table.bootstrapTable('refresh', {pageNumber: 1});
                     return false;
                 });
+                // 修复重置事件
+                $("form", table.closest(".bootstrap-table").find(".commonsearch-table")).on('reset', function () {
+                    setTimeout(function () {
+                        // $('.panel-heading [data-field] li.active a[data-toggle="tab"]').trigger('shown.bs.tab');
+                    }, 0);
+                    $('.panel-heading [data-field] li', table.closest(".panel-intro")).removeClass('active');
+                    $('.panel-heading [data-field] li:first', table.closest(".panel-intro")).addClass('active');
+                });
                 // 刷新按钮事件
                 toolbar.on('click', Table.config.refreshbtn, function () {
                     table.bootstrapTable('refresh');
@@ -11924,7 +11988,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                     var ids = Table.api.selectedids(table);
                     Layer.confirm(
                         __('Are you sure you want to delete the %s selected item?', ids.length),
-                        {icon: 3, title: __('Warning'), offset: 0, shadeClose: true},
+                        {icon: 3, title: __('Warning'), offset: 0, shadeClose: true, btn: [__('OK'), __('Cancel')]},
                         function (index) {
                             Table.api.multi("del", ids, table, that);
                             Layer.close(index);
@@ -12013,7 +12077,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                     var that = this;
                     Layer.confirm(
                         __('Are you sure you want to delete this item?'),
-                        {icon: 3, title: __('Warning'), shadeClose: true},
+                        {icon: 3, title: __('Warning'), shadeClose: true, btn: [__('OK'), __('Cancel')]},
                         function (index) {
                             Table.api.multi("del", id, table, that);
                             Layer.close(index);
@@ -12116,7 +12180,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                         }
                         Layer.confirm(
                             __('Are you sure you want to delete this item?'),
-                            {icon: 3, title: __('Warning'), offset: [top, left], shadeClose: true},
+                            {icon: 3, title: __('Warning'), offset: [top, left], shadeClose: true, btn: [__('OK'), __('Cancel')]},
                             function (index) {
                                 var table = $(that).closest('table');
                                 var options = table.bootstrapTable('getOptions');
@@ -12262,6 +12326,16 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                         value = row[this.customField];
                         field = this.customField;
                     }
+                    if (typeof that.searchList === 'object' && typeof that.custom === 'undefined') {
+                        var i = 0;
+                        var searchValues = Object.values(colorArr);
+                        $.each(that.searchList, function (key, val) {
+                            if (typeof colorArr[key] == 'undefined') {
+                                colorArr[key] = searchValues[i];
+                                i = typeof searchValues[i + 1] === 'undefined' ? 0 : i + 1;
+                            }
+                        });
+                    }
 
                     //渲染Flag
                     var html = [];
@@ -12325,6 +12399,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
             },
             buttonlink: function (column, buttons, value, row, index, type) {
                 var table = column.table;
+                column.clickToSelect = false;
                 type = typeof type === 'undefined' ? 'buttons' : type;
                 var options = table ? table.bootstrapTable('getOptions') : {};
                 var html = [];

+ 92 - 17
public/assets/js/require-frontend.min.js

@@ -7364,10 +7364,12 @@ define('upload',['jquery', 'bootstrap', 'dropzone', 'template'], function ($, un
                                 Upload.events.onUploadError(this, ret, file);
                             },
                             uploadprogress: function (file, progress, bytesSent) {
-
+                                if (file.upload.chunked) {
+                                    $(this.element).prop("disabled", true).html("<i class='fa fa-upload'></i> " + __('Upload') + Math.floor((file.upload.bytesSent / file.size) * 100) + "%");
+                                }
                             },
                             totaluploadprogress: function (progress, bytesSent) {
-                                if (this.getActiveFiles().length > 0) {
+                                if (this.getActiveFiles().length > 0 && !this.options.chunking) {
                                     $(this.element).prop("disabled", true).html("<i class='fa fa-upload'></i> " + __('Upload') + Math.floor(progress) + "%");
                                 }
                             },
@@ -7382,13 +7384,13 @@ define('upload',['jquery', 'bootstrap', 'dropzone', 'template'], function ($, un
                                 var that = this;
                                 Fast.api.ajax({
                                     url: this.options.url,
-                                    data: {
+                                    data: $.extend({}, multipart, {
                                         action: 'merge',
                                         filesize: file.size,
                                         filename: file.name,
                                         chunkid: file.upload.uuid,
                                         chunkcount: file.upload.totalChunkCount,
-                                    }
+                                    })
                                 }, function (data, ret) {
                                     done(JSON.stringify(ret));
                                     return false;
@@ -10083,7 +10085,7 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'],
             faselect: function (form) {
                 //绑定fachoose选择附件事件
                 if ($(".faselect,.fachoose", form).size() > 0) {
-                    $(".faselect,.fachoose", form).on('click', function () {
+                    $(".faselect,.fachoose", form).off('click').on('click', function () {
                         var that = this;
                         var multiple = $(this).data("multiple") ? $(this).data("multiple") : false;
                         var mimetype = $(this).data("mimetype") ? $(this).data("mimetype") : '';
@@ -10254,6 +10256,35 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'],
                     return false;
                 });
             },
+            tagsinput: function (form) {
+                //标签输入
+                $("input[data-toggle='tagsinput']").each(function () {
+                    var setting = {
+                        width: 'auto',
+                        defaultText: '输入后空格确认',
+                        minInputWidth: 110,
+                        height: '36px',
+                        placeholderColor: '#999',
+                        onChange: function (row) {
+                            $("input", $(this).next()).parent().focus();
+                            $("input", $(this).next()).trigger("blur.autocomplete").focus();
+                        },
+                    };
+                    var autocomplete = $(this).data("tagsinput-autocomplete");
+                    if (autocomplete) {
+                        if (typeof autocomplete == 'string') {
+                            autocomplete = {url: autocomplete};
+                        }
+                        setting['autocomplete'] = $.extend({
+                            url: '',
+                            minChars: 1,
+                            menuClass: 'autocomplete-tags'
+                        }, autocomplete);
+                    }
+                    setting = $.extend(true, setting, $(this).data("tagsinput") || {});
+                    $(this).tagsInput(setting);
+                });
+            },
             bindevent: function (form) {
 
             },
@@ -10372,6 +10403,8 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'],
                 events.slider(form);
 
                 events.switcher(form);
+
+                events.tagsinput(form);
             },
             custom: {}
         },
@@ -10421,6 +10454,7 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'],
         // 重置搜索
         form.on("click", "button[type=reset]", function (event) {
             form[0].reset();
+
             setTimeout(function () {
                 that.onCommonSearch();
             }, 0);
@@ -10710,13 +10744,19 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator', 'validator-lang'],
         });
 
         that.$container.on("click", "." + that.options.searchClass, function () {
-            var obj = $("form [name='" + $(this).data("field") + "']", that.$commonsearch);
+            var value = $(this).data("value");
+            var field = $(this).data("field");
+            var ul = that.$container.closest(".panel-intro").find("ul[data-field='" + field + "']");
+            if (ul.length > 0) {
+                $('li a[data-value="' + value + '"][data-toggle="tab"]', ul).trigger('click');
+                return;
+            }
+            var obj = $("form [name='" + field + "']", that.$commonsearch);
             if (obj.size() > 0) {
-                var value = $(this).data("value");
                 if (obj.is("select")) {
                     $("option[value='" + value + "']", obj).prop("selected", true);
                 } else if (obj.size() > 1) {
-                    $("form [name='" + $(this).data("field") + "'][value='" + value + "']", that.$commonsearch).prop("checked", true);
+                    $("form [name='" + field + "'][value='" + value + "']", that.$commonsearch).prop("checked", true);
                 } else {
                     obj.val(value + "");
                 }
@@ -11096,8 +11136,8 @@ define("bootstrap-table-jumpto", ["bootstrap-table"], (function (global) {
                 this.$tableBody.css("height", "100%");
                 this.$fixedColumns && this.$fixedColumns.show();
                 this.$fixedColumnsRight && this.$fixedColumnsRight.show();
-                this.$fixedHeaderRight.scrollLeft(this.$tableBody.find('table').width());
-                this.$fixedBodyRight.scrollLeft(this.$tableBody.find('table').width());
+                this.$fixedHeaderRight && this.$fixedHeaderRight.scrollLeft(this.$tableBody.find('table').width());
+                this.$fixedBodyRight && this.$fixedBodyRight.scrollLeft(this.$tableBody.find('table').width());
             }
         }
         if (!that.fixedColumnsSupported()) {
@@ -11107,11 +11147,11 @@ define("bootstrap-table-jumpto", ["bootstrap-table"], (function (global) {
             this.initFixedColumnsHeader();
         } else if (arguments[0] === 'scroll-body') {
             if (this.needFixedColumns && this.options.fixedNumber) {
-                this.$fixedBody.scrollTop(this.$tableBody.scrollTop());
+                this.$fixedBody && this.$fixedBody.scrollTop(this.$tableBody.scrollTop());
             }
 
             if (this.needFixedColumns && this.options.fixedRightNumber) {
-                this.$fixedBodyRight.scrollTop(this.$tableBody.scrollTop());
+                this.$fixedBodyRight && this.$fixedBodyRight.scrollTop(this.$tableBody.scrollTop());
             }
         } else if (arguments[0] === 'load-success') {
             this.hideLoading();
@@ -11309,6 +11349,17 @@ define("bootstrap-table-jumpto", ["bootstrap-table"], (function (global) {
                 //给鼠标滑轮绑定事件
                 updateScroll(e, that.$fixedBody[0]);
             });
+            //给固定表格的checkbox绑定事件
+            this.$fixedBody.find('input[name="' + this.options.selectItemName + '"]').off("click").on('click', function (e) {
+                e.stopImmediatePropagation();
+                var index = $(e.target).data("index");
+                $(that.$selectItem[index]).trigger("click");
+            });
+            //绑定TD点击事件
+            this.$fixedBody.find('> table > tbody > tr[data-index] > td').off('click dblclick').on('click dblclick', function (e) {
+                var index = $(this).closest("tr[data-index]").data("index");
+                $(that.$selectItem[index]).closest("tr[data-index]").find(">td:eq(" + $(this).index() + ")").trigger("click");
+            });
         }
         //给原本表格绑定scroll事件
         $('div.fixed-table-body').off('scroll'); //给所有的body解绑 scroll
@@ -11340,11 +11391,16 @@ define("bootstrap-table-jumpto", ["bootstrap-table"], (function (global) {
                 updateScroll(e, that.$fixedBodyRight[0]);
             });
             //给固定表格的checkbox绑定事件
-            this.$fixedBody && this.$fixedBody.find('input[name="' + this.options.selectItemName + '"]').off("click").on('click', function (e) {
+            this.$fixedBodyRight.find('input[name="' + this.options.selectItemName + '"]').off("click").on('click', function (e) {
                 e.stopImmediatePropagation();
                 var index = $(e.target).data("index");
                 $(that.$selectItem[index]).trigger("click");
             });
+            //绑定TD点击事件
+            this.$fixedBodyRight.find('> table > tbody > tr[data-index] > td').off('click dblclick').on('click dblclick', function (e) {
+                var index = $(this).closest("tr[data-index]").data("index");
+                $(that.$selectItem[index]).closest("tr[data-index]").find(">td:eq(" + $(this).index() + ")").trigger("click");
+            });
         }
 
         if (this.options.filterControl) {
@@ -11662,7 +11718,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                     $(Table.config.disabledbtn, toolbar).toggleClass('disabled', !options.selectedIds.length);
                 });
                 // 绑定TAB事件
-                $('.panel-heading [data-field] a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
+                $('.panel-heading [data-field] a[data-toggle="tab"]', table.closest(".panel-intro")).on('shown.bs.tab', function (e) {
                     var field = $(this).closest("[data-field]").data("field");
                     var value = $(this).data("value");
                     var object = $("[name='" + field + "']", table.closest(".bootstrap-table").find(".commonsearch-table"));
@@ -11675,6 +11731,14 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                     table.bootstrapTable('refresh', {pageNumber: 1});
                     return false;
                 });
+                // 修复重置事件
+                $("form", table.closest(".bootstrap-table").find(".commonsearch-table")).on('reset', function () {
+                    setTimeout(function () {
+                        // $('.panel-heading [data-field] li.active a[data-toggle="tab"]').trigger('shown.bs.tab');
+                    }, 0);
+                    $('.panel-heading [data-field] li', table.closest(".panel-intro")).removeClass('active');
+                    $('.panel-heading [data-field] li:first', table.closest(".panel-intro")).addClass('active');
+                });
                 // 刷新按钮事件
                 toolbar.on('click', Table.config.refreshbtn, function () {
                     table.bootstrapTable('refresh');
@@ -11773,7 +11837,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                     var ids = Table.api.selectedids(table);
                     Layer.confirm(
                         __('Are you sure you want to delete the %s selected item?', ids.length),
-                        {icon: 3, title: __('Warning'), offset: 0, shadeClose: true},
+                        {icon: 3, title: __('Warning'), offset: 0, shadeClose: true, btn: [__('OK'), __('Cancel')]},
                         function (index) {
                             Table.api.multi("del", ids, table, that);
                             Layer.close(index);
@@ -11862,7 +11926,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                     var that = this;
                     Layer.confirm(
                         __('Are you sure you want to delete this item?'),
-                        {icon: 3, title: __('Warning'), shadeClose: true},
+                        {icon: 3, title: __('Warning'), shadeClose: true, btn: [__('OK'), __('Cancel')]},
                         function (index) {
                             Table.api.multi("del", id, table, that);
                             Layer.close(index);
@@ -11965,7 +12029,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                         }
                         Layer.confirm(
                             __('Are you sure you want to delete this item?'),
-                            {icon: 3, title: __('Warning'), offset: [top, left], shadeClose: true},
+                            {icon: 3, title: __('Warning'), offset: [top, left], shadeClose: true, btn: [__('OK'), __('Cancel')]},
                             function (index) {
                                 var table = $(that).closest('table');
                                 var options = table.bootstrapTable('getOptions');
@@ -12111,6 +12175,16 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
                         value = row[this.customField];
                         field = this.customField;
                     }
+                    if (typeof that.searchList === 'object' && typeof that.custom === 'undefined') {
+                        var i = 0;
+                        var searchValues = Object.values(colorArr);
+                        $.each(that.searchList, function (key, val) {
+                            if (typeof colorArr[key] == 'undefined') {
+                                colorArr[key] = searchValues[i];
+                                i = typeof searchValues[i + 1] === 'undefined' ? 0 : i + 1;
+                            }
+                        });
+                    }
 
                     //渲染Flag
                     var html = [];
@@ -12174,6 +12248,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
             },
             buttonlink: function (column, buttons, value, row, index, type) {
                 var table = column.table;
+                column.clickToSelect = false;
                 type = typeof type === 'undefined' ? 'buttons' : type;
                 var options = table ? table.bootstrapTable('getOptions') : {};
                 var html = [];

+ 1 - 0
public/assets/js/require-table.js

@@ -815,6 +815,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
             },
             buttonlink: function (column, buttons, value, row, index, type) {
                 var table = column.table;
+                column.clickToSelect = false;
                 type = typeof type === 'undefined' ? 'buttons' : type;
                 var options = table ? table.bootstrapTable('getOptions') : {};
                 var html = [];

+ 5 - 3
public/assets/less/backend.less

@@ -709,18 +709,20 @@ form.form-horizontal .control-label {
         border-top-right-radius: 0;
 
         a {
-            border-top: 1px solid #eee;
             display: block;
             background-color: #fff;
+            border-top: 1px solid transparent;
             border-bottom: 1px solid #eee;
-            margin-bottom: -1px;
-            display: block;
             padding: 10px 15px;
             color: #222d32;
 
             &:hover {
                 background: #eee;
             }
+
+            &:first-child {
+                border-top: 1px solid #eee;
+            }
         }
     }
 }