pref: 增加服务类优化UI版面

This commit is contained in:
Ying
2023-06-19 14:32:30 +08:00
parent 27eda6f37f
commit 2b8f874450
148 changed files with 3933 additions and 9286 deletions

View File

@@ -67,6 +67,12 @@ class AdminController extends BaseController
*/
protected bool $dataLimit = false;
/**
* 是否开启部门限制
* @var bool
*/
protected bool $departmentLimit = false;
/**
* 数据限制字段
* @var string
@@ -108,7 +114,7 @@ class AdminController extends BaseController
/**
* 获取资源列表
* @return Response|void
* @return Response
*/
public function index()
{
@@ -117,7 +123,6 @@ class AdminController extends BaseController
$limit = (int)input('limit', 18);
$where = $this->buildSelectParams();
$count = $this->model->where($where)->count();
$limit = is_empty($limit) ? 10 : $limit;
$page = $count <= $limit ? 1 : $page;
$fieldList = $this->model->getFields();
$order = !array_key_exists('sort', $fieldList) ? 'id' : 'sort';
@@ -219,6 +224,7 @@ class AdminController extends BaseController
/**
* 删除资源
* @return Response
*/
public function del()
{
@@ -362,14 +368,14 @@ class AdminController extends BaseController
/**
* 获取查询参数
* @return array
*/
protected function buildSelectParams()
protected function buildSelectParams(): array
{
$where = [];
$params = request()->all();
if (!empty($params) && is_array($params)) {
$where = [];
$this->tableFields = $this->model->getFields();
foreach ($params as $field => $value) {
@@ -413,23 +419,18 @@ class AdminController extends BaseController
case 'year':
$value = str_replace(',', '-', $value);
if (strpos($value, '-')) {
$arr = explode(' - ', $value);
if (empty($arr)) {
continue 2;
}
if (in_array($field, $this->converTime)) {
if (isset($arr[0])) {
$arr[0] = strtotime($arr[0]);
}
if (isset($arr[1])) {
$arr[1] = strtotime($arr[1]);
}
}
$exp = 'between';
if ($arr[0] === '') {
$exp = '<=';
@@ -438,7 +439,6 @@ class AdminController extends BaseController
$exp = '>=';
$arr = $arr[0];
}
$where[] = [$field, $exp, $arr];
} else {
$where[] = [$field, '=', $value];
@@ -484,19 +484,22 @@ class AdminController extends BaseController
}
}
// 限制数据字段
if (!$this->auth->SuperAdmin() && $this->dataLimit) {
// 限制个人数据权限
$superAdmin = $this->auth->SuperAdmin();
if (!$superAdmin && $this->dataLimit) {
if (in_array($this->dataLimitField, $this->tableFields)) {
$where[] = [$this->dataLimitField, '=', get_admin_id()];
}
} // 限制部门数据权限
else if (!$superAdmin && $this->departmentLimit
&& in_array('department_id', $this->tableFields)) {
$where[] = ['department_id', 'in', get_admin_info('AdminLogin.department_id')];
}
}
return $where;
}
return false;
}
/**
* 递归查询父节点
* @access public

View File

@@ -11,7 +11,8 @@ declare (strict_types=1);
// +----------------------------------------------------------------------
namespace app;
use app\common\library\Auth;
use app\common\service\user\UserService;
use support\Response;
/**
* Api全局控制器基类
@@ -27,6 +28,52 @@ class ApiController extends BaseController
public function __construct()
{
parent::__construct();
$this->auth = Auth::instance();
}
/**
* 操作成功跳转
* @access protected
* @param mixed $msg
* @param mixed $url
* @param mixed $data
* @param int $count
* @param int $code
* @param int $wait
* @param array $header
* @return Response
*/
protected function success(mixed $msg = '', mixed $url = '', mixed $data = '', int $count = 0, int $code = 200, int $wait = 3, array $header = []): Response
{
$msg = !empty($msg) ? __($msg) : __('操作成功!');
$result = ['code' => $code, 'msg' => $msg, 'data' => $data, 'count' => $count, 'url' => (string)$url, 'wait' => $wait];
return json($result);
}
/**
* 操作错误跳转的快捷方法
* @access protected
* @param mixed $msg 提示信息
* @param mixed $url 跳转的URL地址
* @param mixed $data 返回的数据
* @param int $code
* @param integer $wait 跳转等待时间
* @param array $header 发送的Header信息
* @return Response
*/
protected function error(mixed $msg = '', mixed $url = '', mixed $data = '', int $code = 101, int $wait = 3, array $header = []): Response
{
$msg = !empty($msg) ? __($msg) : __('操作失败!');
$result = ['code' => $code, 'msg' => $msg, 'data' => $data, 'url' => (string)$url, 'wait' => $wait];
return json($result);
}
/**
* 退出登录
* @access public
*/
public function logOut(): Response
{
UserService::logout();
return $this->success('退出成功', '/');
}
}

View File

@@ -10,6 +10,7 @@ declare (strict_types=1);
// | Author: meystack <coolsec@foxmail.com> Apache 2.0 License
// +----------------------------------------------------------------------
namespace app;
use support\Log;
use support\Response;
use think\db\exception\BindParamException;
@@ -44,12 +45,6 @@ class BaseController
*/
public string $scene = '';
/**
* 是否批量验证
* @var bool
*/
protected bool $batchValidate = false;
/**
* 获取访问来源
* @var string
@@ -58,59 +53,7 @@ class BaseController
public function __construct()
{
$this->referer = \request()->header('referer');
}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param $validate
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return bool
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false): bool
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
[$validate, $scene] = explode('.', $validate);
}
$class = str_contains($validate, '\\') ? $validate : $this->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch();
}
return $v->failException()->check($data);
}
/**
* 解析应用类的类名
* @access public
* @param string $layer 层名 controller model ...
* @param string $name 类名
* @return string
*/
protected function parseClass(string $layer, string $name): string
{
$name = str_replace(['/', '.'], '\\', $name);
$array = explode('\\', $name);
$class = Str::studly(array_pop($array));
$path = $array ? implode('\\', $array) . '\\' : '';
return 'app' . '\\' . $layer . '\\' . $path . $class;
$this->referer = \request()->header('referer', '/');
}
/**
@@ -204,8 +147,8 @@ class BaseController
*/
protected function getResponseType(): string
{
$mask=request()->input('_ajax')==1 ||request()->input('_pjax')==1;
return request()->isAjax() || request()->acceptJson() || $mask ? 'json' : 'html';
$_ajax = request()->input('_ajax', input('_pjax'));
return request()->isAjax() || request()->acceptJson() || $_ajax ? 'json' : 'html';
}
/**

View File

@@ -12,7 +12,7 @@ declare(strict_types=1);
// +----------------------------------------------------------------------
namespace app;
use app\common\library\Auth;
use app\common\service\user\UserService;
use Psr\SimpleCache\InvalidArgumentException;
use support\Response;
use think\db\exception\DataNotFoundException;
@@ -45,12 +45,6 @@ class HomeController extends BaseController
*/
public string $errorText = '';
/**
* 接口权限
* @var object
*/
public object $auth;
/**
* 控制器登录鉴权
* @var bool
@@ -67,13 +61,13 @@ class HomeController extends BaseController
* 非鉴权方法
* @var array
*/
public array $noNeedAuth = [];
public array $noNeedLogin = [];
/**
* 跳转URL地址
* @var string
*/
public string $JumpUrl = '/user/index';
public string $JumpUrl = '/';
/**
* 初始化函数
@@ -82,7 +76,6 @@ class HomeController extends BaseController
{
// 获取权限实例
parent::__construct();
$this->auth = Auth::instance();
}
/**
@@ -92,9 +85,6 @@ class HomeController extends BaseController
* @param string $app
* @return Response
* @throws InvalidArgumentException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
protected function view(string $template = '', array $argc = [], string $app = 'index'): \support\Response
{
@@ -113,4 +103,14 @@ class HomeController extends BaseController
return view($template, $argc, $app);
}
/**
* 退出登录
* @access public
*/
public function logOut(): Response
{
UserService::logout();
return $this->success('退出成功', '/');
}
}

View File

