Browse Source

新增前台会员Money字段和余额日志表
新增插件配置温馨提示的功能
新增后台登录入口为默认时的安全提示
新增余额增减的静态方法
优化前台默认布局的展示
优化附件管理中非图片资源的图标显示
优化移动端左侧菜单栏滑动体验
修复语言包在加载失败时页面不加载的BUG
修复通用搜索在重置后分页的BUG
修复管理员禁用后仍然能登录后台的BUG
修复一键打包插件在Win下打包后目录路径错误的BUG
修复API接口Token无法刷新的BUG

Karson 6 years ago
parent
commit
f6ccbb70dd
39 changed files with 292 additions and 190 deletions
  1. 2 2
      application/admin/command/Addon.php
  2. 6 6
      application/admin/command/Api/template/index.html
  3. 17 9
      application/admin/command/Install/fastadmin.sql
  4. 8 1
      application/admin/controller/Addon.php
  5. 2 0
      application/admin/lang/zh-cn.php
  6. 1 0
      application/admin/lang/zh-cn/dashboard.php
  7. 1 0
      application/admin/lang/zh-cn/index.php
  8. 6 1
      application/admin/library/Auth.php
  9. 4 2
      application/admin/library/traits/Backend.php
  10. 10 0
      application/admin/model/User.php
  11. 83 75
      application/admin/view/addon/config.html
  12. 5 0
      application/admin/view/dashboard/index.html
  13. 6 0
      application/admin/view/user/user/edit.html
  14. 6 2
      application/api/controller/Token.php
  15. 1 1
      application/common/library/Auth.php
  16. 18 23
      application/common/model/Area.php
  17. 23 0
      application/common/model/MoneyLog.php
  18. 20 0
      application/common/model/User.php
  19. 3 3
      application/config.php
  20. 2 0
      application/index/lang/zh-cn.php
  21. 8 8
      application/index/view/index/index.html
  22. 5 3
      application/index/view/user/index.html
  23. 7 7
      extend/fast/Tree.php
  24. 6 6
      public/api.html
  25. 3 3
      public/assets/css/backend.css
  26. 1 1
      public/assets/css/backend.min.css
  27. 2 8
      public/assets/css/frontend.css
  28. 1 1
      public/assets/css/frontend.min.css
  29. 5 0
      public/assets/js/adminlte.js
  30. 1 1
      public/assets/js/backend/general/attachment.js
  31. 4 11
      public/assets/js/backend/index.js
  32. 1 0
      public/assets/js/bootstrap-table-commonsearch.js
  33. 1 1
      public/assets/js/fast.js
  34. 14 3
      public/assets/js/require-backend.min.js
  35. 1 1
      public/assets/js/require-form.js
  36. 1 1
      public/assets/js/require-frontend.min.js
  37. 3 3
      public/assets/less/backend.less
  38. 3 6
      public/assets/less/frontend.less
  39. 1 1
      public/install.php

+ 2 - 2
application/admin/command/Addon.php

