作者 Karson

添加多图上传预览和选择

新增bootstrap-table的主键功能,可传入pk设定表的主键
修复管理员权限不刷新的BUG
修复提示未登录时,在登录后不跳转之前页面的BUG
修复在移动版部分按钮在视图的布局
修复头像不显示的BUG
修改UC默认关闭
修复plupload方法重复绑定事件的BUG
修复部分样式的显示错误
修复登录Token错误的BUG
@@ -31,7 +31,7 @@ class Crud extends Command @@ -31,7 +31,7 @@ class Crud extends Command
31 { 31 {
32 $adminPath = dirname(__DIR__) . DS; 32 $adminPath = dirname(__DIR__) . DS;
33 //表名 33 //表名
34 - $table = $input->getOption('table') ? : ''; 34 + $table = $input->getOption('table') ?: '';
35 //自定义控制器 35 //自定义控制器
36 $controller = $input->getOption('controller'); 36 $controller = $input->getOption('controller');
37 //自定义模型 37 //自定义模型
@@ -96,6 +96,7 @@ class Crud extends Command @@ -96,6 +96,7 @@ class Crud extends Command
96 96
97 //从数据库中获取表字段信息 97 //从数据库中获取表字段信息
98 $columnList = Db::query("SELECT * FROM `information_schema`.`columns` WHERE TABLE_SCHEMA = ? AND table_name = ? ORDER BY ORDINAL_POSITION", [$dbname, $tableName]); 98 $columnList = Db::query("SELECT * FROM `information_schema`.`columns` WHERE TABLE_SCHEMA = ? AND table_name = ? ORDER BY ORDINAL_POSITION", [$dbname, $tableName]);
  99 +
99 $fields = []; 100 $fields = [];
100 foreach ($columnList as $k => $v) 101 foreach ($columnList as $k => $v)
101 { 102 {
@@ -109,6 +110,20 @@ class Crud extends Command @@ -109,6 +110,20 @@ class Crud extends Command
109 $field = 'id'; 110 $field = 'id';
110 $order = 'id'; 111 $order = 'id';
111 $priDefined = FALSE; 112 $priDefined = FALSE;
  113 + $prikey = '';
  114 + foreach ($columnList as $k => $v)
  115 + {
  116 + if ($v['COLUMN_KEY'] == 'PRI')
  117 + {
  118 + $prikey = $v['COLUMN_NAME'];
  119 + break;
  120 + }
  121 + }
  122 + if (!$prikey)
  123 + {
  124 + throw new Exception('Primary key not found!');
  125 + }
  126 + $order = $prikey;
112 127
113 try 128 try
114 { 129 {
@@ -161,7 +176,7 @@ class Crud extends Command @@ -161,7 +176,7 @@ class Crud extends Command
161 if ($v['DATA_TYPE'] == 'set') 176 if ($v['DATA_TYPE'] == 'set')
162 { 177 {
163 $attrArr['multiple'] = ''; 178 $attrArr['multiple'] = '';
164 - $fieldName.="[]"; 179 + $fieldName .= "[]";
165 } 180 }
166 $attrStr = $this->getArrayString($attrArr); 181 $attrStr = $this->getArrayString($attrArr);
167 $itemArr = $this->getLangArray($itemArr, FALSE); 182 $itemArr = $this->getLangArray($itemArr, FALSE);
@@ -209,7 +224,7 @@ class Crud extends Command @@ -209,7 +224,7 @@ class Crud extends Command
209 } 224 }
210 else if ($inputType == 'checkbox') 225 else if ($inputType == 'checkbox')
211 { 226 {
212 - $fieldName.="[]"; 227 + $fieldName .= "[]";
213 $itemArr = $this->getLangArray($itemArr, FALSE); 228 $itemArr = $this->getLangArray($itemArr, FALSE);
214 $itemString = $this->getArrayString($itemArr); 229 $itemString = $this->getArrayString($itemArr);
215 $formAddElement = "{:build_checkboxs('{$fieldName}', [{$itemString}], '{$defaultValue}')}"; 230 $formAddElement = "{:build_checkboxs('{$fieldName}', [{$itemString}], '{$defaultValue}')}";
@@ -252,7 +267,7 @@ class Crud extends Command @@ -252,7 +267,7 @@ class Crud extends Command
252 $step = array_intersect($cssClassArr, ['typeahead', 'tagsinput']) ? 0 : $step; 267 $step = array_intersect($cssClassArr, ['typeahead', 'tagsinput']) ? 0 : $step;
253 $attrArr['class'] = implode(' ', $cssClassArr); 268 $attrArr['class'] = implode(' ', $cssClassArr);
254 269
255 - $isUpload = substr($field, -4) == 'file' || substr($field, -5) == 'image' || substr($field, -6) == 'avatar' ? TRUE : FALSE; 270 + $isUpload = in_array(substr($field, -4), ['file']) || in_array(substr($field, -5), ['files', 'image']) || in_array(substr($field, -6), ['images', 'avatar']) || in_array(substr($field, -7), ['avatars']) ? TRUE : FALSE;
256 //如果是步长则加上步长 271 //如果是步长则加上步长
257 if ($step) 272 if ($step)
258 { 273 {
@@ -327,6 +342,7 @@ class Crud extends Command @@ -327,6 +342,7 @@ class Crud extends Command
327 'modelName' => $modelName, 342 'modelName' => $modelName,
328 'tableComment' => $tableComment, 343 'tableComment' => $tableComment,
329 'iconName' => $iconName, 344 'iconName' => $iconName,
  345 + 'pk' => $prikey,
330 'order' => $order, 346 'order' => $order,
331 'table' => $table, 347 'table' => $table,
332 'tableName' => $tableName, 348 'tableName' => $tableName,
@@ -531,11 +547,16 @@ EOD; @@ -531,11 +547,16 @@ EOD;
531 */ 547 */
532 protected function getImageUpload($field, $content) 548 protected function getImageUpload($field, $content)
533 { 549 {
534 - $filter = substr($field, -4) == 'avatar' || substr($field, -5) == 'image' ? 'data-mimetype="image/*"' : ""; 550 + $filter = substr($field, -4) == 'avatar' || substr($field, -5) == 'image' || substr($field, -6) == 'images' ? ' data-mimetype="image/*"' : "";
  551 + $multiple = substr($field, -1) == 's' ? ' data-multiple="true"' : ' data-multiple="false"';
  552 + $preview = $filter ? ' data-preview-id="p-' . $field . '"' : '';
  553 + $previewcontainer = $preview ? '<ul class="row list-inline plupload-preview" id="p-' . $field . '"></ul>' : '';
535 return <<<EOD 554 return <<<EOD
536 <div class="form-inline"> 555 <div class="form-inline">
537 {$content} 556 {$content}
538 - <span><button id="plupload-{$field}" class="btn btn-danger plupload" data-input-id="c-{$field}"{$filter}><i class="fa fa-upload"></i> {:__('Upload')}</button></span> 557 + <span><button type="button" id="plupload-{$field}" class="btn btn-danger plupload" data-input-id="c-{$field}"{$filter}{$multiple}{$preview}><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
  558 + <span><button type="button" id="fachoose-{$field}" class="btn btn-primary fachoose" data-input-id="c-{$field}"{$filter}{$multiple}><i class="fa fa-list"></i> {:__('Choose')}</button></span>
  559 + {$previewcontainer}
539 </div> 560 </div>
540 EOD; 561 EOD;
541 } 562 }
@@ -19,6 +19,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin @@ -19,6 +19,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
19 // 初始化表格 19 // 初始化表格
20 table.bootstrapTable({ 20 table.bootstrapTable({
21 url: $.fn.bootstrapTable.defaults.extend.index_url, 21 url: $.fn.bootstrapTable.defaults.extend.index_url,
  22 + pk: '{%pk%}',
22 sortName: '{%order%}', 23 sortName: '{%order%}',
23 columns: [ 24 columns: [
24 [ 25 [
@@ -70,18 +70,18 @@ class Index extends Backend @@ -70,18 +70,18 @@ class Index extends Backend
70 $result = $validate->check($data); 70 $result = $validate->check($data);
71 if (!$result) 71 if (!$result)
72 { 72 {
73 - $this->error($validate->getError()); 73 + $this->error($validate->getError(), $url, ['token' => $this->request->token()]);
74 return; 74 return;
75 } 75 }
76 $result = $this->auth->login($username, $password, $keeplogin ? 86400 : 0); 76 $result = $this->auth->login($username, $password, $keeplogin ? 86400 : 0);
77 if ($result === true) 77 if ($result === true)
78 { 78 {
79 - $this->success(__('Login successful'), $url); 79 + $this->success(__('Login successful'), $url, ['url' => $url]);
80 return; 80 return;
81 } 81 }
82 else 82 else
83 { 83 {
84 - $this->error(__('Username or password is incorrect'), $url); 84 + $this->error(__('Username or password is incorrect'), $url, ['token' => $this->request->token()]);
85 } 85 }
86 return; 86 return;
87 } 87 }
@@ -46,6 +46,32 @@ class Attachment extends Backend @@ -46,6 +46,32 @@ class Attachment extends Backend
46 } 46 }
47 return $this->view->fetch(); 47 return $this->view->fetch();
48 } 48 }
  49 +
  50 + /**
  51 + * 选择附件
  52 + */
  53 + public function select()
  54 + {
  55 + if ($this->request->isAjax())
  56 + {
  57 + list($where, $sort, $order, $offset, $limit) = $this->buildparams();
  58 + $total = $this->model
  59 + ->where($where)
  60 + ->order($sort, $order)
  61 + ->count();
  62 +
  63 + $list = $this->model
  64 + ->where($where)
  65 + ->order($sort, $order)
  66 + ->limit($offset, $limit)
  67 + ->select();
  68 +
  69 + $result = array("total" => $total, "rows" => $list);
  70 +
  71 + return json($result);
  72 + }
  73 + return $this->view->fetch();
  74 + }
49 75
50 /** 76 /**
51 * 添加 77 * 添加
@@ -2,7 +2,6 @@ @@ -2,7 +2,6 @@
2 2
3 namespace app\admin\library\traits; 3 namespace app\admin\library\traits;
4 4
5 -  
6 trait Backend 5 trait Backend
7 { 6 {
8 7
@@ -61,7 +60,7 @@ trait Backend @@ -61,7 +60,7 @@ trait Backend
61 */ 60 */
62 public function edit($ids = NULL) 61 public function edit($ids = NULL)
63 { 62 {
64 - $row = $this->model->get(['id' => $ids]); 63 + $row = $this->model->get($ids);
65 if (!$row) 64 if (!$row)
66 $this->error(__('No Results were found')); 65 $this->error(__('No Results were found'));
67 if ($this->request->isPost()) 66 if ($this->request->isPost())
@@ -93,7 +92,7 @@ trait Backend @@ -93,7 +92,7 @@ trait Backend
93 $this->code = -1; 92 $this->code = -1;
94 if ($ids) 93 if ($ids)
95 { 94 {
96 - $count = $this->model->where('id', 'in', $ids)->delete(); 95 + $count = $this->model->destroy($ids);
97 if ($count) 96 if ($count)
98 { 97 {
99 $this->code = 1; 98 $this->code = 1;
@@ -118,7 +117,7 @@ trait Backend @@ -118,7 +117,7 @@ trait Backend
118 $values = array_intersect_key($values, array_flip(array('status'))); 117 $values = array_intersect_key($values, array_flip(array('status')));
119 if ($values) 118 if ($values)
120 { 119 {
121 - $count = $this->model->where('id', 'in', $ids)->update($values); 120 + $count = $this->model->where($this->model->getPk(), 'in', $ids)->update($values);
122 if ($count) 121 if ($count)
123 { 122 {
124 $this->code = 1; 123 $this->code = 1;
@@ -64,7 +64,7 @@ @@ -64,7 +64,7 @@
64 </a> 64 </a>
65 </li> 65 </li>
66 66
67 - <li> 67 + <li class="hidden-xs">
68 <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-language"></i></a> 68 <a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-language"></i></a>
69 <ul class="dropdown-menu"> 69 <ul class="dropdown-menu">
70 <li class="{$config['language']=='zh-cn'?'active':''}"> 70 <li class="{$config['language']=='zh-cn'?'active':''}">
@@ -76,7 +76,7 @@ @@ -76,7 +76,7 @@
76 </ul> 76 </ul>
77 </li> 77 </li>
78 78
79 - <li> 79 + <li class="hidden-xs">
80 <a href="#" data-toggle="fullscreen"><i class="fa fa-arrows-alt"></i></a> 80 <a href="#" data-toggle="fullscreen"><i class="fa fa-arrows-alt"></i></a>
81 </li> 81 </li>
82 82
  1 +<div class="panel panel-default panel-intro">
  2 + {:build_heading()}
  3 +
  4 + <div class="panel-body">
  5 + <div id="myTabContent" class="tab-content">
  6 + <div class="tab-pane fade active in" id="one">
  7 + <div class="widget-body no-padding">
  8 + <div id="toolbar" class="toolbar">
  9 + {:build_toolbar('refresh')}
  10 + {if request()->get('multiple') == 'true'}
  11 + <a class="btn btn-danger btn-choose-multi"><i class="fa fa-check"></i> {:__('Choose')}</a>
  12 + {/if}
  13 + </div>
  14 + <table id="table" class="table table-bordered table-hover" width="100%">
  15 +
  16 + </table>
  17 + </div>
  18 + </div>
  19 +
  20 + </div>
  21 + </div>
  22 +</div>
@@ -41,7 +41,7 @@ @@ -41,7 +41,7 @@
41 <div class="box-body box-profile"> 41 <div class="box-body box-profile">
42 42
43 <div class="profile-avatar-container"> 43 <div class="profile-avatar-container">
44 - <img class="profile-user-img img-responsive img-circle plupload" src="{$admin.avatar}" alt=""> 44 + <img class="profile-user-img img-responsive img-circle plupload" src="__CDN__{$admin.avatar}" alt="">
45 <div class="profile-avatar-text img-circle">{:__('Click to edit')}</div> 45 <div class="profile-avatar-text img-circle">{:__('Click to edit')}</div>
46 <button id="plupload-avatar" class="plupload" data-input-id="c-avatar" data-after-upload="changeavatar"><i class="fa fa-upload"></i> {:__('Upload')}</button> 46 <button id="plupload-avatar" class="plupload" data-input-id="c-avatar" data-after-upload="changeavatar"><i class="fa fa-upload"></i> {:__('Upload')}</button>
47 </div> 47 </div>
@@ -28,7 +28,8 @@ @@ -28,7 +28,8 @@
28 <div class="col-xs-12 col-sm-8"> 28 <div class="col-xs-12 col-sm-8">
29 <div class="form-inline"> 29 <div class="form-inline">
30 <input id="c-image" class="form-control" size="50" name="row[image]" type="text" value=""> 30 <input id="c-image" class="form-control" size="50" name="row[image]" type="text" value="">
31 - <span><button id="plupload-image" class="btn btn-danger plupload" data-input-id="c-image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> 31 + <span><button id="plupload-image" class="btn btn-danger plupload" data-input-id="c-image" data-preview-id="plupload-preview-image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
  32 + <ul class="row list-inline plupload-preview" id="plupload-preview-image"></ul>
32 </div> 33 </div>
33 </div> 34 </div>
34 </div> 35 </div>
@@ -29,7 +29,9 @@ @@ -29,7 +29,9 @@
29 <div class="col-xs-12 col-sm-8"> 29 <div class="col-xs-12 col-sm-8">
30 <div class="form-inline"> 30 <div class="form-inline">
31 <input id="c-image" class="form-control" size="50" name="row[image]" type="text" value="{$row.image}"> 31 <input id="c-image" class="form-control" size="50" name="row[image]" type="text" value="{$row.image}">
32 - <span><button id="plupload-image" class="btn btn-danger plupload" data-input-id="c-image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span> 32 + <span><button type="button" id="plupload-image" class="btn btn-danger plupload" data-multiple="false" data-input-id="c-image" data-preview-id="p-image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
  33 + <span><button type="button" id="fachoose-image" class="btn btn-primary fachoose" data-multiple="false" data-input-id="c-image"><i class="fa fa-list-ul"></i> {:__('Choose')}</button></span>
  34 + <ul class="row list-inline plupload-preview" id="p-image"></ul>
33 </div> 35 </div>
34 </div> 36 </div>
35 </div> 37 </div>
@@ -93,19 +93,22 @@ class Backend extends Controller @@ -93,19 +93,22 @@ class Backend extends Controller
93 93
94 // 设置当前请求的URI 94 // 设置当前请求的URI
95 $this->auth->setRequestUri($path); 95 $this->auth->setRequestUri($path);
96 -  
97 // 检测是否需要验证登录 96 // 检测是否需要验证登录
98 if (!$this->auth->match($this->noNeedLogin)) 97 if (!$this->auth->match($this->noNeedLogin))
99 { 98 {
100 //检测是否登录 99 //检测是否登录
101 if (!$this->auth->isLogin()) 100 if (!$this->auth->isLogin())
102 { 101 {
103 - $this->error(__('Please login first'), url('index/login', ['url' => $this->request->url()])); 102 + $url = Session::get('referer');
  103 + $url = $url ? $url : $this->request->url();
  104 + $this->error(__('Please login first'), url('index/login', ['url' => $url]));
104 } 105 }
105 // 判断是否需要验证权限 106 // 判断是否需要验证权限
106 if (!$this->auth->match($this->noNeedRight)) 107 if (!$this->auth->match($this->noNeedRight))
107 { 108 {
108 // 判断控制器和方法判断是否有对应权限 109 // 判断控制器和方法判断是否有对应权限
  110 + $path = $this->request->path();
  111 + $path = substr($path, 0, 1) == '/' ? $path : '/' . $path;
109 if (!$this->auth->check($path)) 112 if (!$this->auth->check($path))
110 { 113 {
111 $this->error(__('You have no permission'), NULL); 114 $this->error(__('You have no permission'), NULL);
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 2
3 //UC配置 3 //UC配置
4 // Ucenter配置配置 4 // Ucenter配置配置
5 -define('UC_STATUS', TRUE); //是否开启Ucenter同步 5 +define('UC_STATUS', false); //是否开启Ucenter同步
6 6
7 define('UC_CONNECT', 'mysql'); 7 define('UC_CONNECT', 'mysql');
8 8
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
26 "bootstrap3-dialog": "bootstrap-dialog#^1.35.3", 26 "bootstrap3-dialog": "bootstrap-dialog#^1.35.3",
27 "require-css": "^0.1.8", 27 "require-css": "^0.1.8",
28 "less": "^2.7.1", 28 "less": "^2.7.1",
29 - "tableExport.jquery.plugin": "^1.6.4", 29 + "tableExport.jquery.plugin": "^1.9.0",
30 "jquery-slimscroll": "slimscroll#^1.3.8", 30 "jquery-slimscroll": "slimscroll#^1.3.8",
31 "jquery.cookie": "^1.4.1", 31 "jquery.cookie": "^1.4.1",
32 "Sortable": "^1.5.0", 32 "Sortable": "^1.5.0",
@@ -209,7 +209,7 @@ class Auth @@ -209,7 +209,7 @@ class Auth
209 $_rulelist[$uid] = []; 209 $_rulelist[$uid] = [];
210 return []; 210 return [];
211 } 211 }
212 - 212 +
213 // 筛选条件 213 // 筛选条件
214 $where = [ 214 $where = [
215 'status' => 'normal' 215 'status' => 'normal'
@@ -220,9 +220,13 @@ class Auth @@ -220,9 +220,13 @@ class Auth
220 } 220 }
221 //读取用户组所有权限规则 221 //读取用户组所有权限规则
222 $this->rules = Db::name($this->config['auth_rule'])->where($where)->field('id,pid,condition,icon,name,title,ismenu')->select(); 222 $this->rules = Db::name($this->config['auth_rule'])->where($where)->field('id,pid,condition,icon,name,title,ismenu')->select();
223 - 223 +
224 //循环规则,判断结果。 224 //循环规则,判断结果。
225 $rulelist = []; // 225 $rulelist = []; //
  226 + if (in_array('*', $ids))
  227 + {
  228 + $rulelist[] = "*";
  229 + }
226 foreach ($this->rules as $rule) 230 foreach ($this->rules as $rule)
227 { 231 {
228 //超级管理员无需验证condition 232 //超级管理员无需验证condition
@@ -106,8 +106,9 @@ body { @@ -106,8 +106,9 @@ body {
106 font-weight: normal; 106 font-weight: normal;
107 } 107 }
108 .user-panel > .image img { 108 .user-panel > .image img {
109 - width: 45px;  
110 - height: 45px; 109 + width: 100%;
  110 + max-width: 45px;
  111 + max-height: 45px;
111 } 112 }
112 /*panel扩展描述样式*/ 113 /*panel扩展描述样式*/
113 .panel-intro { 114 .panel-intro {
@@ -329,6 +330,26 @@ body { @@ -329,6 +330,26 @@ body {
329 .note-editor .note-editing-area .note-editable { 330 .note-editor .note-editing-area .note-editable {
330 display: block !important; 331 display: block !important;
331 } 332 }
  333 +.plupload-preview {
  334 + padding: 10px;
  335 + margin-bottom: 0;
  336 +}
  337 +.plupload-preview li {
  338 + margin-bottom: 10px;
  339 +}
  340 +.plupload-preview .thumbnail {
  341 + margin-bottom: 10px;
  342 +}
  343 +.plupload-preview a {
  344 + display: block;
  345 +}
  346 +.plupload-preview a:first-child {
  347 + height: 90px;
  348 +}
  349 +.plupload-preview a img {
  350 + height: 80px;
  351 + object-fit: cover;
  352 +}
332 .pjax-loader-bar .progress { 353 .pjax-loader-bar .progress {
333 position: fixed; 354 position: fixed;
334 top: 0; 355 top: 0;
@@ -526,6 +547,9 @@ body { @@ -526,6 +547,9 @@ body {
526 .nav-addtabs { 547 .nav-addtabs {
527 display: none; 548 display: none;
528 } 549 }
  550 + .fixed-table-toolbar .columns-right.btn-group {
  551 + display: none;
  552 + }
529 } 553 }
530 /*平板样式*/ 554 /*平板样式*/
531 /*# sourceMappingURL=backend.css.map */ 555 /*# sourceMappingURL=backend.css.map */
@@ -42,6 +42,63 @@ define(['jquery', 'bootstrap', 'backend', 'form', 'table'], function ($, undefin @@ -42,6 +42,63 @@ define(['jquery', 'bootstrap', 'backend', 'form', 'table'], function ($, undefin
42 Table.api.bindevent(table); 42 Table.api.bindevent(table);
43 43
44 }, 44 },
  45 + select: function () {
  46 + // 初始化表格参数配置
  47 + Table.api.init({
  48 + extend: {
  49 + index_url: 'general/attachment/select',
  50 + }
  51 + });
  52 +
  53 + var table = $("#table");
  54 +
  55 + // 初始化表格
  56 + table.bootstrapTable({
  57 + url: $.fn.bootstrapTable.defaults.extend.index_url,
  58 + sortName: 'id',
  59 + columns: [
  60 + [
  61 + {field: 'state', checkbox: true, },
  62 + {field: 'id', title: __('Id')},
  63 + {field: 'url', title: __('Preview'), formatter: Controller.api.formatter.thumb},
  64 + {field: 'imagewidth', title: __('Imagewidth')},
  65 + {field: 'imageheight', title: __('Imageheight')},
  66 + {field: 'mimetype', title: __('Mimetype'), operate: 'LIKE %...%',
  67 + process: function (value, arg) {
  68 + return value.replace(/\*/g, '%');
  69 + }},
  70 + {field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime},
  71 + {field: 'operate', title: __('Operate'), events: {
  72 + 'click .btn-chooseone': function (e, value, row, index) {
  73 + var callback = Backend.api.query('callback');
  74 + var id = Backend.api.query('element_id');
  75 + var multiple = Backend.api.query('multiple');
  76 + multiple = multiple == 'true' ? true : false;
  77 + if (id && callback) {
  78 + parent.window[callback](id, {url: row.url}, multiple);
  79 + }
  80 + },
  81 + }, formatter: function () {
  82 + return '<a href="javascript:;" class="btn btn-danger btn-chooseone btn-xs"><i class="fa fa-check"></i> ' + __('Choose') + '</a>';
  83 + }}
  84 + ]
  85 + ]
  86 + });
  87 +
  88 + // 选中多个
  89 + $(document).on("click", ".btn-choose-multi", function () {
  90 + var callback = Backend.api.query('callback');
  91 + var id = Backend.api.query('element_id');
  92 + var urlArr = new Array();
  93 + $.each(table.bootstrapTable("getAllSelections"), function (i, j) {
  94 + urlArr.push(j.url);
  95 + });
  96 + parent.window[callback](id, {url: urlArr.join(",")}, true);
  97 + });
  98 +
  99 + // 为表格绑定事件
  100 + Table.api.bindevent(table);
  101 + },
45 add: function () { 102 add: function () {
46 Controller.api.bindevent(); 103 Controller.api.bindevent();
47 }, 104 },
@@ -141,7 +141,7 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi @@ -141,7 +141,7 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
141 if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) { 141 if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) {
142 $(".tab-addtabs").addClass("ios-iframe-fix"); 142 $(".tab-addtabs").addClass("ios-iframe-fix");
143 } 143 }
144 - 144 +
145 if (Config.referer) { 145 if (Config.referer) {
146 //刷新页面后跳到到刷新前的页面 146 //刷新页面后跳到到刷新前的页面
147 Backend.api.addtabs(Config.referer); 147 Backend.api.addtabs(Config.referer);
@@ -322,8 +322,8 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi @@ -322,8 +322,8 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
322 $(window).resize(); 322 $(window).resize();
323 }, 323 },
324 login: function () { 324 login: function () {
325 - Form.api.bindevent($("#login-form"), null, function () {  
326 - location.href = Backend.api.fixurl("index/index"); 325 + Form.api.bindevent($("#login-form"), null, function (data) {
  326 + location.href = Backend.api.fixurl(data.url);
327 }); 327 });
328 } 328 }
329 }; 329 };
@@ -51,6 +51,9 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'upload', 'validator'], func @@ -51,6 +51,9 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'upload', 'validator'], func
51 } 51 }
52 Toastr.success(msg ? msg : __('Operation completed')); 52 Toastr.success(msg ? msg : __('Operation completed'));
53 } else { 53 } else {
  54 + if (typeof data.token !== 'undefined') {
  55 + $("input[name='__token__']").val(data.token);
  56 + }
54 Toastr.error(msg ? msg : __('Operation failed')); 57 Toastr.error(msg ? msg : __('Operation failed'));
55 } 58 }
56 } else { 59 } else {
@@ -230,6 +233,33 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'upload', 'validator'], func @@ -230,6 +233,33 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'upload', 'validator'], func
230 if ($(".plupload", form).size() > 0) { 233 if ($(".plupload", form).size() > 0) {
231 Upload.api.plupload(); 234 Upload.api.plupload();
232 } 235 }
  236 +
  237 + //绑定fachoose选择附件事件
  238 + if ($(".fachoose", form).size() > 0) {
  239 + $(document).on('click', ".fachoose", function () {
  240 + var multiple = $(this).data("multiple") ? $(this).data("multiple") : false;
  241 + var mimetype = $(this).data("mimetype") ? $(this).data("mimetype") : '';
  242 + Backend.api.open("general/attachment/select?callback=refreshchoose&element_id=" + $(this).attr("id") + "&multiple=" + multiple + "&mimetype="+mimetype, __('Choose'));
  243 + return false;
  244 + });
  245 +
  246 + //刷新选择的元素
  247 + window.refreshchoose = function (id, data, multiple) {
  248 + var input_id = $("#" + id).data("input-id");
  249 + if (multiple) {
  250 + var urlArr = [];
  251 + var inputObj = $("#" + input_id);
  252 + if (inputObj.val() != "") {
  253 + urlArr.push(inputObj.val());
  254 + }
  255 + urlArr.push(data.url);
  256 + inputObj.val(urlArr.join(",")).trigger("change");
  257 + } else {
  258 + $("#" + input_id).val(data.url).trigger("change");
  259 + }
  260 + layer.closeAll();
  261 + };
  262 + }
233 }, 263 },
234 custom: {} 264 custom: {}
235 }, 265 },
@@ -24,6 +24,7 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'moment', 'bootstrap-table', @@ -24,6 +24,7 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'moment', 'bootstrap-table',
24 locale: 'zh-CN', 24 locale: 'zh-CN',
25 showToggle: true, 25 showToggle: true,
26 showColumns: true, 26 showColumns: true,
  27 + pk: 'id',
27 sortName: 'id', 28 sortName: 'id',
28 sortOrder: 'desc', 29 sortOrder: 'desc',
29 paginationFirstText: __("First"), 30 paginationFirstText: __("First"),
@@ -110,6 +111,7 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'moment', 'bootstrap-table', @@ -110,6 +111,7 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'moment', 'bootstrap-table',
110 //当内容渲染完成后 111 //当内容渲染完成后
111 table.on('post-body.bs.table', function (e, settings, json, xhr) { 112 table.on('post-body.bs.table', function (e, settings, json, xhr) {
112 $(Table.config.refreshbtn, toolbar).find(".fa").removeClass("fa-spin"); 113 $(Table.config.refreshbtn, toolbar).find(".fa").removeClass("fa-spin");
  114 + $(Table.config.disabledbtn, toolbar).toggleClass('disabled', true);
113 115
114 // 挺拽选择,需要重新绑定事件 116 // 挺拽选择,需要重新绑定事件
115 require(['drag', 'drop'], function () { 117 require(['drag', 'drop'], function () {
@@ -187,24 +189,25 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'moment', 'bootstrap-table', @@ -187,24 +189,25 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'moment', 'bootstrap-table',
187 dragEnd: function () { 189 dragEnd: function () {
188 var data = table.bootstrapTable('getData'); 190 var data = table.bootstrapTable('getData');
189 var current = data[parseInt($(this).data("index"))]; 191 var current = data[parseInt($(this).data("index"))];
  192 + var options = table.bootstrapTable('getOptions');
190 //改变的值和改变的ID集合 193 //改变的值和改变的ID集合
191 var ids = $.map($("tbody tr:visible", table), function (tr) { 194 var ids = $.map($("tbody tr:visible", table), function (tr) {
192 - return data[parseInt($(tr).data("index"))].id; 195 + return data[parseInt($(tr).data("index"))][options.pk];
193 }); 196 });
194 - var changeid = current.id; 197 + var changeid = current[options.pk];
195 var pid = typeof current.pid != 'undefined' ? current.pid : ''; 198 var pid = typeof current.pid != 'undefined' ? current.pid : '';
196 - var options = { 199 + var params = {
197 url: table.bootstrapTable('getOptions').extend.dragsort_url, 200 url: table.bootstrapTable('getOptions').extend.dragsort_url,
198 data: { 201 data: {
199 ids: ids.join(','), 202 ids: ids.join(','),
200 changeid: changeid, 203 changeid: changeid,
201 pid: pid, 204 pid: pid,
202 field: Table.config.dragsortfield, 205 field: Table.config.dragsortfield,
203 - orderway: table.bootstrapTable('getOptions').sortOrder,  
204 - table: table.bootstrapTable('getOptions').extend.table 206 + orderway: options.sortOrder,
  207 + table: options.extend.table
205 } 208 }
206 }; 209 };
207 - Backend.api.ajax(options, function (data) { 210 + Backend.api.ajax(params, function (data) {
208 Toastr.success(__('Operation completed')); 211 Toastr.success(__('Operation completed'));
209 table.bootstrapTable('refresh'); 212 table.bootstrapTable('refresh');
210 }); 213 });
@@ -233,7 +236,7 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'moment', 'bootstrap-table', @@ -233,7 +236,7 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'moment', 'bootstrap-table',
233 operate: { 236 operate: {
234 'click .btn-editone': function (e, value, row, index) { 237 'click .btn-editone': function (e, value, row, index) {
235 var options = $(this).closest('table').bootstrapTable('getOptions'); 238 var options = $(this).closest('table').bootstrapTable('getOptions');
236 - Backend.api.open(options.extend.edit_url + "/ids/" + row.id, __('Edit')); 239 + Backend.api.open(options.extend.edit_url + "/ids/" + row[options.pk], __('Edit'));
237 }, 240 },
238 'click .btn-delone': function (e, value, row, index) { 241 'click .btn-delone': function (e, value, row, index) {
239 var that = this; 242 var that = this;
@@ -250,7 +253,8 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'moment', 'bootstrap-table', @@ -250,7 +253,8 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'moment', 'bootstrap-table',
250 {icon: 3, title: __('Warning'), offset: [top, left], shadeClose: true}, 253 {icon: 3, title: __('Warning'), offset: [top, left], shadeClose: true},
251 function () { 254 function () {
252 var table = $(that).closest('table'); 255 var table = $(that).closest('table');
253 - Table.api.multi("del", row.id, table, that); 256 + var options = table.bootstrapTable('getOptions');
  257 + Table.api.multi("del", row[options.pk], table, that);
254 Backend.api.layer.close(index); 258 Backend.api.layer.close(index);
255 } 259 }
256 ); 260 );
@@ -341,8 +345,9 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'moment', 'bootstrap-table', @@ -341,8 +345,9 @@ define(['jquery', 'bootstrap', 'backend', 'toastr', 'moment', 'bootstrap-table',
341 }, 345 },
342 // 获取选中的条目ID集合 346 // 获取选中的条目ID集合
343 selectedids: function (table) { 347 selectedids: function (table) {
  348 + var options = table.bootstrapTable('getOptions');
344 return $.map(table.bootstrapTable('getSelections'), function (row) { 349 return $.map(table.bootstrapTable('getSelections'), function (row) {
345 - return row.id 350 + return row[options.pk];
346 }); 351 });
347 }, 352 },
348 // 切换复选框状态 353 // 切换复选框状态
1 -define(['jquery', 'bootstrap', 'backend', 'plupload'], function ($, undefined, Backend, Plupload) { 1 +define(['jquery', 'bootstrap', 'backend', 'plupload', 'dragsort', 'template'], function ($, undefined, Backend, Plupload, Dragsort, Template) {
2 var Upload = { 2 var Upload = {
3 list: {}, 3 list: {},
4 config: { 4 config: {
5 container: document.body, 5 container: document.body,
6 - classname: '.plupload', 6 + classname: '.plupload:not([initialized])',
  7 + previewtpl: '<li class="col-xs-3"><a href="<%=fullurl%>" data-url="<%=url%>" target="_blank" class="thumbnail"><img src="<%=fullurl%>" class="img-responsive"></a><a href="javascript:;" class="btn btn-danger btn-xs btn-trash"><i class="fa fa-trash"></i></a></li>',
7 }, 8 },
8 api: { 9 api: {
9 //Plupload上传 10 //Plupload上传
10 plupload: function (element, onAfterUpload) { 11 plupload: function (element, onAfterUpload) {
11 element = typeof element == 'undefined' ? Upload.config.classname : element; 12 element = typeof element == 'undefined' ? Upload.config.classname : element;
12 $(element, Upload.config.container).each(function () { 13 $(element, Upload.config.container).each(function () {
  14 + $(this).attr("initialized", true);
13 var that = this; 15 var that = this;
14 var id = $(this).prop("id"); 16 var id = $(this).prop("id");
15 var url = $(this).data("url"); 17 var url = $(this).data("url");
@@ -20,14 +22,18 @@ define(['jquery', 'bootstrap', 'backend', 'plupload'], function ($, undefined, B @@ -20,14 +22,18 @@ define(['jquery', 'bootstrap', 'backend', 'plupload'], function ($, undefined, B
20 //上传URL 22 //上传URL
21 url = url ? url : Config.upload.uploadurl; 23 url = url ? url : Config.upload.uploadurl;
22 url = Backend.api.fixurl(url); 24 url = Backend.api.fixurl(url);
  25 + //填充ID
  26 + var input_id = $(that).data("input-id") ? $(that).data("input-id") : "";
  27 + //预览ID
  28 + var preview_id = $(that).data("preview-id") ? $(that).data("preview-id") : "";
23 //最大可上传 29 //最大可上传
24 - maxsize = maxsize ? maxsize : Config.upload.maxsize; 30 + maxsize = typeof maxsize !== "undefined" ? maxsize : Config.upload.maxsize;
25 //文件类型 31 //文件类型
26 - mimetype = mimetype ? mimetype : Config.upload.mimetype; 32 + mimetype = typeof mimetype !== "undefined" ? mimetype : Config.upload.mimetype;
27 //请求的表单参数 33 //请求的表单参数
28 - multipart = multipart ? multipart : Config.upload.multipart; 34 + multipart = typeof multipart !== "undefined" ? multipart : Config.upload.multipart;
29 //是否支持批量上传 35 //是否支持批量上传
30 - multiple = multiple ? multiple : Config.upload.multiple; 36 + multiple = typeof multiple !== "undefined" ? multiple : Config.upload.multiple;
31 //生成Plupload实例 37 //生成Plupload实例
32 Upload.list[id] = new Plupload.Uploader({ 38 Upload.list[id] = new Plupload.Uploader({
33 runtimes: 'html5,flash,silverlight,html4', 39 runtimes: 'html5,flash,silverlight,html4',
@@ -63,6 +69,7 @@ define(['jquery', 'bootstrap', 'backend', 'plupload'], function ($, undefined, B @@ -63,6 +69,7 @@ define(['jquery', 'bootstrap', 'backend', 'plupload'], function ($, undefined, B
63 $(that).prop("disabled", true).html("<i class='fa fa-upload'></i> 上传" + file.percent + "%"); 69 $(that).prop("disabled", true).html("<i class='fa fa-upload'></i> 上传" + file.percent + "%");
64 }, 70 },
65 FileUploaded: function (up, file, info) { 71 FileUploaded: function (up, file, info) {
  72 + var options = this.getOption();
66 //还原按钮文字及状态 73 //还原按钮文字及状态
67 $(that).prop("disabled", false).html($(that).data("bakup-html")); 74 $(that).prop("disabled", false).html($(that).data("bakup-html"));
68 //这里可以改成其它的表现形式 75 //这里可以改成其它的表现形式
@@ -76,9 +83,14 @@ define(['jquery', 'bootstrap', 'backend', 'plupload'], function ($, undefined, B @@ -76,9 +83,14 @@ define(['jquery', 'bootstrap', 'backend', 'plupload'], function ($, undefined, B
76 var data = ret.hasOwnProperty("data") && ret.data != "" ? ret.data : null; 83 var data = ret.hasOwnProperty("data") && ret.data != "" ? ret.data : null;
77 var msg = ret.hasOwnProperty("msg") && ret.msg != "" ? ret.msg : ""; 84 var msg = ret.hasOwnProperty("msg") && ret.msg != "" ? ret.msg : "";
78 if (ret.code === 1) { 85 if (ret.code === 1) {
79 - //$("input[data-plupload-id='" + id + "-text']").val(data.url);  
80 - if ($(that).data("input-id")) {  
81 - $("input#" + $(that).data("input-id")).val(data.url); 86 + if (input_id) {
  87 + var urlArr = [];
  88 + var inputObj = $("#" + input_id);
  89 + if (options.multi_selection && inputObj.val() != "") {
  90 + urlArr.push(inputObj.val());
  91 + }
  92 + urlArr.push(data.url);
  93 + inputObj.val(urlArr.join(",")).trigger("change");
82 } 94 }
83 var afterUpload = $("#" + id).data("after-upload"); 95 var afterUpload = $("#" + id).data("after-upload");
84 if (afterUpload && typeof Upload.api.custom[afterUpload] == 'function') { 96 if (afterUpload && typeof Upload.api.custom[afterUpload] == 'function') {
@@ -102,6 +114,49 @@ define(['jquery', 'bootstrap', 'backend', 'plupload'], function ($, undefined, B @@ -102,6 +114,49 @@ define(['jquery', 'bootstrap', 'backend', 'plupload'], function ($, undefined, B
102 } 114 }
103 } 115 }
104 }); 116 });
  117 +
  118 + //拖动排序
  119 + if (preview_id && multiple) {
  120 + $("#" + preview_id).dragsort({
  121 + dragSelector: "li",
  122 + dragEnd: function () {
  123 + $("#" + preview_id).trigger("fa.preview.change");
  124 + },
  125 + placeHolderTemplate: '<li class="col-xs-3"></li>'
  126 + });
  127 + }
  128 + if (preview_id && input_id) {
  129 + $(document.body).on("keyup change", "#" + input_id, function () {
  130 + var inputStr = $("#" + input_id).val();
  131 + var inputArr = inputStr.split(/\,/);
  132 + $("#" + preview_id).empty();
  133 + $.each(inputArr, function (i, j) {
  134 + if (!j) {
  135 + return true;
  136 + }
  137 + var html = Template.render(Upload.config.previewtpl, {url: j, fullurl: Config.upload.cdnurl + j});
  138 + $("#" + preview_id).append(html);
  139 + });
  140 + });
  141 + $("#" + input_id).trigger("keyup");
  142 + }
  143 + if (preview_id) {
  144 + // 监听事件
  145 + $(document.body).on("fa.preview.change", "#" + preview_id, function () {
  146 + var urlArr = new Array();
  147 + $("#" + preview_id + " [data-url]").each(function (i, j) {
  148 + urlArr.push($(this).data("url"));
  149 + });
  150 + if (input_id) {
  151 + $("#" + input_id).val(urlArr.join(","));
  152 + }
  153 + });
  154 + //移除按钮事件
  155 + $(document.body).on("click", "#" + preview_id + " .btn-trash", function () {
  156 + $(this).closest("li").remove();
  157 + $("#" + preview_id).trigger("fa.preview.change");
  158 + });
  159 + }
105 Upload.list[id].init(); 160 Upload.list[id].init();
106 }); 161 });
107 }, 162 },
@@ -140,8 +140,9 @@ body { @@ -140,8 +140,9 @@ body {
140 } 140 }
141 141
142 .user-panel > .image img{ 142 .user-panel > .image img{
143 - width:45px;  
144 - height:45px; 143 + width:100%;
  144 + max-width:45px;
  145 + max-height:45px;
145 } 146 }
146 147
147 /*panel扩展描述样式*/ 148 /*panel扩展描述样式*/
@@ -364,6 +365,27 @@ body { @@ -364,6 +365,27 @@ body {
364 display: block !important; 365 display: block !important;
365 } 366 }
366 367
  368 +.plupload-preview {
  369 + padding:10px;
  370 + margin-bottom:0;
  371 + li {
  372 + margin-bottom:10px;
  373 + }
  374 + .thumbnail {
  375 + margin-bottom:10px;
  376 + }
  377 + a{
  378 + display:block;
  379 + &:first-child{
  380 + height:90px;
  381 + }
  382 + img{
  383 + height:80px;
  384 + object-fit: cover;
  385 + }
  386 + }
  387 +}
  388 +
367 .pjax-loader-bar .progress { 389 .pjax-loader-bar .progress {
368 position: fixed; 390 position: fixed;
369 top: 0; 391 top: 0;
@@ -567,6 +589,11 @@ body { @@ -567,6 +589,11 @@ body {
567 .nav-addtabs { 589 .nav-addtabs {
568 display:none; 590 display:none;
569 } 591 }
  592 + .fixed-table-toolbar {
  593 + .columns-right.btn-group{
  594 + display:none;
  595 + }
  596 + }
570 } 597 }
571 /*平板样式*/ 598 /*平板样式*/
572 @media (max-width: @screen-tablet) { 599 @media (max-width: @screen-tablet) {