新增附件记录上传会员和上传管理员ID

新增后台管理员admin_login_after和admin_logout_after的行为
新增tooltip和popover
优化和改版插件管理功能
优化多个Layer弹窗的切换体验
优化弹窗高度大于视察高度的操作体验
优化系统配置中发送测试邮件的逻辑
修复生成关联模型时未判断selectpage的BUG
修复表单前置返回失败未释放锁定的BUG
修复API文档生成时采用了GET方法的BUG
pull/59/head v1.0.0.20180506_beta
Karson 2018-05-06 02:05:27 +08:00
parent 924e52b5e5
commit e57171dea9
56 changed files with 901 additions and 814 deletions

View File

@ -33,6 +33,9 @@ class Addon extends Command
{ {
$name = $input->getOption('name') ?: ''; $name = $input->getOption('name') ?: '';
$action = $input->getOption('action') ?: ''; $action = $input->getOption('action') ?: '';
if(stripos($name, 'addons/')!==false){
$name = explode('/', $name)[1];
}
//强制覆盖 //强制覆盖
$force = $input->getOption('force'); $force = $input->getOption('force');
//版本 //版本
@ -65,8 +68,8 @@ class Addon extends Command
if (is_dir($addonDir)) { if (is_dir($addonDir)) {
rmdirs($addonDir); rmdirs($addonDir);
} }
mkdir($addonDir); mkdir($addonDir, 0755, true);
mkdir($addonDir . DS . 'controller'); mkdir($addonDir . DS . 'controller', 0755, true);
$menuList = \app\common\library\Menu::export($name); $menuList = \app\common\library\Menu::export($name);
$createMenu = $this->getCreateMenu($menuList); $createMenu = $this->getCreateMenu($menuList);
$prefix = Config::get('database.prefix'); $prefix = Config::get('database.prefix');

View File

@ -437,8 +437,8 @@
$.ajax({ $.ajax({
url: $('#apiUrl').val() + url, url: $('#apiUrl').val() + url,
data: $(form).attr('method') == 'get' ? $(form).serialize() : formData, data: $(form).prop('method').toLowerCase() == 'get' ? $(form).serialize() : formData,
type: $(form).attr('method') + '', type: $(form).prop('method') + '',
dataType: 'json', dataType: 'json',
contentType: false, contentType: false,
processData: false, processData: false,

View File

@ -1137,7 +1137,7 @@ EOD;
$langField = mb_ucfirst($field); $langField = mb_ucfirst($field);
return <<<EOD return <<<EOD
<div class="form-group"> <div class="form-group">
<label for="c-{$field}" class="control-label col-xs-12 col-sm-2">{:__('{$langField}')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('{$langField}')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{$content} {$content}
</div> </div>
@ -1149,7 +1149,7 @@ EOD;
* 获取图片模板数据 * 获取图片模板数据
* @param string $field * @param string $field
* @param string $content * @param string $content
* @return array * @return string
*/ */
protected function getImageUpload($field, $content) protected function getImageUpload($field, $content)
{ {

View File

@ -14,6 +14,7 @@ class {%controllerName%} extends Backend
/** /**
* {%modelName%}模型对象 * {%modelName%}模型对象
* @var \{%modelNamespace%}\{%modelName%}
*/ */
protected $model = null; protected $model = null;

View File

@ -10,6 +10,11 @@
$this->request->filter(['strip_tags']); $this->request->filter(['strip_tags']);
if ($this->request->isAjax()) if ($this->request->isAjax())
{ {
//如果发送的来源是Selectpage则转发到Selectpage
if ($this->request->request('keyField'))
{
return $this->selectpage();
}
list($where, $sort, $order, $offset, $limit) = $this->buildparams(); list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model $total = $this->model
{%relationWithList%} {%relationWithList%}

View File

@ -50,7 +50,7 @@ CREATE TABLE `fa_admin_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`admin_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '管理员ID', `admin_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '管理员ID',
`username` varchar(30) NOT NULL DEFAULT '' COMMENT '管理员名字', `username` varchar(30) NOT NULL DEFAULT '' COMMENT '管理员名字',
`url` varchar(255) NOT NULL DEFAULT '' COMMENT '操作页面', `url` varchar(1500) NOT NULL DEFAULT '' COMMENT '操作页面',
`title` varchar(100) NOT NULL DEFAULT '' COMMENT '日志标题', `title` varchar(100) NOT NULL DEFAULT '' COMMENT '日志标题',
`content` text NOT NULL COMMENT '内容', `content` text NOT NULL COMMENT '内容',
`ip` varchar(50) NOT NULL DEFAULT '' COMMENT 'IP', `ip` varchar(50) NOT NULL DEFAULT '' COMMENT 'IP',
@ -66,6 +66,8 @@ CREATE TABLE `fa_admin_log` (
DROP TABLE IF EXISTS `fa_attachment`; DROP TABLE IF EXISTS `fa_attachment`;
CREATE TABLE `fa_attachment` ( CREATE TABLE `fa_attachment` (
`id` int(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `id` int(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`admin_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '管理员ID',
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
`url` varchar(255) NOT NULL DEFAULT '' COMMENT '物理路径', `url` varchar(255) NOT NULL DEFAULT '' COMMENT '物理路径',
`imagewidth` varchar(30) NOT NULL DEFAULT '' COMMENT '宽度', `imagewidth` varchar(30) NOT NULL DEFAULT '' COMMENT '宽度',
`imageheight` varchar(30) NOT NULL DEFAULT '' COMMENT '高度', `imageheight` varchar(30) NOT NULL DEFAULT '' COMMENT '高度',
@ -77,7 +79,7 @@ CREATE TABLE `fa_attachment` (
`createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建日期', `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建日期',
`updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间', `updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
`uploadtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '上传时间', `uploadtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '上传时间',
`storage` enum('local','upyun','qiniu') NOT NULL DEFAULT 'local' COMMENT '存储位置', `storage` varchar(100) NOT NULL DEFAULT 'local' COMMENT '存储位置',
`sha1` varchar(40) NOT NULL DEFAULT '' COMMENT '文件 sha1编码', `sha1` varchar(40) NOT NULL DEFAULT '' COMMENT '文件 sha1编码',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='附件表'; ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='附件表';
@ -86,7 +88,7 @@ CREATE TABLE `fa_attachment` (
-- Records of fa_attachment -- Records of fa_attachment
-- ---------------------------- -- ----------------------------
BEGIN; BEGIN;
INSERT INTO `fa_attachment` VALUES (1, '/assets/img/qrcode.png', '150', '150', 'png', 0, 21859, 'image/png', '', 1499681848, 1499681848, 1499681848, 'local', '17163603d0263e4838b9387ff2cd4877e8b018f6'); INSERT INTO `fa_attachment` VALUES (1, 1, 0, '/assets/img/qrcode.png', '150', '150', 'png', 0, 21859, 'image/png', '', 1499681848, 1499681848, 1499681848, 'local', '17163603d0263e4838b9387ff2cd4877e8b018f6');
COMMIT; COMMIT;
-- ---------------------------- -- ----------------------------
@ -344,7 +346,7 @@ DROP TABLE IF EXISTS `fa_ems`;
CREATE TABLE `fa_ems` ( CREATE TABLE `fa_ems` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID', `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
`event` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '事件', `event` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '事件',
`email` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '邮箱', `email` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '邮箱',
`code` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '验证码', `code` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '验证码',
`times` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '验证次数', `times` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '验证次数',
`ip` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'IP', `ip` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'IP',

View File

@ -76,7 +76,7 @@ class Addon extends Backend
Service::refresh(); Service::refresh();
$this->success(); $this->success();
} catch (Exception $e) { } catch (Exception $e) {
$this->error($e->getMessage()); $this->error(__($e->getMessage()));
} }
} }
$this->error(__('Parameter %s can not be empty', '')); $this->error(__('Parameter %s can not be empty', ''));
@ -112,9 +112,9 @@ class Addon extends Backend
$info['state'] = 1; $info['state'] = 1;
$this->success(__('Install successful'), null, ['addon' => $info]); $this->success(__('Install successful'), null, ['addon' => $info]);
} catch (AddonException $e) { } catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), $e->getMessage()); $this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) { } catch (Exception $e) {
$this->error($e->getMessage(), $e->getCode()); $this->error(__($e->getMessage()), $e->getCode());
} }
} }
@ -132,9 +132,9 @@ class Addon extends Backend
Service::uninstall($name, $force); Service::uninstall($name, $force);
$this->success(__('Uninstall successful')); $this->success(__('Uninstall successful'));
} catch (AddonException $e) { } catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), $e->getMessage()); $this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) { } catch (Exception $e) {
$this->error($e->getMessage()); $this->error(__($e->getMessage()));
} }
} }
@ -156,9 +156,9 @@ class Addon extends Backend
Cache::rm('__menu__'); Cache::rm('__menu__');
$this->success(__('Operate successful')); $this->success(__('Operate successful'));
} catch (AddonException $e) { } catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), $e->getMessage()); $this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) { } catch (Exception $e) {
$this->error($e->getMessage()); $this->error(__($e->getMessage()));
} }
} }
@ -222,16 +222,16 @@ class Addon extends Backend
$this->success(__('Offline installed tips'), null, ['addon' => $info]); $this->success(__('Offline installed tips'), null, ['addon' => $info]);
} catch (Exception $e) { } catch (Exception $e) {
@rmdirs($newAddonDir); @rmdirs($newAddonDir);
throw new Exception($e->getMessage()); throw new Exception(__($e->getMessage()));
} }
} catch (Exception $e) { } catch (Exception $e) {
@unlink($tmpFile); @unlink($tmpFile);
@rmdirs($tmpAddonDir); @rmdirs($tmpAddonDir);
$this->error($e->getMessage()); $this->error(__($e->getMessage()));
} }
} else { } else {
// 上传失败获取错误信息 // 上传失败获取错误信息
$this->error($file->getError()); $this->error(__($file->getError()));
} }
} }
@ -260,9 +260,9 @@ class Addon extends Backend
Cache::rm('__menu__'); Cache::rm('__menu__');
$this->success(__('Operate successful')); $this->success(__('Operate successful'));
} catch (AddonException $e) { } catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), $e->getMessage()); $this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) { } catch (Exception $e) {
$this->error($e->getMessage()); $this->error(__($e->getMessage()));
} }
} }
@ -297,7 +297,7 @@ class Addon extends Backend
continue; continue;
if (isset($onlineaddons[$v['name']])) { if (isset($onlineaddons[$v['name']])) {
$v = array_merge($onlineaddons[$v['name']], $v); $v = array_merge($v, $onlineaddons[$v['name']]);
} else { } else {
$v['category_id'] = 0; $v['category_id'] = 0;
$v['flag'] = ''; $v['flag'] = '';
@ -306,6 +306,8 @@ class Addon extends Backend
$v['donateimage'] = ''; $v['donateimage'] = '';
$v['demourl'] = ''; $v['demourl'] = '';
$v['price'] = '0.00'; $v['price'] = '0.00';
$v['screenshots'] = [];
$v['releaselist'] = [];
} }
$v['url'] = addon_url($v['name']); $v['url'] = addon_url($v['name']);
$v['createtime'] = filemtime(ADDON_PATH . $v['name']); $v['createtime'] = filemtime(ADDON_PATH . $v['name']);

View File

@ -106,6 +106,8 @@ class Ajax extends Backend
$imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight; $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
} }
$params = array( $params = array(
'admin_id' => (int)$this->auth->id,
'user_id' => 0,
'filesize' => $fileInfo['size'], 'filesize' => $fileInfo['size'],
'imagewidth' => $imagewidth, 'imagewidth' => $imagewidth,
'imageheight' => $imageheight, 'imageheight' => $imageheight,

View File

@ -90,6 +90,7 @@ class Index extends Backend
$result = $this->auth->login($username, $password, $keeplogin ? 86400 : 0); $result = $this->auth->login($username, $password, $keeplogin ? 86400 : 0);
if ($result === true) if ($result === true)
{ {
Hook::listen("admin_login_after", $this->request);
$this->success(__('Login successful'), $url, ['url' => $url, 'id' => $this->auth->id, 'username' => $username, 'avatar' => $this->auth->avatar]); $this->success(__('Login successful'), $url, ['url' => $url, 'id' => $this->auth->id, 'username' => $username, 'avatar' => $this->auth->avatar]);
} }
else else
@ -109,7 +110,7 @@ class Index extends Backend
$background = stripos($background, 'http')===0 ? $background : config('site.cdnurl') . $background; $background = stripos($background, 'http')===0 ? $background : config('site.cdnurl') . $background;
$this->view->assign('background', $background); $this->view->assign('background', $background);
$this->view->assign('title', __('Login')); $this->view->assign('title', __('Login'));
Hook::listen("login_init", $this->request); Hook::listen("admin_login_init", $this->request);
return $this->view->fetch(); return $this->view->fetch();
} }
@ -119,6 +120,7 @@ class Index extends Backend
public function logout() public function logout()
{ {
$this->auth->logout(); $this->auth->logout();
Hook::listen("admin_logout_after", $this->request);
$this->success(__('Logout successful'), 'index/login'); $this->success(__('Logout successful'), 'index/login');
} }

View File

