作者 Karson

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

新增后台管理员admin_login_after和admin_logout_after的行为
新增tooltip和popover
优化和改版插件管理功能
优化多个Layer弹窗的切换体验
优化弹窗高度大于视察高度的操作体验
优化系统配置中发送测试邮件的逻辑
修复生成关联模型时未判断selectpage的BUG
修复表单前置返回失败未释放锁定的BUG
修复API文档生成时采用了GET方法的BUG
正在显示 56 个修改的文件 包含 902 行增加815 行删除
... ... @@ -33,6 +33,9 @@ class Addon extends Command
{
$name = $input->getOption('name') ?: '';
$action = $input->getOption('action') ?: '';
if(stripos($name, 'addons/')!==false){
$name = explode('/', $name)[1];
}
//强制覆盖
$force = $input->getOption('force');
//版本
... ... @@ -65,8 +68,8 @@ class Addon extends Command
if (is_dir($addonDir)) {
rmdirs($addonDir);
}
mkdir($addonDir);
mkdir($addonDir . DS . 'controller');
mkdir($addonDir, 0755, true);
mkdir($addonDir . DS . 'controller', 0755, true);
$menuList = \app\common\library\Menu::export($name);
$createMenu = $this->getCreateMenu($menuList);
$prefix = Config::get('database.prefix');
... ...
... ... @@ -437,8 +437,8 @@
$.ajax({
url: $('#apiUrl').val() + url,
data: $(form).attr('method') == 'get' ? $(form).serialize() : formData,
type: $(form).attr('method') + '',
data: $(form).prop('method').toLowerCase() == 'get' ? $(form).serialize() : formData,
type: $(form).prop('method') + '',
dataType: 'json',
contentType: false,
processData: false,
... ...
... ... @@ -1137,7 +1137,7 @@ EOD;
$langField = mb_ucfirst($field);
return <<<EOD
<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">
{$content}
</div>
... ... @@ -1149,7 +1149,7 @@ EOD;
* 获取图片模板数据
* @param string $field
* @param string $content
* @return array
* @return string
*/
protected function getImageUpload($field, $content)
{
... ...
... ... @@ -14,6 +14,7 @@ class {%controllerName%} extends Backend
/**
* {%modelName%}模型对象
* @var \{%modelNamespace%}\{%modelName%}
*/
protected $model = null;
... ...
... ... @@ -10,6 +10,11 @@
$this->request->filter(['strip_tags']);
if ($this->request->isAjax())
{
//如果发送的来源是Selectpage,则转发到Selectpage
if ($this->request->request('keyField'))
{
return $this->selectpage();
}
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
{%relationWithList%}
... ...
... ... @@ -50,7 +50,7 @@ CREATE TABLE `fa_admin_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`admin_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '管理员ID',
`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 '日志标题',
`content` text NOT NULL COMMENT '内容',
`ip` varchar(50) NOT NULL DEFAULT '' COMMENT 'IP',
... ... @@ -66,6 +66,8 @@ CREATE TABLE `fa_admin_log` (
DROP TABLE IF EXISTS `fa_attachment`;
CREATE TABLE `fa_attachment` (
`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 '物理路径',
`imagewidth` 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 '创建日期',
`updatetime` 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编码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='附件表';
... ... @@ -86,7 +88,7 @@ CREATE TABLE `fa_attachment` (
-- Records of fa_attachment
-- ----------------------------
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;
-- ----------------------------
... ... @@ -344,7 +346,7 @@ DROP TABLE IF EXISTS `fa_ems`;
CREATE TABLE `fa_ems` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
`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 '验证码',
`times` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '验证次数',
`ip` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'IP',
... ...
... ... @@ -76,7 +76,7 @@ class Addon extends Backend
Service::refresh();
$this->success();
} catch (Exception $e) {
$this->error($e->getMessage());
$this->error(__($e->getMessage()));
}
}
$this->error(__('Parameter %s can not be empty', ''));
... ... @@ -112,9 +112,9 @@ class Addon extends Backend
$info['state'] = 1;
$this->success(__('Install successful'), null, ['addon' => $info]);
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), $e->getMessage());
$this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} 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);
$this->success(__('Uninstall successful'));
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), $e->getMessage());
$this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) {
$this->error($e->getMessage());
$this->error(__($e->getMessage()));
}
}
... ... @@ -156,9 +156,9 @@ class Addon extends Backend
Cache::rm('__menu__');
$this->success(__('Operate successful'));
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), $e->getMessage());
$this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} 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]);
} catch (Exception $e) {
@rmdirs($newAddonDir);
throw new Exception($e->getMessage());
throw new Exception(__($e->getMessage()));
}
} catch (Exception $e) {
@unlink($tmpFile);
@rmdirs($tmpAddonDir);
$this->error($e->getMessage());
$this->error(__($e->getMessage()));
}
} else {
// 上传失败获取错误信息
$this->error($file->getError());
$this->error(__($file->getError()));
}
}
... ... @@ -260,9 +260,9 @@ class Addon extends Backend
Cache::rm('__menu__');
$this->success(__('Operate successful'));
} catch (AddonException $e) {
$this->result($e->getData(), $e->getCode(), $e->getMessage());
$this->result($e->getData(), $e->getCode(), __($e->getMessage()));
} catch (Exception $e) {
$this->error($e->getMessage());
$this->error(__($e->getMessage()));
}
}
... ... @@ -297,7 +297,7 @@ class Addon extends Backend
continue;
if (isset($onlineaddons[$v['name']])) {
$v = array_merge($onlineaddons[$v['name']], $v);
$v = array_merge($v, $onlineaddons[$v['name']]);
} else {
$v['category_id'] = 0;
$v['flag'] = '';
... ... @@ -306,6 +306,8 @@ class Addon extends Backend
$v['donateimage'] = '';
$v['demourl'] = '';
$v['price'] = '0.00';
$v['screenshots'] = [];
$v['releaselist'] = [];
}
$v['url'] = addon_url($v['name']);
$v['createtime'] = filemtime(ADDON_PATH . $v['name']);
... ...
... ... @@ -106,6 +106,8 @@ class Ajax extends Backend
$imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
}
$params = array(
'admin_id' => (int)$this->auth->id,
'user_id' => 0,
'filesize' => $fileInfo['size'],
'imagewidth' => $imagewidth,
'imageheight' => $imageheight,
... ...
... ... @@ -90,6 +90,7 @@ class Index extends Backend
$result = $this->auth->login($username, $password, $keeplogin ? 86400 : 0);
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]);
}
else
... ... @@ -109,7 +110,7 @@ class Index extends Backend
$background = stripos($background, 'http')===0 ? $background : config('site.cdnurl') . $background;
$this->view->assign('background', $background);
$this->view->assign('title', __('Login'));
Hook::listen("login_init", $this->request);
Hook::listen("admin_login_init", $this->request);
return $this->view->fetch();
}
... ... @@ -119,6 +120,7 @@ class Index extends Backend
public function logout()
{
$this->auth->logout();
Hook::listen("admin_logout_after", $this->request);
$this->success(__('Logout successful'), 'index/login');
}
... ...
... ... @@ -10,7 +10,7 @@ use think\Exception;
/**
* 系统配置
*
* @icon fa fa-circle-o
* @icon fa fa-cogs
* @remark 可以在此增改系统的变量和分组,也可以自定义分组和变量,如果需要删除请从数据库中删除
*/
class Config extends Backend
... ... @@ -32,31 +32,26 @@ class Config extends Backend
{
$siteList = [];
$groupList = ConfigModel::getGroupList();
foreach ($groupList as $k => $v)
{
foreach ($groupList as $k => $v) {
$siteList[$k]['name'] = $k;
$siteList[$k]['title'] = $v;
$siteList[$k]['list'] = [];
}
foreach ($this->model->all() as $k => $v)
{
if (!isset($siteList[$v['group']]))
{
foreach ($this->model->all() as $k => $v) {
if (!isset($siteList[$v['group']])) {
continue;
}
$value = $v->toArray();
$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['content'] = json_decode($value['content'], TRUE);
$siteList[$v['group']]['list'][] = $value;
}
$index = 0;
foreach ($siteList as $k => &$v)
{
foreach ($siteList as $k => &$v) {
$v['active'] = !$index ? true : false;
$index++;
}
... ... @@ -71,45 +66,30 @@ class Config extends Backend
*/
public function add()
{
if ($this->request->isPost())
{
if ($this->request->isPost()) {
$params = $this->request->post("row/a");
if ($params)
{
foreach ($params as $k => &$v)
{
if ($params) {
foreach ($params as $k => &$v) {
$v = is_array($v) ? implode(',', $v) : $v;
}
try
{
if (in_array($params['type'], ['select', 'selects', 'checkbox', 'radio', 'array']))
{
try {
if (in_array($params['type'], ['select', 'selects', 'checkbox', 'radio', 'array'])) {
$params['content'] = json_encode(ConfigModel::decode($params['content']), JSON_UNESCAPED_UNICODE);
}
else
{
} else {
$params['content'] = '';
}
$result = $this->model->create($params);
if ($result !== false)
{
try
{
if ($result !== false) {
try {
$this->refreshFile();
$this->success();
}
catch (Exception $e)
{
} catch (Exception $e) {
$this->error($e->getMessage());
}
}
else
{
} else {
$this->error($this->model->getError());
}
}
catch (Exception $e)
{
} catch (Exception $e) {
$this->error($e->getMessage());
}
}
... ... @@ -124,23 +104,16 @@ class Config extends Backend
*/
public function edit($ids = NULL)
{
if ($this->request->isPost())
{
if ($this->request->isPost()) {
$row = $this->request->post("row/a");
if ($row)
{
if ($row) {
$configList = [];
foreach ($this->model->all() as $v)
{
if (isset($row[$v['name']]))
{
foreach ($this->model->all() as $v) {
if (isset($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);
}
else
{
} else {
$value = is_array($value) ? implode(',', $value) : $value;
}
$v['value'] = $value;
... ... @@ -148,13 +121,10 @@ class Config extends Backend
}
}
$this->model->allowField(true)->saveAll($configList);
try
{
try {
$this->refreshFile();
$this->success();
}
catch (Exception $e)
{
} catch (Exception $e) {
$this->error($e->getMessage());
}
}
... ... @@ -162,20 +132,20 @@ class Config extends Backend
}
}
/**
* 刷新配置文件
*/
protected function refreshFile()
{
$config = [];
foreach ($this->model->all() as $k => $v)
{
foreach ($this->model->all() as $k => $v) {
$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']);
}
if ($value['type'] == 'array')
{
$value['value'] = (array) json_decode($value['value'], TRUE);
if ($value['type'] == 'array') {
$value['value'] = (array)json_decode($value['value'], TRUE);
}
$config[$value['name']] = $value['value'];
}
... ... @@ -183,26 +153,21 @@ class Config extends Backend
}
/**
* 检测配置项是否存在
* @internal
*/
public function check()
{
$params = $this->request->post("row/a");
if ($params)
{
if ($params) {
$config = $this->model->get($params);
if (!$config)
{
if (!$config) {
return $this->success();
}
else
{
} else {
return $this->error(__('Name already exist'));
}
}
else
{
} else {
return $this->error(__('Invalid parameters'));
}
}
... ... @@ -213,19 +178,18 @@ class Config extends Backend
*/
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");
$email = new Email;
$result = $email
->to($receiver)
->subject(__("This is a test mail"))
->message('<div style="min-height:550px; padding: 100px 55px 200px;">' . __('This is a test mail content') . '</div>')
->send();
if ($result)
{
->to($receiver)
->subject(__("This is a test mail"))
->message('<div style="min-height:550px; padding: 100px 55px 200px;">' . __('This is a test mail content') . '</div>')
->send();
if ($result) {
$this->success();
}
else
{
} else {
$this->error($email->getError());
}
}
... ...
... ... @@ -53,8 +53,7 @@ class User extends Backend
->select();
foreach ($list as $k => $v)
{
$v->password = '';
$v->salt = '';
$v->hidden(['password', 'salt']);
}
$result = array("total" => $total, "rows" => $list);
... ...
... ... @@ -34,7 +34,6 @@ return [
'Cancel' => '取消',
'Clear' => '清空',
'Custom Range' => '自定义',
'Cancel' => '取消',
'Today' => '今天',
'Yesterday' => '昨天',
'Last 7 days' => '最近7天',
... ... @@ -78,13 +77,9 @@ return [
'Line' => '行号',
'File' => '文件',
'Menu' => '菜单',
'Name' => '名称',
'Weigh' => '权重',
'Type' => '类型',
'Title' => '标题',
'Content' => '内容',
'Status' => '状态',
'Operate' => '操作',
'Append' => '追加',
'Select' => '选择',
'Memo' => '备注',
... ... @@ -115,6 +110,7 @@ return [
//提示
'Go back' => '返回首页',
'Jump now' => '立即跳转',
'Click to search %s' => '点击搜索 %s',
'Operation completed' => '操作成功!',
'Operation failed' => '操作失败!',
'Unknown data format' => '未知的数据格式!',
... ... @@ -147,7 +143,7 @@ return [
'Admin' => '管理员管理',
'Admin log' => '管理员日志',
'Group' => '角色组',
'Rule' => '规则管理',
'Rule' => '菜单规则',
'User' => '会员管理',
'User group' => '会员分组',
'User rule' => '会员规则',
... ...
... ... @@ -2,13 +2,14 @@
return [
'Id' => 'ID',
'Title' => '标题',
'Title' => '插件名称',
'Value' => '配置值',
'Array key' => '键',
'Array value' => '值',
'File' => '文件',
'Donate' => '打赏作者',
'Warmtips' => '温馨提示',
'Pay now' => '立即支付',
'Offline install' => '离线安装',
'Refresh addon cache' => '刷新插件缓存',
'Userinfo' => '会员信息',
... ... @@ -17,38 +18,47 @@ return [
'Conflict tips' => '此插件中发现和现有系统中部分文件发现冲突!以下文件将会被影响,请备份好相关文件后再继续操作',
'Login tips' => '此处登录账号为<a href="https://www.fastadmin.net" target="_blank">FastAdmin官网账号</a>',
'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 new window tips' => '请在新弹出的窗口中进行支付,支付完成后再重新点击安装按钮进行安装!',
'Uninstall tips' => '确认卸载插件?<p class="text-danger">卸载将会删除所有插件文件且不可找回!!! 插件如果有创建数据库表请手动删除!!!</p>如有重要数据请备份后再操作!',
'Upgrade tips' => '确认升级插件?<p class="text-danger">如果之前购买插件时未登录,此次升级可能出现购买后才可以下载的提示!!!<br>升级后可能出现部分冗余数据记录,请根据需要移除即可!!!</p>如有重要数据请备份后再操作!',
'Offline installed tips' => '插件安装成功!清除插件缓存和框架缓存后生效!',
'Online installed tips' => '插件安装成功!清除插件缓存和框架缓存后生效!',
'Offline installed tips' => '插件安装成功!清除浏览器缓存和框架缓存后生效!',
'Online installed tips' => '插件安装成功!清除浏览器缓存和框架缓存后生效!',
'Not login tips' => '你当前未登录FastAdmin,登录后将同步已购买的记录,下载时无需二次付费!',
'Not installed tips' => '请安装后再访问插件前台页面!',
'Not enabled tips' => '插件已经禁用,请启用后再访问插件前台页面!',
'Please disable addon first' => '请先禁用插件再进行升级',
'Login now' => '立即登录',
'Continue install' => '不登录,继续安装',
'View addon home page' => '查看插件介绍和帮助',
'View addon index page' => '查看插件前台首页',
'View addon screenshots' => '点击查看插件截图',
'Click to toggle status' => '点击切换插件状态',
'Click to contact developer' => '点击与插件开发者取得联系',
'Index' => '前台',
'All' => '全部',
'Uncategoried' => '未归类',
'Recommend' => '推荐',
'Hot' => '热门',
'New' => '新',
'Paying' => '付费',
'Free' => '免费',
'Sale' => '折扣',
'No image' => '暂无缩略图',
'Price' => '价格',
'Downloads' => '下载',
'Author' => '作者',
'Identify' => '标识',
'Homepage' => '主页',
'Intro' => '介绍',
'Version' => '版本',
'New version' => '新版本',
'Createtime' => '添加时间',
'Releasetime' => '更新时间',
'Detail' => '插件详情',
'Document' => '文档',
'Demo' => '在线演示',
'Demo' => '演示',
'Feedback' => '反馈BUG',
'Install' => '安装',
'Uninstall' => '卸载',
... ... @@ -63,9 +73,7 @@ return [
'Logout' => '退出登录',
'Register' => '注册账号',
'You\'re not login' => '当前未登录',
'Pay now' => '立即支付',
'Continue install' => '继续安装',
'Continue uninstall' => '继续安装',
'Continue uninstall' => '继续卸载',
'Continue operate' => '继续操作',
'Install successful' => '安装成功',
'Uninstall successful' => '卸载成功',
... ... @@ -73,4 +81,6 @@ return [
'Addon info file was not found' => '插件配置文件未找到',
'Addon info file data incorrect' => '插件配置信息不正确',
'Addon already exists' => '上传的插件已经存在',
'Unable to open the zip file' => '无法打开ZIP文件',
'Unable to extract the file' => '无法解压ZIP文件',
];
... ...
... ... @@ -10,9 +10,10 @@ return [
'Controller/Action' => '控制器名/方法名',
'Ismenu' => '菜单',
'Search icon' => '搜索图标',
'Menu tips' => '规则任意,不可重复,仅做层级显示,无需匹配控制器和方法',
'Node tips' => '控制器/方法名',
'Toggle menu visible' => '点击切换菜单显示',
'Toggle sub menu' => '点击切换子菜单',
'Menu tips' => '父级菜单无需匹配控制器和方法,子级菜单请使用控制器名',
'Node tips' => '控制器/方法名,如果有目录请使用 目录名/控制器名/方法名',
'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规则只能是小写字母、数字、下划线和/组成',
];
... ...
<?php
return [
'Id' => 'ID',
'Url' => '物理路径',
'Imagewidth' => '宽度',
'Imageheight' => '度',
'Imageheight' => '度',
'Imagetype' => '图片类型',
'Imageframes' => '图片帧数',
'Preview' => '预览',
... ...
... ... @@ -53,6 +53,7 @@ return [
'Mail from' => '发件人邮箱',
'Name already exist' => '变量名称已经存在',
'Send a test message' => '发送测试邮件',
'This is a test mail content' => '这是一封测试邮件,用于测试邮件配置是否正常!',
'This is a test mail' => '这是一封测试邮件',
'This is a test mail content' => '这是一封来自FastAdmin校验邮件,用于校验邮件配置是否正常!',
'This is a test mail' => '这是一封来自FastAdmin的邮件',
'Please input your email' => '请输入测试接收者邮箱',
];
... ...
<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>
<style type="text/css">
.noimage {width:100%;text-align: center;background:#18bc9c;color:#fff;padding-bottom:66.66%;position:relative;}
.noimage > div {position: absolute;top:48%;width:100%;text-align:center;}
.addon {position: relative;border-color:#e4e4e4;}
.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 {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;}
.thumbnail img{width:100%;}
.layui-layer-pay .layui-layer-content {
padding: 0;
height: 600px !important;
}
.layui-layer-pay {
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;
}
.thumbnail img {
width: 100%;
}
.fixed-table-toolbar .pull-right.search {
min-width: 300px;
}
.status-disabled .noimage {
background:#d2d6de;
a.title {
color: #444;
}
.releasetips {
position: relative;
}
@media (min-width: 992px) {
.addon {
-webkit-transition:all 0.3s ease;
-moz-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
transition: all 0.3s ease;
}
.addon:hover {
border-color: #dddddd;
-webkit-box-shadow: 0 26px 40px -24px rgba(0,36,100,0.3);
-moz-box-shadow: 0 26px 40px -24px rgba(0,36,100,0.3);
box-shadow: 0 26px 40px -24px rgba(0,36,100,0.3);
-webkit-transition: all 0.3s ease;
-moz-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
transition: all 0.3s ease;
}
.releasetips i {
display: block;
background: #f00;
border-radius: 50%;
width: 0.3em;
height: 0.3em;
top: 0px;
right: -8px;
position: absolute;
box-shadow: 0px 0px 2px #f11414;
}
</style>
<div class="panel panel-default panel-intro">
... ... @@ -51,16 +70,27 @@
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{: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">
<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" data-type="free" data-url="{$config.fastadmin.api_url}/addon/index"><i class="fa fa-gift"></i> {:__('免费')}</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> {:__('付费')}</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 active" data-type="all"
data-url="{$config.fastadmin.api_url}/addon/index"><i class="fa fa-list"></i>
{:__('All')}</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>
<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>
<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>
... ... @@ -76,28 +106,28 @@
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-3">
<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="form-control" type="text" name="title" placeholder="请输入查找的标题" value=""/>
<input class="form-control" type="text" name="title" placeholder="" value=""/>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<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="form-control" type="text" name="type" placeholder="all" value=""/>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<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 class="form-control" name="category_id" type="text" value="">
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<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 class="form-control" name="faversion" type="text" value="{$config.fastadmin.version}">
</div>
... ... @@ -107,10 +137,10 @@
<label class="control-label"></label>
<div class="row">
<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 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>
... ... @@ -125,18 +155,20 @@
<fieldset>
<div class="alert alert-dismissable alert-danger">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{:__('Warning')}</strong><br />{:__('Login tips')}
<strong>{:__('Warning')}</strong><br/>{:__('Login tips')}
</div>
<div class="form-group">
<label for="inputAccount" class="col-lg-3 control-label">{:__('Username')}</label>
<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 class="form-group">
<label for="inputPassword" class="col-lg-3 control-label">{:__('Password')}</label>
<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>
</fieldset>
... ... @@ -149,57 +181,12 @@
<fieldset>
<div class="alert alert-dismissable alert-success">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{:__('Warning')}</strong><br />{:__('Logined tips', '<%=username%>')}
<strong>{:__('Warning')}</strong><br/>{:__('Logined tips', '<%=username%>')}
</div>
</fieldset>
</form>
</div>
</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">
<div class="payimg" style="background:url('<%=payimg%>') 0 0 no-repeat;background-size:cover;">
<%if(paycode){%>
... ... @@ -219,118 +206,85 @@
</div>
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>{:__('File')}</th>
</tr>
<tr>
<th>#</th>
<th>{:__('File')}</th>
</tr>
</thead>
<tbody>
<%for(var i=0;i < conflictlist.length;i++){%>
<tr>
<th scope="row"><%=i+1%></th>
<td><%=conflictlist[i]%></td>
</tr>
<%}%>
<%for(var i=0;i < conflictlist.length;i++){%>
<tr>
<th scope="row"><%=i+1%></th>
<td><%=conflictlist[i]%></td>
</tr>
<%}%>
</tbody>
</table>
</script>
<script id="itemtpl" type="text/html">
<script id="operatetpl" type="text/html">
<% var labelarr = ['primary', 'success', 'info', 'danger', 'warning']; %>
<% var label = labelarr[item.id % 5]; %>
<% var addon = typeof addons[item.name]!= 'undefined' ? addons[item.name] : null; %>
<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">
<%if(addon){%>
<span>
<a href="<%=addon.url%>" target="_blank" class="btn btn-xs">
<i class="fa fa-home"></i>
<% var addon = item.addon; %>
<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-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>
</span>
<%}%>
<a href="<%=item.url%>" class="btn-addonindex" target="_blank">
<%if(item.image){%>
<img src="<%=item.image%>" class="img-responsive" alt="<%=item.title%>">
<%}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>
<% } %>
<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-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>
<% } %>
<% if(addon){ %>
<% if(addon.config){ %>
<a href="javascript:;" class="btn btn-primary btn-config"><i class="fa fa-pencil"></i> {:__('Setting')}</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{ %>
<a href="javascript:;" class="btn btn-success btn-enable" data-action="enable"><i class="fa fa-check"></i> {:__('Enable')}</a>
<a href="javascript:;" class="btn btn-danger btn-uninstall"><i class="fa fa-times"></i> {:__('Uninstall')}</a>
<% } %>
<% } %>
<% if(addon && item && addon.version!=item.version){%>
<% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
<span class="btn-group">
<a href="javascript:;" class="btn btn-info btn-success btn-upgrade" data-version="<%=item.version%>"><i class="fa fa-cloud"></i> {:__('Upgrade')}</a>
<a class="btn btn-info 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-upgrade" data-version="<%=item.releaselist[j].version%>"><%=item.releaselist[j].version%></a></li>
<% } %>
</ul>
</span>
<% }else{%>
<a href="javascript:;" class="btn btn-info btn-upgrade" data-version="<%=item.version%>"><i class="fa fa-cloud"></i> {:__('Upgrade')}</a>
<% }%>
<% }%>
<% if(item.demourl){ %>
<a href="<%=item.demourl%>" class="btn btn-xs btn-primary btn-info btn-demo" target="_blank">
<i class="fa fa-flash"></i> {:__('Demo')}
</a>
<% } %>
<% } else {%>
<% if(addon.version!=item.version){%>
<% if(typeof item.releaselist !="undefined" && item.releaselist.length>1){%>
<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>
<a class="btn btn-xs btn-info 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-upgrade"
data-version="<%=item.releaselist[j].version%>"><%=item.releaselist[j].version%></a></li>
<% } %>
</ul>
</span>
<% }else{%>
<a href="javascript:;" class="btn btn-xs 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>
</script>
\ No newline at end of file
... ...
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<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">
{:build_select('group[]', $groupdata, null, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])}
</div>
... ... @@ -30,7 +30,7 @@
</div>
</div>
<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">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
... ...
<form id="edit-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<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">
{:build_select('group[]', $groupdata, $groupids, ['class'=>'form-control selectpicker', 'multiple'=>'', 'data-rule'=>'required'])}
</div>
... ... @@ -36,7 +36,7 @@
</div>
</div>
<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">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
... ...
<form id="add-form" class="form-horizontal form-ajax" role="form" data-toggle="validator" method="POST" action="">
<input type="hidden" name="row[rules]" value="" />
<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">
{:build_select('row[pid]', $groupdata, null, ['class'=>'form-control selectpicker', 'data-rule'=>'required'])}
</div>
</div>
<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">
<input type="text" class="form-control" id="name" name="row[name]" value="" data-rule="required" />
</div>
</div>
<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">
<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>
... ... @@ -22,7 +22,7 @@
</div>
</div>
<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">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
... ...
<form id="edit-form" class="form-horizontal form-ajax" role="form" method="POST" action="">
<input type="hidden" name="row[rules]" value="" />
<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">
{: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 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">
<input type="text" class="form-control" id="name" name="row[name]" value="{$row.name}" data-rule="required" />
</div>
</div>
<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">
<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>
... ... @@ -22,7 +22,7 @@
</div>
</div>
<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">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
... ...
<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="">
<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">
{:build_radios('row[ismenu]', ['1'=>__('Yes'), '0'=>__('No')])}
</div>
</div>
<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">
{:build_select('row[pid]', $ruledata, null, ['class'=>'form-control', 'required'=>''])}
</div>
... ... @@ -18,11 +14,12 @@
<div class="form-group">
<label for="name" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<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" />
</div>
</div>
<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">
<input type="text" class="form-control" id="title" name="row[title]" value="" data-rule="required" />
</div>
... ... @@ -55,7 +52,7 @@
</div>
</div>
<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">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
... ...
<form id="edit-form" class="form-horizontal form-ajax" role="form" method="POST" action="">
<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">
{:build_radios('row[ismenu]', ['1'=>__('Yes'), '0'=>__('No')], $row['ismenu'])}
</div>
</div>
<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">
{:build_select('row[pid]', $ruledata, $row['pid'], ['class'=>'form-control', 'required'=>''])}
</div>
... ... @@ -18,7 +18,7 @@
</div>
</div>
<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">
<input type="text" class="form-control" id="title" name="row[title]" value="{$row.title}" data-rule="required" />
</div>
... ... @@ -51,7 +51,7 @@
</div>
</div>
<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">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
... ...
... ... @@ -6,12 +6,13 @@
margin:5px 0 0 0;
}
#chooseicon ul li{
width:30px;height:30px;
line-height:30px;
border:1px solid #ddd;
width:41px;height:42px;
line-height:42px;
border:1px solid #efefef;
padding:1px;
margin:1px;
text-align: center;
font-size:18px;
}
#chooseicon ul li:hover{
border:1px solid #2c3e50;
... ... @@ -31,7 +32,7 @@
<div>
<ul class="list-inline">
<% 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>
</li>
<% } %>
... ...
... ... @@ -81,7 +81,7 @@
</div>
</div>
<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">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
... ...
... ... @@ -81,7 +81,7 @@
</div>
</div>
<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">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
... ...
... ... @@ -54,6 +54,7 @@
</a>
<ul class="dropdown-menu wipecache">
<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="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>
... ...
... ... @@ -24,15 +24,14 @@ class Common extends Api
/**
* 加载初始化
*
*
* @param string $version 版本号
* @param string $lng 经度
* @param string $lat 纬度
*/
public function init()
{
if ($version = $this->request->request('version'))
{
if ($version = $this->request->request('version')) {
$lng = $this->request->request('lng');
$lat = $this->request->request('lat');
$content = [
... ... @@ -42,23 +41,20 @@ class Common extends Api
'coverdata' => Config::get("cover"),
];
$this->success('', $content);
}
else
{
} else {
$this->error(__('Invalid parameters'));
}
}
/**
* 上传文件
*
*
* @param File $file 文件流
*/
public function upload()
{
$file = $this->request->file('file');
if (empty($file))
{
if (empty($file)) {
$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);
$type = strtolower($matches[2]);
$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();
$suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
$suffix = $suffix ? $suffix : 'file';
... ... @@ -108,16 +104,16 @@ class Common extends Api
$fileName = substr($savekey, strripos($savekey, '/') + 1);
//
$splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
if ($splInfo)
{
if ($splInfo) {
$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());
$imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
$imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
}
$params = array(
'admin_id' => 0,
'user_id' => (int)$this->auth->id,
'filesize' => $fileInfo['size'],
'imagewidth' => $imagewidth,
'imageheight' => $imageheight,
... ... @@ -136,9 +132,7 @@ class Common extends Api
$this->success(__('Upload successful'), [
'url' => $uploadDir . $splInfo->getSaveName()
]);
}
else
{
} else {
// 上传失败获取错误信息
$this->error($file->getError());
}
... ...
... ... @@ -2,22 +2,20 @@
// 公共助手函数
if (!function_exists('__'))
{
if (!function_exists('__')) {
/**
* 获取语言变量值
* @param string $name 语言变量名
* @param array $vars 动态变量值
* @param string $lang 语言
* @param string $name 语言变量名
* @param array $vars 动态变量值
* @param string $lang 语言
* @return mixed
*/
function __($name, $vars = [], $lang = '')
{
if (is_numeric($name) || !$name)
return $name;
if (!is_array($vars))
{
if (!is_array($vars)) {
$vars = func_get_args();
array_shift($vars);
$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的地址
* @param string $url 资源相对地址
* @param boolean $domain 是否显示域名 或者直接传入域名
* @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 文件或目录
* @return bool
* @param string $file 文件或目录
* @return bool
*/
function is_really_writable($file)
{
if (DIRECTORY_SEPARATOR === '/')
{
if (DIRECTORY_SEPARATOR === '/') {
return is_writable($file);
}
if (is_dir($file))
{
if (is_dir($file)) {
$file = rtrim($file, '/') . '/' . md5(mt_rand());
if (($fp = @fopen($file, 'ab')) === FALSE)
{
if (($fp = @fopen($file, 'ab')) === FALSE) {
return FALSE;
}
fclose($fp);
@chmod($file, 0777);
@unlink($file);
return TRUE;
}
elseif (!is_file($file) OR ( $fp = @fopen($file, 'ab')) === FALSE)
{
} elseif (!is_file($file) OR ($fp = @fopen($file, 'ab')) === FALSE) {
return FALSE;
}
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))
return false;
$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->getRealPath());
}
if ($withself)
{
if ($withself) {
@rmdir($dirname);
}
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)
{
if (!is_dir($dest))
{
mkdir($dest, 0755);
if (!is_dir($dest)) {
mkdir($dest, 0755, true);
}
foreach (
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST) as $item
)
{
if ($item->isDir())
{
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST) as $item
) {
if ($item->isDir()) {
$sontDir = $dest . DS . $iterator->getSubPathName();
if (!is_dir($sontDir))
{
mkdir($sontDir);
if (!is_dir($sontDir)) {
mkdir($sontDir, 0755, true);
}
}
else
{
} else {
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)
{
... ... @@ -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)
return $items;
$fieldsArr = [];
if (!is_array($fields))
{
if (!is_array($fields)) {
$arr = explode(',', $fields);
foreach ($arr as $k => $v)
{
foreach ($arr as $k => $v) {
$fieldsArr[$v] = ['field' => $v];
}
}
else
{
foreach ($fields as $k => $v)
{
if (is_array($v))
{
} else {
foreach ($fields as $k => $v) {
if (is_array($v)) {
$v['field'] = isset($v['field']) ? $v['field'] : $k;
}
else
{
} else {
$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['display'] = isset($v['display']) ? $v['display'] : str_replace(['_ids', '_id'], ['_names', '_name'], $v['field']);
$v['primary'] = isset($v['primary']) ? $v['primary'] : '';
... ... @@ -258,37 +238,27 @@ if (!function_exists('addtion'))
unset($v);
$ids = [];
$fields = array_keys($fieldsArr);
foreach ($items as $k => $v)
{
foreach ($fields as $m => $n)
{
if (isset($v[$n]))
{
foreach ($items as $k => $v) {
foreach ($fields as $m => $n) {
if (isset($v[$n])) {
$ids[$n] = array_merge(isset($ids[$n]) && is_array($ids[$n]) ? $ids[$n] : [], explode(',', $v[$n]));
}
}
}
$result = [];
foreach ($fieldsArr as $k => $v)
{
if ($v['model'])
{
foreach ($fieldsArr as $k => $v) {
if ($v['model']) {
$model = new $v['model'];
}
else
{
} else {
$model = $v['name'] ? \think\Db::name($v['name']) : \think\Db::table($v['table']);
}
$primary = $v['primary'] ? $v['primary'] : $model->getPk();
$result[$v['field']] = $model->where($primary, 'in', $ids[$v['field']])->column("{$primary},{$v['column']}");
}
foreach ($items as $k => &$v)
{
foreach ($fields as $m => $n)
{
if (isset($v[$n]))
{
foreach ($items as $k => &$v) {
foreach ($fields as $m => $n) {
if (isset($v[$n])) {
$curr = array_flip(explode(',', $v[$n]));
$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 缩进字符
* @return string
*/
function var_export_short($var, $indent = "")
{
switch (gettype($var))
{
switch (gettype($var)) {
case "string":
return '"' . addcslashes($var, "\\\$\"\r\n\t\v\f") . '"';
case "array":
$indexed = array_keys($var) === range(0, count($var) - 1);
$r = [];
foreach ($var as $key => $value)
{
foreach ($var as $key => $value) {
$r[] = "$indent "
. ($indexed ? "" : var_export_short($key) . " => ")
. var_export_short($value, "$indent ");
. ($indexed ? "" : var_export_short($key) . " => ")
. var_export_short($value, "$indent ");
}
return "[\n" . implode(",\n", $r) . "\n" . $indent . "]";
case "boolean":
... ...
... ... @@ -270,7 +270,7 @@ return [
//自动检测更新
'checkupdate' => false,
//版本号
'version' => '1.0.0.20180417_beta',
'version' => '1.0.0.20180506_beta',
//API接口地址
'api_url' => 'https://api.fastadmin.net',
],
... ...
... ... @@ -107,7 +107,7 @@ class User extends Frontend
$validate = new Validate($rule, $msg);
$result = $validate->check($data);
if (!$result) {
$this->error(__($validate->getError()));
$this->error(__($validate->getError()), null, ['token' => $this->request->token()]);
}
if ($this->auth->register($username, $password, $email, $mobile)) {
$synchtml = '';
... ... @@ -118,7 +118,7 @@ class User extends Frontend
}
$this->success(__('Sign up successful') . $synchtml, $url ? $url : url('user/index'));
} 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);
$result = $validate->check($data);
if (!$result) {
$this->error(__($validate->getError()));
$this->error(__($validate->getError()), null, ['token' => $this->request->token()]);
return FALSE;
}
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'));
} 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);
$result = $validate->check($data);
if (!$result) {
$this->error(__($validate->getError()));
$this->error(__($validate->getError()), null, ['token' => $this->request->token()]);
return FALSE;
}
... ... @@ -263,7 +263,7 @@ class User extends Frontend
}
$this->success(__('Reset password successful') . $synchtml, url('user/login'));
} else {
$this->error($this->auth->getError());
$this->error($this->auth->getError(), null, ['token' => $this->request->token()]);
}
}
$this->view->assign('title', __('Change password'));
... ...
... ... @@ -4,6 +4,7 @@
<div class="login-main">
<form name="form" id="login-form" class="form-vertical" method="POST" action="">
<input type="hidden" name="url" value="{$url}" />
{:token()}
<div class="form-group">
<label class="control-label" for="account">{:__('Account')}</label>
<div class="controls">
... ...
... ... @@ -5,6 +5,7 @@
<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="url" value="{$url}" />
{:token()}
<div class="form-group">
<label class="control-label required">{:__('Email')}<span class="text-success"></span></label>
<div class="controls">
... ...
... ... @@ -22,7 +22,7 @@
"topthink/think-captcha": "^1.0",
"mtdowling/cron-expression": "^1.2",
"phpmailer/phpmailer": "^5.2",
"karsonzhang/fastadmin-addons": "~1.1.0",
"karsonzhang/fastadmin-addons": "~1.1.4",
"overtrue/pinyin": "~3.0",
"phpoffice/phpexcel": "^1.8"
},
... ...
... ... @@ -356,7 +356,7 @@
<div class="panel panel-default">
<div class="panel-heading"><strong>参数</strong></div>
<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>
... ... @@ -3359,7 +3359,7 @@
<div class="row mt0 footer">
<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">
<a href="https://www.fastadmin.net" target="_blank">FastAdmin</a>
</div>
... ... @@ -3531,8 +3531,8 @@
$.ajax({
url: $('#apiUrl').val() + url,
data: $(form).attr('method') == 'get' ? $(form).serialize() : formData,
type: $(form).attr('method') + '',
data: $(form).prop('method').toLowerCase() == 'get' ? $(form).serialize() : formData,
type: $(form).prop('method') + '',
dataType: 'json',
contentType: false,
processData: false,
... ...
... ... @@ -559,6 +559,9 @@ form.form-horizontal .control-label {
.bootstrap-table td.bs-checkbox {
vertical-align: middle;
}
.fixed-table-container thead th .sortable {
padding-right: 0;
}
.dropdown-submenu {
position: relative;
}
... ...
... ... @@ -103,20 +103,8 @@ define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
},
refreshmenu: function () {
top.window.$(".sidebar-menu").trigger("refresh");
}
},
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() || {});
},
gettablecolumnbutton: function(options){
if (typeof options.tableId !== 'undefined' && typeof options.fieldIndex !== 'undefined' && typeof options.buttonIndex !== 'undefined') {
var tableOptions = $("#" + options.tableId).bootstrapTable('getOptions');
if (tableOptions) {
... ... @@ -133,20 +121,38 @@ define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
}
});
if (columnObj) {
var button = columnObj['buttons'][options.buttonIndex];
if (button && typeof button.callback === 'function') {
options.callback = button.callback;
}
return columnObj['buttons'][options.buttonIndex];
}
}
}
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') {
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);
});
} else {
Backend.api.open(Backend.api.replaceids(that, $(that).attr('href')), $(that).attr('title'), options);
Backend.api.open(url, title, options);
}
return false;
});
... ... @@ -154,15 +160,16 @@ define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
$(document).on('click', '.btn-addtabs,.addtabsit', 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');
if (typeof options.confirm !== 'undefined') {
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);
});
} else {
Backend.api.addtabs(Backend.api.replaceids(that, $(that).attr('href')), $(that).attr("title"));
Backend.api.addtabs(url, title);
}
return false;
});
//点击包含.btn-ajax的元素时发送Ajax请求
... ... @@ -177,30 +184,13 @@ define(['fast', 'template', 'moment'], function (Fast, Template, Moment) {
var error = typeof options.error === 'function' ? options.error : null;
delete options.success;
delete options.error;
if (typeof options.tableId !== 'undefined' && typeof options.fieldIndex !== 'undefined' && typeof options.buttonIndex !== 'undefined') {
var tableOptions = $("#" + options.tableId).bootstrapTable('getOptions');
if (tableOptions) {
var columnObj = null;
$.each(tableOptions.columns, function (i, columns) {
$.each(columns, function (j, column) {
if (typeof column.fieldIndex !== 'undefined' && column.fieldIndex === options.fieldIndex) {
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;
}
}
var button = Backend.api.gettablecolumnbutton(options);
if (button) {
if (typeof button.success === 'function') {
success = button.success;
}
if (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) {
$(".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);
... ...
... ... @@ -49,13 +49,78 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
url: $.fn.bootstrapTable.defaults.extend.index_url,
columns: [
[
{field: 'id', title: 'ID', operate: false},
{field: 'name', title: __('Name'), operate: false},
{field: 'title', title: __('Title'), operate: 'LIKE'}
{field: 'id', title: 'ID', operate: false, visible: false},
{
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',
templateView: true,
templateView: false,
clickToSelect: false,
search: true,
showColumns: false,
showToggle: false,
... ... @@ -71,41 +136,6 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
// 为表格绑定事件
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) {
Upload.api.plupload("#plupload-addon", function (data, ret) {
... ... @@ -224,22 +254,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
Layer.closeAll();
Config['addons'][data.addon.name] = ret.data.addon;
Layer.alert(__('Online installed tips'), {
btn: [__('OK'), __('Donate')],
btn: [__('OK')],
title: __('Warning'),
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,
});
}
icon: 1
});
$('.btn-refresh').trigger('click');
Fast.api.refreshmenu();
... ... @@ -261,17 +278,12 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
}
});
} else if (ret && ret.code === -2) {
//跳转支付
Layer.alert(__('Pay click tips'), {
btn: [__('Pay now'), __('Cancel')],
icon: 0,
success: function (layero) {
$(".layui-layer-btn0", layero).attr("href", ret.data.payurl).attr("target", "_blank");
Fast.api.open(ret.data.payurl, __('Pay now'), {
area: ["650px", "700px"],
end: function () {
Layer.alert(__('Pay tips'));
}
}, function () {
Layer.alert(__('Pay new window tips'), {icon: 0});
});
} else if (ret && ret.code === -3) {
//插件目录发现影响全局的文件
Layer.open({
... ... @@ -408,7 +420,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], 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 () {
uninstall(name, false);
});
... ... @@ -422,18 +438,18 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], 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");
operate(name, action, false);
});
// 点击升级
$(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});
return false;
}
var name = $(this).closest(".operate").data("name");
var version = $(this).data("version");
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 () {
$(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 () {
Controller.api.bindevent();
... ... @@ -452,6 +483,39 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
Controller.api.bindevent();
},
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 () {
Form.api.bindevent($("form[role=form]"));
},
... ...
... ... @@ -15,6 +15,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
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({
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: 'email', title: __('Email')},
{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) {
if(row.id == Config.admin.id){
return '';
... ...
... ... @@ -27,7 +27,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
{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: '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,
events: Table.api.events.operate,
buttons: [{
... ...
... ... @@ -30,6 +30,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'jstree'], function (
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({
url: $.fn.bootstrapTable.defaults.extend.index_url,
... ...
... ... @@ -23,16 +23,32 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
escape: false,
columns: [
[
{field: 'state', checkbox: true, },
{field: 'state', checkbox: true,},
{field: 'id', title: 'ID'},
{field: 'title', title: __('Title'), align: 'left', formatter: Controller.api.formatter.title},
{field: 'icon', title: __('Icon'), formatter: Controller.api.formatter.icon},
{field: 'name', title: __('Name'), align: 'left', formatter: Controller.api.formatter.name},
{field: 'weigh', title: __('Weigh')},
{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: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
{
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: 'operate',
title: __('Operate'),
table: table,
events: Table.api.events.operate,
formatter: Table.api.formatter.operate
}
]
],
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;
},
menu: function (value, row, index) {
return "<a href='javascript:;' class='btn btn-" + (value ? "info" : "default") + " btn-xs btn-change' data-id='"
+ row.id + "' data-params='ismenu=" + (value ? 0 : 1) + "'>" + (value ? __('Yes') : __('No')) + "</a>";
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>";
},
icon: function (value, row, index) {
return '<span class="' + (!row.ismenu || row.status == 'hidden' ? 'text-muted' : '') + '"><i class="' + value + '"></i></span>';
},
subnode: function (value, row, index) {
return '<a href="javascript:;" 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>';
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>';
}
},
bindevent: function () {
... ... @@ -121,6 +137,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
$("input[name='row[ismenu]']:checked").trigger("click");
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) {
Fast.api.refreshmenu();
});
... ... @@ -132,18 +155,10 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
while ((result = exp.exec(ret)) != null) {
iconlist.push(result[1]);
}
Layer.open({
type: 1,
area: ['460px', '300px'], //宽高
content: Template('chooseicontpl', {iconlist: iconlist})
});
iconfunc();
});
} else {
Layer.open({
type: 1,
area: ['460px', '300px'], //宽高
content: Template('chooseicontpl', {iconlist: iconlist})
});
iconfunc();
}
});
$(document).on('click', '#chooseicon ul li', function () {
... ...
... ... @@ -22,18 +22,31 @@ define(['jquery', 'bootstrap', 'backend', 'form', 'table'], function ($, undefin
sortName: 'id',
columns: [
[
{field: 'state', checkbox: true, },
{field: 'state', checkbox: true,},
{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: 'imagewidth', title: __('Imagewidth')},
{field: 'imageheight', title: __('Imageheight')},
{field: 'imagetype', title: __('Imagetype')},
{field: 'storage', title: __('Storage')},
{field: 'filesize', title: __('Filesize')},
{field: 'mimetype', title: __('Mimetype')},
{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: 'imagewidth', title: __('Imagewidth'), sortable: true},
{field: 'imageheight', title: __('Imageheight'), sortable: true},
{field: 'imagetype', title: __('Imagetype'), formatter:Table.api.formatter.search},
{field: 'storage', title: __('Storage'), formatter: Table.api.formatter.search},
{field: 'filesize', title: __('Filesize'), operate: 'BETWEEN', sortable: true},
{field: 'mimetype', title: __('Mimetype'), formatter:Table.api.formatter.search},
{
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',
columns: [
[
{field: 'state', checkbox: true, },
{field: 'state', checkbox: true,},
{field: 'id', title: __('Id')},
{field: 'url', title: __('Preview'), formatter: Controller.api.formatter.thumb},
{field: 'imagewidth', title: __('Imagewidth')},
{field: 'imageheight', title: __('Imageheight')},
{field: 'mimetype', title: __('Mimetype'), operate: 'LIKE %...%',
{
field: 'mimetype', title: __('Mimetype'), operate: 'LIKE %...%',
process: function (value, arg) {
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) {
var multiple = Backend.api.query('multiple');
multiple = multiple == 'true' ? true : false;
... ... @@ -76,7 +92,8 @@ define(['jquery', 'bootstrap', 'backend', 'form', 'table'], function ($, undefin
},
}, formatter: function () {
return '<a href="javascript:;" class="btn btn-danger btn-chooseone btn-xs"><i class="fa fa-check"></i> ' + __('Choose') + '</a>';
}}
}
}
]
]
});
... ...
... ... @@ -29,7 +29,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
{field: 'intro', title: __('Intro')},
{field: 'group', title: __('Group')},
{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>');
$(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 () {
... ...
... ... @@ -27,8 +27,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'upload'], function (
{field: 'id', title: 'ID'},
{field: 'title', title: __('Title')},
{field: 'url', title: __('Url'), align: 'left', formatter: Table.api.formatter.url},
{field: 'ip', title: __('ip')},
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime},
{field: 'ip', title: __('ip'), formatter:Table.api.formatter.search},
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
]
],
commonSearch: false
... ...
... ... @@ -41,8 +41,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'jstree'], function (
{checkbox: true},
{field: 'id', title: __('Id')},
{field: 'name', title: __('Name')},
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime},
{field: 'updatetime', title: __('Updatetime'), 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, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{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}
]
... ...
... ... @@ -31,8 +31,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
{field: 'name', title: __('Name'), align: 'left'},
{field: 'remark', title: __('Remark')},
{field: 'ismenu', title: __('Ismenu'), formatter: Controller.api.formatter.toggle},
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, visible: false},
{field: 'updatetime', title: __('Updatetime'), 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, operate: 'RANGE', addclass: 'datetimerange', sortable: true, visible: false},
{field: 'weigh', title: __('Weigh')},
{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}
... ...
... ... @@ -105,7 +105,7 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, undefine
}
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
results = regex.exec(url);
if (!results)
return null;
if (!results[2])
... ... @@ -134,31 +134,42 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, undefine
$(layero).data("callback", that.callback);
//$(layero).removeClass("layui-layer-border");
Layer.setTop(layero);
var frame = Layer.getChildFrame('html', index);
var layerfooter = frame.find(".layer-footer");
Fast.api.layerfooter(layero, index, that);
try {
var frame = Layer.getChildFrame('html', index);
var layerfooter = frame.find(".layer-footer");
Fast.api.layerfooter(layero, index, that);
//绑定事件
if (layerfooter.size() > 0) {
// 监听窗口内的元素及属性变化
// Firefox和Chrome早期版本中带有前缀
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
if (MutationObserver) {
// 选择目标节点
var target = layerfooter[0];
// 创建观察者对象
var observer = new MutationObserver(function (mutations) {
Fast.api.layerfooter(layero, index, that);
mutations.forEach(function (mutation) {
//绑定事件
if (layerfooter.size() > 0) {
// 监听窗口内的元素及属性变化
// Firefox和Chrome早期版本中带有前缀
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
if (MutationObserver) {
// 选择目标节点
var target = layerfooter[0];
// 创建观察者对象
var observer = new MutationObserver(function (mutations) {
Fast.api.layerfooter(layero, index, that);
mutations.forEach(function (mutation) {
});
});
});
// 配置观察选项:
var config = {attributes: true, childList: true, characterData: true, subtree: true}
// 传入目标节点和观察选项
observer.observe(target, config);
// 随后,你还可以停止观察
// observer.disconnect();
// 配置观察选项:
var config = {attributes: true, childList: true, characterData: true, subtree: true}
// 传入目标节点和观察选项
observer.observe(target, config);
// 随后,你还可以停止观察
// observer.disconnect();
}
}
} catch (e) {
}
if ($(layero).height() > $(window).height()) {
//当弹出窗口大于浏览器可视高度时,重定位
Layer.style(index, {
top: 0,
height: $(window).height()
});
}
}
}, options ? options : {});
... ... @@ -234,8 +245,8 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, undefine
},
lang: function () {
var args = arguments,
string = args[0],
i = 1;
string = args[0],
i = 1;
string = string.toLowerCase();
//string = typeof Lang[string] != 'undefined' ? Lang[string] : string;
if (typeof Lang[string] != 'undefined') {
... ...
... ... @@ -49,7 +49,9 @@ define(['fast', 'template'], function (Fast, Template) {
return false;
});
//tooltip和popover
$('body').tooltip({selector: '[data-toggle="tooltip"]'});
$('body').tooltip({selector: '[data-toggle="popover"]'});
}
};
Frontend.api = $.extend(Fast.api, Frontend.api);
... ...
... ... @@ -759,7 +759,7 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
}
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
results = regex.exec(url);
if (!results)
return null;
if (!results[2])
... ... @@ -788,31 +788,42 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
$(layero).data("callback", that.callback);
//$(layero).removeClass("layui-layer-border");
Layer.setTop(layero);
var frame = Layer.getChildFrame('html', index);
var layerfooter = frame.find(".layer-footer");
Fast.api.layerfooter(layero, index, that);
//绑定事件
if (layerfooter.size() > 0) {
// 监听窗口内的元素及属性变化
// Firefox和Chrome早期版本中带有前缀
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
if (MutationObserver) {
// 选择目标节点
var target = layerfooter[0];
// 创建观察者对象
var observer = new MutationObserver(function (mutations) {
Fast.api.layerfooter(layero, index, that);
mutations.forEach(function (mutation) {
try {
var frame = Layer.getChildFrame('html', index);
var layerfooter = frame.find(".layer-footer");
Fast.api.layerfooter(layero, index, that);
//绑定事件
if (layerfooter.size() > 0) {
// 监听窗口内的元素及属性变化
// Firefox和Chrome早期版本中带有前缀
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
if (MutationObserver) {
// 选择目标节点
var target = layerfooter[0];
// 创建观察者对象
var observer = new MutationObserver(function (mutations) {
Fast.api.layerfooter(layero, index, that);
mutations.forEach(function (mutation) {
});
});
});
// 配置观察选项:
var config = {attributes: true, childList: true, characterData: true, subtree: true}
// 传入目标节点和观察选项
observer.observe(target, config);
// 随后,你还可以停止观察
// observer.disconnect();
// 配置观察选项:
var config = {attributes: true, childList: true, characterData: true, subtree: true}
// 传入目标节点和观察选项
observer.observe(target, config);
// 随后,你还可以停止观察
// observer.disconnect();
}
}
} catch (e) {
}
if ($(layero).height() > $(window).height()) {
//当弹出窗口大于浏览器可视高度时,重定位
Layer.style(index, {
top: 0,
height: $(window).height()
});
}
}
}, options ? options : {});
... ... @@ -888,8 +899,8 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
},
lang: function () {
var args = arguments,
string = args[0],
i = 1;
string = args[0],
i = 1;
string = string.toLowerCase();
//string = typeof Lang[string] != 'undefined' ? Lang[string] : string;
if (typeof Lang[string] != 'undefined') {
... ... @@ -5318,20 +5329,8 @@ define('backend',['fast', 'template', 'moment'], function (Fast, Template, Momen
},
refreshmenu: function () {
top.window.$(".sidebar-menu").trigger("refresh");
}
},
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() || {});
},
gettablecolumnbutton: function(options){
if (typeof options.tableId !== 'undefined' && typeof options.fieldIndex !== 'undefined' && typeof options.buttonIndex !== 'undefined') {
var tableOptions = $("#" + options.tableId).bootstrapTable('getOptions');
if (tableOptions) {
... ... @@ -5348,20 +5347,38 @@ define('backend',['fast', 'template', 'moment'], function (Fast, Template, Momen
}
});
if (columnObj) {
var button = columnObj['buttons'][options.buttonIndex];
if (button && typeof button.callback === 'function') {
options.callback = button.callback;
}
return columnObj['buttons'][options.buttonIndex];
}
}
}
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') {
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);
});
} else {
Backend.api.open(Backend.api.replaceids(that, $(that).attr('href')), $(that).attr('title'), options);
Backend.api.open(url, title, options);
}
return false;
});
... ... @@ -5369,15 +5386,16 @@ define('backend',['fast', 'template', 'moment'], function (Fast, Template, Momen
$(document).on('click', '.btn-addtabs,.addtabsit', 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');
if (typeof options.confirm !== 'undefined') {
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);
});
} else {
Backend.api.addtabs(Backend.api.replaceids(that, $(that).attr('href')), $(that).attr("title"));
Backend.api.addtabs(url, title);
}
return false;
});
//点击包含.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;
delete options.success;
delete options.error;
if (typeof options.tableId !== 'undefined' && typeof options.fieldIndex !== 'undefined' && typeof options.buttonIndex !== 'undefined') {
var tableOptions = $("#" + options.tableId).bootstrapTable('getOptions');
if (tableOptions) {
var columnObj = null;
$.each(tableOptions.columns, function (i, columns) {
$.each(columns, function (j, column) {
if (typeof column.fieldIndex !== 'undefined' && column.fieldIndex === options.fieldIndex) {
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;
}
}
var button = Backend.api.gettablecolumnbutton(options);
if (button) {
if (typeof button.success === 'function') {
success = button.success;
}
if (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) {
$(".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);
... ... @@ -8434,10 +8448,10 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
},
valid: function (ret) {
var that = this, submitBtn = $(".layer-footer [type=submit]", form);
that.holdSubmit();
$(".layer-footer [type=submit]", form).addClass("disabled");
that.holdSubmit(true);
submitBtn.addClass("disabled");
//验证通过提交表单
Form.api.submit($(ret), function (data, ret) {
var submitResult = Form.api.submit($(ret), function (data, ret) {
that.holdSubmit(false);
submitBtn.removeClass("disabled");
if (false === $(this).triggerHandler("success.form", [data, ret])) {
... ... @@ -8467,6 +8481,11 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
}
}
}, submit);
//如果提交失败则释放锁定
if (!submitResult) {
that.holdSubmit(false);
submitBtn.removeClass("disabled");
}
return false;
}
}, form.data("validator-options") || {}));
... ... @@ -8650,7 +8669,6 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
var textarea = $("textarea[name='" + name + "']", form);
var container = textarea.closest("dl");
var template = container.data("template");
console.log(name, container);
$.each($("input,select", container).serializeArray(), function (i, j) {
var reg = /\[(\w+)\]\[(\w+)\]$/g;
var match = reg.exec(j.name);
... ... @@ -8739,10 +8757,12 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
},
api: {
submit: function (form, success, error, submit) {
if (form.size() === 0)
return Toastr.error("表单未初始化完成,无法提交");
if (form.size() === 0) {
Toastr.error("表单未初始化完成,无法提交");
return false;
}
if (typeof submit === 'function') {
if (false === submit.call(form)) {
if (false === submit.call(form, success, error)) {
return false;
}
}
... ... @@ -8802,7 +8822,7 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
}
}
});
return false;
return true;
},
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'],
pagination: true,
clickToSelect: true, //是否启用点击选中
dblClickToEdit: true, //是否启用双击编辑
singleSelect: false, //是否启用单选
showRefresh: false,
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.config.refreshbtn, toolbar).find(".fa").addClass("fa-spin");
});
//当双击单元格时
table.on('dbl-click-row.bs.table', function (e, row, element, field) {
$(Table.config.editonebtn, element).trigger("click");
});
if (options.dblClickToEdit) {
//当双击单元格时
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.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>';
},
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) {
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',
icon: 'fa fa-arrows',
title: __('Drag to sort'),
extend: 'data-toggle="tooltip"',
classname: 'btn btn-xs btn-primary btn-dragsort'
});
}
... ... @@ -9767,6 +9791,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
name: 'edit',
icon: 'fa fa-pencil',
title: __('Edit'),
extend: 'data-toggle="tooltip"',
classname: 'btn btn-xs btn-success btn-editone',
url: options.extend.edit_url
});
... ... @@ -9776,6 +9801,7 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
name: 'del',
icon: 'fa fa-trash',
title: __('Del'),
extend: 'data-toggle="tooltip"',
classname: 'btn btn-xs btn-danger btn-delone'
});
}
... ... @@ -10338,7 +10364,11 @@ $.fn.addtabs = function (options) {
document.title = title;
if (history.pushState && !$(this).data("pushstate")) {
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);
_add.call(this, {
... ...
... ... @@ -39,10 +39,10 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
},
valid: function (ret) {
var that = this, submitBtn = $(".layer-footer [type=submit]", form);
that.holdSubmit();
$(".layer-footer [type=submit]", form).addClass("disabled");
that.holdSubmit(true);
submitBtn.addClass("disabled");
//验证通过提交表单
Form.api.submit($(ret), function (data, ret) {
var submitResult = Form.api.submit($(ret), function (data, ret) {
that.holdSubmit(false);
submitBtn.removeClass("disabled");
if (false === $(this).triggerHandler("success.form", [data, ret])) {
... ... @@ -72,6 +72,11 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
}
}
}, submit);
//如果提交失败则释放锁定
if (!submitResult) {
that.holdSubmit(false);
submitBtn.removeClass("disabled");
}
return false;
}
}, form.data("validator-options") || {}));
... ... @@ -255,7 +260,6 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
var textarea = $("textarea[name='" + name + "']", form);
var container = textarea.closest("dl");
var template = container.data("template");
console.log(name, container);
$.each($("input,select", container).serializeArray(), function (i, j) {
var reg = /\[(\w+)\]\[(\w+)\]$/g;
var match = reg.exec(j.name);
... ... @@ -344,10 +348,12 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
},
api: {
submit: function (form, success, error, submit) {
if (form.size() === 0)
return Toastr.error("表单未初始化完成,无法提交");
if (form.size() === 0) {
Toastr.error("表单未初始化完成,无法提交");
return false;
}
if (typeof submit === 'function') {
if (false === submit.call(form)) {
if (false === submit.call(form, success, error)) {
return false;
}
}
... ... @@ -407,7 +413,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
}
}
});
return false;
return true;
},
bindevent: function (form, success, error, submit) {
... ...
... ... @@ -759,7 +759,7 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
}
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
results = regex.exec(url);
if (!results)
return null;
if (!results[2])
... ... @@ -788,31 +788,42 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
$(layero).data("callback", that.callback);
//$(layero).removeClass("layui-layer-border");
Layer.setTop(layero);
var frame = Layer.getChildFrame('html', index);
var layerfooter = frame.find(".layer-footer");
Fast.api.layerfooter(layero, index, that);
//绑定事件
if (layerfooter.size() > 0) {
// 监听窗口内的元素及属性变化
// Firefox和Chrome早期版本中带有前缀
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
if (MutationObserver) {
// 选择目标节点
var target = layerfooter[0];
// 创建观察者对象
var observer = new MutationObserver(function (mutations) {
Fast.api.layerfooter(layero, index, that);
mutations.forEach(function (mutation) {
try {
var frame = Layer.getChildFrame('html', index);
var layerfooter = frame.find(".layer-footer");
Fast.api.layerfooter(layero, index, that);
//绑定事件
if (layerfooter.size() > 0) {
// 监听窗口内的元素及属性变化
// Firefox和Chrome早期版本中带有前缀
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
if (MutationObserver) {
// 选择目标节点
var target = layerfooter[0];
// 创建观察者对象
var observer = new MutationObserver(function (mutations) {
Fast.api.layerfooter(layero, index, that);
mutations.forEach(function (mutation) {
});
});
});
// 配置观察选项:
var config = {attributes: true, childList: true, characterData: true, subtree: true}
// 传入目标节点和观察选项
observer.observe(target, config);
// 随后,你还可以停止观察
// observer.disconnect();
// 配置观察选项:
var config = {attributes: true, childList: true, characterData: true, subtree: true}
// 传入目标节点和观察选项
observer.observe(target, config);
// 随后,你还可以停止观察
// observer.disconnect();
}
}
} catch (e) {
}
if ($(layero).height() > $(window).height()) {
//当弹出窗口大于浏览器可视高度时,重定位
Layer.style(index, {
top: 0,
height: $(window).height()
});
}
}
}, options ? options : {});
... ... @@ -888,8 +899,8 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
},
lang: function () {
var args = arguments,
string = args[0],
i = 1;
string = args[0],
i = 1;
string = string.toLowerCase();
//string = typeof Lang[string] != 'undefined' ? Lang[string] : string;
if (typeof Lang[string] != 'undefined') {
... ... @@ -1028,7 +1039,9 @@ define('frontend',['fast', 'template'], function (Fast, Template) {
return false;
});
//tooltip和popover
$('body').tooltip({selector: '[data-toggle="tooltip"]'});
$('body').tooltip({selector: '[data-toggle="popover"]'});
}
};
Frontend.api = $.extend(Fast.api, Frontend.api);
... ...
... ... @@ -20,6 +20,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
pageList: [10, 25, 50, 'All'],
pagination: true,
clickToSelect: true, //是否启用点击选中
dblClickToEdit: true, //是否启用双击编辑
singleSelect: false, //是否启用单选
showRefresh: false,
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.config.refreshbtn, toolbar).find(".fa").addClass("fa-spin");
});
//当双击单元格时
table.on('dbl-click-row.bs.table', function (e, row, element, field) {
$(Table.config.editonebtn, element).trigger("click");
});
if (options.dblClickToEdit) {
//当双击单元格时
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.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>';
},
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) {
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',
icon: 'fa fa-arrows',
title: __('Drag to sort'),
extend: 'data-toggle="tooltip"',
classname: 'btn btn-xs btn-primary btn-dragsort'
});
}
... ... @@ -461,6 +465,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
name: 'edit',
icon: 'fa fa-pencil',
title: __('Edit'),
extend: 'data-toggle="tooltip"',
classname: 'btn btn-xs btn-success btn-editone',
url: options.extend.edit_url
});
... ... @@ -470,6 +475,7 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
name: 'del',
icon: 'fa fa-trash',
title: __('Del'),
extend: 'data-toggle="tooltip"',
classname: 'btn btn-xs btn-danger btn-delone'
});
}
... ...
... ... @@ -591,6 +591,9 @@ form.form-horizontal .control-label {
.bootstrap-table td.bs-checkbox {
vertical-align: middle;
}
.fixed-table-container thead th .sortable{
padding-right:0;
}
.dropdown-submenu {
position: relative;
>.dropdown-menu {
... ...