作者 Karson

新增前台会员模块和API会员模块

新增后台会员管理、会员规则和会员分组管理
新增短信发送的行为事件
新增前台Token、短信、日志模型
新增自动检测更新配制
新增插件信息查看
优化CRUD生成普通搜索的功能
优化后台登录后管理员Session的存储
正在显示 76 个修改的文件 包含 3597 行增加372 行删除
... ... @@ -63,7 +63,7 @@ class Crud extends Command
* 以指定字符结尾的字段格式化函数
*/
protected $fieldFormatterSuffix = [
'status' => 'status',
'status' => ['type' => ['varchar'], 'name' => 'status'],
'icon' => 'icon',
'flag' => 'flag',
'url' => 'url',
... ... @@ -672,7 +672,7 @@ class Crud extends Command
$javascriptList[] = "{checkbox: true}";
}
//构造JS列信息
$javascriptList[] = $this->getJsColumn($field, $v['DATA_TYPE'], $inputType && in_array($inputType, ['select', 'checkbox', 'radio']) ? '_text' : '');
$javascriptList[] = $this->getJsColumn($field, $v['DATA_TYPE'], $inputType && in_array($inputType, ['select', 'checkbox', 'radio']) ? '_text' : '', $itemArr);
//排序方式,如果有指定排序字段,否则按主键排序
$order = $field == $this->sortField ? $this->sortField : $order;
... ... @@ -1197,9 +1197,12 @@ EOD;
/**
* 获取JS列数据
* @param string $field
* @param string $datatype
* @param string $extend
* @param array $itemArr
* @return string
*/
protected function getJsColumn($field, $datatype = '', $extend = '')
protected function getJsColumn($field, $datatype = '', $extend = '', $itemArr = [])
{
$lang = mb_ucfirst($field);
$formatter = '';
... ... @@ -1236,10 +1239,41 @@ EOD;
$formatter = 'label';
}
}
foreach ($itemArr as $k => &$v)
{
if (substr($v, 0, 3) !== '__(')
$v = "__('" . $v . "')";
}
unset($v);
$searchList = json_encode($itemArr);
$searchList = str_replace(['":"', '"}', ')","'], ['":', '}', '),"'], $searchList);
if ($itemArr && !$extend)
{
$html .= ", searchList: " . $searchList;
}
echo $datatype, "\n";
if (in_array($datatype, ['date', 'datetime']) || $formatter === 'datetime')
{
$html .= ", operate:'RANGE', addclass:'datetimerange'";
}
else if (in_array($datatype,['float', 'double', 'decimal']))
{
$html .= ", operate:'BETWEEN'";
}
if ($formatter)
$html .= ", formatter: Table.api.formatter." . $formatter . "}";
else
$html .= "}";
if ($extend)
{
$origin = str_repeat(" ", 24) . "{field: '{$field}', title: __('{$lang}'), visible:false";
if ($searchList)
{
$origin .= ", searchList: " . $searchList;
}
$origin .= "}";
$html = $origin . ",\n" . $html;
}
return $html;
}
... ...
... ... @@ -6,7 +6,12 @@
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar()}
<a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a>
<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('{%controllerUrl%}/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>
<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('{%controllerUrl%}/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
<a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('{%controllerUrl%}/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>
<a href="javascript:;" class="btn btn-danger btn-import {:$auth->check('{%controllerUrl%}/import')?'':'hide'}" title="{:__('Import')}" id="btn-import-file" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"><i class="fa fa-upload"></i> {:__('Import')}</a>
<div class="dropdown btn-group {:$auth->check('{%controllerUrl%}/multi')?'':'hide'}">
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
<ul class="dropdown-menu text-left" role="menu">
... ...
... ... @@ -231,6 +231,25 @@ INSERT INTO `fa_auth_rule` VALUES (62, 'file', 4, 'addon/uninstall', 'Uninstall'
INSERT INTO `fa_auth_rule` VALUES (63, 'file', 4, 'addon/config', 'Setting', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (64, 'file', 4, 'addon/refresh', 'Refresh', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (65, 'file', 4, 'addon/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1502035509, 1502035509, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (66, 'file', 0, 'user', 'User', 'fa fa-list', '', '', 1, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (67, 'file', 66, 'user/user', 'User', 'fa fa-user', '', '', 1, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (68, 'file', 67, 'user/user/index', 'View', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (69, 'file', 67, 'user/user/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (70, 'file', 67, 'user/user/add', 'Add', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (71, 'file', 67, 'user/user/del', 'Del', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (72, 'file', 67, 'user/user/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (73, 'file', 66, 'user/group', 'User group', 'fa fa-users', '', '', 1, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (74, 'file', 73, 'user/group/add', 'Add', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (75, 'file', 73, 'user/group/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (76, 'file', 73, 'user/group/index', 'View', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (77, 'file', 73, 'user/group/del', 'Del', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (78, 'file', 73, 'user/group/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (79, 'file', 66, 'user/rule', 'User rule', 'fa fa-circle-o', '', '', 1, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (80, 'file', 79, 'user/rule/index', 'View', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (81, 'file', 79, 'user/rule/del', 'Del', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (82, 'file', 79, 'user/rule/add', 'Add', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (83, 'file', 79, 'user/rule/edit', 'Edit', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
INSERT INTO `fa_auth_rule` VALUES (84, 'file', 79, 'user/rule/multi', 'Multi', 'fa fa-circle-o', '', '', 0, 1516374729, 1516374729, 0, 'normal');
COMMIT;
-- ----------------------------
... ... @@ -362,4 +381,108 @@ BEGIN;
INSERT INTO `fa_test` VALUES (1, 0, 12, '12,13', 'monday', 'hot,index', 'male', 'music,reading', '我是一篇测试文章', '<p>我是测试内容</p>', '/assets/img/avatar.png', '/assets/img/avatar.png,/assets/img/qrcode.png', '/assets/img/avatar.png', '关键字', '描述', '广西壮族自治区/百色市/平果县', 0.00, 0, '2017-07-10', '2017-07-10 18:24:45', 2017, '18:24:45', 1499682285, 1499682526, 1499682526, 0, 1, 'normal', '1');
COMMIT;
DROP TABLE IF EXISTS `fa_user`;
CREATE TABLE `fa_user` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`group_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '组别ID',
`username` varchar(32) NOT NULL DEFAULT '' COMMENT '用户名',
`nickname` varchar(50) NOT NULL DEFAULT '' COMMENT '昵称',
`password` varchar(32) NOT NULL DEFAULT '' COMMENT '密码',
`salt` varchar(30) NOT NULL DEFAULT '' COMMENT '密码盐',
`email` varchar(100) NOT NULL DEFAULT '' COMMENT '电子邮箱',
`mobile` varchar(11) NOT NULL DEFAULT '' COMMENT '手机号',
`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 '格言',
`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 '最大连续登录天数',
`prevtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '上次登录时间',
`logintime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '登录时间',
`loginip` varchar(50) NOT NULL DEFAULT '' COMMENT '登录IP',
`loginfailure` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '失败次数',
`joinip` varchar(50) NOT NULL DEFAULT '' COMMENT '加入IP',
`jointime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '加入时间',
`createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
`token` varchar(50) NOT NULL DEFAULT '' COMMENT 'Token',
`status` varchar(30) NOT NULL DEFAULT '' COMMENT '状态',
PRIMARY KEY (`id`),
KEY `username` (`username`),
KEY `email` (`email`),
KEY `mobile` (`mobile`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='会员表';
BEGIN;
INSERT INTO `fa_user` VALUES (1, 1, 'admin', 'admin', 'c13f62012fd6a8fdf06b3452a94430e5', 'rpR6Bv', 'admin@163.com', '13888888888', '/assets/img/avatar.png', 0, 0, '2017-04-15', '', 0, 1, 1, 1516170492, 1516171614, '127.0.0.1', 0, '127.0.0.1', 1491461418, 0, 1516171614, '', 'normal');
COMMIT;
DROP TABLE IF EXISTS `fa_user_group`;
CREATE TABLE `fa_user_group` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT '' COMMENT '组名',
`rules` text COMMENT '权限节点',
`createtime` int(10) DEFAULT NULL COMMENT '添加时间',
`updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
`status` enum('normal','hidden') DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='会员组表';
BEGIN;
INSERT INTO `fa_user_group` VALUES (1, '默认组', '1,2,3,4,5,6,7,8,9,10,11,12', 1515386468, 1516168298, 'normal');
COMMIT;
DROP TABLE IF EXISTS `fa_user_rule`;
CREATE TABLE `fa_user_rule` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`pid` int(10) DEFAULT NULL COMMENT '父ID',
`name` varchar(50) DEFAULT NULL COMMENT '名称',
`title` varchar(50) DEFAULT '' COMMENT '标题',
`remark` varchar(100) DEFAULT NULL COMMENT '备注',
`ismenu` tinyint(1) DEFAULT NULL COMMENT '是否菜单',
`createtime` int(10) DEFAULT NULL COMMENT '创建时间',
`updatetime` int(10) DEFAULT NULL COMMENT '更新时间',
`weigh` int(10) DEFAULT '0' COMMENT '权重',
`status` enum('normal','hidden') DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 COMMENT='会员规则表';
BEGIN;
INSERT INTO `fa_user_rule` VALUES (1, 0, 'index', '前台', '', 1, 1516168079, 1516168079, 1, 'normal');
INSERT INTO `fa_user_rule` VALUES (2, 0, 'api', 'API接口', '', 1, 1516168062, 1516168062, 2, 'normal');
INSERT INTO `fa_user_rule` VALUES (3, 1, 'user', '会员模块', '', 1, 1515386221, 1516168103, 12, 'normal');
INSERT INTO `fa_user_rule` VALUES (4, 2, 'user', '会员模块', '', 1, 1515386221, 1516168092, 11, 'normal');
INSERT INTO `fa_user_rule` VALUES (5, 3, 'index/user/login', '登录', '', 0, 1515386247, 1515386247, 5, 'normal');
INSERT INTO `fa_user_rule` VALUES (6, 3, 'index/user/register', '注册', '', 0, 1515386262, 1516015236, 7, 'normal');
INSERT INTO `fa_user_rule` VALUES (7, 3, 'index/user/index', '会员中心', '', 0, 1516015012, 1516015012, 9, 'normal');
INSERT INTO `fa_user_rule` VALUES (8, 3, 'index/user/profile', '个人资料', '', 0, 1516015012, 1516015012, 4, 'normal');
INSERT INTO `fa_user_rule` VALUES (9, 4, 'api/user/login', '登录', '', 0, 1515386247, 1515386247, 6, 'normal');
INSERT INTO `fa_user_rule` VALUES (10, 4, 'api/user/register', '注册', '', 0, 1515386262, 1516015236, 8, 'normal');
INSERT INTO `fa_user_rule` VALUES (11, 4, 'api/user/index', '会员中心', '', 0, 1516015012, 1516015012, 10, 'normal');
INSERT INTO `fa_user_rule` VALUES (12, 4, 'api/user/profile', '个人资料', '', 0, 1516015012, 1516015012, 3, 'normal');
COMMIT;
DROP TABLE IF EXISTS `fa_user_score_log`;
CREATE TABLE `fa_user_score_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
`score` int(10) NOT NULL DEFAULT '0' COMMENT '变更积分',
`before` int(10) NOT NULL DEFAULT '0' COMMENT '变更前积分',
`after` int(10) NOT NULL DEFAULT '0' COMMENT '变更后积分',
`memo` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
`createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='会员积分变动表';
DROP TABLE IF EXISTS `fa_user_token`;
CREATE TABLE `fa_user_token` (
`token` varchar(50) NOT NULL COMMENT 'Token',
`user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '会员ID',
`createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`expiretime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '过期时间',
PRIMARY KEY (`token`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='会员Token表';
SET FOREIGN_KEY_CHECKS = 1;
... ...
... ... @@ -114,7 +114,7 @@ function build_toolbar($btns = NULL, $attr = [])
continue;
}
list($href, $class, $icon, $text, $title) = $btnAttr[$v];
$extend = $v == 'import' ? 'id="btn-import-' . \fast\Random::alpha() . '" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"' : '';
$extend = $v == 'import' ? 'id="btn-import-file" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"' : '';
$html[] = '<a href="' . $href . '" class="' . $class . '" title="' . $title . '" ' . $extend . '><i class="' . $icon . '"></i> ' . $text . '</a>';
}
return implode(' ', $html);
... ...
... ... @@ -49,7 +49,7 @@ class Index extends Backend
$url = $this->request->get('url', 'index/index');
if ($this->auth->isLogin())
{
$this->error(__("You've logged in, do not login again"), $url);
$this->success(__("You've logged in, do not login again"), $url);
}
if ($this->request->isPost())
{
... ...
<?php
namespace app\admin\controller\user;
use app\common\controller\Backend;
/**
* 会员组管理
*
* @icon fa fa-users
*/
class Group extends Backend
{
/**
* UserGroup模型对象
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('UserGroup');
$this->view->assign("statusList", $this->model->getStatusList());
}
public function add()
{
$nodeList = \app\admin\model\UserRule::getTreeList();
$this->assign("nodeList", $nodeList);
return parent::add();
}
public function edit($ids = NULL)
{
$row = $this->model->get($ids);
if (!$row)
$this->error(__('No Results were found'));
$rules = explode(',', $row['rules']);
$nodeList = \app\admin\model\UserRule::getTreeList($rules);
$this->assign("nodeList", $nodeList);
return parent::edit($ids);
}
}
... ...
<?php
namespace app\admin\controller\user;
use app\common\controller\Backend;
use fast\Tree;
/**
* 会员规则管理
*
* @icon fa fa-circle-o
*/
class Rule extends Backend
{
/**
* UserRule模型对象
*/
protected $model = null;
protected $rulelist = [];
public function _initialize()
{
parent::_initialize();
$this->model = model('UserRule');
$this->view->assign("statusList", $this->model->getStatusList());
// 必须将结果集转换为数组
$ruleList = collection($this->model->order('weigh', 'desc')->select())->toArray();
foreach ($ruleList as $k => &$v)
{
$v['title'] = __($v['title']);
$v['remark'] = __($v['remark']);
}
unset($v);
Tree::instance()->init($ruleList);
$this->rulelist = Tree::instance()->getTreeList(Tree::instance()->getTreeArray(0), 'title');
$ruledata = [0 => __('None')];
foreach ($this->rulelist as $k => &$v)
{
if (!$v['ismenu'])
continue;
$ruledata[$v['id']] = $v['title'];
}
$this->view->assign('ruledata', $ruledata);
}
/**
* 查看
*/
public function index()
{
if ($this->request->isAjax())
{
$list = $this->rulelist;
$total = count($this->rulelist);
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
/**
* 删除
*/
public function del($ids = "")
{
if ($ids)
{
$delIds = [];
foreach (explode(',', $ids) as $k => $v)
{
$delIds = array_merge($delIds, Tree::instance()->getChildrenIds($v, TRUE));
}
$delIds = array_unique($delIds);
$count = $this->model->where('id', 'in', $delIds)->delete();
if ($count)
{
$this->success();
}
}
$this->error();
}
}
... ...
<?php
namespace app\admin\controller\user;
use app\common\controller\Backend;
/**
* 会员管理
*
* @icon fa fa-user
*/
class User extends Backend
{
protected $relationSearch = true;
/**
* User模型对象
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = model('User');
}
/**
* 查看
*/
public function index()
{
//设置过滤方法
$this->request->filter(['strip_tags']);
if ($this->request->isAjax())
{
//如果发送的来源是Selectpage,则转发到Selectpage
if ($this->request->request('pkey_name'))
{
return $this->selectpage();
}
list($where, $sort, $order, $offset, $limit) = $this->buildparams();
$total = $this->model
->with('group')
->where($where)
->order($sort, $order)
->count();
$list = $this->model
->with('group')
->where($where)
->order($sort, $order)
->limit($offset, $limit)
->select();
foreach ($list as $k => $v)
{
$v->password = '';
$v->salt = '';
}
$result = array("total" => $total, "rows" => $list);
return json($result);
}
return $this->view->fetch();
}
/**
* 编辑
*/
public function edit($ids = NULL)
{
$row = $this->model->get($ids);
if (!$row)
$this->error(__('No Results were found'));
$this->view->assign('groupList', build_select('row[group_id]', \app\admin\model\UserGroup::column('id,name'), $row['group_id'], ['class' => 'form-control selectpicker']));
return parent::edit($ids);
}
}
... ...
... ... @@ -144,6 +144,9 @@ return [
'Admin log' => '管理员日志',
'Group' => '角色组',
'Rule' => '规则管理',
'User' => '会员管理',
'User group' => '会员分组',
'User rule' => '会员规则',
'Select attachment' => '选择附件',
'Update profile' => '更新个人信息',
'Local install' => '本地安装',
... ...
... ... @@ -25,6 +25,8 @@ return [
'Offline installed tips' => '插件安装成功!你需要手动启用该插件,并清除缓存使之生效',
'Online installed tips' => '插件安装成功!清除插件缓存和框架缓存后生效!',
'Not login tips' => '你当前未登录FastAdmin,登录后将同步已购买的记录,下载时无需二次付费!',
'Not installed tips' => '请安装后再访问插件前台页面!',
'Not enabled tips' => '插件已经禁用,请启用后再访问插件前台页面!',
'Login now' => '立即登录',
'Continue install' => '不登录,继续安装',
'Recommend' => '推荐',
... ... @@ -33,11 +35,18 @@ return [
'Free' => '免费',
'Sale' => '折扣',
'No image' => '暂无缩略图',
'Price' => '价格',
'Author' => '作者',
'Identify' => '标识',
'Homepage' => '主页',
'Intro' => '介绍',
'Version' => '版本',
'Createtime' => '添加时间',
'Releasetime' => '更新时间',
'Detail' => '插件详情',
'Document' => '文档',
'Demo' => '在线演示',
'Feedback' => '反馈BUG',
'Install' => '安装',
'Uninstall' => '卸载',
'Setting' => '配置',
... ...
<?php
return [
'Name' => '组名',
'Rules' => '权限节点',
'Createtime' => '添加时间',
'Updatetime' => '更新时间',
'Status' => '状态'
];
... ...
<?php
return [
'Pid' => '父ID',
'Name' => '规则',
'Title' => '标题',
'Remark' => '备注',
'Ismenu' => '是否菜单',
'Createtime' => '创建时间',
'Updatetime' => '更新时间',
'Menu tips' => '规则任意,请不可重复,仅做层级显示,无需匹配控制器和方法',
'Node tips' => '模块/控制器/方法名',
'Weigh' => '权重',
'Status' => '状态'
];
... ...
<?php
return [
'Id' => 'ID',
'Group_id' => '组别ID',
'Username' => '用户名',
'Nickname' => '昵称',
'Password' => '密码',
'Salt' => '密码盐',
'Email' => '电子邮箱',
'Mobile' => '手机号',
'Avatar' => '头像',
'Level' => '等级',
'Gender' => '性别',
'Birthday' => '生日',
'Bio' => '格言',
'Score' => '积分',
'Successions' => '连续登录天数',
'Maxsuccessions' => '最大连续登录天数',
'Prevtime' => '上次登录时间',
'Logintime' => '登录时间',
'Loginip' => '登录IP',
'Loginfailure' => '失败次数',
'Joinip' => '加入IP',
'Jointime' => '加入时间',
'Createtime' => '创建时间',
'Updatetime' => '更新时间',
'Token' => 'Token',
'Status' => '状态'
];
... ...
... ... @@ -44,7 +44,7 @@ class Auth extends \fast\Auth
$admin->logintime = time();
$admin->token = Random::uuid();
$admin->save();
Session::set("admin", $admin);
Session::set("admin", $admin->toArray());
$this->keeplogin($keeptime);
return true;
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class User extends Model
{
// 表名
protected $name = 'user';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
// 追加属性
protected $append = [
'prevtime_text',
'logintime_text',
'jointime_text'
];
protected static function init()
{
self::beforeUpdate(function ($row) {
$changed = $row->getChangedData();
//如果有修改密码
if (isset($changed['password']))
{
$salt = \fast\Random::alnum();
$row->password = \app\common\library\Auth::instance()->getEncryptPassword($changed['password'], $salt);
$row->salt = $salt;
}
});
}
public function getGenderList()
{
return ['1' => __('Male'), '0' => __('Female')];
}
public function getStatusList()
{
return ['normal' => __('Normal'), 'hidden' => __('Hidden')];
}
public function getPrevtimeTextAttr($value, $data)
{
$value = $value ? $value : $data['prevtime'];
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getLogintimeTextAttr($value, $data)
{
$value = $value ? $value : $data['logintime'];
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
public function getJointimeTextAttr($value, $data)
{
$value = $value ? $value : $data['jointime'];
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
protected function setPrevtimeAttr($value)
{
return $value && !is_numeric($value) ? strtotime($value) : $value;
}
protected function setLogintimeAttr($value)
{
return $value && !is_numeric($value) ? strtotime($value) : $value;
}
protected function setJointimeAttr($value)
{
return $value && !is_numeric($value) ? strtotime($value) : $value;
}
public function group()
{
return $this->belongsTo('UserGroup', 'group_id', 'id', [], 'LEFT')->setEagerlyType(0);
}
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class UserGroup extends Model
{
// 表名
protected $name = 'user_group';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
// 追加属性
protected $append = [
'status_text'
];
public function getStatusList()
{
return ['normal' => __('Normal'), 'hidden' => __('Hidden')];
}
public function getStatusTextAttr($value, $data)
{
$value = $value ? $value : $data['status'];
$list = $this->getStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
}
... ...
<?php
namespace app\admin\model;
use think\Model;
class UserRule extends Model
{
// 表名
protected $name = 'user_rule';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
// 追加属性
protected $append = [
'status_text'
];
protected static function init()
{
self::afterInsert(function ($row) {
$pk = $row->getPk();
$row->getQuery()->where($pk, $row[$pk])->update(['weigh' => $row[$pk]]);
});
}
public function getStatusList()
{
return ['normal' => __('Normal'), 'hidden' => __('Hidden')];
}
public function getStatusTextAttr($value, $data)
{
$value = $value ? $value : $data['status'];
$list = $this->getStatusList();
return isset($list[$value]) ? $list[$value] : '';
}
public static function getTreeList($selected = [])
{
$ruleList = collection(self::where('status', 'normal')->select())->toArray();
$nodeList = [];
foreach ($ruleList as $k => $v)
{
$state = array('selected' => $v['ismenu'] ? false : in_array($v['id'], $selected));
$nodeList[] = array('id' => $v['id'], 'parent' => $v['pid'] ? $v['pid'] : '#', 'text' => __($v['title']), 'type' => 'menu', 'state' => $state);
}
return $nodeList;
}
}
... ...
<?php
namespace app\admin\validate;
use think\Validate;
class User extends Validate
{
/**
* 验证规则
*/
protected $rule = [
];
/**
* 提示消息
*/
protected $message = [
];
/**
* 验证场景
*/
protected $scene = [
'add' => [],
'edit' => [],
];
}
... ...
<?php
namespace app\admin\validate;
use think\Validate;
class UserGroup extends Validate
{
/**
* 验证规则
*/
protected $rule = [
];
/**
* 提示消息
*/
protected $message = [
];
/**
* 验证场景
*/
protected $scene = [
'add' => [],
'edit' => [],
];
}
... ...
<?php
namespace app\admin\validate;
use think\Validate;
class UserRule extends Validate
{
/**
* 验证规则
*/
protected $rule = [
];
/**
* 提示消息
*/
protected $message = [
];
/**
* 验证场景
*/
protected $scene = [
'add' => [],
'edit' => [],
];
}
... ...
... ... @@ -77,6 +77,51 @@
</form>
</div>
</script>
<script id="addoninfotpl" type="text/html">
<div style="font-size:13px;">
<table class="table table-striped">
<thead>
<tr>
<th colspan="2"><h4><%=item.title%></h4></th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">{:__('Price')}</th>
<td><div class="text-<%=item.price>0?'danger':'success'%>"><b><%=item.price%></b></div></td>
</tr>
<tr>
<th scope="row">{:__('Author')}</th>
<td><a href="<%=item.url?item.url:'javascript:;'%>" target="_blank"><%=item.author%></a></td>
</tr>
<tr>
<th scope="row">{:__('Identify')}</th>
<td><%=item.name%></td>
</tr>
<tr>
<th scope="row">{:__('Homepage')}</th>
<td><a href="http://www.fastadmin.net/store/<%=item.name%>.html" target="_blank">http://www.fastadmin.net/store/<%=item.name%>.html</a></td>
</tr>
<tr>
<th scope="row">{:__('Intro')}</th>
<td><%=item.intro%></td>
</tr>
<tr>
<th scope="row">{:__('Version')}</th>
<td><%=# addon && item && addon.version!=item.version?'<span class="label label-danger">'+addon.version+'</span> -> <span class="label label-success">'+item.version+'</span>':item.version%></td>
</tr>
<tr>
<th scope="row">{:__('Createtime')}</th>
<td><%=Moment(item.createtime*1000).format("YYYY-MM-DD HH:mm:ss")%></td>
</tr>
<tr>
<th scope="row">{:__('Releasetime')}</th>
<td><%=Moment(item.releasetime*1000).format("YYYY-MM-DD HH:mm:ss")%></td>
</tr>
</tbody>
</table>
</div>
</script>
<script id="paytpl" type="text/html">
<div class="payimg" style="background:url('<%=payimg%>') 0 0 no-repeat;background-size:cover;">
<%if(paycode){%>
... ... @@ -117,8 +162,8 @@
<% var label = labelarr[item.id % 5]; %>
<% var addon = typeof addons[item.name]!= 'undefined' ? addons[item.name] : null; %>
<div class="thumbnail addon">
<!--<span class="btn btn-<%=label%>">ID:<%=item.id%></span>-->
<a href="<%=addon?addon.url:'javascript:;'%>" target="_blank">
<!--<span class="btn btn-primary"><%=item.name%></span>-->
<a href="<%=addon?addon.url:'javascript:;'%>" class="btn-addonindex" target="_blank">
<%if(item.image){%>
<img src="<%=item.image%>" class="img-responsive" alt="<%=item.title%>">
<%}else{%>
... ... @@ -164,11 +209,11 @@
<a href="javascript:;" class="btn btn-danger btn-uninstall"><i class="fa fa-times"></i> {:__('Uninstall')}</a>
<% } %>
<% } %>
<!--
<span class="pull-right" style="margin-top:10px;">
<input name="checkbox" data-id="<%=item.id%>" type="checkbox" />
<a href="javascript:;" class="btn-addoninfo text-gray" data-index="<%=i%>" title="<%=item.title?item.title:'{:__('None')}'%>"><i class="fa fa-bars"></i></a>
</span>
-->
</p>
</div>
</div>
... ...
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<input type="hidden" name="row[rules]" />
<div class="form-group">
<label for="c-name" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-name" class="form-control" name="row[name]" type="text" value="">
</div>
</div>
<div class="form-group">
<label for="nickname" class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label>
<div class="col-xs-12 col-sm-8">
<span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><small>{:__('Check all')}</small></label></span>
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><small>{:__('Expand all')}</small></label></span>
<div id="treeview"></div>
</div>
</div>
<div class="form-group">
<label for="c-status" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="radio">
{foreach name="statusList" item="vo"}
<label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio" value="{$key}" {in name="key" value="normal"}checked{/in} /> {$vo}</label>
{/foreach}
</div>
</div>
</div>
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
<script>
var nodeData = {:json_encode($nodeList); };
</script>
\ No newline at end of file
... ...
<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<input type="hidden" name="row[rules]" value="{$row.rules}" />
<div class="form-group">
<label for="c-name" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-name" class="form-control" name="row[name]" type="text" value="{$row.name}">
</div>
</div>
<div class="form-group">
<label for="nickname" class="control-label col-xs-12 col-sm-2">{:__('Permission')}:</label>
<div class="col-xs-12 col-sm-8">
<span class="text-muted"><input type="checkbox" name="" id="checkall" /> <label for="checkall"><small>{:__('Check all')}</small></label></span>
<span class="text-muted"><input type="checkbox" name="" id="expandall" /> <label for="expandall"><small>{:__('Expand all')}</small></label></span>
<div id="treeview"></div>
</div>
</div>
<div class="form-group">
<label for="c-status" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="radio">
{foreach name="statusList" item="vo"}
<label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio" value="{$key}" {in name="key" value="$row.status"}checked{/in} /> {$vo}</label>
{/foreach}
</div>
</div>
</div>
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
<script>
var nodeData = {:json_encode($nodeList); };
</script>
... ...
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar()}
<div class="dropdown btn-group {:$auth->check('user/group/multi')?'':'hide'}">
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
<ul class="dropdown-menu text-left" role="menu">
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li>
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li>
</ul>
</div>
</div>
<table id="table" class="table table-striped table-bordered table-hover"
data-operate-edit="{:$auth->check('user/group/edit')}"
data-operate-del="{:$auth->check('user/group/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Ismenu')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[ismenu]', ['1'=>__('Yes'), '0'=>__('No')])}
</div>
</div>
<div class="form-group">
<label for="c-pid" class="control-label col-xs-12 col-sm-2">{:__('Pid')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $ruledata, null, ['class'=>'form-control', 'required'=>''])}
</div>
</div>
<div class="form-group">
<label for="c-name" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-name" class="form-control" name="row[name]" type="text" data-placeholder-node="{:__('Node tips')}" data-placeholder-menu="{:__('Menu tips')}">
</div>
</div>
<div class="form-group">
<label for="c-title" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-title" class="form-control" name="row[title]" type="text" value="">
</div>
</div>
<div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Remark')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="remark" name="row[remark]"></textarea>
</div>
</div>
<div class="form-group">
<label for="c-weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-weigh" class="form-control" name="row[weigh]" type="number" value="0">
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')])}
</div>
</div>
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Ismenu')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[ismenu]', ['1'=>__('Yes'), '0'=>__('No')], $row['ismenu'])}
</div>
</div>
<div class="form-group">
<label for="pid" class="control-label col-xs-12 col-sm-2">{:__('Parent')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_select('row[pid]', $ruledata, $row['pid'], ['class'=>'form-control', 'required'=>''])}
</div>
</div>
<div class="form-group">
<label for="c-name" class="control-label col-xs-12 col-sm-2">{:__('Name')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-name" class="form-control" name="row[name]" type="text" placeholder="{:__('Controller/Action')}" value="{$row.name}">
</div>
</div>
<div class="form-group">
<label for="c-title" class="control-label col-xs-12 col-sm-2">{:__('Title')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-title" class="form-control" name="row[title]" type="text" value="{$row.title}">
</div>
</div>
<div class="form-group">
<label for="remark" class="control-label col-xs-12 col-sm-2">{:__('Remark')}:</label>
<div class="col-xs-12 col-sm-8">
<textarea class="form-control" id="remark" name="row[remark]">{$row.remark}</textarea>
</div>
</div>
<div class="form-group">
<label for="c-weigh" class="control-label col-xs-12 col-sm-2">{:__('Weigh')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-weigh" class="form-control" name="row[weigh]" type="number" value="{$row.weigh}">
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
</div>
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar()}
<div class="dropdown btn-group {:$auth->check('user/rule/multi')?'':'hide'}">
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
<ul class="dropdown-menu text-left" role="menu">
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li>
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li>
</ul>
</div>
</div>
<table id="table" class="table table-striped table-bordered table-hover"
data-operate-edit="{:$auth->check('user/rule/edit')}"
data-operate-del="{:$auth->check('user/rule/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label for="c-group_id" class="control-label col-xs-12 col-sm-2">{:__('Group')}:</label>
<div class="col-xs-12 col-sm-4">
{$groupList}
</div>
</div>
<div class="form-group">
<label for="c-username" class="control-label col-xs-12 col-sm-2">{:__('Username')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-username" data-rule="required" class="form-control" name="row[username]" type="text" value="{$row.username}">
</div>
</div>
<div class="form-group">
<label for="c-nickname" class="control-label col-xs-12 col-sm-2">{:__('Nickname')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-nickname" data-rule="required" class="form-control" name="row[nickname]" type="text" value="{$row.nickname}">
</div>
</div>
<div class="form-group">
<label for="c-password" class="control-label col-xs-12 col-sm-2">{:__('Password')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-password" data-rule="" class="form-control" name="row[password]" type="text" value="" placeholder="{:__('Leave password blank if dont want to change')}" autocomplete="new-password" />
</div>
</div>
<div class="form-group">
<label for="c-email" class="control-label col-xs-12 col-sm-2">{:__('Email')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-email" data-rule="" class="form-control" name="row[email]" type="text" value="{$row.email}">
</div>
</div>
<div class="form-group">
<label for="c-mobile" class="control-label col-xs-12 col-sm-2">{:__('Mobile')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-mobile" data-rule="" class="form-control" name="row[mobile]" type="text" value="{$row.mobile}">
</div>
</div>
<div class="form-group">
<label for="c-avatar" class="control-label col-xs-12 col-sm-2">{:__('Avatar')}:</label>
<div class="col-xs-12 col-sm-8">
<div class="input-group">
<input id="c-avatar" data-rule="" class="form-control" size="50" name="row[avatar]" type="text" value="{$row.avatar}">
<div class="input-group-addon no-border no-padding">
<span><button type="button" id="plupload-avatar" class="btn btn-danger plupload" data-input-id="c-avatar" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-avatar"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
<span><button type="button" id="fachoose-avatar" class="btn btn-primary fachoose" data-input-id="c-avatar" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
</div>
<span class="msg-box n-right" for="c-avatar"></span>
</div>
<ul class="row list-inline plupload-preview" id="p-avatar"></ul>
</div>
</div>
<div class="form-group">
<label for="c-level" class="control-label col-xs-12 col-sm-2">{:__('Level')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-level" data-rule="required" class="form-control" name="row[level]" type="number" value="{$row.level}">
</div>
</div>
<div class="form-group">
<label for="c-gender" class="control-label col-xs-12 col-sm-2">{:__('Gender')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[gender]', ['1'=>__('Male'), '0'=>__('Female')], $row['gender'])}
</div>
</div>
<div class="form-group">
<label for="c-birthday" class="control-label col-xs-12 col-sm-2">{:__('Birthday')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-birthday" data-rule="" class="form-control datetimepicker" data-date-format="YYYY-MM-DD" data-use-current="true" name="row[birthday]" type="text" value="{$row.birthday}">
</div>
</div>
<div class="form-group">
<label for="c-bio" class="control-label col-xs-12 col-sm-2">{:__('Bio')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-bio" data-rule="" class="form-control" name="row[bio]" type="text" value="{$row.bio}">
</div>
</div>
<div class="form-group">
<label for="c-score" class="control-label col-xs-12 col-sm-2">{:__('Score')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-score" data-rule="required" class="form-control" name="row[score]" type="number" value="{$row.score}">
</div>
</div>
<div class="form-group">
<label for="c-successions" class="control-label col-xs-12 col-sm-2">{:__('Successions')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-successions" data-rule="required" class="form-control" name="row[successions]" type="number" value="{$row.successions}">
</div>
</div>
<div class="form-group">
<label for="c-maxsuccessions" class="control-label col-xs-12 col-sm-2">{:__('Maxsuccessions')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-maxsuccessions" data-rule="required" class="form-control" name="row[maxsuccessions]" type="number" value="{$row.maxsuccessions}">
</div>
</div>
<div class="form-group">
<label for="c-prevtime" class="control-label col-xs-12 col-sm-2">{:__('Prevtime')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-prevtime" data-rule="required" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[prevtime]" type="text" value="{$row.prevtime|datetime}">
</div>
</div>
<div class="form-group">
<label for="c-logintime" class="control-label col-xs-12 col-sm-2">{:__('Logintime')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-logintime" data-rule="required" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[logintime]" type="text" value="{$row.logintime|datetime}">
</div>
</div>
<div class="form-group">
<label for="c-loginip" class="control-label col-xs-12 col-sm-2">{:__('Loginip')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-loginip" data-rule="required" class="form-control" name="row[loginip]" type="text" value="{$row.loginip}">
</div>
</div>
<div class="form-group">
<label for="c-loginfailure" class="control-label col-xs-12 col-sm-2">{:__('Loginfailure')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-loginfailure" data-rule="required" class="form-control" name="row[loginfailure]" type="number" value="{$row.loginfailure}">
</div>
</div>
<div class="form-group">
<label for="c-joinip" class="control-label col-xs-12 col-sm-2">{:__('Joinip')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-joinip" data-rule="required" class="form-control" name="row[joinip]" type="text" value="{$row.joinip}">
</div>
</div>
<div class="form-group">
<label for="c-jointime" class="control-label col-xs-12 col-sm-2">{:__('Jointime')}:</label>
<div class="col-xs-12 col-sm-4">
<input id="c-jointime" data-rule="required" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[jointime]" type="text" value="{$row.jointime|datetime}">
</div>
</div>
<div class="form-group">
<label for="content" class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
{:build_radios('row[status]', ['normal'=>__('Normal'), 'hidden'=>__('Hidden')], $row['status'])}
</div>
</div>
<div class="form-group layer-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
{:build_toolbar('refresh,edit,del')}
<div class="dropdown btn-group {:$auth->check('user/user/multi')?'':'hide'}">
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
<ul class="dropdown-menu text-left" role="menu">
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li>
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li>
</ul>
</div>
</div>
<table id="table" class="table table-striped table-bordered table-hover"
data-operate-edit="{:$auth->check('user/user/edit')}"
data-operate-del="{:$auth->check('user/user/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
... ... @@ -5,6 +5,7 @@ namespace app\api\controller;
use app\api\model\Area;
use app\common\controller\Api;
use fast\Version;
use fast\Random;
use think\Config;
/**
... ... @@ -13,7 +14,7 @@ use think\Config;
class Common extends Api
{
protected $noNeedLogin = '*';
protected $noNeedLogin = ['init'];
protected $noNeedRight = '*';
public function _initialize()
... ... @@ -24,8 +25,9 @@ class Common extends Api
/**
* 加载初始化
*
* 必选参数:version<br>
* 可选参数:lng,lat
* @param string $version 版本号
* @param string $lng 经度
* @param string $lat 纬度
*/
public function init()
{
... ... @@ -47,4 +49,94 @@ class Common extends Api
}
}
/**
* 上传文件
*
* @param File $file 文件流
*/
public function upload()
{
$file = $this->request->file('file');
if (empty($file))
{
$this->error(__('No file upload or server upload limit exceeded'));
}
//判断是否已经存在附件
$sha1 = $file->hash();
$upload = Config::get('upload');
preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches);
$type = strtolower($matches[2]);
$typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
$size = (int) $upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
$fileInfo = $file->getInfo();
$suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
$suffix = $suffix ? $suffix : 'file';
$mimetypeArr = explode(',', $upload['mimetype']);
$typeArr = explode('/', $fileInfo['type']);
//验证文件后缀
if ($upload['mimetype'] !== '*' && !in_array($suffix, $mimetypeArr) && !in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr))
{
$this->error(__('Uploaded file format is limited'));
}
$replaceArr = [
'{year}' => date("Y"),
'{mon}' => date("m"),
'{day}' => date("d"),
'{hour}' => date("H"),
'{min}' => date("i"),
'{sec}' => date("s"),
'{random}' => Random::alnum(16),
'{random32}' => Random::alnum(32),
'{filename}' => $suffix ? substr($fileInfo['name'], 0, strripos($fileInfo['name'], '.')) : $fileInfo['name'],
'{suffix}' => $suffix,
'{.suffix}' => $suffix ? '.' . $suffix : '',
'{filemd5}' => md5_file($fileInfo['tmp_name']),
];
$savekey = $upload['savekey'];
$savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey);
$uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1);
$fileName = substr($savekey, strripos($savekey, '/') + 1);
//
$splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
if ($splInfo)
{
$imagewidth = $imageheight = 0;
if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']))
{
$imgInfo = getimagesize($splInfo->getPathname());
$imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
$imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
}
$params = array(
'filesize' => $fileInfo['size'],
'imagewidth' => $imagewidth,
'imageheight' => $imageheight,
'imagetype' => $suffix,
'imageframes' => 0,
'mimetype' => $fileInfo['type'],
'url' => $uploadDir . $splInfo->getSaveName(),
'uploadtime' => time(),
'storage' => 'local',
'sha1' => $sha1,
);
$attachment = model("attachment");
$attachment->data(array_filter($params));
$attachment->save();
\think\Hook::listen("upload_after", $attachment);
$this->success(__('Upload successful'), [
'url' => $uploadDir . $splInfo->getSaveName()
]);
}
else
{
// 上传失败获取错误信息
$this->error($file->getError());
}
}
}
... ...
... ... @@ -22,8 +22,6 @@ class Demo extends Api
/**
* 无需登录的接口
*
* 必选参数:无<br>
* 可选参数:无
*/
public function test1()
{
... ... @@ -33,8 +31,6 @@ class Demo extends Api
/**
* 需要登录的接口
*
* 必选参数:token<br>
* 可选参数:无
*/
public function test2()
{
... ... @@ -44,8 +40,6 @@ class Demo extends Api
/**
* 需要登录且需要验证有相应组的权限
*
* 必选参数:token<br>
* 可选参数:无
*/
public function test3()
{
... ...
... ... @@ -16,8 +16,6 @@ class Index extends Api
/**
* 首页
*
* 必选参数:无<br>
* 可选参数:lng,lat
*/
public function index()
{
... ...
... ... @@ -23,35 +23,40 @@ class Sms extends Api
/**
* 发送验证码
*
* 必选参数:mobile,type<br>
* 可选参数:无
* @param string $mobile 手机号
* @param string $event 事件名称
*/
public function send()
{
$mobile = $this->request->request("mobile");
$type = $this->request->request("type");
$type = $type ? $type : 'register';
$event = $this->request->request("event");
$event = $event ? $event : 'register';
$last = Smslib::get($mobile, $type);
$last = Smslib::get($mobile, $event);
if ($last && time() - $last['createtime'] < 60)
{
$this->error(__('发送频繁'));
}
if ($type)
if ($event)
{
$userinfo = User::getByMobile($mobile);
if ($type == 'register' && $userinfo)
if ($event == 'register' && $userinfo)
{
//已被注册
$this->error(__('已被注册'));
}
else if (in_array($type, ['changepwd', 'resetpwd']) && !$userinfo)
else if (in_array($event, ['changemobile']) && $userinfo)
{
//被占用
$this->error(__('已被占用'));
}
else if (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo)
{
//未注册
$this->error(__('未注册'));
}
}
$ret = Smslib::send($mobile, '', $type);
$ret = Smslib::send($mobile, NULL, $event);
if ($ret)
{
$this->success(__('发送成功'));
... ... @@ -65,31 +70,37 @@ class Sms extends Api
/**
* 检测验证码
*
* 必选参数:mobile,type,captcha<br>
* 可选参数:无
* @param string $mobile 手机号
* @param string $event 事件名称
* @param string $captcha 验证码
*/
public function check()
{
$mobile = $this->request->request("mobile");
$type = $this->request->request("type");
$type = $type ? $type : 'register';
$event = $this->request->request("event");
$event = $event ? $event : 'register';
$captcha = $this->request->request("captcha");
if ($type)
if ($event)
{
$userinfo = User::getByMobile($mobile);
if ($type == 'register' && $userinfo)
if ($event == 'register' && $userinfo)
{
//已被注册
$this->error(__('已被注册'));
}
else if (in_array($type, ['changepwd', 'resetpwd']) && !$userinfo)
else if (in_array($event, ['changemobile']) && $userinfo)
{
//被占用
$this->error(__('已被占用'));
}
else if (in_array($event, ['changepwd', 'resetpwd']) && !$userinfo)
{
//未注册
$this->error(__('未注册'));
}
}
$ret = Smslib::check($mobile, $captcha, $type);
$ret = Smslib::check($mobile, $captcha, $event);
if ($ret)
{
$this->success(__('成功'));
... ...
<?php
namespace app\api\controller;
use app\common\controller\Api;
use app\common\library\Email;
use app\common\library\Sms;
use fast\Random;
use think\Validate;
/**
* 会员接口
*/
class User extends Api
{
protected $noNeedLogin = ['login', 'mobilelogin', 'register', 'resetpwd', 'changeemail', 'changemobile', 'third'];
protected $noNeedRight = '*';
public function _initialize()
{
parent::_initialize();
}
/**
* 会员中心
*/
public function index()
{
$this->success('', ['welcome' => $this->auth->nickname]);
}
/**
* 会员登录
*
* @param string $account 账号
* @param string $password 密码
*/
public function login()
{
$account = $this->request->request('account');
$password = $this->request->request('password');
if (!$account || !$password)
{
$this->error(__('Invalid parameters'));
}
$ret = $this->auth->login($account, $password);
if ($ret)
{
$data = ['userinfo' => $this->auth->getUserinfo()];
$this->success(__('Logged in successful'), $data);
}
else
{
$this->error($this->auth->getError());
}
}
/**
* 手机验证码登录
*
* @param string $mobile 手机号
* @param string $captcha 验证码
*/
public function mobilelogin()
{
$mobile = $this->request->request('mobile');
$captcha = $this->request->request('captcha');
if (!$mobile || !$captcha)
{
$this->error(__('Invalid parameters'));
}
if (!Validate::regex($mobile, "^1\d{10}$"))
{
$this->error(__('Mobile incorrect'));
}
if (!Sms::check($mobile, $captcha, 'mobilelogin'))
{
$this->error(__('Captcha invalid'));
}
$user = \app\common\model\User::getByMobile($mobile);
if ($user)
{
//如果已经有账号则直接登录
$ret = $this->auth->direct($user->id);
}
else
{
$ret = $this->auth->register($mobile, Random::alnum(), '', $mobile, []);
}
if ($ret)
{
Sms::flush($mobile, 'mobilelogin');
$data = ['userinfo' => $this->auth->getUserinfo()];
$this->success(__('Logged in successful'), $data);
}
else
{
$this->error($this->auth->getError());
}
}
/**
* 注册会员
*
* @param string $username 用户名
* @param string $password 密码
* @param string $email 邮箱
* @param string $mobile 手机号
*/
public function register()
{
$username = $this->request->request('username');
$password = $this->request->request('password');
$email = $this->request->request('email');
$mobile = $this->request->request('mobile');
if (!$username || !$password)
{
$this->error(__('Invalid parameters'));
}
if ($email && !Validate::is($email, "email"))
{
$this->error(__('Email incorrect'));
}
if ($mobile && !Validate::regex($mobile, "^1\d{10}$"))
{
$this->error(__('Mobile incorrect'));
}
$ret = $this->auth->register($username, $password, $email, $mobile, []);
if ($ret)
{
$data = ['userinfo' => $this->auth->getUserinfo()];
$this->success(__('Sign up successful'), $data);
}
else
{
$this->error($this->auth->getError());
}
}
/**
* 注销登录
*/
public function logout()
{
$this->auth->logout();
$this->success(__('Logout successful'));
}
/**
* 修改会员个人信息
*
* @param string $avatar 头像地址
* @param string $username 用户名
* @param string $nickname 昵称
* @param string $bio 个人简介
*/
public function profile()
{
$user = $this->auth->getUser();
$username = $this->request->request('username');
$nickname = $this->request->request('nickname');
$bio = $this->request->request('bio');
$avatar = $this->request->request('avatar');
$exists = \app\common\model\User::where('username', $username)->where('id', '<>', $this->auth->id)->find();
if ($exists)
{
$this->error(__('Username already exists'));
}
$user->username = $username;
$user->nickname = $nickname;
$user->bio = $bio;
$user->avatar = $avatar;
$user->save();
$this->success();
}
/**
* 修改邮箱
*
* @param string $email 邮箱
*/
public function changeemail()
{
$user = $this->auth->getUser();
$email = $this->request->post('email');
if (!$email)
{
$this->error(__('Invalid parameters'));
}
if (!Validate::is($email, "email"))
{
$this->error(__('Mobile incorrect'));
}
if (\app\common\model\User::where('email', $email)->where('id', '<>', $user->id)->find())
{
$this->error(__('Email already exists'));
}
$verification = $user->verification;
$verification->email = 0;
$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();
$this->success();
}
/**
* 修改手机号
*
* @param string $email 手机号
* @param string $captcha 验证码
*/
public function changemobile()
{
$user = $this->auth->getUser();
$mobile = $this->request->request('mobile');
$captcha = $this->request->request('captcha');
if (!$mobile || !$captcha)
{
$this->error(__('Invalid parameters'));
}
if (!Validate::regex($mobile, "^1\d{10}$"))
{
$this->error(__('Mobile incorrect'));
}
if (\app\common\model\User::where('mobile', $mobile)->where('id', '<>', $user->id)->find())
{
$this->error(__('Mobile already exists'));
}
$result = Sms::check($mobile, $captcha, 'changemobile');
if (!$result)
{
$this->error(__('Captcha invalid'));
}
$verification = $user->verification;
$verification->mobile = 1;
$user->verification = $verification;
$user->mobile = $mobile;
$user->save();
Sms::flush($mobile, 'changemobile');
$this->success();
}
/**
* 第三方登录
*
* @param string $platform 平台名称
* @param string $code Code码
*/
public function third()
{
$url = url('user/index');
$platform = $this->request->request("platform");
$code = $this->request->request("code");
$config = get_addon_config('third');
if (!$config || !isset($config[$platform]))
{
$this->error(__('Invalid parameters'));
}
$app = new \addons\third\library\Application($config);
//通过code换access_token和绑定会员
$result = $app->{$platform}->getUserInfo(['code' => $code]);
if ($result)
{
$loginret = \addons\third\library\Service::connect($platform, $result);
if ($loginret)
{
$data = [
'userinfo' => $this->auth->getUserinfo(),
'thirdinfo' => $result
];
$this->success(__('Logged in successful'), $data);
}
}
$this->error(__('Operation failed'), $url);
}
/**
* 重置密码
*
* @param string $mobile 手机号
* @param string $newpassword 新密码
* @param string $captcha 验证码
*/
public function resetpwd()
{
$mobile = $this->request->request("mobile");
$newpassword = $this->request->request("newpassword");
$captcha = $this->request->request("captcha");
if (!$mobile || !$newpassword || !$captcha)
{
$this->error(__('Invalid parameters'));
}
if ($mobile && !Validate::regex($mobile, "^1\d{10}$"))
{
$this->error(__('Mobile 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 invalid'));
}
Sms::flush($mobile, 'resetpwd');
//模拟一次登录
$this->auth->direct($user->id);
$ret = $this->auth->changepwd($newpassword, '', true);
if ($ret)
{
$this->success(__('Reset password successful'));
}
else
{
$this->error($this->auth->getError());
}
}
}
... ...
<?php
namespace app\api\controller;
use app\common\controller\Api;
use app\common\model\User;
/**
* 验证接口
*/
class Validate extends Api
{
protected $noNeedLogin = '*';
protected $layout = '';
protected $error = null;
public function _initialize()
{
parent::_initialize();
}
/**
* 检测邮箱
*
* @param string $email 邮箱
* @param string $id 会员ID
*/
public function check_email_available()
{
$email = $this->request->request('email');
$id = (int) $this->request->request('id');
$count = User::where('email', '=', $email)->where('id', '<>', $id)->count();
if ($count > 0)
{
$this->error(__('邮箱已经被占用'));
}
$this->success();
}
/**
* 检测用户名
*
* @param string $username 用户名
* @param string $id 会员ID
*/
public function check_username_available()
{
$email = $this->request->request('username');
$id = (int) $this->request->request('id');
$count = User::where('username', '=', $email)->where('id', '<>', $id)->count();
if ($count > 0)
{
$this->error(__('用户名已经被占用'));
}
$this->success();
}
/**
* 检测手机
*
* @param string $mobile 手机号
* @param string $id 会员ID
*/
public function check_mobile_available()
{
$email = $this->request->request('mobile');
$id = (int) $this->request->request('id');
$count = User::where('mobile', '=', $email)->where('id', '<>', $id)->count();
if ($count > 0)
{
$this->error(__('已经使用该手机号注册'));
}
$this->success();
}
/**
* 检测手机
*
* @param string $mobile 手机号
*/
public function check_mobile_exist()
{
$email = $this->request->request('mobile');
$count = User::where('mobile', '=', $email)->count();
if (!$count)
{
$this->error(__('手机号不存在'));
}
$this->success();
}
/**
* 检测验证码
*
* @param string $mobile 手机号
* @param string $captcha 验证码
* @param string $event 事件
*/
public function check_sms_correct()
{
$mobile = $this->request->request('mobile');
$captcha = $this->request->request('captcha');
$event = $this->request->request('event');
if (!\app\common\library\Sms::check($mobile, $captcha, $event))
{
$this->error(__('验证码不正确'));
}
$this->success();
}
}
... ...
<?php
return [
'No file upload or server upload limit exceeded' => '未上传文件或超出服务器上传限制',
'Uploaded file format is limited' => '上传文件格式受限制',
'Upload successful' => '上传成功',
];
... ...
<?php
return [
'User center' => '会员中心',
'Register' => '注册',
'Login' => '登录',
'Sign up successful' => '注册成功',
'Username can not be empty' => '用户名不能为空',
'Username must be 6 to 30 characters' => '用户名必须6-30个字符',
'Password can not be empty' => '密码不能为空',
'Password must be 6 to 30 characters' => '密码必须6-30个字符',
'Email is incorrect' => '邮箱格式不正确',
'Mobile is incorrect' => '手机格式不正确',
'Username already exist' => '用户名已经存在',
'Email already exist' => '邮箱已经存在',
'Mobile already exist' => '手机号已经存在',
'Username is incorrect' => '用户名不正确',
'Email is incorrect' => '邮箱不正确',
'Account is locked' => '账户已经被锁定',
'Password is incorrect' => '密码不正确',
'Account is incorrect' => '账户不正确',
'Account not exist' => '账户不存在',
'Account can not be empty' => '账户不能为空',
'Username or password is incorrect' => '用户名或密码不正确',
'You are not logged in' => '你当前还未登录',
'You\'ve logged in, do not login again' => '你已经存在,请不要重复登录',
'Profile' => '个人资料',
'Verify email' => '邮箱验证',
'Change password' => '修改密码',
'Change password successful' => '修改密码成功',
'Captcha is incorrect' => '验证码不正确',
'Sign up successful' => '注册成功',
'Logged in successful' => '登录成功',
'Logout successful' => '注销成功',
'Operation failed' => '操作失败',
'Invalid parameters' => '参数不正确',
'Change password failure' => '修改密码失败',
'Change password successful' => '修改密码成功',
'Reset password successful' => '重置密码成功',
];
... ...
... ... @@ -47,7 +47,7 @@ class Api
* @var array
*/
protected $noNeedRight = [];
/**
* 权限Auth
* @var Auth
... ... @@ -89,9 +89,9 @@ class Api
$modulename = $this->request->module();
$controllername = strtolower($this->request->controller());
$actionname = strtolower($this->request->action());
// token
$token = $this->request->request('token');
$token = $this->request->request('token') ?: $this->request->cookie('token');
$path = str_replace('.', '/', $controllername) . '/' . $actionname;
// 设置当前请求的URI
... ...
... ... @@ -320,6 +320,8 @@ class Auth
$this->_token = Random::uuid();
Token::set($this->_token, $user->id);
$this->_logined = TRUE;
//登录成功的事件
Hook::listen("user_login_successed", $this->_user);
... ...
... ... @@ -127,12 +127,17 @@ class Email
/**
* 获取最后产生的错误
* @return string
*/
public function getError()
{
return $this->_error;
}
/**
* 设置错误
* @param string $error 信息信息
*/
protected function setError($error)
{
$this->_error = $error;
... ...
... ... @@ -2,9 +2,11 @@
namespace app\common\library;
use addons\alisms\library\Alisms;
use app\common\model\MobileCode;
use think\Hook;
/**
* 验证码类
*/
class Sms
{
... ... @@ -23,94 +25,89 @@ class Sms
/**
* 获取最后一次手机发送的数据
*
* @param int $mobile 手机号
* @param string $type 类型
* @return array
* @param int $mobile 手机号
* @param string $event 事件
* @return Sms
*/
public static function get($mobile, $type = 'default')
public static function get($mobile, $event = 'default')
{
return MobileCode::
where(['mobile' => $mobile, 'type' => $type])
->order('id', 'DESC')
->find();
$sms = \app\common\model\Sms::
where(['mobile' => $mobile, 'event' => $event])
->order('id', 'DESC')
->find();
$result = Hook::listen('sms_get', $sms);
return $result ? $result : NULL;
}
/**
* 发送验证码
*
* @param int $mobile 手机号
* @param int $code 验证码
* @param string $type 类型
* @return array
* @param int $mobile 手机号
* @param int $code 验证码,为空时将自动生成4位数字
* @param string $event 事件
* @return boolean
*/
public static function send($mobile, $code = '', $type = 'default')
public static function send($mobile, $code = NULL, $event = 'default')
{
$config = get_addon_config('alisms');
$code = !$code ? mt_rand(1000, 9999) : $code;
$alisms = new Alisms();
$ret = $alisms->mobile($mobile)
->template($config['template'][$type])
->param(['code' => $code])
->send();
if ($ret)
{
$time = time();
MobileCode::create(['type' => $type, 'mobile' => $mobile, 'code' => $code, 'createtime' => $time]);
return TRUE;
}
else
$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]);
$result = Hook::listen('sms_send', $sms);
if (!$result)
{
$sms->delete();
return FALSE;
}
return TRUE;
}
/**
* 发送通知
* @param int $mobile 手机号
* @param string $template 模板ID
*
* @param array $params 参数
* @return boolean
*/
public static function notice($mobile, $template, $params = [])
public static function notice($params = [])
{
$alisms = Alisms::instance();
$ret = $alisms->mobile($mobile)
->template($template)
->param($params)
->send();
return $ret ? TRUE : FALSE;
$result = Hook::listen('sms_notice', $params);
return $result ? TRUE : FALSE;
}
/**
* 校验验证码
*
* @param int $mobile 手机号
* @param int $code 验证码
* @param string $type 类型
* @return boolean
* @param int $mobile 手机号
* @param int $code 验证码
* @param string $event 事件
* @return boolean
*/
public static function check($mobile, $code, $type = 'default')
public static function check($mobile, $code, $event = 'default')
{
$time = time() - self::$expire;
$obj = MobileCode::where(['mobile' => $mobile, 'type' => $type])
$sms = \app\common\model\Sms::where(['mobile' => $mobile, 'event' => $event])
->order('id', 'DESC')
->find();
if ($obj)
if ($sms)
{
if ($obj['createtime'] > $time && $obj['times'] <= self::$maxCheckNums)
if ($sms['createtime'] > $time && $sms['times'] <= self::$maxCheckNums)
{
$correct = $code == $obj['code'];
$correct = $code == $sms['code'];
if (!$correct)
{
$obj->times = $obj->times + 1;
$obj->save();
$sms->times = $sms->times + 1;
$sms->save();
return FALSE;
}
else
{
$result = Hook::listen('sms_check', $sms);
return $result;
}
return $correct;
}
else
{
// 过期则清空该手机验证码
self::flush($mobile, $type);
self::flush($mobile, $event);
return FALSE;
}
}
... ... @@ -123,15 +120,16 @@ class Sms
/**
* 清空指定手机号验证码
*
* @param int $mobile 手机号
* @param string $type 类型
* @return boolean
* @param int $mobile 手机号
* @param string $event 事件
* @return boolean
*/
public static function flush($mobile, $type = 'default')
public static function flush($mobile, $event = 'default')
{
MobileCode::
where(['mobile' => $mobile, 'type' => $type])
\app\common\model\Sms::
where(['mobile' => $mobile, 'event' => $event])
->delete();
Hook::listen('sms_flush');
return TRUE;
}
... ...
... ... @@ -10,20 +10,21 @@ class Token
/**
* 存储Token
* @param string $token Token
* @param int $user_id 会员ID
* @param int $expire 过期时长,0表示无限,单位秒
* @param string $token Token
* @param int $user_id 会员ID
* @param int $expire 过期时长,0表示无限,单位秒
*/
public static function set($token, $user_id, $expire = 0)
{
$expiretime = $expire ? time() + $expire : 0;
\app\common\model\Token::create(['token' => $token, 'user_id' => $user_id, 'expiretime' => $expiretime]);
return TRUE;
}
/**
* 获取Token内的信息
* @param string $token
* @return array
* @param string $token
* @return array
*/
public static function get($token)
{
... ... @@ -44,9 +45,9 @@ class Token
/**
* 判断Token是否可用
* @param string $token Token
* @param int $user_id 会员ID
* @return boolean
* @param string $token Token
* @param int $user_id 会员ID
* @return boolean
*/
public static function check($token, $user_id)
{
... ... @@ -56,8 +57,8 @@ class Token
/**
* 删除Token
* @param string $token
* @return boolean
* @param string $token
* @return boolean
*/
public static function delete($token)
{
... ... @@ -72,8 +73,8 @@ class Token
/**
* 删除指定用户的所有Token
* @param int $user_id
* @return boolean
* @param int $user_id
* @return boolean
*/
public static function clear($user_id)
{
... ...
<?php
namespace app\common\model;
use think\Model;
/**
* 会员积分日志模型
*/
class ScoreLog Extends Model
{
// 表名
protected $name = 'score_log';
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = '';
// 追加属性
protected $append = [
];
}
... ...
<?php
namespace app\common\model;
use think\Model;
/**
* 短信验证码
*/
class Sms Extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
// 追加属性
protected $append = [
];
}
... ...
<?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 = [
];
}
... ...
<?php
namespace app\common\model;
use think\Model;
/**
* 会员模型
*/
class User Extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
// 追加属性
protected $append = [
'url',
];
/**
* 获取个人URL
* @param string $value
* @param array $data
* @return string
*/
public function getUrlAttr($value, $data)
{
return "/u/" . $data['id'];
}
/**
* 获取头像
* @param string $value
* @param array $data
* @return string
*/
public function getAvatarAttr($value, $data)
{
return $value ? $value : '/assets/img/avatar.png';
}
/**
* 获取会员的组别
*/
public function getGroupAttr($value, $data)
{
return UserGroup::get($data['group_id']);
}
/**
* 获取验证字段数组值
* @param string $value
* @param array $data
* @return object
*/
public function getVerificationAttr($value, $data)
{
$value = array_filter((array) json_decode($value, TRUE));
$value = array_merge(['email' => 0, 'mobile' => 0], $value);
return (object) $value;
}
/**
* 设置验证字段
* @param mixed $value
* @return string
*/
public function setVerificationAttr($value)
{
$value = is_object($value) || is_array($value) ? json_encode($value) : $value;
return $value;
}
/**
* 变更会员积分
* @param int $score 积分
* @param int $user_id 会员ID
* @param string $memo 备注
*/
public static function score($score, $user_id, $memo)
{
$user = self::get($user_id);
if ($user)
{
$before = $user->score;
$after = $user->score + $score;
$level = self::nextlevel($after);
//更新会员信息
$user->save(['score' => $after, 'level' => $level]);
//写入日志
ScoreLog::create(['user_id' => $user_id, 'score' => $score, 'before' => $before, 'after' => $after, 'memo' => $memo]);
}
}
/**
* 根据积分获取等级
* @param int $score 积分
* @return int
*/
public static function nextlevel($score = 0)
{
$lv = array(1 => 0, 2 => 30, 3 => 100, 4 => 500, 5 => 1000, 6 => 2000, 7 => 3000, 8 => 5000, 9 => 8000, 10 => 10000);
$level = 1;
foreach ($lv as $key => $value)
{
if ($score >= $value)
{
$level = $key;
}
}
return $level;
}
}
... ...
<?php
namespace app\common\model;
use think\Model;
class UserGroup extends Model
{
// 表名
protected $name = 'user_group';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
// 追加属性
protected $append = [
];
}
... ...
<?php
namespace app\common\model;
use think\Model;
class UserRule extends Model
{
// 表名
protected $name = 'user_rule';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
// 追加属性
protected $append = [
];
}
... ...
... ... @@ -250,8 +250,10 @@ return [
'login_unique' => false,
//登录页默认背景图
'login_background' => "/assets/img/loginbg.jpg",
//自动检测更新
'checkupdate' => false,
//版本号
'version' => '1.0.0.20180117_beta',
'api_url' => 'http://api.fastadmin.net',
'version' => '1.0.0.20180119_beta',
'api_url' => '//api.fastadmin.net',
],
];
... ...
... ... @@ -3,8 +3,6 @@
namespace app\index\controller;
use app\common\controller\Frontend;
use fast\Random;
use think\Config;
use think\Lang;
/**
... ... @@ -31,94 +29,13 @@ class Ajax extends Frontend
$result = 'define(' . json_encode(Lang::get(), JSON_FORCE_OBJECT | JSON_UNESCAPED_UNICODE) . ');';
return $result;
}
/**
* 上传文件
*/
public function upload()
{
Config::set('default_return_type', 'json');
$file = $this->request->file('file');
if (empty($file))
{
$this->error(__('No file upload or server upload limit exceeded'));
}
//判断是否已经存在附件
$sha1 = $file->hash();
$upload = Config::get('upload');
preg_match('/(\d+)(\w+)/', $upload['maxsize'], $matches);
$type = strtolower($matches[2]);
$typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
$size = (int) $upload['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
$fileInfo = $file->getInfo();
$suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
$suffix = $suffix ? $suffix : 'file';
$mimetypeArr = explode(',', $upload['mimetype']);
$typeArr = explode('/', $fileInfo['type']);
//验证文件后缀
if ($upload['mimetype'] !== '*' && !in_array($suffix, $mimetypeArr) && !in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr))
{
$this->error(__('Uploaded file format is limited'));
}
$replaceArr = [
'{year}' => date("Y"),
'{mon}' => date("m"),
'{day}' => date("d"),
'{hour}' => date("H"),
'{min}' => date("i"),
'{sec}' => date("s"),
'{random}' => Random::alnum(16),
'{random32}' => Random::alnum(32),
'{filename}' => $suffix ? substr($fileInfo['name'], 0, strripos($fileInfo['name'], '.')) : $fileInfo['name'],
'{suffix}' => $suffix,
'{.suffix}' => $suffix ? '.' . $suffix : '',
'{filemd5}' => md5_file($fileInfo['tmp_name']),
];
$savekey = $upload['savekey'];
$savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey);
$uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1);
$fileName = substr($savekey, strripos($savekey, '/') + 1);
//
$splInfo = $file->validate(['size' => $size])->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
if ($splInfo)
{
$imagewidth = $imageheight = 0;
if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf']))
{
$imgInfo = getimagesize($splInfo->getPathname());
$imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
$imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
}
$params = array(
'filesize' => $fileInfo['size'],
'imagewidth' => $imagewidth,
'imageheight' => $imageheight,
'imagetype' => $suffix,
'imageframes' => 0,
'mimetype' => $fileInfo['type'],
'url' => $uploadDir . $splInfo->getSaveName(),
'uploadtime' => time(),
'storage' => 'local',
'sha1' => $sha1,
);
$attachment = model("attachment");
$attachment->data(array_filter($params));
$attachment->save();
\think\Hook::listen("upload_after", $attachment);
$this->success(__('Upload successful'), null, [
'url' => $uploadDir . $splInfo->getSaveName()
]);
}
else
{
// 上传失败获取错误信息
$this->error($file->getError());
}
return action('api/common/upload');
}
}
... ...
<?php
namespace app\index\controller;
use app\common\controller\Frontend;
use think\Cookie;
use think\Hook;
use think\Session;
use think\Validate;
/**
* 会员中心
*/
class User extends Frontend
{
protected $layout = 'default';
protected $noNeedLogin = ['login', 'register', 'third'];
protected $noNeedRight = ['*'];
public function _initialize()
{
parent::_initialize();
$auth = $this->auth;
//监听注册登录注销的事件
Hook::add('user_login_successed', function($user) use($auth) {
Cookie::set('uid', $user->id);
Cookie::set('token', $auth->getToken());
});
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) {
Cookie::delete('uid');
Cookie::delete('token');
});
Hook::add('user_logout_successed', function($user) use($auth) {
Cookie::delete('uid');
Cookie::delete('token');
});
}
/**
* 会员中心
*/
public function index()
{
$this->view->assign('title', __('User center'));
return $this->view->fetch();
}
/**
* 注册会员
*/
public function register()
{
$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())
{
$username = $this->request->post('username');
$password = $this->request->post('password');
$email = $this->request->post('email');
$mobile = $this->request->post('mobile', '');
$captcha = $this->request->post('captcha');
$token = $this->request->post('__token__');
$rule = [
'username' => 'require|length:3,30',
'password' => 'require|length:6,30',
'email' => 'require|email',
'mobile' => 'regex:/^1\d{10}$/',
'captcha' => 'require|captcha',
'__token__' => 'token',
];
$msg = [
'username.require' => 'Username can not be empty',
'username.length' => 'Username must be 3 to 30 characters',
'password.require' => 'Password can not be empty',
'password.length' => 'Password must be 6 to 30 characters',
'captcha.require' => 'Captcha can not be empty',
'captcha.captcha' => 'Captcha is incorrect',
'email' => 'Email is incorrect',
'mobile' => 'Mobile is incorrect',
];
$data = [
'username' => $username,
'password' => $password,
'email' => $email,
'mobile' => $mobile,
'captcha' => $captcha,
'__token__' => $token,
];
$validate = new Validate($rule, $msg);
$result = $validate->check($data);
if (!$result)
{
$this->error(__($validate->getError()));
}
if ($this->auth->register($username, $password, $email, $mobile))
{
$synchtml = '';
////////////////同步到Ucenter////////////////
if (defined('UC_STATUS') && UC_STATUS)
{
$uc = new \addons\ucenter\library\client\Client();
$synchtml = $uc->uc_user_synregister($this->auth->id, $password);
}
$referer = Cookie::get('referer_url');
$this->success(__('Sign up successful') . $synchtml, $referer);
}
else
{
$this->error($this->auth->getError());
}
}
Session::set('redirect_url', $url);
$this->view->assign('title', __('Register'));
return $this->view->fetch();
}
/**
* 会员登录
*/
public function login()
{
$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())
{
$account = $this->request->post('account');
$password = $this->request->post('password');
$keeptime = (int) $this->request->post('keeptime');
$token = $this->request->post('__token__');
$rule = [
'account' => 'require|length:3,50',
'password' => 'require|length:6,30',
'__token__' => 'token',
];
$msg = [
'account.require' => 'Account can not be empty',
'account.length' => 'Account must be 3 to 50 characters',
'password.require' => 'Password can not be empty',
'password.length' => 'Password must be 6 to 30 characters',
];
$data = [
'account' => $account,
'password' => $password,
'__token__' => $token,
];
$validate = new Validate($rule, $msg);
$result = $validate->check($data);
if (!$result)
{
$this->error(__($validate->getError()));
return FALSE;
}
if ($this->auth->login($account, $password, $keeptime))
{
$synchtml = '';
////////////////同步到Ucenter////////////////
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
{
$this->error($this->auth->getError());
}
}
$this->view->assign('title', __('Login'));
return $this->view->fetch();
}
/**
* 注销登录
*/
function logout()
{
//注销本站
$this->auth->logout();
$synchtml = '';
////////////////同步到Ucenter////////////////
if (defined('UC_STATUS') && UC_STATUS)
{
$uc = new \addons\ucenter\library\client\Client();
$synchtml = $uc->uc_user_synlogout();
}
$this->success(__('Logout successful') . $synchtml, url('user/index'));
}
/**
* 第三方登录跳转和回调处理
*/
public function third()
{
$url = url('user/index');
$action = $this->request->param('action');
$platform = $this->request->param('platform');
$config = get_addon_config('third');
if (!$config || !isset($config[$platform]))
{
$this->error(__('Invalid parameters'));
}
foreach ($config as $k => &$v)
{
$v['callback'] = url('user/third', ['action' => 'callback', 'platform' => $k], false, true);
}
unset($v);
$app = new \addons\third\library\Application($config);
if ($action == 'redirect')
{
// 跳转到登录授权页面
$this->redirect($app->{$platform}->getAuthorizeUrl());
}
else if ($action == 'callback')
{
// 授权成功后的回调
$result = $app->{$platform}->getUserInfo();
if ($result)
{
$loginret = \addons\third\library\Service::connect($platform, $result);
if ($loginret)
{
$synchtml = '';
////////////////同步到Ucenter////////////////
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);
}
}
$this->error(__('Operation failed'), $url);
}
else
{
$this->error(__('Invalid parameters'));
}
}
/**
* 个人信息
*/
public function profile()
{
$this->view->assign('title', __('Profile'));
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;
}
/**
* 修改密码
*/
public function changepwd()
{
if ($this->request->isPost())
{
$oldpassword = $this->request->post("oldpassword");
$newpassword = $this->request->post("newpassword");
$renewpassword = $this->request->post("renewpassword");
$token = $this->request->post('__token__');
$rule = [
'oldpassword' => 'require|length:6,30',
'newpassword' => 'require|length:6,30',
'renewpassword' => 'require|length:6,30|confirm:newpassword',
'__token__' => 'token',
];
$msg = [
];
$data = [
'oldpassword' => $oldpassword,
'newpassword' => $newpassword,
'renewpassword' => $renewpassword,
'__token__' => $token,
];
$field = [
'oldpassword' => __('Old password'),
'newpassword' => __('New password'),
'renewpassword' => __('Renew password')
];
$validate = new Validate($rule, $msg, $field);
$result = $validate->check($data);
if (!$result)
{
$this->error(__($validate->getError()));
return FALSE;
}
$ret = $this->auth->changepwd($newpassword, $oldpassword);
if ($ret)
{
$synchtml = '';
////////////////同步到Ucenter////////////////
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
{
$this->error($this->auth->getError());
}
}
$this->view->assign('title', __('Change password'));
return $this->view->fetch();
}
}
... ...
<?php
return [
'Keep login' => '保持会话',
'Sign in' => '登入',
'Username' => '用户名',
'User id' => '会员ID',
'Username' => '用户名',
'Nickname' => '昵称',
'Password' => '密码',
'Sign up' => '注 册',
'Sign in' => '登 录',
'Sign out' => '注 销',
'Keep login' => '保持会话',
'Guest' => '游客',
'Welcome' => '%s,你好!',
'Add' => '添加',
'Edit' => '编辑',
'Delete' => '删除',
'Move' => '移动',
'Name' => '名称',
'Status' => '状态',
'Weigh' => '权重',
'Operate' => '操作',
'Warning' => '温馨提示',
'Default' => '默认',
'Article' => '文章',
'Page' => '单页',
'OK' => '确定',
'Cancel' => '取消',
'Loading' => '加载中',
'More' => '更多',
'Normal' => '正常',
'Hidden' => '隐藏',
'Submit' => '提交',
'Reset' => '重置',
'Execute' => '执行',
'Close' => '关闭',
'Search' => '搜索',
'Refresh' => '刷新',
'First' => '首页',
'Previous' => '上一页',
'Next' => '下一页',
'Last' => '末页',
'None' => '无',
'Home' => '主页',
'Online' => '在线',
'Logout' => '注销',
'Profile' => '个人资料',
'Index' => '首页',
'Hot' => '热门',
'Recommend' => '推荐',
'Dashboard' => '控制台',
'Code' => '编号',
'Message' => '内容',
'Line' => '行号',
'File' => '文件',
'Menu' => '菜单',
'Name' => '名称',
'Weigh' => '权重',
'Type' => '类型',
'Title' => '标题',
'Content' => '内容',
'Status' => '状态',
'Operate' => '操作',
'Append' => '追加',
'Memo' => '备注',
'Parent' => '父级',
'Params' => '参数',
'Permission' => '权限',
'Advance search' => '高级搜索',
'Check all' => '选中全部',
'Expand all' => '展开全部',
'Begin time' => '开始时间',
'End time' => '结束时间',
'Create time' => '创建时间',
'Flag' => '标志',
'Redirect now' => '立即跳转',
'Operation completed' => '操作成功!',
'Operation failed' => '操作失败!',
'Unknown data format' => '未知的数据格式!',
'Network error' => '网络错误!',
'Advanced search' => '高级搜索',
'Invalid parameters' => '未知参数',
'No results were found' => '记录未找到',
'Parameter %s can not be empty' => '参数%s不能为空',
'You have no permission' => '你没有权限访问',
'An unexpected error occurred' => '发生了一个意外错误,程序猿正在紧急处理中',
'This page will be re-directed in %s seconds' => '页面将在 %s 秒后自动跳转',
'Keep login' => '保持会话',
'Forgot password' => '忘记密码?',
'Sign in' => '登入',
'Username' => '用户名',
'User id' => '会员ID',
'Username' => '用户名',
'Nickname' => '昵称',
'Password' => '密码',
'Sign up' => '注 册',
'Sign in' => '登 录',
'Sign out' => '注 销',
'Guest' => '游客',
'Welcome' => '%s,你好!',
'Add' => '添加',
'Edit' => '编辑',
'Delete' => '删除',
'Move' => '移动',
'Name' => '名称',
'Status' => '状态',
'Weigh' => '权重',
'Operate' => '操作',
'Warning' => '温馨提示',
'Default' => '默认',
'Article' => '文章',
'Page' => '单页',
'OK' => '确定',
'Cancel' => '取消',
'Loading' => '加载中',
'More' => '更多',
'Normal' => '正常',
'Hidden' => '隐藏',
'Submit' => '提交',
'Reset' => '重置',
'Execute' => '执行',
'Close' => '关闭',
'Search' => '搜索',
'Refresh' => '刷新',
'First' => '首页',
'Previous' => '上一页',
'Next' => '下一页',
'Last' => '末页',
'None' => '无',
'Home' => '主页',
'Online' => '在线',
'Logout' => '注销',
'Profile' => '个人资料',
'Index' => '首页',
'Hot' => '热门',
'Recommend' => '推荐',
'Dashboard' => '控制台',
'Code' => '编号',
'Message' => '内容',
'Line' => '行号',
'File' => '文件',
'Menu' => '菜单',
'Name' => '名称',
'Weigh' => '权重',
'Type' => '类型',
'Title' => '标题',
'Content' => '内容',
'Status' => '状态',
'Operate' => '操作',
'Append' => '追加',
'Memo' => '备注',
'Parent' => '父级',
'Params' => '参数',
'Permission' => '权限',
'Advance search' => '高级搜索',
'Check all' => '选中全部',
'Expand all' => '展开全部',
'Begin time' => '开始时间',
'End time' => '结束时间',
'Create time' => '创建时间',
'Flag' => '标志',
'Gitee' => '码云',
'Github' => 'Github',
'QQ group' => 'QQ群',
'Go to Dashboard' => '登录后台',
'Contribution' => '为FastAdmin贡献代码!',
'Copyrights' => '版权所有',
'Responsive' => '响应式开发',
'Languages' => '多语言',
'Module' => '模块化开发',
'Extension' => '自由可扩展',
'Auth' => '权限管理',
'The fastest framework based on ThinkPHP5 and Bootstrap' => '基于ThinkPHP5和Bootstrap的极速后台开发框架',
'Features' => '功能特性',
'Home' => '首页',
'Store' => '插件市场',
'Services' => '服务',
'Download' => '下载',
'Demo' => '演示',
'Donation' => '捐赠',
'Forum' => '社区',
'Docs' => '文档',
'Send verification code' => '发磅验证码',
'Redirect now' => '立即跳转',
'Operation completed' => '操作成功!',
'Operation failed' => '操作失败!',
'Unknown data format' => '未知的数据格式!',
'Network error' => '网络错误!',
'Advanced search' => '高级搜索',
'Invalid parameters' => '未知参数',
'No results were found' => '记录未找到',
'Parameter %s can not be empty' => '参数%s不能为空',
'You have no permission' => '你没有权限访问',
'An unexpected error occurred' => '发生了一个意外错误,程序猿正在紧急处理中',
'This page will be re-directed in %s seconds' => '页面将在 %s 秒后自动跳转',
];
... ...
<?php
return [
'User center' => '会员中心',
'Register' => '注册',
'Login' => '登录',
'Account' => '账号',
'Mobile' => '手机号',
'Email' => '邮箱',
'Captcha' => '验证码',
'Lv' => 'Lv',
'Score' => '积分',
'Day' => '天',
'Intro' => '个人介绍',
'Successions' => '连续登录',
'Maxsuccessions' => '最长连续登录',
'Logintime' => '登录时间',
'Prevtime' => '最后登录',
'Change' => '修改',
'Click to edit' => '点击编辑',
'Email/Mobile/Username' => '邮箱/手机/用户名',
'Sign up successful' => '注册成功',
'Email active successful' => '邮箱激活成功',
'Username can not be empty' => '用户名不能为空',
'Username must be 6 to 30 characters' => '用户名必须6-30个字符',
'Password can not be empty' => '密码不能为空',
'Password must be 6 to 30 characters' => '密码必须6-30个字符',
'Email is incorrect' => '邮箱格式不正确',
'Mobile is incorrect' => '手机格式不正确',
'Username already exist' => '用户名已经存在',
'Email already exist' => '邮箱已经存在',
'Mobile already exist' => '手机号已经存在',
'Username is incorrect' => '用户名不正确',
'Email is incorrect' => '邮箱不正确',
'Account is locked' => '账户已经被锁定',
'Password is incorrect' => '密码不正确',
'Account is incorrect' => '账户不正确',
'Account not exist' => '账户不存在',
'Account can not be empty' => '账户不能为空',
'Username or password is incorrect' => '用户名或密码不正确',
'You are not logged in' => '你当前还未登录',
'You\'ve logged in, do not login again' => '你已经存在,请不要重复登录',
'Profile' => '个人资料',
'Old password' => '旧密码',
'New password' => '新密码',
'Renew password' => '确认新密码',
'Change password' => '修改密码',
'New email' => '新邮箱',
'New mobile' => '新手机号',
'Change password successful' => '修改密码成功',
'Captcha is incorrect' => '验证码不正确',
'Sign up successful' => '注册成功',
'Logged in successful' => '登录成功',
'Logout successful' => '注销成功',
'Operation failed' => '操作失败',
'Invalid parameters' => '参数不正确',
'Change password failure' => '修改密码失败',
'Change password successful' => '修改密码成功',
];
... ...
<meta charset="utf-8">
<title>{$title|default=''} – {:__('The fastest framework based on ThinkPHP5 and Bootstrap')}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta name="renderer" content="webkit">
{if isset($keywords)}
<meta name="keywords" content="{$keywords}">
{/if}
{if isset($description)}
<meta name="description" content="{$description}">
{/if}
<meta name="author" content="FastAdmin">
<link rel="shortcut icon" href="__CDN__/assets/img/favicon.ico" />
<!-- Loading Bootstrap -->
<link href="__CDN__/assets/css/frontend{$Think.config.app_debug?'':'.min'}.css?v={$Think.config.site.version}" rel="stylesheet">
<!-- HTML5 shim, for IE6-8 support of HTML5 elements. All other JS at the end of file. -->
<!--[if lt IE 9]>
<script src="__CDN__/assets/js/html5shiv.js"></script>
<script src="__CDN__/assets/js/respond.min.js"></script>
<![endif]-->
<script type="text/javascript">
var require = {
config: {$config|json_encode}
};
</script>
\ No newline at end of file
... ...
<script src="__CDN__/assets/js/require.js" data-main="__CDN__/assets/js/require-frontend{$Think.config.app_debug?'':'.min'}.js?v={$site.version}"></script>
\ No newline at end of file
... ...
<div class="sidenav">
<ul class="list-group">
<li class="list-group-heading">{:__('User center')}</li>
<li class="list-group-item {:$config['actionname']=='index'?'active':''}"> <a href="{:url('user/index')}"><i class="fa fa-user-circle"></i> {:__('User center')}</a> </li>
<li class="list-group-item {:$config['actionname']=='profile'?'active':''}"> <a href="{:url('user/profile')}"><i class="fa fa-user-o"></i> {:__('Profile')}</a> </li>
<li class="list-group-item {:$config['actionname']=='changepwd'?'active':''}"> <a href="{:url('user/changepwd')}"><i class="fa fa-key"></i> {:__('Change password')}</a> </li>
<li class="list-group-item {:$config['actionname']=='logout'?'active':''}"> <a href="{:url('user/logout')}"><i class="fa fa-sign-out"></i> {:__('Sign out')}</a> </li>
</ul>
</div>
\ No newline at end of file
... ...
... ... @@ -9,7 +9,7 @@
<meta name="description" content="">
<meta name="author" content="">
<title>FastAdmin - 基于ThinkPHP5和Bootstrap的极速后台开发框架</title>
<title>FastAdmin - {:__('The fastest framework based on ThinkPHP5 and Bootstrap')}</title>
<!-- Bootstrap Core CSS -->
<link href="//cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
... ... @@ -39,14 +39,14 @@
<div class="collapse navbar-collapse" id="navbar-collapse-menu">
<ul class="nav navbar-nav navbar-right">
<li><a href="http://www.fastadmin.net">首页</a></li>
<li><a href="http://www.fastadmin.net/store.html" title="FastAdmin插件市场">插件市场</a></li>
<li><a href="http://www.fastadmin.net/service.html" title="FastAdmin增值服务">服务</a></li>
<li><a href="http://www.fastadmin.net/download.html" title="FastAdmin下载">下载</a></li>
<li><a href="http://www.fastadmin.net/demo.html" title="FastAdmin演示">演示</a></li>
<li><a href="http://www.fastadmin.net/donate.html" title="捐赠">捐赠</a></li>
<li><a href="http://forum.fastadmin.net" title="FastAdmin交流社区">社区</a></li>
<li><a href="http://doc.fastadmin.net" title="FastAdmin官方文档">文档</a></li>
<li><a href="http://www.fastadmin.net" target="_blank">{:__('Home')}</a></li>
<li><a href="http://www.fastadmin.net/store.html" target="_blank">{:__('Store')}</a></li>
<li><a href="http://www.fastadmin.net/service.html" target="_blank">{:__('Services')}</a></li>
<li><a href="http://www.fastadmin.net/download.html" target="_blank">{:__('Download')}</a></li>
<li><a href="http://www.fastadmin.net/demo.html" target="_blank">{:__('Demo')}</a></li>
<li><a href="http://www.fastadmin.net/donate.html" target="_blank">{:__('Donation')}</a></li>
<li><a href="http://forum.fastadmin.net" target="_blank">{:__('Forum')}</a></li>
<li><a href="http://doc.fastadmin.net" target="_blank">{:__('Docs')}</a></li>
</ul>
</div>
<!-- /.navbar-collapse -->
... ... @@ -61,8 +61,8 @@
<div class="header-content">
<div class="header-content-inner">
<h1>FastAdmin</h1>
<h3>基于ThinkPHP5和Bootstrap的极速后台开发框架</h3>
<a href="{:url('admin/index/login')}" class="btn btn-outline btn-xl page-scroll">登录后台</a>
<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>
</div>
</div>
</div>
... ... @@ -75,7 +75,7 @@
<div class="row">
<div class="col-lg-12 text-center">
<div class="section-heading">
<h2>功能特性</h2>
<h2>{:__('Features')}</h2>
</div>
</div>
</div>
... ... @@ -86,42 +86,42 @@
<div class="col-md-4">
<div class="feature-item">
<i class="icon-user text-primary"></i>
<h3>权限管理</h3>
<h3>{:__('Auth')}</h3>
<p class="text-muted">基于完善的Auth权限控制管理、无限父子级权限分组、可自由分配子级权限、一个管理员可同时属于多个组别</p>
</div>
</div>
<div class="col-md-4">
<div class="feature-item">
<i class="icon-screen-smartphone text-primary"></i>
<h3>响应式开发</h3>
<h3>{:__('Responsive')}</h3>
<p class="text-muted">基于Bootstrap和AdminLTE进行二次开发,手机、平板、PC均自动适配,无需要担心兼容性问题</p>
</div>
</div>
<div class="col-md-4">
<div class="feature-item">
<i class="icon-present text-primary"></i>
<h3>多语言</h3>
<h3>{:__('Languages')}</h3>
<p class="text-muted">不仅仅后台开发支持多语言,同时视图部分和JS部分仍然共享同一个语言包,语法相同且自动加载</p>
</div>
</div>
<div class="col-md-4">
<div class="feature-item">
<i class="icon-layers text-primary"></i>
<h3>模块化开发</h3>
<h3>{:__('Module')}</h3>
<p class="text-muted">控制器、模型、视图、JS一一对应,使用RequireJS进行JS模块化管理,采用Bower进行前端包组件管理</p>
</div>
</div>
<div class="col-md-4">
<div class="feature-item">
<i class="icon-docs text-primary"></i>
<h3>CRUD</h3>
<h3>{:__('CRUD')}</h3>
<p class="text-muted">控制台进行一键生成控制器、模型、视图和JS文件,同时可一键生成后台权限节点和菜单栏</p>
</div>
</div>
<div class="col-md-4">
<div class="feature-item">
<i class="icon-puzzle text-primary"></i>
<h3>自由可扩展</h3>
<h3>{:__('Extension')}</h3>
<p class="text-muted">FastAdmin提供强大的扩展中心,可直接在线安装和卸载插件,同时支持命令行一键操作</p>
</div>
</div>
... ... @@ -136,7 +136,7 @@
<div class="cta-content">
<div class="container">
<h2>不要犹豫<br>开始行动</h2>
<a href="http://doc.fastadmin.net/docs/contributing.html" class="btn btn-outline btn-xl page-scroll">为FastAdmin贡献代码!</a>
<a href="http://doc.fastadmin.net/docs/contributing.html" class="btn btn-outline btn-xl page-scroll">{:__('Contribution')}</a>
</div>
</div>
<div class="overlay"></div>
... ... @@ -147,13 +147,13 @@
<p>&copy; 2017 FastAdmin. All Rights Reserved.</p>
<ul class="list-inline">
<li>
<a href="https://gitee.com/karson/fastadmin">码云</a>
<a href="https://gitee.com/karson/fastadmin">{:__('Gitee')}</a>
</li>
<li>
<a href="https://github.com/karsonzhang/fastadmin">Github</a>
<a href="https://github.com/karsonzhang/fastadmin">{:__('Github')}</a>
</li>
<li>
<a href="http://shang.qq.com/wpa/qunwpa?idkey=46c326e570d0f97cfae1f8257ae82322192ec8841c79b2136446df0b3b62028c">QQ群</a>
<a href="http://shang.qq.com/wpa/qunwpa?idkey=46c326e570d0f97cfae1f8257ae82322192ec8841c79b2136446df0b3b62028c">{:__('QQ group')}</a>
</li>
</ul>
</div>
... ...
... ... @@ -9,7 +9,7 @@
<meta name="description" content="">
<meta name="author" content="">
<title>FastAdmin - 基于ThinkPHP5和Bootstrap的极速后台开发框架</title>
<title>FastAdmin - {:__('The fastest framework based on ThinkPHP5 and Bootstrap')}</title>
<!-- Bootstrap Core CSS -->
<link href="//cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
... ... @@ -50,14 +50,14 @@
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav pull-right">
<li><a href="http://www.fastadmin.net">首页</a></li>
<li><a href="http://www.fastadmin.net/store.html" title="FastAdmin插件市场">插件市场</a></li>
<li><a href="http://www.fastadmin.net/service.html" title="FastAdmin增值服务">服务</a></li>
<li><a href="http://www.fastadmin.net/download.html" title="FastAdmin下载">下载</a></li>
<li><a href="http://www.fastadmin.net/demo.html" title="FastAdmin演示">演示</a></li>
<li><a href="http://www.fastadmin.net/donate.html" title="捐赠">捐赠</a></li>
<li><a href="http://forum.fastadmin.net" title="FastAdmin交流社区">社区</a></li>
<li><a href="http://doc.fastadmin.net" title="FastAdmin官方文档">文档</a></li>
<li><a href="http://www.fastadmin.net" target="_blank">{:__('Home')}</a></li>
<li><a href="http://www.fastadmin.net/store.html" target="_blank">{:__('Store')}</a></li>
<li><a href="http://www.fastadmin.net/service.html" target="_blank">{:__('Services')}</a></li>
<li><a href="http://www.fastadmin.net/download.html" target="_blank">{:__('Download')}</a></li>
<li><a href="http://www.fastadmin.net/demo.html" target="_blank">{:__('Demo')}</a></li>
<li><a href="http://www.fastadmin.net/donate.html" target="_blank">{:__('Donation')}</a></li>
<li><a href="http://forum.fastadmin.net" target="_blank">{:__('Forum')}</a></li>
<li><a href="http://doc.fastadmin.net" target="_blank">{:__('Docs')}</a></li>
</ul>
</div>
<!-- /.navbar-collapse -->
... ... @@ -73,13 +73,13 @@
<p>&copy; 2017 FastAdmin. All Rights Reserved.</p>
<ul class="list-inline">
<li>
<a href="https://gitee.com/karson/fastadmin">码云</a>
<a href="https://gitee.com/karson/fastadmin">{:__('Gitee')}</a>
</li>
<li>
<a href="https://github.com/karsonzhang/fastadmin">Github</a>
<a href="https://github.com/karsonzhang/fastadmin">{:__('Github')}</a>
</li>
<li>
<a href="http://shang.qq.com/wpa/qunwpa?idkey=46c326e570d0f97cfae1f8257ae82322192ec8841c79b2136446df0b3b62028c">QQ群</a>
<a href="http://shang.qq.com/wpa/qunwpa?idkey=46c326e570d0f97cfae1f8257ae82322192ec8841c79b2136446df0b3b62028c">{:__('QQ group')}</a>
</li>
</ul>
</div>
... ...
<!DOCTYPE html>
<html>
<head>
{include file="common/meta" /}
<link href="__CDN__/assets/css/user.css?v={$Think.config.site.version}" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#header-navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{:url('/')}" style="padding:6px 15px;"><img src="/assets/img/logo.png" style="height:40px;" alt=""></a>
</div>
<div class="collapse navbar-collapse" id="header-navbar">
<ul class="nav navbar-nav navbar-right">
<li><a href="http://www.fastadmin.net" target="_blank">{:__('Home')}</a></li>
<li><a href="http://www.fastadmin.net/store.html" target="_blank">{:__('Store')}</a></li>
<li><a href="http://www.fastadmin.net/service.html" target="_blank">{:__('Services')}</a></li>
<li><a href="http://www.fastadmin.net/download.html" target="_blank">{:__('Download')}</a></li>
<li><a href="http://www.fastadmin.net/demo.html" target="_blank">{:__('Demo')}</a></li>
<li><a href="http://www.fastadmin.net/donate.html" target="_blank">{:__('Donation')}</a></li>
<li><a href="http://forum.fastadmin.net" target="_blank">{:__('Forum')}</a></li>
<li><a href="http://doc.fastadmin.net" target="_blank">{:__('Docs')}</a></li>
<li class="dropdown">
{if $user}
<a href="{:url('user/index')}" class="dropdown-toggle" data-toggle="dropdown" style="padding-top: 10px;height: 50px;">
<span class="avatar-img"><img src="{$user.avatar}" alt=""></span>
</a>
{else /}
<a href="{:url('user/index')}" class="dropdown-toggle" data-toggle="dropdown">{:__('User center')} <b class="caret"></b></a>
{/if}
<ul class="dropdown-menu">
{if $user}
<li><a href="{:url('user/index')}"><i class="fa fa-user-circle"></i>{:__('User center')}</a></li>
<li><a href="{:url('user/profile')}"><i class="fa fa-user-o"></i>{:__('Profile')}</a></li>
<li><a href="{:url('user/changepwd')}"><i class="fa fa-key"></i>{:__('Change password')}</a></li>
<li><a href="{:url('user/logout')}"><i class="fa fa-sign-out"></i>{:__('Sign out')}</a></li>
{else /}
<li><a href="{:url('user/login')}"><i class="fa fa-sign-in"></i> {:__('Sign in')}</a></li>
<li><a href="{:url('user/register')}"><i class="fa fa-user-o"></i> {:__('Sign up')}</a></li>
{/if}
</ul>
</li>
</ul>
</div>
</div>
</nav>
{__CONTENT__}
<footer class="footer" style="clear:both">
<p class="address">Copyright&nbsp;©&nbsp;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" /}
</body>
</html>
\ No newline at end of file
... ...
<div id="content-container" class="container">
<div class="row">
<div class="col-md-3">
{include file="common/sidenav" /}
</div>
<div class="col-md-9">
<div class="panel panel-default">
<div class="panel-body">
<h2 class="page-header">{:__('Change password')}</h2>
<form id="changepwd-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
{:token()}
<div class="form-group">
<label for="c-name" class="control-label col-xs-12 col-sm-2">旧密码:</label>
<div class="col-xs-12 col-sm-4">
<input type="password" class="form-control" id="oldpassword" name="oldpassword" value="" data-rule="required" placeholder="{:__('Old password')}">
</div>
</div>
<div class="form-group">
<label for="c-name" class="control-label col-xs-12 col-sm-2">{:__('New password')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="password" class="form-control" id="newpassword" name="newpassword" value="" data-rule="required" placeholder="{:__('New password')}" />
</div>
</div>
<div class="form-group">
<label for="c-name" class="control-label col-xs-12 col-sm-2">{:__('Renew password')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="password" class="form-control" id="renewpassword" name="renewpassword" value="" data-rule="required" placeholder="{:__('Renew password')}" />
</div>
</div>
<div class="form-group normal-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('Submit')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
... ...
<div id="content-container" class="container">
<div class="row">
<div class="col-md-3">
{include file="common/sidenav" /}
</div>
<div class="col-md-9">
<div class="panel panel-default ">
<div class="panel-body">
<h2 class="page-header">{:__('User center')}</h2>
<div class="row user-baseinfo">
<div class="col-md-3 col-sm-3 col-xs-2 text-center user-center">
<a href="{:url('user/profile')}" title="{:__('Click to edit')}">
<span class="avatar-img"><img src="{$user.avatar}" alt=""></span>
</a>
</div>
<div class="col-md-7 col-sm-7 col-xs-10">
<!-- Content -->
<div class="ui-content">
<!-- Heading -->
<h4><a href="{:url('user/profile')}">{$user.username}</a></h4>
<!-- Paragraph -->
<p><a href="{:url('user/profile')}">{$user.bio|default='这个人很懒,啥也没写'}</a></p>
<!-- Success -->
<div style="margin-top:15px;">
<table class="table">
<tbody><tr>
<th>{:__('Lv')}</th>
<td><a href="javascript:;" class="viewlv">{$user.level}</a></td>
<th>{:__('Score')}</th>
<td><a href="javascript:;" class="viewscore">{$user.score}</a></td>
</tr>
<tr>
<th>{:__('Successions')}</th>
<td>{$user.successions} {:__('Day')}</td>
<th>{:__('Maxsuccessions')}</th>
<td>{$user.maxsuccessions} {:__('Day')}</td>
</tr>
<tr>
<th>{:__('Logintime')}</th>
<td>{$user.logintime|date="Y-m-d H:i:s",###}</td>
<th>{:__('Prevtime')}</th>
<td>{$user.prevtime|date="Y-m-d H:i:s",###}</td>
</tr>
</tbody></table>
</div>
</div>
</div>
<div class="col-md-2 col-sm-2 col-xs-0 col-pad">
<a href="{:url('user/profile')}" class="btn btn-success hidden-xs"><i class="fa fa-pencil"></i> {:__('Profile')}</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
... ...
<div id="content-container" class="container">
<div class="user-section login-section">
<div class="logon-tab clearfix"> <a class="active">{:__('Sign in')}</a> <a href="{:url('user/register')}">{:__('Sign up')}</a> </div>
<div class="login-main">
<form name="form" id="login-form" class="form-vertical" method="POST" action="">
<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">
<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">
</div>
</div>
<div class="form-group">
<div class="controls">
<input type="checkbox" name="keeptime" checked="checked" value="86400"> {:__('Keep login')}
<div class="pull-right"><a href="javascript:;" class="btn-forgot">{:__('Forgot password')}</a></div>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-lg btn-block">{:__('Sign in')}</button>
</div>
</form>
</div>
</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>
</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">
<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">
<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>
</div>
</div>
</script>
\ No newline at end of file
... ...
<style>
.profile-avatar-container {
position:relative;
width:100px;
}
.profile-avatar-container .profile-user-img{
width:100px;
height:100px;
}
.profile-avatar-container .profile-avatar-text {
display:none;
}
.profile-avatar-container:hover .profile-avatar-text {
display:block;
position:absolute;
height:100px;
width:100px;
background:#444;
opacity: .6;
color: #fff;
top:0;
left:0;
line-height: 100px;
text-align: center;
}
.profile-avatar-container button{
position:absolute;
top:0;left:0;width:100px;height:100px;opacity: 0;
}
</style>
<div id="content-container" class="container">
<div class="row">
<div class="col-md-3">
{include file="common/sidenav" /}
</div>
<div class="col-md-9">
<div class="panel panel-default">
<div class="panel-body">
<h2 class="page-header">{:__('Profile')}</h2>
<form id="profile-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="{:url('api/user/profile')}">
{:token()}
<input type="hidden" name="avatar" id="c-avatar" value="{$user.avatar}" />
<div class="form-group">
<label for="c-name" class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-4">
<div class="profile-avatar-container">
<img class="profile-user-img img-responsive img-circle plupload" src="{$user.avatar}" alt="">
<div class="profile-avatar-text img-circle">{:__('Click to edit')}</div>
<button id="plupload-avatar" class="plupload" data-mimetype="png,jpg,jpeg,gif" data-input-id="c-avatar"><i class="fa fa-upload"></i> {:__('Upload')}</button>
</div>
</div>
</div>
<div class="form-group">
<label for="c-username" class="control-label col-xs-12 col-sm-2">{:__('Username')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control" id="username" name="username" value="{$user.username}" data-rule="required;username;remote({:url('api/validate/check_username_available')}, id={$user.id})" placeholder="">
</div>
</div>
<div class="form-group">
<label for="c-nickname" class="control-label col-xs-12 col-sm-2">{:__('Nickname')}:</label>
<div class="col-xs-12 col-sm-4">
<input type="text" class="form-control" id="nickname" name="nickname" value="{$user.nickname}" data-rule="required" placeholder="">
</div>
</div>
<div class="form-group">
<label for="c-bio" class="control-label col-xs-12 col-sm-2">{:__('Intro')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-bio" data-rule="" data-tip="一句话介绍一下你自己" class="form-control" name="row[bio]" type="text" value="{$user.bio}">
</div>
</div>
<div class="form-group">
<label for="c-email" class="control-label col-xs-12 col-sm-2">{:__('Email')}:</label>
<div class="col-xs-12 col-sm-4">
<div class="input-group">
<input type="text" class="form-control" id="c-email" name="email" value="{$user.email}" disabled placeholder="">
<span class="input-group-btn" style="padding:0;border:none;">
<a href="javascript:;" class="btn btn-info btn-change" data-type="email">{:__('Change')}</a>
</span>
</div>
</div>
</div>
<div class="form-group">
<label for="c-mobile" class="control-label col-xs-12 col-sm-2">{:__('Mobile')}:</label>
<div class="col-xs-12 col-sm-4">
<div class="input-group">
<input type="text" class="form-control" id="c-mobile" name="mobile" value="{$user.mobile}" disabled placeholder="">
<span class="input-group-btn" style="padding:0;border:none;">
<a href="javascript:;" class="btn btn-info btn-change" data-type="mobile">{:__('Change')}</a>
</span>
</div>
</div>
</div>
<div class="form-group normal-footer">
<label class="control-label col-xs-12 col-sm-2"></label>
<div class="col-xs-12 col-sm-8">
<button type="submit" class="btn btn-success btn-embossed disabled">{:__('Ok')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</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>
</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>
</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>
</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>
<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>
</script>
\ No newline at end of file
... ...
<div id="content-container" class="container">
<div class="user-section login-section">
<div class="logon-tab clearfix"> <a href="{:url('user/login')}">{:__('Sign in')}</a> <a class="active">{:__('Sign up')}</a> </div>
<div class="login-main">
<form name="form1" id="login-form" class="form-vertical" method="POST" action="">
<input type="hidden" name="invite_user_id" value="0" />
<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')}">
<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')}">
<p class="help-block"></p>
</div>
</div>
<div class="form-group">
<label class="control-label">{:__('Password')}</label>
<div class="controls">
<input type="password" id="repassword" name="repassword" required 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')}">
<p class="help-block"></p>
</div>
</div>
<div class="form-group">
<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;" />
<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>
</div>
<p class="help-block"></p>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-lg btn-block">{:__('Sign up')}</button>
</div>
</form>
</div>
</div>
</div>
\ No newline at end of file
... ...
h2.page-header {
margin:10px 0 25px 0;
padding-bottom:15px;
}
.user-baseinfo {
margin-bottom:25px;
}
.user-baseinfo table tr td {color:#999;}
@media (min-width: 767px) {
.user-center .avatar-text,.user-center .avatar-img {
height:150px;width:150px;border-radius: 150px;line-height:150px;font-size:70px;
}
.user-center .avatar-img {font-size:0;}
.user-center .avatar-img img {
height:150px;width:150px;border-radius:150px;
}
}
\ No newline at end of file
... ...
... ... @@ -59,6 +59,42 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
// 为表格绑定事件
Table.api.bindevent(table);
table.on('click', '.btn-addoninfo', function (event) {
var index = parseInt($(this).data("index"));
var data = table.bootstrapTable("getData");
var item = data[index];
var addon = typeof Config.addons[item.name] != 'undefined' ? Config.addons[item.name] : null;
console.log(item, addon);
Layer.alert(Template("addoninfotpl", {item: item, addon: addon}), {
btn: [__('OK'), __('Donate'), __('Feedback'), __('Document')],
title: __('Detail'),
area: ['450px', '490px'],
btn2: function () {
//打赏
Layer.open({
content: Template("paytpl", {payimg: item.donateimage}),
shade: 0.8,
area: ['800px', '600px'],
skin: 'layui-layer-msg layui-layer-pay',
title: false,
closeBtn: true,
btn: false,
resize: false,
});
},
btn3: function () {
return false;
},
btn4: function () {
return false;
},
success: function (layero, index) {
$(".layui-layer-btn2", layero).attr("href", "http://forum.fastadmin.net/t/bug?ref=addon&name=" + item.name).attr("target", "_blank");
$(".layui-layer-btn3", layero).attr("href", "http://www.fastadmin.net/store/" + item.name + ".html?ref=addon").attr("target", "_blank");
}
});
});
// 如果是https则启用提示
if (location.protocol === "https:") {
$("#warmtips").removeClass("hide");
... ... @@ -73,6 +109,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template'], function
});
});
//查看插件首页
$(document).on("click", ".btn-addonindex", function () {
if ($(this).attr("href") == 'javascript:;') {
Layer.msg(__('Not installed tips'), {icon: 7});
} else if ($(this).parent().find("a.btn-enable").size() > 0) {
Layer.msg(__('Not enabled tips'), {icon: 7});
return false;
}
});
//切换URL
$(document).on("click", ".btn-switch", function () {
$(".btn-switch").removeClass("active");
... ...
... ... @@ -118,7 +118,7 @@ define(['jquery', 'bootstrap', 'backend', 'addtabs', 'adminlte', 'form'], functi
//读取版本检测信息
var ignoreversion = localStorage.getItem("ignoreversion");
if (ignoreversion !== "*") {
if (Config.fastadmin.checkupdate && ignoreversion !== "*") {
checkupdate(ignoreversion, false);
}
//手动检测版本信息
... ...
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'jstree'], function ($, undefined, Backend, Table, Form, undefined) {
//读取选中的条目
$.jstree.core.prototype.get_all_checked = function (full) {
var obj = this.get_selected(), i, j;
for (i = 0, j = obj.length; i < j; i++) {
obj = obj.concat(this.get_node(obj[i]).parents);
}
obj = $.grep(obj, function (v, i, a) {
return v != '#';
});
obj = obj.filter(function (itm, i, a) {
return i == a.indexOf(itm);
});
return full ? $.map(obj, $.proxy(function (i) {
return this.get_node(i);
}, this)) : obj;
};
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'user/group/index',
add_url: 'user/group/add',
edit_url: 'user/group/edit',
del_url: 'user/group/del',
multi_url: 'user/group/multi',
table: 'user_group',
}
});
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: 'id',
sortName: 'id',
columns: [
[
{checkbox: true},
{field: 'id', title: __('Id')},
{field: 'name', title: __('Name')},
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime},
{field: 'updatetime', title: __('Updatetime'), formatter: Table.api.formatter.datetime},
{field: 'status', title: __('Status'), formatter: Table.api.formatter.status},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
]
});
// 为表格绑定事件
Table.api.bindevent(table);
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
api: {
bindevent: function () {
Form.api.bindevent($("form[role=form]"), null, null, function () {
if ($("#treeview").size() > 0) {
var r = $("#treeview").jstree("get_all_checked");
$("input[name='row[rules]']").val(r.join(','));
}
return true;
});
//渲染权限节点树
//销毁已有的节点树
$("#treeview").jstree("destroy");
Controller.api.rendertree(nodeData);
//全选和展开
$(document).on("click", "#checkall", function () {
$("#treeview").jstree($(this).prop("checked") ? "check_all" : "uncheck_all");
});
$(document).on("click", "#expandall", function () {
$("#treeview").jstree($(this).prop("checked") ? "open_all" : "close_all");
});
$("select[name='row[pid]']").trigger("change");
},
rendertree: function (content) {
$("#treeview")
.on('redraw.jstree', function (e) {
$(".layer-footer").attr("domrefresh", Math.random());
})
.jstree({
"themes": {"stripes": true},
"checkbox": {
"keep_selected_style": false,
},
"types": {
"root": {
"icon": "fa fa-folder-open",
},
"menu": {
"icon": "fa fa-folder-open",
},
"file": {
"icon": "fa fa-file-o",
}
},
"plugins": ["checkbox", "types"],
"core": {
'check_callback': true,
"data": content
}
});
}
}
};
return Controller;
});
\ No newline at end of file
... ...
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'user/rule/index',
add_url: 'user/rule/add',
edit_url: 'user/rule/edit',
del_url: 'user/rule/del',
multi_url: 'user/rule/multi',
table: 'user_rule',
}
});
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: 'id',
sortName: 'weigh',
escape: false,
columns: [
[
{checkbox: true},
{field: 'id', title: __('Id')},
{field: 'pid', title: __('Pid'), visible: false},
{field: 'title', title: __('Title'), align: 'left'},
{field: 'name', title: __('Name')},
{field: 'remark', title: __('Remark')},
{field: 'ismenu', title: __('Ismenu'), formatter: Controller.api.formatter.toggle},
{field: 'createtime', title: __('Createtime'), formatter: Table.api.formatter.datetime, visible: false},
{field: 'updatetime', title: __('Updatetime'), formatter: Table.api.formatter.datetime, visible: false},
{field: 'weigh', title: __('Weigh')},
{field: 'status', title: __('Status'), formatter: Table.api.formatter.status},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
]
});
// 为表格绑定事件
Table.api.bindevent(table);
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
api: {
bindevent: function () {
$(document).on('click', "input[name='row[ismenu]']", function () {
var name = $("input[name='row[name]']");
name.prop("placeholder", $(this).val() == 1 ? name.data("placeholder-menu") : name.data("placeholder-node"));
});
$("input[name='row[ismenu]']:checked").trigger("click");
Form.api.bindevent($("form[role=form]"));
},
formatter: {
toggle: function (value, row, index) {
//添加上btn-change可以自定义请求的URL进行数据处理
return '<i class="fa ' + (value == 0 ? 'fa-toggle-off' : 'fa-toggle-on') + ' fa-2x"></i>';
},
}
}
};
return Controller;
});
\ No newline at end of file
... ...
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'user/user/index',
add_url: 'user/user/add',
edit_url: 'user/user/edit',
del_url: 'user/user/del',
multi_url: 'user/user/multi',
table: 'user',
}
});
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: 'id',
sortName: 'user.id',
columns: [
[
{checkbox: true},
{field: 'id', title: __('Id'), sortable: true},
{field: 'group.name', title: __('Group')},
{field: 'username', title: __('Username'), operate: 'LIKE'},
{field: 'nickname', title: __('Nickname'), operate: 'LIKE'},
{field: 'email', title: __('Email'), operate: 'LIKE'},
{field: 'mobile', title: __('Mobile'), operate: 'LIKE'},
{field: 'avatar', title: __('Avatar'), formatter: Table.api.formatter.image, operate: false},
{field: 'level', title: __('Level'), operate: 'BETWEEN', sortable: true},
{field: 'gender', title: __('Gender'), visible: false, searchList: {1: __('Male'), 0: __('Female')}},
{field: 'score', title: __('Score'), operate: 'BETWEEN', sortable: true},
{field: 'successions', title: __('Successions'), visible: false, operate: 'BETWEEN', sortable: true},
{field: 'maxsuccessions', title: __('Maxsuccessions'), visible: false, operate: 'BETWEEN', sortable: true},
{field: 'logintime', title: __('Logintime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'loginip', title: __('Loginip'), formatter: Table.api.formatter.search},
{field: 'jointime', title: __('Jointime'), formatter: Table.api.formatter.datetime, operate: 'RANGE', addclass: 'datetimerange', sortable: true},
{field: 'joinip', title: __('Joinip'), formatter: Table.api.formatter.search},
{field: 'status', title: __('Status'), formatter: Table.api.formatter.status, searchList: {normal: __('Normal'), hidden: __('Hidden')}},
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
]
]
});
// 为表格绑定事件
Table.api.bindevent(table);
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
api: {
bindevent: function () {
Form.api.bindevent($("form[role=form]"));
}
}
};
return Controller;
});
\ No newline at end of file
... ...
... ... @@ -2,26 +2,6 @@ define(['fast'], function (Fast) {
var Frontend = {
api: Fast.api,
init: function () {
//发送邮箱验证码
$(document).on("click", ".btn-email", function (e) {
var email = $(this).closest("form").find("#email");
if (email.val() == "") {
Layer.alert("邮箱不能为空!");
return false;
}
var that = this;
email.isValid(function (v) {
if (v) {
Frontend.api.ajax({url: "sms/sendemail", data: {type: $(that).data("type"), email: email.val()}}, function () {
$(that).val("已发送");
});
} else {
Layer.alert("请确认已经输入了正解的邮箱!");
}
});
return false;
});
//发送手机验证码
$(document).on("click", ".btn-captcha", function (e) {
var mobile = $(this).closest("form").find("#mobile");
... ... @@ -37,8 +17,7 @@ define(['fast'], function (Fast) {
if (v) {
$(that).addClass("disabled", true).text("获取中...");
var si;
Frontend.api.ajax({url: "sms/send", data: {type: $(that).data("type"), mobile: mobile.val()}}, function () {
Layer.msg("验证码已发送");
Frontend.api.ajax({url: $(that).data("url"), data: {event: $(that).data("event"), mobile: mobile.val()}}, function () {
clearInterval(si);
var seconds = 60;
si = setInterval(function () {
... ...
define(['jquery', 'bootstrap', 'frontend', 'form', 'template'], function ($, undefined, Frontend, Form, Template) {
var Controller = {
login: function () {
//本地验证未通过时提示
$("#login-form").data("validator-options", {
invalid: function (form, errors) {
$.each(errors, function (i, j) {
Layer.alert(j);
});
},
});
//为表单绑定事件
Form.api.bindevent($("#login-form"), function (data, ret) {
setTimeout(function () {
location.href = ret.url ? ret.url : "/";
}, 1000);
});
Form.api.bindevent($("#resetpwd-form"), function (data) {
Layer.closeAll();
});
$(document).on("click", ".btn-forgot", function () {
var id = "resetpwdtpl";
var content = Template(id, {});
Layer.open({
type: 1,
title: "修改",
area: ["450px", "auto"],
content: content,
success: function (layero) {
Form.api.bindevent($("#resetpwd-form", layero), function (data) {
Layer.closeAll();
});
}
});
});
},
register: function () {
//本地验证未通过时提示
$("#register-form").data("validator-options", {
invalid: function (form, errors) {
$.each(errors, function (i, j) {
Layer.alert(j);
});
},
});
//为表单绑定事件
Form.api.bindevent($("#register-form"), function (data, ret) {
setTimeout(function () {
location.href = ret.url ? ret.url : "/";
}, 1000);
});
},
changepwd: function () {
//本地验证未通过时提示
$("#resetpwd-form").data("validator-options", {
invalid: function (form, errors) {
$.each(errors, function (i, j) {
Layer.alert(j);
});
},
});
//为表单绑定事件
Form.api.bindevent($("#changepwd-form"), function (data, ret) {
setTimeout(function () {
location.href = ret.url ? ret.url : "/";
}, 1000);
});
},
profile: function () {
// 给上传按钮添加上传成功事件
$("#plupload-avatar").data("upload-success", function (data) {
var url = Fast.api.cdnurl(data.url);
$(".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());
});
$(document).on("click", ".btn-change", function () {
var id = $(this).data("type") + "tpl";
var content = Template(id, {});
Layer.open({
type: 1,
title: "修改",
area: ["450px", "auto"],
content: content,
});
});
}
};
return Controller;
});
\ No newline at end of file
... ...
... ... @@ -9702,7 +9702,10 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
//Bootstrap操作区
var toolbar = $(options.toolbar, parenttable);
//当刷新表格时
table.on('load-error.bs.table', function (status, res) {
table.on('load-error.bs.table', function (status, res, e) {
if (e.status === 0) {
return;
}
Toastr.error(__('Unknown data format'));
});
//当刷新表格时
... ... @@ -10017,9 +10020,16 @@ define('table',['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstr
var options = table ? table.bootstrapTable('getOptions') : {};
// 默认按钮组
var buttons = $.extend([], this.buttons || []);
buttons.push({name: 'dragsort', icon: 'fa fa-arrows', classname: 'btn btn-xs btn-primary btn-dragsort'});
buttons.push({name: 'edit', icon: 'fa fa-pencil', classname: 'btn btn-xs btn-success btn-editone', url: options.extend.edit_url});
buttons.push({name: 'del', icon: 'fa fa-trash', classname: 'btn btn-xs btn-danger btn-delone'});
if (options.extend.dragsort_url !== '') {
buttons.push({name: 'dragsort', icon: 'fa fa-arrows', classname: 'btn btn-xs btn-primary btn-dragsort'});
}
if (options.extend.edit_url !== '') {
buttons.push({name: 'edit', icon: 'fa fa-pencil', classname: 'btn btn-xs btn-success btn-editone', url: options.extend.edit_url});
}
if (options.extend.del_url !== '') {
buttons.push({name: 'del', icon: 'fa fa-trash', classname: 'btn btn-xs btn-danger btn-delone'});
}
return Table.api.buttonlink(this, buttons, value, row, index, 'operate');
},
buttons: function (value, row, index) {
... ... @@ -12744,6 +12754,13 @@ define('form',['jquery', 'bootstrap', 'upload', 'validator'], function ($, undef
display: function (elem) {
return $(elem).closest('.form-group').find(".control-label").text().replace(/\:/, '');
},
dataFilter: function (data) {
if (data.code === 1) {
return "";
} else {
return data.msg;
}
},
target: function (input) {
var $formitem = $(input).closest('.form-group'),
$msgbox = $formitem.find('span.msg-box');
... ...
... ... @@ -17,6 +17,13 @@ define(['jquery', 'bootstrap', 'upload', 'validator'], function ($, undefined, U
display: function (elem) {
return $(elem).closest('.form-group').find(".control-label").text().replace(/\:/, '');
},
dataFilter: function (data) {
if (data.code === 1) {
return "";
} else {
return data.msg;
}
},
target: function (input) {
var $formitem = $(input).closest('.form-group'),
$msgbox = $formitem.find('span.msg-box');
... ...
... ... @@ -2282,26 +2282,6 @@ define('frontend',['fast'], function (Fast) {
var Frontend = {
api: Fast.api,
init: function () {
//发送邮箱验证码
$(document).on("click", ".btn-email", function (e) {
var email = $(this).closest("form").find("#email");
if (email.val() == "") {
Layer.alert("邮箱不能为空!");
return false;
}
var that = this;
email.isValid(function (v) {
if (v) {
Frontend.api.ajax({url: "sms/sendemail", data: {type: $(that).data("type"), email: email.val()}}, function () {
$(that).val("已发送");
});
} else {
Layer.alert("请确认已经输入了正解的邮箱!");
}
});
return false;
});
//发送手机验证码
$(document).on("click", ".btn-captcha", function (e) {
var mobile = $(this).closest("form").find("#mobile");
... ... @@ -2317,8 +2297,7 @@ define('frontend',['fast'], function (Fast) {
if (v) {
$(that).addClass("disabled", true).text("获取中...");
var si;
Frontend.api.ajax({url: "sms/send", data: {type: $(that).data("type"), mobile: mobile.val()}}, function () {
Layer.msg("验证码已发送");
Frontend.api.ajax({url: $(that).data("url"), data: {event: $(that).data("event"), mobile: mobile.val()}}, function () {
clearInterval(si);
var seconds = 60;
si = setInterval(function () {
... ...
... ... @@ -101,7 +101,10 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
//Bootstrap操作区
var toolbar = $(options.toolbar, parenttable);
//当刷新表格时
table.on('load-error.bs.table', function (status, res) {
table.on('load-error.bs.table', function (status, res, e) {
if (e.status === 0) {
return;
}
Toastr.error(__('Unknown data format'));
});
//当刷新表格时
... ... @@ -416,9 +419,16 @@ define(['jquery', 'bootstrap', 'moment', 'moment/locale/zh-cn', 'bootstrap-table
var options = table ? table.bootstrapTable('getOptions') : {};
// 默认按钮组
var buttons = $.extend([], this.buttons || []);
buttons.push({name: 'dragsort', icon: 'fa fa-arrows', classname: 'btn btn-xs btn-primary btn-dragsort'});
buttons.push({name: 'edit', icon: 'fa fa-pencil', classname: 'btn btn-xs btn-success btn-editone', url: options.extend.edit_url});
buttons.push({name: 'del', icon: 'fa fa-trash', classname: 'btn btn-xs btn-danger btn-delone'});
if (options.extend.dragsort_url !== '') {
buttons.push({name: 'dragsort', icon: 'fa fa-arrows', classname: 'btn btn-xs btn-primary btn-dragsort'});
}
if (options.extend.edit_url !== '') {
buttons.push({name: 'edit', icon: 'fa fa-pencil', classname: 'btn btn-xs btn-success btn-editone', url: options.extend.edit_url});
}
if (options.extend.del_url !== '') {
buttons.push({name: 'del', icon: 'fa fa-trash', classname: 'btn btn-xs btn-danger btn-delone'});
}
return Table.api.buttonlink(this, buttons, value, row, index, 'operate');
},
buttons: function (value, row, index) {
... ...