@ -10,7 +10,7 @@ use think\Exception;
/** /**
* 系统配置 * 系统配置
* *
* @icon fa fa-circle-o * @icon fa fa-cogs
* @remark 可以在此增改系统的变量和分组,也可以自定义分组和变量,如果需要删除请从数据库中删除 * @remark 可以在此增改系统的变量和分组,也可以自定义分组和变量,如果需要删除请从数据库中删除
*/ */
class Config extends Backend class Config extends Backend
@ -32,31 +32,26 @@ class Config extends Backend
{ {
$siteList = []; $siteList = [];
$groupList = ConfigModel::getGroupList(); $groupList = ConfigModel::getGroupList();
foreach ($groupList as $k => $v) foreach ($groupList as $k => $v) {
{
$siteList[$k]['name'] = $k; $siteList[$k]['name'] = $k;
$siteList[$k]['title'] = $v; $siteList[$k]['title'] = $v;
$siteList[$k]['list'] = []; $siteList[$k]['list'] = [];
} }
foreach ($this->model->all() as $k => $v) foreach ($this->model->all() as $k => $v) {
{ if (!isset($siteList[$v['group']])) {
if (!isset($siteList[$v['group']]))
{
continue; continue;
} }
$value = $v->toArray(); $value = $v->toArray();
$value['title'] = __($value['title']); $value['title'] = __($value['title']);
if (in_array($value['type'], ['select', 'selects', 'checkbox', 'radio'])) if (in_array($value['type'], ['select', 'selects', 'checkbox', 'radio'])) {
{
$value['value'] = explode(',', $value['value']); $value['value'] = explode(',', $value['value']);
} }
$value['content'] = json_decode($value['content'], TRUE); $value['content'] = json_decode($value['content'], TRUE);
$siteList[$v['group']]['list'][] = $value; $siteList[$v['group']]['list'][] = $value;
} }
$index = 0; $index = 0;
foreach ($siteList as $k => &$v) foreach ($siteList as $k => &$v) {
{
$v['active'] = !$index ? true : false; $v['active'] = !$index ? true : false;
$index++; $index++;
} }
@ -71,45 +66,30 @@ class Config extends Backend
*/ */
public function add() public function add()
{ {
if ($this->request->isPost()) if ($this->request->isPost()) {
{
$params = $this->request->post("row/a"); $params = $this->request->post("row/a");
if ($params) if ($params) {
{ foreach ($params as $k => &$v) {
foreach ($params as $k => &$v)
{
$v = is_array($v) ? implode(',', $v) : $v; $v = is_array($v) ? implode(',', $v) : $v;
} }
try try {
{ if (in_array($params['type'], ['select', 'selects', 'checkbox', 'radio', 'array'])) {
if (in_array($params['type'], ['select', 'selects', 'checkbox', 'radio', 'array']))
{
$params['content'] = json_encode(ConfigModel::decode($params['content']), JSON_UNESCAPED_UNICODE); $params['content'] = json_encode(ConfigModel::decode($params['content']), JSON_UNESCAPED_UNICODE);
} } else {
else
{
$params['content'] = ''; $params['content'] = '';
} }
$result = $this->model->create($params); $result = $this->model->create($params);
if ($result !== false) if ($result !== false) {
{ try {
try
{
$this->refreshFile(); $this->refreshFile();
$this->success(); $this->success();
} } catch (Exception $e) {
catch (Exception $e)
{
$this->error($e->getMessage()); $this->error($e->getMessage());
} }
} } else {
else
{
$this->error($this->model->getError()); $this->error($this->model->getError());
} }
} } catch (Exception $e) {
catch (Exception $e)
{
$this->error($e->getMessage()); $this->error($e->getMessage());
} }
} }
@ -124,23 +104,16 @@ class Config extends Backend
*/ */
public function edit($ids = NULL) public function edit($ids = NULL)
{ {
if ($this->request->isPost()) if ($this->request->isPost()) {
{
$row = $this->request->post("row/a"); $row = $this->request->post("row/a");
if ($row) if ($row) {
{
$configList = []; $configList = [];
foreach ($this->model->all() as $v) foreach ($this->model->all() as $v) {
{ if (isset($row[$v['name']])) {
if (isset($row[$v['name']]))
{
$value = $row[$v['name']]; $value = $row[$v['name']];
if (is_array($value) && isset($value['field'])) if (is_array($value) && isset($value['field'])) {
{
$value = json_encode(ConfigModel::getArrayData($value), JSON_UNESCAPED_UNICODE); $value = json_encode(ConfigModel::getArrayData($value), JSON_UNESCAPED_UNICODE);
} } else {
else
{
$value = is_array($value) ? implode(',', $value) : $value; $value = is_array($value) ? implode(',', $value) : $value;
} }
$v['value'] = $value; $v['value'] = $value;
@ -148,13 +121,10 @@ class Config extends Backend
} }
} }
$this->model->allowField(true)->saveAll($configList); $this->model->allowField(true)->saveAll($configList);
try try {
{
$this->refreshFile(); $this->refreshFile();
$this->success(); $this->success();
} } catch (Exception $e) {
catch (Exception $e)
{
$this->error($e->getMessage()); $this->error($e->getMessage());
} }
} }
@ -162,20 +132,20 @@ class Config extends Backend
} }
} }
/**
* 刷新配置文件
*/
protected function refreshFile() protected function refreshFile()
{ {
$config = []; $config = [];
foreach ($this->model->all() as $k => $v) foreach ($this->model->all() as $k => $v) {
{
$value = $v->toArray(); $value = $v->toArray();
if (in_array($value['type'], ['selects', 'checkbox', 'images', 'files'])) if (in_array($value['type'], ['selects', 'checkbox', 'images', 'files'])) {
{
$value['value'] = explode(',', $value['value']); $value['value'] = explode(',', $value['value']);
} }
if ($value['type'] == 'array') if ($value['type'] == 'array') {
{ $value['value'] = (array)json_decode($value['value'], TRUE);
$value['value'] = (array) json_decode($value['value'], TRUE);
} }
$config[$value['name']] = $value['value']; $config[$value['name']] = $value['value'];
} }
@ -183,26 +153,21 @@ class Config extends Backend
} }
/** /**
* 检测配置项是否存在
* @internal * @internal
*/ */
public function check() public function check()
{ {
$params = $this->request->post("row/a"); $params = $this->request->post("row/a");
if ($params) if ($params) {
{
$config = $this->model->get($params); $config = $this->model->get($params);
if (!$config) if (!$config) {
{
return $this->success(); return $this->success();
} } else {
else
{
return $this->error(__('Name already exist')); return $this->error(__('Name already exist'));
} }
} } else {
else
{
return $this->error(__('Invalid parameters')); return $this->error(__('Invalid parameters'));
} }
} }
@ -213,19 +178,18 @@ class Config extends Backend
*/ */
public function emailtest() public function emailtest()
{ {
$row = $this->request->post('row/a');
\think\Config::set('site', array_merge(\think\Config::get('site'), $row));
$receiver = $this->request->request("receiver"); $receiver = $this->request->request("receiver");
$email = new Email; $email = new Email;
$result = $email $result = $email
->to($receiver) ->to($receiver)
->subject(__("This is a test mail")) ->subject(__("This is a test mail"))
->message('<div style="min-height:550px; padding: 100px 55px 200px;">' . __('This is a test mail content') . '</div>') ->message('<div style="min-height:550px; padding: 100px 55px 200px;">' . __('This is a test mail content') . '</div>')
->send(); ->send();
if ($result) if ($result) {
{
$this->success(); $this->success();
} } else {
else
{
$this->error($email->getError()); $this->error($email->getError());
} }
} }

View File

@ -53,8 +53,7 @@ class User extends Backend
->select(); ->select();
foreach ($list as $k => $v) foreach ($list as $k => $v)
{ {
$v->password = ''; $v->hidden(['password', 'salt']);
$v->salt = '';
} }
$result = array("total" => $total, "rows" => $list); $result = array("total" => $total, "rows" => $list);

View File

@ -34,7 +34,6 @@ return [
'Cancel' => '取消', 'Cancel' => '取消',
'Clear' => '清空', 'Clear' => '清空',
'Custom Range' => '自定义', 'Custom Range' => '自定义',
'Cancel' => '取消',
'Today' => '今天', 'Today' => '今天',
'Yesterday' => '昨天', 'Yesterday' => '昨天',
'Last 7 days' => '最近7天', 'Last 7 days' => '最近7天',
@ -78,13 +77,9 @@ return [
'Line' => '行号', 'Line' => '行号',
'File' => '文件', 'File' => '文件',
'Menu' => '菜单', 'Menu' => '菜单',
'Name' => '名称',
'Weigh' => '权重',
'Type' => '类型', 'Type' => '类型',
'Title' => '标题', 'Title' => '标题',
'Content' => '内容', 'Content' => '内容',
'Status' => '状态',
'Operate' => '操作',
'Append' => '追加', 'Append' => '追加',
'Select' => '选择', 'Select' => '选择',
'Memo' => '备注', 'Memo' => '备注',
@ -115,6 +110,7 @@ return [
//提示 //提示
'Go back' => '返回首页', 'Go back' => '返回首页',
'Jump now' => '立即跳转', 'Jump now' => '立即跳转',
'Click to search %s' => '点击搜索 %s',
'Operation completed' => '操作成功!', 'Operation completed' => '操作成功!',
'Operation failed' => '操作失败!', 'Operation failed' => '操作失败!',
'Unknown data format' => '未知的数据格式!', 'Unknown data format' => '未知的数据格式!',
@ -147,7 +143,7 @@ return [
'Admin' => '管理员管理', 'Admin' => '管理员管理',
'Admin log' => '管理员日志', 'Admin log' => '管理员日志',
'Group' => '角色组', 'Group' => '角色组',
'Rule' => '规则管理', 'Rule' => '菜单规则',
'User' => '会员管理', 'User' => '会员管理',
'User group' => '会员分组', 'User group' => '会员分组',
'User rule' => '会员规则', 'User rule' => '会员规则',

View File

@ -2,13 +2,14 @@
return [ return [
'Id' => 'ID', 'Id' => 'ID',
'Title' => '标题', 'Title' => '插件名称',
'Value' => '配置值', 'Value' => '配置值',
'Array key' => '键', 'Array key' => '键',
'Array value' => '值', 'Array value' => '值',
'File' => '文件', 'File' => '文件',
'Donate' => '打赏作者', 'Donate' => '打赏作者',
'Warmtips' => '温馨提示', 'Warmtips' => '温馨提示',
'Pay now' => '立即支付',
'Offline install' => '离线安装', 'Offline install' => '离线安装',
'Refresh addon cache' => '刷新插件缓存', 'Refresh addon cache' => '刷新插件缓存',
'Userinfo' => '会员信息', 'Userinfo' => '会员信息',
@ -17,38 +18,47 @@ return [
'Conflict tips' => '此插件中发现和现有系统中部分文件发现冲突!以下文件将会被影响,请备份好相关文件后再继续操作', 'Conflict tips' => '此插件中发现和现有系统中部分文件发现冲突!以下文件将会被影响,请备份好相关文件后再继续操作',
'Login tips' => '此处登录账号为<a href="https://www.fastadmin.net" target="_blank">FastAdmin官网账号</a>', 'Login tips' => '此处登录账号为<a href="https://www.fastadmin.net" target="_blank">FastAdmin官网账号</a>',
'Logined tips' => '你好!%s<br />当前你已经登录,将同步保存你的购买记录', 'Logined tips' => '你好!%s<br />当前你已经登录,将同步保存你的购买记录',
'Pay tips' => '支付完成后请稍等1~5分钟后再尝试安装请不要重复支付如果仍然无法安装,请加<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' => '确认卸载插件?<p class="text-danger">卸载将会删除所有插件文件且不可找回!!! 插件如果有创建数据库表请手动删除!!!</p>如有重要数据请备份后再操作!',
'Upgrade tips' => '确认升级插件?<p class="text-danger">如果之前购买插件时未登录,此次升级可能出现购买后才可以下载的提示!!!<br>升级后可能出现部分冗余数据记录,请根据需要移除即可!!!</p>如有重要数据请备份后再操作!', 'Upgrade tips' => '确认升级插件?<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' => '插件已经禁用,请启用后再访问插件前台页面!',
'Please disable addon first' => '请先禁用插件再进行升级', 'Please disable addon first' => '请先禁用插件再进行升级',
'Login now' => '立即登录', 'Login now' => '立即登录',
'Continue install' => '不登录,继续安装', 'Continue install' => '不登录,继续安装',
'View addon home page' => '查看插件介绍和帮助',
'View addon index page' => '查看插件前台首页',
'View addon screenshots' => '点击查看插件截图',
'Click to toggle status' => '点击切换插件状态',
'Click to contact developer' => '点击与插件开发者取得联系',
'Index' => '前台',
'All' => '全部', 'All' => '全部',
'Uncategoried' => '未归类', 'Uncategoried' => '未归类',
'Recommend' => '推荐', 'Recommend' => '推荐',
'Hot' => '热门', 'Hot' => '热门',
'New' => '新', 'New' => '新',
'Paying' => '付费',
'Free' => '免费', 'Free' => '免费',
'Sale' => '折扣', 'Sale' => '折扣',
'No image' => '暂无缩略图', 'No image' => '暂无缩略图',
'Price' => '价格', 'Price' => '价格',
'Downloads' => '下载',
'Author' => '作者', 'Author' => '作者',
'Identify' => '标识', 'Identify' => '标识',
'Homepage' => '主页', 'Homepage' => '主页',
'Intro' => '介绍', 'Intro' => '介绍',
'Version' => '版本', 'Version' => '版本',
'New version' => '新版本',
'Createtime' => '添加时间', 'Createtime' => '添加时间',
'Releasetime' => '更新时间', 'Releasetime' => '更新时间',
'Detail' => '插件详情', 'Detail' => '插件详情',
'Document' => '文档', 'Document' => '文档',
'Demo' => '在线演示', 'Demo' => '演示',
'Feedback' => '反馈BUG', 'Feedback' => '反馈BUG',
'Install' => '安装', 'Install' => '安装',
'Uninstall' => '卸载', 'Uninstall' => '卸载',
@ -63,9 +73,7 @@ return [
'Logout' => '退出登录', 'Logout' => '退出登录',
'Register' => '注册账号', 'Register' => '注册账号',
'You\'re not login' => '当前未登录', 'You\'re not login' => '当前未登录',
'Pay now' => '立即支付', 'Continue uninstall' => '继续卸载',
'Continue install' => '继续安装',
'Continue uninstall' => '继续安装',
'Continue operate' => '继续操作', 'Continue operate' => '继续操作',
'Install successful' => '安装成功', 'Install successful' => '安装成功',
'Uninstall successful' => '卸载成功', 'Uninstall successful' => '卸载成功',
@ -73,4 +81,6 @@ return [
'Addon info file was not found' => '插件配置文件未找到', 'Addon info file was not found' => '插件配置文件未找到',
'Addon info file data incorrect' => '插件配置信息不正确', 'Addon info file data incorrect' => '插件配置信息不正确',
'Addon already exists' => '上传的插件已经存在', 'Addon already exists' => '上传的插件已经存在',
'Unable to open the zip file' => '无法打开ZIP文件',
'Unable to extract the file' => '无法解压ZIP文件',
]; ];

View File

@ -10,9 +10,10 @@ return [
'Controller/Action' => '控制器名/方法名', 'Controller/Action' => '控制器名/方法名',
'Ismenu' => '菜单', 'Ismenu' => '菜单',
'Search icon' => '搜索图标', 'Search icon' => '搜索图标',
'Menu tips' => '规则任意,不可重复,仅做层级显示,无需匹配控制器和方法', 'Toggle menu visible' => '点击切换菜单显示',
'Node tips' => '控制器/方法名', 'Toggle sub menu' => '点击切换子菜单',
'Menu tips' => '父级菜单无需匹配控制器和方法,子级菜单请使用控制器名',
'Node tips' => '控制器/方法名,如果有目录请使用 目录名/控制器名/方法名',
'The non-menu rule must have parent' => '非菜单规则节点必须有父级', 'The non-menu rule must have parent' => '非菜单规则节点必须有父级',
'If not necessary, use the command line to build rule' => '非必要情况下请直接使用命令行<a href="https://doc.fastadmin.net/docs/command.html#一键生成菜单" target="_blank">php think menu</a>来生成',
'Name only supports letters, numbers, underscore and slash' => 'URL规则只能是小写字母、数字、下划线和/组成', 'Name only supports letters, numbers, underscore and slash' => 'URL规则只能是小写字母、数字、下划线和/组成',
]; ];

View File

@ -1,9 +1,10 @@
<?php <?php
return [ return [
'Id' => 'ID',
'Url' => '物理路径', 'Url' => '物理路径',
'Imagewidth' => '宽度', 'Imagewidth' => '宽度',
'Imageheight' => '度', 'Imageheight' => '度',
'Imagetype' => '图片类型', 'Imagetype' => '图片类型',
'Imageframes' => '图片帧数', 'Imageframes' => '图片帧数',
'Preview' => '预览', 'Preview' => '预览',

View File

@ -53,6 +53,7 @@ return [
'Mail from' => '发件人邮箱', 'Mail from' => '发件人邮箱',
'Name already exist' => '变量名称已经存在', 'Name already exist' => '变量名称已经存在',
'Send a test message' => '发送测试邮件', 'Send a test message' => '发送测试邮件',
'This is a test mail content' => '这是一封测试邮件,用于测试邮件配置是否正常!', 'This is a test mail content' => '这是一封来自FastAdmin校验邮件,用于校验邮件配置是否正常!',
'This is a test mail' => '这是一封测试邮件', 'This is a test mail' => '这是一封来自FastAdmin的邮件',
'Please input your email' => '请输入测试接收者邮箱',
]; ];

View File

@ -1,22 +0,0 @@
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="c-name" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8">
<button type="button" id="plupload-addon" class="btn btn-danger plupload" data-url="addon/local" data-mimetype="application/zip" data-multiple="false"><i class="fa fa-upload"></i> {:__('请选择一个安装包')}</button>
</div>
</div>
<div class="form-group">
<label for="c-nickname" class="control-label col-xs-12 col-sm-2">{:__('Nickname')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-nickname" data-rule="required" class="form-control" name="row[nickname]" type="text" value="">
</div>
</div>
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>

View File

@ -1,38 +1,57 @@
<style type="text/css"> <style type="text/css">
.noimage {width:100%;text-align: center;background:#18bc9c;color:#fff;padding-bottom:66.66%;position:relative;} .layui-layer-pay .layui-layer-content {
.noimage > div {position: absolute;top:48%;width:100%;text-align:center;} padding: 0;
.addon {position: relative;border-color:#e4e4e4;} height: 600px !important;
.addon > span {position:absolute;left:15px;top:15px;z-index:9;} }
.addon > span a{opacity: 0.5;border:none;color:#fff;}
.layui-layer-pay .layui-layer-content {padding:0;height:600px!important;} .layui-layer-pay {
.layui-layer-pay {border:none;} border: none;
.payimg{position:relative;width:800px;height:600px;} }
.payimg .alipaycode {position:absolute;left:265px;top:442px;}
.payimg .wechatcode {position:absolute;left:660px;top:442px;} .payimg {
.thumbnail img{width:100%;} position: relative;
width: 800px;
height: 600px;
}
.payimg .alipaycode {
position: absolute;
left: 265px;
top: 442px;
}
.payimg .wechatcode {
position: absolute;
left: 660px;
top: 442px;
}
.thumbnail img {
width: 100%;
}
.fixed-table-toolbar .pull-right.search { .fixed-table-toolbar .pull-right.search {
min-width: 300px; min-width: 300px;
} }
.status-disabled .noimage {
background:#d2d6de; a.title {
color: #444;
} }
@media (min-width: 992px) {
.addon { .releasetips {
-webkit-transition:all 0.3s ease; position: relative;
-moz-transition: all 0.3s ease; }
-o-transition: all 0.3s ease;
transition: all 0.3s ease; .releasetips i {
} display: block;
.addon:hover { background: #f00;
border-color: #dddddd; border-radius: 50%;
-webkit-box-shadow: 0 26px 40px -24px rgba(0,36,100,0.3); width: 0.3em;
-moz-box-shadow: 0 26px 40px -24px rgba(0,36,100,0.3); height: 0.3em;
box-shadow: 0 26px 40px -24px rgba(0,36,100,0.3); top: 0px;
-webkit-transition: all 0.3s ease; right: -8px;
-moz-transition: all 0.3s ease; position: absolute;
-o-transition: all 0.3s ease; box-shadow: 0px 0px 2px #f11414;
transition: all 0.3s ease;
}
} }
</style> </style>
<div class="panel panel-default panel-intro"> <div class="panel panel-default panel-intro">
@ -51,16 +70,27 @@
<div class="widget-body no-padding"> <div class="widget-body no-padding">
<div id="toolbar" class="toolbar"> <div id="toolbar" class="toolbar">
{:build_toolbar('refresh')} {:build_toolbar('refresh')}
<button type="button" id="plupload-addon" class="btn btn-danger plupload" data-url="addon/local" data-mimetype="application/zip" data-multiple="false"><i class="fa fa-upload"></i> {:__('Offline install')}</button> <button type="button" id="plupload-addon" class="btn btn-danger plupload" data-url="addon/local"
data-mimetype="application/zip" data-multiple="false"><i class="fa fa-upload"></i>
{:__('Offline install')}
</button>
<div class="btn-group"> <div class="btn-group">
<a href="#" class="btn btn-info btn-switch active" data-type="all" data-url="{$config.fastadmin.api_url}/addon/index"><i class="fa fa-list"></i> {:__('全部')}</a> <a href="#" class="btn btn-info btn-switch active" data-type="all"
<a href="#" class="btn btn-info btn-switch" data-type="free" data-url="{$config.fastadmin.api_url}/addon/index"><i class="fa fa-gift"></i> {:__('免费')}</a> data-url="{$config.fastadmin.api_url}/addon/index"><i class="fa fa-list"></i>
<a href="#" class="btn btn-info btn-switch" data-type="price" data-url="{$config.fastadmin.api_url}/addon/index"><i class="fa fa-rmb"></i> {:__('付费')}</a> {:__('All')}</a>
<a href="#" class="btn btn-info btn-switch" data-type="local" data-url="addon/downloaded"><i class="fa fa-laptop"></i> {:__('Local addon')}</a> <a href="#" class="btn btn-info btn-switch" data-type="free"
data-url="{$config.fastadmin.api_url}/addon/index"><i class="fa fa-gift"></i>
{:__('Free')}</a>
<a href="#" class="btn btn-info btn-switch" data-type="price"
data-url="{$config.fastadmin.api_url}/addon/index"><i class="fa fa-rmb"></i>
{:__('Paying')}</a>
<a href="#" class="btn btn-info btn-switch" data-type="local" data-url="addon/downloaded"><i
class="fa fa-laptop"></i> {:__('Local addon')}</a>
</div> </div>
<a class="btn btn-primary btn-userinfo" href="javascript:;"><i class="fa fa-user"></i> {:__('Userinfo')}</a> <a class="btn btn-primary btn-userinfo" href="javascript:;"><i class="fa fa-user"></i>
{:__('Userinfo')}</a>
</div> </div>
<table id="table" class="table table-striped table-hover" width="100%"> <table id="table" class="table table-striped table-bordered table-hover" width="100%">
</table> </table>
@ -76,28 +106,28 @@
<div class="row"> <div class="row">
<div class="col-xs-12 col-sm-6 col-md-3"> <div class="col-xs-12 col-sm-6 col-md-3">
<div class="form-group"> <div class="form-group">
<label class="control-label">标题</label> <label class="control-label">{:__('Title')}</label>
<input class="operate" type="hidden" data-name="title" value="like"/> <input class="operate" type="hidden" data-name="title" value="like"/>
<input class="form-control" type="text" name="title" placeholder="请输入查找的标题" value=""/> <input class="form-control" type="text" name="title" placeholder="" value=""/>
</div> </div>
</div> </div>
<div class="col-xs-12 col-sm-6 col-md-3"> <div class="col-xs-12 col-sm-6 col-md-3">
<div class="form-group"> <div class="form-group">
<label class="control-label">类型</label> <label class="control-label">{:__('Type')}</label>
<input class="operate" type="hidden" data-name="type" value="="/> <input class="operate" type="hidden" data-name="type" value="="/>
<input class="form-control" type="text" name="type" placeholder="all" value=""/> <input class="form-control" type="text" name="type" placeholder="all" value=""/>
</div> </div>
</div> </div>
<div class="col-xs-12 col-sm-6 col-md-3"> <div class="col-xs-12 col-sm-6 col-md-3">
<div class="form-group"> <div class="form-group">
<label class="control-label">分类</label> <label class="control-label">{:__('Category')}</label>
<input type="hidden" class="operate" data-name="category_id" value="="/> <input type="hidden" class="operate" data-name="category_id" value="="/>
<input class="form-control" name="category_id" type="text" value=""> <input class="form-control" name="category_id" type="text" value="">
</div> </div>
</div> </div>
<div class="col-xs-12 col-sm-6 col-md-3"> <div class="col-xs-12 col-sm-6 col-md-3">
<div class="form-group"> <div class="form-group">
<label class="control-label">版本号</label> <label class="control-label">{:__('Version')}</label>
<input type="hidden" class="operate" data-name="faversion" value="="/> <input type="hidden" class="operate" data-name="faversion" value="="/>
<input class="form-control" name="faversion" type="text" value="{$config.fastadmin.version}"> <input class="form-control" name="faversion" type="text" value="{$config.fastadmin.version}">
</div> </div>
@ -107,10 +137,10 @@
<label class="control-label"></label> <label class="control-label"></label>
<div class="row"> <div class="row">
<div class="col-xs-6"> <div class="col-xs-6">
<input type="submit" class="btn btn-success btn-block" value="提交"/> <input type="submit" class="btn btn-success btn-block" value="{:__('Submit')}"/>
</div> </div>
<div class="col-xs-6"> <div class="col-xs-6">
<input type="reset" class="btn btn-primary btn-block" value="重置"/> <input type="reset" class="btn btn-primary btn-block" value="{:__('Reset')}"/>
</div> </div>
</div> </div>
</div> </div>
@ -125,18 +155,20 @@
<fieldset> <fieldset>
<div class="alert alert-dismissable alert-danger"> <div class="alert alert-dismissable alert-danger">
<button type="button" class="close" data-dismiss="alert">×</button> <button type="button" class="close" data-dismiss="alert">×</button>
<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> <label for="inputAccount" class="col-lg-3 control-label">{:__('Username')}</label>
<div class="col-lg-9"> <div class="col-lg-9">
<input type="text" class="form-control" id="inputAccount" value="" placeholder="{:__('Your username or email')}"> <input type="text" class="form-control" id="inputAccount" value=""
placeholder="{:__('Your username or email')}">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="inputPassword" class="col-lg-3 control-label">{:__('Password')}</label> <label for="inputPassword" class="col-lg-3 control-label">{:__('Password')}</label>
<div class="col-lg-9"> <div class="col-lg-9">
<input type="password" class="form-control" id="inputPassword" value="" placeholder="{:__('Your password')}"> <input type="password" class="form-control" id="inputPassword" value=""
placeholder="{:__('Your password')}">
</div> </div>
</div> </div>
</fieldset> </fieldset>
@ -149,57 +181,12 @@
<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>
</form> </form>
</div> </div>
</script> </script>
<script id="addoninfotpl" type="text/html">
<div style="font-size:13px;">
<table class="table table-striped">
<thead>
<tr>
<th colspan="2"><h4><%=item.title%></h4></th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">{:__('Price')}</th>
<td><div class="text-<%=item.price>0?'danger':'success'%>"><b><%=item.price%></b></div></td>
</tr>
<tr>
<th scope="row">{:__('Author')}</th>
<td><a href="<%=item.url?item.url:'javascript:;'%>" target="_blank"><%=item.author%></a></td>
</tr>
<tr>
<th scope="row">{:__('Identify')}</th>
<td><%=item.name%></td>
</tr>
<tr>
<th scope="row">{:__('Homepage')}</th>
<td><a href="https://www.fastadmin.net/store/<%=item.name%>.html" target="_blank">https://www.fastadmin.net/store/<%=item.name%>.html</a></td>
</tr>
<tr>
<th scope="row">{:__('Intro')}</th>
<td><%=item.intro%></td>
</tr>
<tr>
<th scope="row">{:__('Version')}</th>
<td><%=# addon && item && addon.version!=item.version?'<span class="label label-danger">'+addon.version+'</span> -> <span class="label label-success">'+item.version+'</span>':item.version%></td>
</tr>
<tr>
<th scope="row">{:__('Createtime')}</th>
<td><%=Moment(item.createtime*1000).format("YYYY-MM-DD HH:mm:ss")%></td>
</tr>
<tr>
<th scope="row">{:__('Releasetime')}</th>
<td><%=Moment(item.releasetime*1000).format("YYYY-MM-DD HH:mm:ss")%></td>
</tr>
</tbody>
</table>
</div>
</script>
<script id="paytpl" type="text/html"> <script id="paytpl" type="text/html">
<div class="payimg" style="background:url('<%=payimg%>') 0 0 no-repeat;background-size:cover;"> <div class="payimg" style="background:url('<%=payimg%>') 0 0 no-repeat;background-size:cover;">
<%if(paycode){%> <%if(paycode){%>
@ -219,118 +206,85 @@
</div> </div>
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
<th>#</th> <th>#</th>
<th>{:__('File')}</th> <th>{:__('File')}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<%for(var i=0;i < conflictlist.length;i++){%> <%for(var i=0;i < conflictlist.length;i++){%>
<tr> <tr>
<th scope="row"><%=i+1%></th> <th scope="row"><%=i+1%></th>
<td><%=conflictlist[i]%></td> <td><%=conflictlist[i]%></td>
</tr> </tr>
<%}%> <%}%>
</tbody> </tbody>
</table> </table>
</script> </script>
<script id="itemtpl" type="text/html"> <script id="operatetpl" type="text/html">
<% var labelarr = ['primary', 'success', 'info', 'danger', 'warning']; %> <% var labelarr = ['primary', 'success', 'info', 'danger', 'warning']; %>
<% var label = labelarr[item.id % 5]; %> <% var label = labelarr[item.id % 5]; %>
<% var addon = typeof addons[item.name]!= 'undefined' ? addons[item.name] : null; %> <% var addon = item.addon; %>
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3 mt-4 status-<%=addon ? (addon.state==1?'enabled':'disabled') : 'uninstalled'%>">
<div class="thumbnail addon"> <div class="operate" data-id="<%=item.id%>" data-name="<%=item.name%>">
<%if(addon){%> <% if(!addon){ %>
<span> <% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
<a href="<%=addon.url%>" target="_blank" class="btn btn-xs"> <span class="btn-group">
<i class="fa fa-home"></i> <a href="javascript:;" class="btn btn-xs btn-primary btn-success btn-install"
data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>"
data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a>
<a class="btn btn-xs btn-success dropdown-toggle" data-toggle="dropdown" href="javascript:;">
<span class="fa fa-caret-down"></span>
</a> </a>
<ul class="dropdown-menu">
<% for(var j=0;j< item.releaselist.length;j++){ %>
<li><a href="javascript:;" class="btn-install" data-type="<%=item.price<=0?'free':'price';%>"
data-donateimage="<%=item.donateimage%>"
data-version="<%=item.releaselist[j].version%>"><%=item.releaselist[j].version%></a></li>
<% } %>
</ul>
</span> </span>
<%}%> <% }else{%>
<a href="<%=item.url%>" class="btn-addonindex" target="_blank"> <a href="javascript:;" class="btn btn-xs btn-primary btn-success btn-install"
<%if(item.image){%> data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>"
<img src="<%=item.image%>" class="img-responsive" alt="<%=item.title%>"> data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a>
<%}else{%> <% } %>
<div class="noimage"><div>{:__('No image')}</div></div>
<%}%>
</a>
<div class="caption">
<h4><%=item.title?item.title:'{:__('None')}'%>
<% if(item.flag.indexOf("recommend")>-1){%>
<span class="label label-success">{:__('Recommend')}</span>
<% } %>
<% if(item.flag.indexOf("hot")>-1){%>
<span class="label label-danger">{:__('Hot')}</span>
<% } %>
<% if(item.flag.indexOf("free")>-1){%>
<span class="label label-info">{:__('Free')}</span>
<% } %>
<% if(item.flag.indexOf("sale")>-1){%>
<span class="label label-warning">{:__('Sale')}</span>
<% } %>
</h4>
<p class="text-<%=item.price>0?'danger':'success'%>"><b><%=item.price%></b></p>
<p class="text-muted">{:__('Author')}: <a href="<%=item.url?item.url:'javascript:;'%>" target="_blank"><%=item.author%></a></p>
<p class="text-muted">{:__('Intro')}: <%=item.intro%></p>
<p class="text-muted">{:__('Version')}: <%=# addon && item && addon.version!=item.version?'<span class="label label-danger">'+addon.version+'</span> -> <span class="label label-success">'+item.version+'</span>':item.version%></p>
<p class="text-muted">{:__('Createtime')}: <%=Moment(item.createtime*1000).format("YYYY-MM-DD HH:mm:ss")%></p>
<div class="operate" data-id="<%=item.id%>" data-name="<%=item.name%>">
<% if(!addon){ %>
<% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
<span class="btn-group">
<a href="javascript:;" class="btn btn-primary btn-success btn-install" data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>" data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a>
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown" href="javascript:;">
<span class="fa fa-caret-down"></span>
</a>
<ul class="dropdown-menu">
<% for(var j=0;j< item.releaselist.length;j++){ %>
<li><a href="javascript:;" class="btn-install" data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>" data-version="<%=item.releaselist[j].version%>"><%=item.releaselist[j].version%></a></li>
<% } %>
</ul>
</span>
<% }else{%>
<a href="javascript:;" class="btn btn-primary btn-success btn-install" data-type="<%=item.price<=0?'free':'price';%>" data-donateimage="<%=item.donateimage%>" data-version="<%=item.version%>"><i class="fa fa-cloud-download"></i> {:__('Install')}</a>
<% } %>
<% if(item.demourl){ %>
<a href="<%=item.demourl%>" class="btn btn-primary btn-info btn-demo" target="_blank"><i class="fa fa-flash"></i> {:__('Demo')}</a>
<% } %>
<% } %>
<% if(addon){ %> <% if(item.demourl){ %>
<% if(addon.config){ %> <a href="<%=item.demourl%>" class="btn btn-xs btn-primary btn-info btn-demo" target="_blank">
<a href="javascript:;" class="btn btn-primary btn-config"><i class="fa fa-pencil"></i> {:__('Setting')}</a> <i class="fa fa-flash"></i> {:__('Demo')}
<% } %> </a>
<% if(addon.state == "1"){ %> <% } %>
<a href="javascript:;" class="btn btn-warning btn-disable" data-action="disable"><i class="fa fa-times"></i> {:__('Disable')}</a> <% } else {%>
<% }else{ %> <% if(addon.version!=item.version){%>
<a href="javascript:;" class="btn btn-success btn-enable" data-action="enable"><i class="fa fa-check"></i> {:__('Enable')}</a> <% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
<a href="javascript:;" class="btn btn-danger btn-uninstall"><i class="fa fa-times"></i> {:__('Uninstall')}</a> <span class="btn-group">
<% } %> <a href="javascript:;" class="btn btn-xs btn-info btn-success btn-upgrade"
<% } %> data-version="<%=item.version%>"><i class="fa fa-cloud"></i> {:__('Upgrade')}</a>
<% if(addon && item && addon.version!=item.version){%> <a class="btn btn-xs btn-info dropdown-toggle" data-toggle="dropdown"
<% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%> href="javascript:;">
<span class="btn-group"> <span class="fa fa-caret-down"></span>
<a href="javascript:;" class="btn btn-info btn-success btn-upgrade" data-version="<%=item.version%>"><i class="fa fa-cloud"></i> {:__('Upgrade')}</a> </a>
<a class="btn btn-info dropdown-toggle" data-toggle="dropdown" href="javascript:;"> <ul class="dropdown-menu">
<span class="fa fa-caret-down"></span> <% for(var j=0;j< item.releaselist.length;j++){ %>
</a> <li><a href="javascript:;" class="btn-upgrade"
<ul class="dropdown-menu"> data-version="<%=item.releaselist[j].version%>"><%=item.releaselist[j].version%></a></li>
<% for(var j=0;j< item.releaselist.length;j++){ %> <% } %>
<li><a href="javascript:;" class="btn-upgrade" data-version="<%=item.releaselist[j].version%>"><%=item.releaselist[j].version%></a></li> </ul>
<% } %> </span>
</ul> <% }else{%>
</span> <a href="javascript:;" class="btn btn-xs btn-info btn-upgrade" data-version="<%=item.version%>"><i
<% }else{%> class="fa fa-cloud"></i> {:__('Upgrade')}</a>
<a href="javascript:;" class="btn btn-info btn-upgrade" data-version="<%=item.version%>"><i class="fa fa-cloud"></i> {:__('Upgrade')}</a> <% }%>
<% }%> <% }%>
<% }%> <% if(addon.config){ %>
<a href="javascript:;" class="btn btn-xs btn-primary btn-config"><i class="fa fa-pencil"></i>
{:__('Setting')}</a>
<% } %>
<a href="javascript:;" class="btn btn-xs btn-danger btn-uninstall"><i class="fa fa-times"></i>
{:__('Uninstall')}</a>
<% } %>
<span class="pull-right" style="margin-top:10px;">
<a href="javascript:;" class="btn-addoninfo text-gray" data-index="<%=i%>" title="<%=item.title?item.title:'{:__('None')}'%>"><i class="fa fa-bars"></i></a>
</span>
</div>
</div>
</div>
</div> </div>
</script> </script>

View File

@ -1,6 +1,6 @@
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action=""> <form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group"> <div class="form-group">
<label for="role_id" class="control-label col-xs-12 col-sm-2">{:__('Group')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Group')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_select('group[]', $groupdata, null, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])} {:build_select('group[]', $groupdata, null, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])}
</div> </div>
@ -30,7 +30,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])} {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div> </div>

View File

@ -1,6 +1,6 @@
<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action=""> <form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group"> <div class="form-group">
<label for="role_id" class="control-label col-xs-12 col-sm-2">{:__('Group')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Group')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_select('group[]', $groupdata, $groupids, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])} {:build_select('group[]', $groupdata, $groupids, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])}
</div> </div>
@ -36,7 +36,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])} {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div> </div>

View File

@ -1,19 +1,19 @@
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action=""> <form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<input type="hidden" name="row[rules]" value="" /> <input type="hidden" name="row[rules]" value="" />
<div class="form-group"> <div class="form-group">
<label for="pid" class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $groupdata, null, ['class'=>'form-control selectpicker', 'data-rule'=>'required'])} {:build_select('row[pid]', $groupdata, null, ['class'=>'form-control selectpicker', 'data-rule'=>'required'])}
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="username" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="name" name="row[name]" value="" data-rule="required" /> <input type="text" class="form-control" id="name" name="row[name]" value="" data-rule="required" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="nickname" class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><small>{:__('Check all')}</small></label></span> <span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><small>{:__('Check all')}</small></label></span>
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><small>{:__('Expand all')}</small></label></span> <span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><small>{:__('Expand all')}</small></label></span>
@ -22,7 +22,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])} {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div> </div>

View File

@ -1,19 +1,19 @@
<form id="edit-form" class="form-horizontal form-ajax" role="form" method="POST" action=""> <form id="edit-form" class="form-horizontal form-ajax" role="form" method="POST" action="">
<input type="hidden" name="row[rules]" value="" /> <input type="hidden" name="row[rules]" value="" />
<div class="form-group"> <div class="form-group">
<label for="pid" class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $groupdata, $row['pid'], ['class'=>'form-control selectpicker', 'data-rule'=>'required', 'data-id'=>$row['id'], 'data-pid'=>$row['pid']])} {:build_select('row[pid]', $groupdata, $row['pid'], ['class'=>'form-control selectpicker', 'data-rule'=>'required', 'data-id'=>$row['id'], 'data-pid'=>$row['pid']])}
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="username" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="name" name="row[name]" value="{$row.name}" data-rule="required" /> <input type="text" class="form-control" id="name" name="row[name]" value="{$row.name}" data-rule="required" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="nickname" class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><small>{:__('Check all')}</small></label></span> <span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><small>{:__('Check all')}</small></label></span>
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><small>{:__('Expand all')}</small></label></span> <span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><small>{:__('Expand all')}</small></label></span>
@ -22,7 +22,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])} {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div> </div>

View File

@ -1,16 +1,12 @@
<div class="callout callout-info">
<h4>{:__('Alert')}!</h4>
{:__('If not necessary, use the command line to build rule')}
</div>
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action=""> <form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group"> <div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Ismenu')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Ismenu')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_radios('row[ismenu]', ['1'=>__('Yes'), '0'=>__('No')])} {:build_radios('row[ismenu]', ['1'=>__('Yes'), '0'=>__('No')])}
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="pid" class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $ruledata, null, ['class'=>'form-control', 'required'=>''])} {:build_select('row[pid]', $ruledata, null, ['class'=>'form-control', 'required'=>''])}
</div> </div>
@ -18,11 +14,12 @@
<div class="form-group"> <div class="form-group">
<label for="name" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label> <label for="name" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<a href="javascript:;" data-toggle="tooltip" title="提示">测试</a>
<input type="text" class="form-control" id="name" name="row[name]" data-placeholder-node="{:__('Node tips')}" data-placeholder-menu="{:__('Menu tips')}" value="" data-rule="required" /> <input type="text" class="form-control" id="name" name="row[name]" data-placeholder-node="{:__('Node tips')}" data-placeholder-menu="{:__('Menu tips')}" value="" data-rule="required" />
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="module" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="title" name="row[title]" value="" data-rule="required" /> <input type="text" class="form-control" id="title" name="row[title]" value="" data-rule="required" />
</div> </div>
@ -55,7 +52,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])} {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div> </div>

View File

@ -1,12 +1,12 @@
<form id="edit-form" class="form-horizontal form-ajax" role="form" method="POST" action=""> <form id="edit-form" class="form-horizontal form-ajax" role="form" method="POST" action="">
<div class="form-group"> <div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Ismenu')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Ismenu')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_radios('row[ismenu]', ['1'=>__('Yes'), '0'=>__('No')], $row['ismenu'])} {:build_radios('row[ismenu]', ['1'=>__('Yes'), '0'=>__('No')], $row['ismenu'])}
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="pid" class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $ruledata, $row['pid'], ['class'=>'form-control', 'required'=>''])} {:build_select('row[pid]', $ruledata, $row['pid'], ['class'=>'form-control', 'required'=>''])}
</div> </div>
@ -18,7 +18,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="action" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
<input type="text" class="form-control" id="title" name="row[title]" value="{$row.title}" data-rule="required" /> <input type="text" class="form-control" id="title" name="row[title]" value="{$row.title}" data-rule="required" />
</div> </div>
@ -51,7 +51,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])} {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div> </div>

View File

@ -6,12 +6,13 @@
margin:5px 0 0 0; margin:5px 0 0 0;
} }
#chooseicon ul li{ #chooseicon ul li{
width:30px;height:30px; width:41px;height:42px;
line-height:30px; line-height:42px;
border:1px solid #ddd; border:1px solid #efefef;
padding:1px; padding:1px;
margin:1px; margin:1px;
text-align: center; text-align: center;
font-size:18px;
} }
#chooseicon ul li:hover{ #chooseicon ul li:hover{
border:1px solid #2c3e50; border:1px solid #2c3e50;
@ -31,7 +32,7 @@
<div> <div>
<ul class="list-inline"> <ul class="list-inline">
<% for(var i=0; i<iconlist.length; i++){ %> <% for(var i=0; i<iconlist.length; i++){ %>
<li data-font="<%=iconlist[i]%>" title="<%=iconlist[i]%>"> <li data-font="<%=iconlist[i]%>" data-toggle="tooltip" title="<%=iconlist[i]%>">
<i class="fa fa-<%=iconlist[i]%>"></i> <i class="fa fa-<%=iconlist[i]%>"></i>
</li> </li>
<% } %> <% } %>

View File

@ -81,7 +81,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-status" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])} {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div> </div>

View File

@ -81,7 +81,7 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="c-status" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label> <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8"> <div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])} {:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div> </div>

View File

@ -54,6 +54,7 @@
</a> </a>
<ul class="dropdown-menu wipecache"> <ul class="dropdown-menu wipecache">
<li><a href="javascript:;" data-type="all"><i class="fa fa-trash"></i> {:__('Wipe all cache')}</a></li> <li><a href="javascript:;" data-type="all"><i class="fa fa-trash"></i> {:__('Wipe all cache')}</a></li>
<li class="divider"></li>
<li><a href="javascript:;" data-type="content"><i class="fa fa-file-text"></i> {:__('Wipe content cache')}</a></li> <li><a href="javascript:;" data-type="content"><i class="fa fa-file-text"></i> {:__('Wipe content cache')}</a></li>
<li><a href="javascript:;" data-type="template"><i class="fa fa-file-image-o"></i> {:__('Wipe template cache')}</a></li> <li><a href="javascript:;" data-type="template"><i class="fa fa-file-image-o"></i> {:__('Wipe template cache')}</a></li>
<li><a href="javascript:;" data-type="addons"><i class="fa fa-rocket"></i> {:__('Wipe addons cache')}</a></li> <li><a href="javascript:;" data-type="addons"><i class="fa fa-rocket"></i> {:__('Wipe addons cache')}</a></li>

