mirror of https://gitee.com/karson/fastadmin.git
新增邮箱验证码功能
新增Token默认有效期 新增Token检测和刷新API接口 新增前台发送验证码事件监听 修复修改个人资料时跳转的BUG 修复API文档Token设置无效的BUG 修复后台移除左侧链接后菜单消失的BUG 优化前台样式CSS,精简多余的CSS 优化会员登录注册视图模板pull/48/head v1.0.0.20180310_beta
parent
3c09a3f918
commit
45b84424e8
|
|
@ -413,7 +413,7 @@
|
|||
|
||||
var token = $('#token').val();
|
||||
if (token.length > 0) {
|
||||
headers[token] = token;
|
||||
headers['token'] = token;
|
||||
}
|
||||
|
||||
$("#sandbox" + theId + " .headers input[type=text]").each(function () {
|
||||
|
|
|
|||
|
|
@ -337,6 +337,21 @@ INSERT INTO `fa_config` VALUES (16, 'mail_verify_type', 'email', 'Mail vertify t
|
|||
INSERT INTO `fa_config` VALUES (17, 'mail_from', 'email', 'Mail from', '', 'string', '10000@qq.com', '', '', '');
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for fa_ems
|
||||
-- ----------------------------
|
||||
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 '邮箱',
|
||||
`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',
|
||||
`createtime` int(10) UNSIGNED NULL DEFAULT 0 COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='邮箱验证码表';
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for fa_sms
|
||||
-- ----------------------------
|
||||
|
|
@ -412,8 +427,8 @@ CREATE TABLE `fa_user` (
|
|||
`avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '头像',
|
||||
`level` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '等级',
|
||||
`gender` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '性别',
|
||||
`birthday` date NOT NULL COMMENT '生日',
|
||||
`bio` varchar(100) NOT NULL COMMENT '格言',
|
||||
`birthday` date COMMENT '生日',
|
||||
`bio` varchar(100) NOT NULL DEFAULT '' COMMENT '格言',
|
||||
`score` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '积分',
|
||||
`successions` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '连续登录天数',
|
||||
`maxsuccessions` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '最大连续登录天数',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
namespace app\api\controller;
|
||||
|
||||
use app\common\controller\Api;
|
||||
use app\common\library\Ems as Emslib;
|
||||
use app\common\model\User;
|
||||
|
||||
/**
|
||||
* 邮箱验证码接口
|
||||
*/
|
||||
class Ems extends Api
|
||||
{
|
||||
|
||||
protected $noNeedLogin = '*';
|
||||
protected $noNeedRight = '*';
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
\think\Hook::add('ems_send', function($params) {
|
||||
$obj = \app\common\library\Email::instance();
|
||||
$result = $obj
|
||||
->to($params->email)
|
||||
->subject('验证码')
|
||||
->message("你的验证码是:" . $params->code)
|
||||
->send();
|
||||
return $result;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送验证码
|
||||
*
|
||||
* @param string $email 邮箱
|
||||
* @param string $event 事件名称
|
||||
*/
|
||||
public function send()
|
||||
{
|
||||
$email = $this->request->request("email");
|
||||
$event = $this->request->request("event");
|
||||
$event = $event ? $event : 'register';
|
||||
|
||||
$last = Emslib::get($email, $event);
|
||||
if ($last && time() - $last['createtime'] < 60)
|
||||
{
|
||||
$this->error(__('发送频繁'));
|
||||
}
|
||||
if ($event)
|
||||
{
|
||||
$userinfo = User::getByEmail($email);
|
||||
if ($event == 'register' && $userinfo)
|
||||
{
|
||||
//已被注册
|
||||
$this->error(__('已被注册'));
|
||||
}
|
||||
else if (in_array($event, ['changeemail']) && $userinfo)
|
||||
{
|
||||
//被占用
|
||||
$this->error(__('已被占用'));
|
||||
}
|
||||
else if (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo)
|
||||
{
|
||||
//未注册
|
||||
$this->error(__('未注册'));
|
||||
}
|
||||
}
|
||||
$ret = Emslib::send($email, NULL, $event);
|
||||
if ($ret)
|
||||
{
|
||||
$this->success(__('发送成功'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->error(__('发送失败'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测验证码
|
||||
*
|
||||
* @param string $email 邮箱
|
||||
* @param string $event 事件名称
|
||||
* @param string $captcha 验证码
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
$email = $this->request->request("email");
|
||||
$event = $this->request->request("event");
|
||||
$event = $event ? $event : 'register';
|
||||
$captcha = $this->request->request("captcha");
|
||||
|
||||
if ($event)
|
||||
{
|
||||
$userinfo = User::getByEmail($email);
|
||||
if ($event == 'register' && $userinfo)
|
||||
{
|
||||
//已被注册
|
||||
$this->error(__('已被注册'));
|
||||
}
|
||||
else if (in_array($event, ['changeemail']) && $userinfo)
|
||||
{
|
||||
//被占用
|
||||
$this->error(__('已被占用'));
|
||||
}
|
||||
else if (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo)
|
||||
{
|
||||
//未注册
|
||||
$this->error(__('未注册'));
|
||||
}
|
||||
}
|
||||
$ret = Emslib::check($email, $captcha, $event);
|
||||
if ($ret)
|
||||
{
|
||||
$this->success(__('成功'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->error(__('验证码不正确'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ use app\common\library\Sms as Smslib;
|
|||
use app\common\model\User;
|
||||
|
||||
/**
|
||||
* 短信接口
|
||||
* 手机短信接口
|
||||
*/
|
||||
class Sms extends Api
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace app\api\controller;
|
||||
|
||||
use app\common\controller\Api;
|
||||
|
||||
/**
|
||||
* Token接口
|
||||
*/
|
||||
class Token extends Api
|
||||
{
|
||||
|
||||
protected $noNeedLogin = [];
|
||||
protected $noNeedRight = '*';
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测Token是否过期
|
||||
*
|
||||
*/
|
||||
public function check()
|
||||
{
|
||||
$token = $this->auth->getToken();
|
||||
$tokenInfo = \app\common\library\Token::get($token);
|
||||
$this->success('', ['token' => $tokenInfo['token'], 'expires_in' => $tokenInfo['expires_in']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新Token
|
||||
*
|
||||
*/
|
||||
public function refresh()
|
||||
{
|
||||
$token = $this->auth->getToken();
|
||||
$tokenInfo = \app\common\library\Token::get($token);
|
||||
$tokenInfo->expiretime = time() + 2592000;
|
||||
$tokenInfo->save();
|
||||
$this->success('', ['token' => $tokenInfo['token'], 'expires_in' => $tokenInfo['expires_in']]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
namespace app\api\controller;
|
||||
|
||||
use app\common\controller\Api;
|
||||
use app\common\library\Email;
|
||||
use app\common\library\Ems;
|
||||
use app\common\library\Sms;
|
||||
use fast\Random;
|
||||
use think\Validate;
|
||||
|
|
@ -179,12 +179,14 @@ class User extends Api
|
|||
* 修改邮箱
|
||||
*
|
||||
* @param string $email 邮箱
|
||||
* @param string $captcha 验证码
|
||||
*/
|
||||
public function changeemail()
|
||||
{
|
||||
$user = $this->auth->getUser();
|
||||
$email = $this->request->post('email');
|
||||
if (!$email)
|
||||
$captcha = $this->request->request('captcha');
|
||||
if (!$email || !$captcha)
|
||||
{
|
||||
$this->error(__('Invalid parameters'));
|
||||
}
|
||||
|
|
@ -196,17 +198,18 @@ class User extends Api
|
|||
{
|
||||
$this->error(__('Email already exists'));
|
||||
}
|
||||
$result = Ems::check($email, $captcha, 'changeemail');
|
||||
if (!$result)
|
||||
{
|
||||
$this->error(__('Captcha is incorrect'));
|
||||
}
|
||||
$verification = $user->verification;
|
||||
$verification->email = 0;
|
||||
$verification->email = 1;
|
||||
$user->verification = $verification;
|
||||
$user->email = $email;
|
||||
$user->save();
|
||||
$time = time();
|
||||
$code = ['id' => $user->id, 'time' => $time, 'key' => md5(md5($user->id . $user->email . $time) . $user->salt)];
|
||||
$code = base64_encode(http_build_query($code));
|
||||
$url = url("index/user/activeemail", ['code' => $code], true, true);
|
||||
$message = __('Verify email') . ":<a href='{$url}'>{$url}</a>";
|
||||
Email::instance()->to($email)->subject(__('Verify email'))->message($message)->send();
|
||||
|
||||
Ems::flush($email, 'changeemail');
|
||||
$this->success();
|
||||
}
|
||||
|
||||
|
|
@ -291,29 +294,51 @@ class User extends Api
|
|||
*/
|
||||
public function resetpwd()
|
||||
{
|
||||
$type = $this->request->request("type");
|
||||
$mobile = $this->request->request("mobile");
|
||||
$email = $this->request->request("email");
|
||||
$newpassword = $this->request->request("newpassword");
|
||||
$captcha = $this->request->request("captcha");
|
||||
if (!$mobile || !$newpassword || !$captcha)
|
||||
if (!$newpassword || !$captcha)
|
||||
{
|
||||
$this->error(__('Invalid parameters'));
|
||||
}
|
||||
if ($mobile && !Validate::regex($mobile, "^1\d{10}$"))
|
||||
if ($type == 'mobile')
|
||||
{
|
||||
$this->error(__('Mobile is incorrect'));
|
||||
if (!Validate::regex($mobile, "^1\d{10}$"))
|
||||
{
|
||||
$this->error(__('Mobile is incorrect'));
|
||||
}
|
||||
$user = \app\common\model\User::getByMobile($mobile);
|
||||
if (!$user)
|
||||
{
|
||||
$this->error(__('User not found'));
|
||||
}
|
||||
$ret = Sms::check($mobile, $captcha, 'resetpwd');
|
||||
if (!$ret)
|
||||
{
|
||||
$this->error(__('Captcha is incorrect'));
|
||||
}
|
||||
Sms::flush($mobile, 'resetpwd');
|
||||
}
|
||||
$user = \app\common\model\User::getByMobile($mobile);
|
||||
if (!$user)
|
||||
else
|
||||
{
|
||||
$this->error(__('User not found'));
|
||||
if (!Validate::is($email, "email"))
|
||||
{
|
||||
$this->error(__('Email is incorrect'));
|
||||
}
|
||||
$user = \app\common\model\User::getByEmail($email);
|
||||
if (!$user)
|
||||
{
|
||||
$this->error(__('User not found'));
|
||||
}
|
||||
$ret = Ems::check($email, $captcha, 'resetpwd');
|
||||
if (!$ret)
|
||||
{
|
||||
$this->error(__('Captcha is incorrect'));
|
||||
}
|
||||
Ems::flush($email, 'resetpwd');
|
||||
}
|
||||
$ret = Sms::check($mobile, $captcha, 'resetpwd');
|
||||
if (!$ret)
|
||||
{
|
||||
$this->error(__('Captcha is incorrect'));
|
||||
}
|
||||
Sms::flush($mobile, 'resetpwd');
|
||||
|
||||
//模拟一次登录
|
||||
$this->auth->direct($user->id);
|
||||
$ret = $this->auth->changepwd($newpassword, '', true);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class Validate extends Api
|
|||
* 检测邮箱
|
||||
*
|
||||
* @param string $email 邮箱
|
||||
* @param string $id 会员ID
|
||||
* @param string $id 排除会员ID
|
||||
*/
|
||||
public function check_email_available()
|
||||
{
|
||||
|
|
@ -42,7 +42,7 @@ class Validate extends Api
|
|||
* 检测用户名
|
||||
*
|
||||
* @param string $username 用户名
|
||||
* @param string $id 会员ID
|
||||
* @param string $id 排除会员ID
|
||||
*/
|
||||
public function check_username_available()
|
||||
{
|
||||
|
|
@ -60,16 +60,16 @@ class Validate extends Api
|
|||
* 检测手机
|
||||
*
|
||||
* @param string $mobile 手机号
|
||||
* @param string $id 会员ID
|
||||
* @param string $id 排除会员ID
|
||||
*/
|
||||
public function check_mobile_available()
|
||||
{
|
||||
$email = $this->request->request('mobile');
|
||||
$mobile = $this->request->request('mobile');
|
||||
$id = (int) $this->request->request('id');
|
||||
$count = User::where('mobile', '=', $email)->where('id', '<>', $id)->count();
|
||||
$count = User::where('mobile', '=', $mobile)->where('id', '<>', $id)->count();
|
||||
if ($count > 0)
|
||||
{
|
||||
$this->error(__('已经使用该手机号注册'));
|
||||
$this->error(__('该手机号已经占用'));
|
||||
}
|
||||
$this->success();
|
||||
}
|
||||
|
|
@ -81,8 +81,8 @@ class Validate extends Api
|
|||
*/
|
||||
public function check_mobile_exist()
|
||||
{
|
||||
$email = $this->request->request('mobile');
|
||||
$count = User::where('mobile', '=', $email)->count();
|
||||
$mobile = $this->request->request('mobile');
|
||||
$count = User::where('mobile', '=', $mobile)->count();
|
||||
if (!$count)
|
||||
{
|
||||
$this->error(__('手机号不存在'));
|
||||
|
|
@ -91,11 +91,27 @@ class Validate extends Api
|
|||
}
|
||||
|
||||
/**
|
||||
* 检测验证码
|
||||
* 检测邮箱
|
||||
*
|
||||
* @param string $mobile 手机号
|
||||
* @param string $captcha 验证码
|
||||
* @param string $event 事件
|
||||
* @param string $mobile 邮箱
|
||||
*/
|
||||
public function check_email_exist()
|
||||
{
|
||||
$email = $this->request->request('email');
|
||||
$count = User::where('email', '=', $email)->count();
|
||||
if (!$count)
|
||||
{
|
||||
$this->error(__('邮箱不存在'));
|
||||
}
|
||||
$this->success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测手机验证码
|
||||
*
|
||||
* @param string $mobile 手机号
|
||||
* @param string $captcha 验证码
|
||||
* @param string $event 事件
|
||||
*/
|
||||
public function check_sms_correct()
|
||||
{
|
||||
|
|
@ -109,4 +125,23 @@ class Validate extends Api
|
|||
$this->success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测邮箱验证码
|
||||
*
|
||||
* @param string $email 邮箱
|
||||
* @param string $captcha 验证码
|
||||
* @param string $event 事件
|
||||
*/
|
||||
public function check_ems_correct()
|
||||
{
|
||||
$email = $this->request->request('email');
|
||||
$captcha = $this->request->request('captcha');
|
||||
$event = $this->request->request('event');
|
||||
if (!\app\common\library\Ems::check($email, $captcha, $event))
|
||||
{
|
||||
$this->error(__('验证码不正确'));
|
||||
}
|
||||
$this->success();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@ class Auth
|
|||
protected $_logined = FALSE;
|
||||
protected $_user = NULL;
|
||||
protected $_token = '';
|
||||
protected $keeptime = 0;
|
||||
//Token默认有效时长
|
||||
protected $keeptime = 2592000;
|
||||
protected $requestUri = '';
|
||||
protected $rules = [];
|
||||
//默认配置
|
||||
|
|
@ -203,7 +204,7 @@ class Auth
|
|||
|
||||
//设置Token
|
||||
$this->_token = Random::uuid();
|
||||
Token::set($this->_token, $user->id);
|
||||
Token::set($this->_token, $user->id, $this->keeptime);
|
||||
|
||||
//注册成功的事件
|
||||
Hook::listen("user_register_successed", $this->_user);
|
||||
|
|
@ -349,7 +350,7 @@ class Auth
|
|||
$this->_user = $user;
|
||||
|
||||
$this->_token = Random::uuid();
|
||||
Token::set($this->_token, $user->id);
|
||||
Token::set($this->_token, $user->id, $this->keeptime);
|
||||
|
||||
$this->_logined = TRUE;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
namespace app\common\library;
|
||||
|
||||
use think\Hook;
|
||||
|
||||
/**
|
||||
* 邮箱验证码类
|
||||
*/
|
||||
class Ems
|
||||
{
|
||||
|
||||
/**
|
||||
* 验证码有效时长
|
||||
* @var int
|
||||
*/
|
||||
protected static $expire = 120;
|
||||
|
||||
/**
|
||||
* 最大允许检测的次数
|
||||
* @var int
|
||||
*/
|
||||
protected static $maxCheckNums = 10;
|
||||
|
||||
/**
|
||||
* 获取最后一次邮箱发送的数据
|
||||
*
|
||||
* @param int $email 邮箱
|
||||
* @param string $event 事件
|
||||
* @return Ems
|
||||
*/
|
||||
public static function get($email, $event = 'default')
|
||||
{
|
||||
$ems = \app\common\model\Ems::
|
||||
where(['email' => $email, 'event' => $event])
|
||||
->order('id', 'DESC')
|
||||
->find();
|
||||
Hook::listen('ems_get', $ems, null, true);
|
||||
return $ems ? $ems : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送验证码
|
||||
*
|
||||
* @param int $email 邮箱
|
||||
* @param int $code 验证码,为空时将自动生成4位数字
|
||||
* @param string $event 事件
|
||||
* @return boolean
|
||||
*/
|
||||
public static function send($email, $code = NULL, $event = 'default')
|
||||
{
|
||||
$code = is_null($code) ? mt_rand(1000, 9999) : $code;
|
||||
$time = time();
|
||||
$ip = request()->ip();
|
||||
$ems = \app\common\model\Ems::create(['event' => $event, 'email' => $email, 'code' => $code, 'ip' => $ip, 'createtime' => $time]);
|
||||
$result = Hook::listen('ems_send', $ems, null, true);
|
||||
if (!$result)
|
||||
{
|
||||
$ems->delete();
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送通知
|
||||
*
|
||||
* @param mixed $email 邮箱,多个以,分隔
|
||||
* @param string $msg 消息内容
|
||||
* @param string $template 消息模板
|
||||
* @return boolean
|
||||
*/
|
||||
public static function notice($email, $msg = '', $template = NULL)
|
||||
{
|
||||
$params = [
|
||||
'email' => $email,
|
||||
'msg' => $msg,
|
||||
'template' => $template
|
||||
];
|
||||
$result = Hook::listen('ems_notice', $params, null, true);
|
||||
return $result ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验验证码
|
||||
*
|
||||
* @param int $email 邮箱
|
||||
* @param int $code 验证码
|
||||
* @param string $event 事件
|
||||
* @return boolean
|
||||
*/
|
||||
public static function check($email, $code, $event = 'default')
|
||||
{
|
||||
$time = time() - self::$expire;
|
||||
$ems = \app\common\model\Ems::where(['email' => $email, 'event' => $event])
|
||||
->order('id', 'DESC')
|
||||
->find();
|
||||
if ($ems)
|
||||
{
|
||||
if ($ems['createtime'] > $time && $ems['times'] <= self::$maxCheckNums)
|
||||
{
|
||||
$correct = $code == $ems['code'];
|
||||
if (!$correct)
|
||||
{
|
||||
$ems->times = $ems->times + 1;
|
||||
$ems->save();
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = Hook::listen('ems_check', $ems, null, true);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 过期则清空该邮箱验证码
|
||||
self::flush($email, $event);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空指定邮箱验证码
|
||||
*
|
||||
* @param int $email 邮箱
|
||||
* @param string $event 事件
|
||||
* @return boolean
|
||||
*/
|
||||
public static function flush($email, $event = 'default')
|
||||
{
|
||||
\app\common\model\Ems::
|
||||
where(['email' => $email, 'event' => $event])
|
||||
->delete();
|
||||
Hook::listen('ems_flush');
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ namespace app\common\library;
|
|||
use think\Hook;
|
||||
|
||||
/**
|
||||
* 验证码类
|
||||
* 短信验证码类
|
||||
*/
|
||||
class Sms
|
||||
{
|
||||
|
|
@ -51,7 +51,8 @@ class Sms
|
|||
{
|
||||
$code = is_null($code) ? mt_rand(1000, 9999) : $code;
|
||||
$time = time();
|
||||
$sms = \app\common\model\Sms::create(['event' => $event, 'mobile' => $mobile, 'code' => $code, 'createtime' => $time]);
|
||||
$ip = request()->ip();
|
||||
$sms = \app\common\model\Sms::create(['event' => $event, 'mobile' => $mobile, 'code' => $code, 'ip' => $ip, 'createtime' => $time]);
|
||||
$result = Hook::listen('sms_send', $sms, null, true);
|
||||
if (!$result)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
|
||||
/**
|
||||
* 邮箱验证码
|
||||
*/
|
||||
class Ems Extends Model
|
||||
{
|
||||
|
||||
// 开启自动写入时间戳字段
|
||||
protected $autoWriteTimestamp = 'int';
|
||||
// 定义时间戳字段名
|
||||
protected $createTime = 'createtime';
|
||||
protected $updateTime = false;
|
||||
// 追加属性
|
||||
protected $append = [
|
||||
];
|
||||
|
||||
}
|
||||
|
|
@ -21,6 +21,16 @@ class Token Extends Model
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ return [
|
|||
//自动检测更新
|
||||
'checkupdate' => false,
|
||||
//版本号
|
||||
'version' => '1.0.0.20180308_beta',
|
||||
'version' => '1.0.0.20180310_beta',
|
||||
'api_url' => 'http://api.fastadmin.net',
|
||||
],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -31,8 +31,9 @@ class User extends Frontend
|
|||
|
||||
//监听注册登录注销的事件
|
||||
Hook::add('user_login_successed', function($user) use($auth) {
|
||||
Cookie::set('uid', $user->id);
|
||||
Cookie::set('token', $auth->getToken());
|
||||
$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) {
|
||||
Cookie::set('uid', $user->id);
|
||||
|
|
@ -139,7 +140,7 @@ class User extends Frontend
|
|||
{
|
||||
$account = $this->request->post('account');
|
||||
$password = $this->request->post('password');
|
||||
$keeptime = (int) $this->request->post('keeptime');
|
||||
$keeplogin = (int) $this->request->post('keeplogin');
|
||||
$token = $this->request->post('__token__');
|
||||
$rule = [
|
||||
'account' => 'require|length:3,50',
|
||||
|
|
@ -165,7 +166,7 @@ class User extends Frontend
|
|||
$this->error(__($validate->getError()));
|
||||
return FALSE;
|
||||
}
|
||||
if ($this->auth->login($account, $password, $keeptime))
|
||||
if ($this->auth->login($account, $password))
|
||||
{
|
||||
$synchtml = '';
|
||||
////////////////同步到Ucenter////////////////
|
||||
|
|
@ -262,39 +263,6 @@ class User extends Frontend
|
|||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 激活邮箱
|
||||
*/
|
||||
public function activeemail()
|
||||
{
|
||||
$code = $this->request->request('code');
|
||||
$code = base64_decode($code);
|
||||
parse_str($code, $params);
|
||||
if (!isset($params['id']) || !isset($params['time']) || !isset($params['key']))
|
||||
{
|
||||
$this->error(__('Invalid parameters'));
|
||||
}
|
||||
$user = \app\common\model\User::get($params['id']);
|
||||
if (!$user)
|
||||
{
|
||||
$this->error(__('User not found'));
|
||||
}
|
||||
if ($user->verification->email)
|
||||
{
|
||||
$this->error(__('Email already activation'));
|
||||
}
|
||||
if ($key !== md5(md5($user->id . $user->email . $time) . $user->salt) || time() - $params['time'] > 1800)
|
||||
{
|
||||
$this->error(__('Secrity code already invalid'));
|
||||
}
|
||||
$verification = $user->verification;
|
||||
$verification->email = 1;
|
||||
$user->verification = $verification;
|
||||
$user->save();
|
||||
$this->success(__('Active email successful'), url('user/index'));
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ return [
|
|||
'Sign up successful' => '注册成功',
|
||||
'Email active successful' => '邮箱激活成功',
|
||||
'Username can not be empty' => '用户名不能为空',
|
||||
'Username must be 6 to 30 characters' => '用户名必须6-30个字符',
|
||||
'Username must be 3 to 30 characters' => '用户名必须3-30个字符',
|
||||
'Account must be 3 to 50 characters' => '账户必须3-50个字符',
|
||||
'Password can not be empty' => '密码不能为空',
|
||||
'Password must be 6 to 30 characters' => '密码必须6-30个字符',
|
||||
'Email is incorrect' => '邮箱格式不正确',
|
||||
|
|
|
|||
|
|
@ -65,8 +65,9 @@
|
|||
<!-- /.container -->
|
||||
</nav>
|
||||
|
||||
|
||||
{__CONTENT__}
|
||||
<main class="content">
|
||||
{__CONTENT__}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
|
|
|
|||
|
|
@ -54,11 +54,12 @@
|
|||
</div>
|
||||
</nav>
|
||||
|
||||
{__CONTENT__}
|
||||
<main class="content">
|
||||
{__CONTENT__}
|
||||
</main>
|
||||
|
||||
<footer class="footer" style="clear:both">
|
||||
|
||||
<p class="address">Copyright © 2017-2018 fastadmin.net All Rights Reserved {$site.name} {:__('Copyrights')} <a href="http://www.miibeian.gov.cn" target="_blank">{$site.beian}</a></p>
|
||||
<p class="copyright">Copyright © 2017-2018 fastadmin.net All Rights Reserved {$site.name} {:__('Copyrights')} <a href="http://www.miibeian.gov.cn" target="_blank">{$site.beian}</a></p>
|
||||
</footer>
|
||||
|
||||
{include file="common/script" /}
|
||||
|
|
|
|||
|
|
@ -6,19 +6,19 @@
|
|||
<div class="form-group">
|
||||
<label class="control-label" for="account">{:__('Account')}</label>
|
||||
<div class="controls">
|
||||
<input class="form-control input-lg" id="account" type="text" name="account" value="" required="" placeholder="{:__('Email/Mobile/Username')}" autocomplete="off">
|
||||
<input class="form-control input-lg" id="account" type="text" name="account" value="" data-rule="required" placeholder="{:__('Email/Mobile/Username')}" autocomplete="off">
|
||||
<div class="help-block"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="password">{:__('Password')}</label>
|
||||
<div class="controls">
|
||||
<input class="form-control input-lg" id="password" type="password" name="password" required="" placeholder="{:__('Password')}" autocomplete="off">
|
||||
<input class="form-control input-lg" id="password" type="password" name="password" data-rule="required;password" placeholder="{:__('Password')}" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="controls">
|
||||
<input type="checkbox" name="keeptime" checked="checked" value="86400"> {:__('Keep login')}
|
||||
<input type="checkbox" name="keeplogin" checked="checked" value="1"> {:__('Keep login')}
|
||||
<div class="pull-right"><a href="javascript:;" class="btn-forgot">{:__('Forgot password')}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -30,43 +30,57 @@
|
|||
</div>
|
||||
</div>
|
||||
<script type="text/html" id="resetpwdtpl">
|
||||
<div style="padding:30px;">
|
||||
<div class="row">
|
||||
<form id="resetpwd-form" class="form-horizontal" method="POST" action="{:url('api/user/resetpwd')}">
|
||||
<input type="hidden" name="action" value="changemobile" />
|
||||
<div class="form-group">
|
||||
<label for="c-mobile" class="control-label col-xs-12 col-sm-3">{:__('Mobile')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input type="text" class="form-control" id="mobile" name="mobile" value="" data-rule="required;mobile;remote({:url('api/validate/check_mobile_exist')}, event=resetpwd, id={$user.id})" placeholder="">
|
||||
<span class="msg-box"></span>
|
||||
<form id="resetpwd-form" class="form-horizontal form-layer" method="POST" action="{:url('api/user/resetpwd')}">
|
||||
<div class="form-body">
|
||||
<input type="hidden" name="action" value="resetpwd" />
|
||||
<div class="form-group">
|
||||
<label for="" class="control-label col-xs-12 col-sm-3">{:__('Type')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<div class="radio">
|
||||
<label for="type-email"><input id="type-email" checked="checked" name="type" data-send-url="{:url('api/ems/send')}" data-check-url="{:url('api/validate/check_ems_correct')}" type="radio" value="email"> 通过邮箱找回</label>
|
||||
<label for="type-mobile"><input id="type-mobile" name="type" type="radio" data-send-url="{:url('api/sms/send')}" data-check-url="{:url('api/validate/check_sms_correct')}" value="mobile"> 通过手机找回</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="c-captcha" class="control-label col-xs-12 col-sm-3">{:__('Captcha')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<div class="input-group">
|
||||
<input type="text" name="captcha" class="form-control" data-rule="required;length(4);integer[+];remote({:url('api/validate/check_sms_correct')}, event=resetpwd, mobile:#mobile)" />
|
||||
<span class="input-group-btn" style="padding:0;border:none;">
|
||||
<a href="javascript:;" class="btn btn-info btn-captcha" data-url="{:url('api/sms/send')}" data-event="resetpwd">{:__('Send verification code')}</a>
|
||||
</span>
|
||||
</div>
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" data-type="email">
|
||||
<label for="email" class="control-label col-xs-12 col-sm-3">{:__('Email')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input type="text" class="form-control" id="email" name="email" value="" data-rule="required(#type-email:checked);email;remote({:url('api/validate/check_email_exist')}, event=resetpwd, id={$user.id})" placeholder="">
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="c-newpassword" class="control-label col-xs-12 col-sm-3">{:__('New password')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input type="password" class="form-control" id="newpassword" name="newpassword" value="" data-rule="required;password" placeholder="">
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group hide" data-type="mobile">
|
||||
<label for="mobile" class="control-label col-xs-12 col-sm-3">{:__('Mobile')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input type="text" class="form-control" id="mobile" name="mobile" value="" data-rule="required(#type-mobile:checked);mobile;remote({:url('api/validate/check_mobile_exist')}, event=resetpwd, id={$user.id})" placeholder="">
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-3"></label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<button type="submit" class="btn btn-md btn-info">{:__('Ok')}</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="captcha" class="control-label col-xs-12 col-sm-3">{:__('Captcha')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<div class="input-group">
|
||||
<input type="text" name="captcha" class="form-control" data-rule="required;length(4);integer[+];remote({:url('api/validate/check_ems_correct')}, event=resetpwd, email:#email)" />
|
||||
<span class="input-group-btn" style="padding:0;border:none;">
|
||||
<a href="javascript:;" class="btn btn-info btn-captcha" data-url="{:url('api/ems/send')}" data-type="email" data-event="resetpwd">{:__('Send verification code')}</a>
|
||||
</span>
|
||||
</div>
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="newpassword" class="control-label col-xs-12 col-sm-3">{:__('New password')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input type="password" class="form-control" id="newpassword" name="newpassword" value="" data-rule="required;password" placeholder="">
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group form-footer">
|
||||
<label class="control-label col-xs-12 col-sm-3"></label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<button type="submit" class="btn btn-md btn-info">{:__('Ok')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
|
@ -107,58 +107,96 @@
|
|||
</div>
|
||||
|
||||
<script type="text/html" id="emailtpl">
|
||||
<div style="padding:30px;">
|
||||
<div class="row">
|
||||
<form id="email-form" class="form-horizontal" method="POST" action="{:url('api/user/changeemail')}">
|
||||
<input type="hidden" name="action" value="changeemail" />
|
||||
<div class="form-group">
|
||||
<label for="c-email" class="control-label col-xs-12 col-sm-3">{:__('New email')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input type="text" class="form-control" id="email" name="email" value="" data-rule="required;email;remote({:url('api/validate/check_email_available')}, type=changeemail, id={$user.id})" placeholder="{:__('New email')}">
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
<form id="email-form" class="form-horizontal form-layer" method="POST" action="{:url('api/user/changeemail')}">
|
||||
<div class="form-body">
|
||||
<input type="hidden" name="action" value="changeemail" />
|
||||
<div class="form-group">
|
||||
<label for="c-email" class="control-label col-xs-12 col-sm-3">{:__('New Email')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input type="text" class="form-control" id="email" name="email" value="" data-rule="required;email;remote({:url('api/validate/check_email_available')}, event=changeemail, id={$user.id})" placeholder="{:__('New email')}">
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-3"></label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<button type="submit" class="btn btn-md btn-info">{:__('Submit')}</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="c-captcha" class="control-label col-xs-12 col-sm-3">{:__('Captcha')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<div class="input-group">
|
||||
<input type="text" name="captcha" id="email-captcha" class="form-control" data-rule="required;length(4);integer[+];remote({:url('api/validate/check_ems_correct')}, event=changeemail, email:#email)" />
|
||||
<span class="input-group-btn" style="padding:0;border:none;">
|
||||
<a href="javascript:;" class="btn btn-info btn-captcha" data-url="{:url('api/ems/send')}" data-type="email" data-event="changeemail">获取验证码</a>
|
||||
</span>
|
||||
</div>
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-footer">
|
||||
<div class="form-group" style="margin-bottom:0;">
|
||||
<label class="control-label col-xs-12 col-sm-3"></label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<button type="submit" class="btn btn-md btn-info">{:__('Submit')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<script type="text/html" id="mobiletpl">
|
||||
<div style="padding:30px;">
|
||||
<div class="row">
|
||||
<form id="mobile-form" class="form-horizontal" method="POST" action="{:url('api/user/changemobile')}">
|
||||
<input type="hidden" name="action" value="changemobile" />
|
||||
<div class="form-group">
|
||||
<label for="c-mobile" class="control-label col-xs-12 col-sm-3">{:__('New mobile')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input type="text" class="form-control" id="mobile" name="mobile" value="" data-rule="required;mobile;remote({:url('api/validate/check_mobile_available')}, event=changemobile, id={$user.id})" placeholder="{:__('New mobile')}">
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
<form id="mobile-form" class="form-horizontal form-layer" method="POST" action="{:url('api/user/changemobile')}">
|
||||
<div class="form-body">
|
||||
<input type="hidden" name="action" value="changemobile" />
|
||||
<div class="form-group">
|
||||
<label for="c-mobile" class="control-label col-xs-12 col-sm-3">{:__('New mobile')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<input type="text" class="form-control" id="mobile" name="mobile" value="" data-rule="required;mobile;remote({:url('api/validate/check_mobile_available')}, event=changemobile, id={$user.id})" placeholder="{:__('New mobile')}">
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="c-captcha" class="control-label col-xs-12 col-sm-3">{:__('Captcha')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<div class="input-group">
|
||||
<input type="text" name="captcha" class="form-control" data-rule="required;length(4);integer[+];remote({:url('api/validate/check_sms_correct')}, event=changemobile, mobile:#mobile)" />
|
||||
<span class="input-group-btn" style="padding:0;border:none;">
|
||||
<a href="javascript:;" class="btn btn-info btn-captcha" data-url="{:url('api/sms/send')}" data-event="changemobile">获取验证码</a>
|
||||
</span>
|
||||
</div>
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="c-captcha" class="control-label col-xs-12 col-sm-3">{:__('Captcha')}:</label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<div class="input-group">
|
||||
<input type="text" name="captcha" id="mobile-captcha" class="form-control" data-rule="required;length(4);integer[+];remote({:url('api/validate/check_sms_correct')}, event=changemobile, mobile:#mobile)" />
|
||||
<span class="input-group-btn" style="padding:0;border:none;">
|
||||
<a href="javascript:;" class="btn btn-info btn-captcha" data-url="{:url('api/sms/send')}" data-type="mobile" data-event="changemobile">获取验证码</a>
|
||||
</span>
|
||||
</div>
|
||||
<span class="msg-box"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-xs-12 col-sm-3"></label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<button type="submit" class="btn btn-md btn-info">{:__('Submit')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-footer">
|
||||
<div class="form-group" style="margin-bottom:0;">
|
||||
<label class="control-label col-xs-12 col-sm-3"></label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<button type="submit" class="btn btn-md btn-info">{:__('Submit')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
<style>
|
||||
.form-layer {height:100%;min-height:150px;min-width:300px;}
|
||||
.form-body {
|
||||
width:100%;
|
||||
overflow:auto;
|
||||
top:0;
|
||||
position:absolute;
|
||||
z-index:10;
|
||||
bottom:50px;
|
||||
padding:15px;
|
||||
}
|
||||
.form-layer .form-footer {
|
||||
height:50px;
|
||||
line-height:50px;
|
||||
background-color: #ecf0f1;
|
||||
width:100%;
|
||||
position:absolute;
|
||||
z-index:200;
|
||||
bottom:0;
|
||||
margin:0;
|
||||
}
|
||||
.form-footer .form-group{
|
||||
margin-left:0;
|
||||
margin-right:0;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -7,28 +7,28 @@
|
|||
<div class="form-group">
|
||||
<label class="control-label required">{:__('Email')}<span class="text-success"></span></label>
|
||||
<div class="controls">
|
||||
<input type="text" name="email" id="email" required class="form-control input-lg" placeholder="{:__('Email')}">
|
||||
<input type="text" name="email" id="email" data-rule="required;email" class="form-control input-lg" placeholder="{:__('Email')}">
|
||||
<p class="help-block"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">{:__('Username')}</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="username" name="username" required class="form-control input-lg" placeholder="{:__('Username must be 6 to 30 characters')}">
|
||||
<input type="text" id="username" name="username" data-rule="required;username" class="form-control input-lg" placeholder="{:__('Username must be 3 to 30 characters')}">
|
||||
<p class="help-block"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">{:__('Password')}</label>
|
||||
<div class="controls">
|
||||
<input type="password" id="password" name="password" required class="form-control input-lg" placeholder="{:__('Password must be 6 to 30 characters')}">
|
||||
<input type="password" id="password" name="password" data-rule="required;password" class="form-control input-lg" placeholder="{:__('Password must be 6 to 30 characters')}">
|
||||
<p class="help-block"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label">{:__('Mobile')}</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="mobile" name="mobile" required class="form-control input-lg" placeholder="{:__('Mobile')}">
|
||||
<input type="text" id="mobile" name="mobile" data-rule="required;mobile" class="form-control input-lg" placeholder="{:__('Mobile')}">
|
||||
<p class="help-block"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
<label class="control-label">{:__('Captcha')}</label>
|
||||
<div class="controls">
|
||||
<div class="input-group input-group-lg">
|
||||
<input type="text" name="captcha" class="form-control" placeholder="{:__('Captcha')}" required style="border-radius: 0;" />
|
||||
<input type="text" name="captcha" class="form-control" placeholder="{:__('Captcha')}" data-rule="required;length(4);integer[+]" style="border-radius: 0;" />
|
||||
<span class="input-group-addon" style="padding:0;border:none;">
|
||||
<img src="{:captcha_src()}" width="140" height="42" onclick="this.src = '{:captcha_src()}?r=' + Math.random();"/>
|
||||
</span>
|
||||
|
|
|
|||
1956
public/api.html
1956
public/api.html
File diff suppressed because it is too large
Load Diff
|
|
@ -417,6 +417,35 @@ form.form-horizontal .control-label {
|
|||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
/* 弹窗中的表单 */
|
||||
.form-layer {
|
||||
height: 100%;
|
||||
min-height: 150px;
|
||||
min-width: 300px;
|
||||
}
|
||||
.form-layer .form-body {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
bottom: 50px;
|
||||
padding: 15px;
|
||||
}
|
||||
.form-layer .form-footer {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
background-color: #ecf0f1;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
z-index: 200;
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.form-layer .form-footer .form-group {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
#treeview .jstree-container-ul .jstree-node {
|
||||
display: block;
|
||||
clear: both;
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -14,15 +14,6 @@ body {
|
|||
padding-top: 50px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.wow {
|
||||
visibility: hidden;
|
||||
}
|
||||
.img-portfolio {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.img-hover:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
.dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
|
|
@ -66,12 +57,22 @@ body {
|
|||
height: 80px;
|
||||
object-fit: cover;
|
||||
}
|
||||
.layui-layer-content {
|
||||
clear: both;
|
||||
}
|
||||
.layui-layer-fast-msg {
|
||||
min-width: 100px;
|
||||
border-radius: 2px;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
color: #fff;
|
||||
}
|
||||
.layui-layer-fast-msg .layui-layer-content {
|
||||
padding: 12px 25px;
|
||||
text-align: center;
|
||||
}
|
||||
#header-navbar li.dropdown ul.dropdown-menu {
|
||||
min-width: 94px;
|
||||
}
|
||||
.panel-col {
|
||||
min-height: 400px;
|
||||
}
|
||||
.panel-default {
|
||||
padding: 0 15px;
|
||||
border-color: #e4ecf3;
|
||||
|
|
@ -132,23 +133,6 @@ body {
|
|||
background: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 1920px) {
|
||||
.panel-default > .panel-body .zuixin {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
padding-bottom: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.panel-default > .panel-body .zuixin {
|
||||
width: 50%;
|
||||
padding-bottom: 5px;
|
||||
margin-bottom: 10px;
|
||||
float: left;
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
.panel-primary > .panel-heading {
|
||||
background-color: #46c37b;
|
||||
color: #fff;
|
||||
|
|
@ -226,84 +210,35 @@ body {
|
|||
line-height: 1.5;
|
||||
padding: 4px 13px;
|
||||
}
|
||||
.metas {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
color: #c1c1c1;
|
||||
/* 弹窗中的表单 */
|
||||
.form-layer {
|
||||
height: 100%;
|
||||
min-height: 150px;
|
||||
min-width: 300px;
|
||||
}
|
||||
.metas i {
|
||||
margin-right: 5px;
|
||||
.form-layer .form-body {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
bottom: 50px;
|
||||
padding: 15px;
|
||||
}
|
||||
.metas .addon-price {
|
||||
float: right;
|
||||
.form-layer .form-footer {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
background-color: #ecf0f1;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
z-index: 200;
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.metas .price {
|
||||
color: #e83d2c;
|
||||
font-size: 14px;
|
||||
.form-layer .form-footer .form-group {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
.metas .free {
|
||||
color: #238312;
|
||||
}
|
||||
.metas .comment {
|
||||
margin-left: 10px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.metas .metas {
|
||||
padding: 5px;
|
||||
}
|
||||
.metas .comment {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.text-line {
|
||||
position: relative;
|
||||
padding: 30px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.text-line.small {
|
||||
padding: 10px 0;
|
||||
}
|
||||
.text-line.small h5 {
|
||||
font-size: 14px;
|
||||
}
|
||||
.text-line.small h5 > span {
|
||||
padding: 0 20px;
|
||||
}
|
||||
.text-line h5 {
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
font-size: 32px;
|
||||
z-index: 1;
|
||||
color: #313131;
|
||||
}
|
||||
.text-line h5 > i {
|
||||
padding-left: 20px;
|
||||
background: #fff;
|
||||
}
|
||||
.text-line h5 > span {
|
||||
padding: 0 40px;
|
||||
}
|
||||
.text-line .subtitle {
|
||||
font-size: 16px;
|
||||
color: #919191;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.text-line {
|
||||
padding: 20px 0;
|
||||
}
|
||||
.text-line h5 {
|
||||
font-size: 16px;
|
||||
}
|
||||
.text-line .subtitle {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
header.carousel .carousel {
|
||||
height: 70%;
|
||||
}
|
||||
}
|
||||
footer.footer {
|
||||
width: 100%;
|
||||
color: #aaa;
|
||||
|
|
@ -311,87 +246,61 @@ footer.footer {
|
|||
margin-top: 25px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
z-index: 99;
|
||||
}
|
||||
footer.footer ul {
|
||||
margin: 60px 0 30px 0;
|
||||
padding: 0;
|
||||
}
|
||||
footer.footer ul li.f-tit {
|
||||
margin-bottom: 10px;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
}
|
||||
footer.footer ul li {
|
||||
line-height: 26px;
|
||||
white-space: nowrap;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
footer.footer ul li a {
|
||||
color: #aaa;
|
||||
}
|
||||
footer.footer ul li a:hover {
|
||||
color: #aaa;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
footer.footer .address {
|
||||
footer.footer .copyright {
|
||||
line-height: 50px;
|
||||
text-align: center;
|
||||
background: #393939;
|
||||
margin: 0;
|
||||
}
|
||||
footer p.address a {
|
||||
footer.footer .copyright a {
|
||||
color: #aaa;
|
||||
}
|
||||
footer p.address a:hover {
|
||||
footer.footer .copyright a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
footer.footer {
|
||||
overflow: hidden;
|
||||
}
|
||||
footer.footer .container {
|
||||
margin: 0 20px;
|
||||
}
|
||||
footer.footer ul {
|
||||
margin: 20px 0 10px 0;
|
||||
}
|
||||
footer.footer .address {
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
.rotate {
|
||||
-webkit-transition-duration: 0.8s;
|
||||
-moz-transition-duration: 0.8s;
|
||||
-o-transition-duration: 0.8s;
|
||||
transition-duration: 0.8s;
|
||||
-webkit-transition-property: transform;
|
||||
transition-property: transform;
|
||||
-webkit-transition-property: -webkit-transform;
|
||||
-moz-transition-property: -moz-transform;
|
||||
-o-transition-property: -o-transform;
|
||||
transition-property: transform;
|
||||
transition-property: -webkit-transform,-moz-transform,-o-transform,transform;
|
||||
overflow: hidden;
|
||||
}
|
||||
.rotate:hover {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-moz-transform: rotate(360deg);
|
||||
-o-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
.user-section {
|
||||
background: #fff;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
-webkit-border-radius: 4px;
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-border-radius: 4px;
|
||||
-moz-background-clip: padding;
|
||||
border-radius: 4px;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #e4ecf3;
|
||||
}
|
||||
.login-section {
|
||||
margin: 50px auto;
|
||||
width: 460px;
|
||||
-webkit-border-radius: 0;
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-border-radius: 0;
|
||||
-moz-background-clip: padding;
|
||||
border-radius: 0;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
.login-section.login-section-weixin {
|
||||
min-height: 315px;
|
||||
|
|
@ -433,42 +342,43 @@ footer p.address a:hover {
|
|||
.login-section .control-label {
|
||||
font-size: 13px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.login-section {
|
||||
width: 100%;
|
||||
margin: 20px auto;
|
||||
}
|
||||
.login-section .login-main {
|
||||
padding: 20px 0 0 0;
|
||||
}
|
||||
.login-section .n-bootstrap .form-group {
|
||||
position: relative;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.login-modal {
|
||||
width: 350px;
|
||||
}
|
||||
.login-modal .modal-body {
|
||||
padding: 30px 30px 15px 30px;
|
||||
}
|
||||
.login-modal .modal-footer {
|
||||
padding: 30px;
|
||||
}
|
||||
.login-section .n-bootstrap .input-group {
|
||||
position: inherit;
|
||||
}
|
||||
#content-container {
|
||||
margin: 30px auto;
|
||||
min-height: 400px;
|
||||
.login-section .n-bootstrap .n-right {
|
||||
margin-top: 0;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
#content-container {
|
||||
min-height: 250px;
|
||||
}
|
||||
.login-section .n-bootstrap .n-right .msg-wrap {
|
||||
position: relative;
|
||||
}
|
||||
main.content {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
bottom: 50px;
|
||||
padding: 15px;
|
||||
padding-top: 67px;
|
||||
}
|
||||
.sidenav {
|
||||
padding: 20px 0 10px 0;
|
||||
margin-bottom: 20px;
|
||||
background-color: #fff;
|
||||
-webkit-border-radius: 4px;
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-border-radius: 4px;
|
||||
-moz-background-clip: padding;
|
||||
border-radius: 4px;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid #e4ecf3;
|
||||
}
|
||||
.sidenav .list-group:last-child {
|
||||
|
|
@ -483,8 +393,11 @@ footer p.address a:hover {
|
|||
}
|
||||
.sidenav .list-group .list-group-item {
|
||||
-webkit-border-radius: 0;
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-border-radius: 0;
|
||||
-moz-background-clip: padding;
|
||||
border-radius: 0;
|
||||
background-clip: padding-box;
|
||||
border: none;
|
||||
padding: 0;
|
||||
border-left: 2px solid transparent;
|
||||
|
|
@ -492,8 +405,11 @@ footer p.address a:hover {
|
|||
.sidenav .list-group .list-group-item:last-child,
|
||||
.sidenav .list-group .list-group-item:first-child {
|
||||
-webkit-border-radius: 0;
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-border-radius: 0;
|
||||
-moz-background-clip: padding;
|
||||
border-radius: 0;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
.sidenav .list-group .list-group-item:hover {
|
||||
background-color: #f5f5f5;
|
||||
|
|
@ -510,9 +426,6 @@ footer p.address a:hover {
|
|||
.sidenav .list-group .list-group-item.active > a {
|
||||
color: #46c37b;
|
||||
}
|
||||
.flarum-section ul li a {
|
||||
font-size: 13px;
|
||||
}
|
||||
.nav li .avatar-text,
|
||||
.nav li .avatar-img {
|
||||
height: 30px;
|
||||
|
|
@ -551,4 +464,24 @@ footer p.address a:hover {
|
|||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
main.content {
|
||||
position: inherit;
|
||||
padding: 15px 0;
|
||||
}
|
||||
.login-section {
|
||||
width: 100%;
|
||||
margin: 20px auto;
|
||||
}
|
||||
.login-section .login-main {
|
||||
padding: 20px 0 0 0;
|
||||
}
|
||||
footer.footer {
|
||||
position: inherit;
|
||||
}
|
||||
footer.footer .copyright {
|
||||
padding: 10px;
|
||||
line-height: 30px;
|
||||
}
|
||||
}
|
||||
/*# sourceMappingURL=frontend.css.map */
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -185,7 +185,7 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
|
|||
data: {action: 'refreshmenu'}
|
||||
}, function (data) {
|
||||
$(".sidebar-menu li:not([data-rel='external'])").remove();
|
||||
$(data.menulist).insertBefore($(".sidebar-menu li:first"));
|
||||
$(".sidebar-menu").prepend(data.menulist);
|
||||
$("#nav ul li[role='presentation'].active a").trigger('click');
|
||||
return false;
|
||||
}, function () {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ define(['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, undefine
|
|||
return;
|
||||
}
|
||||
}
|
||||
Toastr.error(ret.msg + "(code:" + ret.code + ")");
|
||||
Toastr.error(ret.msg);
|
||||
},
|
||||
//服务器响应数据后
|
||||
onAjaxResponse: function (response) {
|
||||
|
|
|
|||
|
|
@ -2,36 +2,48 @@ define(['fast'], function (Fast) {
|
|||
var Frontend = {
|
||||
api: Fast.api,
|
||||
init: function () {
|
||||
//发送手机验证码
|
||||
var si = {};
|
||||
//发送验证码
|
||||
$(document).on("click", ".btn-captcha", function (e) {
|
||||
var mobile = $(this).closest("form").find("#mobile");
|
||||
if (mobile.val() == "") {
|
||||
Layer.alert("手机号码不能为空!");
|
||||
var type = $(this).data("type") ? $(this).data("type") : 'mobile';
|
||||
var element = $(this).data("input-id") ? $("#" + $(this).data("input-id")) : $("input[name='" + type + "']", $(this).closest("form"));
|
||||
var text = type === 'email' ? '邮箱' : '手机号码';
|
||||
if (element.val() === "") {
|
||||
Layer.msg(text + "不能为空!");
|
||||
element.focus();
|
||||
return false;
|
||||
} else if (!mobile.val().match(/^1[3-9]\d{9}$/)) {
|
||||
Layer.alert("请输入正确的手机号码!");
|
||||
} else if (type === 'mobile' && !element.val().match(/^1[3-9]\d{9}$/)) {
|
||||
Layer.msg("请输入正确的" + text + "!");
|
||||
element.focus();
|
||||
return false;
|
||||
} else if (type === 'email' && !element.val().match(/^[\w\+\-]+(\.[\w\+\-]+)*@[a-z\d\-]+(\.[a-z\d\-]+)*\.([a-z]{2,4})$/)) {
|
||||
Layer.msg("请输入正确的" + text + "!");
|
||||
element.focus();
|
||||
return false;
|
||||
}
|
||||
var that = this;
|
||||
mobile.isValid(function (v) {
|
||||
element.isValid(function (v) {
|
||||
if (v) {
|
||||
$(that).addClass("disabled", true).text("获取中...");
|
||||
var si;
|
||||
Frontend.api.ajax({url: $(that).data("url"), data: {event: $(that).data("event"), mobile: mobile.val()}}, function () {
|
||||
clearInterval(si);
|
||||
$(that).addClass("disabled", true).text("发送中...");
|
||||
var data = {event: $(that).data("event")};
|
||||
data[type] = element.val();
|
||||
Frontend.api.ajax({url: $(that).data("url"), data: data}, function () {
|
||||
clearInterval(si[type]);
|
||||
var seconds = 60;
|
||||
si = setInterval(function () {
|
||||
si[type] = setInterval(function () {
|
||||
seconds--;
|
||||
if (seconds <= 0) {
|
||||
clearInterval(si);
|
||||
$(that).removeClass("disabled", false).text("获取验证码");
|
||||
$(that).removeClass("disabled").text("发送验证码");
|
||||
} else {
|
||||
$(that).addClass("disabled", true).text(seconds + "秒后可再次发送");
|
||||
$(that).addClass("disabled").text(seconds + "秒后可再次发送");
|
||||
}
|
||||
}, 1000);
|
||||
}, function () {
|
||||
$(that).removeClass("disabled").text('发送验证码');
|
||||
});
|
||||
} else {
|
||||
Layer.alert("请确认已经输入了正解的手机号!");
|
||||
Layer.msg("请确认已经输入了正确的" + text + "!");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,24 @@
|
|||
define(['jquery', 'bootstrap', 'frontend', 'form', 'template'], function ($, undefined, Frontend, Form, Template) {
|
||||
var validatoroptions = {
|
||||
invalid: function (form, errors) {
|
||||
$.each(errors, function (i, j) {
|
||||
Layer.msg(j);
|
||||
});
|
||||
}
|
||||
};
|
||||
var Controller = {
|
||||
login: function () {
|
||||
//本地验证未通过时提示
|
||||
$("#login-form").data("validator-options", {
|
||||
invalid: function (form, errors) {
|
||||
$.each(errors, function (i, j) {
|
||||
Layer.alert(j);
|
||||
});
|
||||
},
|
||||
$("#login-form").data("validator-options", validatoroptions);
|
||||
|
||||
$(document).on("change", "input[name=type]", function () {
|
||||
var type = $(this).val();
|
||||
$("div.form-group[data-type]").addClass("hide");
|
||||
$("div.form-group[data-type='" + type + "']").removeClass("hide");
|
||||
$('#resetpwd-form').validator("setField", {
|
||||
captcha: "required;length(4);integer[+];remote(" + $(this).data("check-url") + ", event=resetpwd, " + type + ":#" + type + ")",
|
||||
});
|
||||
$(".btn-captcha").data("url", $(this).data("send-url")).data("type", type);
|
||||
});
|
||||
|
||||
//为表单绑定事件
|
||||
|
|
@ -27,7 +38,7 @@ define(['jquery', 'bootstrap', 'frontend', 'form', 'template'], function ($, und
|
|||
Layer.open({
|
||||
type: 1,
|
||||
title: "修改",
|
||||
area: ["450px", "auto"],
|
||||
area: ["450px", "355px"],
|
||||
content: content,
|
||||
success: function (layero) {
|
||||
Form.api.bindevent($("#resetpwd-form", layero), function (data) {
|
||||
|
|
@ -39,13 +50,7 @@ define(['jquery', 'bootstrap', 'frontend', 'form', 'template'], function ($, und
|
|||
},
|
||||
register: function () {
|
||||
//本地验证未通过时提示
|
||||
$("#register-form").data("validator-options", {
|
||||
invalid: function (form, errors) {
|
||||
$.each(errors, function (i, j) {
|
||||
Layer.alert(j);
|
||||
});
|
||||
},
|
||||
});
|
||||
$("#register-form").data("validator-options", validatoroptions);
|
||||
|
||||
//为表单绑定事件
|
||||
Form.api.bindevent($("#register-form"), function (data, ret) {
|
||||
|
|
@ -56,13 +61,7 @@ define(['jquery', 'bootstrap', 'frontend', 'form', 'template'], function ($, und
|
|||
},
|
||||
changepwd: function () {
|
||||
//本地验证未通过时提示
|
||||
$("#resetpwd-form").data("validator-options", {
|
||||
invalid: function (form, errors) {
|
||||
$.each(errors, function (i, j) {
|
||||
Layer.alert(j);
|
||||
});
|
||||
},
|
||||
});
|
||||
$("#changepwd-form").data("validator-options", validatoroptions);
|
||||
|
||||
//为表单绑定事件
|
||||
Form.api.bindevent($("#changepwd-form"), function (data, ret) {
|
||||
|
|
@ -78,26 +77,23 @@ define(['jquery', 'bootstrap', 'frontend', 'form', 'template'], function ($, und
|
|||
$(".profile-user-img").prop("src", url);
|
||||
Toastr.success("上传成功!");
|
||||
});
|
||||
|
||||
//为表单绑定事件
|
||||
Form.api.bindevent($("#profile-form"), function (data) {
|
||||
});
|
||||
Form.api.bindevent($("#email-form"), function (data) {
|
||||
Layer.closeAll();
|
||||
$("#basic-form #email").val($("#email").val());
|
||||
});
|
||||
Form.api.bindevent($("#mobile-form"), function (data) {
|
||||
Layer.closeAll();
|
||||
$("#basic-form #mobile").val($("#mobile").val());
|
||||
});
|
||||
Form.api.bindevent($("#profile-form"));
|
||||
$(document).on("click", ".btn-change", function () {
|
||||
var that = this;
|
||||
var id = $(this).data("type") + "tpl";
|
||||
var content = Template(id, {});
|
||||
Layer.open({
|
||||
type: 1,
|
||||
title: "修改",
|
||||
area: ["450px", "auto"],
|
||||
area: ["400px", "250px"],
|
||||
content: content,
|
||||
success: function (layero) {
|
||||
var form = $("form", layero);
|
||||
Form.api.bindevent(form, function (data) {
|
||||
Layer.closeAll();
|
||||
console.log(123);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -696,7 +696,7 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
|
|||
return;
|
||||
}
|
||||
}
|
||||
Toastr.error(ret.msg + "(code:" + ret.code + ")");
|
||||
Toastr.error(ret.msg);
|
||||
},
|
||||
//服务器响应数据后
|
||||
onAjaxResponse: function (response) {
|
||||
|
|
|
|||
|
|
@ -696,7 +696,7 @@ define('fast',['jquery', 'bootstrap', 'toastr', 'layer', 'lang'], function ($, u
|
|||
return;
|
||||
}
|
||||
}
|
||||
Toastr.error(ret.msg + "(code:" + ret.code + ")");
|
||||
Toastr.error(ret.msg);
|
||||
},
|
||||
//服务器响应数据后
|
||||
onAjaxResponse: function (response) {
|
||||
|
|
@ -977,36 +977,48 @@ define('frontend',['fast'], function (Fast) {
|
|||
var Frontend = {
|
||||
api: Fast.api,
|
||||
init: function () {
|
||||
//发送手机验证码
|
||||
var si = {};
|
||||
//发送验证码
|
||||
$(document).on("click", ".btn-captcha", function (e) {
|
||||
var mobile = $(this).closest("form").find("#mobile");
|
||||
if (mobile.val() == "") {
|
||||
Layer.alert("手机号码不能为空!");
|
||||
var type = $(this).data("type") ? $(this).data("type") : 'mobile';
|
||||
var element = $(this).data("input-id") ? $("#" + $(this).data("input-id")) : $("input[name='" + type + "']", $(this).closest("form"));
|
||||
var text = type === 'email' ? '邮箱' : '手机号码';
|
||||
if (element.val() === "") {
|
||||
Layer.msg(text + "不能为空!");
|
||||
element.focus();
|
||||
return false;
|
||||
} else if (!mobile.val().match(/^1[3-9]\d{9}$/)) {
|
||||
Layer.alert("请输入正确的手机号码!");
|
||||
} else if (type === 'mobile' && !element.val().match(/^1[3-9]\d{9}$/)) {
|
||||
Layer.msg("请输入正确的" + text + "!");
|
||||
element.focus();
|
||||
return false;
|
||||
} else if (type === 'email' && !element.val().match(/^[\w\+\-]+(\.[\w\+\-]+)*@[a-z\d\-]+(\.[a-z\d\-]+)*\.([a-z]{2,4})$/)) {
|
||||
Layer.msg("请输入正确的" + text + "!");
|
||||
element.focus();
|
||||
return false;
|
||||
}
|
||||
var that = this;
|
||||
mobile.isValid(function (v) {
|
||||
element.isValid(function (v) {
|
||||
if (v) {
|
||||
$(that).addClass("disabled", true).text("获取中...");
|
||||
var si;
|
||||
Frontend.api.ajax({url: $(that).data("url"), data: {event: $(that).data("event"), mobile: mobile.val()}}, function () {
|
||||
clearInterval(si);
|
||||
$(that).addClass("disabled", true).text("发送中...");
|
||||
var data = {event: $(that).data("event")};
|
||||
data[type] = element.val();
|
||||
Frontend.api.ajax({url: $(that).data("url"), data: data}, function () {
|
||||
clearInterval(si[type]);
|
||||
var seconds = 60;
|
||||
si = setInterval(function () {
|
||||
si[type] = setInterval(function () {
|
||||
seconds--;
|
||||
if (seconds <= 0) {
|
||||
clearInterval(si);
|
||||
$(that).removeClass("disabled", false).text("获取验证码");
|
||||
$(that).removeClass("disabled").text("发送验证码");
|
||||
} else {
|
||||
$(that).addClass("disabled", true).text(seconds + "秒后可再次发送");
|
||||
$(that).addClass("disabled").text(seconds + "秒后可再次发送");
|
||||
}
|
||||
}, 1000);
|
||||
}, function () {
|
||||
$(that).removeClass("disabled").text('发送验证码');
|
||||
});
|
||||
} else {
|
||||
Layer.alert("请确认已经输入了正解的手机号!");
|
||||
Layer.msg("请确认已经输入了正确的" + text + "!");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -452,6 +452,34 @@ form.form-horizontal .control-label {
|
|||
ins{width:110px;display: inline-block;text-decoration:none;font-weight: bold;}
|
||||
}
|
||||
|
||||
/* 弹窗中的表单 */
|
||||
.form-layer {
|
||||
height:100%;min-height:150px;min-width:300px;
|
||||
.form-body {
|
||||
width:100%;
|
||||
overflow:auto;
|
||||
top:0;
|
||||
position:absolute;
|
||||
z-index:10;
|
||||
bottom:50px;
|
||||
padding:15px;
|
||||
}
|
||||
.form-footer {
|
||||
height:50px;
|
||||
line-height:50px;
|
||||
background-color: #ecf0f1;
|
||||
width:100%;
|
||||
position:absolute;
|
||||
z-index:200;
|
||||
bottom:0;
|
||||
margin:0;
|
||||
}
|
||||
.form-footer .form-group{
|
||||
margin-left:0;
|
||||
margin-right:0;
|
||||
}
|
||||
}
|
||||
|
||||
#treeview {
|
||||
.jstree-container-ul .jstree-node{
|
||||
display:block;clear:both;
|
||||
|
|
|
|||
|
|
@ -32,16 +32,6 @@ body {
|
|||
font-size:13px;
|
||||
}
|
||||
|
||||
.wow { visibility: hidden; }
|
||||
|
||||
.img-portfolio {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.img-hover:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
|
|
@ -66,7 +56,6 @@ body {
|
|||
display:inherit;
|
||||
}
|
||||
|
||||
|
||||
/*预览区域*/
|
||||
.plupload-preview {
|
||||
padding:10px;
|
||||
|
|
@ -89,13 +78,24 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.layui-layer-content {
|
||||
clear: both;
|
||||
}
|
||||
.layui-layer-fast-msg {
|
||||
min-width: 100px;
|
||||
border-radius: 2px;
|
||||
background-color: rgba(0,0,0,.6);
|
||||
color: #fff;
|
||||
.layui-layer-content {
|
||||
padding: 12px 25px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
#header-navbar li.dropdown ul.dropdown-menu {
|
||||
min-width:94px;
|
||||
}
|
||||
|
||||
.panel-col {
|
||||
min-height: 400px;
|
||||
}
|
||||
.panel-default {
|
||||
padding: 0 15px;
|
||||
border-color: #e4ecf3;
|
||||
|
|
@ -154,17 +154,6 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1920px) {
|
||||
.panel-default > .panel-body .zuixin{
|
||||
width:100%;border-bottom: 1px solid #f5f5f5; padding-bottom:5px; margin-bottom:10px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.panel-default > .panel-body .zuixin{
|
||||
width:50%; padding-bottom:5px; margin-bottom:10px; float:left; padding-right:5px;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-primary {
|
||||
> .panel-heading {
|
||||
background-color: #46c37b;
|
||||
|
|
@ -203,6 +192,7 @@ body {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.panel-page {
|
||||
padding: 15px;
|
||||
|
|
@ -235,143 +225,65 @@ body {
|
|||
padding: 4px 13px;
|
||||
}
|
||||
|
||||
.metas {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
color: #c1c1c1;
|
||||
|
||||
i {
|
||||
margin-right: 5px;
|
||||
/* 弹窗中的表单 */
|
||||
.form-layer {
|
||||
height:100%;min-height:150px;min-width:300px;
|
||||
.form-body {
|
||||
width:100%;
|
||||
overflow:auto;
|
||||
top:0;
|
||||
position:absolute;
|
||||
z-index:10;
|
||||
bottom:50px;
|
||||
padding:15px;
|
||||
}
|
||||
.addon-price {
|
||||
float: right;
|
||||
.form-footer {
|
||||
height:50px;
|
||||
line-height:50px;
|
||||
background-color: #ecf0f1;
|
||||
width:100%;
|
||||
position:absolute;
|
||||
z-index:200;
|
||||
bottom:0;
|
||||
margin:0;
|
||||
}
|
||||
.price {
|
||||
color: #e83d2c;
|
||||
font-size: 14px;
|
||||
margin-right: 0;
|
||||
}
|
||||
.free {
|
||||
color: #238312;
|
||||
}
|
||||
.comment {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.metas {
|
||||
.metas {
|
||||
padding: 5px;
|
||||
}
|
||||
.comment {
|
||||
display: none;
|
||||
}
|
||||
.form-footer .form-group{
|
||||
margin-left:0;
|
||||
margin-right:0;
|
||||
}
|
||||
}
|
||||
|
||||
.text-line {
|
||||
position: relative;
|
||||
padding: 30px 0;
|
||||
text-align: center;
|
||||
&.small {
|
||||
padding: 10px 0;
|
||||
h5 {
|
||||
font-size: 14px;
|
||||
> span {
|
||||
padding: 0 20px;
|
||||
}
|
||||
footer.footer{
|
||||
width:100%;color: #aaa;background: #555;margin-top:25px;position: fixed;bottom: 0;z-index:99;
|
||||
.copyright{
|
||||
line-height: 50px;text-align: center;background: #393939;margin:0;
|
||||
a{
|
||||
color: #aaa;
|
||||
&:hover{color: #fff;}
|
||||
}
|
||||
}
|
||||
h5 {
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
font-size: 32px;
|
||||
z-index: 1;
|
||||
color: #313131;
|
||||
> i {
|
||||
padding-left: 20px;
|
||||
background: #fff;
|
||||
}
|
||||
> span {
|
||||
padding: 0 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 16px;
|
||||
color: #919191;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.text-line {
|
||||
padding: 20px 0;
|
||||
h5 {
|
||||
font-size: 16px;
|
||||
}
|
||||
.subtitle {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width:767px) {
|
||||
header.carousel .carousel {
|
||||
height: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
footer.footer{width:100%;color: #aaa;background: #555;margin-top:25px;position: fixed;bottom: 0;}
|
||||
footer.footer ul{margin:60px 0 30px 0;padding:0;}
|
||||
footer.footer ul li.f-tit{margin-bottom:10px;font-size: 14px;color: #fff;}
|
||||
footer.footer ul li{line-height: 26px;white-space: nowrap;list-style: none;margin:0;padding:0;}
|
||||
footer.footer ul li a{color: #aaa;}
|
||||
footer.footer ul li a:hover{color: #aaa;text-decoration: underline !important;}
|
||||
footer.footer .address{line-height: 50px;text-align: center;background: #393939;margin:0;}
|
||||
footer p.address a{color: #aaa;}
|
||||
footer p.address a:hover{color: #fff;}
|
||||
@media(max-width:767px) {
|
||||
footer.footer {overflow: hidden;}
|
||||
footer.footer .container{margin:0 20px;}
|
||||
footer.footer ul {margin:20px 0 10px 0;}
|
||||
footer.footer .address{padding:0 10px;}
|
||||
}
|
||||
|
||||
.rotate{
|
||||
-webkit-transition-duration: 0.8s;
|
||||
-moz-transition-duration: 0.8s;
|
||||
-o-transition-duration: 0.8s;
|
||||
transition-duration: 0.8s;
|
||||
|
||||
-webkit-transition-property: -webkit-transform;
|
||||
-moz-transition-property: -moz-transform;
|
||||
-o-transition-property: -o-transform;
|
||||
transition-property: transform;
|
||||
|
||||
.transition-duration(0.8s);
|
||||
.transition-property(transform);
|
||||
overflow:hidden;
|
||||
&:hover
|
||||
{
|
||||
-webkit-transform:rotate(360deg);
|
||||
-moz-transform:rotate(360deg);
|
||||
-o-transform:rotate(360deg);
|
||||
&:hover{
|
||||
.transform(rotate(360deg));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.user-section {
|
||||
background: #fff;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
.border-radius(4px);
|
||||
border: 1px solid #e4ecf3;
|
||||
}
|
||||
.login-section {
|
||||
margin: 50px auto;
|
||||
width: 460px;
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
.border-radius(0);
|
||||
&.login-section-weixin {
|
||||
min-height: 315px;
|
||||
}
|
||||
|
|
@ -403,47 +315,42 @@ footer p.address a:hover{color: #fff;}
|
|||
.control-label {
|
||||
font-size:13px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.login-section {
|
||||
width: 100%;
|
||||
margin: 20px auto;
|
||||
.login-main {
|
||||
padding: 20px 0 0 0;
|
||||
.n-bootstrap {
|
||||
.form-group {
|
||||
position:relative;
|
||||
}
|
||||
.input-group {
|
||||
position: inherit;
|
||||
}
|
||||
.n-right {
|
||||
margin-top:0;
|
||||
top:0;
|
||||
position:absolute;
|
||||
left:0;
|
||||
text-align:right;
|
||||
width:100%;
|
||||
.msg-wrap {
|
||||
position:relative;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.login-modal {
|
||||
width: 350px;
|
||||
.modal-body {
|
||||
padding: 30px 30px 15px 30px;
|
||||
}
|
||||
.modal-footer {
|
||||
padding: 30px;
|
||||
}
|
||||
}
|
||||
main.content {
|
||||
width:100%;
|
||||
overflow:auto;
|
||||
top:0;
|
||||
position:absolute;
|
||||
z-index:10;
|
||||
bottom:50px;
|
||||
padding:15px;
|
||||
padding-top:67px;
|
||||
}
|
||||
|
||||
|
||||
#content-container {
|
||||
margin: 30px auto;
|
||||
min-height: 400px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
#content-container {
|
||||
min-height: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.sidenav {
|
||||
padding: 20px 0 10px 0;
|
||||
margin-bottom: 20px;
|
||||
background-color: #fff;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
.border-radius(4px);
|
||||
border: 1px solid #e4ecf3;
|
||||
.list-group{
|
||||
&:last-child {
|
||||
|
|
@ -457,16 +364,12 @@ footer p.address a:hover{color: #fff;}
|
|||
font-size:14px;
|
||||
}
|
||||
.list-group-item {
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
.border-radius(0);
|
||||
border: none;
|
||||
padding: 0;
|
||||
border-left: 2px solid transparent;
|
||||
&:last-child,&:first-child {
|
||||
-webkit-border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
border-radius: 0;
|
||||
.border-radius(0);
|
||||
}
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
|
|
@ -487,9 +390,6 @@ footer p.address a:hover{color: #fff;}
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.flarum-section ul li a{font-size:13px;}
|
||||
|
||||
.nav li{
|
||||
.avatar-text,.avatar-img {
|
||||
height:30px;
|
||||
|
|
@ -521,8 +421,28 @@ footer p.address a:hover{color: #fff;}
|
|||
}
|
||||
.avatar-img {
|
||||
font-size:0;
|
||||
img{
|
||||
border-radius:48px;
|
||||
width:48px;height:48px;
|
||||
}
|
||||
}
|
||||
.avatar-img img{
|
||||
border-radius:48px;
|
||||
width:48px;height:48px;
|
||||
|
||||
@media (max-width: 767px) {
|
||||
main.content {
|
||||
position:inherit;
|
||||
padding:15px 0;
|
||||
}
|
||||
|
||||
.login-section {
|
||||
width: 100%;
|
||||
margin: 20px auto;
|
||||
.login-main {
|
||||
padding: 20px 0 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
footer.footer {
|
||||
position:inherit;
|
||||
.copyright{padding:10px;line-height:30px;}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue