mirror of https://gitee.com/karson/fastadmin.git
新增Token多种存储方式
新增fieldlist自定义模板功能 新增关闭会员中心接口 优化Token存储,采用加密存储方式pull/56/head v1.0.0.20180401_beta
parent
2ecae60d86
commit
39ad7c97a2
|
|
@ -105,7 +105,8 @@ class Index extends Backend
|
|||
{
|
||||
$this->redirect($url);
|
||||
}
|
||||
$background = cdnurl(Config::get('fastadmin.login_background'));
|
||||
$background = Config::get('fastadmin.login_background');
|
||||
$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);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ class Config extends Backend
|
|||
$this->model = model('Config');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$siteList = [];
|
||||
|
|
@ -48,10 +51,6 @@ class Config extends Backend
|
|||
{
|
||||
$value['value'] = explode(',', $value['value']);
|
||||
}
|
||||
if ($value['type'] == 'array')
|
||||
{
|
||||
$value['value'] = (array) json_decode($value['value'], TRUE);
|
||||
}
|
||||
$value['content'] = json_decode($value['content'], TRUE);
|
||||
$siteList[$v['group']]['list'][] = $value;
|
||||
}
|
||||
|
|
@ -119,6 +118,10 @@ class Config extends Backend
|
|||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param null $ids
|
||||
*/
|
||||
public function edit($ids = NULL)
|
||||
{
|
||||
if ($this->request->isPost())
|
||||
|
|
|
|||
|
|
@ -54,20 +54,13 @@
|
|||
<textarea name="row[{$item.name}]" class="form-control editor" data-rule="{$item.rule}" rows="5" data-tip="{$item.tip}" {$item.extend}>{$item.value}</textarea>
|
||||
{/case}
|
||||
{case array}
|
||||
<dl class="fieldlist" rel="{$item.value|count}" data-name="row[{$item.name}]">
|
||||
<dl class="fieldlist" data-name="row[{$item.name}]">
|
||||
<dd>
|
||||
<ins>{:__('Array key')}</ins>
|
||||
<ins>{:__('Array value')}</ins>
|
||||
</dd>
|
||||
{foreach $item.value as $key => $vo}
|
||||
<dd class="form-inline">
|
||||
<input type="text" name="row[{$item.name}][field][{$key}]" class="form-control" value="{$key}" size="10" />
|
||||
<input type="text" name="row[{$item.name}][value][{$key}]" class="form-control" value="{$vo}" size="40" />
|
||||
<span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span>
|
||||
<span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span>
|
||||
</dd>
|
||||
{/foreach}
|
||||
<dd><a href="javascript:;" class="append btn btn-sm btn-success"><i class="fa fa-plus"></i> {:__('Append')}</a></dd>
|
||||
<dd><a href="javascript:;" class="btn btn-sm btn-success btn-append"><i class="fa fa-plus"></i> {:__('Append')}</a></dd>
|
||||
<textarea name="row[{$item.name}]" class="form-control hide" cols="30" rows="5">{$item.value}</textarea>
|
||||
</dl>
|
||||
{/case}
|
||||
{case datetime}
|
||||
|
|
|
|||
|
|
@ -2,84 +2,158 @@
|
|||
|
||||
namespace app\common\library;
|
||||
|
||||
use app\common\library\token\Driver;
|
||||
use think\App;
|
||||
use think\Config;
|
||||
use think\Log;
|
||||
|
||||
/**
|
||||
* Token操作类
|
||||
*/
|
||||
class Token
|
||||
{
|
||||
/**
|
||||
* @var array Token的实例
|
||||
*/
|
||||
public static $instance = [];
|
||||
|
||||
/**
|
||||
* 存储Token
|
||||
* @param string $token Token
|
||||
* @param int $user_id 会员ID
|
||||
* @param int $expire 过期时长,0表示无限,单位秒
|
||||
* @var object 操作句柄
|
||||
*/
|
||||
public static function set($token, $user_id, $expire = 0)
|
||||
public static $handler;
|
||||
|
||||
/**
|
||||
* 连接Token驱动
|
||||
* @access public
|
||||
* @param array $options 配置数组
|
||||
* @param bool|string $name Token连接标识 true 强制重新连接
|
||||
* @return Driver
|
||||
*/
|
||||
public static function connect(array $options = [], $name = false)
|
||||
{
|
||||
$expiretime = $expire ? time() + $expire : 0;
|
||||
\app\common\model\Token::create(['token' => $token, 'user_id' => $user_id, 'expiretime' => $expiretime]);
|
||||
return TRUE;
|
||||
$type = !empty($options['type']) ? $options['type'] : 'File';
|
||||
|
||||
if (false === $name) {
|
||||
$name = md5(serialize($options));
|
||||
}
|
||||
|
||||
if (true === $name || !isset(self::$instance[$name])) {
|
||||
$class = false === strpos($type, '\\') ?
|
||||
'\\app\\common\\library\\token\\driver\\' . ucwords($type) :
|
||||
$type;
|
||||
|
||||
// 记录初始化信息
|
||||
App::$debug && Log::record('[ TOKEN ] INIT ' . $type, 'info');
|
||||
|
||||
if (true === $name) {
|
||||
return new $class($options);
|
||||
}
|
||||
|
||||
self::$instance[$name] = new $class($options);
|
||||
}
|
||||
|
||||
return self::$instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Token内的信息
|
||||
* @param string $token
|
||||
* @return array
|
||||
* 自动初始化Token
|
||||
* @access public
|
||||
* @param array $options 配置数组
|
||||
* @return Driver
|
||||
*/
|
||||
public static function get($token)
|
||||
public static function init(array $options = [])
|
||||
{
|
||||
$data = \app\common\model\Token::get($token);
|
||||
if ($data)
|
||||
{
|
||||
if (!$data['expiretime'] || $data['expiretime'] > time())
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
else
|
||||
{
|
||||
self::delete($token);
|
||||
if (is_null(self::$handler)) {
|
||||
if (empty($options) && 'complex' == Config::get('token.type')) {
|
||||
$default = Config::get('token.default');
|
||||
// 获取默认Token配置,并连接
|
||||
$options = Config::get('token.' . $default['type']) ?: $default;
|
||||
} elseif (empty($options)) {
|
||||
$options = Config::get('token');
|
||||
}
|
||||
|
||||
self::$handler = self::connect($options);
|
||||
}
|
||||
return [];
|
||||
|
||||
return self::$handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断Token是否可用(check别名)
|
||||
* @access public
|
||||
* @param string $token Token标识
|
||||
* @return bool
|
||||
*/
|
||||
public static function has($token, $user_id)
|
||||
{
|
||||
return self::check($token, $user_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断Token是否可用
|
||||
* @param string $token Token
|
||||
* @param int $user_id 会员ID
|
||||
* @return boolean
|
||||
* @param string $token Token标识
|
||||
* @return bool
|
||||
*/
|
||||
public static function check($token, $user_id)
|
||||
{
|
||||
$data = self::get($token);
|
||||
return $data && $data['user_id'] == $user_id ? true : false;
|
||||
return self::init()->check($token, $user_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取Token
|
||||
* @access public
|
||||
* @param string $token Token标识
|
||||
* @param mixed $default 默认值
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get($token, $default = false)
|
||||
{
|
||||
return self::init()->get($token, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入Token
|
||||
* @access public
|
||||
* @param string $token Token标识
|
||||
* @param mixed $user_id 存储数据
|
||||
* @param int|null $expire 有效时间 0为永久
|
||||
* @return boolean
|
||||
*/
|
||||
public static function set($token, $user_id, $expire = null)
|
||||
{
|
||||
return self::init()->set($token, $user_id, $expire);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除Token(delete别名)
|
||||
* @access public
|
||||
* @param string $token Token标识
|
||||
* @return boolean
|
||||
*/
|
||||
public static function rm($token)
|
||||
{
|
||||
return self::delete($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除Token
|
||||
* @param string $token
|
||||
* @return boolean
|
||||
* @param string $token 标签名
|
||||
* @return bool
|
||||
*/
|
||||
public static function delete($token)
|
||||
{
|
||||
$data = \app\common\model\Token::get($token);
|
||||
if ($data)
|
||||
{
|
||||
$data->delete();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return self::init()->delete($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定用户的所有Token
|
||||
* @param int $user_id
|
||||
* @return boolean
|
||||
* 清除Token
|
||||
* @access public
|
||||
* @param string $token Token标记
|
||||
* @return boolean
|
||||
*/
|
||||
public static function clear($user_id)
|
||||
public static function clear($user_id = null)
|
||||
{
|
||||
\app\common\model\Token::where('user_id', $user_id)->delete();
|
||||
return true;
|
||||
return self::init()->clear($user_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* Token模型
|
||||
*/
|
||||
class Token Extends Model
|
||||
{
|
||||
|
||||
// 表名
|
||||
protected $name = 'user_token';
|
||||
// 开启自动写入时间戳字段
|
||||
protected $autoWriteTimestamp = 'int';
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'createtime';
|
||||
protected $updateTime = false;
|
||||
// 定义主键
|
||||
protected $pk = 'token';
|
||||
// 追加属性
|
||||
protected $append = [
|
||||
'expires_in'
|
||||
];
|
||||
|
||||
/**
|
||||
* 获取Token剩余有效期
|
||||
* @return int
|
||||
*/
|
||||
public function getExpiresInAttr($value, $data)
|
||||
{
|
||||
return $data['expiretime'] ? max(0, $data['expiretime'] - time()) : 365 * 86400;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -242,8 +242,23 @@ return [
|
|||
// 验证成功后是否重置
|
||||
'reset' => true
|
||||
],
|
||||
// +----------------------------------------------------------------------
|
||||
// | Token设置
|
||||
// +----------------------------------------------------------------------
|
||||
'token' => [
|
||||
// 驱动方式
|
||||
'type' => 'Redis',
|
||||
// 缓存前缀
|
||||
'key' => 'i3d6o32wo8fvs1fvdpwens',
|
||||
// 加密方式
|
||||
'hashalgo' => 'ripemd160',
|
||||
// 缓存有效期 0表示永久缓存
|
||||
'expire' => 0,
|
||||
],
|
||||
//FastAdmin配置
|
||||
'fastadmin' => [
|
||||
//是否开启前台会员中心
|
||||
'usercenter' => true,
|
||||
//登录验证码
|
||||
'login_captcha' => false,
|
||||
//是否同一账号同一时间只能在一个地方登录
|
||||
|
|
@ -253,7 +268,8 @@ return [
|
|||
//自动检测更新
|
||||
'checkupdate' => false,
|
||||
//版本号
|
||||
'version' => '1.0.0.20180327_beta',
|
||||
'version' => '1.0.0.20180401_beta',
|
||||
//API接口地址
|
||||
'api_url' => 'https://api.fastadmin.net',
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace app\index\controller;
|
||||
|
||||
use app\common\controller\Frontend;
|
||||
use app\common\library\Token;
|
||||
|
||||
class Index extends Frontend
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace app\index\controller;
|
||||
|
||||
use app\common\controller\Frontend;
|
||||
use think\Config;
|
||||
use think\Cookie;
|
||||
use think\Hook;
|
||||
use think\Session;
|
||||
|
|
@ -23,27 +24,30 @@ class User extends Frontend
|
|||
parent::_initialize();
|
||||
$auth = $this->auth;
|
||||
|
||||
if (!Config::get('fastadmin.usercenter')) {
|
||||
$this->error(__('User center already closed'));
|
||||
}
|
||||
|
||||
$ucenter = get_addon_info('ucenter');
|
||||
if ($ucenter && $ucenter['state'])
|
||||
{
|
||||
if ($ucenter && $ucenter['state']) {
|
||||
include ADDON_PATH . 'ucenter' . DS . 'uc.php';
|
||||
}
|
||||
|
||||
//监听注册登录注销的事件
|
||||
Hook::add('user_login_successed', function($user) use($auth) {
|
||||
Hook::add('user_login_successed', function ($user) use ($auth) {
|
||||
$expire = input('post.keeplogin') ? 30 * 86400 : 0;
|
||||
Cookie::set('uid', $user->id, $expire);
|
||||
Cookie::set('token', $auth->getToken(), $expire);
|
||||
});
|
||||
Hook::add('user_register_successed', function($user) use($auth) {
|
||||
Hook::add('user_register_successed', function ($user) use ($auth) {
|
||||
Cookie::set('uid', $user->id);
|
||||
Cookie::set('token', $auth->getToken());
|
||||
});
|
||||
Hook::add('user_delete_successed', function($user) use($auth) {
|
||||
Hook::add('user_delete_successed', function ($user) use ($auth) {
|
||||
Cookie::delete('uid');
|
||||
Cookie::delete('token');
|
||||
});
|
||||
Hook::add('user_logout_successed', function($user) use($auth) {
|
||||
Hook::add('user_logout_successed', function ($user) use ($auth) {
|
||||
Cookie::delete('uid');
|
||||
Cookie::delete('token');
|
||||
});
|
||||
|
|
@ -66,8 +70,7 @@ class User extends Frontend
|
|||
$url = $this->request->request('url', url('user/index'));
|
||||
if ($this->auth->id)
|
||||
$this->success(__('You\'ve logged in, do not login again'), $url);
|
||||
if ($this->request->isPost())
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
$username = $this->request->post('username');
|
||||
$password = $this->request->post('password');
|
||||
$email = $this->request->post('email');
|
||||
|
|
@ -103,23 +106,18 @@ class User extends Frontend
|
|||
];
|
||||
$validate = new Validate($rule, $msg);
|
||||
$result = $validate->check($data);
|
||||
if (!$result)
|
||||
{
|
||||
if (!$result) {
|
||||
$this->error(__($validate->getError()));
|
||||
}
|
||||
if ($this->auth->register($username, $password, $email, $mobile))
|
||||
{
|
||||
if ($this->auth->register($username, $password, $email, $mobile)) {
|
||||
$synchtml = '';
|
||||
////////////////同步到Ucenter////////////////
|
||||
if (defined('UC_STATUS') && UC_STATUS)
|
||||
{
|
||||
if (defined('UC_STATUS') && UC_STATUS) {
|
||||
$uc = new \addons\ucenter\library\client\Client();
|
||||
$synchtml = $uc->uc_user_synregister($this->auth->id, $password);
|
||||
}
|
||||
$this->success(__('Sign up successful') . $synchtml, $url);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$this->error($this->auth->getError());
|
||||
}
|
||||
}
|
||||
|
|
@ -136,11 +134,10 @@ class User extends Frontend
|
|||
$url = $this->request->request('url', url('user/index'));
|
||||
if ($this->auth->id)
|
||||
$this->success(__('You\'ve logged in, do not login again'), $url);
|
||||
if ($this->request->isPost())
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
$account = $this->request->post('account');
|
||||
$password = $this->request->post('password');
|
||||
$keeplogin = (int) $this->request->post('keeplogin');
|
||||
$keeplogin = (int)$this->request->post('keeplogin');
|
||||
$token = $this->request->post('__token__');
|
||||
$rule = [
|
||||
'account' => 'require|length:3,50',
|
||||
|
|
@ -161,24 +158,19 @@ class User extends Frontend
|
|||
];
|
||||
$validate = new Validate($rule, $msg);
|
||||
$result = $validate->check($data);
|
||||
if (!$result)
|
||||
{
|
||||
if (!$result) {
|
||||
$this->error(__($validate->getError()));
|
||||
return FALSE;
|
||||
}
|
||||
if ($this->auth->login($account, $password))
|
||||
{
|
||||
if ($this->auth->login($account, $password)) {
|
||||
$synchtml = '';
|
||||
////////////////同步到Ucenter////////////////
|
||||
if (defined('UC_STATUS') && UC_STATUS)
|
||||
{
|
||||
if (defined('UC_STATUS') && UC_STATUS) {
|
||||
$uc = new \addons\ucenter\library\client\Client();
|
||||
$synchtml = $uc->uc_user_synlogin($this->auth->id);
|
||||
}
|
||||
$this->success(__('Logged in successful') . $synchtml, $url);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$this->error($this->auth->getError());
|
||||
}
|
||||
}
|
||||
|
|
@ -195,8 +187,7 @@ class User extends Frontend
|
|||
$this->auth->logout();
|
||||
$synchtml = '';
|
||||
////////////////同步到Ucenter////////////////
|
||||
if (defined('UC_STATUS') && UC_STATUS)
|
||||
{
|
||||
if (defined('UC_STATUS') && UC_STATUS) {
|
||||
$uc = new \addons\ucenter\library\client\Client();
|
||||
$synchtml = $uc->uc_user_synlogout();
|
||||
}
|
||||
|
|
@ -217,8 +208,7 @@ class User extends Frontend
|
|||
*/
|
||||
public function changepwd()
|
||||
{
|
||||
if ($this->request->isPost())
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
$oldpassword = $this->request->post("oldpassword");
|
||||
$newpassword = $this->request->post("newpassword");
|
||||
$renewpassword = $this->request->post("renewpassword");
|
||||
|
|
@ -245,26 +235,21 @@ class User extends Frontend
|
|||
];
|
||||
$validate = new Validate($rule, $msg, $field);
|
||||
$result = $validate->check($data);
|
||||
if (!$result)
|
||||
{
|
||||
if (!$result) {
|
||||
$this->error(__($validate->getError()));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$ret = $this->auth->changepwd($newpassword, $oldpassword);
|
||||
if ($ret)
|
||||
{
|
||||
if ($ret) {
|
||||
$synchtml = '';
|
||||
////////////////同步到Ucenter////////////////
|
||||
if (defined('UC_STATUS') && UC_STATUS)
|
||||
{
|
||||
if (defined('UC_STATUS') && UC_STATUS) {
|
||||
$uc = new \addons\ucenter\library\client\Client();
|
||||
$synchtml = $uc->uc_user_synlogout();
|
||||
}
|
||||
$this->success(__('Reset password successful') . $synchtml, url('user/login'));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$this->error($this->auth->getError());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ return [
|
|||
'Github' => 'Github',
|
||||
'QQ group' => 'QQ群',
|
||||
'Go to Dashboard' => '登录后台',
|
||||
'Go to Member center' => '会员中心',
|
||||
'Contribution' => '为FastAdmin贡献代码!',
|
||||
'Copyrights' => '版权所有',
|
||||
'Responsive' => '响应式开发',
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ return [
|
|||
'Sign up successful' => '注册成功',
|
||||
'Logged in successful' => '登录成功',
|
||||
'Logout successful' => '注销成功',
|
||||
'User center already closed' => '会员中心已经关闭',
|
||||
'Operation failed' => '操作失败',
|
||||
'Invalid parameters' => '参数不正确',
|
||||
'Change password failure' => '修改密码失败',
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@
|
|||
<div class="header-content-inner">
|
||||
<h1>FastAdmin</h1>
|
||||
<h3>{:__('The fastest framework based on ThinkPHP5 and Bootstrap')}</h3>
|
||||
<a href="{:url('admin/index/login')}" class="btn btn-outline btn-xl page-scroll">{:__('Go to Dashboard')}</a>
|
||||
<a href="{:url('admin/index/login')}" class="btn btn-warning btn-xl page-scroll">{:__('Go to Dashboard')}</a>
|
||||
<a href="{:url('index/user/index')}" class="btn btn-outline btn-xl page-scroll">{:__('Go to Member center')}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11148,6 +11148,7 @@ define('validator',['validator-core', 'validator-lang'], function (Validator, un
|
|||
define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, Upload, Validator) {
|
||||
var Form = {
|
||||
config: {
|
||||
fieldlisttpl: '<dd class="form-inline"><input type="text" name="<%=name%>[<%=index%>][key]" class="form-control" value="<%=row.key%>" size="10" /> <input type="text" name="<%=name%>[<%=index%>][value]" class="form-control" value="<%=row.value%>" size="40" /> <span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span> <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span></dd>'
|
||||
},
|
||||
events: {
|
||||
validator: function (form, success, error, submit) {
|
||||
|
|
@ -11173,7 +11174,7 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
|
|||
},
|
||||
target: function (input) {
|
||||
var $formitem = $(input).closest('.form-group'),
|
||||
$msgbox = $formitem.find('span.msg-box');
|
||||
$msgbox = $formitem.find('span.msg-box');
|
||||
if (!$msgbox.length) {
|
||||
return [];
|
||||
}
|
||||
|
|
@ -11269,7 +11270,8 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
|
|||
citypicker: function (form) {
|
||||
//绑定城市远程插件
|
||||
if ($("[data-toggle='city-picker']", form).size() > 0) {
|
||||
require(['citypicker'], function () {});
|
||||
require(['citypicker'], function () {
|
||||
});
|
||||
}
|
||||
},
|
||||
datetimepicker: function (form) {
|
||||
|
|
@ -11387,27 +11389,90 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
|
|||
}
|
||||
},
|
||||
fieldlist: function (form) {
|
||||
//绑定fieldlist
|
||||
if ($(".fieldlist", form).size() > 0) {
|
||||
$(".fieldlist", form).on("click", ".append", function () {
|
||||
var rel = parseInt($(this).closest("dl").attr("rel")) + 1;
|
||||
var name = $(this).closest("dl").data("name");
|
||||
$(this).closest("dl").attr("rel", rel);
|
||||
$('<dd class="form-inline"><input type="text" name="' + name + '[field][' + rel + ']" class="form-control" value="" size="10" /> <input type="text" name="' + name + '[value][' + rel + ']" class="form-control" value="" size="40" /> <span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span> <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span></dd>').insertBefore($(this).parent());
|
||||
});
|
||||
$(".fieldlist", form).on("click", "dd .btn-remove", function () {
|
||||
$(this).parent().remove();
|
||||
});
|
||||
//拖拽排序
|
||||
require(['dragsort'], function () {
|
||||
//绑定拖动排序
|
||||
require(['dragsort', 'template'], function (undefined, Template) {
|
||||
//刷新隐藏textarea的值
|
||||
var refresh = function (name) {
|
||||
var data = {};
|
||||
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);
|
||||
if (!match)
|
||||
return true;
|
||||
match[1] = "x" + parseInt(match[1]);
|
||||
if (typeof data[match[1]] == 'undefined') {
|
||||
data[match[1]] = {};
|
||||
}
|
||||
data[match[1]][match[2]] = j.value;
|
||||
});
|
||||
var result = template ? [] : {};
|
||||
$.each(data, function (i, j) {
|
||||
if (j) {
|
||||
if (!template) {
|
||||
if (j.key != '') {
|
||||
result[j.key] = j.value;
|
||||
}
|
||||
} else {
|
||||
result.push(j);
|
||||
}
|
||||
}
|
||||
});
|
||||
textarea.val(JSON.stringify(result));
|
||||
};
|
||||
//监听文本框改变事件
|
||||
$(document).on('change keyup', ".fieldlist input,.fieldlist textarea,.fieldlist select", function () {
|
||||
refresh($(this).closest("dl").data("name"));
|
||||
});
|
||||
//追加控制
|
||||
$(".fieldlist", form).on("click", ".btn-append", function (e, row) {
|
||||
var container = $(this).closest("dl");
|
||||
var index = container.data("index");
|
||||
var name = container.data("name");
|
||||
var template = container.data("template");
|
||||
var data = container.data();
|
||||
index = index ? parseInt(index) : 0;
|
||||
container.data("index", index + 1);
|
||||
var row = row ? row : {};
|
||||
var vars = {index: index, name: name, data: data, row: row};
|
||||
var html = template ? Template(template, vars) : Template.render(Form.config.fieldlisttpl, vars);
|
||||
$(html).insertBefore($(this).closest("dd"));
|
||||
$(this).trigger("fa.event.appendfieldlist", $(this).closest("dd").prev());
|
||||
});
|
||||
//移除控制
|
||||
$(".fieldlist", form).on("click", "dd .btn-remove", function () {
|
||||
var container = $(this).closest("dl");
|
||||
$(this).closest("dd").remove();
|
||||
refresh(container.data("name"));
|
||||
});
|
||||
//拖拽排序
|
||||
$("dl.fieldlist", form).dragsort({
|
||||
itemSelector: 'dd',
|
||||
dragSelector: ".btn-dragsort",
|
||||
dragSelector: ".btn-fdragsort",
|
||||
dragEnd: function () {
|
||||
|
||||
refresh($(this).closest("dl").data("name"));
|
||||
},
|
||||
placeHolderTemplate: "<dd></dd>"
|
||||
});
|
||||
//渲染数据
|
||||
$(".fieldlist", form).each(function () {
|
||||
var container = this;
|
||||
var textarea = $("textarea[name='" + $(this).data("name") + "']", form);
|
||||
if (textarea.val() == '') {
|
||||
return true;
|
||||
}
|
||||
var template = $(this).data("template");
|
||||
$.each(JSON.parse(textarea.val()), function (i, j) {
|
||||
$(".btn-append", container).trigger('click', template ? j : {
|
||||
key: i,
|
||||
value: j
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, Upload, Validator) {
|
||||
var Form = {
|
||||
config: {
|
||||
fieldlisttpl: '<dd class="form-inline"><input type="text" name="<%=name%>[<%=index%>][key]" class="form-control" value="<%=row.key%>" size="10" /> <input type="text" name="<%=name%>[<%=index%>][value]" class="form-control" value="<%=row.value%>" size="40" /> <span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span> <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span></dd>'
|
||||
},
|
||||
events: {
|
||||
validator: function (form, success, error, submit) {
|
||||
|
|
@ -26,7 +27,7 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
|
|||
},
|
||||
target: function (input) {
|
||||
var $formitem = $(input).closest('.form-group'),
|
||||
$msgbox = $formitem.find('span.msg-box');
|
||||
$msgbox = $formitem.find('span.msg-box');
|
||||
if (!$msgbox.length) {
|
||||
return [];
|
||||
}
|
||||
|
|
@ -122,7 +123,8 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
|
|||
citypicker: function (form) {
|
||||
//绑定城市远程插件
|
||||
if ($("[data-toggle='city-picker']", form).size() > 0) {
|
||||
require(['citypicker'], function () {});
|
||||
require(['citypicker'], function () {
|
||||
});
|
||||
}
|
||||
},
|
||||
datetimepicker: function (form) {
|
||||
|
|
@ -240,27 +242,90 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
|
|||
}
|
||||
},
|
||||
fieldlist: function (form) {
|
||||
//绑定fieldlist
|
||||
if ($(".fieldlist", form).size() > 0) {
|
||||
$(".fieldlist", form).on("click", ".append", function () {
|
||||
var rel = parseInt($(this).closest("dl").attr("rel")) + 1;
|
||||
var name = $(this).closest("dl").data("name");
|
||||
$(this).closest("dl").attr("rel", rel);
|
||||
$('<dd class="form-inline"><input type="text" name="' + name + '[field][' + rel + ']" class="form-control" value="" size="10" /> <input type="text" name="' + name + '[value][' + rel + ']" class="form-control" value="" size="40" /> <span class="btn btn-sm btn-danger btn-remove"><i class="fa fa-times"></i></span> <span class="btn btn-sm btn-primary btn-dragsort"><i class="fa fa-arrows"></i></span></dd>').insertBefore($(this).parent());
|
||||
});
|
||||
$(".fieldlist", form).on("click", "dd .btn-remove", function () {
|
||||
$(this).parent().remove();
|
||||
});
|
||||
//拖拽排序
|
||||
require(['dragsort'], function () {
|
||||
//绑定拖动排序
|
||||
require(['dragsort', 'template'], function (undefined, Template) {
|
||||
//刷新隐藏textarea的值
|
||||
var refresh = function (name) {
|
||||
var data = {};
|
||||
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);
|
||||
if (!match)
|
||||
return true;
|
||||
match[1] = "x" + parseInt(match[1]);
|
||||
if (typeof data[match[1]] == 'undefined') {
|
||||
data[match[1]] = {};
|
||||
}
|
||||
data[match[1]][match[2]] = j.value;
|
||||
});
|
||||
var result = template ? [] : {};
|
||||
$.each(data, function (i, j) {
|
||||
if (j) {
|
||||
if (!template) {
|
||||
if (j.key != '') {
|
||||
result[j.key] = j.value;
|
||||
}
|
||||
} else {
|
||||
result.push(j);
|
||||
}
|
||||
}
|
||||
});
|
||||
textarea.val(JSON.stringify(result));
|
||||
};
|
||||
//监听文本框改变事件
|
||||
$(document).on('change keyup', ".fieldlist input,.fieldlist textarea,.fieldlist select", function () {
|
||||
refresh($(this).closest("dl").data("name"));
|
||||
});
|
||||
//追加控制
|
||||
$(".fieldlist", form).on("click", ".btn-append", function (e, row) {
|
||||
var container = $(this).closest("dl");
|
||||
var index = container.data("index");
|
||||
var name = container.data("name");
|
||||
var template = container.data("template");
|
||||
var data = container.data();
|
||||
index = index ? parseInt(index) : 0;
|
||||
container.data("index", index + 1);
|
||||
var row = row ? row : {};
|
||||
var vars = {index: index, name: name, data: data, row: row};
|
||||
var html = template ? Template(template, vars) : Template.render(Form.config.fieldlisttpl, vars);
|
||||
$(html).insertBefore($(this).closest("dd"));
|
||||
$(this).trigger("fa.event.appendfieldlist", $(this).closest("dd").prev());
|
||||
});
|
||||
//移除控制
|
||||
$(".fieldlist", form).on("click", "dd .btn-remove", function () {
|
||||
var container = $(this).closest("dl");
|
||||
$(this).closest("dd").remove();
|
||||
refresh(container.data("name"));
|
||||
});
|
||||
//拖拽排序
|
||||
$("dl.fieldlist", form).dragsort({
|
||||
itemSelector: 'dd',
|
||||
dragSelector: ".btn-dragsort",
|
||||
dragSelector: ".btn-fdragsort",
|
||||
dragEnd: function () {
|
||||
|
||||
refresh($(this).closest("dl").data("name"));
|
||||
},
|
||||
placeHolderTemplate: "<dd></dd>"
|
||||
});
|
||||
//渲染数据
|
||||
$(".fieldlist", form).each(function () {
|
||||
var container = this;
|
||||
var textarea = $("textarea[name='" + $(this).data("name") + "']", form);
|
||||
if (textarea.val() == '') {
|
||||
return true;
|
||||
}
|
||||
var template = $(this).data("template");
|
||||
$.each(JSON.parse(textarea.val()), function (i, j) {
|
||||
$(".btn-append", container).trigger('click', template ? j : {
|
||||
key: i,
|
||||
value: j
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* 安装完成后建议删除此文件
|
||||
* @author Karson
|
||||
* @website http://www.fastadmin.net
|
||||
* @website https://www.fastadmin.net
|
||||
*/
|
||||
// error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
|
||||
// ini_set('display_errors', '1');
|
||||
|
|
@ -41,9 +41,9 @@ $sitename = "FastAdmin";
|
|||
$link = array(
|
||||
'qqun' => "https://jq.qq.com/?_wv=1027&k=487PNBb",
|
||||
'gitee' => 'https://gitee.com/karson/fastadmin/attach_files',
|
||||
'home' => 'http://www.fastadmin.net?ref=install',
|
||||
'forum' => 'http://forum.fastadmin.net?ref=install',
|
||||
'doc' => 'http://doc.fastadmin.net?ref=install',
|
||||
'home' => 'https://www.fastadmin.net?ref=install',
|
||||
'forum' => 'https://forum.fastadmin.net?ref=install',
|
||||
'doc' => 'https://doc.fastadmin.net?ref=install',
|
||||
);
|
||||
|
||||
// 检测目录是否存在
|
||||
|
|
@ -77,7 +77,7 @@ else if (!extension_loaded("PDO"))
|
|||
}
|
||||
else if (!is_really_writable($dbConfigFile))
|
||||
{
|
||||
$errInfo = '当前权限不足,无法写入配置文件application/database.php<br><a href="http://forum.fastadmin.net/?q=%E6%9D%83%E9%99%90%E4%B8%8D%E8%B6%B3" target="_blank">点击查看解决办法</a>';
|
||||
$errInfo = '当前权限不足,无法写入配置文件application/database.php<br><a href="https://forum.fastadmin.net/?q=%E6%9D%83%E9%99%90%E4%B8%8D%E8%B6%B3" target="_blank">点击查看解决办法</a>';
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -86,7 +86,7 @@ else
|
|||
{
|
||||
if (!is_dir(ROOT_PATH . $v))
|
||||
{
|
||||
$errInfo = '当前代码仅包含核心代码,请前往官网下载完整包或资源包覆盖后再尝试安装,<a href="http://www.fastadmin.net/download.html?ref=install" target="_blank">立即前往下载</a>';
|
||||
$errInfo = '当前代码仅包含核心代码,请前往官网下载完整包或资源包覆盖后再尝试安装,<a href="https://www.fastadmin.net/download.html?ref=install" target="_blank">立即前往下载</a>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue