修复searchList使用二维数组数据源时排序丢失的BUG

修复后台插件管理登录状态失效的处理和判断
优化列表页通用搜索样式和排版调整
修复关联搜索使用find_in_set时的BUG
优化CRUD在生成中文数据时的编码问题
pull/765110/MERGE
Karson 2018-05-31 20:26:35 +08:00
parent de8ea27542
commit 045647c407
12 changed files with 245 additions and 206 deletions

View File

@ -1215,7 +1215,7 @@ EOD;
$v = "__('" . $v . "')"; $v = "__('" . $v . "')";
} }
unset($v); unset($v);
$searchList = json_encode($itemArr, JSON_FORCE_OBJECT); $searchList = json_encode($itemArr, JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE);
$searchList = str_replace(['":"', '"}', ')","'], ['":', '}', '),"'], $searchList); $searchList = str_replace(['":"', '"}', ')","'], ['":', '}', '),"'], $searchList);
if ($itemArr && !$extend) { if ($itemArr && !$extend) {
$html .= ", searchList: " . $searchList; $html .= ", searchList: " . $searchList;

View File

@ -21,13 +21,14 @@ return [
'Pay tips' => '扫码支付后如果仍然无法立即下载,请不要重复支付,请加<a href="https://jq.qq.com/?_wv=1027&k=487PNBb" target="_blank">QQ群636393962</a>向管理员反馈', 'Pay tips' => '扫码支付后如果仍然无法立即下载,请不要重复支付,请加<a href="https://jq.qq.com/?_wv=1027&k=487PNBb" target="_blank">QQ群636393962</a>向管理员反馈',
'Pay click tips' => '请点击这里在新窗口中进行支付!', 'Pay click tips' => '请点击这里在新窗口中进行支付!',
'Pay new window tips' => '请在新弹出的窗口中进行支付,支付完成后再重新点击安装按钮进行安装!', 'Pay new window tips' => '请在新弹出的窗口中进行支付,支付完成后再重新点击安装按钮进行安装!',
'Uninstall tips' => '确认卸载插件<p class="text-danger">卸载将会删除所有插件文件且不可找回!!! 插件如果有创建数据库表请手动删除!!!</p>如有重要数据请备份后再操作!', 'Uninstall tips' => '确认卸载[%s]<p class="text-danger">卸载将会删除所有插件文件且不可找回!!! 插件如果有创建数据库表请手动删除!!!</p>如有重要数据请备份后再操作!',
'Upgrade tips' => '确认升级插件<p class="text-danger">如果之前购买插件时未登录,此次升级可能出现购买后才可以下载的提示!!!<br>升级后可能出现部分冗余数据记录,请根据需要移除即可!!!</p>如有重要数据请备份后再操作!', 'Upgrade tips' => '确认升级[%s]<p class="text-danger">如果之前购买插件时未登录,此次升级可能出现购买后才可以下载的提示!!!<br>升级后可能出现部分冗余数据记录,请根据需要移除即可!!!</p>如有重要数据请备份后再操作!',
'Offline installed tips' => '插件安装成功!清除浏览器缓存和框架缓存后生效!', 'Offline installed tips' => '插件安装成功!清除浏览器缓存和框架缓存后生效!',
'Online installed tips' => '插件安装成功!清除浏览器缓存和框架缓存后生效!', 'Online installed tips' => '插件安装成功!清除浏览器缓存和框架缓存后生效!',
'Not login tips' => '你当前未登录FastAdmin登录后将同步已购买的记录下载时无需二次付费', 'Not login tips' => '你当前未登录FastAdmin登录后将同步已购买的记录下载时无需二次付费',
'Not installed tips' => '请安装后再访问插件前台页面!', 'Not installed tips' => '请安装后再访问插件前台页面!',
'Not enabled tips' => '插件已经禁用,请启用后再访问插件前台页面!', 'Not enabled tips' => '插件已经禁用,请启用后再访问插件前台页面!',
'New version tips' => '发现新版本:%s 点击查看更新日志',
'Please disable addon first' => '请先禁用插件再进行升级', 'Please disable addon first' => '请先禁用插件再进行升级',
'Login now' => '立即登录', 'Login now' => '立即登录',
'Continue install' => '不登录,继续安装', 'Continue install' => '不登录,继续安装',
@ -36,6 +37,8 @@ return [
'View addon screenshots' => '点击查看插件截图', 'View addon screenshots' => '点击查看插件截图',
'Click to toggle status' => '点击切换插件状态', 'Click to toggle status' => '点击切换插件状态',
'Click to contact developer' => '点击与插件开发者取得联系', 'Click to contact developer' => '点击与插件开发者取得联系',
'My addons' => '我购买的插件',
'My posts' => '我发布的插件',
'Index' => '前台', 'Index' => '前台',
'All' => '全部', 'All' => '全部',
'Uncategoried' => '未归类', 'Uncategoried' => '未归类',

View File

@ -53,6 +53,9 @@
position: absolute; position: absolute;
box-shadow: 0px 0px 2px #f11414; box-shadow: 0px 0px 2px #f11414;
} }
.form-userinfo .breadcrumb {
margin-bottom:10px;
}
</style> </style>
<div class="panel panel-default panel-intro"> <div class="panel panel-default panel-intro">
<div class="panel-heading"> <div class="panel-heading">
@ -158,17 +161,21 @@
<strong>{:__('Warning')}</strong><br/>{:__('Login tips')} <strong>{:__('Warning')}</strong><br/>{:__('Login tips')}
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputAccount" class="col-lg-3 control-label">{:__('Username')}</label> <div class="col-lg-12">
<div class="col-lg-9"> <div class="input-group">
<input type="text" class="form-control" id="inputAccount" value="" <span class="input-group-addon"><i class="fa fa-user"></i></span>
placeholder="{:__('Your username or email')}"> <input type="text" class="form-control" id="inputAccount" value=""
placeholder="{:__('Your username or email')}">
</div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputPassword" class="col-lg-3 control-label">{:__('Password')}</label> <div class="col-lg-12">
<div class="col-lg-9"> <div class="input-group">
<span class="input-group-addon"><i class="fa fa-lock"></i></span>
<input type="password" class="form-control" id="inputPassword" value="" <input type="password" class="form-control" id="inputPassword" value=""
placeholder="{:__('Your password')}"> placeholder="{:__('Your password')}">
</div>
</div> </div>
</div> </div>
</fieldset> </fieldset>
@ -177,13 +184,15 @@
</script> </script>
<script id="userinfotpl" type="text/html"> <script id="userinfotpl" type="text/html">
<div> <div>
<form class="form-horizontal"> <form class="form-horizontal form-userinfo">
<fieldset> <fieldset>
<div class="alert alert-dismissable alert-success"> <div class="alert alert-dismissable alert-success">
<button type="button" class="close" data-dismiss="alert">×</button> <button type="button" class="close" data-dismiss="alert">×</button>
<strong>{:__('Warning')}</strong><br/>{:__('Logined tips', '<%=username%>')} <strong>{:__('Warning')}</strong><br/>{:__('Logined tips', '<%=username%>')}
</div> </div>
</fieldset> </fieldset>
<div class="breadcrumb"><a href="https://www.fastadmin.net/user/myaddon.html" target="_blank"><i class="fa fa-money"></i> {:__('My addons')}</a></div>
<div class="breadcrumb"><a href="https://www.fastadmin.net/user/addon.html" target="_blank"><i class="fa fa-upload"></i> {:__('My posts')}</a></div>
</form> </form>
</div> </div>
</script> </script>
@ -273,15 +282,15 @@
</ul> </ul>
</span> </span>
<% }else{%> <% }else{%>
<a href="javascript:;" class="btn btn-xs btn-info btn-upgrade" data-version="<%=item.version%>"><i <a href="javascript:;" class="btn btn-xs btn-info btn-upgrade" title="{:__('Upgrade')}" data-version="<%=item.version%>"><i
class="fa fa-cloud"></i> {:__('Upgrade')}</a> class="fa fa-cloud"></i> {:__('Upgrade')}</a>
<% }%> <% }%>
<% }%> <% }%>
<% if(addon.config){ %> <% if(addon.config){ %>
<a href="javascript:;" class="btn btn-xs btn-primary btn-config"><i class="fa fa-pencil"></i> <a href="javascript:;" class="btn btn-xs btn-primary btn-config" title="{:__('Setting')}"><i class="fa fa-pencil"></i>
{:__('Setting')}</a> {:__('Setting')}</a>
<% } %> <% } %>
<a href="javascript:;" class="btn btn-xs btn-danger btn-uninstall"><i class="fa fa-times"></i> <a href="javascript:;" class="btn btn-xs btn-danger btn-uninstall" title="{:__('Uninstall')}"><i class="fa fa-times"></i>
{:__('Uninstall')}</a> {:__('Uninstall')}</a>
<% } %> <% } %>

View File

@ -39,6 +39,12 @@ class Backend extends Controller
*/ */
protected $auth = null; protected $auth = null;
/**
* 模型对象
* @var \think\Model
*/
protected $model = null;
/** /**
* 快速搜索时执行查找的字段 * 快速搜索时执行查找的字段
*/ */
@ -52,7 +58,7 @@ class Backend extends Controller
/** /**
* 是否开启数据限制 * 是否开启数据限制
* 支持auth/personal * 支持auth/personal
* 表示按权限判断/仅限个人 * 表示按权限判断/仅限个人
* 默认为禁用,若启用请务必保证表中存在admin_id字段 * 默认为禁用,若启用请务必保证表中存在admin_id字段
*/ */
protected $dataLimit = false; protected $dataLimit = false;
@ -116,22 +122,18 @@ class Backend extends Controller
// 设置当前请求的URI // 设置当前请求的URI
$this->auth->setRequestUri($path); $this->auth->setRequestUri($path);
// 检测是否需要验证登录 // 检测是否需要验证登录
if (!$this->auth->match($this->noNeedLogin)) if (!$this->auth->match($this->noNeedLogin)) {
{
//检测是否登录 //检测是否登录
if (!$this->auth->isLogin()) if (!$this->auth->isLogin()) {
{
Hook::listen('admin_nologin', $this); Hook::listen('admin_nologin', $this);
$url = Session::get('referer'); $url = Session::get('referer');
$url = $url ? $url : $this->request->url(); $url = $url ? $url : $this->request->url();
$this->error(__('Please login first'), url('index/login', ['url' => $url])); $this->error(__('Please login first'), url('index/login', ['url' => $url]));
} }
// 判断是否需要验证权限 // 判断是否需要验证权限
if (!$this->auth->match($this->noNeedRight)) if (!$this->auth->match($this->noNeedRight)) {
{
// 判断控制器和方法判断是否有对应权限 // 判断控制器和方法判断是否有对应权限
if (!$this->auth->check($path)) if (!$this->auth->check($path)) {
{
Hook::listen('admin_nopermission', $this); Hook::listen('admin_nopermission', $this);
$this->error(__('You have no permission'), ''); $this->error(__('You have no permission'), '');
} }
@ -139,15 +141,12 @@ class Backend extends Controller
} }
// 非选项卡时重定向 // 非选项卡时重定向
if (!$this->request->isPost() && !IS_AJAX && !IS_ADDTABS && !IS_DIALOG && input("ref") == 'addtabs') if (!$this->request->isPost() && !IS_AJAX && !IS_ADDTABS && !IS_DIALOG && input("ref") == 'addtabs') {
{ $url = preg_replace_callback("/([\?|&]+)ref=addtabs(&?)/i", function ($matches) {
$url = preg_replace_callback("/([\?|&]+)ref=addtabs(&?)/i", function($matches) {
return $matches[2] == '&' ? $matches[1] : ''; return $matches[2] == '&' ? $matches[1] : '';
}, $this->request->url()); }, $this->request->url());
if (Config::get('url_domain_deploy')) if (Config::get('url_domain_deploy')) {
{ if (stripos($url, $this->request->server('SCRIPT_NAME')) === 0) {
if (stripos($url, $this->request->server('SCRIPT_NAME')) === 0)
{
$url = substr($url, strlen($this->request->server('SCRIPT_NAME'))); $url = substr($url, strlen($this->request->server('SCRIPT_NAME')));
} }
$url = url($url, '', false); $url = url($url, '', false);
@ -162,8 +161,7 @@ class Backend extends Controller
$this->view->breadcrumb = $breadcrumb; $this->view->breadcrumb = $breadcrumb;
// 如果有使用模板布局 // 如果有使用模板布局
if ($this->layout) if ($this->layout) {
{
$this->view->engine->layout('layout/' . $this->layout); $this->view->engine->layout('layout/' . $this->layout);
} }
@ -220,7 +218,7 @@ class Backend extends Controller
/** /**
* 渲染配置信息 * 渲染配置信息
* @param mixed $name 键名或数组 * @param mixed $name 键名或数组
* @param mixed $value * @param mixed $value
*/ */
protected function assignconfig($name, $value = '') protected function assignconfig($name, $value = '')
{ {
@ -244,48 +242,46 @@ class Backend extends Controller
$order = $this->request->get("order", "DESC"); $order = $this->request->get("order", "DESC");
$offset = $this->request->get("offset", 0); $offset = $this->request->get("offset", 0);
$limit = $this->request->get("limit", 0); $limit = $this->request->get("limit", 0);
$filter = json_decode($filter, TRUE); $filter = (array)json_decode($filter, TRUE);
$op = json_decode($op, TRUE); $op = (array)json_decode($op, TRUE);
$filter = $filter ? $filter : []; $filter = $filter ? $filter : [];
$where = []; $where = [];
$tableName = ''; $tableName = '';
if ($relationSearch) if ($relationSearch) {
{ if (!empty($this->model)) {
if (!empty($this->model)) $name = \think\Loader::parseName(basename(str_replace('\\', '/', get_class($this->model))));
{ $tableName = $name . '.';
$tableName = $this->model->getQuery()->getTable() . ".";
} }
$sort = stripos($sort, ".") === false ? $tableName . $sort : $sort; $sortArr = explode(',', $sort);
foreach ($sortArr as $index => & $item) {
$item = stripos($item, ".") === false ? $tableName . trim($item) : $item;
}
unset($item);
$sort = implode(',', $sortArr);
} }
$adminIds = $this->getDataLimitAdminIds(); $adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) if (is_array($adminIds)) {
{
$where[] = [$tableName . $this->dataLimitField, 'in', $adminIds]; $where[] = [$tableName . $this->dataLimitField, 'in', $adminIds];
} }
if ($search) if ($search) {
{
$searcharr = is_array($searchfields) ? $searchfields : explode(',', $searchfields); $searcharr = is_array($searchfields) ? $searchfields : explode(',', $searchfields);
foreach ($searcharr as $k => &$v) foreach ($searcharr as $k => &$v) {
{
$v = stripos($v, ".") === false ? $tableName . $v : $v; $v = stripos($v, ".") === false ? $tableName . $v : $v;
} }
unset($v); unset($v);
$where[] = [implode("|", $searcharr), "LIKE", "%{$search}%"]; $where[] = [implode("|", $searcharr), "LIKE", "%{$search}%"];
} }
foreach ($filter as $k => $v) foreach ($filter as $k => $v) {
{
$sym = isset($op[$k]) ? $op[$k] : '='; $sym = isset($op[$k]) ? $op[$k] : '=';
if (stripos($k, ".") === false) if (stripos($k, ".") === false) {
{
$k = $tableName . $k; $k = $tableName . $k;
} }
$v = !is_array($v) ? trim($v) : $v; $v = !is_array($v) ? trim($v) : $v;
$sym = strtoupper(isset($op[$k]) ? $op[$k] : $sym); $sym = strtoupper(isset($op[$k]) ? $op[$k] : $sym);
switch ($sym) switch ($sym) {
{
case '=': case '=':
case '!=': case '!=':
$where[] = [$k, $sym, (string) $v]; $where[] = [$k, $sym, (string)$v];
break; break;
case 'LIKE': case 'LIKE':
case 'NOT LIKE': case 'NOT LIKE':
@ -300,8 +296,9 @@ class Backend extends Controller
$where[] = [$k, $sym, intval($v)]; $where[] = [$k, $sym, intval($v)];
break; break;
case 'FINDIN': case 'FINDIN':
case 'FINDINSET':
case 'FIND_IN_SET': case 'FIND_IN_SET':
$where[] = "FIND_IN_SET('{$v}', `{$k}`)"; $where[] = "FIND_IN_SET('{$v}', " . ($this->relationSearch ? $k : '`' . str_replace('.', '`.`', $k) . '`') . ")";
break; break;
case 'IN': case 'IN':
case 'IN(...)': case 'IN(...)':
@ -315,13 +312,10 @@ class Backend extends Controller
if (stripos($v, ',') === false || !array_filter($arr)) if (stripos($v, ',') === false || !array_filter($arr))
continue; continue;
//当出现一边为空时改变操作符 //当出现一边为空时改变操作符
if ($arr[0] === '') if ($arr[0] === '') {
{
$sym = $sym == 'BETWEEN' ? '<=' : '>'; $sym = $sym == 'BETWEEN' ? '<=' : '>';
$arr = $arr[1]; $arr = $arr[1];
} } else if ($arr[1] === '') {
else if ($arr[1] === '')
{
$sym = $sym == 'BETWEEN' ? '>=' : '<'; $sym = $sym == 'BETWEEN' ? '>=' : '<';
$arr = $arr[0]; $arr = $arr[0];
} }
@ -334,13 +328,10 @@ class Backend extends Controller
if (stripos($v, ',') === false || !array_filter($arr)) if (stripos($v, ',') === false || !array_filter($arr))
continue; continue;
//当出现一边为空时改变操作符 //当出现一边为空时改变操作符
if ($arr[0] === '') if ($arr[0] === '') {
{
$sym = $sym == 'RANGE' ? '<=' : '>'; $sym = $sym == 'RANGE' ? '<=' : '>';
$arr = $arr[1]; $arr = $arr[1];
} } else if ($arr[1] === '') {
else if ($arr[1] === '')
{
$sym = $sym == 'RANGE' ? '>=' : '<'; $sym = $sym == 'RANGE' ? '>=' : '<';
$arr = $arr[0]; $arr = $arr[0];
} }
@ -360,15 +351,11 @@ class Backend extends Controller
break; break;
} }
} }
$where = function($query) use ($where) { $where = function ($query) use ($where) {
foreach ($where as $k => $v) foreach ($where as $k => $v) {
{ if (is_array($v)) {
if (is_array($v))
{
call_user_func_array([$query, 'where'], $v); call_user_func_array([$query, 'where'], $v);
} } else {
else
{
$query->where($v); $query->where($v);
} }
} }
@ -383,17 +370,14 @@ class Backend extends Controller
*/ */
protected function getDataLimitAdminIds() protected function getDataLimitAdminIds()
{ {
if (!$this->dataLimit) if (!$this->dataLimit) {
{
return null; return null;
} }
if ($this->auth->isSuperAdmin()) if ($this->auth->isSuperAdmin()) {
{
return null; return null;
} }
$adminIds = []; $adminIds = [];
if (in_array($this->dataLimit, ['auth', 'personal'])) if (in_array($this->dataLimit, ['auth', 'personal'])) {
{
$adminIds = $this->dataLimit == 'auth' ? $this->auth->getChildrenAdminIds(true) : [$this->auth->id]; $adminIds = $this->dataLimit == 'auth' ? $this->auth->getChildrenAdminIds(true) : [$this->auth->id];
} }
return $adminIds; return $adminIds;
@ -401,10 +385,10 @@ class Backend extends Controller
/** /**
* Selectpage的实现方法 * Selectpage的实现方法
* *
* 当前方法只是一个比较通用的搜索匹配,请按需重载此方法来编写自己的搜索逻辑,$where按自己的需求写即可 * 当前方法只是一个比较通用的搜索匹配,请按需重载此方法来编写自己的搜索逻辑,$where按自己的需求写即可
* 这里示例了所有的参数,所以比较复杂,实现上自己实现只需简单的几行即可 * 这里示例了所有的参数,所以比较复杂,实现上自己实现只需简单的几行即可
* *
*/ */
protected function selectpage() protected function selectpage()
{ {
@ -412,7 +396,7 @@ class Backend extends Controller
$this->request->filter(['strip_tags', 'htmlspecialchars']); $this->request->filter(['strip_tags', 'htmlspecialchars']);
//搜索关键词,客户端输入以空格分开,这里接收为数组 //搜索关键词,客户端输入以空格分开,这里接收为数组
$word = (array) $this->request->request("q_word/a"); $word = (array)$this->request->request("q_word/a");
//当前页 //当前页
$page = $this->request->request("pageNumber"); $page = $this->request->request("pageNumber");
//分页大小 //分页大小
@ -420,7 +404,7 @@ class Backend extends Controller
//搜索条件 //搜索条件
$andor = $this->request->request("andOr"); $andor = $this->request->request("andOr");
//排序方式 //排序方式
$orderby = (array) $this->request->request("orderBy/a"); $orderby = (array)$this->request->request("orderBy/a");
//显示的字段 //显示的字段
$field = $this->request->request("showField"); $field = $this->request->request("showField");
//主键 //主键
@ -428,59 +412,48 @@ class Backend extends Controller
//主键值 //主键值
$primaryvalue = $this->request->request("keyValue"); $primaryvalue = $this->request->request("keyValue");
//搜索字段 //搜索字段
$searchfield = (array) $this->request->request("searchField/a"); $searchfield = (array)$this->request->request("searchField/a");
//自定义搜索条件 //自定义搜索条件
$custom = (array) $this->request->request("custom/a"); $custom = (array)$this->request->request("custom/a");
$order = []; $order = [];
foreach ($orderby as $k => $v) foreach ($orderby as $k => $v) {
{
$order[$v[0]] = $v[1]; $order[$v[0]] = $v[1];
} }
$field = $field ? $field : 'name'; $field = $field ? $field : 'name';
//如果有primaryvalue,说明当前是初始化传值 //如果有primaryvalue,说明当前是初始化传值
if ($primaryvalue !== null) if ($primaryvalue !== null) {
{
$where = [$primarykey => ['in', $primaryvalue]]; $where = [$primarykey => ['in', $primaryvalue]];
} } else {
else $where = function ($query) use ($word, $andor, $field, $searchfield, $custom) {
{ foreach ($word as $k => $v) {
$where = function($query) use($word, $andor, $field, $searchfield, $custom) { foreach ($searchfield as $m => $n) {
foreach ($word as $k => $v)
{
foreach ($searchfield as $m => $n)
{
$query->where($n, "like", "%{$v}%", $andor); $query->where($n, "like", "%{$v}%", $andor);
} }
} }
if ($custom && is_array($custom)) if ($custom && is_array($custom)) {
{ foreach ($custom as $k => $v) {
foreach ($custom as $k => $v)
{
$query->where($k, '=', $v); $query->where($k, '=', $v);
} }
} }
}; };
} }
$adminIds = $this->getDataLimitAdminIds(); $adminIds = $this->getDataLimitAdminIds();
if (is_array($adminIds)) if (is_array($adminIds)) {
{
$this->model->where($this->dataLimitField, 'in', $adminIds); $this->model->where($this->dataLimitField, 'in', $adminIds);
} }
$list = []; $list = [];
$total = $this->model->where($where)->count(); $total = $this->model->where($where)->count();
if ($total > 0) if ($total > 0) {
{ if (is_array($adminIds)) {
if (is_array($adminIds))
{
$this->model->where($this->dataLimitField, 'in', $adminIds); $this->model->where($this->dataLimitField, 'in', $adminIds);
} }
$list = $this->model->where($where) $list = $this->model->where($where)
->order($order) ->order($order)
->page($page, $pagesize) ->page($page, $pagesize)
->field("{$primarykey},{$field}") ->field("{$primarykey},{$field}")
->field("password,salt", true) ->field("password,salt", true)
->select(); ->select();
} }
//这里一定要返回有list这个字段,total是可选的,如果total<=list的数量,则会隐藏分页按钮 //这里一定要返回有list这个字段,total是可选的,如果total<=list的数量,则会隐藏分页按钮
return json(['list' => $list, 'total' => $total]); return json(['list' => $list, 'total' => $total]);

View File

@ -63,6 +63,17 @@ return [
'Content' => '内容', 'Content' => '内容',
'Status' => '状态', 'Status' => '状态',
'Operate' => '操作', 'Operate' => '操作',
'Apply' => '应用',
'Cancel' => '取消',
'Clear' => '清空',
'Custom Range' => '自定义',
'Today' => '今天',
'Yesterday' => '昨天',
'Last 7 days' => '最近7天',
'Last 30 days' => '最近30天',
'Last month' => '上月',
'This month' => '本月',
'Choose' => '选择',
'Append' => '追加', 'Append' => '追加',
'Memo' => '备注', 'Memo' => '备注',
'Parent' => '父级', 'Parent' => '父级',

View File

@ -649,6 +649,14 @@ form.form-horizontal .control-label {
.bootstrap-table .fa-toggle-on.fa-2x { .bootstrap-table .fa-toggle-on.fa-2x {
font-size: 1.86em; font-size: 1.86em;
} }
.bootstrap-table .form-commonsearch .form-group {
margin-left: 0;
margin-right: 0;
}
.bootstrap-table .form-commonsearch .form-group > .control-label {
padding-left: 0;
padding-right: 0;
}
.toolbar { .toolbar {
margin-top: 10px; margin-top: 10px;
margin-bottom: 10px; margin-bottom: 10px;

File diff suppressed because one or more lines are too long

View File

@ -173,11 +173,12 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
// 会员信息 // 会员信息
$(document).on("click", ".btn-userinfo", function () { $(document).on("click", ".btn-userinfo", function () {
var that = this;
var userinfo = Controller.api.userinfo.get(); var userinfo = Controller.api.userinfo.get();
if (!userinfo) { if (!userinfo) {
Layer.open({ Layer.open({
content: Template("logintpl", {}), content: Template("logintpl", {}),
area: ['400px', '330px'], area: ['430px', '350px'],
title: __('Login FastAdmin'), title: __('Login FastAdmin'),
resize: false, resize: false,
btn: [__('Login'), __('Register')], btn: [__('Login'), __('Register')],
@ -206,33 +207,43 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
} }
}); });
} else { } else {
var userinfo = Controller.api.userinfo.get(); Fast.api.ajax({
if (!userinfo) { url: Config.fastadmin.api_url + '/user/index',
Layer.alert(__('You\'re not login')); dataType: 'jsonp',
return false; data: {
} user_id: userinfo.id,
Layer.open({ token: userinfo.token,
content: Template("userinfotpl", userinfo),
area: ['400px', '330px'],
title: __('Userinfo'),
resize: false,
btn: [__('Logout'), __('Cancel')],
yes: function () {
Fast.api.ajax({
url: Config.fastadmin.api_url + '/user/logout',
dataType: 'jsonp',
data: {uid: userinfo.id, token: userinfo.token}
}, function (data, ret) {
Controller.api.userinfo.set(null);
Layer.closeAll();
Layer.alert(ret.msg);
}, function (data, ret) {
Controller.api.userinfo.set(null);
Layer.closeAll();
Layer.alert(ret.msg);
});
} }
}, function (data) {
Layer.open({
content: Template("userinfotpl", userinfo),
area: ['430px', '360px'],
title: __('Userinfo'),
resize: false,
btn: [__('Logout'), __('Cancel')],
yes: function () {
Fast.api.ajax({
url: Config.fastadmin.api_url + '/user/logout',
dataType: 'jsonp',
data: {uid: userinfo.id, token: userinfo.token}
}, function (data, ret) {
Controller.api.userinfo.set(null);
Layer.closeAll();
Layer.alert(ret.msg);
}, function (data, ret) {
Controller.api.userinfo.set(null);
Layer.closeAll();
Layer.alert(ret.msg);
});
}
});
return false;
}, function (data) {
Controller.api.userinfo.set(null);
$(that).trigger('click');
return false;
}); });
} }
}); });
@ -278,6 +289,12 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
} }
}); });
} else if (ret && ret.code === -2) { } else if (ret && ret.code === -2) {
//如果登录已经超时,重新提醒登录
if (uid && uid != ret.data.uid) {
Controller.api.userinfo.set(null);
$(".operate[data-name='" + name + "'] .btn-install").trigger("click");
return;
}
top.Fast.api.open(ret.data.payurl, __('Pay now'), { top.Fast.api.open(ret.data.payurl, __('Pay now'), {
area: ["650px", "700px"], area: ["650px", "700px"],
end: function () { end: function () {
@ -425,7 +442,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
Layer.alert(__('Please disable addon first'), {icon: 7}); Layer.alert(__('Please disable addon first'), {icon: 7});
return false; return false;
} }
Layer.confirm(__('Uninstall tips'), function () { Layer.confirm(__('Uninstall tips', Config['addons'][name].title), function () {
uninstall(name, false); uninstall(name, false);
}); });
}); });
@ -452,7 +469,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
} }
var version = $(this).data("version"); var version = $(this).data("version");
Layer.confirm(__('Upgrade tips'), function () { Layer.confirm(__('Upgrade tips', Config['addons'][name].title), function () {
upgrade(name, version); upgrade(name, version);
}); });
}); });
@ -510,7 +527,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
return value; return value;
}, },
version: function (value, row, index) { version: function (value, row, index) {
return row.addon && row.addon.version != row.version ? '<span class="releasetips" data-toggle="tooltip" title="' + __('New version') + ':' + row.version + '">' + row.addon.version + '<i></i></span>' : row.version; return row.addon && row.addon.version != row.version ? '<a href="' + row.url + '?version=' + row.version + '" target="_blank"><span class="releasetips text-primary" data-toggle="tooltip" title="' + __('New version tips', row.version) + '">' + row.addon.version + '<i></i></span></a>' : row.version;
}, },
home: function (value, row, index) { home: function (value, row, index) {
return row.addon ? '<a href="' + row.addon.url + '" data-toggle="tooltip" title="' + __('View addon index page') + '" target="_blank"><i class="fa fa-home text-primary"></i></a>' : '<a href="javascript:;"><i class="fa fa-home text-gray"></i></a>'; return row.addon ? '<a href="' + row.addon.url + '" data-toggle="tooltip" title="' + __('View addon index page') + '" target="_blank"><i class="fa fa-home text-primary"></i></a>' : '<a href="javascript:;"><i class="fa fa-home text-gray"></i></a>';

View File

@ -78,39 +78,27 @@
var style = typeof vObjCol.style === 'undefined' ? '' : sprintf('style="%s"', vObjCol.style); var style = typeof vObjCol.style === 'undefined' ? '' : sprintf('style="%s"', vObjCol.style);
extend = typeof vObjCol.data !== 'undefined' && extend == '' ? vObjCol.data : extend; extend = typeof vObjCol.data !== 'undefined' && extend == '' ? vObjCol.data : extend;
if (vObjCol.searchList) { if (vObjCol.searchList) {
if (typeof vObjCol.searchList === 'object' && typeof vObjCol.searchList.then === 'function') { if (typeof vObjCol.searchList === 'function') {
htmlForm.push(sprintf('<select class="%s" name="%s" %s %s>%s</select>', addClass, vObjCol.field, style, extend, sprintf('<option value="">%s</option>', that.options.formatCommonChoose())));
(function (vObjCol, that) {
$.when(vObjCol.searchList).done(function (ret) {
var isArray = false;
if (ret.data && ret.data.searchlist && $.isArray(ret.data.searchlist)) {
var resultlist = {};
$.each(ret.data.searchlist, function (key, value) {
resultlist[value.id] = value.name;
});
} else if (ret.constructor === Array || ret.constructor === Object) {
var resultlist = ret;
isArray = ret.constructor === Array ? true : isArray;
}
var optionList = [];
$.each(resultlist, function (key, value) {
var isSelect = (isArray ? value : key) == vObjCol.defaultValue ? 'selected' : '';
optionList.push(sprintf("<option value='" + (isArray ? value : key) + "' %s>" + value + "</option>", isSelect));
});
$("form.form-commonsearch select[name='" + vObjCol.field + "']", that.$container).append(optionList.join(''));
});
})(vObjCol, that);
} else if (typeof vObjCol.searchList == 'function') {
htmlForm.push(vObjCol.searchList.call(this, vObjCol)); htmlForm.push(vObjCol.searchList.call(this, vObjCol));
} else { } else {
var isArray = vObjCol.searchList.constructor === Array; var optionList = [sprintf('<option value="">%s</option>', that.options.formatCommonChoose())];
var searchList = []; if (typeof vObjCol.searchList === 'object' && typeof vObjCol.searchList.then === 'function') {
searchList.push(sprintf('<option value="">%s</option>', that.options.formatCommonChoose())); (function (vObjCol, that) {
$.each(vObjCol.searchList, function (key, value) { $.when(vObjCol.searchList).done(function (ret) {
var isSelect = (isArray ? value : key) == vObjCol.defaultValue ? 'selected' : ''; var searchList = [];
searchList.push(sprintf("<option value='" + (isArray ? value : key) + "' %s>" + value + "</option>", isSelect)); if (ret.data && ret.data.searchlist && $.isArray(ret.data.searchlist)) {
}); searchList = ret.data.searchlist;
htmlForm.push(sprintf('<select class="%s" name="%s" %s %s>%s</select>', addClass, vObjCol.field, style, extend, searchList.join(''))); } else if (ret.constructor === Array || ret.constructor === Object) {
searchList = ret;
}
var optionList = createOptionList(searchList, vObjCol, that);
$("form.form-commonsearch select[name='" + vObjCol.field + "']", that.$container).html(optionList.join(''));
});
})(vObjCol, that);
} else {
optionList = createOptionList(vObjCol.searchList, vObjCol, that);
}
htmlForm.push(sprintf('<select class="%s" name="%s" %s %s>%s</select>', addClass, vObjCol.field, style, extend, optionList.join('')));
} }
} else { } else {
var placeholder = typeof vObjCol.placeholder === 'undefined' ? vObjCol.title : vObjCol.placeholder; var placeholder = typeof vObjCol.placeholder === 'undefined' ? vObjCol.title : vObjCol.placeholder;
@ -153,6 +141,22 @@
return htmlBtn; return htmlBtn;
}; };
var createOptionList = function (searchList, vObjCol, that) {
var isArray = searchList.constructor === Array;
var optionList = [];
optionList.push(sprintf('<option value="">%s</option>', that.options.formatCommonChoose()));
$.each(searchList, function (key, value) {
if (value.constructor === Object) {
key = value.id;
value = value.name;
} else {
key = isArray ? value : key;
}
optionList.push(sprintf("<option value='" + key + "' %s>" + value + "</option>", key == vObjCol.defaultValue ? 'selected' : ''));
});
return optionList;
};
var isSearchAvailble = function (that) { var isSearchAvailble = function (that) {
//只支持服务端搜索 //只支持服务端搜索

View File

@ -8773,7 +8773,7 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
return false; return false;
} }
} }
var type = form.attr("method").toUpperCase(); var type = form.attr("method") ? form.attr("method").toUpperCase() : 'GET';
type = type && (type === 'GET' || type === 'POST') ? type : 'GET'; type = type && (type === 'GET' || type === 'POST') ? type : 'GET';
url = form.attr("action"); url = form.attr("action");
url = url ? url : location.href; url = url ? url : location.href;
@ -8944,39 +8944,27 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
var style = typeof vObjCol.style === 'undefined' ? '' : sprintf('style="%s"', vObjCol.style); var style = typeof vObjCol.style === 'undefined' ? '' : sprintf('style="%s"', vObjCol.style);
extend = typeof vObjCol.data !== 'undefined' && extend == '' ? vObjCol.data : extend; extend = typeof vObjCol.data !== 'undefined' && extend == '' ? vObjCol.data : extend;
if (vObjCol.searchList) { if (vObjCol.searchList) {
if (typeof vObjCol.searchList === 'object' && typeof vObjCol.searchList.then === 'function') { if (typeof vObjCol.searchList === 'function') {
htmlForm.push(sprintf('<select class="%s" name="%s" %s %s>%s</select>', addClass, vObjCol.field, style, extend, sprintf('<option value="">%s</option>', that.options.formatCommonChoose())));
(function (vObjCol, that) {
$.when(vObjCol.searchList).done(function (ret) {
var isArray = false;
if (ret.data && ret.data.searchlist && $.isArray(ret.data.searchlist)) {
var resultlist = {};
$.each(ret.data.searchlist, function (key, value) {
resultlist[value.id] = value.name;
});
} else if (ret.constructor === Array || ret.constructor === Object) {
var resultlist = ret;
isArray = ret.constructor === Array ? true : isArray;
}
var optionList = [];
$.each(resultlist, function (key, value) {
var isSelect = (isArray ? value : key) == vObjCol.defaultValue ? 'selected' : '';
optionList.push(sprintf("<option value='" + (isArray ? value : key) + "' %s>" + value + "</option>", isSelect));
});
$("form.form-commonsearch select[name='" + vObjCol.field + "']", that.$container).append(optionList.join(''));
});
})(vObjCol, that);
} else if (typeof vObjCol.searchList == 'function') {
htmlForm.push(vObjCol.searchList.call(this, vObjCol)); htmlForm.push(vObjCol.searchList.call(this, vObjCol));
} else { } else {
var isArray = vObjCol.searchList.constructor === Array; var optionList = [sprintf('<option value="">%s</option>', that.options.formatCommonChoose())];
var searchList = []; if (typeof vObjCol.searchList === 'object' && typeof vObjCol.searchList.then === 'function') {
searchList.push(sprintf('<option value="">%s</option>', that.options.formatCommonChoose())); (function (vObjCol, that) {
$.each(vObjCol.searchList, function (key, value) { $.when(vObjCol.searchList).done(function (ret) {
var isSelect = (isArray ? value : key) == vObjCol.defaultValue ? 'selected' : ''; var searchList = [];
searchList.push(sprintf("<option value='" + (isArray ? value : key) + "' %s>" + value + "</option>", isSelect)); if (ret.data && ret.data.searchlist && $.isArray(ret.data.searchlist)) {
}); searchList = ret.data.searchlist;
htmlForm.push(sprintf('<select class="%s" name="%s" %s %s>%s</select>', addClass, vObjCol.field, style, extend, searchList.join(''))); } else if (ret.constructor === Array || ret.constructor === Object) {
searchList = ret;
}
var optionList = createOptionList(searchList, vObjCol, that);
$("form.form-commonsearch select[name='" + vObjCol.field + "']", that.$container).html(optionList.join(''));
});
})(vObjCol, that);
} else {
optionList = createOptionList(vObjCol.searchList, vObjCol, that);
}
htmlForm.push(sprintf('<select class="%s" name="%s" %s %s>%s</select>', addClass, vObjCol.field, style, extend, optionList.join('')));
} }
} else { } else {
var placeholder = typeof vObjCol.placeholder === 'undefined' ? vObjCol.title : vObjCol.placeholder; var placeholder = typeof vObjCol.placeholder === 'undefined' ? vObjCol.title : vObjCol.placeholder;
@ -9019,6 +9007,22 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
return htmlBtn; return htmlBtn;
}; };
var createOptionList = function (searchList, vObjCol, that) {
var isArray = searchList.constructor === Array;
var optionList = [];
optionList.push(sprintf('<option value="">%s</option>', that.options.formatCommonChoose()));
$.each(searchList, function (key, value) {
if (value.constructor === Object) {
key = value.id;
value = value.name;
} else {
key = isArray ? value : key;
}
optionList.push(sprintf("<option value='" + key + "' %s>" + value + "</option>", key == vObjCol.defaultValue ? 'selected' : ''));
});
return optionList;
};
var isSearchAvailble = function (that) { var isSearchAvailble = function (that) {
//只支持服务端搜索 //只支持服务端搜索

View File

@ -357,7 +357,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
return false; return false;
} }
} }
var type = form.attr("method").toUpperCase(); var type = form.attr("method") ? form.attr("method").toUpperCase() : 'GET';
type = type && (type === 'GET' || type === 'POST') ? type : 'GET'; type = type && (type === 'GET' || type === 'POST') ? type : 'GET';
url = form.attr("action"); url = form.attr("action");
url = url ? url : location.href; url = url ? url : location.href;

View File

@ -730,8 +730,18 @@ form.form-horizontal .control-label {
.bootstrap-table .fixed-table-toolbar .dropdown-menu { .bootstrap-table .fixed-table-toolbar .dropdown-menu {
overflow: auto; overflow: auto;
} }
.bootstrap-table .fa-toggle-on.fa-2x { .bootstrap-table .fa-toggle-on.fa-2x {
font-size:1.86em; font-size: 1.86em;
}
.bootstrap-table .form-commonsearch .form-group {
margin-left: 0;
margin-right: 0;
> .control-label {
padding-left:0;
padding-right:0;
}
} }
.toolbar { .toolbar {