@@ -12,21 +12,19 @@ declare(strict_types=1);
// +----------------------------------------------------------------------
namespace app\admin\controller;
use app\common\service\notice\EmailService;
use app\common\service\utils\FtpService;
use Psr\SimpleCache\InvalidArgumentException;
use support\Response;
use think\db\exception\BindParamException;
use think\facade\Cache;
use support\Cache;
use think\facade\Db;
use Webman\Event\Event;
use system\Random;
use think\cache\driver\Memcached;
use think\cache\driver\Redis;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use app\AdminController;
use app\common\library\Email;
use app\common\library\Ftp;
use app\common\model\system\AdminNotice;
use app\common\model\system\Attachment;
use app\common\model\system\Config;
@@ -389,7 +387,6 @@ class Index extends AdminController
(new Config())->saveAll($config);
$env = base_path() . '/.env';
$parse = parse_ini_file($env, true);
$parse['CACHE_DRIVER'] = $post['cache_type'];
$parse['CACHE_HOSTNAME'] = $post['cache_host'];
$parse['CACHE_HOSTPORT'] = $post['cache_port'];
$parse['CACHE_SELECT'] = $post['cache_select'];
@@ -401,7 +398,6 @@ class Index extends AdminController
}
// 清理系统核心缓存
Cache::tag('core_system')->clear();
$configList = Cache::get('config_list');
foreach ($configList as $item) {
Cache::delete($item);
@@ -417,7 +413,7 @@ class Index extends AdminController
public function testFtp(): Response
{
if (request()->isPost()) {
if (Ftp::instance()->ftpTest(request()->post())) {
if (FtpService::ftpTest(request()->post())) {
return $this->success('上传测试成功!');
}
}
@@ -427,51 +423,49 @@ class Index extends AdminController
/**
* 邮件测试
* @return Response
*/
public function testEmail()
public function testEmail(): Response
{
if (request()->isPost()) {
$info = Email::instance()->testEMail(request()->post());
return $info === true ? $this->success('测试邮件发送成功!') : $this->error($info);
try {
EmailService::testEmail(request()->post());
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
return $this->success('测试邮件发送成功!');
}
/**
* 缓存测试
* @return Response
*/
public function testCache()
public function testCache(): Response
{
if (request()->isPost()) {
$param = request()->post();
if (!isset($param['type']) || empty($param['host']) || empty($param['port'])) {
if (empty($param['host']) || empty($param['port'])) {
return $this->error('参数错误!');
}
$options = [
'host' => $param['host'],
'port' => (int)$param['port'],
'username' => $param['user'],
'password' => $param['pass']
];
if (!extension_loaded('redis')) {
return $this->error('请先安装redis扩展!');
}
try {
if (strtolower($param['type']) == 'redis') {
$drive = new Redis($options);
} else {
$drive = new Memcached($options);
}
$redis = new \Redis();
$redis->connect($param['host'], (int)$param['port']);
$redis->auth($param['pass']);
$redis->select((int)$param['select']);
$redis->set('key-test', time());
$redis->close();
} catch (\Throwable $th) {
return $this->error($th->getMessage());
}
if ($drive->set('test', 'cacheOK', 1000)) {
}
return $this->success('缓存测试成功!');
} else {
return $this->error('缓存测试失败!');
}
}
return false;
}
}

View File

@@ -26,7 +26,7 @@ use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use think\facade\Cache;
use support\Cache;
use Webman\Http\Request;
/**
@@ -155,14 +155,13 @@ class Admin extends AdminController
return $this->error('该用户名或邮箱已被注册!');
}
// 管理员加密
$post['pwd'] = encryptPwd($post['pwd']);
$post['create_ip'] = request()->getRealIp();
$data = $this->model->create($post);
if (!is_empty($data->id)) {
$access['admin_id'] = $data->id;
$access['group_id'] = $data->group_id;
if (!is_empty($data['id'])) {
$access['admin_id'] = $data['id'];
$access['group_id'] = $data['group_id'];
AdminAccessModel::insert($access);
return $this->success('添加管理员成功!');
} else {
@@ -182,66 +181,59 @@ class Admin extends AdminController
if (request()->isPost()) {
$id = request()->input('id');
if (!empty($id) && is_numeric($id)) {
// 验证数据
$post = request()->all();
$post = request_validate_rules($post, get_class($this->model), 'edit');
if (!is_array($post)) {
return $this->error($post);
$retError = request_validate_rules($post, get_class($this->model), 'edit');
if (!is_array($retError)) {
return $this->error($retError);
}
if (!empty($post['pwd'])) {
if (isset($post['pwd']) && !empty($post['pwd'])) {
$post['pwd'] = encryptPwd($post['pwd']);
} else {
// 清空避免被覆盖
unset($post['pwd']);
}
if ($this->model->update($post)) {
$access['group_id'] = $post['group_id'];
AdminAccessModel::where('admin_id', $id)->update($access);
return $this->success('更新管理员成功!');
} else {
}
}
}
return $this->error('更新管理员失败');
}
}
}
}
/**
* 编辑权限
* @return Response
*/
public function editRules()
public function editRules(): Response
{
if (request()->isPost()) {
return $this->_update_RuleCates();
}
return $this->updateRuleCates();
}
/**
* 编辑栏目权限
* @return Response
*/
public function editCates()
public function editCates(): Response
{
return $this->_update_RuleCates(AUTH_CATE);
return $this->updateRuleCates(AUTH_CATE);
}
/**
* 更新权限函数
* @access protected
* @param string $type
* @return \support\Response|void
* @return Response
*/
protected function _update_RuleCates(string $type = AUTH_RULES)
protected function updateRuleCates(string $type = AUTH_RULES): Response
{
if (request()->isPost()) {
$admin_id = input('admin_id');
$rules = request()->post($type) ?? [];
if (!empty($admin_id) && $admin_id > 0) {
$access = $this->auth->getRulesNode($admin_id, $type);
$rules = array_diff($rules, $access[$this->auth->authGroup]);
@@ -260,25 +252,21 @@ class Admin extends AdminController
$rules = array_unique(array_merge($rules, $current));
$AdminAccessModel = new AdminAccessModel();
$data = [
"$type" => implode(',', $rules)
];
$data = ["$type" => implode(',', $rules)];
if ($AdminAccessModel->where('admin_id', $admin_id)->save($data)) {
if ($AdminAccessModel->update($data, ['admin_id' => $admin_id])) {
return $this->success('更新权限成功!');
}
return $this->error('更新权限失败!');
}
}
}
/**
* 获取用户权限树
* getAdminRules
* @return mixed
*/
public function getPermissions()
public function getPermissions(): mixed
{
$list = [];
if (\request()->isAjax()) {
@@ -666,7 +654,7 @@ class Admin extends AdminController
// 清理内容
if ($type == 'all' || $type == 'content') {
$session = session(AdminSession);
\think\facade\Cache::clear();
\support\Cache::clear();
request()->session()->set(AdminSession, $session);
}

View File

@@ -50,34 +50,14 @@ class AdminRules extends AdminController
}
// 获取总数
$total = $this->model->count();
$total = $this->model->where($where)->count();
$list = $this->model->where($where)->order('sort asc')->select()->toArray();
foreach ($list as $key => $value) {
$list[$key]['title'] = __($value['title']);
}
// 自定义查询
if (count($list) < $total) {
$parentNode = []; // 查找父节点
foreach ($list as $key => $value) {
if ($value['pid'] !== 0 && !list_search($list,['id'=>$value['pid']])) {
$parentNode[] = $this->parentNode($value['pid']);
}
}
foreach ($parentNode as $key => $value) {
$list = array_merge($list,$value);
}
}
$rules = $this->model->getListTree();
return $this->success('获取成功', '',[
'item'=> $list,
'rules'=> $rules
],
count($list),0);
$rules = list_to_tree($list,'id','pid','children',0);
return $this->success('获取成功', '/',$rules, $total);
}

View File

@@ -73,11 +73,7 @@ class Department extends AdminController
}
$depart = $this->model->getListTree();
return $this->success('获取成功', '',[
'item'=> $list,
'depart'=> $depart
],
count($list));
return $this->success('获取成功', '',$depart, $total);
}
return view('system/department/index');

View File

@@ -81,7 +81,7 @@ class Plugin extends AdminController
return $this->error('请勿重复安装插件');
}
// try {
try {
$pluginZip = self::downLoad($name, ['name' => $name, 'token' => input('token')]);
ZipArchives::unzip($pluginZip, plugin_path(), '', true);
@@ -95,10 +95,10 @@ class Plugin extends AdminController
self::pluginMenu($name);
self::executeSql($name);
self::enabled($name);
// } catch (\Throwable $th) {
// recursive_delete($pluginPath);
// return $this->error($th->getMessage(), null, self::$ServerBody, $th->getCode());
// }
} catch (\Throwable $th) {
recursive_delete($pluginPath);
return $this->error($th->getMessage(), null, self::$ServerBody, $th->getCode());
}
return $this->success('插件安装成功', null, get_plugin_config($name, true));
}
@@ -295,17 +295,15 @@ class Plugin extends AdminController
if (request()->isPost()) {
$post['extends'] = input('extends');
$post['rewrite'] = input('rewrite');
foreach ($post['rewrite'] as $kk=>$vv)
{
foreach ($post['rewrite'] as $kk => $vv) {
if ($kk[0] != '/') return $this->error('伪静态变量名称“' . $kk . '" 必须以“/”开头');
$post['rewrite'][$kk] = str_replace('\\', '/', trim($vv, '/\\'));
$value = explode('/', $post['rewrite'][$kk]);
if (count($value) < 2) {
return $this->error('伪静态规则变量值,不符合规则');
return $this->error('伪静态不符合规则');
}
if(strtoupper($value[count($value)-2][0]) !== $value[count($value)-2][0])
{
return $this->error('伪静态规则变量值中,控制器首字母必须大写哦');
if (strtoupper($value[count($value) - 2][0]) !== $value[count($value) - 2][0]) {
return $this->error('控制器首字母必须大写');
}
}
$config = array_merge($config, $post);

View File

@@ -21,7 +21,6 @@ use system\Random;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use Webman\Http\Request;
/**
* 用户管理

View File

@@ -1,8 +1,6 @@
<?php
namespace app\admin\middleware\system;
use app\common\library\Auth;
use think\facade\Cache;
use Webman\Http\Request;
use Webman\Http\Response;
use Webman\MiddlewareInterface;

View File

@@ -27,7 +27,7 @@ class AdminPermissions implements MiddlewareInterface
* 不需要鉴权的方法
* @var array
*/
protected array $noNeedAuth = [
protected array $noNeedLogin = [
'/Index/index',
'/Login/index',
'/Login/logout',
@@ -56,12 +56,12 @@ class AdminPermissions implements MiddlewareInterface
// 获取权限列表
$class = new \ReflectionClass($request->controller);
$properties = $class->getDefaultProperties();
$this->noNeedAuth = $properties['noNeedAuth'] ?? $this->noNeedAuth;
$this->noNeedLogin = $properties['noNeedLogin'] ?? $this->noNeedLogin;
// 控制器鉴权
$method = '/' . $controller . '/' . $action;
if (!in_array('*', $this->noNeedAuth)
&& !in_array(strtolower($method), array_map('strtolower', $this->noNeedAuth))) {
if (!in_array('*', $this->noNeedLogin)
&& !in_array(strtolower($method), array_map('strtolower', $this->noNeedLogin))) {
if (!Auth::instance()->SuperAdmin() && !Auth::instance()->check($method, get_admin_id())) {
if (request()->isAjax()) {
return json(['code' => 101, 'msg' => '没有权限']);

View File

@@ -2,7 +2,7 @@
<!-- 正文开始 -->
<div class="layui-fluid" id="LAY-component-grid-all">
<div class="layui-row layui-col-space10">
<div class="layui-col-xs6 layui-col-sm7 layui-col-md3">
<div class=" layui-col-sm7 layui-col-md3">
<!-- 填充内容 -->
<div class="layui-card">
<div class="layui-card-header">总销售额<i class="layui-icon layui-icon-about layui-fr" lay-tips="指标说明" ></i></div>
@@ -19,7 +19,7 @@
</div>
</div>
</div>
<div class="layui-col-xs6 layui-col-sm5 layui-col-md3">
<div class=" layui-col-sm5 layui-col-md3">
<div class="layui-card">
<div class="layui-card-header">访问量 <span class="layui-badge layui-badge-green pull-right"></span></div>
<div class="layui-card-body">
@@ -32,7 +32,7 @@
</div>
</div>
</div>
<div class="layui-col-xs6 layui-col-sm5 layui-col-md3">
<div class=" layui-col-sm5 layui-col-md3">
<div class="layui-card">
<div class="layui-card-header">支付笔数 <span class="layui-badge layui-badge-blue pull-right"></span></div>
<div class="layui-card-body">
@@ -45,7 +45,7 @@
</div>
</div>
</div>
<div class="layui-col-xs6 layui-col-sm7 layui-col-md3">
<div class=" layui-col-sm7 layui-col-md3">
<div class="layui-card">
<div class="layui-card-header">活动运营效果 <span class="layui-badge layui-badge-red pull-right"></span></div>
<div class="layui-card-body">
@@ -62,7 +62,7 @@
</div>
</div>
</div>
<div class="layui-col-xs6 layui-col-sm7 layui-col-md9">
<div class=" layui-col-sm7 layui-col-md9">
<div class="layui-card">
<div class="layui-card-header">用户地域分布</div>
<div class="layui-card-body">
@@ -70,7 +70,7 @@
</div>
</div>
</div>
<div class="layui-col-xs6 layui-col-sm5 layui-col-md3">
<div class=" layui-col-sm5 layui-col-md3">
<div class="layui-card" >
<div class="layui-card-header">在线人数</div>
<div class="layui-card-body">
@@ -78,7 +78,7 @@
</div>
</div>
</div>
<div class="layui-col-xs6 layui-col-sm5 layui-col-md3">
<div class=" layui-col-sm5 layui-col-md3">
<div class="layui-card" >
<div class="layui-card-header">浏览器分布</div>
<div class="layui-card-body">

View File

@@ -162,8 +162,7 @@
<div class="layui-form-mid layui-word-aux">* {:__('是否开启手机版模式')}</div>
</div>
<div class="mobile" <eq name="$config['site_state']" value="0"> style="display:none;"
</eq> >
<div class="mobile" <eq name="$config['site_state']" value="0"> style="display:none;" </eq> >
<div class="layui-form-item">
<label class="layui-form-label">{:__('手机版类型')}</label>
@@ -337,40 +336,6 @@
<div class="layui-form-mid layui-word-aux">* {:__('开启数据库缓存会提高网站性能!')}</div>
</div>
<div class="cache_status" <eq name="$config['cache_status']" value="0">
style="display:none;" </eq> >
<div class="layui-form-item">
<label class="layui-form-label">{:__('缓存方式')}</label>
<div class="layui-input-inline">
<select name="cache_type" data-display="cache_type" data-disable="file"
lay-filter="selectStatus" class="ctype">
<option value="file" <if condition="$config['cache_type'] eq 'file'">
selected</if> >file</option>
<option value="redis" <if condition="$config['cache_type'] eq 'redis'">
selected</if> >redis</option>
<option value="memcached" <if
condition="$config['cache_type'] eq 'memcached'">selected</if>
>memcached</option>
</select>
</div>
<div class="layui-form-mid layui-word-aux">
<i class="layui-icon layui-icon-about"
lay-tips="{:__('使用Redis缓存方式,出错会抛出Connection refused')}"></i>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">{:__('缓存时间')}</label>
<div class="layui-input-inline">
<input type="text" name="cache_time" autocomplete="off"
value="{$config.cache_time}" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">* {:__('单位 /秒')}</div>
</div>
<div class="cache_type" <if
condition="$config['cache_type'] eq 'file' or $config['cache_type'] eq ''">
style="display:none;" </if> >
<div class="layui-form-item">
<label class="layui-form-label">{:__('服务器IP')}</label>
<div class="layui-input-inline">
@@ -385,12 +350,20 @@
value="{$config['cache_port']}" class="layui-input cport">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">{:__('缓存时间')}</label>
<div class="layui-input-inline">
<input type="text" name="cache_time" autocomplete="off"
value="{$config.cache_time}" class="layui-input">
</div>
<div class="layui-form-mid layui-word-aux">* {:__('单位 /秒')}</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">{:__('数据库')}</label>
<div class="layui-input-inline">
<input type="number" name="cache_select" min="1" max="16"
placeholder="{:__('缓存服务redis库 1- 16')}"
value="{$config['cache_select']}" class="layui-input cuser">
value="{$config['cache_select']}" class="layui-input cselect">
</div>
</div>
<div class="layui-form-item">
@@ -407,9 +380,8 @@
value="{$config['cache_pass']}" class="layui-input cpass">
</div>
<button type="button" class="layui-btn layui-btn-primary" lay-ajax=""
data-url="{:url('/Index/testCache')}"
data-object="type:ctype,host:chost,port:cport,user:cuser,pass:cpass">{:__('测试连接')}</button>
</div>
data-url="{:url('/index/testCache')}"
data-object="host:chost,port:cport,user:cuser,select:cselect,pass:cpass">{:__('测试连接')}</button>
</div>
</div>
@@ -427,8 +399,7 @@
<div class="layui-form-item layui-col-md5">
<label class="layui-form-label">{:__('提示信息')}</label>
<div class="layui-input-block">
<textarea id="site_notice" name="site_notice" lay-verify="siteClose"
type="layui-textarea">{$config.site_notice}</textarea>
<textarea name="site_notice" lay-verify="siteClose" class="layui-textarea">{$config.site_notice}</textarea>
</div>
</div>
</div>
@@ -1835,21 +1806,11 @@
<include file="/public/footer" />
<script>
layui.use(['form', 'jquery', 'layedit', 'admin'], function () {
layui.use(['form', 'jquery', 'admin'], function () {
var form = layui.form;
var admin = layui.admin;
var jquery = layui.jquery;
// 渲染富文本编辑器
var layedit = layui.layedit;
var layindex = layedit.build('site_notice', { height: 110, color: '#ffffff' });
// 异步验证表单
form.verify({
siteClose: function (value) {
return layedit.sync(layindex);
}
});
// 增加变量
jquery('.layui-variable-add').on('click', function () {

View File

@@ -290,6 +290,7 @@
</div>
</div>
</div>
<table class="layui-hide" id="ID-treeTable-demo"></table>
</div>
<script src="__STATICADMIN__module/echarts/echarts.js"></script>
<script src="__STATICADMIN__module/echarts/echarts-wordcloud.js"></script>
@@ -298,10 +299,35 @@
<include file="/public/footer"/>
<script>
layui.use(['jquery','layer'], function () {
layui.use(['jquery','layer','treeTable'], function () {
let $ = layui.jquery;
let layer = layui.layer;
let treeTable = layui.treeTable;
var inst = treeTable.render({
elem: '#ID-treeTable-demo',
url: '/static/demo-1.json?page=1&limit=10', // 此处为静态模拟数据,实际使用时需换成真实接口
tree: {
customName: {
icon: 'icon2',
name: 'title'
},
},
maxHeight: '501px',
toolbar: '#TPL-treeTable-demo',
cols: [[
{type: 'checkbox', fixed: 'left'},
{field: 'id', title: 'ID', width: 80, sort: true, fixed: 'left'},
{field: 'name', title: '用户名', width: 180, fixed: 'left'},
{field: 'experience', title: '积分', width: 90, sort: true},
{field: 'sex', title: '性别', width: 80, sort: true},
{field: 'score', title: '评分', width: 80, sort: true},
{field: 'city', title: '城市'},
{ fixed: "right", title: "操作", width: 181, align: "center", toolbar: "#TPL-treeTable-demo-tools"}
]],
page: true
});
/**
* 用户统计报表

View File

@@ -10,7 +10,7 @@
<div class="layui-card-body">
<div class="layui-panel">
<div class="layui-card-header">
<div class="title"><span class="titles"><img src="{$detail.face}" class="face" width="20"> </span>{$detail.nickname}</div>
<div class="title"><span class="titles"><img src="{$detail.face|default=''}" class="face" width="20"> </span>{$detail.nickname|default='隐藏用户'}</div>
<div class="time"><span class="times">时间:</span>{$detail.create_time}</div>
</div>
<div id="layui-info">{$detail.content|raw}</div>

View File

@@ -122,31 +122,37 @@
<include file="/public/footer" />
<script>
layui.use(['admin','form','treetable','iconPicker'], function () {
layui.use(['admin','form','treeTable','iconPicker'], function () {
var jquery = layui.jquery;
var admin = layui.admin;
var form = layui.form;
var table = layui.table;
var treetable = layui.treetable;
var treeTable = layui.treeTable;
var iconPicker = layui.iconPicker;
var tableURL = "{:url('/system/AdminRules/index')}";
// 渲染初始化表格
var renderTable = function (tableURL) {
treetable.render({
treeTable.render({
elem: '#lay-tableList',
treeColIndex: 1,
treeSpid: 0,
treeIdName: 'id',
treePidName: 'pid',
url: tableURL,
cellMinWidth: 100,
treeDefaultClose: true,
tree: {
customName: {
pid: 'pid',
icon: 'icon1',
},
view: {
iconClose: '', // 关闭时候的图标
iconOpen: '', // 打开时候的图标
iconLeaf: '', // 叶子节点的图标
}
},
cols: [[
{type: 'numbers'},
{field: 'title', title: '{:__("菜单名称")}'},
{field: 'name', title: '{:__("菜单名称")}',templet: function(d) {
return '<i class="layui-icon '+d.icon+'"></i> '+d.title;
},},
{field: 'router', title: '{:__("路由地址")}'},
{field: 'alias', title: '{:__("权限标识")}'},
{field: 'auth', width: 80,title: '{:__("鉴权")}',templet: function(d) {
@@ -246,7 +252,7 @@
tips: '请选择上级菜单',
name: 'pid',
height: 'auto',
data: table.cache['rules'],
data: table.cache['lay-tableList'],
radio: true,
clickClose: true,
initValue: checkedId,
@@ -314,6 +320,7 @@
var pageThat = jquery(this);
pageThat.attr("disabled",true);
// 获取提交地址
var _pageUrl;
if (typeof (tableThis) !== 'undefined') {
_pageUrl = tableThis.event === 'edit' ? pageThat.attr('lay-edit') : pageThat.attr('lay-add');
} else {
@@ -328,7 +335,7 @@
// 开始POST提交数据
jquery.post(_pageUrl,
post.field, function(res){
if (res.code == 200) {
if (res.code === 200) {
layer.msg(res.msg);
@@ -356,12 +363,12 @@
// 展开所有
jquery('#expandAll').click(function(){
treetable.expandAll('#lay-tableList');
treeTable.expandAll('lay-tableList', true);
})
// 折叠所有
jquery('#foldAll').click(function () {
treetable.foldAll('#lay-tableList');
treeTable.expandAll('lay-tableList',false);
});
// 执行初始化

View File

@@ -112,26 +112,35 @@
<include file="/public/footer" />
<script src="__STATICADMIN__module/xmselect/xmselect.js"></script>
<script>
layui.use(['admin','form','treetable'], function () {
layui.use(['admin','form','treeTable'], function () {
var jquery = layui.jquery;
var admin = layui.admin;
var form = layui.form;
var table = layui.table;
var treetable = layui.treetable;
var treeTable = layui.treeTable;
var tableURL = "{:url('/system/Department/index')}";
// 渲染初始化表格
var renderTable = function (tableURL) {
var ss = treetable.render({
treeTable.render({
elem: '#lay-tableList',
treeColIndex: 1,
treeSpid: 0,
treeIdName: 'id',
treePidName: 'pid',
url: tableURL,
cellMinWidth: 100,
tree: {
customName: {
name: 'title',
icon: 'icon1',
},
view: {
iconClose: '', // 关闭时候的图标
iconOpen: '', // 打开时候的图标
iconLeaf: '', // 叶子节点的图标
expandAllDefault: true,
}
},
// 默认展开
cols: [[
{type: 'numbers'},
{field: 'title', title: '{:__("部门名称")}'},
@@ -179,7 +188,7 @@
tips: '请选择上级部门',
name: 'pid',
height: 'auto',
data: table.cache.depart,
data: table.cache['lay-tableList'],
radio: true,
clickClose: true,
initValue: checkedId,
@@ -210,6 +219,7 @@
var pageThat = jquery(this);
pageThat.attr("disabled",true);
// 获取提交地址
var _pageUrl;
if (typeof (tableThis) !== 'undefined') {
_pageUrl = tableThis.event === 'edit' ? pageThat.attr('lay-edit') : pageThat.attr('lay-add');
} else {
@@ -225,7 +235,7 @@
// 开始POST提交数据
jquery.post(_pageUrl,
post.field, function(res){
if (res.code == 200) {
if (res.code === 200) {
layer.msg(res.msg);
// 更新列数据
if (typeof(tableThis) !== 'undefined') {

View File

@@ -108,6 +108,7 @@
let $ = layui.jquery;
let table = layui.table;
let dropdown = layui.dropdown;
window.framework = "{:config('app.version')}";
window.plugins = {$plugin|raw};
/*
* 初始化表格

View File

@@ -4,11 +4,10 @@ declare (strict_types=1);
namespace app\api\controller;
use app\ApiController;
use app\common\library\Email;
use app\common\library\Sms;
use app\common\model\system\User;
use PHPMailer\PHPMailer\Exception;
use app\common\exception\OperateException;
use app\common\service\notice\EmailService;
use app\common\service\notice\SmsService;
use Psr\SimpleCache\InvalidArgumentException;
use support\Response;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
@@ -19,87 +18,47 @@ use think\db\exception\ModelNotFoundException;
*/
class Ajax extends ApiController
{
public bool $needLogin = true;
/**
* 发送短信
* @return Response|void
* @throws DataNotFoundException
* @throws DbException
* 首页
*/
public function smsSend()
public function index(): Response
{
if (request()->isPost()) {
$mobile = input('mobile');
$event = input('event', 'register');
if (!is_mobile($mobile)) {
return $this->error('手机号码不正确');
}
$sms = Sms::instance();
$data = $sms->getLast($mobile);
if ($data && (time() - strtotime($data['create_time'])) < 60) {
return $this->error(__('发送频繁'));
}
$user = User::getByMobile($mobile);
if (in_array($event, ['register', 'changer']) && $user) {
return $this->error('当前手机号已被占用');
} else if ($event == 'forgot' && !$user) {
return $this->error('当前手机号未注册');
}
if ($sms->send($mobile, $event)) {
return $this->success("验证码发送成功!");
} else {
return $this->error($sms->getError());
}
}
return json(['msg' => 'success', 'data' => 'Hello']);
return response('Hello swiftadmin!');
}
/**
* 发送邮件
* @return Response|void
* 发送短信验证码
* @return Response
* @throws InvalidArgumentException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws Exception
*/
public function emailSend()
public function smsSend(): Response
{
if (request()->isPost()) {
$mobile = input('mobile', '');
$event = input('event', 'register');
if (!SmsService::filterMobile($mobile)) {
return $this->error('手机号码不正确');
}
SmsService::send($mobile, $event);
return $this->success("验证码发送成功!");
}
/**
* 发送邮件验证码
* @return Response
* @throws InvalidArgumentException
* @throws OperateException
*/
public function emailSend(): Response
{
$email = input('email');
$event = input('event', 'register');
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
if (!EmailService::filterEmail($email)) {
return $this->error('邮件格式不正确');
}
$Ems = Email::instance();
$data = $Ems->getLast($email);
if ($data && (time() - strtotime($data['create_time'])) < 60) {
return $this->error(__('发送频繁'));
}
$user = User::getByEmail($email);
if (in_array($event, ['register', 'changer']) && $user) {
return $this->error('当前邮箱已被注册');
} else if ($event == 'forgot' && !$user) {
return $this->error('当前邮箱不存在');
}
if ($Ems->captcha($email, $event)->send()) {
EmailService::captcha($email, $event);
return $this->success("验证码发送成功!");
} else {
return $this->error($Ems->getError());
}
}
}
}

View File

@@ -4,10 +4,18 @@
namespace app\api\controller;
use app\ApiController;
use app\common\exception\OperateException;
use app\common\exception\user\UserException;
use app\common\library\ResultCode;
use app\common\library\Sms;
use app\common\library\Upload;
use app\common\model\system\User as UserModel;
use app\common\validate\system\User as UserValidate;
use app\common\service\user\UserService;
use PHPMailer\PHPMailer\Exception;
use Psr\SimpleCache\InvalidArgumentException;
use support\Request;
use support\Response;
use system\Random;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
@@ -27,76 +35,261 @@ class User extends ApiController
* 非鉴权方法
* @var array
*/
public array $noNeedAuth = ['register', 'login'];
public array $noNeedLogin = ['register', 'login', 'mobileLogin', 'mnpLogin', 'forgot'];
/**
* 构造方法
*/
public function __construct()
{
parent::__construct();
$this->model = new UserModel();
}
/**
* 用户中心
* @param Request $request
* @return Response
*/
public function center(Request $request): Response
{
$fields = $this->model->getVisibleFields();
$userInfo = array_intersect_key($request->userInfo, array_flip($fields));
return $this->success('获取成功', '', $userInfo);
}
/**
* 修改用户资料
* @param Request $request
* @return Response
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws OperateException
*/
public function profile(Request $request): Response
{
$post = request()->post();
validate(UserValidate::class)->scene('nickname')->check($post);
UserService::editProfile($post, $request->userId);
return $this->success('修改成功', '/');
}
/**
* 用户注册
* @return mixed|void
* @throws DataNotFoundException
* @return Response
* @throws DbException
* @throws ModelNotFoundException|InvalidArgumentException
* @throws InvalidArgumentException
* @throws OperateException
*/
public function register()
public function register(): Response
{
if (request()->isPost()) {
// 获取参数
$post = input('post.');
// 获取注册方式
$registerType = saenv('user_register');
if ($registerType == 'mobile') {
$mobile = input('mobile');
$captcha = input('captcha');
// 校验手机验证码
if (!Sms::instance()->check($mobile, $captcha, 'register')) {
return $this->error(Sms::instance()->getError());
}
}
$response = $this->auth->register($post);
if (!$response) {
return $this->error($this->auth->getError());
}
return $response->withBody(json_encode(ResultCode::REGISTERSUCCESS));
}
$post = request()->post();
validate(UserValidate::class)->scene('register')->check($post);
$result = UserService::register($post);
return $this->success('注册成功', '/', ['token' => $result['token']]);
}
/**
* 用户登录
* @return mixed|void
* @return Response
* @throws InvalidArgumentException
* @throws OperateException
*/
public function login() {
if (request()->isPost()) {
// 获取参数
public function login(): Response
{
$nickname = input('nickname');
$password = input('pwd');
$response = $this->auth->login($nickname, $password);
if (!$response) {
return $this->error($this->auth->getError());
}
$response->withBody(json_encode(array_merge(ResultCode::LOGINSUCCESS, ['token' => $this->auth->token])));
return $response;
if (!$nickname || !$password) {
return $this->error('请输入用户名或密码');
}
$result = UserService::accountLogin($nickname, $password);
return $this->success('登录成功', '/', ['token' => $result['token']]);
}
/**
* 文件上传
* 手机号登录
* @return Response
* @throws DataNotFoundException
* @throws DbException
* @throws InvalidArgumentException
* @throws ModelNotFoundException
* @throws OperateException
*/
public function upload()
public function mobileLogin(): Response
{
$mobile = input('mobile');
$captcha = input('captcha');
$result = UserService::mobileLogin($mobile, $captcha);
return $this->success('登录成功', '/', ['token' => $result['token']]);
}
/**
* 修改密码
* @param Request $request
* @return Response
* @throws OperateException
*/
public function changePwd(Request $request): Response
{
$post = request()->post();
UserService::changePwd($post, $request->userId);
return $this->success('修改密码成功!');
}
/**
* 找回密码
* @return Response
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws OperateException
*/
public function forgot(): Response
{
$post = request()->post();
validate(UserValidate::class)->check($post);
UserService::forgotPwd($post);
return $this->success('修改密码成功!');
}
/**
* 获取消息列表
* @param Request $request
* @return Response
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function message(Request $request): Response
{
$page = input('page/d', 1);
$limit = input('limit/d', 1);
$status = input('status', 'all');
$where[] = ['user_id', '=', $request->userId];
if ($status !== 'all') {
$where[] = ['status', '=', $status];
}
list($list, $count) = UserService::listMessage($limit, $page, $where);
return $this->success('查询成功', "/", $list, $count);
}
/**
* 查看消息
* @param Request $request
* @return Response
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws OperateException
*/
public function viewMessage(Request $request): Response
{
$id = input('id/d', 0);
$result = UserService::viewMessage($id, $request->userId);
return $this->success('查询成功', "/", $result);
}
/**
* 批量操作消息
* @param Request $request
* @return Response
*/
public function batchMessage(Request $request): Response
{
$ids = input('id');
$type = input('type', 'del');
try {
UserService::batchMessage($ids, $type, $request->userId);
} catch (UserException $e) {
return $this->error($e->getMessage());
}
return $this->success('操作成功');
}
/**
* 申请APP_KEY
* @param Request $request
* @return Response
*/
public function appid(Request $request): Response
{
$data['id'] = $request->userId;
$data['app_id'] = 10000 + $request->userId;
$data['app_secret'] = Random::alpha(22);
if ($this->model->update($data)) {
return $this->success('申请成功!', '/', $data);
}
return $this->error('申请失败!');
}
/**
* 修改邮箱地址
* @param Request $request
* @return Response
* @throws Exception|UserException|OperateException
*/
public function changeEmail(Request $request): Response
{
$email = input('email');
$captcha = input('captcha');
$event = input('event');
UserService::changeEmail($email, $captcha, $event, $request->userId);
return $this->success('修改邮箱成功!');
}
/**
* 修改手机号
* @param Request $request
* @return Response
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws OperateException
* @throws UserException
*/
public function changeMobile(Request $request): Response
{
$mobile = input('mobile');
$captcha = input('captcha');
$event = input('event');
UserService::changeMobile($mobile, $captcha, $event, $request->userId);
return $this->success('修改手机号成功!');
}
/**
* 意见反馈
* @return Response
*/
public function feedback(): Response
{
$type = input('type', '');
$content = input('content');
if (empty($type) || empty($content)) {
return $this->error('参数错误');
}
return $this->success('反馈成功');
}
/**
* 文件上传函数
* @return Response
* @throws DataNotFoundException
* @throws DbException
* @throws InvalidArgumentException
* @throws ModelNotFoundException
*/
public function upload(): Response
{
if (request()->isPost()) {
$file = Upload::instance()->upload();
if (!$file) {
$response = Upload::instance()->upload();
if (empty($response)) {
return $this->error(Upload::instance()->getError());
}
return json($file);
}
return json($response);
}
return json(ResultCode::SUCCESS);
}
}

View File

@@ -1,9 +1,9 @@
<?php
namespace app\api\middleware\system;
use app\common\library\Auth;
use app\common\library\ResultCode;
use app\common\service\user\UserTokenService;
use Psr\SimpleCache\InvalidArgumentException;
use Webman\Event\Event;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
@@ -28,42 +28,52 @@ class ApiPermissions implements MiddlewareInterface
*/
public bool $authWorkflow = true;
/**
* 禁止登录重复
* @var array
*/
public array $repeatLogin = ['login', 'register'];
/**
* 非鉴权方法
* @var array
*/
public array $noNeedAuth = [];
public array $noNeedLogin = [];
/**
* 校验权限
* @param Request $request
* @param \support\Request|Request $request
* @param callable $handler
* @return Response
* @throws InvalidArgumentException
* @throws \ReflectionException
*/
public function process(Request $request, callable $handler): Response
public function process(\support\Request|Request $request, callable $handler): Response
{
$app = request()->getApp();
$controller = request()->getController();
$action = request()->getAction();
$method = $controller . '/' . $action;
$refClass = new \ReflectionClass($request->controller);
$property = $refClass->getDefaultProperties();
$this->needLogin = $property['needLogin'] ?? $this->needLogin;
$this->noNeedAuth = $property['noNeedAuth'] ?? $this->noNeedAuth;
$this->noNeedLogin = $property['noNeedLogin'] ?? $this->noNeedLogin;
$this->repeatLogin = $property['repeatLogin'] ?? $this->repeatLogin;
$auth = Auth::instance();
if ($auth->isLogin()) {
// 验证权限
// 是否验证登录器
$userInfo = UserTokenService::isLogin();
if (!empty($userInfo)) {
$request->userId = $userInfo['id'];
$request->userInfo = $userInfo;
// 是否验证API权限
if ($this->authWorkflow && Event::hasListener('apiAuth')) {
$result = Event::emit('apiAuth', ['method' => $method, 'user_id' => $auth->user_id], true);
$result = Event::emit('apiAuth', ['method' => $method, 'user_id' => $userInfo['id']], true);
if (isset($result['code']) && $result['code'] != 200) {
return json($result);
}
}
} else {
if ($this->needLogin && !in_array($action, $this->noNeedAuth)) {
if ($this->needLogin && !in_array($action, $this->noNeedLogin)) {
return json(ResultCode::AUTH_ERROR);
}
}

View File

@@ -6,8 +6,7 @@ use app\common\model\system\SystemLog;
use Psr\SimpleCache\InvalidArgumentException;
use support\exception\BusinessException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use Webman\Exception\ExceptionHandler;
use Webman\Http\Request;
use Webman\Http\Response;
@@ -17,44 +16,36 @@ class ExceptionHandle extends ExceptionHandler
{
public $dontReport = [
BusinessException::class,
ValidateException::class,
DataNotFoundException::class,
OperateException::class,
DumpException::class,
];
/**
* 异常日志记录
* @param Throwable $exception
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws InvalidArgumentException
*/
public function report(Throwable $exception)
{
try {
if (saenv('system_exception') && !empty($exception->getMessage())) {
$data = [
'module' => request()->app,
'controller' => request()->controller,
'action' => request()->action,
'params' => serialize(request()->all()),
'method' => request()->method(),
'url' => request()->url(),
'ip' => request()->getRealIp(),
'name' => session('AdminLogin.name'),
];
if (empty($data['name'])) {
$data['name'] = 'system';
if (saenv('system_exception')
&& !$this->shouldntReport($exception)) {
$logs['module'] = request()->app;
$logs['controller'] = request()->controller;
$logs['action'] = request()->action;
$logs['params'] = serialize(request()->all());
$logs['method'] = request()->method();
$logs['url'] = request()->url();
$logs['ip'] = request()->getRealIp();
$logs['name'] = session('AdminLogin.name') ?? 'system';
$logs['type'] = 1;
$logs['code'] = $exception->getCode();
$logs['file'] = $exception->getFile();
$logs['line'] = $exception->getLine();
$logs['error'] = $exception->getMessage();
SystemLog::write($logs);
}
$data['type'] = 1;
$data['code'] = $exception->getCode();
$data['file'] = $exception->getFile();
$data['line'] = $exception->getLine();
$data['error'] = $exception->getMessage();
SystemLog::write($data);
}
} catch (InvalidArgumentException $e) {
}
parent::report($exception);
}
/**
@@ -64,12 +55,16 @@ class ExceptionHandle extends ExceptionHandler
*/
public function render(Request $request, Throwable $exception): Response
{
if ($exception instanceof \RuntimeException) {
switch (true) {
case $exception instanceof OperateException:
case $exception instanceof ValidateException:
return json(['code' => $exception->getCode() ?? 101, 'msg' => $exception->getMessage()]);
case $exception instanceof DumpException:
return \response($exception->getMessage());
default:
break;
}
if (!file_exists(root_path() . '.env')) {
return parent::render($request, $exception);
}
return get_env('APP_DEBUG') ? parent::render($request, $exception) : view(config('app.exception_tpl'), ['trace' => $exception]);
}
}

View File

@@ -1,336 +0,0 @@
<?php
declare(strict_types=1);
// +----------------------------------------------------------------------
// | swiftAdmin 极速开发框架 [基于WebMan开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
// +----------------------------------------------------------------------
// | swiftAdmin.net High Speed Development Framework
// +----------------------------------------------------------------------
// | Author: meystack <coolsec@foxmail.com> Apache 2.0 License
// +----------------------------------------------------------------------
namespace app\common\library;
use app\common\model\system\UserLog;
use Psr\SimpleCache\InvalidArgumentException;
use system\Random;
use support\Response;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Cache;
use app\common\model\system\User as UserModel;
use Webman\Event\Event;
class Auth
{
/**
* token令牌
* @var string
*/
public string $token;
/**
* 用户ID
*/
public mixed $user_id = 0;
/**
* 用户数据
* @var object|array
*/
public mixed $userInfo;
/**
* 保活时间
* @var int
*/
protected int $keepTime = 604800;
/**
* 错误信息
* @var string
*/
protected string $_error = '';
/**
* @var object 对象实例
*/
protected static $instance;
/**
* 类构造函数
* class constructor.
*/
public function __construct($config = [])
{
$this->keepTime = config('session.cookie_lifetime');
}
/**
* 初始化
* @access public
* @param array $options 参数
* @return object
*/
public static function instance(array $options = [])
{
if (is_null(self::$instance)) {
self::$instance = new static($options);
}
// 返回实例
return self::$instance;
}
/**
* 用户注册
* @param array $post
* @return false|Response
* @throws DataNotFoundException
* @throws DbException
* @throws InvalidArgumentException
* @throws ModelNotFoundException
*/
public function register(array $post)
{
if (!saenv('user_status')) {
$this->setError('暂未开放注册!');
return false;
}
// 禁止批量注册
$where[] = ['create_ip', '=', request()->getRealIp()];
$where[] = ['create_time', '>', linux_time(1)];
$totalMax = UserModel::where($where)->count();
if ($totalMax >= saenv('user_register_second')) {
$this->setError('当日注册量已达到上限');
return false;
}
// 过滤用户信息
if (isset($post['nickname']) && UserModel::getByNickname($post['nickname'])) {
$this->setError('当前用户名已被占用!');
return false;
}
if (isset($post['email']) && UserModel::getByEmail($post['email'])) {
$this->setError('当前邮箱已被占用!');
return false;
}
if (isset($post['mobile']) && UserModel::getByMobile($post['mobile'])) {
$this->setError('当前手机号已被占用!');
return false;
}
try {
/**
* 是否存在邀请注册
*/
$post['invite_id'] = $this->getToken('inviter');
if (isset($post['pwd']) && $post['pwd']) {
$post['salt'] = Random::alpha();
$post['pwd'] = encryptPwd($post['pwd'], $post['salt']);
}
$user = UserModel::create($post);
} catch (\Throwable $th) {
$this->setError($th->getMessage());
return false;
}
return $this->responseToken($user);
}
/**
* 用户检测登录
* @param string $nickname
* @param string $pwd
* @return false|Response
* @throws DataNotFoundException
* @throws DbException
* @throws InvalidArgumentException
* @throws ModelNotFoundException
*/
public function login(string $nickname = '', string $pwd = '')
{
// 支持邮箱或手机登录
if (filter_var($nickname, FILTER_VALIDATE_EMAIL)) {
$where[] = ['email', '=', htmlspecialchars(trim($nickname))];
} else {
$where[] = ['mobile', '=', htmlspecialchars(trim($nickname))];
}
$user = UserModel::where($where)->find();
if (!empty($user)) {
$uPwd = encryptPwd($pwd, $user['salt']);
if ($user['pwd'] !== $uPwd) {
$this->setError('用户名或密码错误');
UserLog::write($this->getError(), $user['nickname'], $user['id']);
return false;
}
if (!$user['status']) {
$this->setError('用户异常或未审核,请联系管理员');
UserLog::write($this->getError(), $user['nickname'], $user['id']);
return false;
}
// 更新登录数据
$update = [
'id' => $user['id'],
'login_time' => time(),
'login_ip' => request()->getRealIp(),
'login_count' => $user['login_count'] + 1,
];
if (UserModel::update($update)) {
Event::emit('userLoginSuccess', $user);
UserLog::write('登录成功', $user['nickname'], $user['id'], 1);
return $this->responseToken($user);
}
}
$this->setError('您登录的用户不存在');
return false;
}
/**
* 验证是否登录
* @return bool
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException|InvalidArgumentException
*/
public function isLogin(): bool
{
$token = $this->getToken();
if (!$token) {
return false;
}
// 验证token
$user = $this->checkToken($token);
if (isset($user['id'])) {
$this->userInfo = UserModel::with('group')->find($user['id']);
if (!empty($this->userInfo)) {
$this->token = $token;
$this->user_id = $user['id'];
$this->refreshUserInfo($token, $this->userInfo);
return true;
}
}
return false;
}
/**
* 获取用户信息
*/
public function getUserInfo()
{
$token = $this->getToken();
if (!$token) {
return false;
}
// 获取用户信息
return $this->checkToken($token);
}
/**
*
* 返回前端令牌
* @param $user
* @param bool $token
* @return Response
* @throws InvalidArgumentException
*/
public function responseToken($user, bool $token = false): Response
{
$this->token = $token ? $this->getToken() : $this->buildToken($user['id']);
$response = response();
$response->cookie('uid', $user['id'], $this->keepTime, '/');
$response->cookie('token', $this->token, $this->keepTime, '/');
$response->cookie('nickname', $user['nickname'], $this->keepTime, '/');
$this->refreshUserInfo($this->token, $user);
// 执行登录成功事件
Event::emit("userLoginSuccess", $user);
return $response;
}
/**
* 刷新用户信息
* @param $token
* @param $user
* @return void
* @throws InvalidArgumentException
*/
private function refreshUserInfo($token, $user): void
{
Cache::set($token, $user, $this->keepTime);
}
/**
* 生成token
* @access protected
* @param $id
* @return string
*/
protected function buildToken($id): string
{
return md5(Random::alpha(16) . $id);
}
/**
* 获取token
*/
public function getToken($token = 'token')
{
return request()->header($token, input($token, request()->cookie($token)));
}
/**
* 校验token
*/
public function checkToken($token)
{
return Cache::get($token);
}
/**
* 退出登录
* @return void
* @throws InvalidArgumentException
*/
public function logout()
{
Cache::delete($this->token);
}
/**
* 获取最后产生的错误
* @return string
*/
public function getError(): string
{
return $this->_error;
}
/**
* 设置错误
* @param string $error 信息信息
* @return void
*/
protected function setError(string $error): void
{
$this->_error = $error;
}
}

View File

@@ -1,358 +0,0 @@
<?php
declare(strict_types=1);
// +----------------------------------------------------------------------
// | swiftAdmin 极速开发框架 [基于WebMan开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
// +----------------------------------------------------------------------
// | swiftAdmin.net High Speed Development Framework
// +----------------------------------------------------------------------
// | Author: meystack <coolsec@foxmail.com> Apache 2.0 License
// +----------------------------------------------------------------------
namespace app\common\library;
use app\common\model\system\UserValidate;
use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\PHPMailer;
use Psr\SimpleCache\InvalidArgumentException;
use system\Random;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\db\Query;
use think\Model;
/**
* 邮件发送类
*
*/
class Email
{
/**
* @var object 对象实例
*/
protected static $instance = null;
/**
* @PHPMailer 对象实例
*/
protected mixed $mail;
/**
* 验证码对象
* @var mixed
*/
private mixed $userVModel;
/**
* 验证码过期时间
* @var int
*/
private int $expireTime = 5; //验证码过期时间(分钟)
/**
* 错误信息
* @var string
*/
protected string $_error = '';
//默认配置
protected array $config = [
'smtp_debug' => false, // 是否调试
'smtp_host' => 'smtp.163.com', // 服务器地址
'smtp_port' => 587, // 服务器端口
'smtp_user' => 'yourname@163.com', // 邮件用户名
'smtp_pass' => '****', // 邮件密码
'smtp_name' => '管理员', // 发送邮件显示
];
/**
* 类构造函数
* class constructor.
* @throws Exception
* @throws InvalidArgumentException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function __construct()
{
// 此配置项为数组
if ($email = saenv('email')) {
$this->config = array_merge($this->config, $email);
}
// 创建PHPMailer对象实例
$this->mail = new PHPMailer();
$this->mail->CharSet = 'UTF-8';
$this->mail->IsSMTP();
/**
* 是否开启调试模式
*/
$this->mail->SMTPDebug = $this->config['smtp_debug'];
$this->mail->SMTPAuth = true;
$this->mail->SMTPSecure = 'ssl';
$this->mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);
$this->mail->Host = $this->config['smtp_host'];
$this->mail->Port = $this->config['smtp_port'];
$this->mail->Username = $this->config['smtp_user'];
$this->mail->Password = trim($this->config['smtp_pass']);
$this->mail->SetFrom($this->config['smtp_user'], $this->config['smtp_name']);
$this->userVModel = new UserValidate();
}
/**
* 初始化
* @access public
* @param array $options 参数
* @return EMAIL
* @throws DataNotFoundException
* @throws DbException
* @throws Exception
* @throws InvalidArgumentException
* @throws ModelNotFoundException
*/
public static function instance($options = [])
{
if (is_null(self::$instance)) {
self::$instance = new static($options);
}
// 返回实例
return self::$instance;
}
/**
* 设置邮件主题
* @param string $subject 邮件主题
* @return $this
*/
public function Subject(string $subject): Email
{
$this->mail->Subject = $subject;
return $this;
}
/**
* 设置发件人
* @param string $email 发件人邮箱
* @param string $name 发件人名称
* @return $this
* @throws \PHPMailer\PHPMailer\Exception
*/
public function from(string $email, string $name = ''): Email
{
$this->mail->setFrom($email, $name);
return $this;
}
/**
* 设置邮件内容
* @param $MsgHtml
* @param boolean $isHtml 是否HTML格式
* @return $this
* @throws \PHPMailer\PHPMailer\Exception
*/
public function MsgHTML($MsgHtml, bool $isHtml = true): Email
{
if ($isHtml) {
$this->mail->msgHTML($MsgHtml);
} else {
$this->mail->Body = $MsgHtml;
}
return $this;
}
/**
* 设置收件人
* @param $email
* @param string $name
* @return $this
* @throws Exception
*/
public function to($email, string $name = ''): Email
{
$emailArr = $this->buildAddress($email);
foreach ($emailArr as $address => $name) {
$this->mail->addAddress($address, $name);
}
return $this;
}
/**
* 添加附件
* @param string $path 附件路径
* @param string $name 附件名称
* @return Email
* @throws \PHPMailer\PHPMailer\Exception
*/
public function attachment(string $path, string $name = ''): Email
{
if (is_file($path)) {
$this->mail->addAttachment($path, $name);
}
return $this;
}
/**
* 构建Email地址
* @param $emails
* @return array
*/
protected function buildAddress($emails): array
{
$emails = is_array($emails) ? $emails : explode(',', str_replace(";", ",", $emails));
$result = [];
foreach ($emails as $key => $value) {
$email = is_numeric($key) ? $value : $key;
$result[$email] = is_numeric($key) ? "" : $value;
}
return $result;
}
/**
* 获取最后一条
* @param string $email
* @return mixed
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function getLast(string $email)
{
$sms = UserValidate::where('email', $email)->order('id', 'desc')->find();
return $sms ?: null;
}
/**
* 发送验证码
* @param string $email 收件人邮箱
* @param string $event
* @return Email
* @throws \PHPMailer\PHPMailer\Exception
*/
public function captcha(string $email = '', string $event = "default"): Email
{
$code = Random::number();
$array = [
'code' => $code,
'event' => $event,
'email' => $email,
'status' => 1,
];
$this->userVModel->create($array);
$content = read_file(base_path() . '/extend/conf/tpl/captcha.tpl');
$content = str_replace(['{code}', '{site_name}', '{time}'], [$code, saenv('site_name'), date('Y-m-d H:i:s')], $content);
$this->to($email)->Subject("验证码")->MsgHTML($content);
return $this;
}
/**
* 检查验证码
* @param string $email
* @param string $code
* @param string $event
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function check(string $email, string $code = '', string $event = "default"): bool
{
$result = $this->userVModel->where([
['event', '=', $event],
['email', '=', $email],
['status', '=', 1],
])->order("id", "desc")->find();
if (!empty($result) && $result->code == $code) {
// 设置已使用
$result->status = 0;
$result->save();
// 是否过期
$expires = time() - strtotime($result['create_time']);
if ($expires <= $this->expireTime * 60) {
return true;
}
$this->setError("当前验证码已过期!");
} else {
$this->setError("无效验证码");
}
return false;
}
/**
* 获取最后产生的错误
* @return string
*/
public function getError(): string
{
return $this->_error;
}
/**
* 设置错误
* @param string $error 信息信息
*/
protected function setError(string $error): void
{
$this->_error = $error;
}
/**
* 发送邮件
* @return boolean
*/
public function send(): bool
{
$result = false;
try {
$result = $this->mail->send();
} catch (\PHPMailer\PHPMailer\Exception $e) {
$this->setError($e->getMessage());
}
$this->setError($result ? '' : $this->mail->ErrorInfo);
return $result;
}
/**
* 测试发送邮件
*/
public function testEmail($config)
{
if (empty($config) || !is_array($config)) {
return '缺少必要的信息';
}
$this->config = array_merge($this->config, $config);
$this->mail->Host = $this->config['smtp_host'];
$this->mail->Port = $this->config['smtp_port'];
$this->mail->Username = $this->config['smtp_user'];
$this->mail->Password = trim($this->config['smtp_pass']);
$this->mail->SetFrom($this->config['smtp_user'], $this->config['smtp_name']);
return $this->to($config['smtp_test'])->Subject("测试邮件")->MsgHTML("如果您看到这封邮件,说明测试成功了!")->send();
}
}

View File

@@ -1,154 +0,0 @@
<?php
declare(strict_types=1);
// +----------------------------------------------------------------------
// | swiftAdmin 极速开发框架 [基于WebMan开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
// +----------------------------------------------------------------------
// | swiftAdmin.net High Speed Development Framework
// +----------------------------------------------------------------------
// | Author: meystack <coolsec@foxmail.com> Apache 2.0 License
// +----------------------------------------------------------------------
namespace app\common\library;
use support\Log;
use system\Random;
/**
* FTP上传类
*
*/
class Ftp
{
/**
* @var object 对象实例
*/
protected static $instance = null;
//默认配置
protected array $config = [
'upload_ftp_host' => '127.0.0.1', // 服务器地址
'upload_ftp_port' => 21, // 服务器端口
'upload_ftp_user' => 'username', // FTP用户名
'upload_ftp_pass' => 'password', // FTP密码
'upload_path' => 'upload', // 上传路径
];
/**
* 类构造函数
* class constructor.
*/
public function __construct()
{
if ($upload = saenv('upload', true)) {
$this->config = array_merge($this->config, $upload);
}
}
/**
* 初始化
* @access public
* @param array $options 参数
* @return Ftp
*/
public static function instance($options = [])
{
if (is_null(self::$instance)) {
self::$instance = new static($options);
}
// 返回实例
return self::$instance;
}
/**
* FTP上传函数
* @access public
* @param string $source 源文件
* @param string $filepath 文件路径
* @param string $filename 文件名称
* @return bool true|false
*/
public function ftpUpload(string $source, string $filepath, string $filename): bool
{
if (!empty($source) && !empty($filepath)) {
// 链接FTP
$connect = @ftp_connect($this->config['upload_ftp_host'], $this->config['upload_ftp_port']) or die('Could not connect');
if (!ftp_login($connect, $this->config['upload_ftp_user'], $this->config['upload_ftp_pass'])) {
return false;
}
// 开启被动模式
ftp_pasv($connect, TRUE);
$source = fopen($source, "r");
// 循环创建文件夹
$filepath = str_replace("\\", '/', $filepath);
$dirs = explode('/', $filepath);
foreach ($dirs as $val) {
if (@ftp_chdir($connect, $val) == false) {
if (!ftp_mkdir($connect, $val)) {
//创建失败
return false;
}
// 切换目录
@ftp_chdir($connect, $val);
}
}
if (!@ftp_fput($connect, $filename, $source, FTP_BINARY)) {
return false;
}
ftp_close($connect);
return true;
} else {
return false;
}
}
/**
* FTP测试函数
* @access public
* @param array $config 配置信息
* @return bool true|false
*/
public function ftpTest(array $config): bool
{
$connect = @ftp_connect($config['host'], (int)$config['port']) or die('Could not connect');
if (@ftp_login($connect, $config['user'], $config['pass'])) {
try {
// 开启被动模式
ftp_pasv($connect, TRUE);
$folder = Random::alpha(16);
if (ftp_mkdir($connect, $folder)) {
// 读取测试文件
$location = __DIR__;
$source = fopen($location, "r"); // 上传测试文件
$filename = $folder . "/target.txt";
ftp_fput($connect, $filename, $source, FTP_BINARY);
// 删除测试文件
ftp_delete($connect, $filename);
ftp_rmdir($connect, $folder);
ftp_close($connect);
return true;
}
} catch (\Throwable $th) {
Log::info('upload ftp ' . $th->getMessage());
return false;
}
}
return false;
}
}

View File

@@ -1,192 +0,0 @@
<?php
declare (strict_types=1);
// +----------------------------------------------------------------------
// | swiftAdmin 极速开发框架 [基于WebMan开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2030 http://www.swiftadmin.net
// +----------------------------------------------------------------------
// | swiftAdmin.net High Speed Development Framework
// +----------------------------------------------------------------------
// | Author: meystack <coolsec@foxmail.com> Apache 2.0 License
// +----------------------------------------------------------------------
namespace app\common\library;
use app\common\model\system\UserValidate;
use Psr\SimpleCache\InvalidArgumentException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use Webman\Event\Event;
/**
* 短信息类
*
*/
class Sms
{
/**
* 默认配置
* @var array
*/
protected array $config = [];
/**
* 错误信息
* @var string
*/
protected string $_error = '';
/**
* 验证码对象
* @var mixed
*/
protected string $smsType = 'alisms';
/**
* 验证码过期时间
* @var int
*/
private int $expireTime = 5; //验证码过期时间(分钟)
/**
* @var object 对象实例
*/
protected static $instance = null;
/**
* 类构造函数
* class constructor.
* @throws InvalidArgumentException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function __construct()
{
// 此配置项为数组。
if ($this->smsType = saenv('smstype')) {
$this->config = array_merge($this->config, saenv($this->smsType));
}
}
/**
* 初始化
* @access public
* @param array $options 参数
* @return self
* @throws DataNotFoundException
* @throws DbException
* @throws InvalidArgumentException
* @throws ModelNotFoundException
*/
public static function instance($options = [])
{
if (is_null(self::$instance)) {
self::$instance = new static($options);
}
// 返回实例
return self::$instance;
}
/**
* 发送短信
* @param string $mobile
* @param string $event
* @return bool
*/
public function send(string $mobile, string $event = 'register'): bool
{
if (!Event::hasListener('smsMsgSend')) {
$this->setError('短信插件未安装');
return false;
}
$config = include(base_path() . "/extend/conf/sms/sms.php");
if (!isset($config[$this->smsType][$event]['template'])) {
$this->setError('短信模板错误');
return false;
}
$response = Event::emit('smsMsgSend', [
'mobile' => $mobile,
'event' => $event,
'template' => $config[$this->smsType][$event]['template']
],true);
if ($response['error']) {
$this->setError($response['msg']);
return false;
}
return true;
}
/**
* 获取最后一条
* @param string $mobile
* @return UserValidate|array|mixed|\think\Model|null
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getLast(string $mobile)
{
$mobile = str_replace(['+86', '-', ' ', '.'], '', $mobile);
$sms = UserValidate::where('mobile', $mobile)->order('id', 'desc')->find();
return $sms ?: null;
}
/**
* 检查验证码
*
* @param string $mobile
* @param string $code
* @param string $event
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function check(string $mobile, string $code, string $event = "default"): bool
{
$where = [
['event', '=', $event],
['mobile', '=', $mobile],
['status', '=', 1],
];
$result = UserValidate::where($where)->order("id", "desc")->find();
if (!empty($result) && $result->code === $code) {
$result->status = 0;
$result->save();
$expires = time() - strtotime($result['create_time']);
if ($expires <= $this->expireTime * 60) {
return true;
}
$this->setError("当前验证码已过期!");
} else {
$this->setError("无效验证码");
}
return false;
}
/**
* 获取最后产生的错误
* @return string
*/
public function getError(): string
{
return $this->_error;
}
/**
* 设置错误
* @param string $error 信息信息
*/
protected function setError(string $error): void
{
$this->_error = $error;
}
}

View File

@@ -1,6 +1,8 @@
<?php
namespace app\common\logic;
namespace app\common\logic\admin;
use app\common\service\BaseServiceLogic;
/**
* 管理员日志逻辑层
@@ -9,7 +11,7 @@ namespace app\common\logic;
* @author meystack<
* @version 1.0
*/
class AdminLogic extends \think\model
class AdminLogic extends BaseServiceLogic
{
// TODO..
}

View File

@@ -19,6 +19,10 @@ class User extends Model
// 定义时间戳字段名
protected $createTime = 'create_time';
protected $updateTime = 'update_time';
/**
* @var array|string[] 可见字段
*/
protected array $visibleFields = ['id', 'nickname', 'heart', 'avatar', 'mobile', 'email', 'score', 'gender', 'create_time', 'update_time'];
/**
* 定义第三方登录
@@ -121,6 +125,25 @@ class User extends Model
return $value;
}
/**
* 获取可见字段
* @return array|string[]
*/
public function getVisibleFields(): array
{
return $this->visibleFields;
}
/**
* 设置可见字段
* @param array $visibleFields
* @return void
*/
public function setVisibleFields(array $visibleFields): void
{
$this->visibleFields = $visibleFields;
}
/**
* 减少会员积分
*
@@ -128,7 +151,7 @@ class User extends Model
* @param integer $score
* @return void
*/
public static function reduceScore(int $id = 0, int $score = 0)
public static function reduceScore(int $id = 0, int $score = 0): void
{
try {
if ($score) {

View File

@@ -58,6 +58,8 @@ class SaLibs extends TagLib
if (isset($variable[$tags['name']])) {
return $variable[$tags['name']];
}
return '';
}
/**

View File

@@ -18,4 +18,15 @@ class Dictionary extends Validate
'name' => 'require',
'value' => 'require',
];
/**
* 定义错误信息
* 格式:'字段名.规则名' => '错误信息'
*
* @var array
*/
protected $message = [
'name.require' => '字典名称不能为空',
'value.require' => '字典值不能为空',
];
}

View File

@@ -19,9 +19,11 @@ class User extends Validate
* @var array
*/
protected $rule = [
'test_filed' => 'max:255',
'nickname' => 'require|min:2|max:12|filters|chsAlphaNum',
'nickname' => 'require|min:5|max:32|checkName',
'pwd|密码' => 'require|min:6|max:64',
'email' => 'require',
'mobile' => 'require|mobile',
'captcha' => 'require',
];
/**
@@ -32,35 +34,54 @@ class User extends Validate
*/
protected $message = [
'nickname.require' => '用户名不能为空',
'nickname.min' => '用户名不能少于2个字符',
'nickname.max' => '用户名不能超过12个字符',
'nickname.filters' => '用户名包含禁止注册字符',
'nickname.chsAlphaNum' => '用户名只能是汉字、字母和数字',
'test_filed.max' => '测试场景用',
'nickname.min' => '用户名不能少于5个字符',
'nickname.max' => '用户名不能超过32个字符',
'nickname.checkName' => '用户名包含禁止注册字符',
'pwd.require' => '密码不能为空',
'pwd.min' => '密码不能少于6个字符',
'pwd.max' => '密码不能超过64个字符',
'email.require' => '邮箱不能为空',
'mobile.require' => '手机号不能为空',
'mobile.mobile' => '手机号格式不正确',
'captcha.require' => '验证码不能为空',
];
// 测试验证场景
protected $scene = [
'test' => ['test_filed'],
'nickname' => ['nickname'],
'mobile' => ['mobile', 'captcha'],
'login' => ['nickname', 'pwd'],
];
/**
* 自定义验证规则
* @param $value
* @return bool
* @return string|bool
* @throws InvalidArgumentException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
protected function filters($value): bool
protected function checkName($value): string|bool
{
$notAllow = saenv('user_reg_notallow');
$notAllow = explode(',', $notAllow);
if (in_array($value, $notAllow)) {
return false;
return '用户名不合法!';
}
return true;
}
public function sceneRegister(): User
{
return $this->only(['nickname', 'pwd']);
}
public function scenePwd(): User
{
return $this->only(['pwd'])->append('pwd', 'confirm');
}
public function sceneMobile(): User
{
return $this->only(['mobile', 'captcha']);
}
}

View File

@@ -3,11 +3,10 @@
* 全局公共函数库
*/
use app\common\library\Auth;
use app\common\model\system\UserThird;
use think\facade\Cache;
use app\common\model\system\Config;
use think\helper\Str;
use support\Cache;
// 权限常量
const AUTH_CATE = 'cates';
@@ -113,31 +112,6 @@ if (!function_exists('token_field')) {
}
}
if (!function_exists('get_user_id')) {
/**
* 获取会员ID
*/
function get_user_id()
{
return get_user_info('id');
}
}
if (!function_exists('get_user_info')) {
/**
* 获取会员信息
*/
function get_user_info($field = '')
{
$data = Auth::instance()->getUserInfo();
if ($field && isset($data[$field])) {
return $data[$field];
}
return $data;
}
}
if (!function_exists('get_admin_id')) {
/**
* 获取管理员ID
@@ -660,15 +634,11 @@ if (!function_exists('saenv')) {
* @param bool $group
* @return mixed
* @throws \Psr\SimpleCache\InvalidArgumentException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
function saenv(string $name, bool $group = false)
function saenv(string $name, bool $group = false): mixed
{
$redis = 'config_' . $name;
$config = Cache::get($redis);
try {
$configList = Cache::get('config_list') ?? [];
if (is_array($config) ? empty($config) : is_empty($config)) {
@@ -683,52 +653,11 @@ if (!function_exists('saenv')) {
Cache::set('config_list', $configList);
}
}
} catch (\Exception $e) {
}
} catch (\Exception $e) {}
return $config;
}
}
if (!function_exists('system_cache')) {
/**
* 全局缓存控制函数
* @param string $name
* @param mixed $value
* @param null $options
* @param null $tag
* @return mixed
* @throws \Psr\SimpleCache\InvalidArgumentException
*/
function system_cache(string $name = '', mixed $value = '', $options = null, $tag = null)
{
if (is_null($name)) {
return [];
}
if ('' === $value) {
// 获取缓存
return str_starts_with($name, '?') ? Cache::has(substr($name, 1)) : Cache::get($name);
} elseif (is_null($value)) {
// 删除缓存
return Cache::delete($name);
}
// 缓存数据
if (is_array($options)) {
$expire = $options['expire'] ?? null;
} else {
$expire = $options;
}
if (is_null($tag)) {
return Cache::set($name, $value, $expire);
} else {
return Cache::tag($tag)->set($name, $value, $expire);
}
}
}
if (!function_exists('system_reload')) {
/**
* 重载系统
@@ -1096,6 +1025,71 @@ if (!function_exists('request_validate_rules')) {
}
}
if (!function_exists('validate')) {
/**
* 验证数据
* @access protected
* @param $validate
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @param bool $failException
* @return \think\Validate
*/
function validate($validate, array $message = [], bool $batch = false, bool $failException = true): \think\Validate
{
if (is_array($validate) || '' === $validate) {
$v = new \think\Validate();
if (is_array($validate)) {
$v->rule($validate);
}
} else {
if (strpos($validate, '.')) {
// 支持场景
[$validate, $scene] = explode('.', $validate);
}
$class = str_contains($validate, '\\') ? $validate : parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
return $v->message($message)->batch($batch)->failException($failException);
}
}
if (!function_exists('parseClass')) {
/**
* 解析应用类的类名
* @access public
* @param string $layer 层名 controller model ...
* @param string $name 类名
* @return string
*/
function parseClass(string $layer, string $name): string
{
$name = str_replace(['/', '.'], '\\', $name);
$array = explode('\\', $name);
$class = underline_to_hump(array_pop($array));
$path = $array ? implode('\\', $array) . '\\' : '';
return 'app' . '\\' . $layer . '\\' . $path . $class;
}
}
if (!function_exists('underline_to_hump')) {
/**
* 下划线转驼峰
* @param string $value
* @return string
*/
function underline_to_hump(string $value): string
{
$value = ucwords(str_replace(['-', '_'], ' ', $value));
return str_replace(' ', '', $value);
}
}
if (!function_exists('check_user_third')) {
/**
* 获取第三方登录
@@ -1336,7 +1330,7 @@ if (!function_exists('get_plugin_instance')) {
* @param string $class 当前类名
* @return mixed
*/
function get_plugin_instance(string $name, string $class = '')
function get_plugin_instance(string $name, string $class = ''): mixed
{
$object = get_plugin_class($name, $class);
return $object ? new $object : '';
@@ -1370,7 +1364,7 @@ if (!function_exists('get_plugin_list')) {
$list = array_merge($list, $other);
}
return $list ?: [];
return $list ?? [];
}
}
@@ -1434,21 +1428,18 @@ if (!function_exists('set_plugin_config')) {
if (!function_exists('get_plugin_menu_entry')) {
/**
* 获取插件快捷入口
* @param string $type
* @return void
*/
function get_plugin_menu_entry(string $type = 'menu')
function get_plugin_menu_entry(string $type = 'menu'): void
{
$quickEntry = '';
$pluginList = get_plugin_list();
foreach ($pluginList as $item) {
try {
if (!$item['status']) {
continue;
}
$file = plugin_path($item['name']) . 'data/' . $type . '.html';
if (is_file($file)) {
$quickEntry .= file_get_contents($file) . PHP_EOL;
@@ -1457,7 +1448,6 @@ if (!function_exists('get_plugin_menu_entry')) {
continue;
}
}
echo $quickEntry;
}
}
@@ -1469,77 +1459,48 @@ if (!function_exists('plugin_refresh_hooks')) {
*/
function plugin_refresh_hooks(): bool
{
$pluginEvent = [];
$pluginList = get_plugin_list();
$taglib = [];
$events = [];
$routeList = '';
$parseRules = '<?php' . PHP_EOL . 'return [array' . PHP_EOL . '];';
foreach ($pluginList as $item) {
if (!$item['status']) {
continue;
}
// 插件名称
$name = $item['name'];
$rewrite = $item['rewrite'] ?: [];
foreach ($rewrite as $key => $route) {
$parse = explode('/', $route);
$action = end($parse);
array_pop($parse);
$path = implode('\\', $parse);
$controller = 'app\\index\\controller\\' . $path;
if (class_exists($controller) && method_exists($controller, $action)) {
$controller = preg_replace('#//#', '/', $controller);
$routeList .= PHP_EOL . " '$key'=>[$controller::class, '$action'],";
}
}
$namespace = '\\plugin\\' . $name . '\\' . ucfirst($name);
$methods = get_class_methods($namespace);
$diff_hooks = array_diff($methods, get_class_methods("\\app\\PluginController"));
foreach ($diff_hooks as $hook) {
$hookName = $name . '.' . $hook;
$events[$hook][] = [$namespace, $hook];
}
$taglibPath = plugin_path($name . DIRECTORY_SEPARATOR . 'taglib');
$tagList = glob($taglibPath . '*.php');
foreach ($tagList as $index => $tag) {
$tag = pathinfo($tag, PATHINFO_FILENAME);
$taglib[] = 'plugin\\' . $name . '\\taglib\\' . $tag;
$pluginEvent[$hook][] = [$namespace, $hook];
}
}
arr2file(root_path('config') . 'taglib.php', $taglib);
$routePath = root_path('config') . 'defineRoute.php';
write_file($routePath, str_replace('array', $routeList, $parseRules));
$hooks = include/** @lang text */
(root_path('config') . 'event.php');
foreach ($hooks as $key => $item) {
$eventPath = root_path('config') . 'event.php';
$eventOrigin = include /** @lang text */
$eventPath;
foreach ($eventOrigin as $key => $item) {
$separator = explode('.', $key);
if (current($separator) == 'system') {
continue;
}
if (!array_key_exists($key, $events)) {
unset($hooks[$key]);
if (!array_key_exists($key, $pluginEvent)) {
unset($eventOrigin[$key]);
}
}
$eventList = '';
$events = array_merge($hooks, array_diff_key($events, $hooks));
foreach ($events as $key => $event) {
$eventList .= PHP_EOL . " '$key'=> [";
$eventChars = '';
$eventLists = array_merge($eventOrigin, array_diff_key($pluginEvent, $eventOrigin));
foreach ($eventLists as $key => $event) {
$eventChars .= PHP_EOL . " '$key'=> [";
foreach ($event as $value) {
$eventList .= PHP_EOL . " [" . $value[0] . "::class, '" . $value[1] . "']," . PHP_EOL;
$eventChars .= PHP_EOL . " [" . $value[0] . "::class, '" . $value[1] . "']," . PHP_EOL;
}
$eventChars .= ' ],';
}
$eventList .= ' ],';
}
$eventPath = root_path('config') . 'event.php';
write_file($eventPath, str_replace('array', $eventList, $parseRules));
$parseEvents = '<?php' . PHP_EOL . 'return [array' . PHP_EOL . '];';
write_file($eventPath, str_replace('array', $eventChars, $parseEvents));
return system_reload();
}
}

View File

@@ -12,17 +12,8 @@
namespace app\index\controller;
use app\common\library\Email;
use app\common\library\Sms;
use app\common\model\system\User;
use app\HomeController;
use PHPMailer\PHPMailer\Exception;
use Psr\SimpleCache\InvalidArgumentException;
use support\Response;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\response\Json;
/**
* Ajax控制器
@@ -35,86 +26,6 @@ class Ajax extends HomeController
*/
public function index(): Response
{
return \response('Hello SWIFT!', 200);
}
/**
* 发送短信验证码
* @throws DataNotFoundException
* @throws DbException
* @throws InvalidArgumentException
* @throws ModelNotFoundException
*/
public function smsSend()
{
if (request()->isPost()) {
$mobile = input('mobile');
$event = input('event', 'register');
if (!is_mobile($mobile)) {
return $this->error('手机号码不正确');
}
$sms = Sms::instance();
$data = $sms->getLast($mobile);
if ($data && (time() - strtotime($data['create_time'])) < 60) {
return $this->error(__('发送频繁'));
}
$user = User::getByMobile($mobile);
if (in_array($event, ['register', 'changer']) && $user) {
return $this->error('当前手机号已被占用');
} else if ($event == 'forgot' && !$user) {
return $this->error('当前手机号未注册');
}
if ($sms->send($mobile, $event)) {
return $this->success("验证码发送成功!");
} else {
return $this->error($sms->getError());
}
}
}
/**
* 发送邮件验证码
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws Exception
* @throws InvalidArgumentException
*/
public function emailSend()
{
if (request()->isPost()) {
$email = input('email');
$event = input('event', 'register');
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
return $this->error('邮件格式不正确');
}
$Ems = Email::instance();
$data = $Ems->getLast($email);
if ($data && (time() - strtotime($data['create_time'])) < 60) {
return $this->error(__('发送频繁'));
}
$user = User::getByEmail($email);
if (in_array($event, ['register', 'changer']) && $user) {
return $this->error('当前邮箱已被注册');
} else if ($event == 'forgot' && !$user) {
return $this->error('当前邮箱不存在');
}
if ($Ems->captcha($email, $event)->send()) {
return $this->success("验证码发送成功!");
} else {
return $this->error($Ems->getError());
}
}
return \response('Hello swiftadmin!', 200);
}
}

View File

@@ -12,11 +12,8 @@ declare (strict_types=1);
namespace app\index\controller;
use app\HomeController;
use support\Response;
use Psr\SimpleCache\InvalidArgumentException;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use support\Response;
class Index extends HomeController
{
@@ -24,19 +21,9 @@ class Index extends HomeController
* 前端首页
* @return Response
* @throws InvalidArgumentException
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function index(): Response
{
$data = [
'欢迎使用swiftAdmin极速开发框架',
__DIR__.'\Index.php 正在使用halt函数输出到浏览器',
'请在app\index\controller\Index.php中删除halt函数',
];
halt($data);
return $this->view('index/index', ['name' => 'meystack']);
}
}

View File

@@ -12,11 +12,13 @@ declare (strict_types=1);
namespace app\index\controller;
use app\common\library\Auth;
use app\common\library\ResultCode;
use app\common\service\user\UserService;
use app\common\service\user\UserTokenService;
use app\HomeController;
use app\common\model\system\User;
use app\common\model\system\UserThird;
use Psr\SimpleCache\InvalidArgumentException;
use support\Response;
use system\Random;
use think\db\exception\DataNotFoundException;
@@ -87,10 +89,11 @@ class Third extends HomeController
/**
* 用户回调函数
* @return mixed|void
* @return Response
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
* @throws InvalidArgumentException
*/
public function callback()
{
@@ -100,9 +103,9 @@ class Third extends HomeController
return $this->error($e->getMessage());
}
$user = $this->oauth->getUserInfo();
if (!empty($user) && !$this->auth->isLogin()) {
if (!empty($user) && !UserTokenService::isLogin()) {
return $this->register($user, $this->type);
} else if ($this->auth->isLogin()) { // 绑定用户
} else if (UserTokenService::isLogin()) { // 绑定用户
return $this->doBind($user, $this->type);
}
}
@@ -123,31 +126,28 @@ class Third extends HomeController
$userInfo = UserThird::alias('th')->view('user', '*', 'user.id=th.user_id')->where(['openid' => $openid, 'type' => $type])->find();
if (!empty($userInfo)) {
$array['id'] = $userInfo['id'];
$array['login_time'] = time();
$array['login_ip'] = request()->getRealIp();
$array['login_count'] = $userInfo['login_count'] + 1;
if (User::update($array)) {
$response = $this->auth->responseToken($userInfo);
$response->withBody(json_encode(ResultCode::LOGINSUCCESS))->redirect(request()->cookie('redirectUrl', '/'));
if (User::update($array, ['id' => $userInfo['user_id']])) {
UserService::createUserCookies($userInfo);
return redirect(request()->cookie('redirectUrl', '/'));
}
} else {
// 注册本地用户
$data['nickname'] = $nickname;
$data['avatar'] = $info['userData']['avatar'];
$post['nickname'] = $nickname;
$post['avatar'] = $info['userData']['avatar'];
if (User::getByNickname($nickname)) {
$data['nickname'] .= Random::alpha(3);
$post['nickname'] .= Random::alpha(3);
}
$data['group_id'] = 1;
$data['create_ip'] = request()->getRealIp();
$result = $this->auth->register($data);
$post['group_id'] = 1;
$post['create_ip'] = request()->getRealIp();
$result = UserService::register($post);
// 封装第三方数据
if (!empty($result)) {
$userThird = [
$third = [
'type' => $this->type,
'user_id' => $result['id'],
'openid' => $openid,
@@ -158,13 +158,10 @@ class Third extends HomeController
'login_time' => time(),
'expiretime' => time() + $info['expires_in'],
];
}
// 注册第三方数据
if (isset($userThird) && is_array($userThird)) {
if (UserThird::create($userThird)) {
$response = $this->auth->responseToken($result);
$response->withBody(json_encode(ResultCode::LOGINSUCCESS))->redirect(request()->cookie('redirectUrl', '/'));
if (UserThird::create($third)) {
UserService::createUserCookies($result);
return redirect(request()->cookie('redirectUrl', '/'));
}
}
}
@@ -175,10 +172,11 @@ class Third extends HomeController
/**
* 用户绑定操作
* @return Response
* @throws InvalidArgumentException
*/
public function bind(): Response
{
if (Auth::instance()->isLogin()) {
if (UserTokenService::isLogin()) {
$buildQuery = [
'bind' => true,
'type' => input('type'),
@@ -193,7 +191,9 @@ class Third extends HomeController
/**
* 用户解除绑定
* @return Response
* @throws DbException
* @throws InvalidArgumentException
*/
public function unbind(): Response
{
@@ -202,9 +202,8 @@ class Third extends HomeController
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
if ($this->auth->isLogin()) {
$result = $this->auth->userInfo;
$result = UserTokenService::isLogin();
if (!empty($result)) {
if (empty($result['email']) || empty($result['pwd'])) {
@@ -217,7 +216,7 @@ class Third extends HomeController
return $this->success('解除绑定成功!');
}
}
}
return $this->error();
}
@@ -233,10 +232,8 @@ class Third extends HomeController
*/
protected function doBind(array $info = [], string $type = null)
{
$openid = $info['openid'] ?? $info['id'];
$nickname = $info['userData']['name'] ?? $info['userData']['nickname'];
// 查询是否被注册
$where['openid'] = $openid;
$where['type'] = $this->type;

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,9 @@
namespace app\index\middleware\system;
use app\common\library\Auth;
use app\common\library\ResultCode;
use app\common\service\user\UserTokenService;
use Psr\SimpleCache\InvalidArgumentException;
use support\View;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
@@ -32,22 +33,23 @@ class IndexPermissions implements MiddlewareInterface
* 非鉴权方法
* @var array
*/
public array $noNeedAuth = [];
public array $noNeedLogin = [];
/**
* 跳转URL地址
* @var string
*/
public string $JumpUrl = '/index/user/index';
public string $JumpUrl = '/index/';
/**
* 校验权限
* @param Request $request
* @param \support\Request|Request $request
* @param callable $handler
* @return Response
* @throws InvalidArgumentException
* @throws \ReflectionException
*/
public function process(Request $request, callable $handler): Response
public function process(\support\Request|Request $request, callable $handler): Response
{
$app = request()->getApp();
$controller = request()->getController();
@@ -56,23 +58,23 @@ class IndexPermissions implements MiddlewareInterface
$refClass = new \ReflectionClass($request->controller);
$property = $refClass->getDefaultProperties();
$this->needLogin = $property['needLogin'] ?? false;
$this->noNeedAuth = $property['noNeedAuth'] ?? $this->noNeedAuth;
$this->noNeedLogin = $property['noNeedLogin'] ?? $this->noNeedLogin;
$this->repeatLogin = $property['repeatLogin'] ?? $this->repeatLogin;
$this->JumpUrl = $property['JumpUrl'] ?? $this->JumpUrl;
// 是否验证登录器
$auth = Auth::instance();
if ($auth->isLogin()) {
// 禁止重复登录
$userInfo = UserTokenService::isLogin();
if (!empty($userInfo)) {
if (in_array($action, $this->repeatLogin)) {
var_dump($this->JumpUrl);
return redirect($this->JumpUrl);
}
View::assign('user', $auth->userInfo);
$request->userId = $userInfo['id'];
$request->userInfo = $userInfo;
View::assign('user', $userInfo);
} else {
if ($this->needLogin && !in_array($action, $this->noNeedAuth)) {
if ($this->needLogin && !in_array($action, $this->noNeedLogin)) {
if (\request()->isAjax()) {
return json(ResultCode::PLEASELOGININ);
} else {

View File

@@ -7,7 +7,6 @@
<link rel="stylesheet" href="/static/js/layui/css/layui.css">
<link rel="stylesheet" href="/static/css/style.css?v={:release()}">
<script src="/static/js/layui/layui.js"></script>
<script src="/static/js/common.js?v={:release()}"></script>
<!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>

View File

@@ -14,8 +14,30 @@
<div class="layui-nav layui-hide-xs fr" id="login">
<notempty name="$user.id"> <li class="layui-nav-item"><a class="" href="/index/user/index" >会员中心</a></li> <else/>
<li class="layui-nav-item"><a href="javascript:;" lay-open data-title="用户注册" data-area="490px" data-url="/index/user/register" >注册</a></li>
<li class="layui-nav-item"><a href="javascript:;" lay-open data-title="用户登录" data-area="450px,420px" data-url="/index/user/login" >登录</a></li>
<li class="layui-nav-item"><a href="/index/user/register" target="_blank">注册</a></li>
<li class="layui-nav-item"><a href="/index/user/login" target="_blank">登录</a></li>
<li class="layui-nav-item"><a id="ajaxLogin" href="javascript:;" lay-open data-title="用户登录" data-area="450px,420px" data-url="/index/user/ajaxLogin" >Ajax登录</a></li>
</notempty>
</div>
</div>
<script >
layui.use([], function(e) {
var $ = layui.jquery;
var layer = layui.layer;
//监听导航点击
$('#ajaxLogin').on('click', function() {
var url = $(this).attr('data-url');
var title = $(this).attr('data-title');
var area = $(this).attr('data-area');
layer.open({
type: 2,
title: title,
area: ['450px','420px'],
shadeClose: true, //点击遮罩关闭
content: url
});
});
})
</script>

View File

@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>{$site_name} 用户登录</title>
<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<meta name="applicable-device" content="pc,mobile">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<script src="/static/js/layui/layui.js"></script>
<link rel="stylesheet" type="text/css" href="/static/js/layui/css/font-awesome.css" />
<link rel="stylesheet" type="text/css" href="/static/js/layui/css/layui.css" />
<link rel="stylesheet" type="text/css" href="/static/css/login.css" />
<script src="/static/js/center.js?v={:release()}"></script>
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"/>
</head>
<body>
<div id="ajaxLogin" >
<div class="other-link">
<span class="other">第三方账号登录:</span>
<span>
<a href="{:url('/third/login',['type'=>'qq'])}&ref={$referer}" class="qq" target="_top"></a>
<a href="{:url('/third/login',['type'=>'weixin'])}&ref={$referer}" class="wx" target="_top"></a>
<a href="{:url('/third/login',['type'=>'weibo'])}&ref={$referer}" class="sina" target="_top"></a>
</span>
</div>
<form class="layui-form" action="/index/user/login" method="post" style="height: auto">
<input type="hidden" name="__token__" value="{:token()}"/>
<div class="layui-form-item">
<div class="item">
<label class="left-icon layui-icon layui-icon-username"></label>
<input type="text" id="nickname" name="nickname" lay-verify="required" placeholder="{:__('请输入账号或邮箱')}" class="layui-input" value="test@swiftadmin.net">
</div>
</div>
<div class="layui-form-item">
<div class="item">
<label class="left-icon layui-icon layui-icon-password"></label>
<input type="password" id="pwd" name="pwd" lay-verify="required" placeholder="{:__('密码')}" class="layui-input" value="admin888">
</div>
</div>
<div class="layui-form-item" style="margin-bottom: 20px;">
<div class="fl">
<input type="checkbox" name="remember" lay-skin="primary" title="{:__('记住密码')}" checked>
</div>
<a lay-open data-title="找回密码" data-area="500px,320px" data-object="top" data-url="/index/user/forgot"
class="forgot-link fr" style="margin-top: 7px;">{:__('忘记密码?')}</a>
</div>
<div class="layui-form-item">
<input type="submit" value="{:__('立即登录')}" lay-submit="" lay-filter="submitIframe" data-reload="top"
class="layui-btn layui-btn-login layui-btn-fluid layui-btn-normal">
</div>
</form>
</div>
</body>
</html>

View File

@@ -74,7 +74,7 @@
<div class="contract-title">手机</div>
<div class="contract-detail">+86 {$user.mobile|default='未绑定'}
<i class="layui-icon fa-edit" title="编辑" lay-open data-title="修改手机"
data-url="/index/user/mobile" data-area="500px,300px"></i>
data-url="/index/user/changeMobile" data-area="500px,300px"></i>
</div>
</div>
@@ -87,7 +87,7 @@
<div class="contract-title">办公室邮箱</div>
<div class="contract-detail">{$user.email|default='member@domain.com'}
<i class="layui-icon fa-edit" title="编辑" lay-open data-title="修改邮箱"
data-url="/index/user/email" data-area="500px,300px"></i>
data-url="/index/user/changeEmail" data-area="500px,300px"></i>
</div>
</div>
<div class="layui-col-md3">
@@ -242,7 +242,7 @@
<li>
<a title="{$vo.nickname}" href="#" target="_blank">
<img class="media-object" src="{$vo.avatar}"></a>
<a class="truncate" href="{$vo.url}" target="_blank">{$vo.nickname}</a>
<a class="truncate" href="{$vo.url|default='#'}" target="_blank">{$vo.nickname}</a>
</li>
</volist>
</ul>

View File

@@ -1,79 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>修改密码</title>
<include file="user:include"/>
</head>
<body>
<div class="layui-card-body">
<form action="/index/user/changePwd" class="layui-form layui-form-fixed">
<input type="text" name="nickname" value="{$user.nickname}" hidden="">
<div class="layui-form-item">
<label class="layui-form-label">原密码</label>
<div class="layui-input-block">
<input type="password" id="oldpwd" name="oldpwd" class="layui-input" >
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">新密码</label>
<div class="layui-input-block">
<input type="password" id="pwd" name="pwd" class="layui-input" >
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">确认密码</label>
<div class="layui-input-block">
<input type="password" id="repwd" name="repwd" class="layui-input" >
</div>
</div>
<div class="layui-form-item" style="margin-top: 22px;text-align: center;">
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
<button type="submit" class="layui-btn layui-btn-normal" lay-submit="" lay-filter="submit">立即提交</button>
</div>
</form>
</div>
<script>
layui.use(['jquery','form'],function(){
let $ = layui.jquery;
let form = layui.form;
//监听提交
form.on('submit(submit)', function(data){
if($("#pwd").val().length < 6){
layer.tips('请至少输入6个字符作为密码',"#pwd",{'tips':3});
return false;
}
if ($("#pwd").val() !== $("#repwd").val()) {
layer.tips('两次输入的密码不一样!',"#repwd",{'tips':3});
return false;
}
$.ajax({
url: $(this).attr('action'),
type: 'POST',
dataType: 'json',
timeout: 6000,
data: data.field,
success: function(res){
if (res.code === 200) {
top.layer.msg(res.msg);
}
else {
top.layer.msg(res.msg,'error');
}
}
});
return false;
});
})
</script>
</body>
</html>

View File

@@ -1,32 +0,0 @@
<layout name="layout:layout"/>
<!-- 内容主体区域 -->
<div id="content">
<div class="layui-fluid ">
<form class="layui-form layui-form-fixed" action="/index/user/email">
<div class="layui-form-item">
<label class="layui-form-label">{:__('邮箱地址')}</label>
<div class="layui-input-inline" style="width: 265px">
<input name="email" placeholder="{:__('请输入邮箱地址')}" type="text" class="layui-input email"
autocomplete="off" lay-verify="required|email"/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">{:__('验证码')}</label>
<div class="layui-input-inline">
<input name="captcha" placeholder="{:__('请输入验证码')}" type="text" class="layui-input"
autocomplete="off" lay-verify="required" maxlength="10"/>
</div>
<button class="layui-btn layui-btn-normal layui-btn-sm" type="button" lay-ajax data-url="/index/user/email"
data-object="email:email,event:event">{:__('获取')}
</button>
</div>
<input type="text" hidden name="event" class="event" value="change">
<div class="layui-footer layui-form-item layui-center">
<button class="layui-btn layui-btn-primary" type="button" sa-event="closeDialog">{:__('取消')}</button>
<button class="layui-btn layui-btn-normal" data-reload="parent" lay-filter="submitIframe" lay-submit>{:__('提交')}</button>
</div>
</form>
</div>
</div>

View File

@@ -1,57 +1,45 @@
<!DOCTYPE html>
<html lang="zh-CN">
<html>
<head>
<meta charset="UTF-8">
<title>SwiftAdmin 用户登录</title>
<include file="public:header"/>
<title>{$site_name} 找回密码</title>
<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<meta name="applicable-device" content="pc,mobile">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<script src="/static/js/layui/layui.js"></script>
<link rel="stylesheet" type="text/css" href="/static/js/layui/css/font-awesome.css" />
<link rel="stylesheet" type="text/css" href="/static/js/layui/css/layui.css" />
<link rel="stylesheet" type="text/css" href="/static/css/login.css" />
<script src="/static/js/center.js?v={:release()}"></script>
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"/>
</head>
<body>
<style>
.layui-form-checked[lay-skin="primary"] i {
border-color: #1890ff !important;
background-color: #1890ff;
color: #fff;
}
.layui-form-item {
margin-bottom: 25px;
}
.red {
color: red;
}
.layui-input:hover {
border: 1px solid #1890ff!important;
}
</style>
<div class="layui-fluid">
<form class="layui-form layui-form-fixed" action="/index/user/forgot" method="post">
<input type="hidden" name="__token__" value="{:token()}"/>
<div class="layui-form-item">
<label class="layui-form-label"><span class="red">*</span> {:__('手机/邮箱')}</label>
<div class="layui-input-inline" style="width: 306px">
<input id="string" name="mobile" placeholder="{:__('请输入邮箱或手机号')}" type="text" class="layui-input string"
autocomplete="off" lay-verify="required"/>
<input id="name" name="name" placeholder="{:__('请输入邮箱或手机号')}" type="text" class="layui-input"
lay-verify="required"/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><span class="red">*</span> {:__('验证码')}</label>
<div class="layui-input-inline">
<input name="captcha" placeholder="{:__('请输入验证码')}" type="text" class="layui-input" autocomplete="off" lay-verify="required" maxlength="10"/>
<div class="layui-input-inline" style="width: 226px">
<input name="captcha" placeholder="{:__('请输入验证码')}" type="text" class="layui-input"
autocomplete="off" lay-verify="required" maxlength="10"/>
</div>
<button id="send" class="layui-btn layui-btn-normal" type="button"
lay-ajax data-url="/ajax/smsSend" data-object="mobile:string,event:event">{:__('获取')}
<button id="uCode" class="layui-btn layui-btn-normal" type="button">{:__('获取')}
</button>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><span class="red">*</span> {:__('新密码')}</label>
<div class="layui-input-inline" style="width: 306px">
<input type="password" id="pwd" name="pwd" lay-verify="required" placeholder="{:__('密码')}" class="layui-input" >
<input type="password" id="pwd" name="pwd" lay-verify="required" placeholder="{:__('密码')}"
class="layui-input">
</div>
</div>
<input type="text" hidden name="event" class="event" value="forgot">
<div class="layui-footer layui-form-item layui-center">
<button class="layui-btn layui-btn-primary" type="button" sa-event="closeDialog">{:__('取消')}</button>
<button class="layui-btn layui-btn-normal" lay-filter="submitIframe" lay-submit>{:__('提交')}</button>
@@ -63,24 +51,39 @@
layui.use('jquery', function () {
let $ = layui.jquery;
$('#string').on('keyup',function (e) {
let val = $(this).val();
let string = $('#string');
let send = $('#send');
let regx = /^[1][3,4,5,6.7,8,9][0-9]{9}$/
if (regx.test(val)) {
string.attr('name','mobile');
send.attr('data-object','mobile:string,event:event');
send.attr('data-url','/ajax/smsSend');
} else {
string.attr('name','email');
send.attr('data-object','email:string,event:event');
send.attr('data-url','/ajax/emailsend');
$('#uCode').click(function (e) {
let name = $('#name').val();
if (name === '') {
layer.msg('请输入邮箱或手机号', 'info');
return false;
}
})
let regUrl = '/api/ajax/smsSend';
let data = { mobile: name };
let regxEmail = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/;
if (regxEmail.test(name)) {
regUrl = '/api/ajax/emailSend';
data = { email: name };
}
data.event = 'forgot';
$(this).attr('disabled', true);
$.ajax({
url: regUrl,
type: 'post',
data: data,
dataType: 'json',
success: function (res) {
if (res.code === 200) {
layer.msg(res.msg, 'success');
} else {
layer.msg(res.msg, 'error');
}
}
});
setTimeout(function () {
$('#uCode').attr('disabled', false);
}, 10000);
});
})
</script>
</html>

View File

@@ -1,40 +0,0 @@
<div class="layui-header">
<div class="layui-logo layui-hide-xs layui-bg-black">
<span class="logo-text">SAPHP <span style="font-size: medium ">用户后台</span></span>
</div>
<!-- 头部区域可配合layui 已有的水平导航) -->
<ul class="layui-nav layui-layout-left">
<!-- 移动端显示 -->
<li class="layui-nav-item layui-show-xs-inline-block" lay-header-event="menuLeft">
<i class="layui-icon layui-icon-spread-left"></i>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item" lay-unselect="">
<a href="{$site_http}" lay-text="主页">
<i class="layui-icon layui-icon-website"></i>
</a>
</li>
<li class="layui-nav-item" lay-unselect="">
<a href="javascript:;" sa-event="message" lay-text="消息中心" data-url="/admin.php/system.admin/message">
<i class="layui-icon fa-bell-o"></i>
<!-- 如果有新消息,则显示小圆点 -->
<span class="layui-badge-dot"></span>
</a>
</li>
<li class="layui-nav-item layui-hide layui-show-md-inline-block">
<a href="javascript:;"><img src="{$user.avatar}" alt="{$user.nickname}" class="layui-nav-img">{$user.nickname}</a>
<dl class="layui-nav-child">
<dd><a lay-open lay-title="修改密码" lay-url="/index/user/changepwd" lay-area="470px,330px" href="javascript:;">修改密码</a>
</dd>
<dd><a href="/index/user/logout" >退出</a></dd>
</dl>
</li>
<li class="layui-nav-item" lay-header-event="menuRight" lay-unselect>
<a href="javascript:;"><i class="layui-icon layui-icon-more-vertical"></i></a>
</li>
</ul>
</div>

View File

@@ -9,7 +9,7 @@
<link href="/static/js/layui/css/font-awesome.css?v={:config('app.version')}" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="/static/css/center.css?v={:release()}">
<script src="/static/js/layui/layui.js"></script>
<script src="/static/js/common.js?v={:release()}"></script>
<script src="/static/js/center.js?v={:release()}"></script>
<!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>

View File

@@ -1,62 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>SwiftAdmin 用户登录</title>
<include file="public:header"/>
</head>
<body>
<style>
.layui-form-checked[lay-skin="primary"] i {
border-color: #1890ff !important;
background-color: #1890ff;
color: #fff;
}
.forget-link {
margin-top: 7px;
color: #1890ff;
}
</style>
<div id="userLogin" class="layui-fluid">
<div class="login-link">
<span class="other">第三方账号登录:</span>
<span>
<a href="{:url('/third/login',['type'=>'qq'])}&ref={$referer}" class="qq" target="_top"></a>
<a href="{:url('/third/login',['type'=>'weixin'])}&ref={$referer}" class="wx" target="_top"></a>
<a href="{:url('/third/login',['type'=>'weibo'])}&ref={$referer}" class="sina" target="_top"></a>
</span>
</div>
<form class="layui-form" action="/index/user/login" method="post" style="height: auto">
<input type="hidden" name="__token__" value="{:token()}"/>
<div class="layui-form-item">
<div class="item">
<label class="user-login-icon layui-icon layui-icon-username"></label>
<input type="text" id="nickname" name="nickname" lay-verify="required|email"
placeholder="{:__('请输入邮箱或手机号')}" class="layui-input" value="test@swiftadmin.net">
</div>
</div>
<div class="layui-form-item">
<div class="item">
<label class="user-login-icon layui-icon layui-icon-password"></label>
<input type="password" id="pwd" name="pwd" lay-verify="required" placeholder="{:__('密码')}"
class="layui-input" value="admin888">
</div>
</div>
<div class="layui-form-item" style="margin-bottom: 20px;">
<div class="fl">
<input type="checkbox" name="remember" lay-skin="primary" title="{:__('记住密码')}" checked>
</div>
<a lay-open data-title="找回密码" data-area="510px,360px" data-object="top" data-url="/index/user/forgot" class="forget-link fr" style="margin-top: 7px;">{:__('忘记密码?')}</a>
</div>
<div class="layui-form-item">
<input type="submit" value="{:__('立即登录')}" lay-submit="" lay-filter="submitIframe" data-reload="top"
class="layui-btn layui-btn-fluid layui-btn-normal">
</div>
</form>
</div>
</body>
</html>

View File

@@ -19,7 +19,7 @@
*/
var isTable = table.render({
elem: "#lay-tableList"
, url: "{:url('/user/login_log')}"
, url: "{:url('/user/loginLog')}"
, page: true
, limit: 20
, cols: [[

View File

@@ -17,8 +17,8 @@
<button class="layui-btn layui-btn-normal layui-btn-sm layui-btn-post" data-status="all" >{:__('全部消息')}</button>
<button class="layui-btn layui-btn-primary layui-btn-sm layui-btn-post" data-status="1">{:__('已读消息')}</button>
<button class="layui-btn layui-btn-primary layui-btn-sm layui-btn-post" data-status="0">{:__('未读消息')}</button>
<button class="layui-btn layui-btn-danger layui-btn-sm" lay-batch data-table="lay-tableList" data-url="/index/user/dermessage?type=del" >{:__('删除消息')}</button>
<button class="layui-btn layui-btn-checked layui-btn-sm" lay-batch data-table="lay-tableList" data-url="/index/user/dermessage?type=read" >{:__('标记已读')}</button>
<button class="layui-btn layui-btn-danger layui-btn-sm" lay-batch data-table="lay-tableList" data-url="/index/user/batchMessage?type=del" >{:__('删除消息')}</button>
<button class="layui-btn layui-btn-checked layui-btn-sm" lay-batch data-table="lay-tableList" data-url="/index/user/batchMessage?type=read" >{:__('标记已读')}</button>
</div>
</div>
</div>
@@ -45,14 +45,14 @@
, page: true
, limit: 20
, cols: [[
{type: 'checkbox', width: 45},
{type: 'checkbox', width: 60},
{
field: 'title', align: 'left', templet: function (e) {
let title = '<a class="layui-table-text';
if (e.status === 0) {
title += ' layui-table-text-red';
}
title += '" lay-open data-title="查看消息" data-url="/index/user/viewmessage?id=' + e.id + '" data-area="600px, 390px" >';
title += '" lay-open data-title="查看消息" data-url="/index/user/viewMessage?id=' + e.id + '" data-area="600px, 390px" >';
if (e.status === 0) {
title += '<i class="layui-icon fa-envelope"></i> ';
} else {

View File

@@ -1,30 +0,0 @@
<layout name="layout:layout"/>
<!-- 内容主体区域 -->
<div id="content">
<div class="layui-fluid">
<form class="layui-form layui-form-fixed" action="/index/user/mobile">
<div class="layui-form-item">
<label class="layui-form-label">{:__('手机号')}</label>
<div class="layui-input-inline" style="width: 265px">
<input name="mobile" placeholder="{:__('请输入号码')}" type="text" class="layui-input mobile"
autocomplete="off" lay-verify="required|phone"/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">{:__('验证码')}</label>
<div class="layui-input-inline">
<input name="captcha" placeholder="{:__('请输入验证码')}" type="text" class="layui-input"
autocomplete="off" lay-verify="required" maxlength="10"/>
</div>
<button class="layui-btn layui-btn-normal layui-btn-sm" type="button" lay-ajax data-url="/index/user/mobile"
data-object="mobile:mobile,event:event">{:__('获取')}
</button>
</div>
<input type="text" hidden name="event" class="event" value="change">
<div class="layui-footer layui-form-item layui-center">
<button class="layui-btn layui-btn-primary" type="button" sa-event="closeDialog">{:__('取消')}</button>
<button class="layui-btn layui-btn-normal" data-reload="parent" lay-filter="submitIframe" lay-submit>{:__('提交')}</button>
</div>
</form>
</div>
</div>

View File

@@ -1,35 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>消息管理 | {$site_name}</title>
<include file="user:include" />
</head>
<body>
<div class="layui-layout layui-layout-admin">
<include file="user:header" />
<div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<!-- 左侧导航区域可配合layui已有的垂直导航 -->
<include file="user:userNav" />
</div>
</div>
<div class="layui-body">
<!-- 内容主体区域 -->
<div id="content">
<h1>消息 示例页面</h1>
</div>
</div>
<include file="user:footer"/>
</div>
</body>
</html>
</body>
</html>

View File

@@ -2,85 +2,125 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SwiftAdmin 用户注册</title>
<include file="public:header"/>
<title>{$site_name} 用户注册</title>
<meta http-equiv="Cache-Control" content="no-transform"/>
<meta http-equiv="Cache-Control" content="no-siteapp"/>
<meta name="applicable-device" content="pc,mobile">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<script src="/static/js/layui/layui.js"></script>
<link rel="stylesheet" type="text/css" href="/static/js/layui/css/font-awesome.css"/>
<link rel="stylesheet" type="text/css" href="/static/js/layui/css/layui.css"/>
<link rel="stylesheet" type="text/css" href="/static/css/login.css"/>
<script src="/static/js/center.js?v={:release()}"></script>
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"/>
</head>
<body>
<style>
<div id="content" class="userLogin layui-fluid">
.layui-form-item {
margin-bottom: 15px;
}
<div class="form-header">
<i class="layui-icon fa-user-plus"></i>
<h6>用户注册</h6>
</div>
<div class="formLogin active">
.red {
color: red;
}
.layui-input:hover {
border: 1px solid #1890ff !important;
}
</style>
<div id="register" class="layui-fluid">
<form class="layui-form layui-form-fixed" action="/index/user/register" method="post">
<div class="layui-form-item">
<label class="layui-form-label"><span class="red">*</span> 用户帐号</label>
<div class="layui-input-block">
<input type="text" name="nickname" placeholder="请输入帐号" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><span class="red">*</span> 密码</label>
<div class="layui-input-block">
<input type="password" id="pwd" name="pwd" placeholder="请输入密码" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><span class="red">*</span> 确认密码</label>
<div class="layui-input-block">
<input type="password" id="repwd" name="repwd" placeholder="请输入确认密码" class="layui-input">
<form class="layui-form mobileLogin" action="/index/user/register" method="post">
<div class="layui-form-item item-input">
<input type="text" id="nickname" name="nickname" lay-verify="required" data-title="账号"
placeholder="{:__('请输入登录账号')}" class="inputStyle" value="">
</div>
<div class="layui-form-item item-input">
<input type="password" id="pwd" name="pwd" lay-verify="required" data-title="密码" maxlength="32"
placeholder="{:__('请输入密码')}" class="inputStyle" value="">
<span class="fr-icon visiblePwd"><i class="layui-icon fa-eye-slash"></i></span>
</div>
<div class="layui-form-item item-input">
<input type="password" id="pwd2" lay-verify="required" data-title="密码" maxlength="32"
placeholder="{:__('请输入确认密码')}" class="inputStyle" value="">
<span class="fr-icon visiblePwd"><i class="layui-icon fa-eye-slash"></i></span>
</div>
<eq name="style" value="mobile">
<div class="layui-form-item">
<label class="layui-form-label"><span class="red">*</span> 手机号</label>
<div class="layui-input-block">
<input type="text" id="mobile" name="mobile" placeholder="请输入手机号" lay-verify="require|phone"
class="layui-input mobile">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"><span class="red">*</span> 验证码</label>
<div class="layui-input-block">
<input type="text" name="captcha" placeholder="{:__('验证码')}" class="layui-input captcha">
<div class="captcha fr">
<button id="captcha" type="button" class="layui-btn layui-btn-normal"
lay-ajax data-url="/ajax/smsSend" data-object="mobile:mobile,event:event"
>获取验证码
</button>
</div>
<div class="layui-form-item item-input">
<input type="text" id="mobile" name="mobile" lay-verify="required" data-title="手机号"
placeholder="{:__('请输入手机号码')}" class="inputStyle mobile" value="">
</div>
<div class="layui-form-item item-input">
<input type="text" id="captcha" name="captcha" lay-verify="required" data-title="验证码"
maxlength="6"
placeholder="{:__('短信验证码')}" class="inputStyle" value="">
<input type="text" hidden name="event" class="event" value="login">
<span class="fr-icon getCaptcha" lay-ajax data-url="/api/ajax/smsSend"
data-object="mobile:mobile,event:event">获取验证码</span>
</div>
<else/>
<div class="layui-form-item">
<label class="layui-form-label"><span class="red">*</span> 邮箱地址</label>
<div class="layui-input-block">
<input type="text" name="email" lay-verify="require|email" placeholder="请输入邮箱" class="layui-input">
</div>
<div class="layui-form-item item-input">
<input type="text" name="email" lay-verify="require|email" placeholder="请输入邮箱" class="inputStyle">
</div>
</eq>
<input type="text" hidden name="event" class="event" value="register">
<div class="layui-footer layui-form-item layui-center">
<button class="layui-btn layui-btn-primary" type="button" sa-event="closeDialog">{:__('取消')}</button>
<button class="layui-btn layui-btn-normal" lay-filter="submitIframe" data-reload="top" lay-submit>
{:__('立即注册')}
</button>
<input type="hidden" id="token" name="__token__" value="{:token()}"/>
<div class="layui-form-item">
<div class="fl">
<input type="checkbox" name="remember" lay-skin="primary" title="{:__('记住密码')}" checked>
</div>
<div class="fr">
<a href="/index/user/login" class="forgot-link" style="margin-top: 7px;">{:__('返回登录')}</a>
</div>
</div>
<div class="layui-form-item">
<button class="layui-btn layui-btn-login layui-btn-fluid layui-btn-normal"
lay-filter="submitIframe" data-reload="top" lay-submit>{:__('立即注册')}</button>
</div>
<div class="agreement">
<span>未注册手机验证后自动登录,注册即代表同意<a href="#">《用户协议》</a>以及网站<a href="#">《隐私保护指引》</a></span>
</div>
</form>
</div>
<div class="loginLine"></div>
<div class="appUserDown">
<div class="fr">
<a class="link" href="#" target="_top">
<span>
<i class="layui-icon fa-apple"></i>
<i class="layui-icon fa-android"></i>
<i class="layui-icon fa-windows"></i>
<span class="tit">下载 APP</span>
</span>
</a>
</div>
</div>
</div>
</body>
<script>
layui.use(['jquery'], function (e) {
let $ = layui.jquery;
let layer = layui.layer;
$('#pwd, #pwd2').blur(function(e) {
let v1 = $('#pwd').val();
let v2 = $('#pwd2').val();
let v3 = v1 && v2 && (v1 !== v2);
v3 && layer.msg('密码不相同');
$('.layui-btn-login').attr('disabled', v3);
})
/* 显示隐藏密码 */
$('.visiblePwd').click(function() {
// 获取我同级上面得input元素
let elem = $(this).prev('input');
let type = $(elem).attr('type');
if (type === 'password') {
$(elem).attr('type','text');
$(this).find('i.layui-icon').addClass('fa-eye').removeClass('fa-eye-slash');
} else {
$(elem).attr('type','password');
$(this).find('i.layui-icon').addClass('fa-eye-slash').removeClass('fa-eye');
}
});
});
</script>
</html>

View File

@@ -60,7 +60,7 @@
<span class="setting-intro">安全性高的密码可以使账户更安全;互联网账号存在被盗风险,建议您定期更换密码</span>
</div>
<div class="setting-operate fr">
<a lay-open="" data-title="修改密码" data-url="/index/user/changepwd" data-area="470px,330px" href="javascript:;">修改</a>
<a lay-open="" data-title="修改密码" data-url="/index/user/changePwd" data-area="470px,330px" href="javascript:;">修改</a>
</div>
</div>
@@ -84,7 +84,7 @@
</div>
<div class="setting-operate fr">
<a lay-open data-title="修改手机" data-url="/index/user/mobile" data-area="500px,300px">修改</a>
<a lay-open data-title="修改手机" data-url="/index/user/changeMobile" data-area="500px,300px">修改</a>
</div>
</div>
@@ -108,7 +108,7 @@
</div>
<div class="setting-operate fr">
<a lay-open data-title="修改邮箱" data-url="/index/user/email" data-area="500px,300px">修改</a>
<a lay-open data-title="修改邮箱" data-url="/index/user/changeEmail" data-area="500px,300px">修改</a>
</div>
</div>

View File

@@ -15,7 +15,7 @@
<dl class="layui-nav-child">
<dd><a lay-href="/index/user/profile">我的资料</a></dd>
<dd><a lay-href="/index/user/message">站内消息</a></dd>
<dd><a lay-href="/index/user/login_log">登录日志</a></dd>
<dd><a lay-href="/index/user/loginLog">登录日志</a></dd>
<dd><a lay-href="/index/user/certification">实名认证</a></dd>
<dd><a lay-href="/index/user/security">安全中心</a></dd>
</dl>

View File

@@ -3,8 +3,7 @@ declare (strict_types=1);
namespace app\install\controller;
use app\common\library\DataBase;
use think\facade\Cache;
use support\Cache;
use app\BaseController;
const SUCCESS = 'layui-icon-ok-circle';
@@ -36,7 +35,7 @@ class Index extends BaseController
// 检测生产环境
foreach ($this->checkEnv() as $key => $value) {
if ($key == 'php' && (float)$value < 8.0.0) {
if ($key == 'php' && (float)$value < 8.0) {
return $this->error('PHP版本过低');
}
}

View File

@@ -11,7 +11,7 @@
Target Server Version : 50738
File Encoding : 65001
Date: 25/04/2023 20:00:37
Date: 19/06/2023 14:24:08
*/
SET NAMES utf8mb4;
@@ -49,15 +49,15 @@ CREATE TABLE `__PREFIX__admin` (
`delete_time` int(11) NULL DEFAULT NULL COMMENT '软删除标识',
PRIMARY KEY (`id`) USING BTREE,
INDEX `id`(`id`) USING BTREE,
UNIQUE INDEX `name`(`name`) USING BTREE,
INDEX `name`(`name`) USING BTREE,
INDEX `pwd`(`pwd`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '后台管理员表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of __PREFIX__admin
-- ----------------------------
INSERT INTO `__PREFIX__admin` VALUES (1, '1', '2', '3', 'admin', '超级管理员', '13682bec405cf4b9002e6e8306312ce6', 1, 'a:3:{i:0;s:12:\"测试效果\";i:1;s:15:\"隔壁帅小伙\";i:2;s:9:\"技术宅\";}', '/upload/avatars/f8e34ec67a2a0233_100x100.jpg', '海阔天空,有容乃大', 'admin@swiftadmin.net', '0310', '15188888888', '高级管理人员', 391, '河北省邯郸市', '127.0.0.1', 1682411837, '3232254977', 1, NULL, 1596682835, 1682411837, NULL);
INSERT INTO `__PREFIX__admin` VALUES (2, '2', '4', '5,6', 'ceshi', '测试用户', '13682bec405cf4b9002e6e8306312ce6', 1, 'a:3:{i:0;s:6:\"呵呵\";i:1;s:5:\"Think\";i:2;s:12:\"铁血柔肠\";}', '/upload/avatars/a0b923820dcc509a_100x100.png', 'PHP是全世界最好的语言', 'baimei@your.com', '0310', '15188888888', '我原本以为吕布已经天下无敌了,没想到还有比吕布勇猛的,这谁的部将?', 57, '河北省邯郸市廉颇大道110号指挥中心', '127.0.0.1', 1682221728, '3232254977', 1, '违规', 1609836672, 1682221728, NULL);
INSERT INTO `__PREFIX__admin` VALUES (1, '1,2', '2', '3', 'admin', '超级管理员', '13682bec405cf4b9002e6e8306312ce6', 1, 'a:3:{i:0;s:12:\"测试效果\";i:1;s:15:\"隔壁帅小伙\";i:2;s:9:\"技术宅\";}', '/upload/avatars/f8e34ec67a2a0233_100x100.jpg', '海阔天空,有容乃大', 'admin@swiftadmin.net', '0310', '15188888888', '高级管理人员', 402, '河北省邯郸市', '127.0.0.1', 1687154816, '3232254977', 1, NULL, 1596682835, 1687154816, NULL);
INSERT INTO `__PREFIX__admin` VALUES (2, '2', '4', '5,4', 'ceshi', '测试用户', '13682bec405cf4b9002e6e8306312ce6', 1, 'a:3:{i:0;s:6:\"呵呵\";i:1;s:5:\"Think\";i:2;s:12:\"铁血柔肠\";}', '/upload/avatars/a0b923820dcc509a_100x100.png', 'PHP是全世界最好的语言', 'baimei@your.com', '0310', '15188888888', '我原本以为吕布已经天下无敌了,没想到还有比吕布勇猛的,这谁的部将?', 58, '河北省邯郸市廉颇大道110号指挥中心', '127.0.0.1', 1687154742, '3232254977', 1, '违规', 1609836672, 1687154742, NULL);
-- ----------------------------
-- Table structure for __PREFIX__admin_access
@@ -75,8 +75,8 @@ CREATE TABLE `__PREFIX__admin_access` (
-- ----------------------------
-- Records of __PREFIX__admin_access
-- ----------------------------
INSERT INTO `__PREFIX__admin_access` VALUES (1, '1', '5,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26,115,116', NULL);
INSERT INTO `__PREFIX__admin_access` VALUES (2, '2', '5,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26,115,116', NULL);
INSERT INTO `__PREFIX__admin_access` VALUES (1, '1,2', '5,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26,115,116', NULL);
INSERT INTO `__PREFIX__admin_access` VALUES (2, '2', '85,86,90,91,92,93,100,101,103,107,108,109,110,111,112', '');
-- ----------------------------
-- Table structure for __PREFIX__admin_group
@@ -103,7 +103,7 @@ CREATE TABLE `__PREFIX__admin_group` (
-- Records of __PREFIX__admin_group
-- ----------------------------
INSERT INTO `__PREFIX__admin_group` VALUES (1, 0, 1, '超级管理员', 'admin', 1, 1, '网站超级管理员组的', '100,107,108,109,110,111,112', NULL, 'layui-bg-blue', 1607832158, NULL);
INSERT INTO `__PREFIX__admin_group` VALUES (2, 1, 2, '网站编辑', 'editor', 1, 1, '负责公司软文的编写', '', NULL, 'layui-bg-cyan', 1607832158, NULL);
INSERT INTO `__PREFIX__admin_group` VALUES (2, 1, 2, '网站编辑', 'editor', 1, 1, '负责公司软文的编写', '', '5', 'layui-bg-cyan', 1607832158, NULL);
-- ----------------------------
-- Table structure for __PREFIX__admin_log
@@ -123,7 +123,7 @@ CREATE TABLE `__PREFIX__admin_log` (
`create_time` int(11) NULL DEFAULT NULL COMMENT '登录时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `user_ip`(`user_ip`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户登录记录表' ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户登录记录表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of __PREFIX__admin_log
@@ -154,8 +154,8 @@ CREATE TABLE `__PREFIX__admin_notice` (
-- Records of __PREFIX__admin_notice
-- ----------------------------
INSERT INTO `__PREFIX__admin_notice` VALUES (1, 'notice', 1, '系统通知', '您有新的通知内容', 0, '10.10.11.22', 0, 0, 0, 1668249585, NULL);
INSERT INTO `__PREFIX__admin_notice` VALUES (2, 'message', 1, '请注意查收短消息', '听说你又接了一个大项目', 2, '10.10.11.22', 0, 0, 1, 1668323353, NULL);
INSERT INTO `__PREFIX__admin_notice` VALUES (3, 'todo', 1, '您有一项待办', '请完成项目的迭代工作与BUG修复', 0, '10.10.11.22', 0, 0, 0, 1668393025, NULL);
INSERT INTO `__PREFIX__admin_notice` VALUES (2, 'message', 1, '请注意查收短消息', '听说你又接了一个大项目', 2, '10.10.11.22', 0, 0, 0, 1668323353, NULL);
INSERT INTO `__PREFIX__admin_notice` VALUES (3, 'todo', 1, '您有一项待办', '请完成项目的迭代工作与BUG修复', 0, '10.10.11.22', 0, 0, 3, 1668393025, NULL);
-- ----------------------------
-- Table structure for __PREFIX__admin_rules
@@ -181,7 +181,7 @@ CREATE TABLE `__PREFIX__admin_rules` (
PRIMARY KEY (`id`) USING BTREE,
INDEX `id`(`id`) USING BTREE,
INDEX `sort`(`sort`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 123 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '菜单权限表' ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 146 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '菜单权限表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of __PREFIX__admin_rules
@@ -190,7 +190,7 @@ INSERT INTO `__PREFIX__admin_rules` VALUES (1, 0, 'Dashboard', 'Dashboard', 'das
INSERT INTO `__PREFIX__admin_rules` VALUES (2, 1, '控制台', '/index/console', 'index:console', 0, '', '', 2, '', 0, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (3, 1, '分析页', '/index/analysis', 'index:analysis', 0, '', '', 3, '', 0, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (4, 1, '监控页', '/index/monitor', 'index:monitor', 0, '', '', 4, '', 0, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (5, 0, '系统管理', 'System', 'system', 0, '', '', 5, 'layui-icon-set-fill', 1, 1, 0, 1657367099, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (5, 0, '系统管理', 'System', 'system', 0, '', '', 5, 'layui-icon-set-fill', 1, 1, 0, 1687144413, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (6, 5, '基本设置', '/index/basecfg', 'index:basecfg', 0, '', '', 6, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (7, 6, '修改配置', '/index/baseset', 'index:baseset', 2, '', '', 7, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (8, 6, 'FTP接口', '/index/testftp', 'index:testftp', 2, '', '', 8, '', 0, 1, 0, 1657002180, 1657002180, NULL);
@@ -242,15 +242,15 @@ INSERT INTO `__PREFIX__admin_rules` VALUES (53, 50, '删除', '/system/LoginLog/
INSERT INTO `__PREFIX__admin_rules` VALUES (54, 50, '状态', '/system/LoginLog/status', 'system:LoginLog:status', 1, '', '', 54, NULL, 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (55, 0, '高级管理', 'Management', 'management', 0, '', '', 55, 'layui-icon-engine', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (56, 55, '公司管理', '/system/Company/index', 'system:Company:index', 0, '', '', 56, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (57, 56, '查看', '/system/Company/index', 'system:Company:index', 1, '', '', 57, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (58, 56, '添加', '/system/Company/add', 'system:Company:add', 1, '', '', 58, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (57, 56, '查看', '/system/Company/index', 'system:Company:index', 1, '', '', 57, '', 1, 1, 0, 1686755836, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (58, 56, '添加', '/system/Company/add', 'system:Company:add', 1, '', '', 58, '', 1, 1, 0, 1687147120, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (59, 56, '编辑', '/system/Company/edit', 'system:Company:edit', 1, '', '', 59, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (60, 56, '删除', '/system/Company/del', 'system:Company:del', 1, '', '', 60, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (61, 56, '状态', '/system/Company/status', 'system:Company:status', 2, '', '', 61, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (62, 55, '部门管理', '/system/Department/index', 'system:Department:index', 0, '', '', 62, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (63, 62, '查看', '/system/Department/index', 'system:Department:index', 1, '', '', 63, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (64, 62, '添加', '/system/Department/add', 'system:Department:add', 1, '', '', 64, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (65, 62, '编辑', '/system/Department/edit', 'system:Department:edit', 1, '', '', 65, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (65, 62, '编辑', '/system/Department/edit', 'system:Department:edit', 1, '', '', 65, '', 1, 1, 0, 1686881933, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (66, 62, '删除', '/system/Department/del', 'system:Department:del', 1, '', '', 66, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (67, 62, '状态', '/system/Department/status', 'system:Department:status', 2, '', '', 67, '', 1, 1, 0, 1657002180, 1657002180, NULL);
INSERT INTO `__PREFIX__admin_rules` VALUES (68, 55, '岗位管理', '/system/Jobs/index', 'system:Jobs:index', 0, '', '', 68, '', 1, 1, 0, 1657002180, 1657002180, NULL);
@@ -393,13 +393,13 @@ INSERT INTO `__PREFIX__config` VALUES (16, 'site_notice', 1, 'site', 'string', '
INSERT INTO `__PREFIX__config` VALUES (17, 'auth_key', 0, NULL, 'string', '38nfCIlkqancd', '授权码');
INSERT INTO `__PREFIX__config` VALUES (18, 'auth_code', 0, NULL, 'string', 'wMRkfKO4Lr37HTJQ', '加密KEY');
INSERT INTO `__PREFIX__config` VALUES (19, 'system_logs', 0, NULL, 'string', '0', '后台日志');
INSERT INTO `__PREFIX__config` VALUES (20, 'system_exception', 0, NULL, 'string', '0', '异常日志');
INSERT INTO `__PREFIX__config` VALUES (20, 'system_exception', 0, NULL, 'string', '1', '异常日志');
INSERT INTO `__PREFIX__config` VALUES (21, 'cache_status', 0, 'cache', 'string', '1', '缓存状态');
INSERT INTO `__PREFIX__config` VALUES (22, 'cache_type', 0, 'cache', 'string', 'redis', '缓存类型');
INSERT INTO `__PREFIX__config` VALUES (23, 'cache_time', 0, 'cache', 'string', '6000', '缓存时间');
INSERT INTO `__PREFIX__config` VALUES (24, 'cache_host', 0, 'cache', 'string', '127.0.0.1', '服务器IP');
INSERT INTO `__PREFIX__config` VALUES (25, 'cache_port', 0, 'cache', 'string', '6379', '端口');
INSERT INTO `__PREFIX__config` VALUES (26, 'cache_select', 0, 'cache', 'string', '2', '缓存数据库');
INSERT INTO `__PREFIX__config` VALUES (26, 'cache_select', 0, 'cache', 'string', '4', '缓存数据库');
INSERT INTO `__PREFIX__config` VALUES (27, 'cache_user', 0, 'cache', 'string', '', '用户名');
INSERT INTO `__PREFIX__config` VALUES (28, 'cache_pass', 0, 'cache', 'string', '', '密码');
INSERT INTO `__PREFIX__config` VALUES (29, 'upload_path', 0, 'upload', 'string', 'upload', '上传路径');
@@ -520,14 +520,14 @@ CREATE TABLE `__PREFIX__dictionary` (
-- ----------------------------
-- Records of __PREFIX__dictionary
-- ----------------------------
INSERT INTO `__PREFIX__dictionary` VALUES (1, 0, '内容属性', 'content', 1, '', 1, 1682217587, 1637738903, NULL);
INSERT INTO `__PREFIX__dictionary` VALUES (1, 0, '内容属性', 'content', 1, '', 1, 1687140686, 1637738903, NULL);
INSERT INTO `__PREFIX__dictionary` VALUES (2, 1, '头条', '1', 2, '', 1, 1669690446, 1638093403, NULL);
INSERT INTO `__PREFIX__dictionary` VALUES (3, 1, '推荐', '2', 3, '', 1, 1669690444, 1638093425, NULL);
INSERT INTO `__PREFIX__dictionary` VALUES (4, 1, '幻灯', '3', 4, '', 1, 1669690440, 1638093430, NULL);
INSERT INTO `__PREFIX__dictionary` VALUES (5, 1, '滚动', '4', 5, '', 1, 1669690442, 1638093435, NULL);
INSERT INTO `__PREFIX__dictionary` VALUES (6, 1, '图文', '5', 6, '', 1, 1638093456, 1638093456, NULL);
INSERT INTO `__PREFIX__dictionary` VALUES (7, 1, '跳转', '6', 7, '', 1, 1638093435, 1638093435, NULL);
INSERT INTO `__PREFIX__dictionary` VALUES (8, 0, '友链类型', 'friendlink', 8, '', 1, 1682217595, 1638093456, NULL);
INSERT INTO `__PREFIX__dictionary` VALUES (8, 0, '友链类型', 'friendlink', 8, '', 1, 1687140689, 1638093456, NULL);
INSERT INTO `__PREFIX__dictionary` VALUES (9, 8, '资源', '1', 9, '', 1, 1638093430, 1638093430, NULL);
INSERT INTO `__PREFIX__dictionary` VALUES (10, 8, '社区', '2', 10, '', 1, 1638093435, 1638093435, NULL);
INSERT INTO `__PREFIX__dictionary` VALUES (11, 8, '合作伙伴', '3', 11, '', 1, 1659450310, 1638093456, NULL);
@@ -588,7 +588,7 @@ CREATE TABLE `__PREFIX__system_log` (
INDEX `method`(`method`) USING BTREE,
INDEX `create_time`(`create_time`) USING BTREE,
INDEX `line`(`line`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统日志表' ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统日志表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of __PREFIX__system_log
@@ -645,12 +645,12 @@ CREATE TABLE `__PREFIX__user` (
INDEX `create_time`(`create_time`) USING BTREE,
INDEX `login_time`(`login_time`) USING BTREE,
INDEX `invite_id`(`invite_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '会员管理' ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '会员管理' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of __PREFIX__user
-- ----------------------------
INSERT INTO `__PREFIX__user` VALUES (1, 1, '创始人', '513bd12b00b512d0b879962b777b5560', 'wdONQC', NULL, NULL, '/upload/avatars/a0b923820dcc509a_100x100.png', '这个人很懒,什么都没有留下~ ', 'test@swiftadmin.net', NULL, '林自图', 0, '2022-11-04 20:04:55', '15253325632533', '河北省邯郸市中华区人民东路023号', '', 0, 100, 1983.56, '你的幸运数字是?', 'aa', 1, 1, 10001, 'myKDalrGjpEVxWPQcXzwFu', NULL, NULL, NULL, NULL, NULL, NULL, 1, '127.0.0.1', 1682390408, 162, NULL, '1861775580', 1657332918, NULL);
INSERT INTO `__PREFIX__user` VALUES (1, 1, '创始人', '513bd12b00b512d0b879962b777b5560', 'wdONQC', NULL, NULL, '/upload/avatars/a0b923820dcc509a_100x100.png', '这个人很懒,什么都没有留下~ ', 'test@swiftadmin.net', NULL, '林自图', 0, '2022-11-04 20:04:55', '15253325632533', '河北省邯郸市中华区人民东路023号', '', 0, 100, 1983.56, '你的幸运数字是?', '1', 1, 1, 10001, 'myKDalrGjpEVxWPQcXzwFu', NULL, NULL, NULL, NULL, NULL, NULL, 1, '127.0.0.1', 1686621464, 163, NULL, '1861775580', 1657332918, NULL);
-- ----------------------------
-- Table structure for __PREFIX__user_group
@@ -697,7 +697,7 @@ CREATE TABLE `__PREFIX__user_log` (
`create_time` int(11) NULL DEFAULT NULL COMMENT '登录时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `user_ip`(`login_ip`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户记录表' ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '用户记录表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of __PREFIX__user_log

View File

@@ -61,8 +61,8 @@
<tbody>
<tr>
<td>php</td>
<td> >= 8.0.0 </td>
<td <elt name="$checkEnv.php" value="8.0.0"> style="color:red;" </elt> >{$checkEnv.php}</td>
<td> >= 8.0 </td>
<td <elt name="$checkEnv.php" value="8.0"> style="color:red;" </elt> >{$checkEnv.php}</td>
</tr>
<tr>
<td>mysqli</td>

View File

@@ -9,7 +9,7 @@ use Webman\RedisQueue\Consumer;
* @author meystack
* @date 2022-11-20
*/
class Works implements Consumer
class Worker implements Consumer
{
/**
* 消费队列名称

View File

@@ -31,7 +31,6 @@
"workerman/webman-framework": "1.5.5",
"webman/think-orm": "^1.0",
"webman/redis-queue": "^1.2",
"webman/think-cache": "^1.0",
"webman/console": "1.2.33",
"webman/event": "^1.0",
"webman/captcha": "^1.0",
@@ -47,7 +46,9 @@
"php-di/php-di": "^6.4",
"yansongda/pay": "~3.1.0",
"overtrue/pinyin": "5.0",
"phpoffice/phpspreadsheet": "^1.28"
"phpoffice/phpspreadsheet": "^1.28",
"illuminate/redis": "^9.52",
"symfony/cache": "^5.4"
},
"suggest": {
"ext-event": "For better performance. "

932
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -38,7 +38,7 @@ return [
'dispatch_success' => app_path() . '/admin/view/public/jumptpl.html',
'exception_tpl' => app_path() . '/admin/view/error/500.html',
'error_message' => '页面错误!请稍后再试~',
'version' => 'v1.1.6',
'version' => 'v1.1.7',
'cors_domain' => ['*', '127.0.0.1'],
'api_url' => 'https://api.swiftadmin.net/',
'show_error_msg' => false,

View File

@@ -12,9 +12,11 @@
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
use app\common\bootstrap\RedisCache;
return [
support\bootstrap\Session::class,
support\bootstrap\LaravelDb::class,
RedisCache::class, // 缓存服务器
Webman\ThinkOrm\ThinkOrm::class,
Webman\ThinkCache\ThinkCache::class,
];

View File

@@ -1,3 +0,0 @@
<?php
return [
];

View File

@@ -1,4 +1,4 @@
<?php
return [
'enable' => true,
'enable' => false,
];

View File

@@ -1,4 +1,4 @@
<?php
return [
'enable' => true,
'enable' => false,
];

View File

@@ -14,9 +14,11 @@
return [
'default' => [
'host' => '127.0.0.1',
'host' => get_env('CACHE_HOSTNAME') ?? '127.0.0.1',
'password' => get_env('REDIS_PASSWORD'),
'port' => 6379,
'database' => 1,
'port' => get_env('CACHE_HOSTPORT') ?? 6379,
'database' => get_env('CACHE_SELECT') ?? 0,
'prefix' => 'redis_',
'expire' => 0,
],
];

View File

@@ -14,16 +14,6 @@ use Webman\Route;
// 验证码路由
Route::any('/captcha', [app\BaseController::class, 'captcha']);
/**
* 加载自定义路由 [插件路由]
*/
$defineRoute = require __DIR__ . '/defineRoute.php';
if ($defineRoute && is_array($defineRoute)) {
foreach ($defineRoute as $key => $value) {
Route::any($key, $value);
}
}
/**
* 默认管理员路由
* @var string $manage
@@ -77,3 +67,29 @@ Route::fallback(function ($request) {
return response(request_error(current($parseApp)), 404);
});
// 执行插件初始化
$pluginList = get_plugin_list();
foreach ($pluginList as $item) {
if (!$item['status']) {
continue;
}
foreach ($item['rewrite'] as $route => $value) {
$separator = explode('/', $value);
$method = end($separator);
array_pop($separator);
$filePath = implode('\\', $separator);
$controller = 'app\\index\\controller\\' . $filePath;
if (class_exists($controller) && method_exists($controller, $method)) {
try {
$classFullName = (new ReflectionClass($controller))->getName();
Route::any($route, [$classFullName, $method]);
} catch (\Throwable $e) {
var_dump('error: ' . $e->getMessage());
}
} else {
var_dump("\033[31m$controller or $method does not exist!\033[0m");
}
}
}

View File

@@ -1,3 +0,0 @@
<?php
return [
];

View File

@@ -1,24 +0,0 @@
<?php
return [
'default' => get_env('CACHE_DRIVER') ?: 'file',
'stores' => [
'file' => [
'type' => 'File',
// 缓存保存目录
'path' => runtime_path() . '/cache/',
// 缓存前缀
'prefix' => '',
// 缓存有效期 0表示永久缓存
'expire' => 0,
],
'redis' => [
'type' => 'redis',
'host' => get_env('CACHE_HOSTNAME') ?: '127.0.0.1',
'port' => get_env('CACHE_HOSTPORT') ?: 6379,
'select' => get_env('CACHE_SELECT') ?: 0,
'password' => get_env('CACHE_PASSWORD') ?: '',
'prefix' => 'redis_',
'expire' => 0,
],
],
];

View File

@@ -25,7 +25,9 @@ return [
// 断线重连
'break_reconnect' => true,
// 关闭SQL监听日志
'trigger_sql' => false,
'trigger_sql' => true,
// 开启字段缓存
'fields_cache' => false,
],
],
];

View File

@@ -23,7 +23,7 @@ return [
'tpl_cache' => true,
'taglib_begin' => '<',
'taglib_end' => '>',
'taglib_pre_load' => implode(',', array_merge(['app\common\taglib\SaLibs'],include __DIR__ . '/taglib.php')),
'taglib_pre_load' => 'app\common\taglib\SaLibs',
'tpl_replace_string' => [
'__STATIC__' => '/static/',
'__STATICJS__' => '/static/js/',

View File

@@ -65,6 +65,11 @@ b.msg {
color: #000;
}
.layui-btn {
height: 33px!important;
line-height: 33px!important;
}
.layui-form-label {
padding: 6px 15px;
}

View File

@@ -107,7 +107,7 @@ a {
#header #login {
right: 20px;
left: unset;
width: 150px;
/*width: 150px;*/
}
#header .nav-item a {

View File

@@ -409,7 +409,7 @@ a {
}
.layui-tree-iconClick .layui-icon {
font-size: 16px!important;
font-size: 14px!important;
}
.layui-tree-txt {
@@ -1312,10 +1312,6 @@ a {
right: 0
}
.layui-tree-subtraction .layui-form-checkbox[lay-skin=primary] i.layui-icon-ok:before {
content: "\e67e";
}
.swiftadmin-tabs-select.layui-nav {
position: absolute;
left: 0;
@@ -2233,22 +2229,18 @@ a {
}
.layui-form-onswitch {
height: 16px;
line-height: 16px;
min-width: 28px;
margin-top: 6px;
background-color: #1890ff;
border: 1px solid #1890ff;
}
.layui-form-switch i {
top: 2px;
top: 1px;
width: 12px;
height: 12px;
}
.layui-form-onswitch i {
margin-left: -18px;
margin-left: -16px;
}
/* 拖拽上传 */
@@ -2437,6 +2429,24 @@ a {
.layui-table-view .layui-form-checkbox[lay-skin=primary] i {
width: 16px;
height: 16px;
line-height: 15px;
}
.layui-form-checkbox[lay-skin="primary"] > .layui-icon-indeterminate {
border-color: #1890ff;
color: #fff;
background-color: #1890ff;
}
.layui-form-checkbox[lay-skin="primary"] > .layui-icon-indeterminate:before {
content: '';
display: inline-block;
vertical-align: middle;
position: relative;
width: 50%;
height: 1px;
margin: -1px auto 0;
background-color: #fff;
}
.layui-laypage .layui-laypage-curr .layui-laypage-em {

View File

@@ -12,7 +12,6 @@ layui.config({
iconPicker: 'iconPicker/iconPicker',
echarts: "echarts/echarts",
xmselect: 'xmselect/xmselect',
treetable: 'treetable/treetable',
tableSelect: 'tableSelect/tableSelect',
formDesign: 'formDesign/formDesign',
soulTable: 'soulTable/soulTable',

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-view{display:block;position:relative;margin:10px 0;padding:0;border:1px solid #eee;border-left-width:6px;background-color:#fafafa;color:#333;font-family:Courier New;font-size:13px}.layui-code-title{position:relative;padding:0 10px;height:40px;line-height:40px;border-bottom:1px solid #eee;font-size:12px}.layui-code-title>.layui-code-about{position:absolute;right:10px;top:0;color:#b7b7b7}.layui-code-about>a{padding-left:10px}.layui-code-view>.layui-code-ol,.layui-code-view>.layui-code-ul{position:relative;overflow:auto}.layui-code-view>.layui-code-ol>li{position:relative;margin-left:45px;line-height:20px;padding:0 10px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view>.layui-code-ol>li:first-child,.layui-code-view>.layui-code-ul>li:first-child{padding-top:10px}.layui-code-view>.layui-code-ol>li:last-child,.layui-code-view>.layui-code-ul>li:last-child{padding-bottom:10px}.layui-code-view>.layui-code-ul>li{position:relative;line-height:20px;padding:0 10px;list-style-type:none;*list-style-type:none;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-dark{border:1px solid #0c0c0c;border-left-color:#3f3f3f;background-color:#0c0c0c;color:#c2be9e}.layui-code-dark>.layui-code-title{border-bottom:none}.layui-code-dark>.layui-code-ol>li,.layui-code-dark>.layui-code-ul>li{background-color:#3f3f3f;border-left:none}.layui-code-dark>.layui-code-ul>li{margin-left:6px}.layui-code-demo .layui-code{visibility:visible!important;margin:-15px;border-top:none;border-right:none;border-bottom:none}.layui-code-demo .layui-tab-content{padding:15px;border-top:none}

View File

@@ -1,16 +0,0 @@
/** 图标字体 **/
@font-face {font-family: 'laydate-icon';
src: url('./font/iconfont.eot');
src: url('./font/iconfont.eot#iefix') format('embedded-opentype'),
url('./font/iconfont.svg#iconfont') format('svg'),
url('./font/iconfont.woff') format('woff'),
url('./font/iconfont.ttf') format('truetype');
}
.laydate-icon{
font-family:"laydate-icon" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
.layui-tags{border:1px solid #e3e7f1;height:29px;line-height:1.3;background-color:#fff;border-radius:2px;padding-left:10px}.layui-tags input{width:90px;font-family:helvetica;font-size:13px;border:1px solid transparent;background:0 0;color:#000;outline:0;height:28px;float:left}.layui-tags .tag-elem{float:left;height:25px;font-size:12px;box-sizing:border-box;margin-right:5px;padding:5px;margin-top:2px;-moz-border-radius:2px;-webkit-border-radius:2px;font-family:helvetica;color:#1890ff;background:#e6f7ff;border:1px solid #91d5ff}.layui-tags span.tag-elem i{font-family:Verdana;color:#0084ff;margin-left:5px;font-size:12px;cursor:pointer}#layui-tags-ajax li b,.layui-tags span.tag-elem i:hover{color:red}#layui-tags-ajax{text-align:left;cursor:default;background:#fff;border:1px solid rgba(0,0,0,.15);border-radius:2px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);-moz-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box;position:absolute;display:none;z-index:1029;max-height:254px;overflow:hidden;overflow-y:auto;width:138px;box-sizing:border-box}#layui-tags-ajax li{position:relative;line-height:20px;overflow:hidden;text-overflow:ellipsis;font-size:1em;color:#333;padding:5px 10px;cursor:pointer;white-space:nowrap}#layui-tags-ajax .layui-tag-this,#layui-tags-ajax li:hover{background:#f0f0f0}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 299 KiB

After

Width:  |  Height:  |  Size: 322 KiB

File diff suppressed because one or more lines are too long

View File

@@ -3,12 +3,13 @@
* by meystack to www.swiftadmin.net
* Apache2.0 Licensed
*/
layui.define(['laypage'], function (exports) {
layui.define(['laypage','dropdown'], function (exports) {
"use strict";
var $ = layui.$
, laypage = layui.laypage
, dropdown = layui.dropdown
//模块名
, MOD_NAME = 'fileManager'
, MOD_INDEX = 'layui_' + MOD_NAME + '_index' //模块索引名
@@ -238,7 +239,7 @@ layui.define(['laypage'], function (exports) {
});
}
layui.dropdown.render({
dropdown.render({
elem: item
, trigger: 'contextmenu'
, id: 'file' + index

View File

@@ -5,6 +5,7 @@ layui.define(['i18n'], function (exports) {
var table = layui.table;
var i18n = layui.i18n;
var form = layui.form;
var notice = layui.notice;
i18n.render(layui.admin.getStorage('language') || 'zh-CN');
var area = [$(window).width() > 800 ? '660px' : '85%', $(window).height() > 800 ? '680px' : '85%'];
@@ -61,8 +62,9 @@ layui.define(['i18n'], function (exports) {
top.layui.admin.reloadLayout();
} else {
layer.msg(res.msg, 'error');
notice.error({
message: res.msg,
})
// 登录超时
if (res.code === -101) {
plugin.login();
@@ -111,7 +113,9 @@ layui.define(['i18n'], function (exports) {
layer.closeAll();
plugin.againClick();
} else {
layer.msg(res.msg, 'error');
notice.error({
message: res.msg,
})
}
}, 'json')
@@ -185,7 +189,9 @@ layui.define(['i18n'], function (exports) {
delete window.plugins[name];
$(elems).find('td:last').children('div').html(html);
} else {
layer.msg(i18n.prop(res.msg), 'error');
notice.error({
message: res.msg,
})
}
layer.close(window.unIndex);
@@ -211,7 +217,7 @@ layui.define(['i18n'], function (exports) {
html += '<div class="layui-form-item">';
html += '<label class="layui-form-label">用户邮箱</label>';
html += '<div class="layui-input-block">';
html += '<input type="text" name="nickname" style="width:330px;" lay-verify="required" placeholder="请输入邮箱或手机号" autocomplete="off" class="layui-input" >';
html += '<input type="text" name="nickname" style="width:330px;" lay-verify="required" placeholder="请输入邮箱或用户名" autocomplete="off" class="layui-input" >';
html += '</div></div>';
html += '<div class="layui-form-item"><label class="layui-form-label">密码</label>';
html += '<div class="layui-input-block">';
@@ -270,7 +276,7 @@ layui.define(['i18n'], function (exports) {
let name = plugin.getTableData(this)['name'];
layui.sessionData('api_install_index', {
key: 'index',
value: plugin.getTableData(this)['LAY_TABLE_INDEX'],
value: plugin.getTableData(this)['LAY_INDEX'],
});
plugin.request(name, null, plugin.getUrl('Plugin', 'install'));
})
@@ -291,7 +297,9 @@ layui.define(['i18n'], function (exports) {
error: function (res) {
$(obj.elem).prop('checked', !obj.elem.checked);
form.render('checkbox');
layer.msg(res.msg, 'error');
notice.error({
message: res.msg,
})
},
success: function (res) {
layer.msg(res.msg);
@@ -335,7 +343,7 @@ layui.define(['i18n'], function (exports) {
html += '</div></form> ';
layui.sessionData('api_install_index', {
key: 'index',
value: plugin.getTableData(this)['LAY_TABLE_INDEX'],
value: plugin.getTableData(this)['LAY_INDEX'],
});
layer.open({
type: 1,
@@ -388,7 +396,9 @@ layui.define(['i18n'], function (exports) {
layer.msg(res.msg);
layer.close(confirm);
} else {
layer.msg(res.msg, 'error');
notice.error({
message: res.msg,
})
}
})
});

View File

@@ -1,22 +0,0 @@
.treeTable-empty {
width: 20px;
display: inline-block;
}
.treeTable-icon {
cursor: pointer;
}
table .treeTable-icon i.layui-icon {
font-size: 14px;
}
.treeTable-icon .layui-icon-right:before {
content: "\e602";
}
.treeTable-icon.open .layui-icon-right:before {
content: "\e61a";
background-color: transparent;
}

View File

@@ -1,223 +0,0 @@
layui.define(['layer', 'table'], function (exports) {
var $ = layui.jquery;
var layer = layui.layer;
var table = layui.table;
var treetable = {
// 渲染树形表格
render: function (param) {
// 检查参数
if (!treetable.checkParam(param)) {
return;
}
// 获取数据
if (param.data) {
treetable.init(param, param.data);
} else {
$.getJSON(param.url, param.where, function (res) {
treetable.init(param, res.data);
});
}
},
// 渲染表格
init: function (param, data) {
var mData = [];
var doneCallback = param.done;
if (typeof data.item !== 'undefined') {
for (let name in data) {
if (name != 'item') {
table.cache[name] = data[name];
}
}
data = data.item;
}
var tNodes = data;
// 补上id和pid字段
for (var i = 0; i < tNodes.length; i++) {
var tt = tNodes[i];
if (!tt.id) {
if (!param.treeIdName) {
layer.msg('参数treeIdName不能为空', {icon: 5});
return;
}
tt.id = tt[param.treeIdName];
}
if (!tt.pid) {
if (!param.treePidName) {
layer.msg('参数treePidName不能为空', {icon: 5});
return;
}
tt.pid = tt[param.treePidName];
}
}
// 对数据进行排序
var sort = function (s_pid, data) {
for (var i = 0; i < data.length; i++) { // 排序
if (data[i].pid == s_pid) {
var len = mData.length;
if (len > 0 && mData[len - 1].id == s_pid) {
mData[len - 1].isParent = true; // 是否为父类
}
mData.push(data[i]);
sort(data[i].id, data);
}
}
};
sort(param.treeSpid, tNodes); // -1
// 重写参数
param.url = undefined;
param.data = mData;
param.page = {
count: param.data.length,
limit: param.data.length
};
param.cols[0][param.treeColIndex].templet = function (d) {
var mId = d.id;
var mPid = d.pid;
var isDir = d.isParent;
var emptyNum = treetable.getEmptyNum(mPid, mData);
var iconHtml = '';
for (var i = 0; i < emptyNum; i++) {
iconHtml += '<span class="treeTable-empty"></span>';
}
// 设置图标
if (isDir) {
iconHtml += '<i class="layui-icon layui-icon-right"></i>';
if (d.icons) {
iconHtml += '&nbsp;&nbsp;<i class="layui-icon '+ d.icons +'"></i>';
}
} else {
iconHtml += '<i class="layui-icon '+ d.icons +'"></i>';
}
iconHtml += '&nbsp;';
var ttype = isDir ? 'dir' : 'file';
var vg = '<span class="treeTable-icon open" lay-tid="' + mId + '" lay-tpid="' + mPid + '" lay-ttype="' + ttype + '">';
return vg + iconHtml + d[param.cols[0][param.treeColIndex].field] + '</span>'
};
param.done = function (res, curr, count) {
$(param.elem).next().addClass('treeTable');
$('.treeTable .layui-table-page').css('display', 'none');
$(param.elem).next().attr('treeLinkage', param.treeLinkage);
// 绑定事件换成对body绑定
/*$('.treeTable .treeTable-icon').click(function () {
treetable.toggleRows($(this), param.treeLinkage);
});*/
if (param.treeDefaultClose) {
treetable.foldAll(param.elem);
}
if (doneCallback) {
doneCallback(res, curr, count);
}
};
// 渲染表格
table.render(param);
},
// 计算缩进的数量
getEmptyNum: function (pid, data) {
var num = 0;
if (!pid) {
return num;
}
var tPid;
for (var i = 0; i < data.length; i++) {
if (pid == data[i].id) {
num += 1;
tPid = data[i].pid;
break;
}
}
return num + treetable.getEmptyNum(tPid, data);
},
// 展开/折叠行
toggleRows: function ($dom, linkage) {
var type = $dom.attr('lay-ttype');
if ('file' == type) {
return;
}
var mId = $dom.attr('lay-tid');
var isOpen = $dom.hasClass('open');
if (isOpen) {
$dom.removeClass('open');
} else {
$dom.addClass('open');
}
$dom.closest('tbody').find('tr').each(function () {
var $ti = $(this).find('.treeTable-icon');
var pid = $ti.attr('lay-tpid');
var ttype = $ti.attr('lay-ttype');
var tOpen = $ti.hasClass('open');
if (mId == pid) {
if (isOpen) {
$(this).hide();
if ('dir' == ttype && tOpen == isOpen) {
$ti.trigger('click');
}
} else {
$(this).show();
if (linkage && 'dir' == ttype && tOpen == isOpen) {
$ti.trigger('click');
}
}
}
});
},
// 检查参数
checkParam: function (param) {
if (!param.treeSpid && param.treeSpid != 0) {
layer.msg('参数treeSpid不能为空');
return false;
}
if (!param.treeColIndex && param.treeColIndex != 0) {
layer.msg('参数treeColIndex不能为空');
return false;
}
return true;
},
// 展开所有
expandAll: function (dom) {
$(dom).next('.treeTable').find('.layui-table-body tbody tr').each(function () {
var $ti = $(this).find('.treeTable-icon');
var ttype = $ti.attr('lay-ttype');
var tOpen = $ti.hasClass('open');
if ('dir' == ttype && !tOpen) {
$ti.trigger('click');
}
});
},
// 折叠所有
foldAll: function (dom) {
$(dom).next('.treeTable').find('.layui-table-body tbody tr').each(function () {
var $ti = $(this).find('.treeTable-icon');
var ttype = $ti.attr('lay-ttype');
var tOpen = $ti.hasClass('open');
if ('dir' == ttype && tOpen) {
$ti.trigger('click');
}
});
}
};
layui.link(layui.cache.base + 'treetable/treetable.css');
// 给图标列绑定事件
$('body').on('click', '.treeTable .treeTable-icon', function () {
var treeLinkage = $(this).parents('.treeTable').attr('treeLinkage');
if ('true' == treeLinkage) {
treetable.toggleRows($(this), true);
} else {
treetable.toggleRows($(this), false);
}
});
exports('treetable', treetable);
});

Some files were not shown because too many files have changed in this diff Show More