View File

@ -24,15 +24,14 @@ class Common extends Api
/** /**
* 加载初始化 * 加载初始化
* *
* @param string $version 版本号 * @param string $version 版本号
* @param string $lng 经度 * @param string $lng 经度
* @param string $lat 纬度 * @param string $lat 纬度
*/ */
public function init() public function init()
{ {
if ($version = $this->request->request('version')) if ($version = $this->request->request('version')) {
{
$lng = $this->request->request('lng'); $lng = $this->request->request('lng');
$lat = $this->request->request('lat'); $lat = $this->request->request('lat');
$content = [ $content = [
@ -42,23 +41,20 @@ class Common extends Api
'coverdata' => Config::get("cover"), 'coverdata' => Config::get("cover"),
]; ];
$this->success('', $content); $this->success('', $content);
} } else {
else
{
$this->error(__('Invalid parameters')); $this->error(__('Invalid parameters'));
} }
} }
/** /**
* 上传文件 * 上传文件
* *
* @param File $file 文件流 * @param File $file 文件流
*/ */
public function upload() public function upload()
{ {
$file = $this->request->file('file'); $file = $this->request->file('file');
if (empty($file)) if (empty($file)) {
{
$this->error(__('No file upload or server upload limit exceeded')); $this->error(__('No file upload or server upload limit exceeded'));
} }
@ -70,7 +66,7 @@ class Common extends Api
preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches); preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches);
$type = strtolower($matches[2]); $type = strtolower($matches[2]);
$typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3]; $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
$size = (int) $upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0); $size = (int)$upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
$fileInfo = $file->getInfo(); $fileInfo = $file->getInfo();
$suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION)); $suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
$suffix = $suffix ? $suffix : 'file'; $suffix = $suffix ? $suffix : 'file';
@ -108,16 +104,16 @@ class Common extends Api
$fileName = substr($savekey, strripos($savekey, '/') + 1); $fileName = substr($savekey, strripos($savekey, '/') + 1);
// //
$splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName); $splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
if ($splInfo) if ($splInfo) {
{
$imagewidth = $imageheight = 0; $imagewidth = $imageheight = 0;
if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf'])) if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf'])) {
{
$imgInfo = getimagesize($splInfo->getPathname()); $imgInfo = getimagesize($splInfo->getPathname());
$imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth; $imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
$imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight; $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
} }
$params = array( $params = array(
'admin_id' => 0,
'user_id' => (int)$this->auth->id,
'filesize' => $fileInfo['size'], 'filesize' => $fileInfo['size'],
'imagewidth' => $imagewidth, 'imagewidth' => $imagewidth,
'imageheight' => $imageheight, 'imageheight' => $imageheight,
@ -136,9 +132,7 @@ class Common extends Api
$this->success(__('Upload successful'), [ $this->success(__('Upload successful'), [
'url' => $uploadDir . $splInfo->getSaveName() 'url' => $uploadDir . $splInfo->getSaveName()
]); ]);
} } else {
else
{
// 上传失败获取错误信息 // 上传失败获取错误信息
$this->error($file->getError()); $this->error($file->getError());
} }

View File

@ -2,22 +2,20 @@
// 公共助手函数 // 公共助手函数
if (!function_exists('__')) if (!function_exists('__')) {
{
/** /**
* 获取语言变量值 * 获取语言变量值
* @param string $name 语言变量名 * @param string $name 语言变量名
* @param array $vars 动态变量值 * @param array $vars 动态变量值
* @param string $lang 语言 * @param string $lang 语言
* @return mixed * @return mixed
*/ */
function __($name, $vars = [], $lang = '') function __($name, $vars = [], $lang = '')
{ {
if (is_numeric($name) || !$name) if (is_numeric($name) || !$name)
return $name; return $name;
if (!is_array($vars)) if (!is_array($vars)) {
{
$vars = func_get_args(); $vars = func_get_args();
array_shift($vars); array_shift($vars);
$lang = ''; $lang = '';
@ -27,8 +25,7 @@ if (!function_exists('__'))
} }
if (!function_exists('format_bytes')) if (!function_exists('format_bytes')) {
{
/** /**
* 将字节转换为可读文本 * 将字节转换为可读文本
@ -46,8 +43,7 @@ if (!function_exists('format_bytes'))
} }
if (!function_exists('datetime')) if (!function_exists('datetime')) {
{
/** /**
* 将时间戳转换为日期时间 * 将时间戳转换为日期时间
@ -63,8 +59,7 @@ if (!function_exists('datetime'))
} }
if (!function_exists('human_date')) if (!function_exists('human_date')) {
{
/** /**
* 获取语义化时间 * 获取语义化时间
@ -79,50 +74,56 @@ if (!function_exists('human_date'))
} }
if (!function_exists('cdnurl')) if (!function_exists('cdnurl')) {
{
/** /**
* 获取上传资源的CDN的地址 * 获取上传资源的CDN的地址
* @param string $url 资源相对地址 * @param string $url 资源相对地址
* @param boolean $domain 是否显示域名 或者直接传入域名
* @return string * @return string
*/ */
function cdnurl($url) function cdnurl($url, $domain = false)
{ {
return preg_match("/^https?:\/\/(.*)/i", $url) ? $url : \think\Config::get('upload.cdnurl') . $url; $url = preg_match("/^https?:\/\/(.*)/i", $url) ? $url : \think\Config::get('upload.cdnurl') . $url;
if ($domain && !preg_match("/^(http:\/\/|https:\/\/)/i", $url)) {
if (is_bool($domain)) {
$public = \think\Config::get('view_replace_str.__PUBLIC__');
$url = rtrim($public, '/') . $url;
if (!preg_match("/^(http:\/\/|https:\/\/)/i", $url)) {
$url = request()->domain() . $url;
}
} else {
$url = $domain . $url;
}
}
return $url;
} }
} }
if (!function_exists('is_really_writable')) if (!function_exists('is_really_writable')) {
{
/** /**
* 判断文件或文件夹是否可写 * 判断文件或文件夹是否可写
* @param string $file 文件或目录 * @param string $file 文件或目录
* @return bool * @return bool
*/ */
function is_really_writable($file) function is_really_writable($file)
{ {
if (DIRECTORY_SEPARATOR === '/') if (DIRECTORY_SEPARATOR === '/') {
{
return is_writable($file); return is_writable($file);
} }
if (is_dir($file)) if (is_dir($file)) {
{
$file = rtrim($file, '/') . '/' . md5(mt_rand()); $file = rtrim($file, '/') . '/' . md5(mt_rand());
if (($fp = @fopen($file, 'ab')) === FALSE) if (($fp = @fopen($file, 'ab')) === FALSE) {
{
return FALSE; return FALSE;
} }
fclose($fp); fclose($fp);
@chmod($file, 0777); @chmod($file, 0777);
@unlink($file); @unlink($file);
return TRUE; return TRUE;
} } elseif (!is_file($file) OR ($fp = @fopen($file, 'ab')) === FALSE) {
elseif (!is_file($file) OR ( $fp = @fopen($file, 'ab')) === FALSE)
{
return FALSE; return FALSE;
} }
fclose($fp); fclose($fp);
@ -131,8 +132,7 @@ if (!function_exists('is_really_writable'))
} }
if (!function_exists('rmdirs')) if (!function_exists('rmdirs')) {
{
/** /**
* 删除文件夹 * 删除文件夹
@ -145,16 +145,14 @@ if (!function_exists('rmdirs'))
if (!is_dir($dirname)) if (!is_dir($dirname))
return false; return false;
$files = new RecursiveIteratorIterator( $files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dirname, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST new RecursiveDirectoryIterator($dirname, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST
); );
foreach ($files as $fileinfo) foreach ($files as $fileinfo) {
{
$todo = ($fileinfo->isDir() ? 'rmdir' : 'unlink'); $todo = ($fileinfo->isDir() ? 'rmdir' : 'unlink');
$todo($fileinfo->getRealPath()); $todo($fileinfo->getRealPath());
} }
if ($withself) if ($withself) {
{
@rmdir($dirname); @rmdir($dirname);
} }
return true; return true;
@ -162,8 +160,7 @@ if (!function_exists('rmdirs'))
} }
if (!function_exists('copydirs')) if (!function_exists('copydirs')) {
{
/** /**
* 复制文件夹 * 复制文件夹
@ -172,25 +169,19 @@ if (!function_exists('copydirs'))
*/ */
function copydirs($source, $dest) function copydirs($source, $dest)
{ {
if (!is_dir($dest)) if (!is_dir($dest)) {
{ mkdir($dest, 0755, true);
mkdir($dest, 0755);
} }
foreach ( foreach (
$iterator = new RecursiveIteratorIterator( $iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST) as $item new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST) as $item
) ) {
{ if ($item->isDir()) {
if ($item->isDir())
{
$sontDir = $dest . DS . $iterator->getSubPathName(); $sontDir = $dest . DS . $iterator->getSubPathName();
if (!is_dir($sontDir)) if (!is_dir($sontDir)) {
{ mkdir($sontDir, 0755, true);
mkdir($sontDir);
} }
} } else {
else
{
copy($item, $dest . DS . $iterator->getSubPathName()); copy($item, $dest . DS . $iterator->getSubPathName());
} }
} }
@ -198,8 +189,7 @@ if (!function_exists('copydirs'))
} }
if (!function_exists('mb_ucfirst')) if (!function_exists('mb_ucfirst')) {
{
function mb_ucfirst($string) function mb_ucfirst($string)
{ {
@ -208,8 +198,7 @@ if (!function_exists('mb_ucfirst'))
} }
if (!function_exists('addtion')) if (!function_exists('addtion')) {
{
/** /**
* 附加关联字段数据 * 附加关联字段数据
@ -222,31 +211,22 @@ if (!function_exists('addtion'))
if (!$items || !$fields) if (!$items || !$fields)
return $items; return $items;
$fieldsArr = []; $fieldsArr = [];
if (!is_array($fields)) if (!is_array($fields)) {
{
$arr = explode(',', $fields); $arr = explode(',', $fields);
foreach ($arr as $k => $v) foreach ($arr as $k => $v) {
{
$fieldsArr[$v] = ['field' => $v]; $fieldsArr[$v] = ['field' => $v];
} }
} } else {
else foreach ($fields as $k => $v) {
{ if (is_array($v)) {
foreach ($fields as $k => $v)
{
if (is_array($v))
{
$v['field'] = isset($v['field']) ? $v['field'] : $k; $v['field'] = isset($v['field']) ? $v['field'] : $k;
} } else {
else
{
$v = ['field' => $v]; $v = ['field' => $v];
} }
$fieldsArr[$v['field']] = $v; $fieldsArr[$v['field']] = $v;
} }
} }
foreach ($fieldsArr as $k => &$v) foreach ($fieldsArr as $k => &$v) {
{
$v = is_array($v) ? $v : ['field' => $v]; $v = is_array($v) ? $v : ['field' => $v];
$v['display'] = isset($v['display']) ? $v['display'] : str_replace(['_ids', '_id'], ['_names', '_name'], $v['field']); $v['display'] = isset($v['display']) ? $v['display'] : str_replace(['_ids', '_id'], ['_names', '_name'], $v['field']);
$v['primary'] = isset($v['primary']) ? $v['primary'] : ''; $v['primary'] = isset($v['primary']) ? $v['primary'] : '';
@ -258,37 +238,27 @@ if (!function_exists('addtion'))
unset($v); unset($v);
$ids = []; $ids = [];
$fields = array_keys($fieldsArr); $fields = array_keys($fieldsArr);
foreach ($items as $k => $v) foreach ($items as $k => $v) {
{ foreach ($fields as $m => $n) {
foreach ($fields as $m => $n) if (isset($v[$n])) {
{
if (isset($v[$n]))
{
$ids[$n] = array_merge(isset($ids[$n]) && is_array($ids[$n]) ? $ids[$n] : [], explode(',', $v[$n])); $ids[$n] = array_merge(isset($ids[$n]) && is_array($ids[$n]) ? $ids[$n] : [], explode(',', $v[$n]));
} }
} }
} }
$result = []; $result = [];
foreach ($fieldsArr as $k => $v) foreach ($fieldsArr as $k => $v) {
{ if ($v['model']) {
if ($v['model'])
{
$model = new $v['model']; $model = new $v['model'];
} } else {
else
{
$model = $v['name'] ? \think\Db::name($v['name']) : \think\Db::table($v['table']); $model = $v['name'] ? \think\Db::name($v['name']) : \think\Db::table($v['table']);
} }
$primary = $v['primary'] ? $v['primary'] : $model->getPk(); $primary = $v['primary'] ? $v['primary'] : $model->getPk();
$result[$v['field']] = $model->where($primary, 'in', $ids[$v['field']])->column("{$primary},{$v['column']}"); $result[$v['field']] = $model->where($primary, 'in', $ids[$v['field']])->column("{$primary},{$v['column']}");
} }
foreach ($items as $k => &$v) foreach ($items as $k => &$v) {
{ foreach ($fields as $m => $n) {
foreach ($fields as $m => $n) if (isset($v[$n])) {
{
if (isset($v[$n]))
{
$curr = array_flip(explode(',', $v[$n])); $curr = array_flip(explode(',', $v[$n]));
$v[$fieldsArr[$n]['display']] = implode(',', array_intersect_key($result[$n], $curr)); $v[$fieldsArr[$n]['display']] = implode(',', array_intersect_key($result[$n], $curr));
@ -300,29 +270,26 @@ if (!function_exists('addtion'))
} }
if (!function_exists('var_export_short')) if (!function_exists('var_export_short')) {
{
/** /**
* 返回打印数组结构 * 返回打印数组结构
* @param string $var 数组 * @param string $var 数组
* @param string $indent 缩进字符 * @param string $indent 缩进字符
* @return string * @return string
*/ */
function var_export_short($var, $indent = "") function var_export_short($var, $indent = "")
{ {
switch (gettype($var)) switch (gettype($var)) {
{
case "string": case "string":
return '"' . addcslashes($var, "\\\$\"\r\n\t\v\f") . '"'; return '"' . addcslashes($var, "\\\$\"\r\n\t\v\f") . '"';
case "array": case "array":
$indexed = array_keys($var) === range(0, count($var) - 1); $indexed = array_keys($var) === range(0, count($var) - 1);
$r = []; $r = [];
foreach ($var as $key => $value) foreach ($var as $key => $value) {
{
$r[] = "$indent " $r[] = "$indent "
. ($indexed ? "" : var_export_short($key) . " => ") . ($indexed ? "" : var_export_short($key) . " => ")
. var_export_short($value, "$indent "); . var_export_short($value, "$indent ");
} }
return "[\n" . implode(",\n", $r) . "\n" . $indent . "]"; return "[\n" . implode(",\n", $r) . "\n" . $indent . "]";
case "boolean": case "boolean":

View File

@ -270,7 +270,7 @@ return [
//自动检测更新 //自动检测更新
'checkupdate' => false, 'checkupdate' => false,
//版本号 //版本号
'version' => '1.0.0.20180417_beta', 'version' => '1.0.0.20180506_beta',
//API接口地址 //API接口地址
'api_url' => 'https://api.fastadmin.net', 'api_url' => 'https://api.fastadmin.net',
], ],

View File

@ -107,7 +107,7 @@ class User extends Frontend
$validate = new Validate($rule, $msg); $validate = new Validate($rule, $msg);
$result = $validate->check($data); $result = $validate->check($data);
if (!$result) { if (!$result) {
$this->error(__($validate->getError())); $this->error(__($validate->getError()), null, ['token' => $this->request->token()]);
} }
if ($this->auth->register($username, $password, $email, $mobile)) { if ($this->auth->register($username, $password, $email, $mobile)) {
$synchtml = ''; $synchtml = '';
@ -118,7 +118,7 @@ class User extends Frontend
} }
$this->success(__('Sign up successful') . $synchtml, $url ? $url : url('user/index')); $this->success(__('Sign up successful') . $synchtml, $url ? $url : url('user/index'));
} else { } else {
$this->error($this->auth->getError()); $this->error($this->auth->getError(), null, ['token' => $this->request->token()]);
} }
} }
//判断来源 //判断来源
@ -165,7 +165,7 @@ class User extends Frontend
$validate = new Validate($rule, $msg); $validate = new Validate($rule, $msg);
$result = $validate->check($data); $result = $validate->check($data);
if (!$result) { if (!$result) {
$this->error(__($validate->getError())); $this->error(__($validate->getError()), null, ['token' => $this->request->token()]);
return FALSE; return FALSE;
} }
if ($this->auth->login($account, $password)) { if ($this->auth->login($account, $password)) {
@ -177,7 +177,7 @@ class User extends Frontend
} }
$this->success(__('Logged in successful') . $synchtml, $url ? $url : url('user/index')); $this->success(__('Logged in successful') . $synchtml, $url ? $url : url('user/index'));
} else { } else {
$this->error($this->auth->getError()); $this->error($this->auth->getError(), null, ['token' => $this->request->token()]);
} }
} }
//判断来源 //判断来源
@ -249,7 +249,7 @@ class User extends Frontend
$validate = new Validate($rule, $msg, $field); $validate = new Validate($rule, $msg, $field);
$result = $validate->check($data); $result = $validate->check($data);
if (!$result) { if (!$result) {
$this->error(__($validate->getError())); $this->error(__($validate->getError()), null, ['token' => $this->request->token()]);
return FALSE; return FALSE;
} }
@ -263,7 +263,7 @@ class User extends Frontend
} }
$this->success(__('Reset password successful') . $synchtml, url('user/login')); $this->success(__('Reset password successful') . $synchtml, url('user/login'));
} else { } else {
$this->error($this->auth->getError()); $this->error($this->auth->getError(), null, ['token' => $this->request->token()]);
} }
} }
$this->view->assign('title', __('Change password')); $this->view->assign('title', __('Change password'));

View File

@ -4,6 +4,7 @@
<div class="login-main"> <div class="login-main">
<form name="form" id="login-form" class="form-vertical" method="POST" action=""> <form name="form" id="login-form" class="form-vertical" method="POST" action="">
<input type="hidden" name="url" value="{$url}" /> <input type="hidden" name="url" value="{$url}" />
{:token()}
<div class="form-group"> <div class="form-group">
<label class="control-label" for="account">{:__('Account')}</label> <label class="control-label" for="account">{:__('Account')}</label>
<div class="controls"> <div class="controls">

View File

@ -5,6 +5,7 @@
<form name="form1" id="register-form" class="form-vertical" method="POST" action=""> <form name="form1" id="register-form" class="form-vertical" method="POST" action="">
<input type="hidden" name="invite_user_id" value="0" /> <input type="hidden" name="invite_user_id" value="0" />
<input type="hidden" name="url" value="{$url}" /> <input type="hidden" name="url" value="{$url}" />
{:token()}
<div class="form-group"> <div class="form-group">
<label class="control-label required">{:__('Email')}<span class="text-success"></span></label> <label class="control-label required">{:__('Email')}<span class="text-success"></span></label>
<div class="controls"> <div class="controls">

View File

@ -22,7 +22,7 @@
"topthink/think-captcha": "^1.0", "topthink/think-captcha": "^1.0",
"mtdowling/cron-expression": "^1.2", "mtdowling/cron-expression": "^1.2",
"phpmailer/phpmailer": "^5.2", "phpmailer/phpmailer": "^5.2",
"karsonzhang/fastadmin-addons": "~1.1.0", "karsonzhang/fastadmin-addons": "~1.1.4",
"overtrue/pinyin": "~3.0", "overtrue/pinyin": "~3.0",
"phpoffice/phpexcel": "^1.8" "phpoffice/phpexcel": "^1.8"
}, },

View File

@ -356,7 +356,7 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"><strong>参数</strong></div> <div class="panel-heading"><strong>参数</strong></div>
<div class="panel-body"> <div class="panel-body">
<form enctype="application/x-www-form-urlencoded" role="form" action="/api/demo/test1" method="get" name="form2" id="form2"> <form enctype="application/x-www-form-urlencoded" role="form" action="/api/demo/test1" method="GET" name="form2" id="form2">
<div class="form-group"> <div class="form-group">
</div> </div>
@ -3359,7 +3359,7 @@
<div class="row mt0 footer"> <div class="row mt0 footer">
<div class="col-md-6" align="left"> <div class="col-md-6" align="left">
Generated on 2018-04-06 19:15:01 </div> Generated on 2018-05-04 11:06:48 </div>
<div class="col-md-6" align="right"> <div class="col-md-6" align="right">
<a href="https://www.fastadmin.net" target="_blank">FastAdmin</a> <a href="https://www.fastadmin.net" target="_blank">FastAdmin</a>
</div> </div>
@ -3531,8 +3531,8 @@
$.ajax({ $.ajax({
url: $('#apiUrl').val() + url, url: $('#apiUrl').val() + url,
data: $(form).attr('method') == 'get' ? $(form).serialize() : formData, data: $(form).prop('method').toLowerCase() == 'get' ? $(form).serialize() : formData,
type: $(form).attr('method') + '', type: $(form).prop('method') + '',
dataType: 'json', dataType: 'json',
contentType: false, contentType: false,
processData: false, processData: false,

View File

@ -559,6 +559,9 @@ form.form-horizontal .control-label {
.bootstrap-table td.bs-checkbox { .bootstrap-table td.bs-checkbox {
vertical-align: middle; vertical-align: middle;
} }
.fixed-table-container thead th .sortable {
padding-right: 0;
}
.dropdown-submenu { .dropdown-submenu {
position: relative; position: relative;
} }

File diff suppressed because one or more lines are too long

View File

@ -103,20 +103,8 @@ define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
}, },
refreshmenu: function () { refreshmenu: function () {
top.window.$(".sidebar-menu").trigger("refresh"); top.window.$(".sidebar-menu").trigger("refresh");
} },
}, gettablecolumnbutton: function(options){
init: function () {
//公共代码
//添加ios-fix兼容iOS下的iframe
if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) {
$("html").addClass("ios-fix");
}
//配置Toastr的参数
Toastr.options.positionClass = Config.controllername === 'index' ? "toast-top-right-index" : "toast-top-right";
//点击包含.btn-dialog的元素时弹出dialog
$(document).on('click', '.btn-dialog,.dialogit', function (e) {
var that = this;
var options = $.extend({}, $(that).data() || {});
if (typeof options.tableId !== 'undefined' && typeof options.fieldIndex !== 'undefined' && typeof options.buttonIndex !== 'undefined') { if (typeof options.tableId !== 'undefined' && typeof options.fieldIndex !== 'undefined' && typeof options.buttonIndex !== 'undefined') {
var tableOptions = $("#" + options.tableId).bootstrapTable('getOptions'); var tableOptions = $("#" + options.tableId).bootstrapTable('getOptions');
if (tableOptions) { if (tableOptions) {
@ -133,20 +121,38 @@ define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
} }
}); });
if (columnObj) { if (columnObj) {
var button = columnObj['buttons'][options.buttonIndex]; return columnObj['buttons'][options.buttonIndex];
if (button && typeof button.callback === 'function') {
options.callback = button.callback;
}
} }
} }
} }
return null;
},
},
init: function () {
//公共代码
//添加ios-fix兼容iOS下的iframe
if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) {
$("html").addClass("ios-fix");
}
//配置Toastr的参数
Toastr.options.positionClass = Config.controllername === 'index' ? "toast-top-right-index" : "toast-top-right";
//点击包含.btn-dialog的元素时弹出dialog
$(document).on('click', '.btn-dialog,.dialogit', function (e) {
var that = this;
var options = $.extend({}, $(that).data() || {});
var url = Backend.api.replaceids(that, $(that).attr('href'));
var title = $(that).attr("title") || $(that).data("title") || $(that).data('original-title');
var button = Backend.api.gettablecolumnbutton(options);
if (button && typeof button.callback === 'function') {
options.callback = button.callback;
}
if (typeof options.confirm !== 'undefined') { if (typeof options.confirm !== 'undefined') {
Layer.confirm(options.confirm, function (index) { Layer.confirm(options.confirm, function (index) {
Backend.api.open(Backend.api.replaceids(that, $(that).attr('href')), $(that).attr('title'), options); Backend.api.open(url, title, options);
Layer.close(index); Layer.close(index);
}); });
} else { } else {
Backend.api.open(Backend.api.replaceids(that, $(that).attr('href')), $(that).attr('title'), options); Backend.api.open(url, title, options);
} }
return false; return false;
}); });
@ -154,15 +160,16 @@ define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
$(document).on('click', '.btn-addtabs,.addtabsit', function (e) { $(document).on('click', '.btn-addtabs,.addtabsit', function (e) {
var that = this; var that = this;
var options = $.extend({}, $(that).data() || {}); var options = $.extend({}, $(that).data() || {});
var url = Backend.api.replaceids(that, $(that).attr('href'));
var title = $(that).attr("title") || $(that).data("title") || $(that).data('original-title');
if (typeof options.confirm !== 'undefined') { if (typeof options.confirm !== 'undefined') {
Layer.confirm(options.confirm, function (index) { Layer.confirm(options.confirm, function (index) {
Backend.api.addtabs(Backend.api.replaceids(that, $(that).attr('href')), $(that).attr("title")); Backend.api.addtabs(url, title);
Layer.close(index); Layer.close(index);
}); });
} else { } else {
Backend.api.addtabs(Backend.api.replaceids(that, $(that).attr('href')), $(that).attr("title")); Backend.api.addtabs(url, title);
} }
return false; return false;
}); });
//点击包含.btn-ajax的元素时发送Ajax请求 //点击包含.btn-ajax的元素时发送Ajax请求
@ -177,30 +184,13 @@ define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
var error = typeof options.error === 'function' ? options.error : null; var error = typeof options.error === 'function' ? options.error : null;
delete options.success; delete options.success;
delete options.error; delete options.error;
if (typeof options.tableId !== 'undefined' && typeof options.fieldIndex !== 'undefined' && typeof options.buttonIndex !== 'undefined') { var button = Backend.api.gettablecolumnbutton(options);
var tableOptions = $("#" + options.tableId).bootstrapTable('getOptions'); if (button) {
if (tableOptions) { if (typeof button.success === 'function') {
var columnObj = null; success = button.success;
$.each(tableOptions.columns, function (i, columns) { }
$.each(columns, function (j, column) { if (typeof button.error === 'function') {
if (typeof column.fieldIndex !== 'undefined' && column.fieldIndex === options.fieldIndex) { error = button.error;
columnObj = column;
return false;
}
});
if (columnObj) {
return false;
}
});
if (columnObj) {
var button = columnObj['buttons'][options.buttonIndex];
if (button && typeof button.success === 'function') {
success = button.success;
}
if (button && typeof button.error === 'function') {
error = button.error;
}
}
} }
} }
//如果未设备成功的回调,设定了自动刷新的情况下自动进行刷新 //如果未设备成功的回调,设定了自动刷新的情况下自动进行刷新
@ -225,6 +215,19 @@ define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
if ($(".layer-footer").size() > 0 && self === top) { if ($(".layer-footer").size() > 0 && self === top) {
$(".layer-footer").show(); $(".layer-footer").show();
} }
//优化在多个弹窗下点击不能切换的操作体验
if (Fast.api.query("dialog") == "1" && self != top && self.frameElement && self.frameElement.tagName == "IFRAME") {
$(window).on('click', function () {
var layero = self.frameElement.parentNode.parentElement;
if (parent.Layer.zIndex != parseInt(parent.window.$(layero).css("z-index"))) {
parent.window.$(layero).trigger("mousedown");
parent.Layer.zIndex = parseInt(parent.window.$(layero).css("z-index"));
}
});
}
//tooltip和popover
$('body').tooltip({selector: '[data-toggle="tooltip"]'});
$('body').tooltip({selector: '[data-toggle="popover"]'});
} }
}; };
Backend.api = $.extend(Fast.api, Backend.api); Backend.api = $.extend(Fast.api, Backend.api);

View File

@ -49,13 +49,78 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
url: $.fn.bootstrapTable.defaults.extend.index_url, url: $.fn.bootstrapTable.defaults.extend.index_url,
columns: [ columns: [
[ [
{field: 'id', title: 'ID', operate: false}, {field: 'id', title: 'ID', operate: false, visible: false},
{field: 'name', title: __('Name'), operate: false}, {
{field: 'title', title: __('Title'), operate: 'LIKE'} field: 'home',
title: __('Index'),
width: '50px',
formatter: Controller.api.formatter.home
},
{field: 'name', title: __('Name'), operate: false, visible: false, width: '120px'},
{
field: 'title',
title: __('Title'),
operate: 'LIKE',
align: 'left',
formatter: Controller.api.formatter.title
},
{field: 'intro', title: __('Intro'), operate: 'LIKE', align: 'left', class:'visible-lg'},
{
field: 'author',
title: __('Author'),
operate: 'LIKE',
width: '100px',
formatter: Controller.api.formatter.author
},
{
field: 'price',
title: __('Price'),
operate: 'LIKE',
width: '100px',
align: 'center',
formatter: Controller.api.formatter.price
},
{
field: 'downloads',
title: __('Downloads'),
operate: 'LIKE',
width: '100px',
align: 'center',
formatter: Controller.api.formatter.downloads
},
{
field: 'version',
title: __('Version'),
operate: 'LIKE',
width: '100px',
align: 'center',
formatter: Controller.api.formatter.version
},
{
field: 'toggle',
title: __('Status'),
width: '100px',
formatter: Controller.api.formatter.toggle
},
{
field: 'id',
title: __('Operate'),
align: 'center',
table: table,
formatter: Controller.api.formatter.operate,
align: 'right'
},
] ]
], ],
responseHandler: function (res) {
$.each(res.rows, function (i, j) {
j.addon = typeof Config.addons[j.name] != 'undefined' ? Config.addons[j.name] : null;
});
return res;
},
dataType: 'jsonp', dataType: 'jsonp',
templateView: true, templateView: false,
clickToSelect: false,
search: true, search: true,
showColumns: false, showColumns: false,
showToggle: false, showToggle: false,
@ -71,41 +136,6 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
// 为表格绑定事件 // 为表格绑定事件
Table.api.bindevent(table); Table.api.bindevent(table);
table.on('click', '.btn-addoninfo', function (event) {
var index = parseInt($(this).data("index"));
var data = table.bootstrapTable("getData");
var item = data[index];
var addon = typeof Config.addons[item.name] != 'undefined' ? Config.addons[item.name] : null;
Layer.alert(Template("addoninfotpl", {item: item, addon: addon}), {
btn: [__('OK'), __('Donate'), __('Feedback'), __('Document')],
title: __('Detail'),
area: ['450px', '490px'],
btn2: function () {
//打赏
Layer.open({
content: Template("paytpl", {payimg: item.donateimage}),
shade: 0.8,
area: ['800px', '600px'],
skin: 'layui-layer-msg layui-layer-pay',
title: false,
closeBtn: true,
btn: false,
resize: false,
});
},
btn3: function () {
return false;
},
btn4: function () {
return false;
},
success: function (layero, index) {
$(".layui-layer-btn2", layero).attr("href", "http://forum.fastadmin.net/t/bug?ref=addon&name=" + item.name).attr("target", "_blank");
$(".layui-layer-btn3", layero).attr("href", "http://www.fastadmin.net/store/" + item.name + ".html?ref=addon").attr("target", "_blank");
}
});
});
// 离线安装 // 离线安装
require(['upload'], function (Upload) { require(['upload'], function (Upload) {
Upload.api.plupload("#plupload-addon", function (data, ret) { Upload.api.plupload("#plupload-addon", function (data, ret) {
@ -224,22 +254,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
Layer.closeAll(); Layer.closeAll();
Config['addons'][data.addon.name] = ret.data.addon; Config['addons'][data.addon.name] = ret.data.addon;
Layer.alert(__('Online installed tips'), { Layer.alert(__('Online installed tips'), {
btn: [__('OK'), __('Donate')], btn: [__('OK')],
title: __('Warning'), title: __('Warning'),
icon: 1, icon: 1
btn2: function () {
//打赏
Layer.open({
content: Template("paytpl", {payimg: $(that).data("donateimage")}),
shade: 0.8,
area: ['800px', '600px'],
skin: 'layui-layer-msg layui-layer-pay',
title: false,
closeBtn: true,
btn: false,
resize: false,
});
}
}); });
$('.btn-refresh').trigger('click'); $('.btn-refresh').trigger('click');
Fast.api.refreshmenu(); Fast.api.refreshmenu();
@ -261,17 +278,12 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
} }
}); });
} else if (ret && ret.code === -2) { } else if (ret && ret.code === -2) {
//跳转支付 Fast.api.open(ret.data.payurl, __('Pay now'), {
Layer.alert(__('Pay click tips'), { area: ["650px", "700px"],
btn: [__('Pay now'), __('Cancel')], end: function () {
icon: 0, Layer.alert(__('Pay tips'));
success: function (layero) {
$(".layui-layer-btn0", layero).attr("href", ret.data.payurl).attr("target", "_blank");
} }
}, function () {
Layer.alert(__('Pay new window tips'), {icon: 0});
}); });
} else if (ret && ret.code === -3) { } else if (ret && ret.code === -3) {
//插件目录发现影响全局的文件 //插件目录发现影响全局的文件
Layer.open({ Layer.open({
@ -408,7 +420,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
// 点击卸载 // 点击卸载
$(document).on("click", ".btn-uninstall", function () { $(document).on("click", ".btn-uninstall", function () {
var name = $(this).closest(".operate").data("name"); var name = $(this).closest(".operate").data('name');
if (Config['addons'][name].state == 1) {
Layer.alert(__('Please disable addon first'), {icon: 7});
return false;
}
Layer.confirm(__('Uninstall tips'), function () { Layer.confirm(__('Uninstall tips'), function () {
uninstall(name, false); uninstall(name, false);
}); });
@ -422,18 +438,18 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
// 点击启用/禁用 // 点击启用/禁用
$(document).on("click", ".btn-enable,.btn-disable", function () { $(document).on("click", ".btn-enable,.btn-disable", function () {
var name = $(this).closest(".operate").data("name"); var name = $(this).data("name");
var action = $(this).data("action"); var action = $(this).data("action");
operate(name, action, false); operate(name, action, false);
}); });
// 点击升级 // 点击升级
$(document).on("click", ".btn-upgrade", function () { $(document).on("click", ".btn-upgrade", function () {
if ($(this).closest(".operate").find("a.btn-disable").size() > 0) { var name = $(this).closest(".operate").data('name');
if (Config['addons'][name].state == 1) {
Layer.alert(__('Please disable addon first'), {icon: 7}); Layer.alert(__('Please disable addon first'), {icon: 7});
return false; return false;
} }
var name = $(this).closest(".operate").data("name");
var version = $(this).data("version"); var version = $(this).data("version");
Layer.confirm(__('Upgrade tips'), function () { Layer.confirm(__('Upgrade tips'), function () {
@ -444,6 +460,21 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
$(document).on("click", ".operate .btn-group .dropdown-toggle", function () { $(document).on("click", ".operate .btn-group .dropdown-toggle", function () {
$(this).closest(".btn-group").toggleClass("dropup", $(document).height() - $(this).offset().top <= 200); $(this).closest(".btn-group").toggleClass("dropup", $(document).height() - $(this).offset().top <= 200);
}); });
$(document).on("click", ".view-screenshots", function () {
var row = Table.api.getrowbyindex(table, parseInt($(this).data("index")));
var data = [];
$.each(row.screenshots, function (i, j) {
data.push({
"src": "http://www.fh.com" + j
});
});
var json = {
"title": row.title,
"data": data
};
top.Layer.photos(top.JSON.parse(JSON.stringify({photos: json})));
});
}, },
add: function () { add: function () {
Controller.api.bindevent(); Controller.api.bindevent();
@ -452,6 +483,39 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
Controller.api.bindevent(); Controller.api.bindevent();
}, },
api: { api: {
formatter: {
title: function (value, row, index) {
var title = '<a class="title" href="' + row.url + '" data-toggle="tooltip" title="' + __('View addon home page') + '" target="_blank">' + value + '</a>';
if (row.screenshots.length > 0) {
title += ' <a href="javascript:;" data-index="' + index + '" class="view-screenshots text-success" title="' + __('View addon screenshots') + '" data-toggle="tooltip"><i class="fa fa-image"></i></a>';
}
return title;
},
operate: function (value, row, index) {
return Template("operatetpl", {item: row, index: index});
},
toggle: function (value, row, index) {
if (!row.addon) {
return '';
}
return '<a href="javascript:;" data-toggle="tooltip" title="' + __('Click to toggle status') + '" class="btn-' + (row.addon.state == 1 ? "disable" : "enable") + '" data-action="' + (row.addon.state == 1 ? "disable" : "enable") + '" data-name="' + row.name + '"><i class="fa ' + (row.addon.state == 0 ? 'fa-toggle-on fa-rotate-180 text-gray' : 'fa-toggle-on text-success') + ' fa-2x"></i></a>';
},
author: function (value, row, index) {
return '<a href="https://wpa.qq.com/msgrd?v=3&uin=' + row.qq + '&site=fastadmin.net&menu=yes" target="_blank" data-toggle="tooltip" title="'+__('Click to contact developer')+'" class="text-primary">' + value + '</a>';
},
price: function (value, row, index) {
return parseFloat(value) == 0 ? '<span class="text-success">' + __('Free') + '</span>' : '<span class="text-danger">¥' + value + '</span>';
},
downloads: function (value, row, index) {
return value;
},
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;
},
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>';
},
},
bindevent: function () { bindevent: function () {
Form.api.bindevent($("form[role=form]")); Form.api.bindevent($("form[role=form]"));
}, },

View File

@ -15,6 +15,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
var table = $("#table"); var table = $("#table");
//在表格内容渲染完成后回调的事件
table.on('post-body.bs.table', function (e, json) {
$("tbody tr[data-index]", this).each(function () {
if (parseInt($("td:eq(1)", this).text()) == Config.admin.id) {
$("input[type=checkbox]", this).prop("disabled", true);
}
});
});
// 初始化表格 // 初始化表格
table.bootstrapTable({ table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url, url: $.fn.bootstrapTable.defaults.extend.index_url,
@ -27,7 +36,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
{field: 'groups_text', title: __('Group'), operate:false, formatter: Table.api.formatter.label}, {field: 'groups_text', title: __('Group'), operate:false, formatter: Table.api.formatter.label},
{field: 'email', title: __('Email')}, {field: 'email', title: __('Email')},
{field: 'status', title: __("Status"), formatter: Table.api.formatter.status}, {field: 'status', title: __("Status"), formatter: Table.api.formatter.status},
{field: 'logintime', title: __('Login time'), formatter: Table.api.formatter.datetime}, {field: 'logintime', title: __('Login time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: function (value, row, index) { {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: function (value, row, index) {
if(row.id == Config.admin.id){ if(row.id == Config.admin.id){
return ''; return '';

View File

@ -27,7 +27,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
{field: 'url', title: __('Url'), align: 'left', formatter: Table.api.formatter.url}, {field: 'url', title: __('Url'), align: 'left', formatter: Table.api.formatter.url},
{field: 'ip', title: __('IP'), events: Table.api.events.ip, formatter: Table.api.formatter.search}, {field: 'ip', title: __('IP'), events: Table.api.events.ip, formatter: Table.api.formatter.search},
{field: 'browser', title: __('Browser'), operate: false, formatter: Controller.api.formatter.browser}, {field: 'browser', title: __('Browser'), operate: false, formatter: Controller.api.formatter.browser},
{field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'BETWEEN', type: 'datetime', addclass: 'datetimepicker', data: 'data-date-format="YYYY-MM-DD HH:mm:ss"'}, {field: 'createtime', title: __('Create time'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'operate', title: __('Operate'), table: table, {field: 'operate', title: __('Operate'), table: table,
events: Table.api.events.operate, events: Table.api.events.operate,
buttons: [{ buttons: [{

View File

@ -30,6 +30,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'jstree'], function (
var table = $("#table"); var table = $("#table");
//在表格内容渲染完成后回调的事件
table.on('post-body.bs.table', function (e, json) {
$("tbody tr[data-index]", this).each(function () {
if (Config.admin.group_ids.indexOf(parseInt(parseInt($("td:eq(1)", this).text()))) > -1) {
$("input[type=checkbox]", this).prop("disabled", true);
}
});
});
// 初始化表格 // 初始化表格
table.bootstrapTable({ table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url, url: $.fn.bootstrapTable.defaults.extend.index_url,

View File

@ -23,16 +23,32 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
escape: false, escape: false,
columns: [ columns: [
[ [
{field: 'state', checkbox: true, }, {field: 'state', checkbox: true,},
{field: 'id', title: 'ID'}, {field: 'id', title: 'ID'},
{field: 'title', title: __('Title'), align: 'left', formatter: Controller.api.formatter.title}, {field: 'title', title: __('Title'), align: 'left', formatter: Controller.api.formatter.title},
{field: 'icon', title: __('Icon'), formatter: Controller.api.formatter.icon}, {field: 'icon', title: __('Icon'), formatter: Controller.api.formatter.icon},
{field: 'name', title: __('Name'), align: 'left', formatter: Controller.api.formatter.name}, {field: 'name', title: __('Name'), align: 'left', formatter: Controller.api.formatter.name},
{field: 'weigh', title: __('Weigh')}, {field: 'weigh', title: __('Weigh')},
{field: 'status', title: __('Status'), formatter: Table.api.formatter.status}, {field: 'status', title: __('Status'), formatter: Table.api.formatter.status},
{field: 'ismenu', title: __('Ismenu'), align: 'center', formatter: Controller.api.formatter.menu}, {
{field: 'id', title: '<a href="javascript:;" class="btn btn-success btn-xs btn-toggle"><i class="fa fa-chevron-up"></i></a>', operate: false, formatter: Controller.api.formatter.subnode}, field: 'ismenu',
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} title: __('Ismenu'),
align: 'center',
formatter: Controller.api.formatter.menu
},
{
field: 'id',
title: '<a href="javascript:;" class="btn btn-success btn-xs btn-toggle"><i class="fa fa-chevron-up"></i></a>',
operate: false,
formatter: Controller.api.formatter.subnode
},
{
field: 'operate',
title: __('Operate'),
table: table,
events: Table.api.events.operate,
formatter: Table.api.formatter.operate
}
] ]
], ],
pagination: false, pagination: false,
@ -102,15 +118,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
return !row.ismenu || row.status == 'hidden' ? "<span class='text-muted'>" + value + "</span>" : value; return !row.ismenu || row.status == 'hidden' ? "<span class='text-muted'>" + value + "</span>" : value;
}, },
menu: function (value, row, index) { menu: function (value, row, index) {
return "<a href='javascript:;' class='btn btn-" + (value ? "info" : "default") + " btn-xs btn-change' data-id='" return "<a href='javascript:;' data-toggle='tooltip' title='" + __('Toggle menu visible') + "' class='btn btn-" + (value ? "info" : "default") + " btn-xs btn-change' data-id='"
+ row.id + "' data-params='ismenu=" + (value ? 0 : 1) + "'>" + (value ? __('Yes') : __('No')) + "</a>"; + row.id + "' data-params='ismenu=" + (value ? 0 : 1) + "'>" + (value ? __('Yes') : __('No')) + "</a>";
}, },
icon: function (value, row, index) { icon: function (value, row, index) {
return '<span class="' + (!row.ismenu || row.status == 'hidden' ? 'text-muted' : '') + '"><i class="' + value + '"></i></span>'; return '<span class="' + (!row.ismenu || row.status == 'hidden' ? 'text-muted' : '') + '"><i class="' + value + '"></i></span>';
}, },
subnode: function (value, row, index) { subnode: function (value, row, index) {
return '<a href="javascript:;" data-id="' + row.id + '" data-pid="' + row.pid + '" class="btn btn-xs ' return '<a href="javascript:;" data-toggle="tooltip" title="' + __('Toggle sub menu') + '" data-id="' + row.id + '" data-pid="' + row.pid + '" class="btn btn-xs '
+ (row.haschild == 1 || row.ismenu == 1 ? 'btn-success' : 'btn-default disabled') + ' btn-node-sub"><i class="fa fa-sitemap"></i></a>'; + (row.haschild == 1 || row.ismenu == 1 ? 'btn-success' : 'btn-default disabled') + ' btn-node-sub"><i class="fa fa-sitemap"></i></a>';
} }
}, },
bindevent: function () { bindevent: function () {
@ -121,6 +137,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
$("input[name='row[ismenu]']:checked").trigger("click"); $("input[name='row[ismenu]']:checked").trigger("click");
var iconlist = []; var iconlist = [];
var iconfunc = function () {
Layer.open({
type: 1,
area: ['99%', '98%'], //宽高
content: Template('chooseicontpl', {iconlist: iconlist})
});
};
Form.api.bindevent($("form[role=form]"), function (data) { Form.api.bindevent($("form[role=form]"), function (data) {
Fast.api.refreshmenu(); Fast.api.refreshmenu();
}); });
@ -132,18 +155,10 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
while ((result = exp.exec(ret)) != null) { while ((result = exp.exec(ret)) != null) {
iconlist.push(result[1]); iconlist.push(result[1]);
} }
Layer.open({ iconfunc();
type: 1,
area: ['460px', '300px'], //宽高
content: Template('chooseicontpl', {iconlist: iconlist})
});
}); });
} else { } else {
Layer.open({ iconfunc();
type: 1,
area: ['460px', '300px'], //宽高
content: Template('chooseicontpl', {iconlist: iconlist})
});
} }
}); });
$(document).on('click', '#chooseicon ul li', function () { $(document).on('click', '#chooseicon ul li', function () {

View File

@ -22,18 +22,31 @@ define(['jquery', 'bootstrap', 'backend', 'form', 'table'], function ($, undefin
sortName: 'id', sortName: 'id',
columns: [ columns: [
[ [
{field: 'state', checkbox: true, }, {field: 'state', checkbox: true,},
{field: 'id', title: __('Id')}, {field: 'id', title: __('Id')},
{field: 'url', title: __('Preview'), formatter: Controller.api.formatter.thumb}, {field: 'url', title: __('Preview'), formatter: Controller.api.formatter.thumb, operate: false},
{field: 'url', title: __('Url'), formatter: Controller.api.formatter.url}, {field: 'url', title: __('Url'), formatter: Controller.api.formatter.url},
{field: 'imagewidth', title: __('Imagewidth')}, {field: 'imagewidth', title: __('Imagewidth'), sortable: true},
{field: 'imageheight', title: __('Imageheight')}, {field: 'imageheight', title: __('Imageheight'), sortable: true},
{field: 'imagetype', title: __('Imagetype')}, {field: 'imagetype', title: __('Imagetype'), formatter:Table.api.formatter.search},
{field: 'storage', title: __('Storage')}, {field: 'storage', title: __('Storage'), formatter: Table.api.formatter.search},
{field: 'filesize', title: __('Filesize')}, {field: 'filesize', title: __('Filesize'), operate: 'BETWEEN', sortable: true},
{field: 'mimetype', title: __('Mimetype')}, {field: 'mimetype', title: __('Mimetype'), formatter:Table.api.formatter.search},
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime}, {
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} field: 'createtime',
title: __('Createtime'),
formatter: Table.api.formatter.datetime,
operate: 'RANGE',
addclass: 'datetimerange',
sortable: true
},
{
field: 'operate',
title: __('Operate'),
table: table,
events: Table.api.events.operate,
formatter: Table.api.formatter.operate
}
] ]
], ],
}); });
@ -58,17 +71,20 @@ define(['jquery', 'bootstrap', 'backend', 'form', 'table'], function ($, undefin
sortName: 'id', sortName: 'id',
columns: [ columns: [
[ [
{field: 'state', checkbox: true, }, {field: 'state', checkbox: true,},
{field: 'id', title: __('Id')}, {field: 'id', title: __('Id')},
{field: 'url', title: __('Preview'), formatter: Controller.api.formatter.thumb}, {field: 'url', title: __('Preview'), formatter: Controller.api.formatter.thumb},
{field: 'imagewidth', title: __('Imagewidth')}, {field: 'imagewidth', title: __('Imagewidth')},
{field: 'imageheight', title: __('Imageheight')}, {field: 'imageheight', title: __('Imageheight')},
{field: 'mimetype', title: __('Mimetype'), operate: 'LIKE %...%', {
field: 'mimetype', title: __('Mimetype'), operate: 'LIKE %...%',
process: function (value, arg) { process: function (value, arg) {
return value.replace(/\*/g, '%'); return value.replace(/\*/g, '%');
}}, }
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime}, },
{field: 'operate', title: __('Operate'), events: { {field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{
field: 'operate', title: __('Operate'), events: {
'click .btn-chooseone': function (e, value, row, index) { 'click .btn-chooseone': function (e, value, row, index) {
var multiple = Backend.api.query('multiple'); var multiple = Backend.api.query('multiple');
multiple = multiple == 'true' ? true : false; multiple = multiple == 'true' ? true : false;
@ -76,7 +92,8 @@ define(['jquery', 'bootstrap', 'backend', 'form', 'table'], function ($, undefin
}, },
}, formatter: function () { }, formatter: function () {
return '<a href="javascript:;" class="btn btn-danger btn-chooseone btn-xs"><i class="fa fa-check"></i> ' + __('Choose') + '</a>'; return '<a href="javascript:;" class="btn btn-danger btn-chooseone btn-xs"><i class="fa fa-check"></i> ' + __('Choose') + '</a>';
}} }
}
] ]
] ]
}); });

View File

@ -29,7 +29,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
{field: 'intro', title: __('Intro')}, {field: 'intro', title: __('Intro')},
{field: 'group', title: __('Group')}, {field: 'group', title: __('Group')},
{field: 'type', title: __('Type')}, {field: 'type', title: __('Type')},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} {
field: 'operate',
title: __('Operate'),
table: table,
events: Table.api.events.operate,
formatter: Table.api.formatter.operate
}
] ]
] ]
}); });
@ -58,7 +64,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
//添加向发件人发送测试邮件按钮和方法 //添加向发件人发送测试邮件按钮和方法
$('input[name="row[mail_from]"]').parent().next().append('<a class="btn btn-info testmail">' + __('Send a test message') + '</a>'); $('input[name="row[mail_from]"]').parent().next().append('<a class="btn btn-info testmail">' + __('Send a test message') + '</a>');
$(document).on("click", ".testmail", function () { $(document).on("click", ".testmail", function () {
Backend.api.ajax({url: "general/config/emailtest", data: {receiver: $('input[name="row[mail_from]"]').val()}}); var that = this;
Layer.prompt({title: __('Please input your email'), formType: 0}, function (value, index) {
Backend.api.ajax({
url: "general/config/emailtest?receiver=" + value,
data: $(that).closest("form").serialize()
});
});
}); });
}, },
add: function () { add: function () {

View File

@ -27,8 +27,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'upload'], function (
{field: 'id', title: 'ID'}, {field: 'id', title: 'ID'},
{field: 'title', title: __('Title')}, {field: 'title', title: __('Title')},
{field: 'url', title: __('Url'), align: 'left', formatter: Table.api.formatter.url}, {field: 'url', title: __('Url'), align: 'left', formatter: Table.api.formatter.url},
{field: 'ip', title: __('ip')}, {field: 'ip', title: __('ip'), formatter:Table.api.formatter.search},
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime}, {field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
] ]
], ],
commonSearch: false commonSearch: false

View File

@ -41,8 +41,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'jstree'], function (
{checkbox: true}, {checkbox: true},
{field: 'id', title: __('Id')}, {field: 'id', title: __('Id')},
{field: 'name', title: __('Name')}, {field: 'name', title: __('Name')},
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime}, {field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'updatetime', title: __('Updatetime'), formatter: Table.api.formatter.datetime}, {field: 'updatetime', title: __('Updatetime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'status', title: __('Status'), formatter: Table.api.formatter.status}, {field: 'status', title: __('Status'), formatter: Table.api.formatter.status},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
] ]

View File

@ -31,8 +31,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
{field: 'name', title: __('Name'), align: 'left'}, {field: 'name', title: __('Name'), align: 'left'},
{field: 'remark', title: __('Remark')}, {field: 'remark', title: __('Remark')},
{field: 'ismenu', title: __('Ismenu'), formatter: Controller.api.formatter.toggle}, {field: 'ismenu', title: __('Ismenu'), formatter: Controller.api.formatter.toggle},
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, visible: false}, {field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true, visible: false},
{field: 'updatetime', title: __('Updatetime'), formatter: Table.api.formatter.datetime, visible: false}, {field: 'updatetime', title: __('Updatetime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true, visible: false},
{field: 'weigh', title: __('Weigh')}, {field: 'weigh', title: __('Weigh')},
{field: 'status', title: __('Status'), formatter: Table.api.formatter.status}, {field: 'status', title: __('Status'), formatter: Table.api.formatter.status},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}

View File

@ -105,7 +105,7 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, undefine
} }
name = name.replace(/[\[\]]/g, "\\$&"); name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url); results = regex.exec(url);
if (!results) if (!results)
return null; return null;
if (!results[2]) if (!results[2])
@ -134,31 +134,42 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, undefine
$(layero).data("callback", that.callback); $(layero).data("callback", that.callback);
//$(layero).removeClass("layui-layer-border"); //$(layero).removeClass("layui-layer-border");
Layer.setTop(layero); Layer.setTop(layero);
var frame = Layer.getChildFrame('html', index); try {
var layerfooter = frame.find(".layer-footer"); var frame = Layer.getChildFrame('html', index);
Fast.api.layerfooter(layero, index, that); var layerfooter = frame.find(".layer-footer");
Fast.api.layerfooter(layero, index, that);
//绑定事件 //绑定事件
if (layerfooter.size() > 0) { if (layerfooter.size() > 0) {
// 监听窗口内的元素及属性变化 // 监听窗口内的元素及属性变化
// Firefox和Chrome早期版本中带有前缀 // Firefox和Chrome早期版本中带有前缀
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
if (MutationObserver) { if (MutationObserver) {
// 选择目标节点 // 选择目标节点
var target = layerfooter[0]; var target = layerfooter[0];
// 创建观察者对象 // 创建观察者对象
var observer = new MutationObserver(function (mutations) { var observer = new MutationObserver(function (mutations) {
Fast.api.layerfooter(layero, index, that); Fast.api.layerfooter(layero, index, that);
mutations.forEach(function (mutation) { mutations.forEach(function (mutation) {
});
}); });
}); // 配置观察选项:
// 配置观察选项: var config = {attributes: true, childList: true, characterData: true, subtree: true}
var config = {attributes: true, childList: true, characterData: true, subtree: true} // 传入目标节点和观察选项
// 传入目标节点和观察选项 observer.observe(target, config);
observer.observe(target, config); // 随后,你还可以停止观察
// 随后,你还可以停止观察 // observer.disconnect();
// observer.disconnect(); }
} }
} catch (e) {
}
if ($(layero).height() > $(window).height()) {
//当弹出窗口大于浏览器可视高度时,重定位
Layer.style(index, {
top: 0,
height: $(window).height()
});
} }
} }
}, options ? options : {}); }, options ? options : {});
@ -234,8 +245,8 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, undefine
}, },
lang: function () { lang: function () {
var args = arguments, var args = arguments,
string = args[0], string = args[0],
i = 1; i = 1;
string = string.toLowerCase(); string = string.toLowerCase();
//string = typeof Lang[string] != 'undefined' ? Lang[string] : string; //string = typeof Lang[string] != 'undefined' ? Lang[string] : string;
if (typeof Lang[string] != 'undefined') { if (typeof Lang[string] != 'undefined') {

View File

@ -49,7 +49,9 @@ define(['fast', 'template'], function (Fast, Template) {
return false; return false;
}); });
//tooltip和popover
$('body').tooltip({selector: '[data-toggle="tooltip"]'});
$('body').tooltip({selector: '[data-toggle="popover"]'});
} }
}; };
Frontend.api = $.extend(Fast.api, Frontend.api); Frontend.api = $.extend(Fast.api, Frontend.api);

View File

@ -759,7 +759,7 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
} }
name = name.replace(/[\[\]]/g, "\\$&"); name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url); results = regex.exec(url);
if (!results) if (!results)
return null; return null;
if (!results[2]) if (!results[2])
@ -788,31 +788,42 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
$(layero).data("callback", that.callback); $(layero).data("callback", that.callback);
//$(layero).removeClass("layui-layer-border"); //$(layero).removeClass("layui-layer-border");
Layer.setTop(layero); Layer.setTop(layero);
var frame = Layer.getChildFrame('html', index); try {
var layerfooter = frame.find(".layer-footer"); var frame = Layer.getChildFrame('html', index);
Fast.api.layerfooter(layero, index, that); var layerfooter = frame.find(".layer-footer");
Fast.api.layerfooter(layero, index, that);
//绑定事件 //绑定事件
if (layerfooter.size() > 0) { if (layerfooter.size() > 0) {
// 监听窗口内的元素及属性变化 // 监听窗口内的元素及属性变化
// Firefox和Chrome早期版本中带有前缀 // Firefox和Chrome早期版本中带有前缀
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
if (MutationObserver) { if (MutationObserver) {
// 选择目标节点 // 选择目标节点
var target = layerfooter[0]; var target = layerfooter[0];
// 创建观察者对象 // 创建观察者对象
var observer = new MutationObserver(function (mutations) { var observer = new MutationObserver(function (mutations) {
Fast.api.layerfooter(layero, index, that); Fast.api.layerfooter(layero, index, that);
mutations.forEach(function (mutation) { mutations.forEach(function (mutation) {
});
}); });
}); // 配置观察选项:
// 配置观察选项: var config = {attributes: true, childList: true, characterData: true, subtree: true}
var config = {attributes: true, childList: true, characterData: true, subtree: true} // 传入目标节点和观察选项
// 传入目标节点和观察选项 observer.observe(target, config);
observer.observe(target, config); // 随后,你还可以停止观察
// 随后,你还可以停止观察 // observer.disconnect();
// observer.disconnect(); }
} }
} catch (e) {
}
if ($(layero).height() > $(window).height()) {
//当弹出窗口大于浏览器可视高度时,重定位
Layer.style(index, {
top: 0,
height: $(window).height()
});
} }
} }
}, options ? options : {}); }, options ? options : {});
@ -888,8 +899,8 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
}, },
lang: function () { lang: function () {
var args = arguments, var args = arguments,
string = args[0], string = args[0],
i = 1; i = 1;
string = string.toLowerCase(); string = string.toLowerCase();
//string = typeof Lang[string] != 'undefined' ? Lang[string] : string; //string = typeof Lang[string] != 'undefined' ? Lang[string] : string;
if (typeof Lang[string] != 'undefined') { if (typeof Lang[string] != 'undefined') {
@ -5318,20 +5329,8 @@ define('backend',['fast', 'template', 'moment'], function (Fast, Template, Momen
}, },
refreshmenu: function () { refreshmenu: function () {
top.window.$(".sidebar-menu").trigger("refresh"); top.window.$(".sidebar-menu").trigger("refresh");
} },
}, gettablecolumnbutton: function(options){
init: function () {
//公共代码
//添加ios-fix兼容iOS下的iframe
if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) {
$("html").addClass("ios-fix");
}
//配置Toastr的参数
Toastr.options.positionClass = Config.controllername === 'index' ? "toast-top-right-index" : "toast-top-right";
//点击包含.btn-dialog的元素时弹出dialog
$(document).on('click', '.btn-dialog,.dialogit', function (e) {
var that = this;
var options = $.extend({}, $(that).data() || {});
if (typeof options.tableId !== 'undefined' && typeof options.fieldIndex !== 'undefined' && typeof options.buttonIndex !== 'undefined') { if (typeof options.tableId !== 'undefined' && typeof options.fieldIndex !== 'undefined' && typeof options.buttonIndex !== 'undefined') {
var tableOptions = $("#" + options.tableId).bootstrapTable('getOptions'); var tableOptions = $("#" + options.tableId).bootstrapTable('getOptions');
if (tableOptions) { if (tableOptions) {
@ -5348,20 +5347,38 @@ define('backend',['fast', 'template', 'moment'], function (Fast, Template, Momen
} }
}); });
if (columnObj) { if (columnObj) {
var button = columnObj['buttons'][options.buttonIndex]; return columnObj['buttons'][options.buttonIndex];
if (button && typeof button.callback === 'function') {
options.callback = button.callback;
}
} }
} }
} }
return null;
},
},
init: function () {
//公共代码
//添加ios-fix兼容iOS下的iframe
if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) {
$("html").addClass("ios-fix");
}
//配置Toastr的参数
Toastr.options.positionClass = Config.controllername === 'index' ? "toast-top-right-index" : "toast-top-right";
//点击包含.btn-dialog的元素时弹出dialog
$(document).on('click', '.btn-dialog,.dialogit', function (e) {
var that = this;
var options = $.extend({}, $(that).data() || {});
var url = Backend.api.replaceids(that, $(that).attr('href'));
var title = $(that).attr("title") || $(that).data("title") || $(that).data('original-title');
var button = Backend.api.gettablecolumnbutton(options);
if (button && typeof button.callback === 'function') {
options.callback = button.callback;
}
if (typeof options.confirm !== 'undefined') { if (typeof options.confirm !== 'undefined') {
Layer.confirm(options.confirm, function (index) { Layer.confirm(options.confirm, function (index) {
Backend.api.open(Backend.api.replaceids(that, $(that).attr('href')), $(that).attr('title'), options); Backend.api.open(url, title, options);
Layer.close(index); Layer.close(index);
}); });
} else { } else {
Backend.api.open(Backend.api.replaceids(that, $(that).attr('href')), $(that).attr('title'), options); Backend.api.open(url, title, options);
} }
return false; return false;
}); });
@ -5369,15 +5386,16 @@ define('backend',['fast', 'template', 'moment'], function (Fast, Template, Momen
$(document).on('click', '.btn-addtabs,.addtabsit', function (e) { $(document).on('click', '.btn-addtabs,.addtabsit', function (e) {
var that = this; var that = this;
var options = $.extend({}, $(that).data() || {}); var options = $.extend({}, $(that).data() || {});
var url = Backend.api.replaceids(that, $(that).attr('href'));
var title = $(that).attr("title") || $(that).data("title") || $(that).data('original-title');
if (typeof options.confirm !== 'undefined') { if (typeof options.confirm !== 'undefined') {
Layer.confirm(options.confirm, function (index) { Layer.confirm(options.confirm, function (index) {
Backend.api.addtabs(Backend.api.replaceids(that, $(that).attr('href')), $(that).attr("title")); Backend.api.addtabs(url, title);
Layer.close(index); Layer.close(index);
}); });
} else { } else {
Backend.api.addtabs(Backend.api.replaceids(that, $(that).attr('href')), $(that).attr("title")); Backend.api.addtabs(url, title);
} }
return false; return false;
}); });
//点击包含.btn-ajax的元素时发送Ajax请求 //点击包含.btn-ajax的元素时发送Ajax请求
@ -5392,30 +5410,13 @@ define('backend',['fast', 'template', 'moment'], function (Fast, Template, Momen
var error = typeof options.error === 'function' ? options.error : null; var error = typeof options.error === 'function' ? options.error : null;
delete options.success; delete options.success;
delete options.error; delete options.error;
if (typeof options.tableId !== 'undefined' && typeof options.fieldIndex !== 'undefined' && typeof options.buttonIndex !== 'undefined') { var button = Backend.api.gettablecolumnbutton(options);
var tableOptions = $("#" + options.tableId).bootstrapTable('getOptions'); if (button) {
if (tableOptions) { if (typeof button.success === 'function') {
var columnObj = null; success = button.success;
$.each(tableOptions.columns, function (i, columns) { }
$.each(columns, function (j, column) { if (typeof button.error === 'function') {
if (typeof column.fieldIndex !== 'undefined' && column.fieldIndex === options.fieldIndex) { error = button.error;
columnObj = column;
return false;
}
});
if (columnObj) {
return false;
}
});
if (columnObj) {
var button = columnObj['buttons'][options.buttonIndex];
if (button && typeof button.success === 'function') {
success = button.success;
}
if (button && typeof button.error === 'function') {
error = button.error;
}
}
} }
} }
//如果未设备成功的回调,设定了自动刷新的情况下自动进行刷新 //如果未设备成功的回调,设定了自动刷新的情况下自动进行刷新
@ -5440,6 +5441,19 @@ define('backend',['fast', 'template', 'moment'], function (Fast, Template, Momen
if ($(".layer-footer").size() > 0 && self === top) { if ($(".layer-footer").size() > 0 && self === top) {
$(".layer-footer").show(); $(".layer-footer").show();
} }
//优化在多个弹窗下点击不能切换的操作体验
if (Fast.api.query("dialog") == "1" && self != top && self.frameElement && self.frameElement.tagName == "IFRAME") {
$(window).on('click', function () {
var layero = self.frameElement.parentNode.parentElement;
if (parent.Layer.zIndex != parseInt(parent.window.$(layero).css("z-index"))) {
parent.window.$(layero).trigger("mousedown");
parent.Layer.zIndex = parseInt(parent.window.$(layero).css("z-index"));
}
});
}
//tooltip和popover
$('body').tooltip({selector: '[data-toggle="tooltip"]'});
$('body').tooltip({selector: '[data-toggle="popover"]'});
} }
}; };
Backend.api = $.extend(Fast.api, Backend.api); Backend.api = $.extend(Fast.api, Backend.api);
@ -8434,10 +8448,10 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
}, },
valid: function (ret) { valid: function (ret) {
var that = this, submitBtn = $(".layer-footer [type=submit]", form); var that = this, submitBtn = $(".layer-footer [type=submit]", form);
that.holdSubmit(); that.holdSubmit(true);
$(".layer-footer [type=submit]", form).addClass("disabled"); submitBtn.addClass("disabled");
//验证通过提交表单 //验证通过提交表单
Form.api.submit($(ret), function (data, ret) { var submitResult = Form.api.submit($(ret), function (data, ret) {
that.holdSubmit(false); that.holdSubmit(false);
submitBtn.removeClass("disabled"); submitBtn.removeClass("disabled");
if (false === $(this).triggerHandler("success.form", [data, ret])) { if (false === $(this).triggerHandler("success.form", [data, ret])) {
@ -8467,6 +8481,11 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
} }
} }
}, submit); }, submit);
//如果提交失败则释放锁定
if (!submitResult) {
that.holdSubmit(false);
submitBtn.removeClass("disabled");
}
return false; return false;
} }
}, form.data("validator-options") || {})); }, form.data("validator-options") || {}));
@ -8650,7 +8669,6 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
var textarea = $("textarea[name='" + name + "']", form); var textarea = $("textarea[name='" + name + "']", form);
var container = textarea.closest("dl"); var container = textarea.closest("dl");
var template = container.data("template"); var template = container.data("template");
console.log(name, container);
$.each($("input,select", container).serializeArray(), function (i, j) { $.each($("input,select", container).serializeArray(), function (i, j) {
var reg = /\[(\w+)\]\[(\w+)\]$/g; var reg = /\[(\w+)\]\[(\w+)\]$/g;
var match = reg.exec(j.name); var match = reg.exec(j.name);
@ -8739,10 +8757,12 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
}, },
api: { api: {
submit: function (form, success, error, submit) { submit: function (form, success, error, submit) {
if (form.size() === 0) if (form.size() === 0) {
return Toastr.error("表单未初始化完成,无法提交"); Toastr.error("表单未初始化完成,无法提交");
return false;
}
if (typeof submit === 'function') { if (typeof submit === 'function') {
if (false === submit.call(form)) { if (false === submit.call(form, success, error)) {
return false; return false;
} }
} }
@ -8802,7 +8822,7 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
} }
} }
}); });
return false; return true;
}, },
bindevent: function (form, success, error, submit) { bindevent: function (form, success, error, submit) {
@ -9326,6 +9346,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
pageList: [10, 25, 50, 'All'], pageList: [10, 25, 50, 'All'],
pagination: true, pagination: true,
clickToSelect: true, //是否启用点击选中 clickToSelect: true, //是否启用点击选中
dblClickToEdit: true, //是否启用双击编辑
singleSelect: false, //是否启用单选 singleSelect: false, //是否启用单选
showRefresh: false, showRefresh: false,
locale: 'zh-CN', locale: 'zh-CN',
@ -9420,10 +9441,12 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
table.on('refresh.bs.table', function (e, settings, data) { table.on('refresh.bs.table', function (e, settings, data) {
$(Table.config.refreshbtn, toolbar).find(".fa").addClass("fa-spin"); $(Table.config.refreshbtn, toolbar).find(".fa").addClass("fa-spin");
}); });
//当双击单元格时 if (options.dblClickToEdit) {
table.on('dbl-click-row.bs.table', function (e, row, element, field) { //当双击单元格时
$(Table.config.editonebtn, element).trigger("click"); table.on('dbl-click-row.bs.table', function (e, row, element, field) {
}); $(Table.config.editonebtn, element).trigger("click");
});
}
//当内容渲染完成后 //当内容渲染完成后
table.on('post-body.bs.table', function (e, settings, json, xhr) { table.on('post-body.bs.table', function (e, settings, json, xhr) {
$(Table.config.refreshbtn, toolbar).find(".fa").removeClass("fa-spin"); $(Table.config.refreshbtn, toolbar).find(".fa").removeClass("fa-spin");
@ -9706,7 +9729,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
return '<div class="input-group input-group-sm" style="width:250px;margin:0 auto;"><input type="text" class="form-control input-sm" value="' + value + '"><span class="input-group-btn input-group-sm"><a href="' + value + '" target="_blank" class="btn btn-default btn-sm"><i class="fa fa-link"></i></a></span></div>'; return '<div class="input-group input-group-sm" style="width:250px;margin:0 auto;"><input type="text" class="form-control input-sm" value="' + value + '"><span class="input-group-btn input-group-sm"><a href="' + value + '" target="_blank" class="btn btn-default btn-sm"><i class="fa fa-link"></i></a></span></div>';
}, },
search: function (value, row, index) { search: function (value, row, index) {
return '<a href="javascript:;" class="searchit" data-field="' + this.field + '" data-value="' + value + '">' + value + '</a>'; return '<a href="javascript:;" class="searchit" data-toggle="tooltip" title="' + __('Click to search %s', value) + '" data-field="' + this.field + '" data-value="' + value + '">' + value + '</a>';
}, },
addtabs: function (value, row, index) { addtabs: function (value, row, index) {
var url = Table.api.replaceurl(this.url, row, this.table); var url = Table.api.replaceurl(this.url, row, this.table);
@ -9759,6 +9782,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
name: 'dragsort', name: 'dragsort',
icon: 'fa fa-arrows', icon: 'fa fa-arrows',
title: __('Drag to sort'), title: __('Drag to sort'),
extend: 'data-toggle="tooltip"',
classname: 'btn btn-xs btn-primary btn-dragsort' classname: 'btn btn-xs btn-primary btn-dragsort'
}); });
} }
@ -9767,6 +9791,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
name: 'edit', name: 'edit',
icon: 'fa fa-pencil', icon: 'fa fa-pencil',
title: __('Edit'), title: __('Edit'),
extend: 'data-toggle="tooltip"',
classname: 'btn btn-xs btn-success btn-editone', classname: 'btn btn-xs btn-success btn-editone',
url: options.extend.edit_url url: options.extend.edit_url
}); });
@ -9776,6 +9801,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
name: 'del', name: 'del',
icon: 'fa fa-trash', icon: 'fa fa-trash',
title: __('Del'), title: __('Del'),
extend: 'data-toggle="tooltip"',
classname: 'btn btn-xs btn-danger btn-delone' classname: 'btn btn-xs btn-danger btn-delone'
}); });
} }
@ -10338,7 +10364,11 @@ $.fn.addtabs = function (options) {
document.title = title; document.title = title;
if (history.pushState && !$(this).data("pushstate")) { if (history.pushState && !$(this).data("pushstate")) {
var pushurl = url.indexOf("ref=addtabs") == -1 ? (url + (url.indexOf("?") > -1 ? "&" : "?") + "ref=addtabs") : url; var pushurl = url.indexOf("ref=addtabs") == -1 ? (url + (url.indexOf("?") > -1 ? "&" : "?") + "ref=addtabs") : url;
window.history.pushState(state, title, pushurl); try {
window.history.pushState(state, title, pushurl);
}catch(e){
}
} }
$(this).data("pushstate", null); $(this).data("pushstate", null);
_add.call(this, { _add.call(this, {

View File

@ -39,10 +39,10 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
}, },
valid: function (ret) { valid: function (ret) {
var that = this, submitBtn = $(".layer-footer [type=submit]", form); var that = this, submitBtn = $(".layer-footer [type=submit]", form);
that.holdSubmit(); that.holdSubmit(true);
$(".layer-footer [type=submit]", form).addClass("disabled"); submitBtn.addClass("disabled");
//验证通过提交表单 //验证通过提交表单
Form.api.submit($(ret), function (data, ret) { var submitResult = Form.api.submit($(ret), function (data, ret) {
that.holdSubmit(false); that.holdSubmit(false);
submitBtn.removeClass("disabled"); submitBtn.removeClass("disabled");
if (false === $(this).triggerHandler("success.form", [data, ret])) { if (false === $(this).triggerHandler("success.form", [data, ret])) {
@ -72,6 +72,11 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
} }
} }
}, submit); }, submit);
//如果提交失败则释放锁定
if (!submitResult) {
that.holdSubmit(false);
submitBtn.removeClass("disabled");
}
return false; return false;
} }
}, form.data("validator-options") || {})); }, form.data("validator-options") || {}));
@ -255,7 +260,6 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
var textarea = $("textarea[name='" + name + "']", form); var textarea = $("textarea[name='" + name + "']", form);
var container = textarea.closest("dl"); var container = textarea.closest("dl");
var template = container.data("template"); var template = container.data("template");
console.log(name, container);
$.each($("input,select", container).serializeArray(), function (i, j) { $.each($("input,select", container).serializeArray(), function (i, j) {
var reg = /\[(\w+)\]\[(\w+)\]$/g; var reg = /\[(\w+)\]\[(\w+)\]$/g;
var match = reg.exec(j.name); var match = reg.exec(j.name);
@ -344,10 +348,12 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
}, },
api: { api: {
submit: function (form, success, error, submit) { submit: function (form, success, error, submit) {
if (form.size() === 0) if (form.size() === 0) {
return Toastr.error("表单未初始化完成,无法提交"); Toastr.error("表单未初始化完成,无法提交");
return false;
}
if (typeof submit === 'function') { if (typeof submit === 'function') {
if (false === submit.call(form)) { if (false === submit.call(form, success, error)) {
return false; return false;
} }
} }
@ -407,7 +413,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
} }
} }
}); });
return false; return true;
}, },
bindevent: function (form, success, error, submit) { bindevent: function (form, success, error, submit) {

View File

@ -759,7 +759,7 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
} }
name = name.replace(/[\[\]]/g, "\\$&"); name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url); results = regex.exec(url);
if (!results) if (!results)
return null; return null;
if (!results[2]) if (!results[2])
@ -788,31 +788,42 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
$(layero).data("callback", that.callback); $(layero).data("callback", that.callback);
//$(layero).removeClass("layui-layer-border"); //$(layero).removeClass("layui-layer-border");
Layer.setTop(layero); Layer.setTop(layero);
var frame = Layer.getChildFrame('html', index); try {
var layerfooter = frame.find(".layer-footer"); var frame = Layer.getChildFrame('html', index);
Fast.api.layerfooter(layero, index, that); var layerfooter = frame.find(".layer-footer");
Fast.api.layerfooter(layero, index, that);
//绑定事件 //绑定事件
if (layerfooter.size() > 0) { if (layerfooter.size() > 0) {
// 监听窗口内的元素及属性变化 // 监听窗口内的元素及属性变化
// Firefox和Chrome早期版本中带有前缀 // Firefox和Chrome早期版本中带有前缀
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
if (MutationObserver) { if (MutationObserver) {
// 选择目标节点 // 选择目标节点
var target = layerfooter[0]; var target = layerfooter[0];
// 创建观察者对象 // 创建观察者对象
var observer = new MutationObserver(function (mutations) { var observer = new MutationObserver(function (mutations) {
Fast.api.layerfooter(layero, index, that); Fast.api.layerfooter(layero, index, that);
mutations.forEach(function (mutation) { mutations.forEach(function (mutation) {
});
}); });
}); // 配置观察选项:
// 配置观察选项: var config = {attributes: true, childList: true, characterData: true, subtree: true}
var config = {attributes: true, childList: true, characterData: true, subtree: true} // 传入目标节点和观察选项
// 传入目标节点和观察选项 observer.observe(target, config);
observer.observe(target, config); // 随后,你还可以停止观察
// 随后,你还可以停止观察 // observer.disconnect();
// observer.disconnect(); }
} }
} catch (e) {
}
if ($(layero).height() > $(window).height()) {
//当弹出窗口大于浏览器可视高度时,重定位
Layer.style(index, {
top: 0,
height: $(window).height()
});
} }
} }
}, options ? options : {}); }, options ? options : {});
@ -888,8 +899,8 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
}, },
lang: function () { lang: function () {
var args = arguments, var args = arguments,
string = args[0], string = args[0],
i = 1; i = 1;
string = string.toLowerCase(); string = string.toLowerCase();
//string = typeof Lang[string] != 'undefined' ? Lang[string] : string; //string = typeof Lang[string] != 'undefined' ? Lang[string] : string;
if (typeof Lang[string] != 'undefined') { if (typeof Lang[string] != 'undefined') {
@ -1028,7 +1039,9 @@ define('frontend',['fast', 'template'], function (Fast, Template) {
return false; return false;
}); });
//tooltip和popover
$('body').tooltip({selector: '[data-toggle="tooltip"]'});
$('body').tooltip({selector: '[data-toggle="popover"]'});
} }
}; };
Frontend.api = $.extend(Fast.api, Frontend.api); Frontend.api = $.extend(Fast.api, Frontend.api);