@@ -33,7 +33,7 @@ class Addon extends Command
     {
         $name = $input->getOption('name') ?: '';
         $action = $input->getOption('action') ?: '';
-        if(stripos($name, 'addons/')!==false){
+        if (stripos($name, 'addons/') !== false) {
             $name = explode('/', $name)[1];
         }
         //强制覆盖
@@ -241,7 +241,7 @@ class Addon extends Command
                 foreach ($files as $name => $file) {
                     if (!$file->isDir()) {
                         $filePath = $file->getRealPath();
-                        $relativePath = substr($filePath, strlen($addonDir));
+                        $relativePath = str_replace(DS, '/', substr($filePath, strlen($addonDir)));
                         if (!in_array($file->getFilename(), ['.git', '.DS_Store', 'Thumbs.db'])) {
                             $zip->addFile($filePath, $relativePath);
                         }

+ 6 - 6
application/admin/command/Api/template/index.html

@@ -9,15 +9,15 @@
         <title>{$config.title}</title>
 
         <!-- Bootstrap Core CSS -->
-        <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">
+        <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
 
         <!-- Plugin CSS -->
-        <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
+        <link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
 
         <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
         <!--[if lt IE 9]>
-        <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
-        <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
+        <script src="https://cdn.staticfile.org/html5shiv/3.7.3/html5shiv.min.js"></script>
+        <script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
         <![endif]-->
 
         <style type="text/css">
@@ -354,10 +354,10 @@
         </div> <!-- /container -->
 
         <!-- jQuery -->
-        <script src="https://cdn.jsdelivr.net/npm/jquery@2.1.4/dist/jquery.min.js"></script>
+        <script src="https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
 
         <!-- Bootstrap Core JavaScript -->
-        <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
+        <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
 
         <script type="text/javascript">
             function syntaxHighlight(json) {

+ 17 - 9
application/admin/command/Install/fastadmin.sql

@@ -29,17 +29,13 @@ CREATE TABLE `fa_admin` (
   `status` varchar(30) NOT NULL DEFAULT 'normal' COMMENT '状态',
   PRIMARY KEY (`id`),
   UNIQUE KEY `username` (`username`) USING BTREE
-) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='管理员表';
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='管理员表';
 
 -- ----------------------------
 -- Records of fa_admin
 -- ----------------------------
 BEGIN;
 INSERT INTO `fa_admin` VALUES (1, 'admin', 'Admin', '075eaec83636846f51c152f29b98a2fd', 's4f3', '/assets/img/avatar.png', 'admin@fastadmin.net', 0, 1502029281, 1492186163, 1502029281, 'd3992c3b-5ecc-4ecb-9dc2-8997780fcadc', 'normal');
-INSERT INTO `fa_admin` VALUES (2, 'admin2', 'admin2', '9a28ce07ce875fbd14172a9ca5357d3c', '2dHDmj', '/assets/img/avatar.png', 'admin2@fastadmin.net', 0, 1505450906, 1492186163, 1505450906, 'df45fdd5-26f4-45ca-83b3-47e4491a315a', 'normal');
-INSERT INTO `fa_admin` VALUES (3, 'admin3', 'admin3', '1c11f945dfcd808a130a8c2a8753fe62', 'WOKJEn', '/assets/img/avatar.png', 'admin3@fastadmin.net', 0, 1501980868, 1492186201, 1501982377, '', 'normal');
-INSERT INTO `fa_admin` VALUES (4, 'admin22', 'admin22', '1c1a0aa0c3c56a8c1a908aab94519648', 'Aybcn5', '/assets/img/avatar.png', 'admin22@fastadmin.net', 0, 0, 1492186240, 1492186240, '', 'normal');
-INSERT INTO `fa_admin` VALUES (5, 'admin32', 'admin32', 'ade94d5d7a7033afa7d84ac3066d0a02', 'FvYK0u', '/assets/img/avatar.png', 'admin32@fastadmin.net', 0, 0, 1492186263, 1492186263, '', 'normal');
 COMMIT;
 
 -- ----------------------------
@@ -134,10 +130,6 @@ CREATE TABLE `fa_auth_group_access` (
 -- ----------------------------
 BEGIN;
 INSERT INTO `fa_auth_group_access` VALUES (1, 1);
-INSERT INTO `fa_auth_group_access` VALUES (2, 2);
-INSERT INTO `fa_auth_group_access` VALUES (3, 3);
-INSERT INTO `fa_auth_group_access` VALUES (4, 5);
-INSERT INTO `fa_auth_group_access` VALUES (5, 5);
 COMMIT;
 
 -- ----------------------------
@@ -431,6 +423,7 @@ CREATE TABLE `fa_user` (
   `gender` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '性别',
   `birthday` date COMMENT '生日',
   `bio` varchar(100) NOT NULL DEFAULT '' COMMENT '格言',
+  `money` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '余额',
   `score` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '积分',
   `successions` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '连续登录天数',
   `maxsuccessions` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '最大连续登录天数',
@@ -480,6 +473,21 @@ INSERT INTO `fa_user_group` VALUES (1, '默认组', '1,2,3,4,5,6,7,8,9,10,11,12'
 COMMIT;
 
 -- ----------------------------
+-- Table structure for fa_user_money_log
+-- ----------------------------
+DROP TABLE IF EXISTS `fa_user_money_log`;
+CREATE TABLE `fa_user_money_log` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
+  `money` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变更余额',
+  `before` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变更前余额',
+  `after` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '变更后余额',
+  `memo` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='会员余额变动表';
+
+-- ----------------------------
 -- Table structure for fa_user_rule
 -- ----------------------------
 DROP TABLE IF EXISTS `fa_user_rule`;

+ 8 - 1
application/admin/controller/Addon.php

@@ -81,7 +81,14 @@ class Addon extends Backend
             }
             $this->error(__('Parameter %s can not be empty', ''));
         }
-        $this->view->assign("addon", ['info' => $info, 'config' => $config]);
+        $tips = [];
+        foreach ($config as $index => &$item) {
+            if ($item['name'] == '__tips__') {
+                $tips = $item;
+                unset($config[$index]);
+            }
+        }
+        $this->view->assign("addon", ['info' => $info, 'config' => $config, 'tips' => $tips]);
         $configFile = ADDON_PATH . $name . DS . 'config.html';
         $viewFile = is_file($configFile) ? $configFile : '';
         return $this->view->fetch($viewFile);

+ 2 - 0
application/admin/lang/zh-cn.php

@@ -43,6 +43,8 @@ return [
     'Last month'                                            => '上月',
     'This month'                                            => '本月',
     'Loading'                                               => '加载中',
+    'Money'                                                 => '余额',
+    'Score'                                                 => '积分',
     'More'                                                  => '更多',
     'Yes'                                                   => '是',
     'No'                                                    => '否',

+ 1 - 0
application/admin/lang/zh-cn/dashboard.php

@@ -42,4 +42,5 @@ return [
     'Cdn url'                 => '静态资源CDN',
     'Timezone'                => '时区',
     'Language'                => '语言',
+    'Security tips'           => '<i class="fa fa-warning"></i> 安全提示:你正在使用默认的后台登录入口,为了你的网站安全,建议你修改后台登录入口,<a href="https://forum.fastadmin.net/thread/7640" target="_blank">点击查看修改方法</a>',
 ];

+ 1 - 0
application/admin/lang/zh-cn/index.php

@@ -26,6 +26,7 @@ return [
     'Username or password is incorrect'                          => '用户名或密码不正确',
     'Username is incorrect'                                      => '用户名不正确',
     'Password is incorrect'                                      => '密码不正确',
+    'Admin is forbidden'                                         => '管理员已经被禁止登录',
     'Please try again after 1 day'                               => '请于1天后再尝试登录',
     'Login successful'                                           => '登录成功!',
     'Logout successful'                                          => '退出成功!',

+ 6 - 1
application/admin/library/Auth.php

@@ -43,6 +43,10 @@ class Auth extends \fast\Auth
             $this->setError('Username is incorrect');
             return false;
         }
+        if ($admin['status'] == 'hidden') {
+            $this->setError('Admin is forbidden');
+            return false;
+        }
         if (Config::get('fastadmin.login_failure_retry') && $admin->loginfailure >= 10 && time() - $admin->updatetime < 86400) {
             $this->setError('Please try again after 1 day');
             return false;
@@ -134,6 +138,7 @@ class Auth extends \fast\Auth
      * 检测当前控制器和方法是否匹配传递的数组
      *
      * @param array $arr 需要验证权限的数组
+     * @return bool
      */
     public function match($arr = [])
     {
@@ -432,7 +437,7 @@ class Auth extends \fast\Auth
     /**
      * 设置错误信息
      *
-     * @param $error 错误信息
+     * @param string $error 错误信息
      * @return Auth
      */
     public function setError($error)

+ 4 - 2
application/admin/library/traits/Backend.php

@@ -227,8 +227,10 @@ trait Backend
         if ($ids) {
             if ($this->request->has('params')) {
                 parse_str($this->request->post("params"), $values);
-                $values = array_intersect_key($values, array_flip(is_array($this->multiFields) ? $this->multiFields : explode(',', $this->multiFields)));
-                if ($values || $this->auth->isSuperAdmin()) {
+                if (!$this->auth->isSuperAdmin()) {
+                    $values = array_intersect_key($values, array_flip(is_array($this->multiFields) ? $this->multiFields : explode(',', $this->multiFields)));
+                }
+                if ($values) {
                     $adminIds = $this->getDataLimitAdminIds();
                     if (is_array($adminIds)) {
                         $this->model->where($this->dataLimitField, 'in', $adminIds);

+ 10 - 0
application/admin/model/User.php

@@ -2,6 +2,7 @@
 
 namespace app\admin\model;
 
+use app\common\model\MoneyLog;
 use think\Model;
 
 class User extends Model
@@ -36,6 +37,15 @@ class User extends Model
                 }
             }
         });
+
+
+        self::beforeUpdate(function ($row) {
+            $changedata = $row->getChangedData();
+            if (isset($changedata['money'])) {
+                $origin = $row->getOriginData();
+                MoneyLog::create(['user_id' => $row['id'], 'money' => $changedata['money'] - $origin['money'], 'memo' => '管理员变更金额']);
+            }
+        });
     }
 
     public function getGenderList()

+ 83 - 75
application/admin/view/addon/config.html

@@ -1,88 +1,96 @@
 <form id="config-form" class="edit-form form-horizontal" role="form" data-toggle="validator" method="POST" action="">
+    {if $addon.tips}
+    <div class="alert {$addon.tips.extend|default='alert-info-light'}" style="margin-bottom:10px;">
+        <b>{$addon.tips.title}</b><br>
+        {$addon.tips.value}
+    </div>
+    {/if}
     <table class="table table-striped">
         <thead>
-            <tr>
-                <th width="15%">{:__('Title')}</th>
-                <th width="85%">{:__('Value')}</th>
-            </tr>
+        <tr>
+            <th width="15%">{:__('Title')}</th>
+            <th width="85%">{:__('Value')}</th>
+        </tr>
         </thead>
         <tbody>
-            {foreach $addon.config as $item}
-            <tr>
-                <td>{$item.title}</td>
-                <td>
-                    <div class="row">
-                        <div class="col-sm-8 col-xs-12">
-                            {switch $item.type}
-                            {case string}
-                            <input {$item.extend} type="text" name="row[{$item.name}]" value="{$item.value}" class="form-control" data-rule="{$item.rule}" data-tip="{$item.tip}" />
-                            {/case}
-                            {case text}
-                            <textarea {$item.extend} name="row[{$item.name}]" class="form-control" data-rule="{$item.rule}" rows="5" data-tip="{$item.tip}">{$item.value}</textarea>
-                            {/case}
-                            {case array}
-                            <dl class="fieldlist" data-name="row[{$item.name}]">
-                                <dd>
-                                    <ins>{:__('Array key')}</ins>
-                                    <ins>{:__('Array value')}</ins>
-                                </dd>
-                                <dd><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></dd>
-                                <textarea name="row[{$item.name}]" cols="30" rows="5" class="hide">{$item.value|json_encode}</textarea>
-                            </dl>
-                            {/case}
-                            {case datetime}
-                            <input {$item.extend} type="text" name="row[{$item.name}]" value="{$item.value}" class="form-control datetimepicker" data-tip="{$item.tip}" data-rule="{$item.rule}" />
-                            {/case}
-                            {case number}
-                            <input {$item.extend} type="number" name="row[{$item.name}]" value="{$item.value}" class="form-control" data-tip="{$item.tip}" data-rule="{$item.rule}" />
-                            {/case}
-                            {case checkbox}
-                            {foreach name="item.content" item="vo"}
-                            <label for="row[{$item.name}][]-{$key}"><input id="row[{$item.name}][]-{$key}" name="row[{$item.name}][]" type="checkbox" value="{$key}" data-tip="{$item.tip}" {in name="key" value="$item.value"}checked{/in} /> {$vo}</label>
-                            {/foreach}
-                            {/case}
-                            {case radio}
+        {foreach $addon.config as $item}
+        <tr>
+            <td>{$item.title}</td>
+            <td>
+                <div class="row">
+                    <div class="col-sm-8 col-xs-12">
+                        {switch $item.type}
+                        {case string}
+                        <input {$item.extend} type="text" name="row[{$item.name}]" value="{$item.value}" class="form-control" data-rule="{$item.rule}" data-tip="{$item.tip}"/>
+                        {/case}
+                        {case text}
+                        <textarea {$item.extend} name="row[{$item.name}]" class="form-control" data-rule="{$item.rule}" rows="5" data-tip="{$item.tip}">{$item.value}</textarea>
+                        {/case}
+                        {case array}
+                        <dl class="fieldlist" data-name="row[{$item.name}]">
+                            <dd>
+                                <ins>{:__('Array key')}</ins>
+                                <ins>{:__('Array value')}</ins>
+                            </dd>
+                            <dd><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></dd>
+                            <textarea name="row[{$item.name}]" cols="30" rows="5" class="hide">{$item.value|json_encode}</textarea>
+                        </dl>
+                        {/case}
+                        {case datetime}
+                        <input {$item.extend} type="text" name="row[{$item.name}]" value="{$item.value}" class="form-control datetimepicker" data-tip="{$item.tip}" data-rule="{$item.rule}"/>
+                        {/case}
+                        {case number}
+                        <input {$item.extend} type="number" name="row[{$item.name}]" value="{$item.value}" class="form-control" data-tip="{$item.tip}" data-rule="{$item.rule}"/>
+                        {/case}
+                        {case checkbox}
+                        {foreach name="item.content" item="vo"}
+                        <label for="row[{$item.name}][]-{$key}"><input id="row[{$item.name}][]-{$key}" name="row[{$item.name}][]" type="checkbox" value="{$key}" data-tip="{$item.tip}" {in name="key" value="$item.value" }checked{/in} /> {$vo}</label>
+                        {/foreach}
+                        {/case}
+                        {case radio}
+                        {foreach name="item.content" item="vo"}
+                        <label for="row[{$item.name}]-{$key}"><input id="row[{$item.name}]-{$key}" name="row[{$item.name}]" type="radio" value="{$key}" data-tip="{$item.tip}" {in name="key" value="$item.value" }checked{/in} /> {$vo}</label>
+                        {/foreach}
+                        {/case}
+                        {case value="select" break="0"}{/case}
+                        {case value="selects"}
+                        <select {$item.extend} name="row[{$item.name}]{$item.type=='selects'?'[]':''}" class="form-control selectpicker" data-tip="{$item.tip}" {$item.type=='selects'?'multiple':''}>
                             {foreach name="item.content" item="vo"}
-                            <label for="row[{$item.name}]-{$key}"><input id="row[{$item.name}]-{$key}" name="row[{$item.name}]" type="radio" value="{$key}" data-tip="{$item.tip}" {in name="key" value="$item.value"}checked{/in} /> {$vo}</label>
+                            <option value="{$key}" {in name="key" value="$item.value" }selected{
+                            /in}>{$vo}</option>
                             {/foreach}
-                            {/case}
-                            {case value="select" break="0"}{/case}
-                            {case value="selects"}
-                            <select {$item.extend} name="row[{$item.name}]{$item.type=='selects'?'[]':''}" class="form-control selectpicker" data-tip="{$item.tip}" {$item.type=='selects'?'multiple':''}>
-                                {foreach name="item.content" item="vo"}
-                                <option value="{$key}" {in name="key" value="$item.value"}selected{/in}>{$vo}</option>
-                                {/foreach}
-                            </select>
-                            {/case}
-                            {case value="image" break="0"}{/case}
-                            {case value="images"}
-                            <div class="form-inline">
-                                <input id="c-{$item.name}" class="form-control" size="37" name="row[{$item.name}]" type="text" value="{$item.value}" data-tip="{$item.tip}">
-                                <span><button type="button" id="plupload-{$item.name}" class="btn btn-danger plupload" data-input-id="c-{$item.name}" data-mimetype="image/*" data-multiple="{$item.type=='image'?'false':'true'}" data-preview-id="p-{$item.name}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
-                                <span><button type="button" id="fachoose-{$item.name}" class="btn btn-primary fachoose" data-input-id="c-{$item.name}" data-mimetype="image/*" data-multiple="{$item.type=='image'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
-                                <ul class="row list-inline plupload-preview" id="p-{$item.name}"></ul>
-                            </div>
-                            {/case}
-                            {case value="file" break="0"}{/case}
-                            {case value="files"}
-                            <div class="form-inline">
-                                <input id="c-{$item.name}" class="form-control" size="37" name="row[{$item.name}]" type="text" value="{$item.value}" data-tip="{$item.tip}">
-                                <span><button type="button" id="plupload-{$item.name}" class="btn btn-danger plupload" data-input-id="c-{$item.name}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
-                                <span><button type="button" id="fachoose-{$item.name}" class="btn btn-primary fachoose" data-input-id="c-{$item.name}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
-                            </div>
-                            {/case}
-                            {case bool}
-                            <label for="row[{$item.name}]-yes"><input id="row[{$item.name}]-yes" name="row[{$item.name}]" type="radio" value="1" {$item.value?'checked':''} data-tip="{$item.tip}" /> {:__('Yes')}</label> 
-                            <label for="row[{$item.name}]-no"><input id="row[{$item.name}]-no" name="row[{$item.name}]" type="radio" value="0" {$item.value?'':'checked'} data-tip="{$item.tip}" /> {:__('No')}</label>
-                            {/case}
-                            {/switch}
+                        </select>
+                        {/case}
+                        {case value="image" break="0"}{/case}
+                        {case value="images"}
+                        <div class="form-inline">
+                            <input id="c-{$item.name}" class="form-control" size="37" name="row[{$item.name}]" type="text" value="{$item.value}" data-tip="{$item.tip}">
+                            <span><button type="button" id="plupload-{$item.name}" class="btn btn-danger plupload" data-input-id="c-{$item.name}" data-mimetype="image/*" data-multiple="{$item.type=='image'?'false':'true'}" data-preview-id="p-{$item.name}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
+                            <span><button type="button" id="fachoose-{$item.name}" class="btn btn-primary fachoose" data-input-id="c-{$item.name}" data-mimetype="image/*" data-multiple="{$item.type=='image'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
+                            <ul class="row list-inline plupload-preview" id="p-{$item.name}"></ul>
+                        </div>
+                        {/case}
+                        {case value="file" break="0"}{/case}
+                        {case value="files"}
+                        <div class="form-inline">
+                            <input id="c-{$item.name}" class="form-control" size="37" name="row[{$item.name}]" type="text" value="{$item.value}" data-tip="{$item.tip}">
+                            <span><button type="button" id="plupload-{$item.name}" class="btn btn-danger plupload" data-input-id="c-{$item.name}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
+                            <span><button type="button" id="fachoose-{$item.name}" class="btn btn-primary fachoose" data-input-id="c-{$item.name}" data-multiple="{$item.type=='file'?'false':'true'}"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
                         </div>
-                        <div class="col-sm-4"></div>
+                        {/case}
+                        {case bool}
+                        <label for="row[{$item.name}]-yes"><input id="row[{$item.name}]-yes" name="row[{$item.name}]" type="radio" value="1" {$item.value?'checked':''} data-tip="{$item.tip}" /> {:__('Yes')}</label>
+                        <label for="row[{$item.name}]-no"><input id="row[{$item.name}]-no" name="row[{$item.name}]" type="radio" value="0" {$item.value?'':'checked'} data-tip="{$item.tip}" /> {:__('No')}</label>
+                        {/case}
+                        {default /}{$item.value}
+                        {/switch}
                     </div>
+                    <div class="col-sm-4"></div>
+                </div>
 
-                </td>
-            </tr>
-            {/foreach}
+            </td>
+        </tr>
+        {/foreach}
         </tbody>
     </table>
     <div class="form-group layer-footer">

+ 5 - 0
application/admin/view/dashboard/index.html

@@ -122,6 +122,11 @@
         padding:30px 0;
     }
 </style>
+{if preg_match('/\/admin\/|admin\.php|admin_d75KABNWt\.php/i', url())}
+<div class="alert alert-danger-light">
+    {:__('Security tips')}
+</div>
+{/if}
 <div class="panel panel-default panel-intro">
     <div class="panel-heading">
         {:build_heading(null, false)}

+ 6 - 0
application/admin/view/user/user/edit.html

@@ -75,6 +75,12 @@
         </div>
     </div>
     <div class="form-group">
+        <label for="c-money" class="control-label col-xs-12 col-sm-2">{:__('Money')}:</label>
+        <div class="col-xs-12 col-sm-4">
+            <input id="c-money" data-rule="required" class="form-control" name="row[money]" type="number" value="{$row.money}">
+        </div>
+    </div>
+    <div class="form-group">
         <label for="c-score" class="control-label col-xs-12 col-sm-2">{:__('Score')}:</label>
         <div class="col-xs-12 col-sm-4">
             <input id="c-score" data-rule="required" class="form-control" name="row[score]" type="number" value="{$row.score}">

+ 6 - 2
application/api/controller/Token.php

@@ -3,6 +3,7 @@
 namespace app\api\controller;
 
 use app\common\controller\Api;
+use fast\Random;
 
 /**
  * Token接口
@@ -35,10 +36,13 @@ class Token extends Api
      */
     public function refresh()
     {
+        //删除源Token
         $token = $this->auth->getToken();
+        \app\common\library\Token::delete($token);
+        //创建新Token
+        $token = Random::uuid();
+        \app\common\library\Token::set($token, $this->auth->id, 2592000);
         $tokenInfo = \app\common\library\Token::get($token);
-        $tokenInfo->expiretime = time() + 2592000;
-        $tokenInfo->save();
         $this->success('', ['token' => $tokenInfo['token'], 'expires_in' => $tokenInfo['expires_in']]);
     }
 

+ 1 - 1
application/common/library/Auth.php

@@ -32,7 +32,7 @@ class Auth
     {
         if ($config = Config::get('user'))
         {
-            $this->options = array_merge($this->config, $config);
+            $this->config = array_merge($this->config, $config);
         }
         $this->options = array_merge($this->config, $options);
     }

+ 18 - 23
application/common/model/Area.php

@@ -14,9 +14,9 @@ class Area extends Model
     /**
      * 根据经纬度获取当前地区信息
      *
-     * @param string $lng   经度
-     * @param string $lat   纬度
-     * @return array 城市信息
+     * @param string $lng 经度
+     * @param string $lat 纬度
+     * @return Area 城市信息
      */
     public static function getAreaFromLngLat($lng, $lat, $level = 3)
     {
@@ -24,17 +24,14 @@ class Area extends Model
         $rangearr = [1 => 15000, 2 => 1000, 3 => 200];
         $geoname = isset($namearr[$level]) ? $namearr[$level] : $namearr[3];
         $georange = isset($rangearr[$level]) ? $rangearr[$level] : $rangearr[3];
-        $neararea = [];
         // 读取范围内的ID
         $redis = Cache::store('redis')->handler();
         $georadiuslist = [];
-        if (method_exists($redis, 'georadius'))
-        {
+        if (method_exists($redis, 'georadius')) {
             $georadiuslist = $redis->georadius($geoname, $lng, $lat, $georange, 'km', ['WITHDIST', 'COUNT' => 5, 'ASC']);
         }
 
-        if ($georadiuslist)
-        {
+        if ($georadiuslist) {
             list($id, $distance) = $georadiuslist[0];
         }
         $id = isset($id) && $id ? $id : 3;
@@ -44,16 +41,15 @@ class Area extends Model
     /**
      * 根据经纬度获取省份
      *
-     * @param string $lng   经度
-     * @param string $lat   纬度
-     * @return array
+     * @param string $lng 经度
+     * @param string $lat 纬度
+     * @return Area
      */
     public static function getProvinceFromLngLat($lng, $lat)
     {
-        $provincedata = [];
+        $provincedata = null;
         $citydata = self::getCityFromLngLat($lng, $lat);
-        if ($citydata)
-        {
+        if ($citydata) {
             $provincedata = self::get($citydata['pid']);
         }
         return $provincedata;
@@ -62,16 +58,15 @@ class Area extends Model
     /**
      * 根据经纬度获取城市
      *
-     * @param string $lng   经度
-     * @param string $lat   纬度
-     * @return array
+     * @param string $lng 经度
+     * @param string $lat 纬度
+     * @return Area
      */
     public static function getCityFromLngLat($lng, $lat)
     {
-        $citydata = [];
+        $citydata = null;
         $districtdata = self::getDistrictFromLngLat($lng, $lat);
-        if ($districtdata)
-        {
+        if ($districtdata) {
             $citydata = self::get($districtdata['pid']);
         }
         return $citydata;
@@ -80,9 +75,9 @@ class Area extends Model
     /**
      * 根据经纬度获取地区
      *
-     * @param string $lng   经度
-     * @param string $lat   纬度
-     * @return array
+     * @param string $lng 经度
+     * @param string $lat 纬度
+     * @return Area
      */
     public static function getDistrictFromLngLat($lng, $lat)
     {

+ 23 - 0
application/common/model/MoneyLog.php

@@ -0,0 +1,23 @@
+<?php
+
+namespace app\common\model;
+
+use think\Model;
+
+/**
+ * 会员余额日志模型
+ */
+class MoneyLog Extends Model
+{
+
+    // 表名
+    protected $name = 'user_money_log';
+    // 开启自动写入时间戳字段
+    protected $autoWriteTimestamp = 'int';
+    // 定义时间戳字段名
+    protected $createTime = 'createtime';
+    protected $updateTime = '';
+    // 追加属性
+    protected $append = [
+    ];
+}

+ 20 - 0
application/common/model/User.php

@@ -75,6 +75,26 @@ class User Extends Model
     }
 
     /**
+     * 变更会员余额
+     * @param int $money    余额
+     * @param int $user_id  会员ID
+     * @param string $memo  备注
+     */
+    public static function money($money, $user_id, $memo)
+    {
+        $user = self::get($user_id);
+        if ($user)
+        {
+            $before = $user->money;
+            $after = $user->money + $money;
+            //更新会员信息
+            $user->save(['money' => $after]);
+            //写入日志
+            MoneyLog::create(['user_id' => $user_id, 'money' => $money, 'before' => $before, 'after' => $after, 'memo' => $memo]);
+        }
+    }
+
+    /**
      * 变更会员积分
      * @param int $score    积分
      * @param int $user_id  会员ID

+ 3 - 3
application/config.php

@@ -260,8 +260,8 @@ return [
         //是否开启前台会员中心
         'usercenter'          => true,
         //登录验证码
-        'login_captcha'       => false,
-        //登录失败超过10则1天后重试
+        'login_captcha'       => true,
+        //登录失败超过10则1天后重试
         'login_failure_retry' => true,
         //是否同一账号同一时间只能在一个地方登录
         'login_unique'        => false,
@@ -272,7 +272,7 @@ return [
         //自动检测更新
         'checkupdate'         => false,
         //版本号
-        'version'             => '1.0.0.20181031_beta',
+        'version'             => '1.0.0.20181127_beta',
         //API接口地址
         'api_url'             => 'https://api.fastadmin.net',
     ],

+ 2 - 0
application/index/lang/zh-cn.php

@@ -27,6 +27,8 @@ return [
     'OK'                                                     => '确定',
     'Cancel'                                                 => '取消',
     'Loading'                                                => '加载中',
+    'Money'                                                  => '余额',
+    'Score'                                                  => '积分',
     'More'                                                   => '更多',
     'Normal'                                                 => '正常',
     'Hidden'                                                 => '隐藏',

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

@@ -12,17 +12,17 @@
         <title>FastAdmin - {:__('The fastest framework based on ThinkPHP5 and Bootstrap')}</title>
 
         <!-- Bootstrap Core CSS -->
-        <link href="//cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">
+        <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
         <link href="__CDN__/assets/css/index.css" rel="stylesheet">
 
         <!-- Plugin CSS -->
-        <link href="//cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
-        <link href="//cdn.jsdelivr.net/npm/simple-line-icons@2.4.1/css/simple-line-icons.min.css" rel="stylesheet">
+        <link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
+        <link href="https://cdn.staticfile.org/simple-line-icons/2.4.1/css/simple-line-icons.min.css" rel="stylesheet">
 
         <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
         <!--[if lt IE 9]>
-            <script src="//cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
-            <script src="//cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
+            <script src="https://cdn.staticfile.org/html5shiv/3.7.3/html5shiv.min.js"></script>
+            <script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
         <![endif]-->
     </head>
 
@@ -163,13 +163,13 @@
         </footer>
 
         <!-- jQuery -->
-        <script src="//cdn.jsdelivr.net/npm/jquery@2.1.4/dist/jquery.min.js"></script>
+        <script src=https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js></script>
 
         <!-- Bootstrap Core JavaScript -->
-        <script src="//cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
+        <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
 
         <!-- Plugin JavaScript -->
-        <script src="//cdn.jsdelivr.net/npm/jquery.easing@1.4.1/jquery.easing.min.js"></script>
+        <script src="https://cdn.staticfile.org/jquery-easing/1.4.1/jquery.easing.min.js"></script>
 
         <script>
             $(function () {

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

@@ -44,11 +44,13 @@
                                 <!-- Success -->
                                 <div class="basicinfo">
                                     <div class="row">
-                                        <div class="col-xs-4 col-md-2">{:__('Lv')}</div>
-                                        <div class="col-xs-8 col-md-4"><a href="javascript:;" class="viewlv">{$user.level}</a>
+                                        <div class="col-xs-4 col-md-2">{:__('Money')}</div>
+                                        <div class="col-xs-8 col-md-4">
+                                            <a href="javascript:;" class="viewmoney">{$user.money}</a>
                                         </div>
                                         <div class="col-xs-4 col-md-2">{:__('Score')}</div>
-                                        <div class="col-xs-8 col-md-4"><a href="javascript:;" class="viewscore">{$user.score}</a>
+                                        <div class="col-xs-8 col-md-4">
+                                            <a href="javascript:;" class="viewscore">{$user.score}</a>
                                         </div>
                                     </div>
                                     <div class="row">

+ 7 - 7
extend/fast/Tree.php

@@ -365,11 +365,12 @@ class Tree
     /**
      * 特殊
      * @param integer $myid 要查询的ID
-     * @param string $itemtpl1   第一种HTML代码方式
-     * @param string $itemtpl2  第二种HTML代码方式
-     * @param mixed $selectedids  默认选中
-     * @param mixed $disabledids  禁用
-     * @param integer $itemprefix 前缀
+     * @param string $itemtpl1 第一种HTML代码方式
+     * @param string $itemtpl2 第二种HTML代码方式
+     * @param mixed $selectedids 默认选中
+     * @param mixed $disabledids 禁用
+     * @param string $itemprefix 前缀
+     * @return string
      */
     public function getTreeSpecial($myid, $itemtpl1, $itemtpl2, $selectedids = 0, $disabledids = 0, $itemprefix = '')
     {
@@ -413,9 +414,8 @@ class Tree
      *
      * 获取树状数组
      * @param string $myid 要查询的ID
-     * @param string $nametpl 名称条目模板
      * @param string $itemprefix 前缀
-     * @return string
+     * @return array
      */
     public function getTreeArray($myid, $itemprefix = '')
     {

+ 6 - 6
public/api.html

@@ -9,15 +9,15 @@
         <title>FastAdmin</title>
 
         <!-- Bootstrap Core CSS -->
-        <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">
+        <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
 
         <!-- Plugin CSS -->
-        <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
+        <link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
 
         <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
         <!--[if lt IE 9]>
-        <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
-        <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
+        <script src="https://cdn.staticfile.org/html5shiv/3.7.3/html5shiv.min.js"></script>
+        <script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
         <![endif]-->
 
         <style type="text/css">
@@ -3736,10 +3736,10 @@
         </div> <!-- /container -->
 
         <!-- jQuery -->
-        <script src="https://cdn.jsdelivr.net/npm/jquery@2.1.4/dist/jquery.min.js"></script>
+        <script src="https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
 
         <!-- Bootstrap Core JavaScript -->
-        <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
+        <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
 
         <script type="text/javascript">
             function syntaxHighlight(json) {

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

@@ -558,14 +558,14 @@ form.form-horizontal .control-label {
   float: left;
   background: none;
   margin-left: 0;
-  width: 80px;
+  min-width: 80px;
   clear: none;
 }
 #treeview .jstree-leaf {
   float: left;
   margin-left: 0;
   padding-left: 24px;
-  width: 80px;
+  min-width: 80px;
   clear: none;
   color: #777;
 }
@@ -959,7 +959,7 @@ table.table-nowrap thead > tr > th {
   }
   .main-sidebar,
   .left-side {
-    padding-top: 94px;
+    padding-top: 50px;
   }
   .n-bootstrap .n-right {
     margin-top: 0;

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


+ 2 - 8
public/assets/css/frontend.css

@@ -252,9 +252,6 @@ footer.footer {
   color: #aaa;
   background: #555;
   margin-top: 25px;
-  position: fixed;
-  bottom: 0;
-  z-index: 99;
 }
 footer.footer .copyright {
   line-height: 50px;
@@ -370,12 +367,9 @@ footer.footer .copyright a:hover {
 main.content {
   width: 100%;
   overflow: auto;
-  top: 0;
-  position: absolute;
-  z-index: 10;
-  bottom: 50px;
   padding: 15px;
-  padding-top: 67px;
+  padding-top: 20px;
+  min-height: calc(100vh - 125px);
 }
 .sidenav {
   padding: 20px 0 10px 0;

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


+ 5 - 0
public/assets/js/adminlte.js

@@ -152,6 +152,11 @@ $(function () {
             AdminLTEOptions);
     }
 
+    if ('ontouchstart' in document.documentElement) {
+        $.AdminLTE.options.sidebarSlimScroll = false;
+        $(".main-sidebar").css({height: ($(window).height() - $(".main-header").height()) + "px", overflow: "scroll"});
+    }
+
     //Easy access to options
     var o = $.AdminLTE.options;
 

+ 1 - 1
public/assets/js/backend/general/attachment.js

@@ -132,7 +132,7 @@ define(['jquery', 'bootstrap', 'backend', 'form', 'table'], function ($, undefin
                         var style = row.storage == 'upyun' ? '!/fwfh/120x90' : '';
                         return '<a href="' + row.fullurl + '" target="_blank"><img src="' + row.fullurl + style + '" alt="" style="max-height:90px;max-width:120px"></a>';
                     } else {
-                        return '<a href="' + row.fullurl + '" target="_blank">' + __('None') + '</a>';
+                        return '<a href="' + row.fullurl + '" target="_blank"><img src="https://tool.fastadmin.net/icon/' + row.imagetype + '.png" alt=""></a>';
                     }
                 },
                 url: function (value, row, index) {

+ 4 - 11
public/assets/js/backend/index.js

@@ -19,24 +19,17 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
 
             //快捷搜索
             $(".menuresult").width($("form.sidebar-form > .input-group").width());
-            var isAndroid = /(android)/i.test(navigator.userAgent);
             var searchResult = $(".menuresult");
             $("form.sidebar-form").on("blur", "input[name=q]", function () {
                 searchResult.addClass("hide");
-                if (isAndroid) {
-                    $.AdminLTE.options.sidebarSlimScroll = true;
-                }
             }).on("focus", "input[name=q]", function () {
-                if (isAndroid) {
-                    $.AdminLTE.options.sidebarSlimScroll = false;
-                }
                 if ($("a", searchResult).size() > 0) {
                     searchResult.removeClass("hide");
                 }
             }).on("keyup", "input[name=q]", function () {
                 searchResult.html('');
                 var val = $(this).val();
-                var html = new Array();
+                var html = [];
                 if (val != '') {
                     $("ul.sidebar-menu li a[addtabs]:not([href^='javascript:;'])").each(function () {
                         if ($("span:first", this).text().indexOf(val) > -1 || $(this).attr("py").indexOf(val) > -1 || $(this).attr("pinyin").indexOf(val) > -1) {
@@ -122,7 +115,7 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
                             Layer.open({
                                 title: __('Discover new version'),
                                 maxHeight: 400,
-                                content: '<h5 style="background-color:#f7f7f7; font-size:14px; padding: 10px;">' + __('Your current version') + ':' + ret.data.version + ',' + __('New version') + ':' + ret.data.newversion + '</h5><span class="label label-danger">'+__('Release notes')+'</span><br/>' + ret.data.upgradetext,
+                                content: '<h5 style="background-color:#f7f7f7; font-size:14px; padding: 10px;">' + __('Your current version') + ':' + ret.data.version + ',' + __('New version') + ':' + ret.data.newversion + '</h5><span class="label label-danger">' + __('Release notes') + '</span><br/>' + ret.data.upgradetext,
                                 btn: [__('Go to download'), __('Ignore this version'), __('Do not remind again')],
                                 btn2: function (index, layero) {
                                     localStorage.setItem("ignoreversion", ret.data.newversion);
@@ -304,8 +297,8 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
             //这一行需要放在点击左侧链接事件之前
             var addtabs = Config.referer ? localStorage.getItem("addtabs") : null;
 
-            //绑定tabs事件,如果需要点击强制刷新iframe,则请将iframeForceRefresh置为true
-            nav.addtabs({iframeHeight: "100%", iframeForceRefresh: false, nav: nav});
+            //绑定tabs事件,如果需要点击强制刷新iframe,则请将iframeForceRefresh置为true,iframeForceRefreshTable只强制刷新表格
+            nav.addtabs({iframeHeight: "100%", iframeForceRefresh: false, iframeForceRefreshTable: true, nav: nav});
 
             if ($("ul.sidebar-menu li.active a").size() > 0) {
                 $("ul.sidebar-menu li.active a").trigger("click");

+ 1 - 0
public/assets/js/bootstrap-table-commonsearch.js

@@ -350,6 +350,7 @@
         var searchQuery = getSearchQuery(this);
         this.trigger('common-search', this, searchQuery);
         this.options.pageNumber = 1;
+        this.options.pageSize = $.fn.bootstrapTable.defaults.pageSize;
         this.refresh({});
     };
 

+ 1 - 1
public/assets/js/fast.js

@@ -250,7 +250,7 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, undefine
                 i = 1;
             string = string.toLowerCase();
             //string = typeof Lang[string] != 'undefined' ? Lang[string] : string;
-            if (typeof Lang[string] != 'undefined') {
+            if (typeof Lang !== 'undefined' && typeof Lang[string] !== 'undefined') {
                 if (typeof Lang[string] == 'object')
                     return Lang[string];
                 string = Lang[string];

+ 14 - 3
public/assets/js/require-backend.min.js

@@ -904,7 +904,7 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
                 i = 1;
             string = string.toLowerCase();
             //string = typeof Lang[string] != 'undefined' ? Lang[string] : string;
-            if (typeof Lang[string] != 'undefined') {
+            if (typeof Lang !== 'undefined' && typeof Lang[string] !== 'undefined') {
                 if (typeof Lang[string] == 'object')
                     return Lang[string];
                 string = Lang[string];
@@ -8433,7 +8433,7 @@ define('validator',['validator-core', 'validator-lang'], function (Validator, un
 define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, Upload, Validator) {
     var Form = {
         config: {
-            fieldlisttpl: '<dd class="form-inline"><input type="text" name="<%=name%>[<%=index%>][key]" class="form-control" value="<%=row.key%>" size="10" /> <input type="text" name="<%=name%>[<%=index%>][value]" class="form-control" value="<%=row.value%>" size="40" /> <span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span> <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span></dd>'
+            fieldlisttpl: '<dd class="form-inline"><input type="text" name="<%=name%>[<%=index%>][key]" class="form-control" value="<%=row.key%>" size="10" /> <input type="text" name="<%=name%>[<%=index%>][value]" class="form-control" value="<%=row.value%>" size="30" /> <span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span> <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span></dd>'
         },
         events: {
             validator: function (form, success, error, submit) {
@@ -9258,6 +9258,7 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
         var searchQuery = getSearchQuery(this);
         this.trigger('common-search', this, searchQuery);
         this.options.pageNumber = 1;
+        this.options.pageSize = $.fn.bootstrapTable.defaults.pageSize;
         this.refresh({});
     };
 
@@ -10454,7 +10455,8 @@ define("drop", function(){});
             tab: '.tab-addtabs',
             iframeUse: true, //使用iframe还是ajax
             iframeHeight: $(window).height() - 50, //固定TAB中IFRAME高度,根据需要自己修改
-            iframeForceRefresh: false, //点击后强制刷新对应的iframe
+            iframeForceRefresh: false, //点击后强制加载对应的iframe
+            iframeForceRefreshTable: false, //点击后强制刷新对应的iframe中的table
             callback: function () {
                 //关闭后回调函数
             }
@@ -10579,6 +10581,15 @@ define("drop", function(){});
                     $("#" + conid + " iframe").attr('src', function (i, val) {
                         return val;
                     });
+                } else if (options.iframeForceRefreshTable) {
+                    try {
+                        //检测iframe中是否存在刷新按钮
+                        if ($("#" + conid + " iframe").contents().find(".btn-refresh").size() > 0) {
+                            $("#" + conid + " iframe")[0].contentWindow.$(".btn-refresh").trigger("click");
+                        }
+                    } catch (e) {
+
+                    }
                 }
             }
             localStorage.setItem("addtabs", $(this).prop('outerHTML'));

+ 1 - 1
public/assets/js/require-form.js

@@ -1,7 +1,7 @@
 define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, Upload, Validator) {
     var Form = {
         config: {
-            fieldlisttpl: '<dd class="form-inline"><input type="text" name="<%=name%>[<%=index%>][key]" class="form-control" value="<%=row.key%>" size="10" /> <input type="text" name="<%=name%>[<%=index%>][value]" class="form-control" value="<%=row.value%>" size="40" /> <span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span> <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span></dd>'
+            fieldlisttpl: '<dd class="form-inline"><input type="text" name="<%=name%>[<%=index%>][key]" class="form-control" value="<%=row.key%>" size="10" /> <input type="text" name="<%=name%>[<%=index%>][value]" class="form-control" value="<%=row.value%>" size="30" /> <span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span> <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span></dd>'
         },
         events: {
             validator: function (form, success, error, submit) {

+ 1 - 1
public/assets/js/require-frontend.min.js

@@ -904,7 +904,7 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
                 i = 1;
             string = string.toLowerCase();
             //string = typeof Lang[string] != 'undefined' ? Lang[string] : string;
-            if (typeof Lang[string] != 'undefined') {
+            if (typeof Lang !== 'undefined' && typeof Lang[string] !== 'undefined') {
                 if (typeof Lang[string] == 'object')
                     return Lang[string];
                 string = Lang[string];

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

@@ -641,14 +641,14 @@ form.form-horizontal .control-label {
     float: left;
     background: none;
     margin-left: 0;
-    width: 80px;
+    min-width: 80px;
     clear: none;
   }
   .jstree-leaf {
     float: left;
     margin-left: 0;
     padding-left: 24px;
-    width: 80px;
+    min-width: 80px;
     clear: none;
     color: #777;
   }
@@ -1092,7 +1092,7 @@ table.table-nowrap {
   }
 
   .main-sidebar, .left-side {
-    padding-top: 94px;
+    padding-top: 50px;
   }
 
   .n-bootstrap {

+ 3 - 6
public/assets/less/frontend.less

@@ -261,7 +261,7 @@ body {
 }
 
 footer.footer{
-    width:100%;color: #aaa;background: #555;margin-top:25px;position: fixed;bottom: 0;z-index:99;
+    width:100%;color: #aaa;background: #555;margin-top:25px;
     .copyright{
         line-height: 50px;text-align: center;background: #393939;margin:0;
         a{
@@ -345,12 +345,9 @@ footer.footer{
 main.content {
     width:100%;
     overflow:auto;
-    top:0;
-    position:absolute;
-    z-index:10;
-    bottom:50px;
     padding:15px;
-    padding-top:67px;
+    padding-top:20px;
+    min-height:calc(~ '100vh - 125px');
 }
 
 .sidenav {

+ 1 - 1
public/install.php

@@ -409,7 +409,7 @@ if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST') {
         </form>
 
         <!-- jQuery -->
-        <script src="https://cdn.jsdelivr.net/npm/jquery@2.1.4/dist/jquery.min.js"></script>
+        <script src="https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
 
         <script>
             $(function () {