View File

@ -20,6 +20,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
pageList: [10, 25, 50, 'All'], pageList: [10, 25, 50, 'All'],
pagination: true, pagination: true,
clickToSelect: true, //是否启用点击选中 clickToSelect: true, //是否启用点击选中
dblClickToEdit: true, //是否启用双击编辑
singleSelect: false, //是否启用单选 singleSelect: false, //是否启用单选
showRefresh: false, showRefresh: false,
locale: 'zh-CN', locale: 'zh-CN',
@ -114,10 +115,12 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
table.on('refresh.bs.table', function (e, settings, data) { table.on('refresh.bs.table', function (e, settings, data) {
$(Table.config.refreshbtn, toolbar).find(".fa").addClass("fa-spin"); $(Table.config.refreshbtn, toolbar).find(".fa").addClass("fa-spin");
}); });
//当双击单元格时 if (options.dblClickToEdit) {
table.on('dbl-click-row.bs.table', function (e, row, element, field) { //当双击单元格时
$(Table.config.editonebtn, element).trigger("click"); table.on('dbl-click-row.bs.table', function (e, row, element, field) {
}); $(Table.config.editonebtn, element).trigger("click");
});
}
//当内容渲染完成后 //当内容渲染完成后
table.on('post-body.bs.table', function (e, settings, json, xhr) { table.on('post-body.bs.table', function (e, settings, json, xhr) {
$(Table.config.refreshbtn, toolbar).find(".fa").removeClass("fa-spin"); $(Table.config.refreshbtn, toolbar).find(".fa").removeClass("fa-spin");
@ -400,7 +403,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
return '<div class="input-group input-group-sm" style="width:250px;margin:0 auto;"><input type="text" class="form-control input-sm" value="' + value + '"><span class="input-group-btn input-group-sm"><a href="' + value + '" target="_blank" class="btn btn-default btn-sm"><i class="fa fa-link"></i></a></span></div>'; return '<div class="input-group input-group-sm" style="width:250px;margin:0 auto;"><input type="text" class="form-control input-sm" value="' + value + '"><span class="input-group-btn input-group-sm"><a href="' + value + '" target="_blank" class="btn btn-default btn-sm"><i class="fa fa-link"></i></a></span></div>';
}, },
search: function (value, row, index) { search: function (value, row, index) {
return '<a href="javascript:;" class="searchit" data-field="' + this.field + '" data-value="' + value + '">' + value + '</a>'; return '<a href="javascript:;" class="searchit" data-toggle="tooltip" title="' + __('Click to search %s', value) + '" data-field="' + this.field + '" data-value="' + value + '">' + value + '</a>';
}, },
addtabs: function (value, row, index) { addtabs: function (value, row, index) {
var url = Table.api.replaceurl(this.url, row, this.table); var url = Table.api.replaceurl(this.url, row, this.table);
@ -453,6 +456,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
name: 'dragsort', name: 'dragsort',
icon: 'fa fa-arrows', icon: 'fa fa-arrows',
title: __('Drag to sort'), title: __('Drag to sort'),
extend: 'data-toggle="tooltip"',
classname: 'btn btn-xs btn-primary btn-dragsort' classname: 'btn btn-xs btn-primary btn-dragsort'
}); });
} }
@ -461,6 +465,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
name: 'edit', name: 'edit',
icon: 'fa fa-pencil', icon: 'fa fa-pencil',
title: __('Edit'), title: __('Edit'),
extend: 'data-toggle="tooltip"',
classname: 'btn btn-xs btn-success btn-editone', classname: 'btn btn-xs btn-success btn-editone',
url: options.extend.edit_url url: options.extend.edit_url
}); });
@ -470,6 +475,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
name: 'del', name: 'del',
icon: 'fa fa-trash', icon: 'fa fa-trash',
title: __('Del'), title: __('Del'),
extend: 'data-toggle="tooltip"',
classname: 'btn btn-xs btn-danger btn-delone' classname: 'btn btn-xs btn-danger btn-delone'
}); });
} }

View File

@ -591,6 +591,9 @@ form.form-horizontal .control-label {
.bootstrap-table td.bs-checkbox { .bootstrap-table td.bs-checkbox {
vertical-align: middle; vertical-align: middle;
} }
.fixed-table-container thead th .sortable{
padding-right:0;
}
.dropdown-submenu { .dropdown-submenu {
position: relative; position: relative;
>.dropdown-menu { >.dropdown-menu {