From 44defa48fa99b51b2e8080133a8fe2a763edd9d9 Mon Sep 17 00:00:00 2001 From: net909 Date: Wed, 3 Apr 2024 20:51:10 +0800 Subject: [PATCH] Initial --- .example.env | 19 + .gitignore | 5 + README.md | 72 ++ app/.htaccess | 1 + app/AppService.php | 22 + app/BaseController.php | 122 +++ app/ExceptionHandle.php | 58 ++ app/Request.php | 8 + app/common.php | 210 +++++ app/controller/Auth.php | 115 +++ app/controller/Domain.php | 561 +++++++++++++ app/controller/Index.php | 96 +++ app/controller/Install.php | 84 ++ app/controller/User.php | 164 ++++ app/data/huawei_line.json | 1 + app/event.php | 17 + app/lib/DnsHelper.php | 91 +++ app/lib/DnsInterface.php | 35 + app/lib/dns/aliyun.php | 314 ++++++++ app/lib/dns/baidu.php | 330 ++++++++ app/lib/dns/cloudflare.php | 237 ++++++ app/lib/dns/dnspod.php | 362 +++++++++ app/lib/dns/huawei.php | 345 ++++++++ app/lib/dns/west.php | 226 ++++++ app/middleware.php | 12 + app/middleware/AuthApi.php | 40 + app/middleware/AuthUser.php | 52 ++ app/middleware/CheckLogin.php | 19 + app/middleware/LoadConfig.php | 39 + app/middleware/RefererCheck.php | 24 + app/middleware/ViewOutput.php | 25 + app/provider.php | 9 + app/service.php | 9 + app/sql/install.sql | 63 ++ app/view/auth/login.html | 112 +++ app/view/common/layout.html | 196 +++++ app/view/dispatch_jump.html | 60 ++ app/view/domain/account.html | 234 ++++++ app/view/domain/domain.html | 361 +++++++++ app/view/domain/log.html | 47 ++ app/view/domain/record.html | 436 +++++++++++ app/view/index/error.html | 23 + app/view/index/index.html | 175 +++++ app/view/index/setpwd.html | 60 ++ app/view/install/index.html | 266 +++++++ app/view/user/log.html | 77 ++ app/view/user/user.html | 338 ++++++++ composer.json | 50 ++ config/app.php | 34 + config/cache.php | 29 + config/captcha.php | 39 + config/console.php | 9 + config/cookie.php | 20 + config/database.php | 63 ++ config/filesystem.php | 24 + config/lang.php | 27 + config/log.php | 45 ++ config/middleware.php | 8 + config/route.php | 45 ++ config/session.php | 19 + config/trace.php | 10 + config/view.php | 25 + public/.htaccess | 8 + public/favicon.ico | Bin 0 -> 16446 bytes public/index.php | 24 + public/robots.txt | 2 + public/router.php | 19 + public/static/css/app.min.css | 10 + public/static/css/bootstrap-table.css | 7 + public/static/css/select2.min.css | 1 + public/static/css/skins/skin-black-blue.css | 242 ++++++ public/static/css/skins/skin-black-green.css | 242 ++++++ public/static/css/skins/skin-black-light.css | 192 +++++ public/static/css/skins/skin-black-pink.css | 242 ++++++ public/static/css/skins/skin-black-purple.css | 242 ++++++ public/static/css/skins/skin-black-red.css | 242 ++++++ public/static/css/skins/skin-black-yellow.css | 242 ++++++ public/static/css/skins/skin-black.css | 219 ++++++ public/static/css/skins/skin-blue-light.css | 184 +++++ public/static/css/skins/skin-blue.css | 230 ++++++ public/static/css/skins/skin-green-light.css | 181 +++++ public/static/css/skins/skin-green.css | 175 +++++ public/static/css/skins/skin-purple-light.css | 181 +++++ public/static/css/skins/skin-purple.css | 220 ++++++ public/static/css/skins/skin-red-light.css | 181 +++++ public/static/css/skins/skin-red.css | 175 +++++ public/static/css/skins/skin-yellow-light.css | 181 +++++ public/static/css/skins/skin-yellow.css | 175 +++++ public/static/images/aliyun.ico | Bin 0 -> 4286 bytes public/static/images/baidu.ico | Bin 0 -> 67646 bytes public/static/images/cloudflare.ico | Bin 0 -> 34494 bytes public/static/images/dnspod.ico | Bin 0 -> 67646 bytes public/static/images/error.svg | 22 + public/static/images/huawei.ico | Bin 0 -> 1150 bytes public/static/images/info.svg | 18 + public/static/images/login-head.png | Bin 0 -> 32292 bytes public/static/images/logo.png | Bin 0 -> 9084 bytes public/static/images/success.svg | 18 + public/static/images/user.png | Bin 0 -> 15135 bytes public/static/images/west.ico | Bin 0 -> 1150 bytes public/static/js/app.js | 738 ++++++++++++++++++ public/static/js/bootstrapValidator.min.js | 1 + public/static/js/custom.js | 133 ++++ route/app.php | 78 ++ runtime/.gitignore | 2 + think | 10 + 106 files changed, 11456 insertions(+) create mode 100644 .example.env create mode 100644 .gitignore create mode 100644 README.md create mode 100644 app/.htaccess create mode 100644 app/AppService.php create mode 100644 app/BaseController.php create mode 100644 app/ExceptionHandle.php create mode 100644 app/Request.php create mode 100644 app/common.php create mode 100644 app/controller/Auth.php create mode 100644 app/controller/Domain.php create mode 100644 app/controller/Index.php create mode 100644 app/controller/Install.php create mode 100644 app/controller/User.php create mode 100644 app/data/huawei_line.json create mode 100644 app/event.php create mode 100644 app/lib/DnsHelper.php create mode 100644 app/lib/DnsInterface.php create mode 100644 app/lib/dns/aliyun.php create mode 100644 app/lib/dns/baidu.php create mode 100644 app/lib/dns/cloudflare.php create mode 100644 app/lib/dns/dnspod.php create mode 100644 app/lib/dns/huawei.php create mode 100644 app/lib/dns/west.php create mode 100644 app/middleware.php create mode 100644 app/middleware/AuthApi.php create mode 100644 app/middleware/AuthUser.php create mode 100644 app/middleware/CheckLogin.php create mode 100644 app/middleware/LoadConfig.php create mode 100644 app/middleware/RefererCheck.php create mode 100644 app/middleware/ViewOutput.php create mode 100644 app/provider.php create mode 100644 app/service.php create mode 100644 app/sql/install.sql create mode 100644 app/view/auth/login.html create mode 100644 app/view/common/layout.html create mode 100644 app/view/dispatch_jump.html create mode 100644 app/view/domain/account.html create mode 100644 app/view/domain/domain.html create mode 100644 app/view/domain/log.html create mode 100644 app/view/domain/record.html create mode 100644 app/view/index/error.html create mode 100644 app/view/index/index.html create mode 100644 app/view/index/setpwd.html create mode 100644 app/view/install/index.html create mode 100644 app/view/user/log.html create mode 100644 app/view/user/user.html create mode 100644 composer.json create mode 100644 config/app.php create mode 100644 config/cache.php create mode 100644 config/captcha.php create mode 100644 config/console.php create mode 100644 config/cookie.php create mode 100644 config/database.php create mode 100644 config/filesystem.php create mode 100644 config/lang.php create mode 100644 config/log.php create mode 100644 config/middleware.php create mode 100644 config/route.php create mode 100644 config/session.php create mode 100644 config/trace.php create mode 100644 config/view.php create mode 100644 public/.htaccess create mode 100644 public/favicon.ico create mode 100644 public/index.php create mode 100644 public/robots.txt create mode 100644 public/router.php create mode 100644 public/static/css/app.min.css create mode 100644 public/static/css/bootstrap-table.css create mode 100644 public/static/css/select2.min.css create mode 100644 public/static/css/skins/skin-black-blue.css create mode 100644 public/static/css/skins/skin-black-green.css create mode 100644 public/static/css/skins/skin-black-light.css create mode 100644 public/static/css/skins/skin-black-pink.css create mode 100644 public/static/css/skins/skin-black-purple.css create mode 100644 public/static/css/skins/skin-black-red.css create mode 100644 public/static/css/skins/skin-black-yellow.css create mode 100644 public/static/css/skins/skin-black.css create mode 100644 public/static/css/skins/skin-blue-light.css create mode 100644 public/static/css/skins/skin-blue.css create mode 100644 public/static/css/skins/skin-green-light.css create mode 100644 public/static/css/skins/skin-green.css create mode 100644 public/static/css/skins/skin-purple-light.css create mode 100644 public/static/css/skins/skin-purple.css create mode 100644 public/static/css/skins/skin-red-light.css create mode 100644 public/static/css/skins/skin-red.css create mode 100644 public/static/css/skins/skin-yellow-light.css create mode 100644 public/static/css/skins/skin-yellow.css create mode 100644 public/static/images/aliyun.ico create mode 100644 public/static/images/baidu.ico create mode 100644 public/static/images/cloudflare.ico create mode 100644 public/static/images/dnspod.ico create mode 100644 public/static/images/error.svg create mode 100644 public/static/images/huawei.ico create mode 100644 public/static/images/info.svg create mode 100644 public/static/images/login-head.png create mode 100644 public/static/images/logo.png create mode 100644 public/static/images/success.svg create mode 100644 public/static/images/user.png create mode 100644 public/static/images/west.ico create mode 100644 public/static/js/app.js create mode 100644 public/static/js/bootstrapValidator.min.js create mode 100644 public/static/js/custom.js create mode 100644 route/app.php create mode 100644 runtime/.gitignore create mode 100644 think diff --git a/.example.env b/.example.env new file mode 100644 index 0000000..1a50053 --- /dev/null +++ b/.example.env @@ -0,0 +1,19 @@ +APP_DEBUG = false + +[APP] +DEFAULT_TIMEZONE = Asia/Shanghai +SYS_KEY = {syskey} + +[DATABASE] +TYPE = mysql +HOSTNAME = {dbhost} +DATABASE = {dbname} +USERNAME = {dbuser} +PASSWORD = {dbpwd} +HOSTPORT = {dbport} +CHARSET = utf8mb4 +PREFIX = {dbprefix} +DEBUG = false + +[LANG] +default_lang = zh-cn \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d465120 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/.idea +/.vscode +/vendor +*.log +.env \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..46f486e --- /dev/null +++ b/README.md @@ -0,0 +1,72 @@ +## 聚合DNS管理系统 + +聚合DNS管理系统可以实现在一个网站内管理多个平台的域名解析,目前已支持的域名平台有: + +- 阿里云 +- 腾讯云 +- 华为云 +- 西部数码 +- CloudFlare + +本系统支持多用户,每个用户可分配不同的域名解析权限;支持API接口,支持获取域名独立DNS控制面板登录链接,方便各种IDC系统对接。 + +### 演示截图 + +添加域名账户 + +![](https://p0.meituan.net/csc/090508cdc7aaabd185ba9c76a8c099f9283946.png) + +域名管理列表 + +![](https://p0.meituan.net/csc/60bf3f607d40f30f152ad1f6ee3be098357839.png) + +域名DNS解析管理,支持解析批量操作 + +![](https://p0.meituan.net/csc/f99c599d4febced404c88672dd50d62c212895.png) + +用户管理添加用户,支持为用户开启API接口 + +![](https://p0.meituan.net/csc/d1bd90bedca9b6cbc5da40286bdb5cd5228438.png) + +### 部署方法 + +* 运行环境要求PHP7.4+,MySQL5.6+ +* 设置网站运行目录为`public` +* 设置伪静态为`ThinkPHP` +* 访问网站,会自动跳转到安装页面,根据提示安装完成 +* 访问首页登录控制面板 + +##### 伪静态规则 + +* Nginx + +``` +location / { + if (!-e $request_filename){ + rewrite ^(.*)$ /index.php?s=$1 last; break; + } +} +``` + +* Apache + +``` + + Options +FollowSymlinks -Multiviews + RewriteEngine On + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] + +``` + +### 版权信息 + +版权所有Copyright © 2023~2024 by 消失的彩虹海(https://blog.cccyun.cn) + +### 其他推荐 + +- [彩虹云主机 - 免备案CDN/虚拟主机](https://www.cccyun.net/) +- [小白云高防云服务器](https://www.xiaobaiyun.cn/aff/GMLPMFOV) + diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 0000000..3418e55 --- /dev/null +++ b/app/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/app/AppService.php b/app/AppService.php new file mode 100644 index 0000000..96556e8 --- /dev/null +++ b/app/AppService.php @@ -0,0 +1,22 @@ +app = $app; + $this->request = $this->app->request; + + // 控制器初始化 + $this->initialize(); + } + + // 初始化 + protected function initialize() + { + $this->clientip = real_ip(env('app.ip_type', 0)); + } + + /** + * 验证数据 + * @access protected + * @param array $data 数据 + * @param string|array $validate 验证器名或者验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @return array|string|true + * @throws ValidateException + */ + protected function validate(array $data, $validate, array $message = [], bool $batch = false) + { + if (is_array($validate)) { + $v = new Validate(); + $v->rule($validate); + } else { + if (strpos($validate, '.')) { + // 支持场景 + [$validate, $scene] = explode('.', $validate); + } + $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate); + $v = new $class(); + if (!empty($scene)) { + $v->scene($scene); + } + } + + $v->message($message); + + // 是否批量验证 + if ($batch || $this->batchValidate) { + $v->batch(true); + } + + return $v->failException(true)->check($data); + } + + + protected function alert($code, $msg = '', $url = null, $wait = 3) + { + if ($url) { + $url = (strpos($url, '://') || 0 === strpos($url, '/')) ? $url : (string)$this->app->route->buildUrl($url); + } + if(empty($msg)) $msg = '未知错误'; + + if (request()->isApi) { + return json(['code'=>$code=='success'?0:-1, 'msg'=>$msg]); + } + if (request()->isAjax()) { + return json(['code'=>$code=='success'?0:-1, 'msg'=>$msg, 'url'=>$url]); + } + + View::assign([ + 'code' => $code, + 'msg' => $msg, + 'url' => $url, + 'wait' => $wait, + ]); + return View::fetch(app()->getBasePath().'view/dispatch_jump.html'); + } +} diff --git a/app/ExceptionHandle.php b/app/ExceptionHandle.php new file mode 100644 index 0000000..453d126 --- /dev/null +++ b/app/ExceptionHandle.php @@ -0,0 +1,58 @@ + 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) { + return substr($result, 26); + } else { + return ''; + } + } else { + return $keyc.base64_encode($result); + } +} + +function random($length, $numeric = 0) { + $seed = base_convert(md5(microtime().$_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35); + $seed = $numeric ? (str_replace('0', '', $seed).'012340567890') : ($seed.'zZ'.strtoupper($seed)); + $hash = ''; + $max = strlen($seed) - 1; + for($i = 0; $i < $length; $i++) { + $hash .= $seed[mt_rand(0, $max)]; + } + return $hash; +} + +function checkDomain($domain){ + if(empty($domain) || !preg_match('/^[-$a-z0-9_*.]{2,512}$/i', $domain) || (stripos($domain, '.') === false) || substr($domain, -1) == '.' || substr($domain, 0 ,1) == '.' || substr($domain, 0 ,1) == '*' && substr($domain, 1 ,1) != '.' || substr_count($domain, '*')>1 || strpos($domain, '*')>0 || strlen($domain)<4) return false; + return true; +} + +function getSubstr($str, $leftStr, $rightStr) +{ + $left = strpos($str, $leftStr); + $start = $left+strlen($leftStr); + $right = strpos($str, $rightStr, $start); + if($left < 0) return ''; + if($right>0){ + return substr($str, $start, $right-$start); + }else{ + return substr($str, $start); + } +} + +function checkRefererHost(){ + if(!request()->header('referer'))return false; + $url_arr = parse_url(request()->header('referer')); + $http_host = request()->header('host'); + if(strpos($http_host,':'))$http_host = substr($http_host, 0, strpos($http_host, ':')); + return $url_arr['host'] === $http_host; +} + +function checkIfActive($string) { + $array=explode(',',$string); + $action = request()->action(); + if (in_array($action,$array)){ + return 'active'; + }else + return null; +} + +function getSid() { + return md5(uniqid(mt_rand(), true) . microtime()); +} +function getMd5Pwd($pwd, $salt=null) { + return md5(md5($pwd) . md5('1277180438'.$salt)); +} + +function isNullOrEmpty($str){ + return $str === null || $str === ''; +} + +function checkPermission($type, $domain = null){ + $user = request()->user; + if(empty($user)) return false; + if($user['level'] == 2) return true; + if($type == 1 && $user['level'] == 1 || $type == 0 && $user['level'] >= 0){ + if($domain == null) return true; + if(in_array($domain, $user['permission'])){ + return true; + } + } + return false; +} + +function getAdminSkin(){ + $skin = cookie('admin_skin'); + if(empty($skin)){ + $skin = cache('admin_skin'); + } + if(empty($skin)){ + $skin = 'skin-black-blue'; + } + return $skin; +} \ No newline at end of file diff --git a/app/controller/Auth.php b/app/controller/Auth.php new file mode 100644 index 0000000..2341ea7 --- /dev/null +++ b/app/controller/Auth.php @@ -0,0 +1,115 @@ +getRuntimePath().'@login.lock'; + + if(request()->islogin){ + return redirect('/'); + } + + if(request()->isAjax()){ + $username = input('post.username',null,'trim'); + $password = input('post.password',null,'trim'); + $code = input('post.code',null,'trim'); + + if(empty($username) || empty($password)){ + return json(['code'=>-1, 'msg'=>'用户名或密码不能为空']); + } + if(!captcha_check($code)){ + return json(['code'=>-1, 'msg'=>'验证码错误', 'vcode'=>1]); + } + if (file_exists($login_limit_file)) { + $login_limit = unserialize(file_get_contents($login_limit_file)); + if ($login_limit['count'] >= $login_limit_count && $login_limit['time'] > time() - 86400) { + exit(json_encode(['code' => -1, 'msg' => '多次登录失败,暂时禁止登录。可删除/runtime/@login.lock文件解除限制', 'vcode'=>1])); + } + } + $user = Db::name('user')->where('username', $username)->find(); + if($user && password_verify($password, $user['password'])){ + if($user['status'] == 0) return json(['code'=>-1, 'msg'=>'此用户已被封禁', 'vcode'=>1]); + Db::name('log')->insert(['uid' => $user['id'], 'action' => '登录后台', 'data' => 'IP:'.$this->clientip, 'addtime' => date("Y-m-d H:i:s")]); + DB::name('user')->where('id', $user['id'])->update(['lasttime' => date("Y-m-d H:i:s")]); + $session = md5($user['id'].$user['password']); + $expiretime = time()+2562000; + $token = authcode("user\t{$user['id']}\t{$session}\t{$expiretime}", 'ENCODE', env('app.sys_key')); + cookie('user_token', $token, ['expire' => $expiretime, 'httponly' => true]); + return json(['code'=>0]); + }else{ + if($user){ + Db::name('log')->insert(['uid' => $user['id'], 'action' => '登录失败', 'data' => 'IP:'.$this->clientip, 'addtime' => date("Y-m-d H:i:s")]); + } + if (!file_exists($login_limit_file)) { + $login_limit = ['count' => 0, 'time' => 0]; + } + $login_limit['count']++; + $login_limit['time'] = time(); + file_put_contents($login_limit_file, serialize($login_limit)); + $retry_times = $login_limit_count - $login_limit['count']; + if ($retry_times == 0) { + return json(['code' => -1, 'msg' => '多次登录失败,暂时禁止登录。可删除/runtime/@login.lock文件解除限制', 'vcode' => 1]); + } else { + return json(['code' => -1, 'msg' => '用户名或密码错误,你还可以尝试' . $retry_times . '次', 'vcode' => 1]); + } + } + } + + return view(); + } + + public function logout() + { + cookie('user_token', null); + return redirect('/login'); + } + + public function quicklogin() + { + $domain = input('get.domain',null,'trim'); + $timestamp = input('get.timestamp',null,'trim'); + $token = input('get.token',null,'trim'); + $sign = input('get.sign',null,'trim'); + if(empty($domain) || empty($timestamp) || empty($token) || empty($sign)){ + return $this->alert('error', '参数错误'); + } + if($timestamp < time()-300 || $timestamp > time()+300){ + return $this->alert('error', '时间戳无效'); + } + if(md5(env('app.sys_key').$domain.$timestamp.$token.env('app.sys_key')) !== $sign){ + return $this->alert('error', '签名错误'); + } + if($token != cache('quicklogin_'.$domain)){ + return $this->alert('error', 'Token无效'); + } + $row = Db::name('domain')->where('name', $domain)->find(); + if(!$row){ + return $this->alert('error', '该域名不存在'); + } + if(!$row['is_sso']){ + return $this->alert('error', '该域名不支持快捷登录'); + } + + Db::name('log')->insert(['uid' => 0, 'action' => '域名快捷登录', 'data' => 'IP:'.$this->clientip, 'addtime' => date("Y-m-d H:i:s"), 'domain' => $domain]); + + $session = md5($row['id'].$row['name']); + $expiretime = time()+2562000; + $token = authcode("domain\t{$row['id']}\t{$session}\t{$expiretime}", 'ENCODE', env('app.sys_key')); + cookie('user_token', $token, ['expire' => $expiretime, 'httponly' => true]); + return redirect('/record/'.$row['id']); + } +} diff --git a/app/controller/Domain.php b/app/controller/Domain.php new file mode 100644 index 0000000..0a79ab7 --- /dev/null +++ b/app/controller/Domain.php @@ -0,0 +1,561 @@ +alert('error', '无权限'); + View::assign('dnsconfig', DnsHelper::$dns_config); + return view(); + } + + public function account_data(){ + if(!checkPermission(2)) return json(['total'=>0, 'rows'=>[]]); + $kw = input('post.kw', null, 'trim'); + $offset = input('post.offset/d'); + $limit = input('post.limit/d'); + + $select = Db::name('account'); + if(!empty($kw)){ + $select->whereLike('ak|remark', '%'.$kw.'%'); + } + $total = $select->count(); + $rows = $select->order('id','desc')->limit($offset, $limit)->select(); + + $list = []; + foreach($rows as $row){ + $row['typename'] = DnsHelper::$dns_config[$row['type']]['name']; + $list[] = $row; + } + + return json(['total'=>$total, 'rows'=>$list]); + } + + public function account_op(){ + if(!checkPermission(2)) return $this->alert('error', '无权限'); + $act = input('param.act'); + if($act == 'get'){ + $id = input('post.id/d'); + $row = Db::name('account')->where('id', $id)->find(); + if(!$row) return json(['code'=>-1, 'msg'=>'域名账户不存在']); + return json(['code'=>0, 'data'=>$row]); + }elseif($act == 'add'){ + $type = input('post.type'); + $ak = input('post.ak', null, 'trim'); + $sk = input('post.sk', null, 'trim'); + $ext = input('post.ext', null, 'trim'); + $remark = input('post.remark', null, 'trim'); + if(empty($ak) || empty($sk)) return json(['code'=>-1, 'msg'=>'AccessKey和SecretKey不能为空']); + if(Db::name('account')->where('type', $type)->where('ak', $ak)->find()){ + return json(['code'=>-1, 'msg'=>'域名账户已存在']); + } + Db::startTrans(); + $id = Db::name('account')->insertGetId([ + 'type' => $type, + 'ak' => $ak, + 'sk' => $sk, + 'ext' => $ext, + 'remark' => $remark, + 'addtime' => date('Y-m-d H:i:s'), + ]); + $dns = DnsHelper::getModel($id); + if($dns){ + if($dns->check()){ + Db::commit(); + return json(['code'=>0, 'msg'=>'添加域名账户成功!']); + }else{ + Db::rollback(); + return json(['code'=>-1, 'msg'=>'验证域名账户失败,'.$dns->getError()]); + } + }else{ + Db::rollback(); + return json(['code'=>-1, 'msg'=>'DNS模块('.$type.')不存在']); + } + + }elseif($act == 'edit'){ + $id = input('post.id/d'); + $row = Db::name('account')->where('id', $id)->find(); + if(!$row) return json(['code'=>-1, 'msg'=>'域名账户不存在']); + $type = input('post.type'); + $ak = input('post.ak', null, 'trim'); + $sk = input('post.sk', null, 'trim'); + $ext = input('post.ext', null, 'trim'); + $remark = input('post.remark', null, 'trim'); + if(empty($ak) || empty($sk)) return json(['code'=>-1, 'msg'=>'AccessKey和SecretKey不能为空']); + if(Db::name('account')->where('type', $type)->where('ak', $ak)->where('id', '<>', $id)->find()){ + return json(['code'=>-1, 'msg'=>'域名账户已存在']); + } + Db::startTrans(); + Db::name('account')->where('id', $id)->update([ + 'type' => $type, + 'ak' => $ak, + 'sk' => $sk, + 'ext' => $ext, + 'remark' => $remark, + ]); + $dns = DnsHelper::getModel($id); + if($dns){ + if($dns->check()){ + Db::commit(); + return json(['code'=>0, 'msg'=>'修改域名账户成功!']); + }else{ + Db::rollback(); + return json(['code'=>-1, 'msg'=>'验证域名账户失败,'.$dns->getError()]); + } + }else{ + Db::rollback(); + return json(['code'=>-1, 'msg'=>'DNS模块('.$type.')不存在']); + } + }elseif($act == 'del'){ + $id = input('post.id/d'); + $dcount = DB::name('domain')->where('aid', $id)->count(); + if($dcount > 0) return json(['code'=>-1, 'msg'=>'该域名账户下存在域名,无法删除']); + Db::name('account')->where('id', $id)->delete(); + return json(['code'=>0]); + } + return json(['code'=>-3]); + } + + + public function domain(){ + if(request()->user['type'] == 'domain'){ + return redirect('/record/'.request()->user['id']); + } + $list = Db::name('account')->select(); + $accounts = []; + $types = []; + foreach($list as $row){ + $accounts[$row['id']] = $row['id'].'_'.DnsHelper::$dns_config[$row['type']]['name']; + if(!array_key_exists($row['type'], $types)){ + $types[$row['type']] = DnsHelper::$dns_config[$row['type']]['name']; + } + if(!empty($row['remark'])){ + $accounts[$row['id']] .= '('.$row['remark'].')'; + } + } + View::assign('accounts', $accounts); + View::assign('types', $types); + return view(); + } + + public function domain_data(){ + if(!checkPermission(1)) return json(['total'=>0, 'rows'=>[]]); + $kw = input('post.kw', null, 'trim'); + $type = input('post.type', null, 'trim'); + $offset = input('post.offset/d', 0); + $limit = input('post.limit/d', 10); + + $select = Db::name('domain')->alias('A')->join('account B','A.aid = B.id'); + if(!empty($kw)){ + $select->whereLike('name', '%'.$kw.'%'); + } + if(!empty($type)){ + $select->whereLike('B.type', $type); + } + if(request()->user['level'] == 1){ + $select->where('is_hide', 0)->where('A.name', 'in', request()->user['permission']); + } + $total = $select->count(); + $rows = $select->fieldRaw('A.*,B.type,B.remark')->order('A.id','desc')->limit($offset, $limit)->select(); + + $list = []; + foreach($rows as $row){ + $row['typename'] = DnsHelper::$dns_config[$row['type']]['name']; + $list[] = $row; + } + + return json(['total'=>$total, 'rows'=>$list]); + } + + public function domain_op(){ + if(!checkPermission(1)) return $this->alert('error', '无权限'); + $act = input('param.act'); + if($act == 'get'){ + $id = input('post.id/d'); + $row = Db::name('domain')->where('id', $id)->find(); + if(!$row) return json(['code'=>-1, 'msg'=>'域名不存在']); + return json(['code'=>0, 'data'=>$row]); + }elseif($act == 'add'){ + if(!checkPermission(2)) return $this->alert('error', '无权限'); + $aid = input('post.aid/d'); + $name = input('post.name', null, 'trim'); + $thirdid = input('post.thirdid', null, 'trim'); + $recordcount = input('post.recordcount/d', 0); + if(empty($name) || empty($thirdid)) return json(['code'=>-1, 'msg'=>'参数不能为空']); + if(Db::name('domain')->where('aid', $aid)->where('name', $name)->find()){ + return json(['code'=>-1, 'msg'=>'域名已存在']); + } + Db::name('domain')->insert([ + 'aid' => $aid, + 'name' => $name, + 'thirdid' => $thirdid, + 'addtime' => date('Y-m-d H:i:s'), + 'is_hide' => 0, + 'is_sso' => 1, + 'recordcount' => $recordcount, + ]); + return json(['code'=>0, 'msg'=>'添加域名成功!']); + }elseif($act == 'edit'){ + if(!checkPermission(2)) return $this->alert('error', '无权限'); + $id = input('post.id/d'); + $row = Db::name('domain')->where('id', $id)->find(); + if(!$row) return json(['code'=>-1, 'msg'=>'域名不存在']); + $is_hide = input('post.is_hide/d'); + $is_sso = input('post.is_sso/d'); + Db::name('domain')->where('id', $id)->update([ + 'is_hide' => $is_hide, + 'is_sso' => $is_sso, + ]); + return json(['code'=>0, 'msg'=>'修改域名配置成功!']); + }elseif($act == 'del'){ + if(!checkPermission(2)) return $this->alert('error', '无权限'); + $id = input('post.id/d'); + Db::name('domain')->where('id', $id)->delete(); + return json(['code'=>0]); + } + return json(['code'=>-3]); + } + + public function domain_list(){ + if(!checkPermission(2)) return $this->alert('error', '无权限'); + $aid = input('post.aid/d'); + $kw = input('post.kw', null, 'trim'); + $page = input('?post.page') ? input('post.page/d') : 1; + $pagesize = input('?post.pagesize') ? input('post.pagesize/d') : 10; + $dns = DnsHelper::getModel($aid); + $list = $dns->getDomainList($kw, $page, $pagesize); + if(!$list) return json(['code'=>-1, 'msg'=>'获取域名列表失败,'.$dns->getError()]); + return json(['code'=>0, 'data'=>$list]); + } + + //获取解析线路和最小TTL + private function get_line_and_ttl($drow){ + $recordLine = cache('record_line_'.$drow['id']); + $minTTL = cache('min_ttl_'.$drow['id']); + if(empty($recordLine)){ + $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); + if(!$dns) return $this->alert('error', 'DNS模块不存在'); + $recordLine = $dns->getRecordLine($drow['name']); + if(!$recordLine) return $this->alert('error', '获取解析线路列表失败,'.$dns->getError()); + cache('record_line_'.$drow['id'], $recordLine, 604800); + $minTTL = $dns->getMinTTL($drow['name']); + if($minTTL){ + cache('min_ttl_'.$drow['id'], $minTTL, 604800); + } + } + return [$recordLine, $minTTL]; + } + + public function domain_info(){ + $id = input('param.id/d'); + $drow = Db::name('domain')->where('id', $id)->find(); + if(!$drow){ + return $this->alert('error', '域名不存在'); + } + $dnstype = Db::name('account')->where('id', $drow['aid'])->value('type'); + if(!checkPermission(0, $drow['name'])) return $this->alert('error', '无权限'); + + list($recordLine, $minTTL) = $this->get_line_and_ttl($drow); + + $recordLineArr = []; + foreach($recordLine as $key=>$item){ + $recordLineArr[] = ['id'=>$key, 'name'=>$item['name'], 'parent'=>$item['parent']]; + } + + $dnsconfig = DnsHelper::$dns_config[$dnstype]; + $dnsconfig['type'] = $dnstype; + + $drow['config'] = $dnsconfig; + $drow['recordLine'] = $recordLineArr; + $drow['minTTL'] = $minTTL?$minTTL:1; + if(input('?post.loginurl') && input('post.loginurl') == '1'){ + $token = getSid(); + cache('quicklogin_'.$drow['name'], $token, 3600); + $timestamp = time(); + $sign = md5(env('app.sys_key').$drow['name'].$timestamp.$token.env('app.sys_key')); + $drow['loginurl'] = request()->root(true).'/quicklogin?domain='.$drow['name'].'×tamp='.$timestamp.'&token='.$token.'&sign='.$sign; + } + + return json(['code'=>0, 'data'=>$drow]); + } + + public function record(){ + $id = input('param.id/d'); + $drow = Db::name('domain')->where('id', $id)->find(); + if(!$drow){ + return $this->alert('error', '域名不存在'); + } + $dnstype = Db::name('account')->where('id', $drow['aid'])->value('type'); + if(!checkPermission(0, $drow['name'])) return $this->alert('error', '无权限'); + + list($recordLine, $minTTL) = $this->get_line_and_ttl($drow); + + $recordLineArr = []; + foreach($recordLine as $key=>$item){ + $recordLineArr[] = ['id'=>$key, 'name'=>$item['name'], 'parent'=>$item['parent']]; + } + + $dnsconfig = DnsHelper::$dns_config[$dnstype]; + $dnsconfig['type'] = $dnstype; + + View::assign('domainId', $id); + View::assign('domainName', $drow['name']); + View::assign('recordLine', $recordLineArr); + View::assign('minTTL', $minTTL?$minTTL:1); + View::assign('dnsconfig', $dnsconfig); + return view(); + } + + public function record_data(){ + $id = input('param.id/d'); + $keyword = input('post.keyword', null, 'trim'); + $subdomain = input('post.subdomain', null, 'trim'); + $type = input('post.type', null, 'trim'); + $line = input('post.line', null, 'trim'); + $status = input('post.status', null, 'trim'); + $offset = input('post.offset/d'); + $limit = input('post.limit/d'); + if($limit == 0){ + $page = 1; + }else{ + $page = $offset/$limit + 1; + } + + $drow = Db::name('domain')->where('id', $id)->find(); + if(!$drow){ + return json(['total'=>0, 'rows'=>[]]); + } + if(!checkPermission(0, $drow['name'])) return json(['total'=>0, 'rows'=>[]]); + + $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); + $domainRecords = $dns->getDomainRecords($page, $limit, $keyword, $subdomain, $type, $line, $status); + if(!$domainRecords) return json(['total'=>0, 'rows'=>[]]); + + if($domainRecords['total'] != $drow['recordcount']){ + Db::name('domain')->where('id', $id)->update(['recordcount'=>$domainRecords['total']]); + } + + $recordLine = cache('record_line_'.$id); + + $list = []; + foreach($domainRecords['list'] as $row){ + $row['LineName'] = isset($recordLine[$row['Line']]) ? $recordLine[$row['Line']]['name'] : $row['Line']; + $list[] = $row; + } + + return json(['total'=>$domainRecords['total'], 'rows'=>$list]); + } + + public function record_add(){ + $id = input('param.id/d'); + $drow = Db::name('domain')->where('id', $id)->find(); + if(!$drow){ + return json(['code'=>-1, 'msg'=>'域名不存在']); + } + if(!checkPermission(0, $drow['name'])) return $this->alert('error', '无权限'); + + $name = input('post.name', null, 'trim'); + $type = input('post.type', null, 'trim'); + $value = input('post.value', null, 'trim'); + $line = input('post.line', null, 'trim'); + $ttl = input('post.ttl/d', 600); + $mx = input('post.mx/d', 1); + $remark = input('post.remark', null, 'trim'); + + if(empty($name) || empty($type) || empty($value)){ + return json(['code'=>-1, 'msg'=>'参数不能为空']); + } + + $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); + $recordid = $dns->addDomainRecord($name, $type, $value, $line, $ttl, $mx, $remark); + if($recordid){ + $this->add_log($drow['name'], '添加解析', $type.'记录 '.$name.' '.$value.' (线路:'.$line.' TTL:'.$ttl.')'); + return json(['code'=>0, 'msg'=>'添加解析记录成功!']); + }else{ + return json(['code'=>-1, 'msg'=>'添加解析记录失败,'.$dns->getError()]); + } + } + + public function record_update(){ + $id = input('param.id/d'); + $drow = Db::name('domain')->where('id', $id)->find(); + if(!$drow){ + return json(['code'=>-1, 'msg'=>'域名不存在']); + } + if(!checkPermission(0, $drow['name'])) return $this->alert('error', '无权限'); + + $recordid = input('post.recordid', null, 'trim'); + $name = input('post.name', null, 'trim'); + $type = input('post.type', null, 'trim'); + $value = input('post.value', null, 'trim'); + $line = input('post.line', null, 'trim'); + $ttl = input('post.ttl/d', 600); + $mx = input('post.mx/d', 1); + $remark = input('post.remark', null, 'trim'); + + if(empty($recordid) || empty($name) || empty($type) || empty($value)){ + return json(['code'=>-1, 'msg'=>'参数不能为空']); + } + + $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); + $recordid = $dns->updateDomainRecord($recordid, $name, $type, $value, $line, $ttl, $mx, $remark); + if($recordid){ + $this->add_log($drow['name'], '修改解析', $type.'记录 '.$name.' '.$value.' (线路:'.$line.' TTL:'.$ttl.')'); + return json(['code'=>0, 'msg'=>'修改解析记录成功!']); + }else{ + return json(['code'=>-1, 'msg'=>'修改解析记录失败,'.$dns->getError()]); + } + } + + public function record_delete(){ + $id = input('param.id/d'); + $drow = Db::name('domain')->where('id', $id)->find(); + if(!$drow){ + return json(['code'=>-1, 'msg'=>'域名不存在']); + } + if(!checkPermission(0, $drow['name'])) return $this->alert('error', '无权限'); + + $recordid = input('post.recordid', null, 'trim'); + + if(empty($recordid)){ + return json(['code'=>-1, 'msg'=>'参数不能为空']); + } + + $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); + if($dns->deleteDomainRecord($recordid)){ + $this->add_log($drow['name'], '删除解析', '记录ID:'.$recordid); + return json(['code'=>0, 'msg'=>'删除解析记录成功!']); + }else{ + return json(['code'=>-1, 'msg'=>'删除解析记录失败,'.$dns->getError()]); + } + } + + public function record_status(){ + $id = input('param.id/d'); + $drow = Db::name('domain')->where('id', $id)->find(); + if(!$drow){ + return json(['code'=>-1, 'msg'=>'域名不存在']); + } + if(!checkPermission(0, $drow['name'])) return $this->alert('error', '无权限'); + + $recordid = input('post.recordid', null, 'trim'); + $status = input('post.status', null, 'trim'); + + if(empty($recordid)){ + return json(['code'=>-1, 'msg'=>'参数不能为空']); + } + + $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); + if($dns->setDomainRecordStatus($recordid, $status)){ + $action = $status == '1' ? '启用解析' : '暂停解析'; + $this->add_log($drow['name'], $action, '记录ID:'.$recordid); + return json(['code'=>0, 'msg'=>'操作成功!']); + }else{ + return json(['code'=>-1, 'msg'=>'操作失败,'.$dns->getError()]); + } + } + + public function record_remark(){ + $id = input('param.id/d'); + $drow = Db::name('domain')->where('id', $id)->find(); + if(!$drow){ + return json(['code'=>-1, 'msg'=>'域名不存在']); + } + if(!checkPermission(0, $drow['name'])) return $this->alert('error', '无权限'); + + $recordid = input('post.recordid', null, 'trim'); + $remark = input('post.remark', null, 'trim'); + + if(empty($recordid)){ + return json(['code'=>-1, 'msg'=>'参数不能为空']); + } + if(empty($remark)) $remark = null; + + $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); + if($dns->updateDomainRecordRemark($recordid, $remark)){ + return json(['code'=>0, 'msg'=>'操作成功!']); + }else{ + return json(['code'=>-1, 'msg'=>'操作失败,'.$dns->getError()]); + } + } + + public function record_batch(){ + $id = input('param.id/d'); + $drow = Db::name('domain')->where('id', $id)->find(); + if(!$drow){ + return json(['code'=>-1, 'msg'=>'域名不存在']); + } + if(!checkPermission(0, $drow['name'])) return $this->alert('error', '无权限'); + + $recordids = input('post.recordids', null, 'trim'); + $action = input('post.action', null, 'trim'); + + if(empty($recordids) || empty($action)){ + return json(['code'=>-1, 'msg'=>'参数不能为空']); + } + + $success = 0; + $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); + if($action == 'open'){ + foreach($recordids as $recordid){ + if($dns->setDomainRecordStatus($recordid, '1')){ + $this->add_log($drow['name'], '启用解析', '记录ID:'.$recordid); + $success++; + } + } + $msg = '成功启用'.$success.'条解析记录'; + }else if($action == 'pause'){ + foreach($recordids as $recordid){ + if($dns->setDomainRecordStatus($recordid, '0')){ + $this->add_log($drow['name'], '暂停解析', '记录ID:'.$recordid); + $success++; + } + } + $msg = '成功暂停'.$success.'条解析记录'; + }else if($action == 'delete'){ + foreach($recordids as $recordid){ + if($dns->deleteDomainRecord($recordid)){ + $this->add_log($drow['name'], '删除解析', '记录ID:'.$recordid); + $success++; + } + } + $msg = '成功删除'.$success.'条解析记录'; + } + return json(['code'=>0, 'msg'=>$msg]); + } + + public function record_log(){ + $id = input('param.id/d'); + $drow = Db::name('domain')->where('id', $id)->find(); + if(!$drow){ + return $this->alert('error', '域名不存在'); + } + if(!checkPermission(0, $drow['name'])) return $this->alert('error', '无权限'); + + if(request()->isPost()){ + $offset = input('post.offset/d'); + $limit = input('post.limit/d'); + $page = $offset/$limit + 1; + $dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']); + $domainRecords = $dns->getDomainRecordLog($page, $limit); + if(!$domainRecords) return json(['total'=>0, 'rows'=>[]]); + return json(['total'=>$domainRecords['total'], 'rows'=>$domainRecords['list']]); + } + + View::assign('domainId', $id); + View::assign('domainName', $drow['name']); + return view('log'); + } + + private function add_log($domain, $action, $data){ + Db::name('log')->insert(['uid' => request()->user['id'], 'domain' => $domain, 'action' => $action, 'data' => $data, 'addtime' => date("Y-m-d H:i:s")]); + } +} \ No newline at end of file diff --git a/app/controller/Index.php b/app/controller/Index.php new file mode 100644 index 0000000..bf4a387 --- /dev/null +++ b/app/controller/Index.php @@ -0,0 +1,96 @@ +user['type'] == 'domain'){ + return redirect('/record/'.request()->user['id']); + } + if(request()->isAjax()){ + if(input('post.do') == 'stat'){ + $stat = ['domains'=>0, 'users'=>0, 'records'=>0, 'types'=>count(DnsHelper::$dns_config)]; + if(request()->user['level'] == 2){ + $stat['domains'] = Db::name('domain')->count(); + $stat['users'] = Db::name('user')->count(); + $stat['records'] = Db::name('domain')->sum('recordcount'); + }else{ + $stat['domains'] = Db::name('domain')->where('name', 'in', request()->user['permission'])->count(); + $stat['users'] = 1; + $stat['records'] = Db::name('domain')->where('name', 'in', request()->user['permission'])->sum('recordcount'); + } + return json($stat); + } + return json(['code'=>-3]); + } + + $tmp = 'version()'; + $mysqlVersion = Db::query("select version()")[0][$tmp]; + $info = [ + 'framework_version' => app()::VERSION, + 'php_version' => PHP_VERSION, + 'mysql_version' => $mysqlVersion, + 'software' => $_SERVER['SERVER_SOFTWARE'], + 'os' => php_uname(), + 'date' => date("Y-m-d H:i:s"), + ]; + View::assign('info', $info); + View::assign('checkupdate', '//auth.cccyun.cc/app/dnsmgr.php?ver='.config('app.version')); + return view(); + } + + public function changeskin(){ + $skin = input('post.skin'); + if(request()->user['level'] == 2){ + if(cookie('admin_skin')){ + cookie('admin_skin', null); + } + cache('admin_skin', $skin); + }else{ + cookie('admin_skin', $skin); + } + return json(['code'=>0,'msg'=>'succ']); + } + + public function cleancache(){ + if(!checkPermission(1)) return $this->alert('error', '无权限'); + Cache::clear(); + return json(['code'=>0,'msg'=>'succ']); + } + + public function doc(){ + if(!checkPermission(1)) return $this->alert('error', '无权限'); + View::assign('siteurl', request()->root(true)); + return view(); + } + + public function setpwd(){ + if(!checkPermission(1)) return $this->alert('error', '无权限'); + if(request()->isPost()){ + $oldpwd = input('post.oldpwd'); + $newpwd = input('post.newpwd'); + $newpwd2 = input('post.newpwd2'); + if(empty($oldpwd) || empty($newpwd) || empty($newpwd2)){ + return json(['code'=>-1, 'msg'=>'密码不能为空']); + } + if($newpwd != $newpwd2){ + return json(['code'=>-1, 'msg'=>'两次输入的密码不一致']); + } + if(!password_verify($oldpwd, request()->user['password'])){ + return json(['code'=>-1, 'msg'=>'原密码错误']); + } + Db::name('user')->where('id', request()->user['id'])->update(['password'=>password_hash($newpwd, PASSWORD_DEFAULT)]); + return json(['code'=>0, 'msg'=>'succ']); + } + return view(); + } + +} diff --git a/app/controller/Install.php b/app/controller/Install.php new file mode 100644 index 0000000..3f39265 --- /dev/null +++ b/app/controller/Install.php @@ -0,0 +1,84 @@ +getRootPath().'.env')){ + return '当前已经安装成功,如果需要重新安装,请手动删除根目录.env文件'; + } + if(request()->isPost()){ + $mysql_host = input('post.mysql_host', null, 'trim'); + $mysql_port = intval(input('post.mysql_port', '3306')); + $mysql_user = input('post.mysql_user', null, 'trim'); + $mysql_pwd = input('post.mysql_pwd', null, 'trim'); + $mysql_name = input('post.mysql_name', null, 'trim'); + $mysql_prefix = input('post.mysql_prefix', 'cloud_', 'trim'); + $admin_username = input('post.admin_username', null, 'trim'); + $admin_password = input('post.admin_password', null, 'trim'); + + if(!$mysql_host || !$mysql_user || !$mysql_pwd || !$mysql_name || !$admin_username || !$admin_password){ + return json(['code'=>0, 'msg'=>'必填项不能为空']); + } + + $configdata = file_get_contents(app()->getRootPath().'.example.env'); + $configdata = str_replace(['{syskey}','{dbhost}','{dbname}','{dbuser}','{dbpwd}','{dbport}','{dbprefix}'], [random(16), $mysql_host, $mysql_name, $mysql_user, $mysql_pwd, $mysql_port, $mysql_prefix], $configdata); + + try{ + $DB=new PDO("mysql:host=".$mysql_host.";dbname=".$mysql_name.";port=".$mysql_port,$mysql_user,$mysql_pwd); + }catch(Exception $e){ + if($e->getCode() == 2002){ + $errorMsg='连接数据库失败:数据库地址填写错误!'; + }elseif($e->getCode() == 1045){ + $errorMsg='连接数据库失败:数据库用户名或密码填写错误!'; + }elseif($e->getCode() == 1049){ + $errorMsg='连接数据库失败:数据库名不存在!'; + }else{ + $errorMsg='连接数据库失败:'.$e->getMessage(); + } + return json(['code'=>0, 'msg'=>$errorMsg]); + } + $DB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); + $DB->exec("set sql_mode = ''"); + $DB->exec("set names utf8"); + + $sqls=file_get_contents(app()->getAppPath().'sql/install.sql'); + $sqls=explode(';', $sqls); + + $password = password_hash($admin_password, PASSWORD_DEFAULT); + $sqls[]="INSERT INTO `".$mysql_prefix."user` (`username`,`password`,`level`,`regtime`,`lasttime`,`status`) VALUES ('".addslashes($admin_username)."', '$password', 2, NOW(), NOW(), 1)"; + + $success=0;$error=0;$errorMsg=null; + foreach ($sqls as $value) { + $value=trim($value); + if(empty($value))continue; + $value = str_replace('dnsmgr_',$mysql_prefix,$value); + if($DB->exec($value)===false){ + $error++; + $dberror=$DB->errorInfo(); + $errorMsg.=$dberror[2]."\n"; + }else{ + $success++; + } + } + if(empty($errorMsg)){ + if(!file_put_contents(app()->getRootPath().'.env', $configdata)){ + return json(['code'=>0, 'msg'=>'保存失败,请确保网站根目录有写入权限']); + } + Cache::clear(); + return json(['code'=>1, 'msg'=>'安装完成!成功执行SQL语句'.$success.'条']); + }else{ + return json(['code'=>0, 'msg'=>$errorMsg]); + } + } + return view(); + } + +} diff --git a/app/controller/User.php b/app/controller/User.php new file mode 100644 index 0000000..99b8ab2 --- /dev/null +++ b/app/controller/User.php @@ -0,0 +1,164 @@ +alert('error', '无权限'); + $list = Db::name('domain')->select(); + $domains = []; + foreach($list as $row){ + $domains[] = $row['name']; + } + View::assign('domains', $domains); + return view(); + } + + public function user_data(){ + if(!checkPermission(2)) return json(['total'=>0, 'rows'=>[]]); + $kw = input('post.kw', null, 'trim'); + $offset = input('post.offset/d'); + $limit = input('post.limit/d'); + + $select = Db::name('user'); + if(!empty($kw)){ + $select->whereLike('id|username', $kw); + } + $total = $select->count(); + $rows = $select->order('id','desc')->limit($offset, $limit)->select(); + + return json(['total'=>$total, 'rows'=>$rows]); + } + + public function user_op(){ + if(!checkPermission(2)) return $this->alert('error', '无权限'); + $act = input('param.act'); + if($act == 'get'){ + $id = input('post.id/d'); + $row = Db::name('user')->where('id', $id)->find(); + if(!$row) return json(['code'=>-1, 'msg'=>'用户不存在']); + $row['permission'] = Db::name('permission')->where('uid', $id)->column('domain'); + return json(['code'=>0, 'data'=>$row]); + }elseif($act == 'add'){ + $username = input('post.username', null, 'trim'); + $password = input('post.password', null, 'trim'); + $is_api = input('post.is_api/d'); + $apikey = input('post.apikey', null, 'trim'); + $level = input('post.level/d'); + if(empty($username) || empty($password)) return json(['code'=>-1, 'msg'=>'用户名或密码不能为空']); + if($is_api ==1 && empty($apikey)) return json(['code'=>-1, 'msg'=>'API密钥不能为空']); + if(Db::name('user')->where('username', $username)->find()){ + return json(['code'=>-1, 'msg'=>'用户名已存在']); + } + $uid = Db::name('user')->insertGetId([ + 'username' => $username, + 'password' => password_hash($password, PASSWORD_DEFAULT), + 'is_api' => $is_api, + 'apikey' => $apikey, + 'level' => $level, + 'regtime' => date('Y-m-d H:i:s'), + 'status' => 1, + ]); + if($level == 1){ + $permission = input('post.permission/a'); + if(!empty($permission)){ + $data = []; + foreach($permission as $domain){ + $data[] = ['uid'=>$uid, 'domain'=>$domain]; + } + Db::name('permission')->insertAll($data); + } + } + return json(['code'=>0, 'msg'=>'添加用户成功!']); + }elseif($act == 'edit'){ + $id = input('post.id/d'); + $row = Db::name('user')->where('id', $id)->find(); + if(!$row) return json(['code'=>-1, 'msg'=>'用户不存在']); + $username = input('post.username', null, 'trim'); + $is_api = input('post.is_api/d'); + $apikey = input('post.apikey', null, 'trim'); + $level = input('post.level/d'); + $repwd = input('post.repwd', null, 'trim'); + if(empty($username)) return json(['code'=>-1, 'msg'=>'用户名不能为空']); + if($is_api ==1 && empty($apikey)) return json(['code'=>-1, 'msg'=>'API密钥不能为空']); + if(Db::name('user')->where('username', $username)->where('id', '<>', $id)->find()){ + return json(['code'=>-1, 'msg'=>'用户名已存在']); + } + if($level == 1 && ($id == 1000 || $id == request()->user['id'])) $level = 2; + Db::name('user')->where('id', $id)->update([ + 'username' => $username, + 'is_api' => $is_api, + 'apikey' => $apikey, + 'level' => $level, + ]); + Db::name('permission')->where(['uid'=>$id])->delete(); + if($level == 1){ + $permission = input('post.permission/a'); + if(!empty($permission)){ + $data = []; + foreach($permission as $domain){ + $data[] = ['uid'=>$id, 'domain'=>$domain]; + } + Db::name('permission')->insertAll($data); + } + } + if(!empty($repwd)){ + Db::name('user')->where('id', $id)->update(['password'=>password_hash($repwd, PASSWORD_DEFAULT)]); + } + return json(['code'=>0, 'msg'=>'修改用户成功!']); + }elseif($act == 'set'){ + $id = input('post.id/d'); + $status = input('post.status/d'); + if($id == 1000) return json(['code'=>-1, 'msg'=>'此用户无法修改状态']); + if($id == request()->user['id']) return json(['code'=>-1, 'msg'=>'当前登录用户无法修改状态']); + Db::name('user')->where('id', $id)->update(['status'=>$status]); + return json(['code'=>0]); + }elseif($act == 'del'){ + $id = input('post.id/d'); + if($id == 1000) return json(['code'=>-1, 'msg'=>'此用户无法删除']); + if($id == request()->user['id']) return json(['code'=>-1, 'msg'=>'当前登录用户无法删除']); + Db::name('user')->where('id', $id)->delete(); + return json(['code'=>0]); + } + return json(['code'=>-3]); + } + + public function log(){ + return view(); + } + + public function log_data(){ + $uid = input('post.uid', null, 'trim'); + $kw = input('post.kw', null, 'trim'); + $domain = input('post.domain', null, 'trim'); + $offset = input('post.offset/d'); + $limit = input('post.limit/d'); + + $select = Db::name('log'); + if(request()->user['type'] == 'domain'){ + $select->where('domain', request()->user['name']); + }elseif(request()->user['level'] == 1){ + $select->where('uid', request()->user['id']); + }elseif(!empty($uid)){ + $select->where('uid', $uid); + } + if(!empty($kw)){ + $select->whereLike('action|data', '%'.$kw.'%'); + } + if(!empty($domain)){ + $select->where('domain', $domain); + } + $total = $select->count(); + $rows = $select->order('id','desc')->limit($offset, $limit)->select(); + + return json(['total'=>$total, 'rows'=>$rows]); + } + +} \ No newline at end of file diff --git a/app/data/huawei_line.json b/app/data/huawei_line.json new file mode 100644 index 0000000..941f3b6 --- /dev/null +++ b/app/data/huawei_line.json @@ -0,0 +1 @@ +{"default_view":{"name":"全网默认","parent":null},"Dianxin":{"name":"电信","parent":null},"Dianxin_Huabei":{"name":"电信_华北地区","parent":"Dianxin"},"Dianxin_Beijing":{"name":"电信_北京","parent":"Dianxin_Huabei"},"Dianxin_Tianjin":{"name":"电信_天津","parent":"Dianxin_Huabei"},"Dianxin_Hebei":{"name":"电信_河北","parent":"Dianxin_Huabei"},"Dianxin_Shanxi":{"name":"电信_山西","parent":"Dianxin_Huabei"},"Dianxin_Neimenggu":{"name":"电信_内蒙古","parent":"Dianxin_Huabei"},"Dianxin_Dongbei":{"name":"电信_东北地区","parent":"Dianxin"},"Dianxin_Liaoning":{"name":"电信_辽宁","parent":"Dianxin_Dongbei"},"Dianxin_Jilin":{"name":"电信_吉林","parent":"Dianxin_Dongbei"},"Dianxin_Heilongjiang":{"name":"电信_黑龙江","parent":"Dianxin_Dongbei"},"Dianxin_Xibei":{"name":"电信_西北地区","parent":"Dianxin"},"Dianxin_Shaanxi":{"name":"电信_陕西","parent":"Dianxin_Xibei"},"Dianxin_Gansu":{"name":"电信_甘肃","parent":"Dianxin_Xibei"},"Dianxin_Qinghai":{"name":"电信_青海","parent":"Dianxin_Xibei"},"Dianxin_Ningxia":{"name":"电信_宁夏","parent":"Dianxin_Xibei"},"Dianxin_Xinjiang":{"name":"电信_新疆","parent":"Dianxin_Xibei"},"Dianxin_Huazhong":{"name":"电信_华中地区","parent":"Dianxin"},"Dianxin_Henan":{"name":"电信_河南","parent":"Dianxin_Huazhong"},"Dianxin_Hubei":{"name":"电信_湖北","parent":"Dianxin_Huazhong"},"Dianxin_Hunan":{"name":"电信_湖南","parent":"Dianxin_Huazhong"},"Dianxin_Huadong":{"name":"电信_华东地区","parent":"Dianxin"},"Dianxin_Shanghai":{"name":"电信_上海","parent":"Dianxin_Huadong"},"Dianxin_Jiangsu":{"name":"电信_江苏","parent":"Dianxin_Huadong"},"Dianxin_Zhejiang":{"name":"电信_浙江","parent":"Dianxin_Huadong"},"Dianxin_Anhui":{"name":"电信_安徽","parent":"Dianxin_Huadong"},"Dianxin_Fujian":{"name":"电信_福建","parent":"Dianxin_Huadong"},"Dianxin_Jiangxi":{"name":"电信_江西","parent":"Dianxin_Huadong"},"Dianxin_Shandong":{"name":"电信_山东","parent":"Dianxin_Huadong"},"Dianxin_Huanan":{"name":"电信_华南地区","parent":"Dianxin"},"Dianxin_Guangdong":{"name":"电信_广东","parent":"Dianxin_Huanan"},"Dianxin_Hainan":{"name":"电信_海南","parent":"Dianxin_Huanan"},"Dianxin_Guangxi":{"name":"电信_广西","parent":"Dianxin_Huanan"},"Dianxin_Xinan":{"name":"电信_西南地区","parent":"Dianxin"},"Dianxin_Chongqing":{"name":"电信_重庆","parent":"Dianxin_Xinan"},"Dianxin_Sichuan":{"name":"电信_四川","parent":"Dianxin_Xinan"},"Dianxin_Guizhou":{"name":"电信_贵州","parent":"Dianxin_Xinan"},"Dianxin_Yunnan":{"name":"电信_云南","parent":"Dianxin_Xinan"},"Dianxin_Xizang":{"name":"电信_西藏","parent":"Dianxin_Xinan"},"Yidong":{"name":"移动","parent":null},"Yidong_Huabei":{"name":"移动_华北地区","parent":"Yidong"},"Yidong_Beijing":{"name":"移动_北京","parent":"Yidong_Huabei"},"Yidong_Tianjin":{"name":"移动_天津","parent":"Yidong_Huabei"},"Yidong_Hebei":{"name":"移动_河北","parent":"Yidong_Huabei"},"Yidong_Shanxi":{"name":"移动_山西","parent":"Yidong_Huabei"},"Yidong_Neimenggu":{"name":"移动_内蒙古","parent":"Yidong_Huabei"},"Yidong_Dongbei":{"name":"移动_东北地区","parent":"Yidong"},"Yidong_Liaoning":{"name":"移动_辽宁","parent":"Yidong_Dongbei"},"Yidong_Jilin":{"name":"移动_吉林","parent":"Yidong_Dongbei"},"Yidong_Heilongjiang":{"name":"移动_黑龙江","parent":"Yidong_Dongbei"},"Yidong_Xibei":{"name":"移动_西北地区","parent":"Yidong"},"Yidong_Shaanxi":{"name":"移动_陕西","parent":"Yidong_Xibei"},"Yidong_Gansu":{"name":"移动_甘肃","parent":"Yidong_Xibei"},"Yidong_Qinghai":{"name":"移动_青海","parent":"Yidong_Xibei"},"Yidong_Ningxia":{"name":"移动_宁夏","parent":"Yidong_Xibei"},"Yidong_Xinjiang":{"name":"移动_新疆","parent":"Yidong_Xibei"},"Yidong_Huazhong":{"name":"移动_华中地区","parent":"Yidong"},"Yidong_Henan":{"name":"移动_河南","parent":"Yidong_Huazhong"},"Yidong_Hubei":{"name":"移动_湖北","parent":"Yidong_Huazhong"},"Yidong_Hunan":{"name":"移动_湖南","parent":"Yidong_Huazhong"},"Yidong_Huadong":{"name":"移动_华东地区","parent":"Yidong"},"Yidong_Shanghai":{"name":"移动_上海","parent":"Yidong_Huadong"},"Yidong_Jiangsu":{"name":"移动_江苏","parent":"Yidong_Huadong"},"Yidong_Zhejiang":{"name":"移动_浙江","parent":"Yidong_Huadong"},"Yidong_Anhui":{"name":"移动_安徽","parent":"Yidong_Huadong"},"Yidong_Fujian":{"name":"移动_福建","parent":"Yidong_Huadong"},"Yidong_Jiangxi":{"name":"移动_江西","parent":"Yidong_Huadong"},"Yidong_Shandong":{"name":"移动_山东","parent":"Yidong_Huadong"},"Yidong_Huanan":{"name":"移动_华南地区","parent":"Yidong"},"Yidong_Guangdong":{"name":"移动_广东","parent":"Yidong_Huanan"},"Yidong_Hainan":{"name":"移动_海南","parent":"Yidong_Huanan"},"Yidong_Guangxi":{"name":"移动_广西","parent":"Yidong_Huanan"},"Yidong_Xinan":{"name":"移动_西南地区","parent":"Yidong"},"Yidong_Chongqing":{"name":"移动_重庆","parent":"Yidong_Xinan"},"Yidong_Sichuan":{"name":"移动_四川","parent":"Yidong_Xinan"},"Yidong_Guizhou":{"name":"移动_贵州","parent":"Yidong_Xinan"},"Yidong_Yunnan":{"name":"移动_云南","parent":"Yidong_Xinan"},"Yidong_Xizang":{"name":"移动_西藏","parent":"Yidong_Xinan"},"Liantong":{"name":"联通","parent":null},"Liantong_Huabei":{"name":"联通_华北地区","parent":"Liantong"},"Liantong_Beijing":{"name":"联通_北京","parent":"Liantong_Huabei"},"Liantong_Tianjin":{"name":"联通_天津","parent":"Liantong_Huabei"},"Liantong_Hebei":{"name":"联通_河北","parent":"Liantong_Huabei"},"Liantong_Shanxi":{"name":"联通_山西","parent":"Liantong_Huabei"},"Liantong_Neimenggu":{"name":"联通_内蒙古","parent":"Liantong_Huabei"},"Liantong_Dongbei":{"name":"联通_东北地区","parent":"Liantong"},"Liantong_Liaoning":{"name":"联通_辽宁","parent":"Liantong_Dongbei"},"Liantong_Jilin":{"name":"联通_吉林","parent":"Liantong_Dongbei"},"Liantong_Heilongjiang":{"name":"联通_黑龙江","parent":"Liantong_Dongbei"},"Liantong_Xibei":{"name":"联通_西北地区","parent":"Liantong"},"Liantong_Shaanxi":{"name":"联通_陕西","parent":"Liantong_Xibei"},"Liantong_Gansu":{"name":"联通_甘肃","parent":"Liantong_Xibei"},"Liantong_Qinghai":{"name":"联通_青海","parent":"Liantong_Xibei"},"Liantong_Ningxia":{"name":"联通_宁夏","parent":"Liantong_Xibei"},"Liantong_Xinjiang":{"name":"联通_新疆","parent":"Liantong_Xibei"},"Liantong_Huazhong":{"name":"联通_华中地区","parent":"Liantong"},"Liantong_Henan":{"name":"联通_河南","parent":"Liantong_Huazhong"},"Liantong_Hubei":{"name":"联通_湖北","parent":"Liantong_Huazhong"},"Liantong_Hunan":{"name":"联通_湖南","parent":"Liantong_Huazhong"},"Liantong_Huadong":{"name":"联通_华东地区","parent":"Liantong"},"Liantong_Shanghai":{"name":"联通_上海","parent":"Liantong_Huadong"},"Liantong_Jiangsu":{"name":"联通_江苏","parent":"Liantong_Huadong"},"Liantong_Zhejiang":{"name":"联通_浙江","parent":"Liantong_Huadong"},"Liantong_Anhui":{"name":"联通_安徽","parent":"Liantong_Huadong"},"Liantong_Fujian":{"name":"联通_福建","parent":"Liantong_Huadong"},"Liantong_Jiangxi":{"name":"联通_江西","parent":"Liantong_Huadong"},"Liantong_Shandong":{"name":"联通_山东","parent":"Liantong_Huadong"},"Liantong_Huanan":{"name":"联通_华南地区","parent":"Liantong"},"Liantong_Guangdong":{"name":"联通_广东","parent":"Liantong_Huanan"},"Liantong_Hainan":{"name":"联通_海南","parent":"Liantong_Huanan"},"Liantong_Guangxi":{"name":"联通_广西","parent":"Liantong_Huanan"},"Liantong_Xinan":{"name":"联通_西南地区","parent":"Liantong"},"Liantong_Chongqing":{"name":"联通_重庆","parent":"Liantong_Xinan"},"Liantong_Sichuan":{"name":"联通_四川","parent":"Liantong_Xinan"},"Liantong_Guizhou":{"name":"联通_贵州","parent":"Liantong_Xinan"},"Liantong_Yunnan":{"name":"联通_云南","parent":"Liantong_Xinan"},"Liantong_Xizang":{"name":"联通_西藏","parent":"Liantong_Xinan"},"Jiaoyuwang":{"name":"教育网","parent":null},"Tietong":{"name":"铁通","parent":null},"Pengboshi":{"name":"鹏博士","parent":null},"Pengboshi_Huabei":{"name":"鹏博士_华北地区","parent":"Pengboshi"},"Pengboshi_Beijing":{"name":"鹏博士_北京","parent":"Pengboshi_Huabei"},"Pengboshi_Tianjin":{"name":"鹏博士_天津","parent":"Pengboshi_Huabei"},"Pengboshi_Hebei":{"name":"鹏博士_河北","parent":"Pengboshi_Huabei"},"Pengboshi_Shanxi":{"name":"鹏博士_山西","parent":"Pengboshi_Huabei"},"Pengboshi_Neimenggu":{"name":"鹏博士_内蒙古","parent":"Pengboshi_Huabei"},"Pengboshi_Dongbei":{"name":"鹏博士_东北地区","parent":"Pengboshi"},"Pengboshi_Liaoning":{"name":"鹏博士_辽宁","parent":"Pengboshi_Dongbei"},"Pengboshi_Jilin":{"name":"鹏博士_吉林","parent":"Pengboshi_Dongbei"},"Pengboshi_Heilongjiang":{"name":"鹏博士_黑龙江","parent":"Pengboshi_Dongbei"},"Pengboshi_Xibei":{"name":"鹏博士_西北地区","parent":"Pengboshi"},"Pengboshi_Shaanxi":{"name":"鹏博士_陕西","parent":"Pengboshi_Xibei"},"Pengboshi_Gansu":{"name":"鹏博士_甘肃","parent":"Pengboshi_Xibei"},"Pengboshi_Qinghai":{"name":"鹏博士_青海","parent":"Pengboshi_Xibei"},"Pengboshi_Ningxia":{"name":"鹏博士_宁夏","parent":"Pengboshi_Xibei"},"Pengboshi_Xinjiang":{"name":"鹏博士_新疆","parent":"Pengboshi_Xibei"},"Pengboshi_Huazhong":{"name":"鹏博士_华中地区","parent":"Pengboshi"},"Pengboshi_Henan":{"name":"鹏博士_河南","parent":"Pengboshi_Huazhong"},"Pengboshi_Hubei":{"name":"鹏博士_湖北","parent":"Pengboshi_Huazhong"},"Pengboshi_Hunan":{"name":"鹏博士_湖南","parent":"Pengboshi_Huazhong"},"Pengboshi_Huadong":{"name":"鹏博士_华东地区","parent":"Pengboshi"},"Pengboshi_Shanghai":{"name":"鹏博士_上海","parent":"Pengboshi_Huadong"},"Pengboshi_Jiangsu":{"name":"鹏博士_江苏","parent":"Pengboshi_Huadong"},"Pengboshi_Zhejiang":{"name":"鹏博士_浙江","parent":"Pengboshi_Huadong"},"Pengboshi_Anhui":{"name":"鹏博士_安徽","parent":"Pengboshi_Huadong"},"Pengboshi_Fujian":{"name":"鹏博士_福建","parent":"Pengboshi_Huadong"},"Pengboshi_Jiangxi":{"name":"鹏博士_江西","parent":"Pengboshi_Huadong"},"Pengboshi_Shandong":{"name":"鹏博士_山东","parent":"Pengboshi_Huadong"},"Pengboshi_Huanan":{"name":"鹏博士_华南地区","parent":"Pengboshi"},"Pengboshi_Guangdong":{"name":"鹏博士_广东","parent":"Pengboshi_Huanan"},"Pengboshi_Hainan":{"name":"鹏博士_海南","parent":"Pengboshi_Huanan"},"Pengboshi_Guangxi":{"name":"鹏博士_广西","parent":"Pengboshi_Huanan"},"Pengboshi_Xinan":{"name":"鹏博士_西南地区","parent":"Pengboshi"},"Pengboshi_Chongqing":{"name":"鹏博士_重庆","parent":"Pengboshi_Xinan"},"Pengboshi_Sichuan":{"name":"鹏博士_四川","parent":"Pengboshi_Xinan"},"Pengboshi_Guizhou":{"name":"鹏博士_贵州","parent":"Pengboshi_Xinan"},"Pengboshi_Yunnan":{"name":"鹏博士_云南","parent":"Pengboshi_Xinan"},"Pengboshi_Xizang":{"name":"鹏博士_西藏","parent":"Pengboshi_Xinan"},"CN":{"name":"中国大陆","parent":null},"Huabei":{"name":"中国大陆_华北地区","parent":"CN"},"Beijing":{"name":"中国大陆_北京","parent":"Huabei"},"Tianjin":{"name":"中国大陆_天津","parent":"Huabei"},"Hebei":{"name":"中国大陆_河北","parent":"Huabei"},"Shanxi":{"name":"中国大陆_山西","parent":"Huabei"},"Neimenggu":{"name":"中国大陆_内蒙古","parent":"Huabei"},"Dongbei":{"name":"中国大陆_东北地区","parent":"CN"},"Liaoning":{"name":"中国大陆_辽宁","parent":"Dongbei"},"Jilin":{"name":"中国大陆_吉林","parent":"Dongbei"},"Heilongjiang":{"name":"中国大陆_黑龙江","parent":"Dongbei"},"Xibei":{"name":"中国大陆_西北地区","parent":"CN"},"Shaanxi":{"name":"中国大陆_陕西","parent":"Xibei"},"Gansu":{"name":"中国大陆_甘肃","parent":"Xibei"},"Qinghai":{"name":"中国大陆_青海","parent":"Xibei"},"Ningxia":{"name":"中国大陆_宁夏","parent":"Xibei"},"Xinjiang":{"name":"中国大陆_新疆","parent":"Xibei"},"Huazhong":{"name":"中国大陆_华中地区","parent":"CN"},"Henan":{"name":"中国大陆_河南","parent":"Huazhong"},"Hubei":{"name":"中国大陆_湖北","parent":"Huazhong"},"Hunan":{"name":"中国大陆_湖南","parent":"Huazhong"},"Huadong":{"name":"中国大陆_华东地区","parent":"CN"},"Shanghai":{"name":"中国大陆_上海","parent":"Huadong"},"Jiangsu":{"name":"中国大陆_江苏","parent":"Huadong"},"Zhejiang":{"name":"中国大陆_浙江","parent":"Huadong"},"Anhui":{"name":"中国大陆_安徽","parent":"Huadong"},"Fujian":{"name":"中国大陆_福建","parent":"Huadong"},"Jiangxi":{"name":"中国大陆_江西","parent":"Huadong"},"Shandong":{"name":"中国大陆_山东","parent":"Huadong"},"Huanan":{"name":"中国大陆_华南地区","parent":"CN"},"Guangdong":{"name":"中国大陆_广东","parent":"Huanan"},"Hainan":{"name":"中国大陆_海南","parent":"Huanan"},"Guangxi":{"name":"中国大陆_广西","parent":"Huanan"},"Xinan":{"name":"中国大陆_西南地区","parent":"CN"},"Chongqing":{"name":"中国大陆_重庆","parent":"Xinan"},"Sichuan":{"name":"中国大陆_四川","parent":"Xinan"},"Guizhou":{"name":"中国大陆_贵州","parent":"Xinan"},"Yunnan":{"name":"中国大陆_云南","parent":"Xinan"},"Xizang":{"name":"中国大陆_西藏","parent":"Xinan"},"Abroad":{"name":"全球","parent":null},"AP":{"name":"全球_亚太地区","parent":"Abroad"},"TW":{"name":"全球_中国台湾","parent":"AP"},"HK":{"name":"全球_中国香港","parent":"AP"},"MO":{"name":"全球_中国澳门","parent":"AP"},"JP":{"name":"全球_日本","parent":"AP"},"KR":{"name":"全球_韩国","parent":"AP"},"IN":{"name":"全球_印度","parent":"AP"},"TR":{"name":"全球_土耳其","parent":"AP"},"ID":{"name":"全球_印度尼西亚","parent":"AP"},"VN":{"name":"全球_越南","parent":"AP"},"SG":{"name":"全球_新加坡","parent":"AP"},"TH":{"name":"全球_泰国","parent":"AP"},"MY":{"name":"全球_马来西亚","parent":"AP"},"BD":{"name":"全球_孟加拉","parent":"AP"},"AE":{"name":"全球_阿联酋","parent":"AP"},"AM":{"name":"全球_亚美尼亚","parent":"AP"},"AZ":{"name":"全球_阿塞拜疆","parent":"AP"},"BH":{"name":"全球_巴林","parent":"AP"},"BN":{"name":"全球_文莱","parent":"AP"},"BT":{"name":"全球_不丹","parent":"AP"},"CX":{"name":"全球_圣诞岛","parent":"AP"},"GE":{"name":"全球_格鲁吉亚","parent":"AP"},"IQ":{"name":"全球_伊拉克","parent":"AP"},"JO":{"name":"全球_约旦","parent":"AP"},"KG":{"name":"全球_吉尔吉斯斯坦","parent":"AP"},"KH":{"name":"全球_柬埔寨","parent":"AP"},"KW":{"name":"全球_科威特","parent":"AP"},"KZ":{"name":"全球_哈萨克斯坦","parent":"AP"},"LB":{"name":"全球_黎巴嫩","parent":"AP"},"LK":{"name":"全球_斯里兰卡","parent":"AP"},"MM":{"name":"全球_缅甸","parent":"AP"},"MN":{"name":"全球_蒙古","parent":"AP"},"MV":{"name":"全球_马尔代夫","parent":"AP"},"NP":{"name":"全球_尼泊尔","parent":"AP"},"OM":{"name":"全球_阿曼","parent":"AP"},"PH":{"name":"全球_菲律宾","parent":"AP"},"PK":{"name":"全球_巴基斯坦","parent":"AP"},"PS":{"name":"全球_巴勒斯坦","parent":"AP"},"QA":{"name":"全球_卡塔尔","parent":"AP"},"SA":{"name":"全球_沙特阿拉伯","parent":"AP"},"TJ":{"name":"全球_塔吉克斯坦","parent":"AP"},"TL":{"name":"全球_东帝汶","parent":"AP"},"TM":{"name":"全球_土库曼斯坦","parent":"AP"},"UZ":{"name":"全球_乌兹别克斯坦","parent":"AP"},"YE":{"name":"全球_也门","parent":"AP"},"CY":{"name":"全球_塞浦路斯","parent":"AP"},"IL":{"name":"全球_以色列","parent":"AP"},"AS":{"name":"全球_美属萨摩亚","parent":"AP"},"CK":{"name":"全球_库克群岛","parent":"AP"},"FM":{"name":"全球_密克罗尼西亚","parent":"AP"},"GU":{"name":"全球_关岛","parent":"AP"},"KI":{"name":"全球_基里巴斯","parent":"AP"},"MH":{"name":"全球_马绍尔群岛","parent":"AP"},"MP":{"name":"全球_北马里亚纳群岛","parent":"AP"},"NC":{"name":"全球_新喀里多尼亚","parent":"AP"},"NF":{"name":"全球_诺福克岛","parent":"AP"},"NR":{"name":"全球_瑙鲁","parent":"AP"},"PF":{"name":"全球_法属波利尼西亚","parent":"AP"},"PG":{"name":"全球_巴布亚新几内亚","parent":"AP"},"PW":{"name":"全球_帕劳","parent":"AP"},"SB":{"name":"全球_所罗门群岛","parent":"AP"},"TK":{"name":"全球_托克劳群岛","parent":"AP"},"TO":{"name":"全球_汤加","parent":"AP"},"TV":{"name":"全球_图瓦卢","parent":"AP"},"VU":{"name":"全球_瓦努阿图","parent":"AP"},"WS":{"name":"全球_萨摩亚","parent":"AP"},"AFG":{"name":"全球_阿富汗","parent":"AP"},"LAO":{"name":"全球_老挝","parent":"AP"},"IR":{"name":"全球_伊朗","parent":"AP"},"SY":{"name":"全球_叙利亚","parent":"AP"},"OA":{"name":"全球_大洋洲","parent":"Abroad"},"AU":{"name":"全球_澳大利亚","parent":"OA"},"NZ":{"name":"全球_新西兰","parent":"OA"},"WF":{"name":"全球_瓦利斯和富图纳","parent":"OA"},"FJ":{"name":"全球_斐济群岛","parent":"OA"},"NU":{"name":"全球_纽埃","parent":"OA"},"EU":{"name":"全球_欧洲","parent":"Abroad"},"GB":{"name":"全球_英国","parent":"EU"},"DE":{"name":"全球_德国","parent":"EU"},"FR":{"name":"全球_法国","parent":"EU"},"IT":{"name":"全球_意大利","parent":"EU"},"RU":{"name":"全球_俄罗斯","parent":"EU"},"ES":{"name":"全球_西班牙","parent":"EU"},"UA":{"name":"全球_乌克兰","parent":"EU"},"NL":{"name":"全球_荷兰","parent":"EU"},"SE":{"name":"全球_瑞典","parent":"EU"},"PL":{"name":"全球_波兰","parent":"EU"},"IO":{"name":"全球_英属印度洋领地","parent":"EU"},"BY":{"name":"全球_白俄罗斯","parent":"EU"},"AD":{"name":"全球_安道尔","parent":"EU"},"AL":{"name":"全球_阿尔巴尼亚","parent":"EU"},"AT":{"name":"全球_奥地利","parent":"EU"},"AX":{"name":"全球_奥兰群岛","parent":"EU"},"BE":{"name":"全球_比利时","parent":"EU"},"BG":{"name":"全球_保加利亚","parent":"EU"},"CH":{"name":"全球_瑞士","parent":"EU"},"CZ":{"name":"全球_捷克","parent":"EU"},"DK":{"name":"全球_丹麦","parent":"EU"},"EE":{"name":"全球_爱沙尼亚","parent":"EU"},"FI":{"name":"全球_芬兰","parent":"EU"},"FO":{"name":"全球_法罗群岛","parent":"EU"},"GG":{"name":"全球_根西岛","parent":"EU"},"GI":{"name":"全球_直布罗陀","parent":"EU"},"GR":{"name":"全球_希腊","parent":"EU"},"HR":{"name":"全球_克罗地亚","parent":"EU"},"HU":{"name":"全球_匈牙利","parent":"EU"},"IE":{"name":"全球_爱尔兰","parent":"EU"},"IM":{"name":"全球_马恩岛","parent":"EU"},"IS":{"name":"全球_冰岛","parent":"EU"},"JE":{"name":"全球_泽西岛","parent":"EU"},"LI":{"name":"全球_列支敦士登","parent":"EU"},"LT":{"name":"全球_立陶宛","parent":"EU"},"LU":{"name":"全球_卢森堡","parent":"EU"},"LV":{"name":"全球_拉脱维亚","parent":"EU"},"MC":{"name":"全球_摩纳哥","parent":"EU"},"MD":{"name":"全球_摩尔多瓦","parent":"EU"},"ME":{"name":"全球_黑山","parent":"EU"},"MK":{"name":"全球_北马其顿","parent":"EU"},"MT":{"name":"全球_马耳他","parent":"EU"},"NO":{"name":"全球_挪威","parent":"EU"},"PT":{"name":"全球_葡萄牙","parent":"EU"},"RO":{"name":"全球_罗马尼亚","parent":"EU"},"RS":{"name":"全球_塞尔维亚","parent":"EU"},"SI":{"name":"全球_斯洛文尼亚","parent":"EU"},"SK":{"name":"全球_斯洛伐克","parent":"EU"},"SM":{"name":"全球_圣马力诺","parent":"EU"},"VA":{"name":"全球_梵蒂冈","parent":"EU"},"XK":{"name":"全球_科索沃","parent":"EU"},"SJ":{"name":"全球_斯瓦尔巴群岛和扬马延岛","parent":"EU"},"BQ":{"name":"全球_荷兰加勒比","parent":"EU"},"NA":{"name":"全球_北美洲","parent":"Abroad"},"US":{"name":"全球_美国","parent":"NA"},"CA":{"name":"全球_加拿大","parent":"NA"},"MX":{"name":"全球_墨西哥","parent":"NA"},"AG":{"name":"全球_安提瓜和巴布达","parent":"NA"},"BB":{"name":"全球_巴巴多斯","parent":"NA"},"BS":{"name":"全球_巴哈马","parent":"NA"},"BZ":{"name":"全球_伯利兹","parent":"NA"},"CR":{"name":"全球_哥斯达黎加","parent":"NA"},"DM":{"name":"全球_多米尼克","parent":"NA"},"DO":{"name":"全球_多米尼加","parent":"NA"},"GD":{"name":"全球_格林纳达","parent":"NA"},"GT":{"name":"全球_危地马拉","parent":"NA"},"HN":{"name":"全球_洪都拉斯","parent":"NA"},"HT":{"name":"全球_海地","parent":"NA"},"JM":{"name":"全球_牙买加","parent":"NA"},"KN":{"name":"全球_圣基茨和尼维斯","parent":"NA"},"KY":{"name":"全球_开曼群岛","parent":"NA"},"LC":{"name":"全球_圣卢西亚","parent":"NA"},"NI":{"name":"全球_尼加拉瓜","parent":"NA"},"PA":{"name":"全球_巴拿马","parent":"NA"},"PR":{"name":"全球_波多黎各","parent":"NA"},"SV":{"name":"全球_萨尔瓦多","parent":"NA"},"TC":{"name":"全球_特克斯和凯科斯群岛","parent":"NA"},"TT":{"name":"全球_特立尼达和多巴哥","parent":"NA"},"VG":{"name":"全球_英属维尔京群岛","parent":"NA"},"VI":{"name":"全球_美属维尔京群岛","parent":"NA"},"VC":{"name":"全球_圣文森特和格林纳丁斯","parent":"NA"},"MF":{"name":"全球_法属圣马丁","parent":"NA"},"PM":{"name":"全球_圣皮艾尔和密克隆群岛","parent":"NA"},"CU":{"name":"全球_古巴","parent":"NA"},"GL":{"name":"全球_格陵兰岛","parent":"NA"},"MQ":{"name":"全球_法属马提尼克群岛-马提尼克","parent":"NA"},"SX":{"name":"全球_荷属圣马丁","parent":"NA"},"LA":{"name":"全球_南美洲","parent":"Abroad"},"BR":{"name":"全球_巴西","parent":"LA"},"AR":{"name":"全球_阿根廷","parent":"LA"},"AI":{"name":"全球_安圭拉","parent":"LA"},"AW":{"name":"全球_阿鲁巴","parent":"LA"},"BL":{"name":"全球_圣巴泰勒米岛","parent":"LA"},"BM":{"name":"全球_百慕大","parent":"LA"},"GP":{"name":"全球_瓜德罗普","parent":"LA"},"MS":{"name":"全球_蒙特塞拉特岛","parent":"LA"},"BO":{"name":"全球_玻利维亚","parent":"LA"},"CL":{"name":"全球_智利","parent":"LA"},"CO":{"name":"全球_哥伦比亚","parent":"LA"},"CW":{"name":"全球_库拉索","parent":"LA"},"EC":{"name":"全球_厄瓜多尔","parent":"LA"},"GF":{"name":"全球_法属圭亚那","parent":"LA"},"GY":{"name":"全球_圭亚那","parent":"LA"},"PE":{"name":"全球_秘鲁","parent":"LA"},"PY":{"name":"全球_巴拉圭","parent":"LA"},"SR":{"name":"全球_苏里南","parent":"LA"},"UY":{"name":"全球_乌拉圭","parent":"LA"},"VE":{"name":"全球_委内瑞拉","parent":"LA"},"AF":{"name":"全球_非洲","parent":"Abroad"},"ZA":{"name":"全球_南非","parent":"AF"},"EG":{"name":"全球_埃及","parent":"AF"},"AO":{"name":"全球_安哥拉","parent":"AF"},"BF":{"name":"全球_布基纳法索","parent":"AF"},"BI":{"name":"全球_布隆迪","parent":"AF"},"BJ":{"name":"全球_贝宁","parent":"AF"},"BW":{"name":"全球_博茨瓦纳","parent":"AF"},"CD":{"name":"全球_刚果金","parent":"AF"},"CF":{"name":"全球_中非","parent":"AF"},"CG":{"name":"全球_刚果布","parent":"AF"},"CI":{"name":"全球_科特迪瓦","parent":"AF"},"CM":{"name":"全球_喀麦隆","parent":"AF"},"CV":{"name":"全球_佛得角","parent":"AF"},"DJ":{"name":"全球_吉布提","parent":"AF"},"DZ":{"name":"全球_阿尔及利亚","parent":"AF"},"ER":{"name":"全球_厄立特里亚","parent":"AF"},"ET":{"name":"全球_埃塞俄比亚","parent":"AF"},"GA":{"name":"全球_加蓬","parent":"AF"},"GH":{"name":"全球_加纳","parent":"AF"},"GM":{"name":"全球_冈比亚","parent":"AF"},"GN":{"name":"全球_几内亚","parent":"AF"},"GQ":{"name":"全球_赤道几内亚","parent":"AF"},"GW":{"name":"全球_几内亚比绍","parent":"AF"},"KE":{"name":"全球_肯尼亚","parent":"AF"},"KM":{"name":"全球_科摩罗","parent":"AF"},"LR":{"name":"全球_利比里亚","parent":"AF"},"LS":{"name":"全球_莱索托","parent":"AF"},"LY":{"name":"全球_利比亚","parent":"AF"},"MA":{"name":"全球_摩洛哥","parent":"AF"},"MG":{"name":"全球_马达加斯加","parent":"AF"},"ML":{"name":"全球_马里","parent":"AF"},"MR":{"name":"全球_毛里塔尼亚","parent":"AF"},"MU":{"name":"全球_毛里求斯","parent":"AF"},"MW":{"name":"全球_马拉维","parent":"AF"},"MZ":{"name":"全球_莫桑比克","parent":"AF"},"NE":{"name":"全球_尼日尔","parent":"AF"},"NG":{"name":"全球_尼日利亚","parent":"AF"},"RE":{"name":"全球_留尼汪","parent":"AF"},"RW":{"name":"全球_卢旺达","parent":"AF"},"SC":{"name":"全球_塞舌尔","parent":"AF"},"SL":{"name":"全球_塞拉利昂","parent":"AF"},"SN":{"name":"全球_塞内加尔","parent":"AF"},"SO":{"name":"全球_索马里","parent":"AF"},"SS":{"name":"全球_南苏丹","parent":"AF"},"ST":{"name":"全球_圣多美和普林西比","parent":"AF"},"SZ":{"name":"全球_斯威士兰","parent":"AF"},"TD":{"name":"全球_乍得","parent":"AF"},"TG":{"name":"全球_多哥","parent":"AF"},"TN":{"name":"全球_突尼斯","parent":"AF"},"TZ":{"name":"全球_坦桑尼亚","parent":"AF"},"UG":{"name":"全球_乌干达","parent":"AF"},"YT":{"name":"全球_马约特","parent":"AF"},"ZM":{"name":"全球_赞比亚","parent":"AF"},"ZW":{"name":"全球_津巴布韦","parent":"AF"},"NAM":{"name":"全球_纳米比亚","parent":"AF"},"SD":{"name":"全球_苏丹","parent":"AF"},"AQ":{"name":"全球_南极洲","parent":"AQ"}} \ No newline at end of file diff --git a/app/event.php b/app/event.php new file mode 100644 index 0000000..e9851bb --- /dev/null +++ b/app/event.php @@ -0,0 +1,17 @@ + [ + ], + + 'listen' => [ + 'AppInit' => [], + 'HttpRun' => [], + 'HttpEnd' => [], + 'LogLevel' => [], + 'LogWrite' => [], + ], + + 'subscribe' => [ + ], +]; diff --git a/app/lib/DnsHelper.php b/app/lib/DnsHelper.php new file mode 100644 index 0000000..48dd544 --- /dev/null +++ b/app/lib/DnsHelper.php @@ -0,0 +1,91 @@ + [ + 'name' => '阿里云', + 'config' => [ + 'ak' => 'AccessKeyId', + 'sk' => 'AccessKeySecret' + ], + 'remark' => 1, //是否支持备注,1单独设置备注,2和记录一起设置 + 'status' => true, //是否支持启用暂停 + 'redirect' => true, //是否支持域名转发 + 'log' => true, //是否支持查看日志 + ], + 'dnspod' => [ + 'name' => '腾讯云', + 'config' => [ + 'ak' => 'SecretId', + 'sk' => 'SecretKey' + ], + 'remark' => 1, + 'status' => true, + 'redirect' => true, + 'log' => true, + ], + 'huawei' => [ + 'name' => '华为云', + 'config' => [ + 'ak' => 'AccessKeyId', + 'sk' => 'SecretAccessKey' + ], + 'remark' => 2, + 'status' => true, + 'redirect' => false, + 'log' => false, + ], + 'west' => [ + 'name' => '西部数码', + 'config' => [ + 'ak' => '用户名', + 'sk' => 'API密码' + ], + 'remark' => 0, + 'status' => false, + 'redirect' => false, + 'log' => false, + ], + 'cloudflare' => [ + 'name' => 'Cloudflare', + 'config' => [ + 'ak' => '邮箱地址', + 'sk' => 'API密钥' + ], + 'remark' => 2, + 'status' => false, + 'redirect' => false, + 'log' => false, + ], + ]; + + public static function getList() + { + return self::$dns_config; + } + + private static function getConfig($aid){ + $account = Db::name('account')->where('id', $aid)->find(); + if(!$account) return false; + return $account; + } + + public static function getModel($aid, $domain = null, $domainid = null) + { + $config = self::getConfig($aid); + if(!$config) return false; + $dnstype = $config['type']; + $class = "\\app\\lib\\dns\\{$dnstype}"; + if(class_exists($class)){ + $config['domain'] = $domain; + $config['domainid'] = $domainid; + $model = new $class($config); + return $model; + } + return false; + } +} \ No newline at end of file diff --git a/app/lib/DnsInterface.php b/app/lib/DnsInterface.php new file mode 100644 index 0000000..0cc915f --- /dev/null +++ b/app/lib/DnsInterface.php @@ -0,0 +1,35 @@ +AccessKeyId = $config['ak']; + $this->AccessKeySecret = $config['sk']; + $this->domain = $config['domain']; + } + + public function getError(){ + return $this->error; + } + + public function check(){ + if($this->getDomainList() != false){ + return true; + } + return false; + } + + //获取域名列表 + public function getDomainList($KeyWord=null, $PageNumber=1, $PageSize=20){ + $param = ['Action' => 'DescribeDomains', 'KeyWord' => $KeyWord, 'PageNumber' => $PageNumber, 'PageSize' => $PageSize]; + $data = $this->request($param, true); + if($data){ + $list = []; + foreach($data['Domains']['Domain'] as $row){ + $list[] = [ + 'DomainId' => $row['DomainId'], + 'Domain' => $row['DomainName'], + 'RecordCount' => $row['RecordCount'], + ]; + } + return ['total' => $data['TotalCount'], 'list' => $list]; + } + return false; + } + + //获取解析记录列表 + public function getDomainRecords($PageNumber=1, $PageSize=20, $KeyWord = null, $SubDomain = null, $Type = null, $Line = null, $Status = null){ + $param = ['Action' => 'DescribeDomainRecords', 'DomainName' => $this->domain, 'PageNumber' => $PageNumber, 'PageSize' => $PageSize]; + if(!empty($SubDomain) || !empty($Type) || !empty($Line)){ + $param += ['SearchMode' => 'ADVANCED', 'RRKeyWord' => $SubDomain, 'ValueKeyWord' => $KeyWord, 'Type' => $Type, 'Line' => $Line, 'ValueKeyWord' => $KeyWord]; + }elseif(!empty($KeyWord)){ + $param += ['KeyWord' => $KeyWord]; + } + if(!isNullOrEmpty($Status)){ + $Status = $Status == '1' ? 'Enable' : 'Disable'; + $param += ['Status' => $Status]; + } + $data = $this->request($param, true); + if($data){ + $list = []; + foreach($data['DomainRecords']['Record'] as $row){ + $list[] = [ + 'RecordId' => $row['RecordId'], + 'Domain' => $row['DomainName'], + 'Name' => $row['RR'], + 'Type' => $row['Type'], + 'Value' => $row['Value'], + 'Line' => $row['Line'], + 'TTL' => $row['TTL'], + 'MX' => isset($row['Priority']) ? $row['Priority'] : null, + 'Status' => $row['Status'] == 'ENABLE' ? '1' : '0', + 'Weight' => isset($row['Weight']) ? $row['Weight'] : null, + 'Remark' => isset($row['Remark']) ? $row['Remark'] : null, + 'UpdateTime' => isset($row['UpdateTimestamp']) ? date('Y-m-d H:i:s', $row['UpdateTimestamp']/1000) : null, + ]; + } + return ['total' => $data['TotalCount'], 'list' => $list]; + } + return false; + } + + //获取子域名解析记录列表 + public function getSubDomainRecords($SubDomain, $PageNumber=1, $PageSize=20, $Type = null, $Line = null){ + $param = ['Action' => 'DescribeSubDomainRecords', 'SubDomain' => $SubDomain, 'PageNumber' => $PageNumber, 'PageSize' => $PageSize, 'Type' => $Type, 'Line' => $Line]; + $data = $this->request($param, true); + if($data){ + $list = []; + foreach($data['DomainRecords']['Record'] as $row){ + $list[] = [ + 'RecordId' => $row['RecordId'], + 'Domain' => $row['DomainName'], + 'Name' => $row['RR'], + 'Type' => $row['Type'], + 'Value' => $row['Value'], + 'Line' => $row['Line'], + 'TTL' => $row['TTL'], + 'MX' => isset($row['Priority']) ? $row['Priority'] : null, + 'Status' => $row['Status'] == 'ENABLE' ? '1' : '0', + 'Weight' => isset($row['Weight']) ? $row['Weight'] : null, + 'Remark' => isset($row['Remark']) ? $row['Remark'] : null, + 'UpdateTime' => isset($row['UpdateTimestamp']) ? date('Y-m-d H:i:s', $row['UpdateTimestamp']/1000) : null, + ]; + } + return ['total' => $data['TotalCount'], 'list' => $list]; + } + return false; + } + + //获取解析记录详细信息 + public function getDomainRecordInfo($RecordId){ + $param = ['Action' => 'DescribeDomainRecordInfo', 'RecordId' => $RecordId]; + $data = $this->request($param, true); + if($data){ + return [ + 'RecordId' => $data['RecordId'], + 'Domain' => $data['DomainName'], + 'Name' => $data['RR'], + 'Type' => $data['Type'], + 'Value' => $data['Value'], + 'Line' => $data['Line'], + 'TTL' => $data['TTL'], + 'MX' => isset($data['Priority']) ? $data['Priority'] : null, + 'Status' => $data['Status'] == 'ENABLE' ? '1' : '0', + 'Weight' => isset($data['Weight']) ? $data['Weight'] : null, + 'Remark' => isset($data['Remark']) ? $data['Remark'] : null, + 'UpdateTime' => isset($row['UpdateTimestamp']) ? date('Y-m-d H:i:s', $data['UpdateTimestamp']/1000) : null, + ]; + } + return false; + } + + //添加解析记录 + public function addDomainRecord($Name, $Type, $Value, $Line = 'default', $TTL = 600, $MX = null, $Remark = null){ + $param = ['Action' => 'AddDomainRecord', 'DomainName' => $this->domain, 'RR' => $Name, 'Type' => $Type, 'Value' => $Value, 'Line' => $this->convertLineCode($Line), 'TTL' => intval($TTL)]; + if($MX){ + $params['Priority'] = intval($MX); + } + $data = $this->request($param, true); + if($data){ + return $data['RecordId']; + } + return false; + } + + //修改解析记录 + public function updateDomainRecord($RecordId, $Name, $Type, $Value, $Line = 'default', $TTL = 600, $MX = null, $Remark = null){ + $param = ['Action' => 'UpdateDomainRecord', 'RecordId' => $RecordId, 'RR' => $Name, 'Type' => $Type, 'Value' => $Value, 'Line' => $this->convertLineCode($Line), 'TTL' => intval($TTL)]; + if($MX){ + $params['Priority'] = intval($MX); + } + return $this->request($param); + } + + //修改解析记录备注 + public function updateDomainRecordRemark($RecordId, $Remark){ + $param = ['Action' => 'UpdateDomainRecordRemark', 'RecordId' => $RecordId, 'Remark' => $Remark]; + return $this->request($param); + } + + //删除解析记录 + public function deleteDomainRecord($RecordId){ + $param = ['Action' => 'DeleteDomainRecord', 'RecordId' => $RecordId]; + return $this->request($param); + } + + //删除子域名的解析记录 + public function deleteSubDomainRecords($SubDomain){ + $param = ['Action' => 'DeleteSubDomainRecords', 'DomainName' => $this->domain, 'RR' => $SubDomain]; + return $this->request($param); + } + + //设置解析记录状态 + public function setDomainRecordStatus($RecordId, $Status){ + $Status = $Status == '1' ? 'Enable' : 'Disable'; + $param = ['Action' => 'SetDomainRecordStatus', 'RecordId' => $RecordId, 'Status' => $Status]; + return $this->request($param); + } + + //获取解析记录操作日志 + public function getDomainRecordLog($PageNumber = 1, $PageSize = 20, $KeyWord = null, $StartDate = null, $endDate = null){ + $param = ['Action' => 'DescribeRecordLogs', 'DomainName' => $this->domain, 'PageNumber' => $PageNumber, 'PageSize' => $PageSize, 'KeyWord' => $KeyWord, 'StartDate' => $StartDate, 'endDate' => $endDate, 'Lang' => 'zh']; + $data = $this->request($param, true); + if($data){ + $list = []; + foreach($data['RecordLogs']['RecordLog'] as $row){ + $list[] = ['time'=>date('Y-m-d H:i:s', intval($row['ActionTimestamp']/1000)), 'data'=>$row['Message']]; + } + return ['total' => $data['TotalCount'], 'list' => $list]; + } + return false; + } + + //获取解析线路列表 + public function getRecordLine(){ + $data = $this->getDomainInfo(); + if($data){ + $list = []; + foreach($data['RecordLines']['RecordLine'] as $row){ + $list[$row['LineCode']] = ['name'=>$row['LineDisplayName'], 'parent'=>isset($row['FatherCode']) ? $row['FatherCode'] : null]; + } + return $list; + } + return false; + } + + //获取域名信息 + public function getDomainInfo(){ + if(!empty($this->domainInfo)) return $this->domainInfo; + $param = ['Action' => 'DescribeDomainInfo', 'DomainName' => $this->domain, 'NeedDetailAttributes' => 'true']; + $data = $this->request($param, true); + if($data){ + $this->domainInfo = $data; + return $data; + } + return false; + } + + //获取域名最低TTL + public function getMinTTL(){ + $data = $this->getDomainInfo(); + if($data){ + return $data['MinTtl']; + } + return false; + } + + private function convertLineCode($line){ + $convert_dict = ['0'=>'default', '10=1'=>'unicom', '10=0'=>'telecom', '10=3'=>'mobile', '10=2'=>'edu', '3=0'=>'oversea', '10=22'=>'btvn', '80=0'=>'search', '7=0'=>'internal']; + if(array_key_exists($line, $convert_dict)){ + return $convert_dict[$line]; + } + return $line; + } + + + private function aliyunSignature($parameters, $accessKeySecret, $method) + { + ksort($parameters); + $canonicalizedQueryString = ''; + foreach ($parameters as $key => $value) { + if($value === null) continue; + $canonicalizedQueryString .= '&' . $this->percentEncode($key). '=' . $this->percentEncode($value); + } + $stringToSign = $method . '&%2F&' . $this->percentEncode(substr($canonicalizedQueryString, 1)); + $signature = base64_encode(hash_hmac("sha1", $stringToSign, $accessKeySecret."&", true)); + + return $signature; + } + private function percentEncode($str) + { + $search = ['+', '*', '%7E']; + $replace = ['%20', '%2A', '~']; + return str_replace($search, $replace, urlencode($str)); + } + private function request($param, $returnData=false){ + if(empty($this->AccessKeyId)||empty($this->AccessKeySecret))return false; + $result = $this->request_do($param, $returnData); + if(!$returnData && $result!==true){ + usleep(50000); + $result = $this->request_do($param, $returnData); + } + return $result; + } + private function request_do($param, $returnData=false){ + if(empty($this->AccessKeyId)||empty($this->AccessKeySecret))return false; + $url='https://'.$this->Endpoint.'/'; + $data=array( + 'Format' => 'JSON', + 'Version' => $this->Version, + 'AccessKeyId' => $this->AccessKeyId, + 'SignatureMethod' => 'HMAC-SHA1', + 'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'), + 'SignatureVersion' => '1.0', + 'SignatureNonce' => random(8)); + $data=array_merge($data, $param); + $data['Signature'] = $this->aliyunSignature($data, $this->AccessKeySecret, 'POST'); + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); + $response = curl_exec($ch); + $errno = curl_errno($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if ($errno) { + $this->setError('Curl error: ' . curl_error($ch)); + } + curl_close($ch); + if ($errno) return false; + + $arr = json_decode($response,true); + if($httpCode==200){ + return $returnData ? $arr : true; + }elseif($arr){ + $this->setError($arr['Message']); + return false; + }else{ + $this->setError('返回数据解析失败'); + return false; + } + } + + private function setError($message){ + $this->error = $message; + //file_put_contents('logs.txt',date('H:i:s').' '.$message."\r\n", FILE_APPEND); + } +} diff --git a/app/lib/dns/baidu.php b/app/lib/dns/baidu.php new file mode 100644 index 0000000..aa16920 --- /dev/null +++ b/app/lib/dns/baidu.php @@ -0,0 +1,330 @@ +AccessKeyId = $config['ak']; + $this->SecretAccessKey = $config['sk']; + $this->domain = $config['domain']; + $this->domainid = $config['domainid']; + } + + public function getError(){ + return $this->error; + } + + public function check(){ + if($this->getDomainList() != false){ + return true; + } + return false; + } + + //获取域名列表 + public function getDomainList($KeyWord=null, $PageNumber=1, $PageSize=20){ + $query = ['name' => $KeyWord]; + $data = $this->send_reuqest('GET', '/v1/dns/zone', $query); + if($data){ + $list = []; + foreach($data['zones'] as $row){ + $list[] = [ + 'DomainId' => $row['id'], + 'Domain' => rtrim($row['name'], '.'), + 'RecordCount' => 0, + ]; + } + return ['total' => count($list), 'list' => $list]; + } + return false; + } + + //获取解析记录列表 + public function getDomainRecords($PageNumber=1, $PageSize=20, $KeyWord = null, $SubDomain = null, $Type = null, $Line = null, $Status = null){ + $marker = cookie('baidu_record_marker'); + $query = ['rr' => $KeyWord]; + if(!isNullOrEmpty(($SubDomain))){ + $param['rr'] = $SubDomain; + } + $data = $this->send_reuqest('GET', '/v1/dns/zone/'.$this->domain.'/record', $query); + if($data){ + $list = []; + foreach($data['records'] as $row){ + $list[] = [ + 'RecordId' => $row['id'], + 'Domain' => $this->domain, + 'Name' => $row['rr'], + 'Type' => $row['type'], + 'Value' => $row['value'], + 'Line' => $row['line'], + 'TTL' => $row['ttl'], + 'MX' => $row['priority'], + 'Status' => $row['status'] == 'running' ? '1' : '0', + 'Weight' => null, + 'Remark' => $row['description'], + 'UpdateTime' => null, + ]; + } + return ['total' => count($list), 'list' => $list]; + } + return false; + } + + //获取子域名解析记录列表 + public function getSubDomainRecords($SubDomain, $PageNumber=1, $PageSize=20, $Type = null, $Line = null){ + $domain_arr = explode('.', $SubDomain); + $domain = $domain_arr[count($domain_arr)-2].'.'.$domain_arr[count($domain_arr)-1]; + $subdomain = rtrim(str_replace($domain,'',$SubDomain),'.'); + if($subdomain == '')$subdomain='@'; + return $this->getDomainRecords($PageNumber, $PageSize, null, $subdomain, $Type, $Line); + } + + //获取解析记录详细信息 + public function getDomainRecordInfo($RecordId){ + $data = $this->send_reuqest('GET', '/v2.1/zones/'.$this->domainid.'/recordsets/'.$RecordId); + if($data){ + return [ + 'RecordId' => $data['id'], + 'Domain' => rtrim($data['zone_name'], '.'), + 'Name' => str_replace('.'.$data['zone_name'], '', $data['name']), + 'Type' => $data['type'], + 'Value' => $data['records'], + 'Line' => $data['line'], + 'TTL' => $data['ttl'], + 'MX' => $data['weight'], + 'Status' => $data['status'] == 'ACTIVE' ? '1' : '0', + 'Weight' => $data['weight'], + 'Remark' => $data['description'], + 'UpdateTime' => $data['updated_at'], + ]; + } + return false; + } + + //添加解析记录 + public function addDomainRecord($Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Remark = null){ + $params = ['rr' => $Name, 'type' => $this->convertType($Type), 'value' => $Value, 'line'=>$Line, 'ttl' => intval($TTL), 'description' => $Remark]; + if($Type == 'MX')$param['priority'] = intval($MX); + $query = ['clientToken' => getSid()]; + return $this->send_reuqest('POST', '/v1/dns/zone/'.$this->domain.'/record', $query, $params); + } + + //修改解析记录 + public function updateDomainRecord($RecordId, $Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Remark = null){ + $params = ['rr' => $Name, 'type' => $this->convertType($Type), 'value' => $Value, 'line'=>$Line, 'ttl' => intval($TTL), 'description' => $Remark]; + if($Type == 'MX')$param['priority'] = intval($MX); + $query = ['clientToken' => getSid()]; + return $this->send_reuqest('PUT', '/v1/dns/zone/'.$this->domain.'/record/'.$RecordId, $query, $params); + } + + //修改解析记录备注 + public function updateDomainRecordRemark($RecordId, $Remark){ + return false; + } + + //删除解析记录 + public function deleteDomainRecord($RecordId){ + $query = ['clientToken' => getSid()]; + return $this->send_reuqest('DELETE', '/v1/dns/zone/'.$this->domain.'/record/'.$RecordId, $query); + } + + //设置解析记录状态 + public function setDomainRecordStatus($RecordId, $Status){ + $Status = $Status == '1' ? 'enable' : 'disable'; + $query = [$Status => '', 'clientToken' => getSid()]; + return $this->send_reuqest('PUT', '/v1/dns/zone/'.$this->domain.'/record/'.$RecordId, $query); + } + + //获取解析记录操作日志 + public function getDomainRecordLog($PageNumber = 1, $PageSize = 20, $KeyWord = null, $StartDate = null, $endDate = null){ + return false; + } + + //获取解析线路列表 + public function getRecordLine(){ + return [ + 'default'=>['name'=>'默认', 'parent'=>null], + 'ct'=>['name'=>'电信', 'parent'=>null], + 'cnc'=>['name'=>'联通', 'parent'=>null], + 'cmnet'=>['name'=>'移动', 'parent'=>null], + 'edu'=>['name'=>'教育网', 'parent'=>null], + 'search'=>['name'=>'搜索引擎(百度)', 'parent'=>null], + ]; + } + + //获取域名概览信息 + public function getDomainInfo(){ + $res = $this->getDomainList($this->domain); + if($res && !empty($res['list'])){ + return $res['list'][0]; + } + return false; + } + + //获取域名最低TTL + public function getMinTTL(){ + return false; + } + + private function convertType($type){ + return $type; + } + + private function send_reuqest($method, $path, $query = null, $params = null){ + if(!empty($query)){ + $query = array_filter($query, function($a){ return $a!==null;}); + } + if(!empty($params)){ + $params = array_filter($params, function($a){ return $a!==null;}); + } + + $time = time(); + $date = gmdate("Y-m-d\TH:i:s\Z", $time); + $body = !empty($params) ? json_encode($params) : ''; + $headers = [ + 'Host' => $this->endpoint, + 'x-bce-date' => $date, + ]; + if($body){ + $headers['Content-Type'] = 'application/json'; + } + + $authorization = $this->generateSign($method, $path, $query, $headers, $time); + $headers['Authorization'] = $authorization; + + $url = 'https://'.$this->endpoint.$path; + if(!empty($query)){ + $url .= '?'.http_build_query($query); + } + $header = []; + foreach($headers as $key => $value){ + $header[] = $key.': '.$value; + } + return $this->curl($method, $url, $body, $header); + } + + private function generateSign($method, $path, $query, $headers, $time){ + $algorithm = "bce-auth-v1"; + + // step 1: build canonical request string + $httpRequestMethod = $method; + $canonicalUri = $this->getCanonicalUri($path); + $canonicalQueryString = $this->getCanonicalQueryString($query); + [$canonicalHeaders, $signedHeaders] = $this->getCanonicalHeaders($headers); + $canonicalRequest = $httpRequestMethod."\n" + .$canonicalUri."\n" + .$canonicalQueryString."\n" + .$canonicalHeaders; + + // step 2: calculate signing key + $date = gmdate("Y-m-d\TH:i:s\Z", $time); + $expirationInSeconds = 1800; + $authString = $algorithm . '/' . $this->AccessKeyId . '/' . $date . '/' . $expirationInSeconds; + $signingKey = hash_hmac('sha256', $authString, $this->SecretAccessKey); + + // step 3: sign string + $signature = hash_hmac("sha256", $canonicalRequest, $signingKey); + + // step 4: build authorization + $authorization = $authString . '/' . $signedHeaders . "/" . $signature; + + return $authorization; + } + + private function escape($str) + { + $search = ['+', '*', '%7E']; + $replace = ['%20', '%2A', '~']; + return str_replace($search, $replace, urlencode($str)); + } + + private function getCanonicalUri($path) + { + if(empty($path)) return '/'; + $uri = str_replace('%2F', '/', $this->escape($path)); + if(substr($uri, 0, 1) !== '/') $uri = '/'.$uri; + return $uri; + } + + private function getCanonicalQueryString($parameters) + { + if(empty($parameters)) return ''; + ksort($parameters); + $canonicalQueryString = ''; + foreach ($parameters as $key => $value) { + if($key == 'authorization') continue; + $canonicalQueryString .= '&' . $this->escape($key). '=' . $this->escape($value); + } + return substr($canonicalQueryString, 1); + } + + private function getCanonicalHeaders($oldheaders){ + $headers = array(); + foreach ($oldheaders as $key => $value) { + $headers[strtolower($key)] = trim($value); + } + ksort($headers); + + $canonicalHeaders = ''; + $signedHeaders = ''; + foreach ($headers as $key => $value) { + $canonicalHeaders .= $this->escape($key) . ':' . $this->escape($value) . "\n"; + $signedHeaders .= $key . ';'; + } + $canonicalHeaders = substr($canonicalHeaders, 0, -1); + $signedHeaders = substr($signedHeaders, 0, -1); + return [$canonicalHeaders, $signedHeaders]; + } + + private function curl($method, $url, $body, $header){ + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); + if(!empty($body)){ + curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + } + $response = curl_exec($ch); + $errno = curl_errno($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if ($errno) { + $this->setError('Curl error: ' . curl_error($ch)); + } + curl_close($ch); + if ($errno) return false; + + if(empty($response) && $httpCode == 200){ + return true; + } + $arr=json_decode($response,true); + if($arr){ + if(isset($arr['code']) && isset($arr['message'])){ + $this->setError($arr['message']); + return false; + }else{ + return $arr; + } + }else{ + $this->setError('返回数据解析失败'); + return false; + } + } + + private function setError($message){ + $this->error = $message; + //file_put_contents('logs.txt',date('H:i:s').' '.$message."\r\n", FILE_APPEND); + } +} \ No newline at end of file diff --git a/app/lib/dns/cloudflare.php b/app/lib/dns/cloudflare.php new file mode 100644 index 0000000..b9dc942 --- /dev/null +++ b/app/lib/dns/cloudflare.php @@ -0,0 +1,237 @@ +Email = $config['ak']; + $this->ApiKey = $config['sk']; + $this->domain = $config['domain']; + $this->domainid = $config['domainid']; + } + + public function getError(){ + return $this->error; + } + + public function check(){ + if($this->getDomainList() != false){ + return true; + } + return false; + } + + //获取域名列表 + public function getDomainList($KeyWord=null, $PageNumber=1, $PageSize=20){ + $param = ['page' => $PageNumber, 'per_page' => $PageSize, 'name' => $KeyWord]; + $data = $this->send_reuqest('GET', '/zones', $param); + if($data){ + $list = []; + foreach($data['result'] as $row){ + $list[] = [ + 'DomainId' => $row['id'], + 'Domain' => $row['name'], + 'RecordCount' => 0, + ]; + } + return ['total' => $data['result_info']['total_count'], 'list' => $list]; + } + return false; + } + + //获取解析记录列表 + public function getDomainRecords($PageNumber=1, $PageSize=20, $KeyWord = null, $SubDomain = null, $Type = null, $Line = null, $Status = null){ + $param = ['name' => $SubDomain, 'type' => $Type, 'search' => $KeyWord, 'page' => $PageNumber, 'per_page' => $PageSize]; + if(!isNullOrEmpty($Line)){ + $param['proxied'] = $Line == '1' ? 'true' : 'false'; + } + $data = $this->send_reuqest('GET', '/zones/'.$this->domainid.'/dns_records', $param); + if($data){ + $list = []; + foreach($data['result'] as $row){ + $list[] = [ + 'RecordId' => $row['id'], + 'Domain' => $row['zone_name'], + 'Name' => str_replace('.'.$row['zone_name'], '', $row['name']), + 'Type' => $row['type'], + 'Value' => $row['content'], + 'Line' => $row['proxied'] ? '1' : '0', + 'TTL' => $row['ttl'], + 'MX' => isset($row['priority']) ? $row['priority'] : null, + 'Status' => $row['locked'] ? '0' : '1', + 'Weight' => null, + 'Remark' => $row['comment'], + 'UpdateTime' => $row['modified_on'], + ]; + } + return ['total' => $data['result_info']['total_count'], 'list' => $list]; + } + return false; + } + + //获取子域名解析记录列表 + public function getSubDomainRecords($SubDomain, $PageNumber=1, $PageSize=20, $Type = null, $Line = null){ + $domain_arr = explode('.', $SubDomain); + $domain = $domain_arr[count($domain_arr)-2].'.'.$domain_arr[count($domain_arr)-1]; + $subdomain = rtrim(str_replace($domain,'',$SubDomain),'.'); + if($subdomain == '')$subdomain='@'; + return $this->getDomainRecords($PageNumber, $PageSize, null, $subdomain, $Type, $Line); + } + + //获取解析记录详细信息 + public function getDomainRecordInfo($RecordId){ + $data = $this->send_reuqest('GET', '/zones/'.$this->domainid.'/dns_records/'.$RecordId); + if($data){ + return [ + 'RecordId' => $data['result']['id'], + 'Domain' => $data['result']['zone_name'], + 'Name' => str_replace('.'.$data['result']['zone_name'], '', $data['result']['name']), + 'Type' => $data['result']['type'], + 'Value' => $data['result']['content'], + 'Line' => $data['result']['proxied'] ? '1' : '0', + 'TTL' => $data['result']['ttl'], + 'MX' => isset($data['result']['priority']) ? $data['result']['priority'] : null, + 'Status' => $data['result']['locked'] ? '0' : '1', + 'Weight' => null, + 'Remark' => $data['result']['comment'], + 'UpdateTime' => $data['result']['modified_on'], + ]; + } + return false; + } + + //添加解析记录 + public function addDomainRecord($Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Remark = null){ + $param = ['name' => $Name, 'type' => $this->convertType($Type), 'content' => $Value, 'proxied' => $Line=='1', 'ttl' => intval($TTL), 'comment' => $Remark]; + if($Type == 'MX')$param['priority'] = intval($MX); + $data = $this->send_reuqest('POST', '/zones/'.$this->domainid.'/dns_records', $param); + return is_array($data) ? $data['result']['id'] : false; + } + + //修改解析记录 + public function updateDomainRecord($RecordId, $Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Remark = null){ + $param = ['name' => $Name, 'type' => $this->convertType($Type), 'content' => $Value, 'proxied' => $Line=='1', 'ttl' => intval($TTL), 'comment' => $Remark]; + if($Type == 'MX')$param['priority'] = intval($MX); + $data = $this->send_reuqest('PATCH', '/zones/'.$this->domainid.'/dns_records/'.$RecordId, $param); + return is_array($data); + } + + //修改解析记录备注 + public function updateDomainRecordRemark($RecordId, $Remark){ + return false; + } + + //删除解析记录 + public function deleteDomainRecord($RecordId){ + $data = $this->send_reuqest('DELETE', '/zones/'.$this->domainid.'/dns_records/'.$RecordId); + return is_array($data); + } + + //设置解析记录状态 + public function setDomainRecordStatus($RecordId, $Status){ + return false; + } + + //获取解析记录操作日志 + public function getDomainRecordLog($PageNumber = 1, $PageSize = 20, $KeyWord = null, $StartDate = null, $endDate = null){ + return false; + } + + //获取解析线路列表 + public function getRecordLine(){ + return ['0'=>['name'=>'仅DNS', 'parent'=>null], '1'=>['name'=>'已代理', 'parent'=>null]]; + } + + //获取域名信息 + public function getDomainInfo(){ + $data = $this->send_reuqest('GET', '/zones/'.$this->domainid); + if($data){ + return $data['result']; + } + return false; + } + + //获取域名最低TTL + public function getMinTTL(){ + return false; + } + + private function convertType($type){ + $convert_dict = ['REDIRECT_URL'=>'URI', 'FORWARD_URL'=>'URI']; + if(array_key_exists($type, $convert_dict)){ + return $convert_dict[$type]; + } + return $type; + } + + private function send_reuqest($method, $path, $params = null){ + $url = $this->baseUrl . $path; + + $headers = [ + 'X-Auth-Email: '.$this->Email, + 'X-Auth-Key: '.$this->ApiKey, + ]; + + $body = ''; + if ($method == 'GET' || $method == 'DELETE') { + if ($params) { + $url .= '?' . http_build_query($params); + } + } else { + $body = json_encode($params); + $headers[] = 'Content-Type: application/json'; + } + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + if ($method == 'POST') { + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + } elseif ($method == 'PUT') { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); + curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + } elseif ($method == 'PATCH') { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH'); + curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + } elseif ($method == 'DELETE') { + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); + } + $response = curl_exec($ch); + $errno = curl_errno($ch); + if ($errno) { + $this->setError('Curl error: ' . curl_error($ch)); + } + curl_close($ch); + if ($errno) return false; + + $arr=json_decode($response,true); + if($arr){ + if($arr['success']){ + return $arr; + }else{ + $this->setError(isset($arr['errors'][0])?$arr['errors'][0]['message']:'未知错误'); + return false; + } + }else{ + $this->setError('返回数据解析失败'); + return false; + } + } + + private function setError($message){ + $this->error = $message; + //file_put_contents('logs.txt',date('H:i:s').' '.$message."\r\n", FILE_APPEND); + } +} \ No newline at end of file diff --git a/app/lib/dns/dnspod.php b/app/lib/dns/dnspod.php new file mode 100644 index 0000000..02f9c2e --- /dev/null +++ b/app/lib/dns/dnspod.php @@ -0,0 +1,362 @@ +SecretId = $config['ak']; + $this->SecretKey = $config['sk']; + $this->domain = $config['domain']; + } + + public function getError(){ + return $this->error; + } + + public function check(){ + if($this->getAccountInfo() != false){ + return true; + } + return false; + } + + //获取域名列表 + public function getDomainList($KeyWord=null, $PageNumber=1, $PageSize=20){ + $action = 'DescribeDomainList'; + $offset = ($PageNumber-1)*$PageSize; + $param = ['Offset' => $offset, 'Limit' => $PageSize, 'Keyword' => $KeyWord]; + $data = $this->send_reuqest($action, $param); + if($data){ + $list = []; + foreach($data['DomainList'] as $row){ + $list[] = [ + 'DomainId' => $row['DomainId'], + 'Domain' => $row['Name'], + 'RecordCount' => $row['RecordCount'], + ]; + } + return ['total' => $data['DomainCountInfo']['DomainTotal'], 'list' => $list]; + } + return false; + } + + //获取解析记录列表 + public function getDomainRecords($PageNumber=1, $PageSize=20, $KeyWord = null, $SubDomain = null, $Type = null, $Line = null, $Status = null){ + $offset = ($PageNumber-1)*$PageSize; + if(!isNullOrEmpty($Status)){ + $action = 'DescribeRecordFilterList'; + $Status = $Status == '1' ? 'ENABLE' : 'DISABLE'; + $param = ['Domain' => $this->domain, 'Subdomain' => $SubDomain, 'Keyword' => $KeyWord, 'Offset' => $offset, 'Limit' => $PageSize, 'RecordStatus' => [$Status]]; + if(!isNullOrEmpty($Type)) $param['RecordType'] = [$Type]; + if(!isNullOrEmpty($Line)) $param['RecordLine'] = [$Line]; + }else{ + $action = 'DescribeRecordList'; + $param = ['Domain' => $this->domain, 'Subdomain' => $SubDomain, 'RecordType' => $Type, 'RecordLineId' => $Line, 'Keyword' => $KeyWord, 'Offset' => $offset, 'Limit' => $PageSize]; + } + $data = $this->send_reuqest($action, $param); + if($data){ + $list = []; + foreach($data['RecordList'] as $row){ + //if($row['Name'] == '@' && $row['Type'] == 'NS') continue; + $list[] = [ + 'RecordId' => $row['RecordId'], + 'Domain' => $this->domain, + 'Name' => $row['Name'], + 'Type' => $row['Type'], + 'Value' => $row['Value'], + 'Line' => $row['LineId'], + 'TTL' => $row['TTL'], + 'MX' => $row['MX'], + 'Status' => $row['Status'] == 'ENABLE' ? '1' : '0', + 'Weight' => $row['Weight'], + 'Remark' => $row['Remark'], + 'UpdateTime' => $row['UpdatedOn'], + ]; + } + return ['total' => $data['RecordCountInfo']['TotalCount'], 'list' => $list]; + } + return false; + } + + //获取子域名解析记录列表 + public function getSubDomainRecords($SubDomain, $PageNumber=1, $PageSize=20, $Type = null, $Line = null){ + $domain_arr = explode('.', $SubDomain); + $domain = $domain_arr[count($domain_arr)-2].'.'.$domain_arr[count($domain_arr)-1]; + $subdomain = rtrim(str_replace($domain,'',$SubDomain),'.'); + if($subdomain == '')$subdomain='@'; + return $this->getDomainRecords($PageNumber, $PageSize, null, $subdomain, $Type, $Line); + } + + //获取解析记录详细信息 + public function getDomainRecordInfo($RecordId){ + $action = 'DescribeRecord'; + $param = ['Domain' => $this->domain, 'RecordId' => intval($RecordId)]; + $data = $this->send_reuqest($action, $param); + if($data){ + return [ + 'RecordId' => $data['RecordInfo']['Id'], + 'Domain' => $this->domain, + 'Name' => $data['RecordInfo']['SubDomain'], + 'Type' => $data['RecordInfo']['RecordType'], + 'Value' => $data['RecordInfo']['Value'], + 'Line' => $data['RecordInfo']['RecordLineId'], + 'TTL' => $data['RecordInfo']['TTL'], + 'MX' => $data['RecordInfo']['MX'], + 'Status' => $data['RecordInfo']['Enabled'] == 1 ? '1' : '0', + 'Weight' => $data['RecordInfo']['Weight'], + 'Remark' => $data['RecordInfo']['Remark'], + 'UpdateTime' => $data['RecordInfo']['UpdatedOn'], + ]; + } + return false; + } + + //添加解析记录 + public function addDomainRecord($Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Remark = null){ + $action = 'CreateRecord'; + $param = ['Domain' => $this->domain, 'SubDomain' => $Name, 'RecordType' => $this->convertType($Type), 'Value' => $Value, 'RecordLine'=>$Line, 'RecordLineId' => $this->convertLineCode($Line), 'TTL' => intval($TTL)]; + if($Type == 'MX')$param['MX'] = intval($MX); + $data = $this->send_reuqest($action, $param); + return is_array($data) ? $data['RecordId'] : false; + } + + //修改解析记录 + public function updateDomainRecord($RecordId, $Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Remark = null){ + $action = 'ModifyRecord'; + $param = ['Domain' => $this->domain, 'RecordId' => intval($RecordId), 'SubDomain' => $Name, 'RecordType' => $this->convertType($Type), 'Value' => $Value, 'RecordLine'=>$Line, 'RecordLineId' => $this->convertLineCode($Line), 'TTL' => intval($TTL)]; + if($Type == 'MX')$param['MX'] = intval($MX); + $data = $this->send_reuqest($action, $param); + return is_array($data); + } + + //修改解析记录备注 + public function updateDomainRecordRemark($RecordId, $Remark){ + $action = 'ModifyRecordRemark'; + $param = ['Domain' => $this->domain, 'RecordId' => intval($RecordId), 'Remark' => $Remark]; + $data = $this->send_reuqest($action, $param); + return is_array($data); + } + + //删除解析记录 + public function deleteDomainRecord($RecordId){ + $action = 'DeleteRecord'; + $param = ['Domain' => $this->domain, 'RecordId' => intval($RecordId)]; + $data = $this->send_reuqest($action, $param); + return is_array($data); + } + + //设置解析记录状态 + public function setDomainRecordStatus($RecordId, $Status){ + $Status = $Status == '1' ? 'ENABLE' : 'DISABLE'; + $action = 'ModifyRecordStatus'; + $param = ['Domain' => $this->domain, 'RecordId' => intval($RecordId), 'Status' => $Status]; + $data = $this->send_reuqest($action, $param); + return is_array($data); + } + + //获取解析记录操作日志 + public function getDomainRecordLog($PageNumber = 1, $PageSize = 20, $KeyWord = null, $StartDate = null, $endDate = null){ + $action = 'DescribeDomainLogList'; + $offset = ($PageNumber-1)*$PageSize; + $param = ['Domain' => $this->domain, 'Offset' => $offset, 'Limit' => $PageSize]; + $data = $this->send_reuqest($action, $param); + if($data){ + $list = []; + foreach($data['LogList'] as $row){ + $list[] = ['time'=>substr($row, 0, strpos($row,'(')), 'ip'=>substr($row, strpos($row,'(')+1, strpos($row,')')-strpos($row,'(')-1), 'data'=>substr($row, strpos($row,')')+1, strpos($row,' Uin:')-strpos($row,')')-1)]; + } + return ['total' => $data['TotalCount'], 'list' => $list]; + } + return false; + } + + //获取解析线路列表 + public function getRecordLine(){ + $action = 'DescribeRecordLineCategoryList'; + $param = ['Domain' => $this->domain]; + $data = $this->send_reuqest($action, $param); + if($data){ + $list = []; + $this->processLineList($list, $data['LineList'], null); + return $list; + } + return false; + } + + private function processLineList(&$list, $line_list, $parent){ + foreach($line_list as $row){ + if(!isNullOrEmpty($row['LineId']) && $row['Useful'] && !isset($list[$row['LineId']])){ + $list[$row['LineId']] = ['name'=>$row['LineName'], 'parent'=>$parent]; + if($row['SubGroup']){ + $this->processLineList($list, $row['SubGroup'], $row['LineId']); + } + } + } + } + + //获取域名概览信息 + public function getDomainInfo(){ + $action = 'DescribeDomainPreview'; + $param = ['Domain' => $this->domain]; + $data = $this->send_reuqest($action, $param); + if($data){ + return $data['Domain']; + } + return false; + } + + //获取域名权限 + public function getDomainPurview(){ + $action = 'DescribeDomainPurview'; + $param = ['Domain' => $this->domain]; + $data = $this->send_reuqest($action, $param); + if($data){ + return $data['PurviewList']; + } + return false; + } + + //获取域名最低TTL + public function getMinTTL(){ + $PurviewList = $this->getDomainPurview(); + if($PurviewList){ + foreach($PurviewList as $row){ + if($row['Name'] == '记录 TTL 最低'){ + return intval($row['Value']); + } + } + } + return false; + } + + //获取用户信息 + public function getAccountInfo(){ + $action = 'DescribeUserDetail'; + $param = []; + $data = $this->send_reuqest($action, $param); + if($data){ + return $data['UserInfo']; + } + return false; + } + + private function convertLineCode($line){ + $convert_dict = ['default'=>'0', 'unicom'=>'10=1', 'telecom'=>'10=0', 'mobile'=>'10=3', 'edu'=>'10=2', 'oversea'=>'3=0', 'btvn'=>'10=22', 'search'=>'80=0', 'internal'=>'7=0']; + if(array_key_exists($line, $convert_dict)){ + return $convert_dict[$line]; + } + return $line; + } + + private function convertType($type){ + $convert_dict = ['REDIRECT_URL'=>'显性URL', 'FORWARD_URL'=>'隐性URL']; + if(array_key_exists($type, $convert_dict)){ + return $convert_dict[$type]; + } + return $type; + } + + + private function send_reuqest($action, $param){ + $param = array_filter($param, function($a){ return $a!==null;}); + if(!$param) $param = (object)[]; + $payload = json_encode($param); + $time = time(); + $authorization = $this->generateSign($payload, $time); + $header = [ + 'Authorization: '.$authorization, + 'Content-Type: application/json; charset=utf-8', + 'X-TC-Action: '.$action, + 'X-TC-Timestamp: '.$time, + 'X-TC-Version: '.$this->version, + ]; + return $this->curl_post($payload, $header); + } + + private function generateSign($payload, $time){ + $algorithm = "TC3-HMAC-SHA256"; + + // step 1: build canonical request string + $httpRequestMethod = "POST"; + $canonicalUri = "/"; + $canonicalQueryString = ""; + $canonicalHeaders = "content-type:application/json; charset=utf-8\n"."host:".$this->endpoint."\n"; + $signedHeaders = "content-type;host"; + $hashedRequestPayload = hash("SHA256", $payload); + $canonicalRequest = $httpRequestMethod."\n" + .$canonicalUri."\n" + .$canonicalQueryString."\n" + .$canonicalHeaders."\n" + .$signedHeaders."\n" + .$hashedRequestPayload; + + // step 2: build string to sign + $date = gmdate("Y-m-d", $time); + $credentialScope = $date."/".$this->service."/tc3_request"; + $hashedCanonicalRequest = hash("SHA256", $canonicalRequest); + $stringToSign = $algorithm."\n" + .$time."\n" + .$credentialScope."\n" + .$hashedCanonicalRequest; + + // step 3: sign string + $secretDate = hash_hmac("SHA256", $date, "TC3".$this->SecretKey, true); + $secretService = hash_hmac("SHA256", $this->service, $secretDate, true); + $secretSigning = hash_hmac("SHA256", "tc3_request", $secretService, true); + $signature = hash_hmac("SHA256", $stringToSign, $secretSigning); + + // step 4: build authorization + $authorization = $algorithm + ." Credential=".$this->SecretId."/".$credentialScope + .", SignedHeaders=content-type;host, Signature=".$signature; + + return $authorization; + } + + private function curl_post($payload, $header){ + $url = 'https://'.$this->endpoint.'/'; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); + $response = curl_exec($ch); + $errno = curl_errno($ch); + if ($errno) { + $this->setError('Curl error: ' . curl_error($ch)); + } + curl_close($ch); + if ($errno) return false; + + $arr=json_decode($response,true); + if($arr){ + if(isset($arr['Response']['Error'])){ + $this->setError($arr['Response']['Error']['Message']); + return false; + }else{ + return $arr['Response']; + } + }else{ + $this->setError('返回数据解析失败'); + return false; + } + } + + private function setError($message){ + $this->error = $message; + //file_put_contents('logs.txt',date('H:i:s').' '.$message."\r\n", FILE_APPEND); + } +} \ No newline at end of file diff --git a/app/lib/dns/huawei.php b/app/lib/dns/huawei.php new file mode 100644 index 0000000..9565d3f --- /dev/null +++ b/app/lib/dns/huawei.php @@ -0,0 +1,345 @@ +AccessKeyId = $config['ak']; + $this->SecretAccessKey = $config['sk']; + $this->domain = $config['domain']; + $this->domainid = $config['domainid']; + } + + public function getError(){ + return $this->error; + } + + public function check(){ + if($this->getDomainList() != false){ + return true; + } + return false; + } + + //获取域名列表 + public function getDomainList($KeyWord=null, $PageNumber=1, $PageSize=20){ + $offset = ($PageNumber-1)*$PageSize; + $query = ['offset' => $offset, 'limit' => $PageSize, 'name' => $KeyWord]; + $data = $this->send_reuqest('GET', '/v2/zones', $query); + if($data){ + $list = []; + foreach($data['zones'] as $row){ + $list[] = [ + 'DomainId' => $row['id'], + 'Domain' => rtrim($row['name'], '.'), + 'RecordCount' => $row['record_num'], + ]; + } + return ['total' => $data['metadata']['total_count'], 'list' => $list]; + } + return false; + } + + //获取解析记录列表 + public function getDomainRecords($PageNumber=1, $PageSize=20, $KeyWord = null, $SubDomain = null, $Type = null, $Line = null, $Status = null){ + $offset = ($PageNumber-1)*$PageSize; + $query = ['type' => $Type, 'line_id' => $Line, 'name' => $KeyWord, 'status' => $Status, 'offset' => $offset, 'limit' => $PageSize]; + if(!isNullOrEmpty(($SubDomain))){ + $param['name'] = $SubDomain; + } + $data = $this->send_reuqest('GET', '/v2.1/zones/'.$this->domainid.'/recordsets', $query); + if($data){ + $list = []; + foreach($data['recordsets'] as $row){ + if($row['name'] == $row['zone_name']) $row['name'] = '@'; + $list[] = [ + 'RecordId' => $row['id'], + 'Domain' => rtrim($row['zone_name'], '.'), + 'Name' => str_replace('.'.$row['zone_name'], '', $row['name']), + 'Type' => $row['type'], + 'Value' => $row['records'], + 'Line' => $row['line'], + 'TTL' => $row['ttl'], + 'MX' => $row['weight'], + 'Status' => $row['status'] == 'ACTIVE' ? '1' : '0', + 'Weight' => $row['weight'], + 'Remark' => $row['description'], + 'UpdateTime' => $row['updated_at'], + ]; + } + return ['total' => $data['metadata']['total_count'], 'list' => $list]; + } + return false; + } + + //获取子域名解析记录列表 + public function getSubDomainRecords($SubDomain, $PageNumber=1, $PageSize=20, $Type = null, $Line = null){ + $domain_arr = explode('.', $SubDomain); + $domain = $domain_arr[count($domain_arr)-2].'.'.$domain_arr[count($domain_arr)-1]; + $subdomain = rtrim(str_replace($domain,'',$SubDomain),'.'); + if($subdomain == '')$subdomain='@'; + return $this->getDomainRecords($PageNumber, $PageSize, null, $subdomain, $Type, $Line); + } + + //获取解析记录详细信息 + public function getDomainRecordInfo($RecordId){ + $data = $this->send_reuqest('GET', '/v2.1/zones/'.$this->domainid.'/recordsets/'.$RecordId); + if($data){ + return [ + 'RecordId' => $data['id'], + 'Domain' => rtrim($data['zone_name'], '.'), + 'Name' => str_replace('.'.$data['zone_name'], '', $data['name']), + 'Type' => $data['type'], + 'Value' => $data['records'], + 'Line' => $data['line'], + 'TTL' => $data['ttl'], + 'MX' => $data['weight'], + 'Status' => $data['status'] == 'ACTIVE' ? '1' : '0', + 'Weight' => $data['weight'], + 'Remark' => $data['description'], + 'UpdateTime' => $data['updated_at'], + ]; + } + return false; + } + + //添加解析记录 + public function addDomainRecord($Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Remark = null){ + if($Name == '@') $Name = ''; + else $Name .= '.'; + $Name .= $this->domain . '.'; + $params = ['name' => $Name, 'type' => $this->convertType($Type), 'records' => [$Value], 'line'=>$Line, 'ttl' => intval($TTL), 'description' => $Remark]; + if($Type == 'MX')$param['weight'] = intval($MX); + $data = $this->send_reuqest('POST', '/v2.1/zones/'.$this->domainid.'/recordsets', null, $params); + return is_array($data) ? $data['id'] : false; + } + + //修改解析记录 + public function updateDomainRecord($RecordId, $Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Remark = null){ + if($Name == '@') $Name = ''; + else $Name .= '.'; + $Name .= $this->domain . '.'; + $params = ['name' => $Name, 'type' => $this->convertType($Type), 'records' => [$Value], 'line'=>$Line, 'ttl' => intval($TTL), 'description' => $Remark]; + if($Type == 'MX')$param['weight'] = intval($MX); + $data = $this->send_reuqest('PUT', '/v2.1/zones/'.$this->domainid.'/recordsets/'.$RecordId, null, $params); + return is_array($data); + } + + //修改解析记录备注 + public function updateDomainRecordRemark($RecordId, $Remark){ + return false; + } + + //删除解析记录 + public function deleteDomainRecord($RecordId){ + $data = $this->send_reuqest('DELETE', '/v2.1/zones/'.$this->domainid.'/recordsets/'.$RecordId); + return is_array($data); + } + + //设置解析记录状态 + public function setDomainRecordStatus($RecordId, $Status){ + $Status = $Status == '1' ? 'ENABLE' : 'DISABLE'; + $params = ['status' => $Status]; + $data = $this->send_reuqest('PUT', '/v2.1/recordsets/'.$RecordId.'/statuses/set', null, $params); + return is_array($data); + } + + //获取解析记录操作日志 + public function getDomainRecordLog($PageNumber = 1, $PageSize = 20, $KeyWord = null, $StartDate = null, $endDate = null){ + return false; + } + + //获取解析线路列表 + public function getRecordLine(){ + $file_path = app()->getBasePath().'data'.DIRECTORY_SEPARATOR.'huawei_line.json'; + $content = file_get_contents($file_path); + $data = json_decode($content, true); + if($data){ + return $data; + $list = [$data['DEFAULT']['id'] => ['name'=>$data['DEFAULT']['zh'], 'parent'=>null]]; + $this->processLineList($list, $data['ISP'], null, 1, 1); + $this->processLineList($list, $data['REGION'], null, null, 1); + //file_put_contents($file_path, json_encode($list, JSON_UNESCAPED_UNICODE)); + return $list; + } + return false; + } + + private function processLineList(&$list, $line_list, $parent, $rootId = null, $rootName = null){ + foreach($line_list as $row){ + if($rootId && $rootId!==1){ + $row['id'] = $rootId.'_'.$row['id']; + } + if($rootName && $rootName!==1){ + $row['zh'] = $rootName.'_'.$row['zh']; + } + $list[$row['id']] = ['name'=>$row['zh'], 'parent'=>$parent]; + if(isset($row['children']) && !empty($row['children'])){ + $this->processLineList($list, $row['children'], $row['id'], $rootId === 1 ? $row['id'] : $rootId, $rootName === 1 ? $row['zh'] : $rootName); + } + } + } + + //获取域名概览信息 + public function getDomainInfo(){ + return $this->send_reuqest('GET', '/v2/zones/'.$this->domainid); + } + + //获取域名最低TTL + public function getMinTTL(){ + return false; + } + + private function convertType($type){ + return $type; + } + + private function send_reuqest($method, $path, $query = null, $params = null){ + if(!empty($query)){ + $query = array_filter($query, function($a){ return $a!==null;}); + } + if(!empty($params)){ + $params = array_filter($params, function($a){ return $a!==null;}); + } + + $time = time(); + $date = gmdate("Ymd\THis\Z", $time); + $body = !empty($params) ? json_encode($params) : ''; + $headers = [ + 'Host' => $this->endpoint, + 'X-Sdk-Date' => $date, + ]; + if($body){ + $headers['Content-Type'] = 'application/json'; + } + + $authorization = $this->generateSign($method, $path, $query, $headers, $body, $time); + $headers['Authorization'] = $authorization; + + $url = 'https://'.$this->endpoint.$path; + if(!empty($query)){ + $url .= '?'.http_build_query($query); + } + $header = []; + foreach($headers as $key => $value){ + $header[] = $key.': '.$value; + } + return $this->curl($method, $url, $body, $header); + } + + private function generateSign($method, $path, $query, $headers, $body, $time){ + $algorithm = "SDK-HMAC-SHA256"; + + // step 1: build canonical request string + $httpRequestMethod = $method; + $canonicalUri = $path; + if(substr($canonicalUri, -1) != "/") $canonicalUri .= "/"; + $canonicalQueryString = $this->getCanonicalQueryString($query); + [$canonicalHeaders, $signedHeaders] = $this->getCanonicalHeaders($headers); + $hashedRequestPayload = hash("sha256", $body); + $canonicalRequest = $httpRequestMethod."\n" + .$canonicalUri."\n" + .$canonicalQueryString."\n" + .$canonicalHeaders."\n" + .$signedHeaders."\n" + .$hashedRequestPayload; + + // step 2: build string to sign + $date = gmdate("Ymd\THis\Z", $time); + $hashedCanonicalRequest = hash("sha256", $canonicalRequest); + $stringToSign = $algorithm."\n" + .$date."\n" + .$hashedCanonicalRequest; + + // step 3: sign string + $signature = hash_hmac("sha256", $stringToSign, $this->SecretAccessKey); + + // step 4: build authorization + $authorization = $algorithm . ' Access=' . $this->AccessKeyId . ", SignedHeaders=" . $signedHeaders . ", Signature=" . $signature; + + return $authorization; + } + + private function escape($str) + { + $search = ['+', '*', '%7E']; + $replace = ['%20', '%2A', '~']; + return str_replace($search, $replace, urlencode($str)); + } + + private function getCanonicalQueryString($parameters) + { + if(empty($parameters)) return ''; + ksort($parameters); + $canonicalQueryString = ''; + foreach ($parameters as $key => $value) { + $canonicalQueryString .= '&' . $this->escape($key). '=' . $this->escape($value); + } + return substr($canonicalQueryString, 1); + } + + private function getCanonicalHeaders($oldheaders){ + $headers = array(); + foreach ($oldheaders as $key => $value) { + $headers[strtolower($key)] = trim($value); + } + ksort($headers); + + $canonicalHeaders = ''; + $signedHeaders = ''; + foreach ($headers as $key => $value) { + $canonicalHeaders .= $key . ':' . $value . "\n"; + $signedHeaders .= $key . ';'; + } + $signedHeaders = substr($signedHeaders, 0, -1); + return [$canonicalHeaders, $signedHeaders]; + } + + private function curl($method, $url, $body, $header){ + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); + if(!empty($body)){ + curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + } + $response = curl_exec($ch); + $errno = curl_errno($ch); + if ($errno) { + $this->setError('Curl error: ' . curl_error($ch)); + } + curl_close($ch); + if ($errno) return false; + + $arr=json_decode($response,true); + if($arr){ + if(isset($arr['error_msg'])){ + $this->setError($arr['error_msg']); + return false; + }else{ + return $arr; + } + }else{ + $this->setError('返回数据解析失败'); + return false; + } + } + + private function setError($message){ + $this->error = $message; + //file_put_contents('logs.txt',date('H:i:s').' '.$message."\r\n", FILE_APPEND); + } +} \ No newline at end of file diff --git a/app/lib/dns/west.php b/app/lib/dns/west.php new file mode 100644 index 0000000..5b8c898 --- /dev/null +++ b/app/lib/dns/west.php @@ -0,0 +1,226 @@ +username = $config['ak']; + $this->api_password = $config['sk']; + $this->domain = $config['domain']; + } + + public function getError(){ + return $this->error; + } + + public function check(){ + if($this->getDomainList() != false){ + return true; + } + return false; + } + + //获取域名列表 + public function getDomainList($KeyWord=null, $PageNumber=1, $PageSize=20){ + $param = ['page' => $PageNumber, 'limit' => $PageSize, 'domain' => $KeyWord]; + $data = $this->execute('/domain/?act=getdomains', $param); + if($data){ + $list = []; + foreach($data['items'] as $row){ + $list[] = [ + 'DomainId' => $row['domain'], + 'Domain' => $row['domain'], + 'RecordCount' => 0, + ]; + } + return ['total' => $data['total'], 'list' => $list]; + } + return false; + } + + //获取解析记录列表 + public function getDomainRecords($PageNumber=1, $PageSize=20, $KeyWord = null, $SubDomain = null, $Type = null, $Line = null, $Status = null){ + $param = ['act' => 'dnsrec.list', 'domain' => $this->domain, 'record_type' => $Type, 'record_line' => $Line, 'hostname' => $KeyWord, 'pageno' => $PageNumber, 'limit' => $PageSize]; + if(!isNullOrEmpty(($SubDomain))){ + $param['hostname'] = $SubDomain; + } + $data = $this->execute2('/domain/dns/', $param); + if($data){ + $list = []; + foreach($data['items'] as $row){ + $list[] = [ + 'RecordId' => $row['record_id'], + 'Domain' => $this->domain, + 'Name' => $row['hostname'], + 'Type' => $row['record_type'], + 'Value' => $row['record_value'], + 'Line' => $row['record_line'], + 'TTL' => $row['record_ttl'], + 'MX' => $row['record_mx'], + 'Status' => $row['pause'] == 1 ? '0' : '1', + 'Weight' => null, + 'Remark' => null, + 'UpdateTime' => null, + ]; + } + return ['total' => $data['total'], 'list' => $list]; + } + return false; + } + + //获取子域名解析记录列表 + public function getSubDomainRecords($SubDomain, $PageNumber=1, $PageSize=20, $Type = null, $Line = null){ + $domain_arr = explode('.', $SubDomain); + $domain = $domain_arr[count($domain_arr)-2].'.'.$domain_arr[count($domain_arr)-1]; + $subdomain = rtrim(str_replace($domain,'',$SubDomain),'.'); + if($subdomain == '')$subdomain='@'; + return $this->getDomainRecords($PageNumber, $PageSize, null, $subdomain, $Type, $Line); + } + + //获取解析记录详细信息 + public function getDomainRecordInfo($RecordId){ + return false; + } + + //添加解析记录 + public function addDomainRecord($Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Remark = null){ + $param = ['act' => 'dnsrec.add', 'domain' => $this->domain, 'hostname' => $Name, 'record_type' => $this->convertType($Type), 'record_value' => $Value, 'record_level' => $MX, 'record_ttl' => intval($TTL), 'record_line' => $Line]; + $data = $this->execute2('/domain/dns/', $param); + return is_array($data) ? $data['record_id'] : false; + } + + //修改解析记录 + public function updateDomainRecord($RecordId, $Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Remark = null){ + $param = ['act' => 'dnsrec.modify', 'domain' => $this->domain, 'record_id' => $RecordId, 'record_type' => $this->convertType($Type), 'record_value' => $Value, 'record_level' => $MX, 'record_ttl' => intval($TTL), 'record_line' => $Line]; + $data = $this->execute2('/domain/dns/', $param); + return is_array($data); + } + + //修改解析记录备注 + public function updateDomainRecordRemark($RecordId, $Remark){ + return false; + } + + //删除解析记录 + public function deleteDomainRecord($RecordId){ + $param = ['act' => 'dnsrec.remove', 'domain' => $this->domain, 'record_id' => $RecordId]; + $data = $this->execute2('/domain/dns/', $param); + return is_array($data); + } + + //设置解析记录状态 + public function setDomainRecordStatus($RecordId, $Status){ + return false; + } + + //获取解析记录操作日志 + public function getDomainRecordLog($PageNumber = 1, $PageSize = 20, $KeyWord = null, $StartDate = null, $endDate = null){ + return false; + } + + //获取解析线路列表 + public function getRecordLine(){ + return [ + ''=>['name'=>'默认', 'parent'=>null], + 'LTEL'=>['name'=>'电信', 'parent'=>null], + 'LCNC'=>['name'=>'联通', 'parent'=>null], + 'LMOB'=>['name'=>'移动', 'parent'=>null], + 'LEDU'=>['name'=>'教育网', 'parent'=>null], + 'LSEO'=>['name'=>'搜索引擎', 'parent'=>null], + 'LFOR'=>['name'=>'境外', 'parent'=>null], + ]; + } + + //获取域名信息 + public function getDomainInfo(){ + return false; + } + + //获取域名最低TTL + public function getMinTTL(){ + return false; + } + + private function convertType($type){ + return $type; + } + + private function execute($path, $params){ + $params['username'] = $this->username; + $params['time'] = $this->getMillisecond(); + $params['token'] = md5($this->username.$this->api_password.$params['time']); + $response = $this->curl($path, $params); + $response = mb_convert_encoding($response, 'UTF-8', 'GBK'); + $arr=json_decode($response,true); + if($arr){ + if($arr['result'] == 200){ + return $arr['data']; + }else{ + $this->setError($arr['msg']); + return false; + } + }else{ + $this->setError('返回数据解析失败'); + return false; + } + } + + private function execute2($path, $params){ + $params['username'] = $this->username; + $params['apikey'] = md5($this->api_password); + $response = $this->curl($path, $params); + $response = mb_convert_encoding($response, 'UTF-8', 'GBK'); + $arr=json_decode($response,true); + if($arr){ + if($arr['code'] == 200){ + return $arr['body']; + }else{ + $this->setError($arr['msg']); + return false; + } + }else{ + $this->setError('返回数据解析失败'); + return false; + } + } + + private function curl($path, $params = null){ + $url = $this->baseUrl . $path; + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 10); + if ($params) { + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params)); + } + $response = curl_exec($ch); + $errno = curl_errno($ch); + if ($errno) { + $this->setError('Curl error: ' . curl_error($ch)); + } + curl_close($ch); + if ($errno) return false; + return $response; + } + + private function getMillisecond() + { + list($s1, $s2) = explode(' ', microtime()); + return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000); + } + + private function setError($message){ + $this->error = $message; + //file_put_contents('logs.txt',date('H:i:s').' '.$message."\r\n", FILE_APPEND); + } +} \ No newline at end of file diff --git a/app/middleware.php b/app/middleware.php new file mode 100644 index 0000000..378f4b9 --- /dev/null +++ b/app/middleware.php @@ -0,0 +1,12 @@ +-1, 'msg'=>'认证参数不能为空'])->code(403); + } + if($timestamp < time()-300 || $timestamp > time()+300){ + return json(['code'=>-1, 'msg'=>'时间戳不合法'])->code(403); + } + $user = Db::name('user')->where('id', $uid)->find(); + if(!$user) return json(['code'=>-1, 'msg'=>'用户不存在'])->code(403); + if($user['status'] == 0) return json(['code'=>-1, 'msg'=>'该用户已被封禁'])->code(403); + if($user['is_api'] == 0) return json(['code'=>-1, 'msg'=>'该用户未开启API权限'])->code(403); + if(md5($uid.$timestamp.$user['apikey']) !== $sign){ + return json(['code'=>-1, 'msg'=>'签名错误'])->code(403); + } + + $user['type'] = 'user'; + $user['permission'] = []; + if($user['level'] == 1){ + $user['permission'] = Db::name('permission')->where('uid', $uid)->column('domain'); + } + + $request->islogin = true; + $request->isApi = true; + $request->user = $user; + return $next($request); + } +} diff --git a/app/middleware/AuthUser.php b/app/middleware/AuthUser.php new file mode 100644 index 0000000..d2f2c81 --- /dev/null +++ b/app/middleware/AuthUser.php @@ -0,0 +1,52 @@ +where('id', $uid)->find(); + if($user && $user['status']==1){ + $session=md5($user['id'].$user['password']); + if($session==$sid && $expiretime>time()) { + $islogin = true; + } + $user['type'] = 'user'; + $user['permission'] = []; + if($user['level'] == 1){ + $user['permission'] = Db::name('permission')->where('uid', $uid)->column('domain'); + } + } + }elseif($type == 'domain'){ + $user = Db::name('domain')->where('id', $uid)->find(); + if($user && $user['is_sso']==1){ + $session=md5($user['id'].$user['name']); + if($session==$sid && $expiretime>time()) { + $islogin = true; + } + $user['username'] = $user['name']; + $user['regtime'] = $user['addtime']; + $user['type'] = 'domain'; + $user['level'] = 0; + $user['permission'] = [$user['name']]; + } + } + } + } + $request->islogin = $islogin; + $request->user = $user; + return $next($request); + } +} diff --git a/app/middleware/CheckLogin.php b/app/middleware/CheckLogin.php new file mode 100644 index 0000000..08016dc --- /dev/null +++ b/app/middleware/CheckLogin.php @@ -0,0 +1,19 @@ +islogin) { + if ($request->isAjax() || !$request->isGet()) { + return json(['code'=>-1, 'msg'=>'未登录'])->code(401); + } + return redirect((string)url('/login')); + } + return $next($request); + } +} diff --git a/app/middleware/LoadConfig.php b/app/middleware/LoadConfig.php new file mode 100644 index 0000000..0657b40 --- /dev/null +++ b/app/middleware/LoadConfig.php @@ -0,0 +1,39 @@ +getRootPath().'.env')){ + if(strpos(request()->url(),'/install')===false){ + return redirect((string)url('/install'))->header([ + 'Cache-Control' => 'no-store, no-cache, must-revalidate', + 'Pragma' => 'no-cache', + ]); + }else{ + return $next($request); + } + } + Config::set([], 'sys'); + + $request->isApi = false; + + return $next($request)->header([ + 'Cache-Control' => 'no-store, no-cache, must-revalidate', + 'Pragma' => 'no-cache', + ]); + } +} diff --git a/app/middleware/RefererCheck.php b/app/middleware/RefererCheck.php new file mode 100644 index 0000000..7282761 --- /dev/null +++ b/app/middleware/RefererCheck.php @@ -0,0 +1,24 @@ +islogin); + View::assign('user', $request->user); + View::assign('cdnpublic', '//lib.baomitu.com/'); + View::assign('skin', getAdminSkin()); + return $next($request); + } +} diff --git a/app/provider.php b/app/provider.php new file mode 100644 index 0000000..73d99fa --- /dev/null +++ b/app/provider.php @@ -0,0 +1,9 @@ + Request::class, + 'think\exception\Handle' => ExceptionHandle::class, +]; diff --git a/app/service.php b/app/service.php new file mode 100644 index 0000000..db1ee6a --- /dev/null +++ b/app/service.php @@ -0,0 +1,9 @@ + + + + + + + + 聚合DNS管理系统 - 登录 + + + + + + + + + + +
+ +
+ + + + \ No newline at end of file diff --git a/app/view/common/layout.html b/app/view/common/layout.html new file mode 100644 index 0000000..d25e4b0 --- /dev/null +++ b/app/view/common/layout.html @@ -0,0 +1,196 @@ + + + + + + + + {block name="title"}标题{/block} + + + + + + + + + + + + +
+
+ + + + +
+ + + + +
+ +
+{block name="main"}主内容{/block} +
+ +
+ + + + +
+
+ + + + + + +{block name="script"}{/block} + + \ No newline at end of file diff --git a/app/view/dispatch_jump.html b/app/view/dispatch_jump.html new file mode 100644 index 0000000..7e7452b --- /dev/null +++ b/app/view/dispatch_jump.html @@ -0,0 +1,60 @@ + + + + + 温馨提示 + + + + + +
+
+ +
+

{$msg}

+ {if $url} +

+ 页面将在 {$wait} 秒后自动跳转 +

+ {/if} +

+ 返回上一页 + {if $url} + 立即跳转 + {/if} +

+
+ + + \ No newline at end of file diff --git a/app/view/domain/account.html b/app/view/domain/account.html new file mode 100644 index 0000000..1bacd31 --- /dev/null +++ b/app/view/domain/account.html @@ -0,0 +1,234 @@ +{extend name="common/layout" /} +{block name="title"}域名账户{/block} +{block name="main"} + +
+
+
+
+ +
+
+ + +
+ + 刷新 + 添加 +
+ + +
+
+
+
+
+{/block} +{block name="script"} + + + + + +{/block} \ No newline at end of file diff --git a/app/view/domain/domain.html b/app/view/domain/domain.html new file mode 100644 index 0000000..db29a81 --- /dev/null +++ b/app/view/domain/domain.html @@ -0,0 +1,361 @@ +{extend name="common/layout" /} +{block name="title"}域名管理{/block} +{block name="main"} + + +
+
+
+
+ +
+
+ + +
+
+ +
+ + 刷新 + {if request()->user['level'] eq 2} 添加{/if} +
+ + +
+
+
+
+
+{/block} +{block name="script"} + + + + + + + +{/block} \ No newline at end of file diff --git a/app/view/domain/log.html b/app/view/domain/log.html new file mode 100644 index 0000000..3af7053 --- /dev/null +++ b/app/view/domain/log.html @@ -0,0 +1,47 @@ +{extend name="common/layout" /} +{block name="title"}域名日志{/block} +{block name="main"} + +
+
+
+
+ + +
+
+
+
+
+{/block} +{block name="script"} + + + + + +{/block} \ No newline at end of file diff --git a/app/view/domain/record.html b/app/view/domain/record.html new file mode 100644 index 0000000..d24ba86 --- /dev/null +++ b/app/view/domain/record.html @@ -0,0 +1,436 @@ +{extend name="common/layout" /} +{block name="title"}解析管理 - {$domainName}{/block} +{block name="main"} + + +
+
+
+
+

{if request()->user['type'] eq 'user'} 返回{/if}{$domainName}

+
+
+ +
+
+ + +
+
+ +
+ + 刷新 + 添加记录 +
+ + +
+
+ + +
+
+ + +
+
+
+
+
+{/block} +{block name="script"} + + + + + + +{/block} \ No newline at end of file diff --git a/app/view/index/error.html b/app/view/index/error.html new file mode 100644 index 0000000..4841d4b --- /dev/null +++ b/app/view/index/error.html @@ -0,0 +1,23 @@ + + + + + + 抱歉,出错了 + + + + +
+
+
+

{$errmsg}

+
+
+ + + \ No newline at end of file diff --git a/app/view/index/index.html b/app/view/index/index.html new file mode 100644 index 0000000..d4074f2 --- /dev/null +++ b/app/view/index/index.html @@ -0,0 +1,175 @@ +{extend name="common/layout" /} +{block name="title"}聚合DNS管理系统{/block} +{block name="main"} + +
+
+ +
+
+

0

+

域名数量

+
+
+ +
+ More info +
+
+ +
+ +
+
+

0

+

用户数量

+
+
+ +
+ More info +
+
+ +
+ +
+
+

0

+

解析数量

+
+
+ +
+ More info +
+
+ +
+ +
+
+

0

+

平台数量

+
+
+ +
+ More info +
+
+ +
+ +
+
+
+
+
+ +

服务器信息

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
框架版本{$info.framework_version}
PHP版本{$info.php_version}
MySQL版本{$info.mysql_version}
WEB软件{$info.software}
操作系统{$info.os}
服务器时间{$info.date}
+
+
+
+
+
+ +

版本信息

+
+
    +
    +
    +
    +
    +{/block} +{block name="script"} + + + +{/block} \ No newline at end of file diff --git a/app/view/index/setpwd.html b/app/view/index/setpwd.html new file mode 100644 index 0000000..90d1601 --- /dev/null +++ b/app/view/index/setpwd.html @@ -0,0 +1,60 @@ +{extend name="common/layout" /} +{block name="title"}修改密码{/block} +{block name="main"} +
    +
    +
    +

    修改密码

    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    +
    +
    +{/block} +{block name="script"} + + +{/block} \ No newline at end of file diff --git a/app/view/install/index.html b/app/view/install/index.html new file mode 100644 index 0000000..3667912 --- /dev/null +++ b/app/view/install/index.html @@ -0,0 +1,266 @@ + + + + + + 聚合DNS管理系统 - 安装程序 + + + + + + +
    +

    + + +

    +

    聚合DNS管理系统 - 安装程序

    +
    + +
    + + + +
    +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    +
    + +
    +
    + + +
    + +
    + + +
    +
    + +
    + + + +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/app/view/user/log.html b/app/view/user/log.html new file mode 100644 index 0000000..f51738e --- /dev/null +++ b/app/view/user/log.html @@ -0,0 +1,77 @@ +{extend name="common/layout" /} +{block name="title"}操作日志{/block} +{block name="main"} + +
    +
    +
    +
    + +
    +
    + + {if request()->user['level'] eq 2}{/if} + + +
    + + 刷新 +
    + + +
    +
    +
    +
    +
    +{/block} +{block name="script"} + + + + + +{/block} \ No newline at end of file diff --git a/app/view/user/user.html b/app/view/user/user.html new file mode 100644 index 0000000..eb6a5eb --- /dev/null +++ b/app/view/user/user.html @@ -0,0 +1,338 @@ +{extend name="common/layout" /} +{block name="title"}用户管理{/block} +{block name="main"} + + +
    +
    +
    +
    + +
    +
    + + +
    + + 刷新 + 添加 +
    + + +
    +
    +
    +
    +
    +{/block} +{block name="script"} + + + + + + + +{/block} \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..c645bc1 --- /dev/null +++ b/composer.json @@ -0,0 +1,50 @@ +{ + "name": "topthink/think", + "description": "the new thinkphp framework", + "type": "project", + "keywords": [ + "framework", + "thinkphp", + "ORM" + ], + "homepage": "https://www.thinkphp.cn/", + "license": "Apache-2.0", + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "require": { + "php": ">=7.2.5", + "topthink/framework": "^6.0.0", + "topthink/think-orm": "^2.0", + "topthink/think-view": "^1.0", + "cccyun/think-captcha": "^3.0" + }, + "require-dev": { + "symfony/var-dumper": "^4.2", + "topthink/think-trace":"^1.0" + }, + "autoload": { + "psr-4": { + "app\\": "app" + }, + "psr-0": { + "": "extend/" + } + }, + "config": { + "preferred-install": "dist" + }, + "scripts": { + "post-autoload-dump": [ + "@php think service:discover", + "@php think vendor:publish" + ] + } +} diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..8db0724 --- /dev/null +++ b/config/app.php @@ -0,0 +1,34 @@ + env('app.host', ''), + // 应用的命名空间 + 'app_namespace' => '', + // 是否启用路由 + 'with_route' => true, + // 默认应用 + 'default_app' => 'index', + // 默认时区 + 'default_timezone' => 'Asia/Shanghai', + + // 应用映射(自动多应用模式有效) + 'app_map' => [], + // 域名绑定(自动多应用模式有效) + 'domain_bind' => [], + // 禁止URL访问的应用列表(自动多应用模式有效) + 'deny_app_list' => [], + + // 异常页面的模板文件 + 'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl', + + // 错误显示信息,非调试模式有效 + 'error_message' => '页面错误!请稍后再试~', + // 显示错误信息 + 'show_error_msg' => false, + + 'version' => '1001', +]; diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..a8d69d2 --- /dev/null +++ b/config/cache.php @@ -0,0 +1,29 @@ + env('cache.driver', 'file'), + + // 缓存连接方式配置 + 'stores' => [ + 'file' => [ + // 驱动方式 + 'type' => 'File', + // 缓存保存目录 + 'path' => '', + // 缓存前缀 + 'prefix' => '', + // 缓存有效期 0表示永久缓存 + 'expire' => 0, + // 缓存标签前缀 + 'tag_prefix' => 'tag:', + // 序列化机制 例如 ['serialize', 'unserialize'] + 'serialize' => [], + ], + // 更多的缓存连接 + ], +]; diff --git a/config/captcha.php b/config/captcha.php new file mode 100644 index 0000000..6ec80f6 --- /dev/null +++ b/config/captcha.php @@ -0,0 +1,39 @@ + 4, + // 验证码字符集合 + 'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY', + // 验证码过期时间 + 'expire' => 1800, + // 是否使用中文验证码 + 'useZh' => false, + // 是否使用算术验证码 + 'math' => false, + // 是否使用背景图 + 'useImgBg' => false, + //验证码字符大小 + 'fontSize' => 25, + // 是否使用混淆曲线 + 'useCurve' => true, + //是否添加杂点 + 'useNoise' => true, + // 验证码字体 不设置则随机 + 'fontttf' => '', + //背景颜色 + 'bg' => [243, 251, 254], + // 验证码图片高度 + 'imageH' => 0, + // 验证码图片宽度 + 'imageW' => 0, + + // 添加额外的验证码设置 + // verify => [ + // 'length'=>4, + // ... + //], +]; diff --git a/config/console.php b/config/console.php new file mode 100644 index 0000000..a818a98 --- /dev/null +++ b/config/console.php @@ -0,0 +1,9 @@ + [ + ], +]; diff --git a/config/cookie.php b/config/cookie.php new file mode 100644 index 0000000..d3b3aab --- /dev/null +++ b/config/cookie.php @@ -0,0 +1,20 @@ + 0, + // cookie 保存路径 + 'path' => '/', + // cookie 有效域名 + 'domain' => '', + // cookie 启用安全传输 + 'secure' => false, + // httponly设置 + 'httponly' => false, + // 是否使用 setcookie + 'setcookie' => true, + // samesite 设置,支持 'strict' 'lax' + 'samesite' => '', +]; diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..0cf1346 --- /dev/null +++ b/config/database.php @@ -0,0 +1,63 @@ + env('database.driver', 'mysql'), + + // 自定义时间查询规则 + 'time_query_rule' => [], + + // 自动写入时间戳字段 + // true为自动识别类型 false关闭 + // 字符串则明确指定时间字段类型 支持 int timestamp datetime date + 'auto_timestamp' => true, + + // 时间字段取出后的默认时间格式 + 'datetime_format' => 'Y-m-d H:i:s', + + // 时间字段配置 配置格式:create_time,update_time + 'datetime_field' => '', + + // 数据库连接配置信息 + 'connections' => [ + 'mysql' => [ + // 数据库类型 + 'type' => env('database.type', 'mysql'), + // 服务器地址 + 'hostname' => env('database.hostname', '127.0.0.1'), + // 数据库名 + 'database' => env('database.database', ''), + // 用户名 + 'username' => env('database.username', 'root'), + // 密码 + 'password' => env('database.password', ''), + // 端口 + 'hostport' => env('database.hostport', '3306'), + // 数据库连接参数 + 'params' => [], + // 数据库编码默认采用utf8 + 'charset' => env('database.charset', 'utf8'), + // 数据库表前缀 + 'prefix' => env('database.prefix', ''), + + // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'deploy' => 0, + // 数据库读写是否分离 主从式有效 + 'rw_separate' => false, + // 读写分离后 主服务器数量 + 'master_num' => 1, + // 指定从服务器序号 + 'slave_no' => '', + // 是否严格检查字段是否存在 + 'fields_strict' => true, + // 是否需要断线重连 + 'break_reconnect' => false, + // 监听SQL + 'trigger_sql' => env('app_debug', true), + // 开启字段缓存 + 'fields_cache' => true, + ], + + // 更多的数据库配置信息 + ], +]; diff --git a/config/filesystem.php b/config/filesystem.php new file mode 100644 index 0000000..965297e --- /dev/null +++ b/config/filesystem.php @@ -0,0 +1,24 @@ + env('filesystem.driver', 'local'), + // 磁盘列表 + 'disks' => [ + 'local' => [ + 'type' => 'local', + 'root' => app()->getRuntimePath() . 'storage', + ], + 'public' => [ + // 磁盘类型 + 'type' => 'local', + // 磁盘路径 + 'root' => app()->getRootPath() . 'public/storage', + // 磁盘路径对应的外部URL路径 + 'url' => '/storage', + // 可见性 + 'visibility' => 'public', + ], + // 更多的磁盘配置信息 + ], +]; diff --git a/config/lang.php b/config/lang.php new file mode 100644 index 0000000..59f320f --- /dev/null +++ b/config/lang.php @@ -0,0 +1,27 @@ + env('lang.default_lang', 'zh-cn'), + // 允许的语言列表 + 'allow_lang_list' => [], + // 多语言自动侦测变量名 + 'detect_var' => 'lang', + // 是否使用Cookie记录 + 'use_cookie' => true, + // 多语言cookie变量 + 'cookie_var' => 'think_lang', + // 多语言header变量 + 'header_var' => 'think-lang', + // 扩展语言包 + 'extend_list' => [], + // Accept-Language转义为对应语言包名称 + 'accept_language' => [ + 'zh-hans-cn' => 'zh-cn', + ], + // 是否支持语言分组 + 'allow_group' => false, +]; diff --git a/config/log.php b/config/log.php new file mode 100644 index 0000000..ea24ff9 --- /dev/null +++ b/config/log.php @@ -0,0 +1,45 @@ + env('log.channel', 'file'), + // 日志记录级别 + 'level' => [], + // 日志类型记录的通道 ['error'=>'email',...] + 'type_channel' => [], + // 关闭全局日志写入 + 'close' => false, + // 全局日志处理 支持闭包 + 'processor' => null, + + // 日志通道列表 + 'channels' => [ + 'file' => [ + // 日志记录方式 + 'type' => 'File', + // 日志保存目录 + 'path' => '', + // 单文件日志写入 + 'single' => false, + // 独立日志级别 + 'apart_level' => [], + // 最大日志文件数量 + 'max_files' => 0, + // 使用JSON格式记录 + 'json' => false, + // 日志处理 + 'processor' => null, + // 关闭通道日志写入 + 'close' => false, + // 日志输出格式化 + 'format' => '[%s][%s] %s', + // 是否实时写入 + 'realtime_write' => false, + ], + // 其它日志通道配置 + ], + +]; diff --git a/config/middleware.php b/config/middleware.php new file mode 100644 index 0000000..7e1972f --- /dev/null +++ b/config/middleware.php @@ -0,0 +1,8 @@ + [], + // 优先级设置,此数组中的中间件会按照数组中的顺序优先执行 + 'priority' => [], +]; diff --git a/config/route.php b/config/route.php new file mode 100644 index 0000000..929e2b7 --- /dev/null +++ b/config/route.php @@ -0,0 +1,45 @@ + '/', + // URL伪静态后缀 + 'url_html_suffix' => '', + // URL普通方式参数 用于自动生成 + 'url_common_param' => true, + // 是否开启路由延迟解析 + 'url_lazy_route' => false, + // 是否强制使用路由 + 'url_route_must' => true, + // 合并路由规则 + 'route_rule_merge' => false, + // 路由是否完全匹配 + 'route_complete_match' => false, + // 访问控制器层名称 + 'controller_layer' => 'controller', + // 空控制器名 + 'empty_controller' => 'Error', + // 是否使用控制器后缀 + 'controller_suffix' => false, + // 默认的路由变量规则 + 'default_route_pattern' => '[\w\.]+', + // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 + 'request_cache_key' => false, + // 请求缓存有效期 + 'request_cache_expire' => null, + // 全局请求缓存排除规则 + 'request_cache_except' => [], + // 默认控制器名 + 'default_controller' => 'Index', + // 默认操作名 + 'default_action' => 'index', + // 操作方法后缀 + 'action_suffix' => '', + // 默认JSONP格式返回的处理方法 + 'default_jsonp_handler' => 'jsonpReturn', + // 默认JSONP处理方法 + 'var_jsonp_handler' => 'callback', +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..c1ef6e1 --- /dev/null +++ b/config/session.php @@ -0,0 +1,19 @@ + 'PHPSESSID', + // SESSION_ID的提交变量,解决flash上传跨域 + 'var_session_id' => '', + // 驱动方式 支持file cache + 'type' => 'file', + // 存储连接标识 当type使用cache的时候有效 + 'store' => null, + // 过期时间 + 'expire' => 1440, + // 前缀 + 'prefix' => '', +]; diff --git a/config/trace.php b/config/trace.php new file mode 100644 index 0000000..fad2392 --- /dev/null +++ b/config/trace.php @@ -0,0 +1,10 @@ + 'Html', + // 读取的日志通道名 + 'channel' => '', +]; diff --git a/config/view.php b/config/view.php new file mode 100644 index 0000000..01259a0 --- /dev/null +++ b/config/view.php @@ -0,0 +1,25 @@ + 'Think', + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法 + 'auto_rule' => 1, + // 模板目录名 + 'view_dir_name' => 'view', + // 模板后缀 + 'view_suffix' => 'html', + // 模板文件名分隔符 + 'view_depr' => DIRECTORY_SEPARATOR, + // 模板引擎普通标签开始标记 + 'tpl_begin' => '{', + // 模板引擎普通标签结束标记 + 'tpl_end' => '}', + // 标签库标签开始标记 + 'taglib_begin' => '{', + // 标签库标签结束标记 + 'taglib_end' => '}', +]; diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..cbc7868 --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,8 @@ + + Options +FollowSymlinks -Multiviews + RewriteEngine On + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..0d0c2aee3d1f7e4719f9005bc535015010c45ca2 GIT binary patch literal 16446 zcmeHOYpC2r6yDaiVyz_K%hRsQ9Np1VOC$00j&BLlN9|lk8qw zOBE?rT2WEZmI{K1qV-X%SbXAxT5CZ?TeQW}_uV9G;y1TWJv;X#nd~Mj$lj99%sJor z&N-80W-`f^N>lJ}-nWRrII)Xe}f+AcMlw?4P6*C zt%Yr;a&O?8t31bg%eT$1{f4wi^wX)c9Sd2OM^qP~7y%>uT^KLE%9a)->aHV;U4iAU%9dlh8e=quQ#qb%N zUtJmc?R6dhSO*-^<(!0btgSjevSPC2?mO15NpWHR4{NivR^EYAd6Ki&m7$-%$eLdg zK8i|HbbMn>IM}LNhVL3XIed~2s*7r)r*rnWzF!R*=5w4*m9?Dm8p_#A-M5W>D!`D4{NlB3-; z@1{CgA9v0BBu1z78s|EQYdI!~D|%x6@a zL3_{xgB}?4fZ7A?W@Rxq?x-@czu`41Z>#oPo7%Q)^Ft0JWPZImO0l9IhZS-atJ6;6 zJI0x94+CTGU+J9xKGP@VFP;h29Fn+ItWMi+R!4K^w9UD?oN@VM&A*O|UzeA&~IOFMV=lT&!8;lzV@(dNyZ| zd*k>%RKN14adCAn&TeFs+jpziaU30(K3xCUFZiXyC*GCNwy1M)N|}n)ZR0+_RdUdh z+81^Hv2OT4_zW7>eCiK-q5gy%Ia4`}Ppwm2mb&j&9#*+j-$myy)(te~urWMSjX~(S zIHio*XQ^Ya=6T6MONE2QNIb=68UMxk$GLu=+6Rugo#Pc4Dd)-#4&}N@)H%k-X?#VU z|CViRQDdXABuP@Ec<+NM}h$F=pHiji#< zE9G3NVs+abmyqFR(|XTC{Y15q>2Z8gPVu51*Z%^qVkHMxs#u*i`hFM3C1pDIkHAE= z8%~rqX{E}UgwKLa;u+`$J@9|%0qhCR;*KJ7!x-^p+*pEVho9qow;XE?XNUK;?DJ+E zkCfw^$eTDm-!Wd37+M~z%{-UGOIhfQTtxA4_3)|7r%4;GY&+JYoUOmCaxI6)Hvyk; z_%vDI7@u-{=$D0@E&6#six=x`+x(rgiId@-|MziRLLM!@X3`o;d>h2s;CXLfoS!5) z_M_PMno-R>S+xT;@jZR$lrK(aVfP}(M`bDxo}u2OdRbR-X>HNB(w3I^wq_%>4Q=ZZs^{typS3Q|Gsj6~ z^!sFWUrXXz%Z!Jz_{LuJ6VjHJezSc1{f+0EcTpW%ZzOBpuIn>qeTGRL%qAAAS>%_JTAD@zQVJ@&~y z5Ap32=HLUYo}3fhyT4`emxjf6Cy%806ne3*iGE+oVMBM8ndV36!!gU?>@n|cW#uGq zso$_D|KAK?U9?2WsOZ zZ}AQR^Tw%Z{JrYEx^X4vUq^;}qlJFhgYj^im@ECdu@QDVP~VOCyZW8XgkP-Jdd(}V zJ=WdDAatr% z^%8Rtwh`tW%)4ugI{)~M#~zHoHx?0l-kgYaF7^XH>a{Ph&I`fublf)!dB +// +---------------------------------------------------------------------- + +// [ 应用入口文件 ] +namespace think; + +require __DIR__ . '/../vendor/autoload.php'; + +// 执行HTTP应用并响应 +$http = (new App())->http; + +$response = $http->run(); + +$response->send(); + +$http->end($response); diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..1f53798 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/public/router.php b/public/router.php new file mode 100644 index 0000000..9b39a62 --- /dev/null +++ b/public/router.php @@ -0,0 +1,19 @@ + +// +---------------------------------------------------------------------- +// $Id$ + +if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SCRIPT_NAME"])) { + return false; +} else { + $_SERVER["SCRIPT_FILENAME"] = __DIR__ . '/index.php'; + + require __DIR__ . "/index.php"; +} diff --git a/public/static/css/app.min.css b/public/static/css/app.min.css new file mode 100644 index 0000000..206b76f --- /dev/null +++ b/public/static/css/app.min.css @@ -0,0 +1,10 @@ +/*! + * AdminLTE v2.4.18 + * + * Author: Colorlib + * Support: + * Repository: git://github.com/ColorlibHQ/AdminLTE.git + * License: MIT + */ +html,body{height:100%}.layout-boxed html,.layout-boxed body{height:100%}body{font-family:'Source Sans Pro','Helvetica Neue',Helvetica,Arial,sans-serif;font-weight:400;overflow-x:hidden;overflow-y:auto}.wrapper{height:100%;position:relative;overflow-x:hidden;overflow-y:auto}.wrapper:before,.wrapper:after{content:" ";display:table}.wrapper:after{clear:both}.layout-boxed .wrapper{max-width:1250px;margin:0 auto;min-height:100%;box-shadow:0 0 8px rgba(0,0,0,0.5);position:relative}.layout-boxed{background-color:#f9fafc}.content-wrapper,.main-footer{-webkit-transition:-webkit-transform .3s ease-in-out,margin .3s ease-in-out;-moz-transition:-moz-transform .3s ease-in-out,margin .3s ease-in-out;-o-transition:-o-transform .3s ease-in-out,margin .3s ease-in-out;transition:transform .3s ease-in-out,margin .3s ease-in-out;margin-left:230px;z-index:820}.layout-top-nav .content-wrapper,.layout-top-nav .main-footer{margin-left:0}@media (max-width:767px){.content-wrapper,.main-footer{margin-left:0}}@media (min-width:768px){.sidebar-collapse .content-wrapper,.sidebar-collapse .main-footer{margin-left:0}}@media (max-width:767px){.sidebar-open .content-wrapper,.sidebar-open .main-footer{-webkit-transform:translate(230px, 0);-ms-transform:translate(230px, 0);-o-transform:translate(230px, 0);transform:translate(230px, 0)}}.content-wrapper{min-height:calc(100vh - 101px);background-color:#ecf0f5;z-index:800}@media (max-width:767px){.content-wrapper{min-height:calc(100vh - 151px)}}.main-footer{background:#fff;padding:15px;color:#444;border-top:1px solid #d2d6de}.fixed .main-header,.fixed .main-sidebar,.fixed .left-side{position:fixed}.fixed .main-header{top:0;right:0;left:0}.fixed .content-wrapper,.fixed .right-side{padding-top:50px}@media (max-width:767px){.fixed .content-wrapper,.fixed .right-side{padding-top:100px}}.fixed.layout-boxed .wrapper{max-width:100%}.fixed .wrapper{overflow:hidden}.hold-transition .content-wrapper,.hold-transition .right-side,.hold-transition .main-footer,.hold-transition .main-sidebar,.hold-transition .left-side,.hold-transition .main-header .navbar,.hold-transition .main-header .logo,.hold-transition .menu-open .fa-angle-left{-webkit-transition:none;-o-transition:none;transition:none}.content{min-height:250px;padding:15px;margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:'Source Sans Pro',sans-serif}a{color:#3c8dbc}a:hover,a:active,a:focus{outline:none;text-decoration:none;color:#72afd2}.page-header{margin:10px 0 20px 0;font-size:22px}.page-header>small{color:#666;display:block;margin-top:5px}.main-header{position:relative;max-height:100px;z-index:1030}.main-header .navbar{-webkit-transition:margin-left .3s ease-in-out;-o-transition:margin-left .3s ease-in-out;transition:margin-left .3s ease-in-out;margin-bottom:0;margin-left:230px;border:none;min-height:50px;border-radius:0}.layout-top-nav .main-header .navbar{margin-left:0}.main-header #navbar-search-input.form-control{background:rgba(255,255,255,0.2);border-color:transparent}.main-header #navbar-search-input.form-control:focus,.main-header #navbar-search-input.form-control:active{border-color:rgba(0,0,0,0.1);background:rgba(255,255,255,0.9)}.main-header #navbar-search-input.form-control::-moz-placeholder{color:#ccc;opacity:1}.main-header #navbar-search-input.form-control:-ms-input-placeholder{color:#ccc}.main-header #navbar-search-input.form-control::-webkit-input-placeholder{color:#ccc}.main-header .navbar-custom-menu,.main-header .navbar-right{float:right}@media (max-width:991px){.main-header .navbar-custom-menu a,.main-header .navbar-right a{color:inherit;background:transparent}}@media (max-width:767px){.main-header .navbar-right{float:none}.navbar-collapse .main-header .navbar-right{margin:7.5px -15px}.main-header .navbar-right>li{color:inherit;border:0}}.main-header .sidebar-toggle{float:left;background-color:transparent;background-image:none;padding:15px 15px;font-family:fontAwesome}.main-header .sidebar-toggle:before{content:"\f0c9"}.main-header .sidebar-toggle:hover{color:#fff}.main-header .sidebar-toggle:focus,.main-header .sidebar-toggle:active{background:transparent}.main-header .sidebar-toggle.fa5{font-family:"Font Awesome\ 5 Free"}.main-header .sidebar-toggle.fa5:before{content:"\f0c9";font-weight:900}.main-header .sidebar-toggle .icon-bar{display:none}.main-header .navbar .nav>li.user>a>.fa,.main-header .navbar .nav>li.user>a>.glyphicon,.main-header .navbar .nav>li.user>a>.ion{margin-right:5px}.main-header .navbar .nav>li>a>.label{position:absolute;top:9px;right:7px;text-align:center;font-size:9px;padding:2px 3px;line-height:.9}.main-header .logo{-webkit-transition:width .3s ease-in-out;-o-transition:width .3s ease-in-out;transition:width .3s ease-in-out;display:block;float:left;height:50px;font-size:20px;line-height:50px;text-align:center;width:230px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;padding:0 15px;font-weight:300;overflow:hidden}.main-header .logo img{padding:4px;object-fit:contain;margin:0 auto}.main-header .logo .logo-lg{display:block}.main-header .logo .logo-lg img{max-width:200px;max-height:50px}.main-header .logo .logo-lg .brandlogo-image{margin-top:8px;margin-right:10px;margin-left:-5px}.main-header .logo .logo-mini{display:none}.main-header .logo .logo-mini img{max-width:50px;max-height:50px}.main-header .logo .logo-mini .brandlogo-image{margin-top:8px;margin-right:10px;margin-left:10px}.main-header .logo .brandlogo-image{float:left;height:34px;width:auto}.main-header .navbar-brand{color:#fff}.content-header{position:relative;padding:15px 15px 0 15px}.content-header>h1{margin:0;font-size:24px}.content-header>h1>small{font-size:15px;display:inline-block;padding-left:4px;font-weight:300}.content-header>.breadcrumb{float:right;background:transparent;margin-top:0;margin-bottom:0;font-size:12px;padding:7px 5px;position:absolute;top:15px;right:10px;border-radius:2px}.content-header>.breadcrumb>li>a{color:#444;text-decoration:none;display:inline-block}.content-header>.breadcrumb>li>a>.fa,.content-header>.breadcrumb>li>a>.glyphicon,.content-header>.breadcrumb>li>a>.ion{margin-right:5px}.content-header>.breadcrumb>li+li:before{content:'>\00a0'}@media (max-width:991px){.content-header>.breadcrumb{position:relative;margin-top:5px;top:0;right:0;float:none;background:#d2d6de;padding-left:10px}.content-header>.breadcrumb li:before{color:#97a0b3}}.navbar-toggle{color:#fff;border:0;margin:0;padding:15px 15px}@media (max-width:991px){.navbar-custom-menu .navbar-nav>li{float:left}.navbar-custom-menu .navbar-nav{margin:0;float:left}.navbar-custom-menu .navbar-nav>li>a{padding-top:15px;padding-bottom:15px;line-height:20px}}@media (max-width:767px){.main-header{position:relative}.main-header .logo,.main-header .navbar{width:100%;float:none}.main-header .navbar{margin:0}.main-header .navbar-custom-menu{float:right}}@media (max-width:991px){.navbar-collapse.pull-left{float:none !important}.navbar-collapse.pull-left+.navbar-custom-menu{display:block;position:absolute;top:0;right:40px}}.main-sidebar{position:absolute;top:0;left:0;padding-top:50px;min-height:100%;width:230px;z-index:810;-webkit-transition:-webkit-transform .3s ease-in-out,width .3s ease-in-out;-moz-transition:-moz-transform .3s ease-in-out,width .3s ease-in-out;-o-transition:-o-transform .3s ease-in-out,width .3s ease-in-out;transition:transform .3s ease-in-out,width .3s ease-in-out}@media (max-width:767px){.main-sidebar{padding-top:100px}}@media (max-width:767px){.main-sidebar{-webkit-transform:translate(-230px, 0);-ms-transform:translate(-230px, 0);-o-transform:translate(-230px, 0);transform:translate(-230px, 0)}}@media (min-width:768px){.sidebar-collapse .main-sidebar{-webkit-transform:translate(-230px, 0);-ms-transform:translate(-230px, 0);-o-transform:translate(-230px, 0);transform:translate(-230px, 0)}}@media (max-width:767px){.sidebar-open .main-sidebar{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}}.sidebar{padding-bottom:10px}.sidebar-form input:focus{border-color:transparent}.user-panel{position:relative;width:100%;padding:10px;overflow:hidden}.user-panel:before,.user-panel:after{content:" ";display:table}.user-panel:after{clear:both}.user-panel>.image>img{width:100%;max-width:45px;height:auto}.user-panel>.info{padding:5px 5px 5px 15px;line-height:1;position:absolute;left:55px}.user-panel>.info>p{font-weight:600;margin-bottom:9px}.user-panel>.info>a{text-decoration:none;padding-right:5px;margin-top:3px;font-size:11px}.user-panel>.info>a>.fa,.user-panel>.info>a>.ion,.user-panel>.info>a>.glyphicon{margin-right:3px}.sidebar-menu{list-style:none;margin:0;padding:0}.sidebar-menu>li{position:relative;margin:0;padding:0}.sidebar-menu>li>a{padding:12px 5px 12px 15px;display:block}.sidebar-menu>li>a>.fa,.sidebar-menu>li>a>.glyphicon,.sidebar-menu>li>a>.ion{width:20px}.sidebar-menu>li .label,.sidebar-menu>li .badge{margin-right:5px}.sidebar-menu>li .badge{margin-top:3px}.sidebar-menu li.header{padding:10px 25px 10px 15px;font-size:12px}.sidebar-menu li>a>.fa-angle-left,.sidebar-menu li>a>.pull-right-container>.fa-angle-left{width:auto;height:auto;padding:0;margin-right:10px;-webkit-transition:transform .5s ease;-o-transition:transform .5s ease;transition:transform .5s ease}.sidebar-menu li>a>.fa-angle-left{position:absolute;top:50%;right:10px;margin-top:-8px}.sidebar-menu .menu-open>a>.fa-angle-left,.sidebar-menu .menu-open>a>.pull-right-container>.fa-angle-left{-webkit-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.sidebar-menu .active>.treeview-menu{display:block}@media (min-width:768px){.sidebar-mini.sidebar-collapse .content-wrapper,.sidebar-mini.sidebar-collapse .right-side,.sidebar-mini.sidebar-collapse .main-footer{margin-left:50px !important;z-index:840}.sidebar-mini.sidebar-collapse .main-sidebar{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0);width:50px !important;z-index:850}.sidebar-mini.sidebar-collapse .sidebar-menu>li{position:relative}.sidebar-mini.sidebar-collapse .sidebar-menu>li>a{margin-right:0}.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>span{border-top-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu>li:not(.treeview)>a>span{border-bottom-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{padding-top:5px;padding-bottom:5px;border-bottom-right-radius:4px}.sidebar-mini.sidebar-collapse .main-sidebar .user-panel>.info,.sidebar-mini.sidebar-collapse .sidebar-form,.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>span,.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu,.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>.pull-right,.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>span>.pull-right,.sidebar-mini.sidebar-collapse .sidebar-menu li.header{display:none !important;-webkit-transform:translateZ(0)}.sidebar-mini.sidebar-collapse .main-header .logo{width:50px}.sidebar-mini.sidebar-collapse .main-header .logo>.logo-mini{display:block;margin-left:-15px;margin-right:-15px;font-size:18px}.sidebar-mini.sidebar-collapse .main-header .logo>.logo-lg{display:none}.sidebar-mini.sidebar-collapse .main-header .navbar{margin-left:50px}}@media (min-width:768px){.sidebar-mini:not(.sidebar-mini-expand-feature).sidebar-collapse .sidebar-menu>li:hover>a>span:not(.pull-right),.sidebar-mini:not(.sidebar-mini-expand-feature).sidebar-collapse .sidebar-menu>li:hover>.treeview-menu{display:block !important;position:absolute;width:180px;left:50px}.sidebar-mini:not(.sidebar-mini-expand-feature).sidebar-collapse .sidebar-menu>li:hover>a>span{top:0;margin-left:-3px;padding:12px 5px 12px 20px;background-color:inherit}.sidebar-mini:not(.sidebar-mini-expand-feature).sidebar-collapse .sidebar-menu>li:hover>a>.pull-right-container{position:relative !important;float:right;width:auto !important;left:180px !important;top:-22px !important;z-index:900}.sidebar-mini:not(.sidebar-mini-expand-feature).sidebar-collapse .sidebar-menu>li:hover>a>.pull-right-container>.label:not(:first-of-type){display:none}.sidebar-mini:not(.sidebar-mini-expand-feature).sidebar-collapse .sidebar-menu>li:hover>.treeview-menu{top:44px;margin-left:0}}.sidebar-expanded-on-hover .main-footer,.sidebar-expanded-on-hover .content-wrapper{margin-left:50px}.sidebar-expanded-on-hover .main-sidebar{box-shadow:3px 0 8px rgba(0,0,0,0.125)}.sidebar-menu,.main-sidebar .user-panel,.sidebar-menu>li.header{white-space:nowrap;overflow:hidden}.sidebar-menu:hover{overflow:visible}.sidebar-form,.sidebar-menu>li.header{overflow:hidden;text-overflow:clip}.sidebar-menu li>a{position:relative}.sidebar-menu li>a>.pull-right-container{position:absolute;right:10px;top:50%;margin-top:-7px}.control-sidebar-bg{position:fixed;z-index:1000;bottom:0}.control-sidebar-bg,.control-sidebar{top:0;right:-230px;width:230px;-webkit-transition:right .3s ease-in-out;-o-transition:right .3s ease-in-out;transition:right .3s ease-in-out}.control-sidebar{position:absolute;padding-top:50px;z-index:1010}@media (max-width:767px){.control-sidebar{padding-top:100px}}.control-sidebar>.tab-content{padding:10px 15px}.control-sidebar.control-sidebar-open,.control-sidebar.control-sidebar-open+.control-sidebar-bg{right:0}.control-sidebar-hold-transition .control-sidebar-bg,.control-sidebar-hold-transition .control-sidebar,.control-sidebar-hold-transition .content-wrapper{transition:none}.control-sidebar-open .control-sidebar-bg,.control-sidebar-open .control-sidebar{right:0}@media (min-width:768px){.control-sidebar-open .content-wrapper,.control-sidebar-open .right-side,.control-sidebar-open .main-footer{margin-right:230px}}.fixed .control-sidebar{position:fixed;height:100%;overflow-y:auto;padding-bottom:50px}.nav-tabs.control-sidebar-tabs>li:first-of-type>a,.nav-tabs.control-sidebar-tabs>li:first-of-type>a:hover,.nav-tabs.control-sidebar-tabs>li:first-of-type>a:focus{border-left-width:0}.nav-tabs.control-sidebar-tabs>li>a{border-radius:0}.nav-tabs.control-sidebar-tabs>li>a,.nav-tabs.control-sidebar-tabs>li>a:hover{border-top:none;border-right:none;border-left:1px solid transparent;border-bottom:1px solid transparent}.nav-tabs.control-sidebar-tabs>li>a .icon{font-size:16px}.nav-tabs.control-sidebar-tabs>li.active>a,.nav-tabs.control-sidebar-tabs>li.active>a:hover,.nav-tabs.control-sidebar-tabs>li.active>a:focus,.nav-tabs.control-sidebar-tabs>li.active>a:active{border-top:none;border-right:none;border-bottom:none}@media (max-width:768px){.nav-tabs.control-sidebar-tabs{display:table}.nav-tabs.control-sidebar-tabs>li{display:table-cell}}.control-sidebar-heading{font-weight:400;font-size:16px;padding:10px 0;margin-bottom:10px}.control-sidebar-subheading{display:block;font-weight:400;font-size:14px}.control-sidebar-menu{list-style:none;padding:0;margin:0 -15px}.control-sidebar-menu>li>a{display:block;padding:10px 15px}.control-sidebar-menu>li>a:before,.control-sidebar-menu>li>a:after{content:" ";display:table}.control-sidebar-menu>li>a:after{clear:both}.control-sidebar-menu>li>a>.control-sidebar-subheading{margin-top:0}.control-sidebar-menu .menu-icon{float:left;width:35px;height:35px;border-radius:50%;text-align:center;line-height:35px}.control-sidebar-menu .menu-info{margin-left:45px;margin-top:3px}.control-sidebar-menu .menu-info>.control-sidebar-subheading{margin:0}.control-sidebar-menu .menu-info>p{margin:0;font-size:11px}.control-sidebar-menu .progress{margin:0}.control-sidebar-dark{color:#b8c7ce}.control-sidebar-dark,.control-sidebar-dark+.control-sidebar-bg{background:#222d32}.control-sidebar-dark .nav-tabs.control-sidebar-tabs{border-bottom:#1c2529}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a{background:#181f23;color:#b8c7ce}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:focus{border-left-color:#141a1d;border-bottom-color:#141a1d}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:focus,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:active{background:#1c2529}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:hover{color:#fff}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a:focus,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a:active{background:#222d32;color:#fff}.control-sidebar-dark .control-sidebar-heading,.control-sidebar-dark .control-sidebar-subheading{color:#fff}.control-sidebar-dark .control-sidebar-menu>li>a:hover{background:#1e282c}.control-sidebar-dark .control-sidebar-menu>li>a .menu-info>p{color:#b8c7ce}.control-sidebar-light{color:#5e5e5e}.control-sidebar-light,.control-sidebar-light+.control-sidebar-bg{background:#f9fafc;border-left:1px solid #d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs{border-bottom:#d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a{background:#e8ecf4;color:#444}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:focus{border-left-color:#d2d6de;border-bottom-color:#d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:focus,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:active{background:#eff1f7}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a:focus,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a:active{background:#f9fafc;color:#111}.control-sidebar-light .control-sidebar-heading,.control-sidebar-light .control-sidebar-subheading{color:#111}.control-sidebar-light .control-sidebar-menu{margin-left:-14px}.control-sidebar-light .control-sidebar-menu>li>a:hover{background:#f4f4f5}.control-sidebar-light .control-sidebar-menu>li>a .menu-info>p{color:#5e5e5e}.dropdown-menu{box-shadow:none;border-color:#eee}.dropdown-menu>li>a{color:#777}.dropdown-menu>li>a>.glyphicon,.dropdown-menu>li>a>.fa,.dropdown-menu>li>a>.ion{margin-right:10px}.dropdown-menu>li>a:hover{background-color:#e1e3e9;color:#333}.dropdown-menu>.divider{background-color:#eee}.navbar-nav>.notifications-menu>.dropdown-menu,.navbar-nav>.messages-menu>.dropdown-menu,.navbar-nav>.tasks-menu>.dropdown-menu{width:280px;padding:0 0 0 0;margin:0;top:100%}.navbar-nav>.notifications-menu>.dropdown-menu>li,.navbar-nav>.messages-menu>.dropdown-menu>li,.navbar-nav>.tasks-menu>.dropdown-menu>li{position:relative}.navbar-nav>.notifications-menu>.dropdown-menu>li.header,.navbar-nav>.messages-menu>.dropdown-menu>li.header,.navbar-nav>.tasks-menu>.dropdown-menu>li.header{border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;background-color:#ffffff;padding:7px 10px;border-bottom:1px solid #f4f4f4;color:#444444;font-size:14px}.navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a,.navbar-nav>.messages-menu>.dropdown-menu>li.footer>a,.navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;font-size:12px;background-color:#fff;padding:7px 10px;border-bottom:1px solid #eeeeee;color:#444 !important;text-align:center}@media (max-width:991px){.navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a,.navbar-nav>.messages-menu>.dropdown-menu>li.footer>a,.navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a{background:#fff !important;color:#444 !important}}.navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a:hover,.navbar-nav>.messages-menu>.dropdown-menu>li.footer>a:hover,.navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a:hover{text-decoration:none;font-weight:normal}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu,.navbar-nav>.messages-menu>.dropdown-menu>li .menu,.navbar-nav>.tasks-menu>.dropdown-menu>li .menu{max-height:200px;margin:0;padding:0;list-style:none;overflow-x:hidden}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a,.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a,.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a{display:block;white-space:nowrap;border-bottom:1px solid #f4f4f4}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a:hover,.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:hover,.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a:hover{background:#f4f4f4;text-decoration:none}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a{color:#444444;overflow:hidden;text-overflow:ellipsis;padding:10px}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a>.glyphicon,.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a>.fa,.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a>.ion{width:20px}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a{margin:0;padding:10px 10px}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>div>img{margin:auto 10px auto auto;width:40px;height:40px}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>h4{padding:0;margin:0 0 0 45px;color:#444444;font-size:15px;position:relative}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>h4>small{color:#999999;font-size:10px;position:absolute;top:0;right:0}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>p{margin:0 0 0 45px;font-size:12px;color:#888888}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:before,.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:after{content:" ";display:table}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:after{clear:both}.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a{padding:10px}.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a>h3{font-size:14px;padding:0;margin:0 0 10px 0;color:#666666}.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a>.progress{padding:0;margin:0}.navbar-nav>.user-menu>.dropdown-menu{border-top-right-radius:0;border-top-left-radius:0;padding:1px 0 0 0;border-top-width:0;width:280px}.navbar-nav>.user-menu>.dropdown-menu,.navbar-nav>.user-menu>.dropdown-menu>.user-body{border-bottom-right-radius:4px;border-bottom-left-radius:4px}.navbar-nav>.user-menu>.dropdown-menu>li.user-header{height:175px;padding:10px;text-align:center}.navbar-nav>.user-menu>.dropdown-menu>li.user-header>img{z-index:5;height:90px;width:90px;border:3px solid;border-color:transparent;border-color:rgba(255,255,255,0.2)}.navbar-nav>.user-menu>.dropdown-menu>li.user-header>p{z-index:5;color:#fff;color:rgba(255,255,255,0.8);font-size:17px;margin-top:10px}.navbar-nav>.user-menu>.dropdown-menu>li.user-header>p>small{display:block;font-size:12px}.navbar-nav>.user-menu>.dropdown-menu>.user-body{padding:15px;border-bottom:1px solid #f4f4f4;border-top:1px solid #dddddd}.navbar-nav>.user-menu>.dropdown-menu>.user-body:before,.navbar-nav>.user-menu>.dropdown-menu>.user-body:after{content:" ";display:table}.navbar-nav>.user-menu>.dropdown-menu>.user-body:after{clear:both}.navbar-nav>.user-menu>.dropdown-menu>.user-body a{color:#444 !important}@media (max-width:991px){.navbar-nav>.user-menu>.dropdown-menu>.user-body a{background:#fff !important;color:#444 !important}}.navbar-nav>.user-menu>.dropdown-menu>.user-footer{background-color:#f9f9f9;padding:10px}.navbar-nav>.user-menu>.dropdown-menu>.user-footer:before,.navbar-nav>.user-menu>.dropdown-menu>.user-footer:after{content:" ";display:table}.navbar-nav>.user-menu>.dropdown-menu>.user-footer:after{clear:both}.navbar-nav>.user-menu>.dropdown-menu>.user-footer .btn-default{color:#666666}@media (max-width:991px){.navbar-nav>.user-menu>.dropdown-menu>.user-footer .btn-default:hover{background-color:#f9f9f9}}.navbar-nav>.user-menu .user-image{float:left;width:25px;height:25px;border-radius:50%;margin-right:10px;margin-top:-2px}@media (max-width:767px){.navbar-nav>.user-menu .user-image{float:none;margin-right:0;margin-top:-8px;line-height:10px}}.open:not(.dropup)>.animated-dropdown-menu{backface-visibility:visible !important;-webkit-animation:flipInX .7s both;-o-animation:flipInX .7s both;animation:flipInX .7s both}@keyframes flipInX{0%{transform:perspective(400px) rotate3d(1, 0, 0, 90deg);transition-timing-function:ease-in;opacity:0}40%{transform:perspective(400px) rotate3d(1, 0, 0, -20deg);transition-timing-function:ease-in}60%{transform:perspective(400px) rotate3d(1, 0, 0, 10deg);opacity:1}80%{transform:perspective(400px) rotate3d(1, 0, 0, -5deg)}100%{transform:perspective(400px)}}@-webkit-keyframes flipInX{0%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, 90deg);-webkit-transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, -20deg);-webkit-transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, 10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, -5deg)}100%{-webkit-transform:perspective(400px)}}.navbar-custom-menu>.navbar-nav>li{position:relative}.navbar-custom-menu>.navbar-nav>li>.dropdown-menu{position:absolute;right:0;left:auto}@media (max-width:991px){.navbar-custom-menu>.navbar-nav{float:right}.navbar-custom-menu>.navbar-nav>li{position:static}.navbar-custom-menu>.navbar-nav>li>.dropdown-menu{position:absolute;right:5%;left:auto;border:1px solid #ddd;background:#fff}}.form-control{border-radius:0;box-shadow:none;border-color:#d2d6de}.form-control:focus{border-color:#3c8dbc;box-shadow:none}.form-control::-moz-placeholder,.form-control:-ms-input-placeholder,.form-control::-webkit-input-placeholder{color:#bbb;opacity:1}.form-control:not(select){-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-group.has-success label{color:#00a65a}.form-group.has-success .form-control,.form-group.has-success .input-group-addon{border-color:#00a65a;box-shadow:none}.form-group.has-success .help-block{color:#00a65a}.form-group.has-warning label{color:#f39c12}.form-group.has-warning .form-control,.form-group.has-warning .input-group-addon{border-color:#f39c12;box-shadow:none}.form-group.has-warning .help-block{color:#f39c12}.form-group.has-error label{color:#dd4b39}.form-group.has-error .form-control,.form-group.has-error .input-group-addon{border-color:#dd4b39;box-shadow:none}.form-group.has-error .help-block{color:#dd4b39}.input-group .input-group-addon{border-radius:0;border-color:#d2d6de;background-color:#fff}.btn-group-vertical .btn.btn-flat:first-of-type,.btn-group-vertical .btn.btn-flat:last-of-type{border-radius:0}.icheck>label{padding-left:0}.form-control-feedback.fa{line-height:34px}.input-lg+.form-control-feedback.fa,.input-group-lg+.form-control-feedback.fa,.form-group-lg .form-control+.form-control-feedback.fa{line-height:46px}.input-sm+.form-control-feedback.fa,.input-group-sm+.form-control-feedback.fa,.form-group-sm .form-control+.form-control-feedback.fa{line-height:30px}.progress,.progress>.progress-bar{-webkit-box-shadow:none;box-shadow:none}.progress,.progress>.progress-bar,.progress .progress-bar,.progress>.progress-bar .progress-bar{border-radius:1px}.progress.sm,.progress-sm{height:10px}.progress.sm,.progress-sm,.progress.sm .progress-bar,.progress-sm .progress-bar{border-radius:1px}.progress.xs,.progress-xs{height:7px}.progress.xs,.progress-xs,.progress.xs .progress-bar,.progress-xs .progress-bar{border-radius:1px}.progress.xxs,.progress-xxs{height:3px}.progress.xxs,.progress-xxs,.progress.xxs .progress-bar,.progress-xxs .progress-bar{border-radius:1px}.progress.vertical{position:relative;width:30px;height:200px;display:inline-block;margin-right:10px}.progress.vertical>.progress-bar{width:100%;position:absolute;bottom:0}.progress.vertical.sm,.progress.vertical.progress-sm{width:20px}.progress.vertical.xs,.progress.vertical.progress-xs{width:10px}.progress.vertical.xxs,.progress.vertical.progress-xxs{width:3px}.progress-group .progress-text{font-weight:600}.progress-group .progress-number{float:right}.table tr>td .progress{margin:0}.progress-bar-light-blue,.progress-bar-primary{background-color:#3c8dbc}.progress-striped .progress-bar-light-blue,.progress-striped .progress-bar-primary{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-green,.progress-bar-success{background-color:#00a65a}.progress-striped .progress-bar-green,.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-aqua,.progress-bar-info{background-color:#00c0ef}.progress-striped .progress-bar-aqua,.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-yellow,.progress-bar-warning{background-color:#f39c12}.progress-striped .progress-bar-yellow,.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-red,.progress-bar-danger{background-color:#dd4b39}.progress-striped .progress-bar-red,.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.small-box{border-radius:2px;position:relative;display:block;margin-bottom:20px;box-shadow:0 1px 1px rgba(0,0,0,0.1)}.small-box>.inner{padding:10px}.small-box>.small-box-footer{position:relative;text-align:center;padding:3px 0;color:#fff;color:rgba(255,255,255,0.8);display:block;z-index:10;background:rgba(0,0,0,0.1);text-decoration:none}.small-box>.small-box-footer:hover{color:#fff;background:rgba(0,0,0,0.15)}.small-box h3{font-size:38px;font-weight:bold;margin:0 0 10px 0;white-space:nowrap;padding:0}.small-box p{font-size:15px}.small-box p>small{display:block;color:#f9f9f9;font-size:13px;margin-top:5px}.small-box h3,.small-box p{z-index:5}.small-box .icon{-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;position:absolute;top:-10px;right:10px;z-index:0;font-size:90px;color:rgba(0,0,0,0.15)}.small-box:hover{text-decoration:none;color:#f9f9f9}.small-box:hover .icon{font-size:95px}@media (max-width:767px){.small-box{text-align:center}.small-box .icon{display:none}.small-box p{font-size:12px}}.box{position:relative;border-radius:3px;background:#ffffff;border-top:3px solid #d2d6de;margin-bottom:20px;width:100%;box-shadow:0 1px 1px rgba(0,0,0,0.1)}.box.box-primary{border-top-color:#3c8dbc}.box.box-info{border-top-color:#00c0ef}.box.box-danger{border-top-color:#dd4b39}.box.box-warning{border-top-color:#f39c12}.box.box-success{border-top-color:#00a65a}.box.box-default{border-top-color:#d2d6de}.box.collapsed-box .box-body,.box.collapsed-box .box-footer{display:none}.box .nav-stacked>li{border-bottom:1px solid #f4f4f4;margin:0}.box .nav-stacked>li:last-of-type{border-bottom:none}.box.height-control .box-body{max-height:300px;overflow:auto}.box .border-right{border-right:1px solid #f4f4f4}.box .border-left{border-left:1px solid #f4f4f4}.box.box-solid{border-top:0}.box.box-solid>.box-header .btn.btn-default{background:transparent}.box.box-solid>.box-header .btn:hover,.box.box-solid>.box-header a:hover{background:rgba(0,0,0,0.1)}.box.box-solid.box-default{border:1px solid #d2d6de}.box.box-solid.box-default>.box-header{color:#444;background:#d2d6de;background-color:#d2d6de}.box.box-solid.box-default>.box-header a,.box.box-solid.box-default>.box-header .btn{color:#444}.box.box-solid.box-primary{border:1px solid #3c8dbc}.box.box-solid.box-primary>.box-header{color:#fff;background:#3c8dbc;background-color:#3c8dbc}.box.box-solid.box-primary>.box-header a,.box.box-solid.box-primary>.box-header .btn{color:#fff}.box.box-solid.box-info{border:1px solid #00c0ef}.box.box-solid.box-info>.box-header{color:#fff;background:#00c0ef;background-color:#00c0ef}.box.box-solid.box-info>.box-header a,.box.box-solid.box-info>.box-header .btn{color:#fff}.box.box-solid.box-danger{border:1px solid #dd4b39}.box.box-solid.box-danger>.box-header{color:#fff;background:#dd4b39;background-color:#dd4b39}.box.box-solid.box-danger>.box-header a,.box.box-solid.box-danger>.box-header .btn{color:#fff}.box.box-solid.box-warning{border:1px solid #f39c12}.box.box-solid.box-warning>.box-header{color:#fff;background:#f39c12;background-color:#f39c12}.box.box-solid.box-warning>.box-header a,.box.box-solid.box-warning>.box-header .btn{color:#fff}.box.box-solid.box-success{border:1px solid #00a65a}.box.box-solid.box-success>.box-header{color:#fff;background:#00a65a;background-color:#00a65a}.box.box-solid.box-success>.box-header a,.box.box-solid.box-success>.box-header .btn{color:#fff}.box.box-solid>.box-header>.box-tools .btn{border:0;box-shadow:none}.box.box-solid[class*='bg']>.box-header{color:#fff}.box .box-group>.box{margin-bottom:5px}.box .knob-label{text-align:center;color:#333;font-weight:100;font-size:12px;margin-bottom:.3em}.box>.overlay,.overlay-wrapper>.overlay,.box>.loading-img,.overlay-wrapper>.loading-img{position:absolute;top:0;left:0;width:100%;height:100%}.box .overlay,.overlay-wrapper .overlay{z-index:50;background:rgba(255,255,255,0.7);border-radius:3px}.box .overlay>.fa,.overlay-wrapper .overlay>.fa{position:absolute;top:50%;left:50%;margin-left:-15px;margin-top:-15px;color:#000;font-size:30px}.box .overlay.dark,.overlay-wrapper .overlay.dark{background:rgba(0,0,0,0.5)}.box-header:before,.box-body:before,.box-footer:before,.box-header:after,.box-body:after,.box-footer:after{content:" ";display:table}.box-header:after,.box-body:after,.box-footer:after{clear:both}.box-header{color:#444;display:block;padding:10px;position:relative}.box-header.with-border{border-bottom:1px solid #f4f4f4}.collapsed-box .box-header.with-border{border-bottom:none}.box-header>.fa,.box-header>.glyphicon,.box-header>.ion,.box-header .box-title{display:inline-block;font-size:18px;margin:0;line-height:1}.box-header>.fa,.box-header>.glyphicon,.box-header>.ion{margin-right:5px}.box-header>.box-tools{float:right;margin-top:-5px;margin-bottom:-5px}.box-header>.box-tools [data-toggle="tooltip"]{position:relative}.box-header>.box-tools.pull-right .dropdown-menu{right:0;left:auto}.box-header>.box-tools .dropdown-menu>li>a{color:#444 !important}.btn-box-tool{padding:5px;font-size:12px;background:transparent;color:#97a0b3}.open .btn-box-tool,.btn-box-tool:hover{color:#606c84}.btn-box-tool.btn:active{box-shadow:none}.box-body{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px;padding:10px}.no-header .box-body{border-top-right-radius:3px;border-top-left-radius:3px}.box-body>.table{margin-bottom:0}.box-body .fc{margin-top:5px}.box-body .full-width-chart{margin:-19px}.box-body.no-padding .full-width-chart{margin:-9px}.box-body .box-pane{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:3px}.box-body .box-pane-right{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:0}.box-footer{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px;border-top:1px solid #f4f4f4;padding:10px;background-color:#fff}.chart-legend{margin:10px 0}@media (max-width:991px){.chart-legend>li{float:left;margin-right:10px}}.box-comments{background:#f7f7f7}.box-comments .box-comment{padding:8px 0;border-bottom:1px solid #eee}.box-comments .box-comment:before,.box-comments .box-comment:after{content:" ";display:table}.box-comments .box-comment:after{clear:both}.box-comments .box-comment:last-of-type{border-bottom:0}.box-comments .box-comment:first-of-type{padding-top:0}.box-comments .box-comment img{float:left}.box-comments .comment-text{margin-left:40px;color:#555}.box-comments .username{color:#444;display:block;font-weight:600}.box-comments .text-muted{font-weight:400;font-size:12px}.info-box{display:block;min-height:90px;background:#fff;width:100%;box-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:2px;margin-bottom:15px}.info-box small{font-size:14px}.info-box .progress{background:rgba(0,0,0,0.2);margin:5px -10px 5px -10px;height:2px}.info-box .progress,.info-box .progress .progress-bar{border-radius:0}.info-box .progress .progress-bar{background:#fff}.info-box-icon{border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px;display:block;float:left;height:90px;width:90px;text-align:center;font-size:45px;line-height:90px;background:rgba(0,0,0,0.2)}.info-box-icon>img{max-width:100%}.info-box-content{padding:5px 10px;margin-left:90px}.info-box-number{display:block;font-weight:bold;font-size:18px}.progress-description,.info-box-text{display:block;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.info-box-text{text-transform:uppercase}.info-box-more{display:block}.progress-description{margin:0}.timeline{position:relative;margin:0 0 30px 0;padding:0;list-style:none}.timeline:before{content:'';position:absolute;top:0;bottom:0;width:4px;background:#ddd;left:31px;margin:0;border-radius:2px}.timeline>li{position:relative;margin-right:10px;margin-bottom:15px}.timeline>li:before,.timeline>li:after{content:" ";display:table}.timeline>li:after{clear:both}.timeline>li>.timeline-item{-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:3px;margin-top:0;background:#fff;color:#444;margin-left:60px;margin-right:15px;padding:0;position:relative}.timeline>li>.timeline-item>.time{color:#999;float:right;padding:10px;font-size:12px}.timeline>li>.timeline-item>.timeline-header{margin:0;color:#555;border-bottom:1px solid #f4f4f4;padding:10px;font-size:16px;line-height:1.1}.timeline>li>.timeline-item>.timeline-header>a{font-weight:600}.timeline>li>.timeline-item>.timeline-body,.timeline>li>.timeline-item>.timeline-footer{padding:10px}.timeline>li>.fa,.timeline>li>.glyphicon,.timeline>li>.ion{width:30px;height:30px;font-size:15px;line-height:30px;position:absolute;color:#666;background:#d2d6de;border-radius:50%;text-align:center;left:18px;top:0}.timeline>.time-label>span{font-weight:600;padding:5px;display:inline-block;background-color:#fff;border-radius:4px}.timeline-inverse>li>.timeline-item{background:#f0f0f0;border:1px solid #ddd;-webkit-box-shadow:none;box-shadow:none}.timeline-inverse>li>.timeline-item>.timeline-header{border-bottom-color:#ddd}.btn{border-radius:3px;-webkit-box-shadow:none;box-shadow:none;border:1px solid transparent}.btn.uppercase{text-transform:uppercase}.btn.btn-flat{border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;border-width:1px}.btn:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:focus{outline:none}.btn.btn-file{position:relative;overflow:hidden}.btn.btn-file>input[type='file']{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;opacity:0;filter:alpha(opacity=0);outline:none;background:white;cursor:inherit;display:block}.btn-default{background-color:#f4f4f4;color:#444;border-color:#ddd}.btn-default:hover,.btn-default:active,.btn-default.hover{background-color:#e7e7e7}.btn-primary{background-color:#3c8dbc;border-color:#367fa9}.btn-primary:hover,.btn-primary:active,.btn-primary.hover{background-color:#367fa9}.btn-success{background-color:#00a65a;border-color:#008d4c}.btn-success:hover,.btn-success:active,.btn-success.hover{background-color:#008d4c}.btn-info{background-color:#00c0ef;border-color:#00acd6}.btn-info:hover,.btn-info:active,.btn-info.hover{background-color:#00acd6}.btn-danger{background-color:#dd4b39;border-color:#d73925}.btn-danger:hover,.btn-danger:active,.btn-danger.hover{background-color:#d73925}.btn-warning{background-color:#f39c12;border-color:#e08e0b}.btn-warning:hover,.btn-warning:active,.btn-warning.hover{background-color:#e08e0b}.btn-outline{border:1px solid #fff;background:transparent;color:#fff}.btn-outline:hover,.btn-outline:focus,.btn-outline:active{color:rgba(255,255,255,0.7);border-color:rgba(255,255,255,0.7)}.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn[class*='bg-']:hover{-webkit-box-shadow:inset 0 0 100px rgba(0,0,0,0.2);box-shadow:inset 0 0 100px rgba(0,0,0,0.2)}.btn-app{border-radius:3px;position:relative;padding:15px 5px;margin:0 0 10px 10px;min-width:80px;height:60px;text-align:center;color:#666;border:1px solid #ddd;background-color:#f4f4f4;font-size:12px}.btn-app>.fa,.btn-app>.glyphicon,.btn-app>.ion{font-size:20px;display:block}.btn-app:hover{background:#f4f4f4;color:#444;border-color:#aaa}.btn-app:active,.btn-app:focus{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-app>.badge{position:absolute;top:-3px;right:-10px;font-size:10px;font-weight:400}.callout{border-radius:3px;margin:0 0 20px 0;padding:15px 30px 15px 15px;border-left:5px solid #eee}.callout a{color:#fff;text-decoration:underline}.callout a:hover{color:#eee}.callout h4{margin-top:0;font-weight:600}.callout p:last-child{margin-bottom:0}.callout code,.callout .highlight{background-color:#fff}.callout.callout-danger{border-color:#c23321}.callout.callout-warning{border-color:#c87f0a}.callout.callout-info{border-color:#0097bc}.callout.callout-success{border-color:#00733e}.alert{border-radius:3px}.alert h4{font-weight:600}.alert .icon{margin-right:10px}.alert .close{color:#000;opacity:.2;filter:alpha(opacity=20)}.alert .close:hover{opacity:.5;filter:alpha(opacity=50)}.nav>li>a:hover,.nav>li>a:active,.nav>li>a:focus{color:#444;background:#f7f7f7}.nav-pills>li>a{border-radius:0;border-top:3px solid transparent;color:#444}.nav-pills>li>a>.fa,.nav-pills>li>a>.glyphicon,.nav-pills>li>a>.ion{margin-right:5px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{border-top-color:#3c8dbc}.nav-pills>li.active>a{font-weight:600}.nav-stacked>li>a{border-radius:0;border-top:0;border-left:3px solid transparent;color:#444}.nav-stacked>li.active>a,.nav-stacked>li.active>a:hover{background:transparent;color:#444;border-top:0;border-left-color:#3c8dbc}.nav-stacked>li.header{border-bottom:1px solid #ddd;color:#777;margin-bottom:10px;padding:5px 10px;text-transform:uppercase}.nav-tabs-custom{margin-bottom:20px;background:#fff;box-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:3px}.nav-tabs-custom>.nav-tabs{margin:0;border-bottom-color:#f4f4f4;border-top-right-radius:3px;border-top-left-radius:3px}.nav-tabs-custom>.nav-tabs>li{border-top:3px solid transparent;margin-bottom:-2px;margin-right:5px}.nav-tabs-custom>.nav-tabs>li.disabled>a{color:#777}.nav-tabs-custom>.nav-tabs>li>a{color:#444;border-radius:0}.nav-tabs-custom>.nav-tabs>li>a.text-muted{color:#999}.nav-tabs-custom>.nav-tabs>li>a,.nav-tabs-custom>.nav-tabs>li>a:hover{background:transparent;margin:0}.nav-tabs-custom>.nav-tabs>li>a:hover{color:#999}.nav-tabs-custom>.nav-tabs>li:not(.active)>a:hover,.nav-tabs-custom>.nav-tabs>li:not(.active)>a:focus,.nav-tabs-custom>.nav-tabs>li:not(.active)>a:active{border-color:transparent}.nav-tabs-custom>.nav-tabs>li.active{border-top-color:#3c8dbc}.nav-tabs-custom>.nav-tabs>li.active>a,.nav-tabs-custom>.nav-tabs>li.active:hover>a{background-color:#fff;color:#444}.nav-tabs-custom>.nav-tabs>li.active>a{border-top-color:transparent;border-left-color:#f4f4f4;border-right-color:#f4f4f4}.nav-tabs-custom>.nav-tabs>li:first-of-type{margin-left:0}.nav-tabs-custom>.nav-tabs>li:first-of-type.active>a{border-left-color:transparent}.nav-tabs-custom>.nav-tabs.pull-right{float:none !important}.nav-tabs-custom>.nav-tabs.pull-right>li{float:right}.nav-tabs-custom>.nav-tabs.pull-right>li:first-of-type{margin-right:0}.nav-tabs-custom>.nav-tabs.pull-right>li:first-of-type>a{border-left-width:1px}.nav-tabs-custom>.nav-tabs.pull-right>li:first-of-type.active>a{border-left-color:#f4f4f4;border-right-color:transparent}.nav-tabs-custom>.nav-tabs>li.header{line-height:35px;padding:0 10px;font-size:20px;color:#444}.nav-tabs-custom>.nav-tabs>li.header>.fa,.nav-tabs-custom>.nav-tabs>li.header>.glyphicon,.nav-tabs-custom>.nav-tabs>li.header>.ion{margin-right:5px}.nav-tabs-custom>.tab-content{background:#fff;padding:10px;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.nav-tabs-custom .dropdown.open>a:active,.nav-tabs-custom .dropdown.open>a:focus{background:transparent;color:#999}.nav-tabs-custom.tab-primary>.nav-tabs>li.active{border-top-color:#3c8dbc}.nav-tabs-custom.tab-info>.nav-tabs>li.active{border-top-color:#00c0ef}.nav-tabs-custom.tab-danger>.nav-tabs>li.active{border-top-color:#dd4b39}.nav-tabs-custom.tab-warning>.nav-tabs>li.active{border-top-color:#f39c12}.nav-tabs-custom.tab-success>.nav-tabs>li.active{border-top-color:#00a65a}.nav-tabs-custom.tab-default>.nav-tabs>li.active{border-top-color:#d2d6de}.pagination>li>a{background:#fafafa;color:#666}.pagination.pagination-flat>li>a{border-radius:0 !important}.products-list{list-style:none;margin:0;padding:0}.products-list>.item{border-radius:3px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1);padding:10px 0;background:#fff}.products-list>.item:before,.products-list>.item:after{content:" ";display:table}.products-list>.item:after{clear:both}.products-list .product-img{float:left}.products-list .product-img img{width:50px;height:50px}.products-list .product-info{margin-left:60px}.products-list .product-title{font-weight:600}.products-list .product-description{display:block;color:#999;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.product-list-in-box>.item{-webkit-box-shadow:none;box-shadow:none;border-radius:0;border-bottom:1px solid #f4f4f4}.product-list-in-box>.item:last-of-type{border-bottom-width:0}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{border-top:1px solid #f4f4f4}.table>thead>tr>th{border-bottom:2px solid #f4f4f4}.table tr td .progress{margin-top:5px}.table-bordered{border:1px solid #f4f4f4}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #f4f4f4}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table.no-border,.table.no-border td,.table.no-border th{border:0}table.text-center,table.text-center td,table.text-center th{text-align:center}.table.align th{text-align:left}.table.align td{text-align:right}.label-default{background-color:#d2d6de;color:#444}.carousel-control.left,.carousel-control.right{background-image:none}.carousel-control>.fa{font-size:40px;position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-20px}.modal{background:rgba(0,0,0,0.3)}.modal-content{border-radius:0;-webkit-box-shadow:0 2px 3px rgba(0,0,0,0.125);box-shadow:0 2px 3px rgba(0,0,0,0.125);border:0}@media (min-width:768px){.modal-content{-webkit-box-shadow:0 2px 3px rgba(0,0,0,0.125);box-shadow:0 2px 3px rgba(0,0,0,0.125)}}.modal-header{border-bottom-color:#f4f4f4}.modal-footer{border-top-color:#f4f4f4}.modal-primary .modal-header,.modal-primary .modal-footer{border-color:#307095}.modal-warning .modal-header,.modal-warning .modal-footer{border-color:#c87f0a}.modal-info .modal-header,.modal-info .modal-footer{border-color:#0097bc}.modal-success .modal-header,.modal-success .modal-footer{border-color:#00733e}.modal-danger .modal-header,.modal-danger .modal-footer{border-color:#c23321}.box-widget{border:none;position:relative}.widget-user .widget-user-header{padding:20px;height:120px;border-top-right-radius:3px;border-top-left-radius:3px}.widget-user .widget-user-username{margin-top:0;margin-bottom:5px;font-size:25px;font-weight:300;text-shadow:0 1px 1px rgba(0,0,0,0.2)}.widget-user .widget-user-desc{margin-top:0}.widget-user .widget-user-image{position:absolute;top:65px;left:50%;margin-left:-45px}.widget-user .widget-user-image>img{width:90px;height:auto;border:3px solid #fff}.widget-user .box-footer{padding-top:30px}.widget-user-2 .widget-user-header{padding:20px;border-top-right-radius:3px;border-top-left-radius:3px}.widget-user-2 .widget-user-username{margin-top:5px;margin-bottom:5px;font-size:25px;font-weight:300}.widget-user-2 .widget-user-desc{margin-top:0}.widget-user-2 .widget-user-username,.widget-user-2 .widget-user-desc{margin-left:75px}.widget-user-2 .widget-user-image>img{width:65px;height:auto;float:left}.treeview-menu{display:none;list-style:none;padding:0;margin:0;padding-left:5px}.treeview-menu .treeview-menu{padding-left:20px}.treeview-menu>li{margin:0}.treeview-menu>li>a{padding:5px 5px 5px 15px;display:block;font-size:14px}.treeview-menu>li>a>.fa,.treeview-menu>li>a>.glyphicon,.treeview-menu>li>a>.ion{width:20px}.treeview-menu>li>a>.pull-right-container>.fa-angle-left,.treeview-menu>li>a>.pull-right-container>.fa-angle-down,.treeview-menu>li>a>.fa-angle-left,.treeview-menu>li>a>.fa-angle-down{width:auto}.treeview>ul.treeview-menu{overflow:hidden;height:auto;padding-top:0px !important;padding-bottom:0px !important}.treeview.menu-open>ul.treeview-menu{overflow:visible;height:auto}.mailbox-messages>.table{margin:0}.mailbox-controls{padding:5px}.mailbox-controls.with-border{border-bottom:1px solid #f4f4f4}.mailbox-read-info{border-bottom:1px solid #f4f4f4;padding:10px}.mailbox-read-info h3{font-size:20px;margin:0}.mailbox-read-info h5{margin:0;padding:5px 0 0 0}.mailbox-read-time{color:#999;font-size:13px}.mailbox-read-message{padding:10px}.mailbox-attachments li{float:left;width:200px;border:1px solid #eee;margin-bottom:10px;margin-right:10px}.mailbox-attachment-name{font-weight:bold;color:#666}.mailbox-attachment-icon,.mailbox-attachment-info,.mailbox-attachment-size{display:block}.mailbox-attachment-info{padding:10px;background:#f4f4f4}.mailbox-attachment-size{color:#999;font-size:12px}.mailbox-attachment-icon{text-align:center;font-size:65px;color:#666;padding:20px 10px}.mailbox-attachment-icon.has-img{padding:0}.mailbox-attachment-icon.has-img>img{max-width:100%;height:auto}.lockscreen{background:#d2d6de}.lockscreen-logo{font-size:35px;text-align:center;margin-bottom:25px;font-weight:300}.lockscreen-logo a{color:#444}.lockscreen-wrapper{max-width:400px;margin:0 auto;margin-top:10%}.lockscreen .lockscreen-name{text-align:center;font-weight:600}.lockscreen-item{border-radius:4px;padding:0;background:#fff;position:relative;margin:10px auto 30px auto;width:290px}.lockscreen-image{border-radius:50%;position:absolute;left:-10px;top:-25px;background:#fff;padding:5px;z-index:10}.lockscreen-image>img{border-radius:50%;width:70px;height:70px}.lockscreen-credentials{margin-left:70px}.lockscreen-credentials .form-control{border:0}.lockscreen-credentials .btn{background-color:#fff;border:0;padding:0 10px}.lockscreen-footer{margin-top:10px}.login-logo,.register-logo{font-size:35px;text-align:center;margin-bottom:25px;font-weight:300}.login-logo a,.register-logo a{color:#444}.login-page,.register-page{height:auto;background:#d2d6de}.login-box,.register-box{width:360px;margin:7% auto}@media (max-width:768px){.login-box,.register-box{width:90%;margin-top:20px}}.login-box-body,.register-box-body{background:#fff;padding:20px;border-top:0;color:#666}.login-box-body .form-control-feedback,.register-box-body .form-control-feedback{color:#777}.login-box-msg,.register-box-msg{margin:0;text-align:center;padding:0 20px 20px 20px}.social-auth-links{margin:10px 0}.error-page{width:600px;margin:20px auto 0 auto}@media (max-width:991px){.error-page{width:100%}}.error-page>.headline{float:left;font-size:100px;font-weight:300}@media (max-width:991px){.error-page>.headline{float:none;text-align:center}}.error-page>.error-content{margin-left:190px;display:block}@media (max-width:991px){.error-page>.error-content{margin-left:0}}.error-page>.error-content>h3{font-weight:300;font-size:25px}@media (max-width:991px){.error-page>.error-content>h3{text-align:center}}.invoice{position:relative;background:#fff;border:1px solid #f4f4f4;padding:20px;margin:10px 25px}.invoice-title{margin-top:0}.profile-user-img{margin:0 auto;width:100px;padding:3px;border:3px solid #d2d6de}.profile-username{font-size:21px;margin-top:5px}.post{border-bottom:1px solid #d2d6de;margin-bottom:15px;padding-bottom:15px;color:#666}.post:last-of-type{border-bottom:0;margin-bottom:0;padding-bottom:0}.post .user-block{margin-bottom:15px}.fc-button{background:#f4f4f4;background-image:none;color:#444;border-color:#ddd;border-bottom-color:#ddd}.fc-button:hover,.fc-button:active,.fc-button.hover{background-color:#e9e9e9}.fc-header-title h2{font-size:15px;line-height:1.6em;color:#666;margin-left:10px}.fc-header-right{padding-right:10px}.fc-header-left{padding-left:10px}.fc-widget-header{background:#fafafa}.fc-grid{width:100%;border:0}.fc-widget-header:first-of-type,.fc-widget-content:first-of-type{border-left:0;border-right:0}.fc-widget-header:last-of-type,.fc-widget-content:last-of-type{border-right:0}.fc-toolbar{padding:10px;margin:0}.fc-day-number{font-size:20px;font-weight:300;padding-right:10px}.fc-color-picker{list-style:none;margin:0;padding:0}.fc-color-picker>li{float:left;font-size:30px;margin-right:5px;line-height:30px}.fc-color-picker>li .fa{-webkit-transition:-webkit-transform linear .3s;-moz-transition:-moz-transform linear .3s;-o-transition:-o-transform linear .3s;transition:transform linear .3s}.fc-color-picker>li .fa:hover{-webkit-transform:rotate(30deg);-ms-transform:rotate(30deg);-o-transform:rotate(30deg);transform:rotate(30deg)}#add-new-event{-webkit-transition:all linear .3s;-o-transition:all linear .3s;transition:all linear .3s}.external-event{padding:5px 10px;font-weight:bold;margin-bottom:4px;box-shadow:0 1px 1px rgba(0,0,0,0.1);text-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:3px;cursor:move}.external-event:hover{box-shadow:inset 0 0 90px rgba(0,0,0,0.2)}.select2-container--default.select2-container--focus,.select2-selection.select2-container--focus,.select2-container--default:focus,.select2-selection:focus,.select2-container--default:active,.select2-selection:active{outline:none}.select2-container--default .select2-selection--single,.select2-selection .select2-selection--single{border:1px solid #d2d6de;border-radius:0;padding:6px 12px;height:34px}.select2-container--default.select2-container--open{border-color:#3c8dbc}.select2-dropdown{border:1px solid #d2d6de;border-radius:0}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#3c8dbc;color:white}.select2-results__option{padding:6px 12px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{padding-left:0;padding-right:0;height:auto;margin-top:-4px}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:6px;padding-left:20px}.select2-container--default .select2-selection--single .select2-selection__arrow{height:28px;right:3px}.select2-container--default .select2-selection--single .select2-selection__arrow b{margin-top:0}.select2-dropdown .select2-search__field,.select2-search--inline .select2-search__field{border:1px solid #d2d6de}.select2-dropdown .select2-search__field:focus,.select2-search--inline .select2-search__field:focus{outline:none}.select2-container--default.select2-container--focus .select2-selection--multiple,.select2-container--default .select2-search--dropdown .select2-search__field{border-color:#3c8dbc !important}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option[aria-selected=true],.select2-container--default .select2-results__option[aria-selected=true]:hover{color:#444}.select2-container--default .select2-selection--multiple{border:1px solid #d2d6de;border-radius:0}.select2-container--default .select2-selection--multiple:focus{border-color:#3c8dbc}.select2-container--default.select2-container--focus .select2-selection--multiple{border-color:#d2d6de}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#3c8dbc;border-color:#367fa9;padding:1px 10px;color:#fff}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{margin-right:5px;color:rgba(255,255,255,0.7)}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#fff}.select2-container .select2-selection--single .select2-selection__rendered{padding-right:10px}.box .datepicker-inline,.box .datepicker-inline .datepicker-days,.box .datepicker-inline>table,.box .datepicker-inline .datepicker-days>table{width:100%}.box .datepicker-inline td:hover,.box .datepicker-inline .datepicker-days td:hover,.box .datepicker-inline>table td:hover,.box .datepicker-inline .datepicker-days>table td:hover{background-color:rgba(255,255,255,0.3)}.box .datepicker-inline td.day.old,.box .datepicker-inline .datepicker-days td.day.old,.box .datepicker-inline>table td.day.old,.box .datepicker-inline .datepicker-days>table td.day.old,.box .datepicker-inline td.day.new,.box .datepicker-inline .datepicker-days td.day.new,.box .datepicker-inline>table td.day.new,.box .datepicker-inline .datepicker-days>table td.day.new{color:#777}.pad{padding:10px}.margin{margin:10px}.margin-bottom{margin-bottom:20px}.margin-bottom-none{margin-bottom:0}.margin-r-5{margin-right:5px}.inline{display:inline}.description-block{display:block;margin:10px 0;text-align:center}.description-block.margin-bottom{margin-bottom:25px}.description-block>.description-header{margin:0;padding:0;font-weight:600;font-size:16px}.description-block>.description-text{text-transform:uppercase}.bg-red,.bg-yellow,.bg-aqua,.bg-blue,.bg-light-blue,.bg-green,.bg-navy,.bg-teal,.bg-olive,.bg-lime,.bg-orange,.bg-fuchsia,.bg-purple,.bg-maroon,.bg-black,.bg-red-active,.bg-yellow-active,.bg-aqua-active,.bg-blue-active,.bg-light-blue-active,.bg-green-active,.bg-navy-active,.bg-teal-active,.bg-olive-active,.bg-lime-active,.bg-orange-active,.bg-fuchsia-active,.bg-purple-active,.bg-maroon-active,.bg-black-active,.callout.callout-danger,.callout.callout-warning,.callout.callout-info,.callout.callout-success,.label-danger,.label-info,.label-warning,.label-primary,.label-success,.modal-primary .modal-body,.modal-primary .modal-header,.modal-primary .modal-footer,.modal-warning .modal-body,.modal-warning .modal-header,.modal-warning .modal-footer,.modal-info .modal-body,.modal-info .modal-header,.modal-info .modal-footer,.modal-success .modal-body,.modal-success .modal-header,.modal-success .modal-footer,.modal-danger .modal-body,.modal-danger .modal-header,.modal-danger .modal-footer{color:#fff !important}.bg-gray{color:#000;background-color:#d2d6de !important}.bg-gray-light{background-color:#f7f7f7}.bg-black{background-color:#111 !important}.bg-red,.callout.callout-danger,.label-danger,.modal-danger .modal-body{background-color:#dd4b39 !important}.bg-yellow,.callout.callout-warning,.alert-warning,.label-warning,.modal-warning .modal-body{background-color:#f39c12 !important}.bg-aqua,.callout.callout-info,.label-info,.modal-info .modal-body{background-color:#00c0ef !important}.bg-blue{background-color:#0073b7 !important}.bg-light-blue,.label-primary,.modal-primary .modal-body{background-color:#3c8dbc !important}.bg-green,.callout.callout-success,.label-success,.modal-success .modal-body{background-color:#00a65a !important}.bg-navy{background-color:#001F3F !important}.bg-teal{background-color:#39CCCC !important}.bg-olive{background-color:#3D9970 !important}.bg-lime{background-color:#01FF70 !important}.bg-orange{background-color:#FF851B !important}.bg-fuchsia{background-color:#F012BE !important}.bg-purple{background-color:#605ca8 !important}.bg-maroon{background-color:#D81B60 !important}.bg-gray-active{color:#000;background-color:#b5bbc8 !important}.bg-black-active{background-color:#000 !important}.bg-red-active,.modal-danger .modal-header,.modal-danger .modal-footer{background-color:#d33724 !important}.bg-yellow-active,.modal-warning .modal-header,.modal-warning .modal-footer{background-color:#db8b0b !important}.bg-aqua-active,.modal-info .modal-header,.modal-info .modal-footer{background-color:#00a7d0 !important}.bg-blue-active{background-color:#005384 !important}.bg-light-blue-active,.modal-primary .modal-header,.modal-primary .modal-footer{background-color:#357ca5 !important}.bg-green-active,.modal-success .modal-header,.modal-success .modal-footer{background-color:#008d4c !important}.bg-navy-active{background-color:#001a35 !important}.bg-teal-active{background-color:#30bbbb !important}.bg-olive-active{background-color:#368763 !important}.bg-lime-active{background-color:#00e765 !important}.bg-orange-active{background-color:#ff7701 !important}.bg-fuchsia-active{background-color:#db0ead !important}.bg-purple-active{background-color:#555299 !important}.bg-maroon-active{background-color:#ca195a !important}[class^="bg-"].disabled{opacity:.65;filter:alpha(opacity=65)}.text-red{color:#dd4b39 !important}.text-yellow{color:#f39c12 !important}.text-aqua{color:#00c0ef !important}.text-blue{color:#0073b7 !important}.text-black{color:#111 !important}.text-light-blue{color:#3c8dbc !important}.text-green{color:#00a65a !important}.text-gray{color:#d2d6de !important}.text-navy{color:#001F3F !important}.text-teal{color:#39CCCC !important}.text-olive{color:#3D9970 !important}.text-lime{color:#01FF70 !important}.text-orange{color:#FF851B !important}.text-fuchsia{color:#F012BE !important}.text-purple{color:#605ca8 !important}.text-maroon{color:#D81B60 !important}.link-muted{color:#7a869d}.link-muted:hover,.link-muted:focus{color:#606c84}.link-black{color:#666}.link-black:hover,.link-black:focus{color:#999}.hide{display:none !important}.no-border{border:0 !important}.no-padding{padding:0 !important}.no-margin{margin:0 !important}.no-shadow{box-shadow:none !important}.list-unstyled,.chart-legend,.contacts-list,.users-list,.mailbox-attachments{list-style:none;margin:0;padding:0}.list-group-unbordered>.list-group-item{border-left:0;border-right:0;border-radius:0;padding-left:0;padding-right:0}.flat{border-radius:0 !important}.text-bold,.text-bold.table td,.text-bold.table th{font-weight:700}.text-sm{font-size:12px}.jqstooltip{padding:5px !important;width:auto !important;height:auto !important}.bg-teal-gradient{background:#39CCCC !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #39CCCC), color-stop(1, #7adddd)) !important;background:-ms-linear-gradient(bottom, #39CCCC, #7adddd) !important;background:-moz-linear-gradient(center bottom, #39CCCC 0%, #7adddd 100%) !important;background:-o-linear-gradient(#7adddd, #39CCCC) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#7adddd', endColorstr='#39CCCC', GradientType=0) !important;color:#fff}.bg-light-blue-gradient{background:#3c8dbc !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #3c8dbc), color-stop(1, #67a8ce)) !important;background:-ms-linear-gradient(bottom, #3c8dbc, #67a8ce) !important;background:-moz-linear-gradient(center bottom, #3c8dbc 0%, #67a8ce 100%) !important;background:-o-linear-gradient(#67a8ce, #3c8dbc) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#67a8ce', endColorstr='#3c8dbc', GradientType=0) !important;color:#fff}.bg-blue-gradient{background:#0073b7 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #0073b7), color-stop(1, #0089db)) !important;background:-ms-linear-gradient(bottom, #0073b7, #0089db) !important;background:-moz-linear-gradient(center bottom, #0073b7 0%, #0089db 100%) !important;background:-o-linear-gradient(#0089db, #0073b7) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0089db', endColorstr='#0073b7', GradientType=0) !important;color:#fff}.bg-aqua-gradient{background:#00c0ef !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #00c0ef), color-stop(1, #14d1ff)) !important;background:-ms-linear-gradient(bottom, #00c0ef, #14d1ff) !important;background:-moz-linear-gradient(center bottom, #00c0ef 0%, #14d1ff 100%) !important;background:-o-linear-gradient(#14d1ff, #00c0ef) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#14d1ff', endColorstr='#00c0ef', GradientType=0) !important;color:#fff}.bg-yellow-gradient{background:#f39c12 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #f39c12), color-stop(1, #f7bc60)) !important;background:-ms-linear-gradient(bottom, #f39c12, #f7bc60) !important;background:-moz-linear-gradient(center bottom, #f39c12 0%, #f7bc60 100%) !important;background:-o-linear-gradient(#f7bc60, #f39c12) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f7bc60', endColorstr='#f39c12', GradientType=0) !important;color:#fff}.bg-purple-gradient{background:#605ca8 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #605ca8), color-stop(1, #9491c4)) !important;background:-ms-linear-gradient(bottom, #605ca8, #9491c4) !important;background:-moz-linear-gradient(center bottom, #605ca8 0%, #9491c4 100%) !important;background:-o-linear-gradient(#9491c4, #605ca8) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#9491c4', endColorstr='#605ca8', GradientType=0) !important;color:#fff}.bg-green-gradient{background:#00a65a !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #00a65a), color-stop(1, #00ca6d)) !important;background:-ms-linear-gradient(bottom, #00a65a, #00ca6d) !important;background:-moz-linear-gradient(center bottom, #00a65a 0%, #00ca6d 100%) !important;background:-o-linear-gradient(#00ca6d, #00a65a) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ca6d', endColorstr='#00a65a', GradientType=0) !important;color:#fff}.bg-red-gradient{background:#dd4b39 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #dd4b39), color-stop(1, #e47365)) !important;background:-ms-linear-gradient(bottom, #dd4b39, #e47365) !important;background:-moz-linear-gradient(center bottom, #dd4b39 0%, #e47365 100%) !important;background:-o-linear-gradient(#e47365, #dd4b39) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e47365', endColorstr='#dd4b39', GradientType=0) !important;color:#fff}.bg-black-gradient{background:#111 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #111), color-stop(1, #2b2b2b)) !important;background:-ms-linear-gradient(bottom, #111, #2b2b2b) !important;background:-moz-linear-gradient(center bottom, #111 0%, #2b2b2b 100%) !important;background:-o-linear-gradient(#2b2b2b, #111) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#2b2b2b', endColorstr='#111', GradientType=0) !important;color:#fff}.bg-maroon-gradient{background:#D81B60 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #D81B60), color-stop(1, #e73f7c)) !important;background:-ms-linear-gradient(bottom, #D81B60, #e73f7c) !important;background:-moz-linear-gradient(center bottom, #D81B60 0%, #e73f7c 100%) !important;background:-o-linear-gradient(#e73f7c, #D81B60) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e73f7c', endColorstr='#D81B60', GradientType=0) !important;color:#fff}.description-block .description-icon{font-size:16px}.no-pad-top{padding-top:0}.position-static{position:static !important}.list-header{font-size:15px;padding:10px 4px;font-weight:bold;color:#666}.list-seperator{height:1px;background:#f4f4f4;margin:15px 0 9px 0}.list-link>a{padding:4px;color:#777}.list-link>a:hover{color:#222}.font-light{font-weight:300}.user-block:before,.user-block:after{content:" ";display:table}.user-block:after{clear:both}.user-block img{width:40px;height:40px;float:left}.user-block .username,.user-block .description,.user-block .comment{display:block;margin-left:50px}.user-block .username{font-size:16px;font-weight:600}.user-block .description{color:#999;font-size:13px}.user-block.user-block-sm .username,.user-block.user-block-sm .description,.user-block.user-block-sm .comment{margin-left:40px}.user-block.user-block-sm .username{font-size:14px}.img-sm,.img-md,.img-lg,.box-comments .box-comment img,.user-block.user-block-sm img{float:left}.img-sm,.box-comments .box-comment img,.user-block.user-block-sm img{width:30px !important;height:30px !important}.img-sm+.img-push{margin-left:40px}.img-md{width:60px;height:60px}.img-md+.img-push{margin-left:70px}.img-lg{width:100px;height:100px}.img-lg+.img-push{margin-left:110px}.img-bordered{border:3px solid #d2d6de;padding:3px}.img-bordered-sm{border:2px solid #d2d6de;padding:2px}.attachment-block{border:1px solid #f4f4f4;padding:5px;margin-bottom:10px;background:#f7f7f7}.attachment-block .attachment-img{max-width:100px;max-height:100px;height:auto;float:left}.attachment-block .attachment-pushed{margin-left:110px}.attachment-block .attachment-heading{margin:0}.attachment-block .attachment-text{color:#555}.connectedSortable{min-height:100px}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sort-highlight{background:#f4f4f4;border:1px dashed #ddd;margin-bottom:10px}.full-opacity-hover{opacity:.65;filter:alpha(opacity=65)}.full-opacity-hover:hover{opacity:1;filter:alpha(opacity=100)}.chart{position:relative;overflow:hidden;width:100%}.chart svg,.chart canvas{width:100% !important}hr{border-top:1px solid #555}#red .slider-selection{background:#f56954}#blue .slider-selection{background:#3c8dbc}#green .slider-selection{background:#00a65a}#yellow .slider-selection{background:#f39c12}#aqua .slider-selection{background:#00c0ef}#purple .slider-selection{background:#932ab6}@media print{.no-print,.main-sidebar,.left-side,.main-header,.content-header{display:none !important}.content-wrapper,.right-side,.main-footer{margin-left:0 !important;min-height:0 !important;-webkit-transform:translate(0, 0) !important;-ms-transform:translate(0, 0) !important;-o-transform:translate(0, 0) !important;transform:translate(0, 0) !important}.fixed .content-wrapper,.fixed .right-side{padding-top:0 !important}.invoice{width:100%;border:0;margin:0;padding:0}.invoice-col{float:left;width:33.3333333%}.table-responsive{overflow:auto}.table-responsive>.table tr th,.table-responsive>.table tr td{white-space:normal !important}} +.m-0{margin-top:0!important;margin-right:0!important;margin-bottom:0!important;margin-left:0!important}.mt-0{margin-top:0!important}.mr-0{margin-right:0!important}.mb-0{margin-bottom:0!important}.ml-0{margin-left:0!important}.mx-0{margin-left:0!important;margin-right:0!important}.my-0{margin-top:0!important;margin-bottom:0!important}.m-1{margin-top:5px!important;margin-right:5px!important;margin-bottom:5px!important;margin-left:5px!important}.mt-1{margin-top:5px!important}.mr-1{margin-right:5px!important}.mb-1{margin-bottom:5px!important}.ml-1{margin-left:5px!important}.mx-1{margin-left:5px!important;margin-right:5px!important}.my-1{margin-top:5px!important;margin-bottom:5px!important}.m-2{margin-top:10px!important;margin-right:10px!important;margin-bottom:10px!important;margin-left:10px!important}.mt-2{margin-top:10px!important}.mr-2{margin-right:10px!important}.mb-2{margin-bottom:10px!important}.ml-2{margin-left:10px!important}.mx-2{margin-left:10px!important;margin-right:10px!important}.my-2{margin-top:10px!important;margin-bottom:10px!important}.m-3{margin-top:15px!important;margin-right:15px!important;margin-bottom:15px!important;margin-left:15px!important}.mt-3{margin-top:15px!important}.mr-3{margin-right:15px!important}.mb-3{margin-bottom:15px!important}.ml-3{margin-left:15px!important}.mx-3{margin-left:15px!important;margin-right:15px!important}.my-3{margin-top:15px!important;margin-bottom:15px!important}.m-4{margin-top:20px!important;margin-right:20px!important;margin-bottom:20px!important;margin-left:20px!important}.mt-4{margin-top:20px!important}.mr-4{margin-right:20px!important}.mb-4{margin-bottom:20px!important}.ml-4{margin-left:20px!important}.mx-4{margin-left:20px!important;margin-right:20px!important}.my-4{margin-top:20px!important;margin-bottom:20px!important}.p-0{padding-top:0!important;padding-right:0!important;padding-bottom:0!important;padding-left:0!important}.pt-0{padding-top:0!important}.pr-0{padding-right:0!important}.pb-0{padding-bottom:0!important}.pl-0{padding-left:0!important}.px-0{padding-left:0!important;padding-right:0!important}.py-0{padding-top:0!important;padding-bottom:0!important}.p-1{padding-top:5px!important;padding-right:5px!important;padding-bottom:5px!important;padding-left:5px!important}.pt-1{padding-top:5px!important}.pr-1{padding-right:5px!important}.pb-1{padding-bottom:5px!important}.pl-1{padding-left:5px!important}.px-1{padding-left:5px!important;padding-right:5px!important}.py-1{padding-top:5px!important;padding-bottom:5px!important}.p-2{padding-top:10px!important;padding-right:10px!important;padding-bottom:10px!important;padding-left:10px!important}.pt-2{padding-top:10px!important}.pr-2{padding-right:10px!important}.pb-2{padding-bottom:10px!important}.pl-2{padding-left:10px!important}.px-2{padding-left:10px!important;padding-right:10px!important}.py-2{padding-top:10px!important;padding-bottom:10px!important}.p-3{padding-top:15px!important;padding-right:15px!important;padding-bottom:15px!important;padding-left:15px!important}.pt-3{padding-top:15px!important}.pr-3{padding-right:15px!important}.pb-3{padding-bottom:15px!important}.pl-3{padding-left:15px!important}.px-3{padding-left:15px!important;padding-right:15px!important}.py-3{padding-top:15px!important;padding-bottom:15px!important}.p-4{padding-top:20px!important;padding-right:20px!important;padding-bottom:20px!important;padding-left:20px!important}.pt-4{padding-top:20px!important}.pr-4{padding-right:20px!important}.pb-4{padding-bottom:20px!important}.pl-4{padding-left:20px!important}.px-4{padding-left:20px!important;padding-right:20px!important}.py-4{padding-top:20px!important;padding-bottom:20px!important}body{line-height:1.5715}.wrapper{height:100%}.content-wrapper{height:100%}.tab-addtabs .tab-pane{height:100%;width:100%}.row-between .col-xs-6+.col-xs-6:before{content:"-";position:absolute;left:-2%;top:6px}.navbar{height:50px;border-bottom:1px solid transparent;box-shadow:0 1px 4px rgba(0,21,41,.08)}.navbar .sidebar-toggle{line-height:1.42857143}.navbar .navbar-custom-menu{position:absolute;top:0;right:0;z-index:99;background:0 0}@media only screen and (min-width:481px){.row-flex{display:flex;flex-wrap:wrap}.row-flex>[class*=col-]{display:flex;flex-direction:column}.row-flex.row:after,.row-flex.row:before{display:flex}}@media (max-width:480px){.navbar-custom-menu ul li a{padding-left:10px;padding-right:10px}.navbar-nav>.user-menu .user-image{margin-top:-3px}}@media (max-width:767px){.wrapper .main-header .logo{border-bottom:0 solid transparent;position:absolute;top:0;z-index:1200;width:200px;left:50%;margin-left:-120px}.wrapper .main-header .navbar .dropdown-menu li>a{color:#333}.wrapper .main-header .navbar .dropdown-menu li>a:hover{background:#eee}.wrapper .main-header .navbar .dropdown-menu li.active>a{color:#fff}.wrapper .main-header .navbar .dropdown-menu li.active>a:hover{background:#222d32}.left-side,.main-sidebar{padding-top:50px}}@media (max-width:991px){.main-header .navbar-custom-menu a.btn-danger{color:#fff;background-color:#f75444}.main-header .navbar-custom-menu a.btn-primary{color:#fff;background-color:#444c69}}.sidebar-menu li.active>a>.fa-angle-left,.sidebar-menu li.active>a>.pull-right-container>.fa-angle-left{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}.sidebar-menu li.menu-open>a>.fa-angle-left,.sidebar-menu li.menu-open>a>.pull-right-container>.fa-angle-left{-webkit-transform:rotate(-90deg);-moz-transform:rotate(-90deg);-o-transform:rotate(-90deg);-ms-transform:rotate(-90deg);transform:rotate(-90deg)}.sidebar-menu .treeview-menu>li{margin:4px 0 4px 0}.panel-intro{margin-bottom:0;border:none}.panel-intro>.panel-heading{padding:15px;padding-bottom:0;background:#e8edf0;border-color:#e8edf0;position:relative}.panel-intro>.panel-heading .panel-lead{margin-bottom:15px}.panel-intro>.panel-heading .panel-lead em{display:block;font-weight:700;font-style:normal}.panel-intro>.panel-heading .panel-title{height:25px;font-weight:400;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.panel-intro>.panel-heading .panel-control{height:42px;position:absolute;top:8px;right:8px}.panel-intro>.panel-heading .panel-control .fa{font-size:14px}.panel-intro>.panel-heading .nav-tabs{border-bottom:0;margin-bottom:0}.panel-intro>.panel-heading .nav-tabs>li>a{margin-right:4px;color:#95a5a6;background-color:#d8e0e6;border:1px solid #e8edf0;border-bottom-color:transparent}.panel-intro>.panel-heading .nav-tabs>li>a:focus,.panel-intro>.panel-heading .nav-tabs>li>a:hover{border:1px solid #e8edf0;color:#7b8a8b;background-color:#c9d4dc}.panel-intro>.panel-heading .nav-tabs>li.active>a,.panel-intro>.panel-heading .nav-tabs>li.active>a:focus,.panel-intro>.panel-heading .nav-tabs>li.active>a:hover{color:#7b8a8b;background-color:#fff;border-bottom-color:transparent;cursor:default}@media (max-width:768px){.panel-intro>.panel-heading .nav-tabs{white-space:nowrap;overflow-x:auto;overflow-y:hidden;margin-bottom:-1px}.panel-intro>.panel-heading .nav-tabs>li{display:inline-block;float:none}}.skin-list li{float:left;width:33.33333%;padding:5px}.skin-list li a{display:block;box-shadow:0 0 3px rgba(0,0,0,.4)}.skin-list li a span{display:block;float:left}.skin-list li.active a{opacity:1}.skin-list li.active p{color:#fff}.small-box .icon{font-size:80px}.sidebar-menu .treeview-menu:after,.sidebar-menu .treeview-menu:before{content:"";display:table} diff --git a/public/static/css/bootstrap-table.css b/public/static/css/bootstrap-table.css new file mode 100644 index 0000000..f7beca8 --- /dev/null +++ b/public/static/css/bootstrap-table.css @@ -0,0 +1,7 @@ +.bootstrap-table .fixed-table-toolbar::after{content:"";display:block;clear:both}.bootstrap-table .fixed-table-toolbar .bs-bars,.bootstrap-table .fixed-table-toolbar .columns,.bootstrap-table .fixed-table-toolbar .search{position:relative;margin-top:10px;margin-bottom:10px}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group{display:inline-block;margin-left:-1px!important}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group>.btn{border-radius:0}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group:first-child>.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group:last-child>.btn{border-top-right-radius:4px;border-bottom-right-radius:4px}.bootstrap-table .fixed-table-toolbar .columns .dropdown-menu{text-align:left;max-height:300px;overflow:auto;-ms-overflow-style:scrollbar;z-index:1001}.bootstrap-table .fixed-table-toolbar .columns label{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.4286}.bootstrap-table .fixed-table-toolbar .columns-left{margin-right:5px}.bootstrap-table .fixed-table-toolbar .columns-right{margin-left:5px}.bootstrap-table .fixed-table-toolbar .pull-right .dropdown-menu{right:0;left:auto}.bootstrap-table .fixed-table-container{position:relative;clear:both}.bootstrap-table .fixed-table-container .table{width:100%;margin-bottom:0!important}.bootstrap-table .fixed-table-container .table td,.bootstrap-table .fixed-table-container .table th{vertical-align:middle;box-sizing:border-box}.bootstrap-table .fixed-table-container .table thead th{vertical-align:bottom;padding:0;margin:0}.bootstrap-table .fixed-table-container .table thead th:focus{outline:0 solid transparent}.bootstrap-table .fixed-table-container .table thead th.detail{width:30px}.bootstrap-table .fixed-table-container .table thead th .th-inner{padding:.75rem;vertical-align:bottom;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bootstrap-table .fixed-table-container .table thead th .sortable{cursor:pointer;background-position:right;background-repeat:no-repeat;padding-right:30px!important}.bootstrap-table .fixed-table-container .table thead th .both{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC")}.bootstrap-table .fixed-table-container .table thead th .asc{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==")}.bootstrap-table .fixed-table-container .table thead th .desc{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII= ")}.bootstrap-table .fixed-table-container .table tbody tr.selected td{background-color:rgba(0,0,0,.075)}.bootstrap-table .fixed-table-container .table tbody tr.no-records-found td{text-align:center}.bootstrap-table .fixed-table-container .table tbody tr .card-view{display:flex}.bootstrap-table .fixed-table-container .table tbody tr .card-view .card-view-title{font-weight:700;display:inline-block;min-width:30%;width:auto!important;text-align:left!important}.bootstrap-table .fixed-table-container .table tbody tr .card-view .card-view-value{width:100%!important;text-align:left!important}.bootstrap-table .fixed-table-container .table .bs-checkbox{text-align:center}.bootstrap-table .fixed-table-container .table .bs-checkbox label{margin-bottom:0}.bootstrap-table .fixed-table-container .table .bs-checkbox label input[type=checkbox],.bootstrap-table .fixed-table-container .table .bs-checkbox label input[type=radio]{margin:0 auto!important}.bootstrap-table .fixed-table-container .table.table-sm .th-inner{padding:.3rem}.bootstrap-table .fixed-table-container.fixed-height:not(.has-footer){border-bottom:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height.has-card-view{border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height .fixed-table-border{border-left:1px solid #dee2e6;border-right:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height .table thead th{border-bottom:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height .table-dark thead th{border-bottom:1px solid #32383e}.bootstrap-table .fixed-table-container .fixed-table-header{overflow:hidden}.bootstrap-table .fixed-table-container .fixed-table-body{overflow-x:auto;overflow-y:auto;height:100%}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading{align-items:center;background:#fff;display:flex;justify-content:center;position:absolute;bottom:0;width:100%;max-width:100%;z-index:1000;transition:visibility 0s,opacity .15s ease-in-out;opacity:0;visibility:hidden}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.open{visibility:visible;opacity:1}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap{align-items:baseline;display:flex;justify-content:center}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .loading-text{margin-right:6px}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap{align-items:center;display:flex;justify-content:center}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-dot,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::after,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::before{content:"";animation-duration:1.5s;animation-iteration-count:infinite;animation-name:loading;background:#212529;border-radius:50%;display:block;height:5px;margin:0 4px;opacity:0;width:5px}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-dot{animation-delay:.3s}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::after{animation-delay:.6s}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark{background:#212529}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-dot,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-wrap::after,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-wrap::before{background:#fff}.bootstrap-table .fixed-table-container .fixed-table-footer{overflow:hidden}.bootstrap-table .fixed-table-pagination::after{content:"";display:block;clear:both}.bootstrap-table .fixed-table-pagination>.pagination,.bootstrap-table .fixed-table-pagination>.pagination-detail{margin-top:10px;margin-bottom:10px}.bootstrap-table .fixed-table-pagination>.pagination-detail .pagination-info{line-height:34px;margin-right:5px}.bootstrap-table .fixed-table-pagination>.pagination-detail .page-list{display:inline-block}.bootstrap-table .fixed-table-pagination>.pagination-detail .page-list .btn-group{position:relative;display:inline-block;vertical-align:middle}.bootstrap-table .fixed-table-pagination>.pagination-detail .page-list .btn-group .dropdown-menu{margin-bottom:0}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination{margin:0}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.page-intermediate a{color:#c8c8c8}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.page-intermediate a::before{content:"\2B05"}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.page-intermediate a::after{content:"\27A1"}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.disabled a{pointer-events:none;cursor:default}.bootstrap-table.fullscreen{position:fixed;top:0;left:0;z-index:1050;width:100%!important;background:#fff;height:calc(100vh);overflow-y:scroll}.bootstrap-table.bootstrap4 .pagination-lg .page-link,.bootstrap-table.bootstrap5 .pagination-lg .page-link{padding:.5rem 1rem}.bootstrap-table.bootstrap5 .float-left{float:left}.bootstrap-table.bootstrap5 .float-right{float:right}div.fixed-table-scroll-inner{width:100%;height:200px}div.fixed-table-scroll-outer{top:0;left:0;visibility:hidden;width:200px;height:150px;overflow:hidden}@keyframes loading{0%{opacity:0}50%{opacity:1}to{opacity:0}} +.table-bottom-border{border-bottom: 2px solid #ddd;} +@media screen and (max-width:767px){.fixed-table-body{border:1px solid #ddd}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{white-space:nowrap}.columns-right{display:none;}} +.bootstrap-table.bootstrap3 .fixed-table-pagination>.pagination .page-jump-to{display:inline-block}.bootstrap-table.bootstrap3 .fixed-table-pagination>.pagination .input-group-btn{width:auto}.bootstrap-table .fixed-table-pagination>.pagination .page-jump-to input{width:70px;margin-left:5px;text-align:center;float:left} +.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle} +.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle} +.bv-form .help-block{margin-bottom:0}.bv-form .tooltip-inner{text-align:left}.nav-tabs li.bv-tab-success>a{color:#3c763d}.nav-tabs li.bv-tab-error>a{color:#a94442}.bv-form .bv-icon-no-label{top:0}.bv-form .bv-icon-input-group{top:0;z-index:100} diff --git a/public/static/css/select2.min.css b/public/static/css/select2.min.css new file mode 100644 index 0000000..dc2315a --- /dev/null +++ b/public/static/css/select2.min.css @@ -0,0 +1 @@ +.select2-container{box-sizing:border-box;display:inline-block;margin:0;position:relative;vertical-align:middle}.select2-container .select2-selection--single{box-sizing:border-box;cursor:pointer;display:block;height:28px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{display:block;padding-left:8px;padding-right:20px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-selection--single .select2-selection__clear{position:relative}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:8px;padding-left:20px}.select2-container .select2-selection--multiple{box-sizing:border-box;cursor:pointer;display:block;min-height:32px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--multiple .select2-selection__rendered{display:inline-block;overflow:hidden;padding-left:8px;text-overflow:ellipsis;white-space:nowrap}.select2-container .select2-search--inline{float:left}.select2-container .select2-search--inline .select2-search__field{box-sizing:border-box;border:none;font-size:100%;margin-top:5px;padding:0}.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-dropdown{background-color:white;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;display:block;position:absolute;left:-100000px;width:100%;z-index:1051}.select2-results{display:block}.select2-results__options{list-style:none;margin:0;padding:0}.select2-results__option{padding:6px;user-select:none;-webkit-user-select:none}.select2-results__option[aria-selected]{cursor:pointer}.select2-container--open .select2-dropdown{left:0}.select2-container--open .select2-dropdown--above{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--open .select2-dropdown--below{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-search--dropdown{display:block;padding:4px}.select2-search--dropdown .select2-search__field{padding:4px;width:100%;box-sizing:border-box}.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button{-webkit-appearance:none}.select2-search--dropdown.select2-search--hide{display:none}.select2-close-mask{border:0;margin:0;padding:0;display:block;position:fixed;left:0;top:0;min-height:100%;min-width:100%;height:auto;width:auto;opacity:0;z-index:99;background-color:#fff;filter:alpha(opacity=0)}.select2-hidden-accessible{border:0 !important;clip:rect(0 0 0 0) !important;-webkit-clip-path:inset(50%) !important;clip-path:inset(50%) !important;height:1px !important;overflow:hidden !important;padding:0 !important;position:absolute !important;width:1px !important;white-space:nowrap !important}.select2-container--default .select2-selection--single{background-color:#fff;border:1px solid #aaa;border-radius:4px}.select2-container--default .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--default .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold}.select2-container--default .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--default .select2-selection--single .select2-selection__arrow{height:26px;position:absolute;top:1px;right:1px;width:20px}.select2-container--default .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow{left:1px;right:auto}.select2-container--default.select2-container--disabled .select2-selection--single{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear{display:none}.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--default .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text}.select2-container--default .select2-selection--multiple .select2-selection__rendered{box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--default .select2-selection--multiple .select2-selection__rendered li{list-style:none}.select2-container--default .select2-selection--multiple .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-top:5px;margin-right:10px}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{color:#999;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#333}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice,.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline{float:right}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice{margin-left:5px;margin-right:auto}.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--default.select2-container--focus .select2-selection--multiple{border:solid black 1px;outline:0}.select2-container--default.select2-container--disabled .select2-selection--multiple{background-color:#eee;cursor:default}.select2-container--default.select2-container--disabled .select2-selection__choice__remove{display:none}.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple{border-top-left-radius:0;border-top-right-radius:0}.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--default .select2-search--dropdown .select2-search__field{border:1px solid #aaa}.select2-container--default .select2-search--inline .select2-search__field{background:transparent;border:none;outline:0;box-shadow:none;-webkit-appearance:textfield}.select2-container--default .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--default .select2-results__option[role=group]{padding:0}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option .select2-results__option{padding-left:1em}.select2-container--default .select2-results__option .select2-results__option .select2-results__group{padding-left:0}.select2-container--default .select2-results__option .select2-results__option .select2-results__option{margin-left:-1em;padding-left:2em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-2em;padding-left:3em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-3em;padding-left:4em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-4em;padding-left:5em}.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option{margin-left:-5em;padding-left:6em}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#5897fb;color:white}.select2-container--default .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic .select2-selection--single{background-color:#f7f7f7;border:1px solid #aaa;border-radius:4px;outline:0;background-image:-webkit-linear-gradient(top, #fff 50%, #eee 100%);background-image:-o-linear-gradient(top, #fff 50%, #eee 100%);background-image:linear-gradient(to bottom, #fff 50%, #eee 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic .select2-selection--single:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--single .select2-selection__rendered{color:#444;line-height:28px}.select2-container--classic .select2-selection--single .select2-selection__clear{cursor:pointer;float:right;font-weight:bold;margin-right:10px}.select2-container--classic .select2-selection--single .select2-selection__placeholder{color:#999}.select2-container--classic .select2-selection--single .select2-selection__arrow{background-color:#ddd;border:none;border-left:1px solid #aaa;border-top-right-radius:4px;border-bottom-right-radius:4px;height:26px;position:absolute;top:1px;right:1px;width:20px;background-image:-webkit-linear-gradient(top, #eee 50%, #ccc 100%);background-image:-o-linear-gradient(top, #eee 50%, #ccc 100%);background-image:linear-gradient(to bottom, #eee 50%, #ccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0)}.select2-container--classic .select2-selection--single .select2-selection__arrow b{border-color:#888 transparent transparent transparent;border-style:solid;border-width:5px 4px 0 4px;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute;top:50%;width:0}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear{float:left}.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow{border:none;border-right:1px solid #aaa;border-radius:0;border-top-left-radius:4px;border-bottom-left-radius:4px;left:1px;right:auto}.select2-container--classic.select2-container--open .select2-selection--single{border:1px solid #5897fb}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow{background:transparent;border:none}.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b{border-color:transparent transparent #888 transparent;border-width:0 4px 5px 4px}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single{border-top:none;border-top-left-radius:0;border-top-right-radius:0;background-image:-webkit-linear-gradient(top, #fff 0%, #eee 50%);background-image:-o-linear-gradient(top, #fff 0%, #eee 50%);background-image:linear-gradient(to bottom, #fff 0%, #eee 50%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0)}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;background-image:-webkit-linear-gradient(top, #eee 50%, #fff 100%);background-image:-o-linear-gradient(top, #eee 50%, #fff 100%);background-image:linear-gradient(to bottom, #eee 50%, #fff 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0)}.select2-container--classic .select2-selection--multiple{background-color:white;border:1px solid #aaa;border-radius:4px;cursor:text;outline:0}.select2-container--classic .select2-selection--multiple:focus{border:1px solid #5897fb}.select2-container--classic .select2-selection--multiple .select2-selection__rendered{list-style:none;margin:0;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__clear{display:none}.select2-container--classic .select2-selection--multiple .select2-selection__choice{background-color:#e4e4e4;border:1px solid #aaa;border-radius:4px;cursor:default;float:left;margin-right:5px;margin-top:5px;padding:0 5px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove{color:#888;cursor:pointer;display:inline-block;font-weight:bold;margin-right:2px}.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover{color:#555}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice{float:right;margin-left:5px;margin-right:auto}.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove{margin-left:2px;margin-right:auto}.select2-container--classic.select2-container--open .select2-selection--multiple{border:1px solid #5897fb}.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple{border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--classic .select2-search--dropdown .select2-search__field{border:1px solid #aaa;outline:0}.select2-container--classic .select2-search--inline .select2-search__field{outline:0;box-shadow:none}.select2-container--classic .select2-dropdown{background-color:#fff;border:1px solid transparent}.select2-container--classic .select2-dropdown--above{border-bottom:none}.select2-container--classic .select2-dropdown--below{border-top:none}.select2-container--classic .select2-results>.select2-results__options{max-height:200px;overflow-y:auto}.select2-container--classic .select2-results__option[role=group]{padding:0}.select2-container--classic .select2-results__option[aria-disabled=true]{color:grey}.select2-container--classic .select2-results__option--highlighted[aria-selected]{background-color:#3875d7;color:#fff}.select2-container--classic .select2-results__group{cursor:default;display:block;padding:6px}.select2-container--classic.select2-container--open .select2-dropdown{border-color:#5897fb} diff --git a/public/static/css/skins/skin-black-blue.css b/public/static/css/skins/skin-black-blue.css new file mode 100644 index 0000000..d3042d0 --- /dev/null +++ b/public/static/css/skins/skin-black-blue.css @@ -0,0 +1,242 @@ +/* + * Skin: Black blue + * ----------- + */ +.skin-black-blue .main-header { + background: #222d32; + -webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); +} +.skin-black-blue .main-header .navbar { + background-color: #fff; +} +.skin-black-blue .main-header .navbar .nav > li > a { + color: #666; +} +.skin-black-blue .main-header .navbar .nav > li > a:hover, +.skin-black-blue .main-header .navbar .nav > li > a:active, +.skin-black-blue .main-header .navbar .nav > li > a:focus, +.skin-black-blue .main-header .navbar .nav .open > a, +.skin-black-blue .main-header .navbar .nav .open > a:hover, +.skin-black-blue .main-header .navbar .nav .open > a:focus, +.skin-black-blue .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.02); + color: #333; +} +.skin-black-blue .main-header .navbar .nav-addtabs li > .close-tab { + color: #333; +} +.skin-black-blue .main-header .navbar .sidebar-toggle { + color: #666; +} +.skin-black-blue .main-header .navbar .sidebar-toggle:hover { + color: #333; + background: rgba(0, 0, 0, 0.02); +} +.skin-black-blue .main-header .navbar .navbar-nav > li > a { + border-right: none; +} +.skin-black-blue .main-header .navbar .navbar-custom-menu .navbar-nav > li > a, +.skin-black-blue .main-header .navbar .navbar-right > li > a { + border-left: none; + border-right-width: 0; +} +@media (max-width: 767px) { + .skin-black-blue .main-header .navbar { + background-color: #181f23; + } + .skin-black-blue .main-header .navbar .nav > li > a { + color: #fff; + } + .skin-black-blue .main-header .navbar .nav > li > a:hover, + .skin-black-blue .main-header .navbar .nav > li > a:active, + .skin-black-blue .main-header .navbar .nav > li > a:focus, + .skin-black-blue .main-header .navbar .nav .open > a, + .skin-black-blue .main-header .navbar .nav .open > a:hover, + .skin-black-blue .main-header .navbar .nav .open > a:focus, + .skin-black-blue .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.1); + color: #f6f6f6; + } + .skin-black-blue .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; + } + .skin-black-blue .main-header .navbar .sidebar-toggle { + color: #fff; + } + .skin-black-blue .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.1); + } +} +.skin-black-blue .main-header .logo { + background-color: #222d32; + color: #fff; + border-bottom: 0 solid transparent; + border-right: 1px solid #222d32; +} +.skin-black-blue .main-header .logo:hover { + background-color: #202a2f; +} +@media (max-width: 767px) { + .skin-black-blue .main-header .logo { + background-color: #181f23; + color: #fff; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-black-blue .main-header .logo:hover { + background-color: #161d20; + } +} +.skin-black-blue .main-header li.user-header { + background-color: #222d32; +} +.skin-black-blue .main-header .nav-addtabs > li > a, +.skin-black-blue .main-header .nav-addtabs > li.active > a { + border-right-color: transparent; +} +.skin-black-blue .content-header { + background: transparent; + box-shadow: none; +} +.skin-black-blue .wrapper, +.skin-black-blue .main-sidebar, +.skin-black-blue .left-side { + background-color: #222d32; +} +.skin-black-blue .user-panel > .info, +.skin-black-blue .user-panel > .info > a { + color: #fff; +} +.skin-black-blue .sidebar-menu .treeview-menu { + padding-left: 3px; +} +.skin-black-blue .sidebar-menu > li.header { + color: #4b646f; + background: #1a2226; +} +.skin-black-blue .sidebar-menu > li:hover > a, +.skin-black-blue .sidebar-menu > li.active > a { + color: #fff; + background: #1e282c; + border-left-color: #fff; +} +.skin-black-blue .sidebar-menu > li > .treeview-menu { + background: #181f23; +} +.skin-black-blue .sidebar a { + color: #b8c7ce; +} +.skin-black-blue .sidebar a:hover { + text-decoration: none; +} +.skin-black-blue .treeview-menu > li > a { + color: #6c8c9b; +} +.skin-black-blue .treeview-menu > li.active > a, +.skin-black-blue .treeview-menu > li > a:hover { + color: #fff; +} +.skin-black-blue .sidebar-form { + border-radius: 3px; + border: 1px solid #374850; + background-color: #374850; + margin: 10px 10px; +} +.skin-black-blue .sidebar-form input[type="text"], +.skin-black-blue .sidebar-form .btn { + box-shadow: none; + background-color: #374850; + border: 1px solid transparent; + height: 35px; +} +.skin-black-blue .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-black-blue .sidebar-form input[type="text"]:focus, +.skin-black-blue .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-black-blue .sidebar-form input[type="text"]:focus + .input-group-btn { + background: #fff; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black-blue .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-black-blue .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black-blue .treeview-menu > li > a { + padding-left: 18px; +} +.skin-black-blue .treeview-menu > li.active > a { + background-color: #4e73df; +} +.skin-black-blue .sidebar-menu > li.active > a { + color: #fff; + background: #4e73df; + border-left-color: #4e73df; +} +.skin-black-blue .sidebar-menu > li:hover > a { + border-left-color: transparent; +} +.skin-black-blue .sidebar-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +.skin-black-blue .sidebar-menu li.treeview.active > a, +.skin-black-blue .sidebar-menu li.treeview.treeview-open > a { + background-color: #181f23; + border-left-color: #181f23; +} +.skin-black-blue .sidebar-menu .treeview-menu { + padding-left: 0; +} +.skin-black-blue .sidebar-menu .treeview-menu .treeview-menu { + padding-left: 0; +} +.skin-black-blue .sidebar-menu .treeview-menu .treeview-menu > li > a { + padding-left: 30px; +} +.skin-black-blue .sidebar-menu .treeview-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +.skin-black-blue.sidebar-collapse .sidebar-menu li:hover > a, +.skin-black-blue.sidebar-collapse .sidebar-menu li.active > a { + color: #fff; + background: #4e73df; +} +.skin-black-blue.sidebar-collapse .sidebar-menu .treeview-menu li.active > a { + color: #fff; + background: #4e73df; +} +.skin-black-blue.sidebar-collapse .sidebar-menu .treeview-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +@media (max-width: 767px) { + .skin-black-blue.multiplenav .sidebar .mobilenav a.btn-app { + background: #374850; + color: #fff; + } + .skin-black-blue.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #4e73df; + color: #fff; + } +} +/*# sourceMappingURL=skin-black-blue.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-black-green.css b/public/static/css/skins/skin-black-green.css new file mode 100644 index 0000000..ba82498 --- /dev/null +++ b/public/static/css/skins/skin-black-green.css @@ -0,0 +1,242 @@ +/* + * Skin: Black green + * ----------- + */ +.skin-black-green .main-header { + background: #222d32; + -webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); +} +.skin-black-green .main-header .navbar { + background-color: #fff; +} +.skin-black-green .main-header .navbar .nav > li > a { + color: #666; +} +.skin-black-green .main-header .navbar .nav > li > a:hover, +.skin-black-green .main-header .navbar .nav > li > a:active, +.skin-black-green .main-header .navbar .nav > li > a:focus, +.skin-black-green .main-header .navbar .nav .open > a, +.skin-black-green .main-header .navbar .nav .open > a:hover, +.skin-black-green .main-header .navbar .nav .open > a:focus, +.skin-black-green .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.02); + color: #333; +} +.skin-black-green .main-header .navbar .nav-addtabs li > .close-tab { + color: #333; +} +.skin-black-green .main-header .navbar .sidebar-toggle { + color: #666; +} +.skin-black-green .main-header .navbar .sidebar-toggle:hover { + color: #333; + background: rgba(0, 0, 0, 0.02); +} +.skin-black-green .main-header .navbar .navbar-nav > li > a { + border-right: none; +} +.skin-black-green .main-header .navbar .navbar-custom-menu .navbar-nav > li > a, +.skin-black-green .main-header .navbar .navbar-right > li > a { + border-left: none; + border-right-width: 0; +} +@media (max-width: 767px) { + .skin-black-green .main-header .navbar { + background-color: #181f23; + } + .skin-black-green .main-header .navbar .nav > li > a { + color: #fff; + } + .skin-black-green .main-header .navbar .nav > li > a:hover, + .skin-black-green .main-header .navbar .nav > li > a:active, + .skin-black-green .main-header .navbar .nav > li > a:focus, + .skin-black-green .main-header .navbar .nav .open > a, + .skin-black-green .main-header .navbar .nav .open > a:hover, + .skin-black-green .main-header .navbar .nav .open > a:focus, + .skin-black-green .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.1); + color: #f6f6f6; + } + .skin-black-green .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; + } + .skin-black-green .main-header .navbar .sidebar-toggle { + color: #fff; + } + .skin-black-green .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.1); + } +} +.skin-black-green .main-header .logo { + background-color: #222d32; + color: #fff; + border-bottom: 0 solid transparent; + border-right: 1px solid #222d32; +} +.skin-black-green .main-header .logo:hover { + background-color: #202a2f; +} +@media (max-width: 767px) { + .skin-black-green .main-header .logo { + background-color: #181f23; + color: #fff; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-black-green .main-header .logo:hover { + background-color: #161d20; + } +} +.skin-black-green .main-header li.user-header { + background-color: #222d32; +} +.skin-black-green .main-header .nav-addtabs > li > a, +.skin-black-green .main-header .nav-addtabs > li.active > a { + border-right-color: transparent; +} +.skin-black-green .content-header { + background: transparent; + box-shadow: none; +} +.skin-black-green .wrapper, +.skin-black-green .main-sidebar, +.skin-black-green .left-side { + background-color: #222d32; +} +.skin-black-green .user-panel > .info, +.skin-black-green .user-panel > .info > a { + color: #fff; +} +.skin-black-green .sidebar-menu .treeview-menu { + padding-left: 3px; +} +.skin-black-green .sidebar-menu > li.header { + color: #4b646f; + background: #1a2226; +} +.skin-black-green .sidebar-menu > li:hover > a, +.skin-black-green .sidebar-menu > li.active > a { + color: #fff; + background: #1e282c; + border-left-color: #fff; +} +.skin-black-green .sidebar-menu > li > .treeview-menu { + background: #181f23; +} +.skin-black-green .sidebar a { + color: #b8c7ce; +} +.skin-black-green .sidebar a:hover { + text-decoration: none; +} +.skin-black-green .treeview-menu > li > a { + color: #6c8c9b; +} +.skin-black-green .treeview-menu > li.active > a, +.skin-black-green .treeview-menu > li > a:hover { + color: #fff; +} +.skin-black-green .sidebar-form { + border-radius: 3px; + border: 1px solid #374850; + background-color: #374850; + margin: 10px 10px; +} +.skin-black-green .sidebar-form input[type="text"], +.skin-black-green .sidebar-form .btn { + box-shadow: none; + background-color: #374850; + border: 1px solid transparent; + height: 35px; +} +.skin-black-green .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-black-green .sidebar-form input[type="text"]:focus, +.skin-black-green .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-black-green .sidebar-form input[type="text"]:focus + .input-group-btn { + background: #fff; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black-green .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-black-green .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black-green .treeview-menu > li > a { + padding-left: 18px; +} +.skin-black-green .treeview-menu > li.active > a { + background-color: #18bc9c; +} +.skin-black-green .sidebar-menu > li.active > a { + color: #fff; + background: #18bc9c; + border-left-color: #18bc9c; +} +.skin-black-green .sidebar-menu > li:hover > a { + border-left-color: transparent; +} +.skin-black-green .sidebar-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +.skin-black-green .sidebar-menu li.treeview.active > a, +.skin-black-green .sidebar-menu li.treeview.treeview-open > a { + background-color: #181f23; + border-left-color: #181f23; +} +.skin-black-green .sidebar-menu .treeview-menu { + padding-left: 0; +} +.skin-black-green .sidebar-menu .treeview-menu .treeview-menu { + padding-left: 0; +} +.skin-black-green .sidebar-menu .treeview-menu .treeview-menu > li > a { + padding-left: 30px; +} +.skin-black-green .sidebar-menu .treeview-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +.skin-black-green.sidebar-collapse .sidebar-menu li:hover > a, +.skin-black-green.sidebar-collapse .sidebar-menu li.active > a { + color: #fff; + background: #18bc9c; +} +.skin-black-green.sidebar-collapse .sidebar-menu .treeview-menu li.active > a { + color: #fff; + background: #18bc9c; +} +.skin-black-green.sidebar-collapse .sidebar-menu .treeview-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +@media (max-width: 767px) { + .skin-black-green.multiplenav .sidebar .mobilenav a.btn-app { + background: #374850; + color: #fff; + } + .skin-black-green.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #18bc9c; + color: #fff; + } +} +/*# sourceMappingURL=skin-black-green.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-black-light.css b/public/static/css/skins/skin-black-light.css new file mode 100644 index 0000000..67dd410 --- /dev/null +++ b/public/static/css/skins/skin-black-light.css @@ -0,0 +1,192 @@ +/* + * Skin: Black light + * ----------- + */ +.skin-black-light .main-header { + -webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); +} +.skin-black-light .main-header .navbar-toggle { + color: #333; +} +.skin-black-light .main-header .navbar-brand { + color: #333; + border-right: 1px solid #eee; +} +.skin-black-light .main-header .navbar { + background-color: #222d32; +} +.skin-black-light .main-header .navbar .nav > li > a { + color: #fff; +} +.skin-black-light .main-header .navbar .nav > li > a:hover, +.skin-black-light .main-header .navbar .nav > li > a:active, +.skin-black-light .main-header .navbar .nav > li > a:focus, +.skin-black-light .main-header .navbar .nav .open > a, +.skin-black-light .main-header .navbar .nav .open > a:hover, +.skin-black-light .main-header .navbar .nav .open > a:focus, +.skin-black-light .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.3); + color: #f6f6f6; +} +.skin-black-light .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; +} +.skin-black-light .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-black-light .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.3); +} +.skin-black-light .main-header .navbar .navbar-nav > li > a { + color: #fff; +} +.skin-black-light .main-header .navbar .navbar-custom-menu .navbar-nav > li > a, +.skin-black-light .main-header .navbar .navbar-right > li > a { + border-left: none; + border-right-width: 0; +} +.skin-black-light .main-header .logo { + background-color: #222d32; + color: #fff; + border-bottom: 0 solid transparent; +} +.skin-black-light .main-header .logo:hover { + background-color: #202a2f; +} +@media (max-width: 767px) { + .skin-black-light .main-header .logo { + background-color: #222d32; + color: #fff; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-black-light .main-header .logo:hover { + background-color: #202a2f; + } +} +.skin-black-light .main-header li.user-header { + background-color: #222d32; +} +.skin-black-light .content-header { + background: transparent; + box-shadow: none; +} +.skin-black-light .wrapper, +.skin-black-light .main-sidebar, +.skin-black-light .left-side { + background-color: #f9fafc; +} +.skin-black-light .content-wrapper, +.skin-black-light .main-footer { + border-left: 1px solid #d2d6de; +} +.skin-black-light .user-panel > .info, +.skin-black-light .user-panel > .info > a { + color: #444; +} +.skin-black-light .sidebar-menu > li { + -webkit-transition: border-left-color 0.3s ease; + -o-transition: border-left-color 0.3s ease; + transition: border-left-color 0.3s ease; +} +.skin-black-light .sidebar-menu > li.header { + color: #848484; + background: #f9fafc; +} +.skin-black-light .sidebar-menu > li:hover > a, +.skin-black-light .sidebar-menu > li.active > a { + color: #000; + background: #f4f4f5; + border-left-color: #222d32; +} +.skin-black-light .sidebar-menu > li.active { + border-left-color: #222d32; +} +.skin-black-light .sidebar-menu > li > .treeview-menu { + background: #f4f4f5; +} +.skin-black-light .sidebar a { + color: #444; +} +.skin-black-light .sidebar a:hover { + text-decoration: none; +} +.skin-black-light .treeview-menu > li > a { + color: #777; +} +.skin-black-light .treeview-menu > li.active > a, +.skin-black-light .treeview-menu > li > a:hover { + color: #000; +} +.skin-black-light .treeview-menu > li.active > a { + font-weight: 600; +} +.skin-black-light .sidebar-form { + border-radius: 3px; + border: 1px solid #d2d6de; + margin: 10px 10px; +} +.skin-black-light .sidebar-form input[type="text"], +.skin-black-light .sidebar-form .btn { + box-shadow: none; + background-color: #fff; + border: 1px solid transparent; + height: 35px; +} +.skin-black-light .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-black-light .sidebar-form input[type="text"]:focus, +.skin-black-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-black-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-black-light .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +@media (min-width: 768px) { + .skin-black-light.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu { + border-left: 1px solid #d2d6de; + } +} +.skin-black-light .sidebar-menu > li > a { + border-left: 3px solid transparent; + padding-left: 12px; +} +@media (min-width: 768px) { + .skin-black-light.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right) { + margin-left: -3px; + } +} +.skin-black-light .main-sidebar { + -webkit-box-shadow: 7px 0 14px rgba(0, 0, 0, 0.03); + box-shadow: 7px 0 14px rgba(0, 0, 0, 0.03); +} +.skin-black-light .content-wrapper, +.skin-black-light .main-footer { + border-left: none; +} +@media (max-width: 767px) { + .skin-black-light.multiplenav .sidebar .mobilenav a.btn-app { + background: #eceff3; + color: #757575; + } + .skin-black-light.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #222d32; + color: #fff; + } +} +/*# sourceMappingURL=skin-black-light.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-black-pink.css b/public/static/css/skins/skin-black-pink.css new file mode 100644 index 0000000..a9b2e5e --- /dev/null +++ b/public/static/css/skins/skin-black-pink.css @@ -0,0 +1,242 @@ +/* + * Skin: Black pink + * ----------- + */ +.skin-black-pink .main-header { + background: #222d32; + -webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); +} +.skin-black-pink .main-header .navbar { + background-color: #fff; +} +.skin-black-pink .main-header .navbar .nav > li > a { + color: #666; +} +.skin-black-pink .main-header .navbar .nav > li > a:hover, +.skin-black-pink .main-header .navbar .nav > li > a:active, +.skin-black-pink .main-header .navbar .nav > li > a:focus, +.skin-black-pink .main-header .navbar .nav .open > a, +.skin-black-pink .main-header .navbar .nav .open > a:hover, +.skin-black-pink .main-header .navbar .nav .open > a:focus, +.skin-black-pink .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.02); + color: #333; +} +.skin-black-pink .main-header .navbar .nav-addtabs li > .close-tab { + color: #333; +} +.skin-black-pink .main-header .navbar .sidebar-toggle { + color: #666; +} +.skin-black-pink .main-header .navbar .sidebar-toggle:hover { + color: #333; + background: rgba(0, 0, 0, 0.02); +} +.skin-black-pink .main-header .navbar .navbar-nav > li > a { + border-right: none; +} +.skin-black-pink .main-header .navbar .navbar-custom-menu .navbar-nav > li > a, +.skin-black-pink .main-header .navbar .navbar-right > li > a { + border-left: none; + border-right-width: 0; +} +@media (max-width: 767px) { + .skin-black-pink .main-header .navbar { + background-color: #181f23; + } + .skin-black-pink .main-header .navbar .nav > li > a { + color: #fff; + } + .skin-black-pink .main-header .navbar .nav > li > a:hover, + .skin-black-pink .main-header .navbar .nav > li > a:active, + .skin-black-pink .main-header .navbar .nav > li > a:focus, + .skin-black-pink .main-header .navbar .nav .open > a, + .skin-black-pink .main-header .navbar .nav .open > a:hover, + .skin-black-pink .main-header .navbar .nav .open > a:focus, + .skin-black-pink .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.1); + color: #f6f6f6; + } + .skin-black-pink .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; + } + .skin-black-pink .main-header .navbar .sidebar-toggle { + color: #fff; + } + .skin-black-pink .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.1); + } +} +.skin-black-pink .main-header .logo { + background-color: #222d32; + color: #fff; + border-bottom: 0 solid transparent; + border-right: 1px solid #222d32; +} +.skin-black-pink .main-header .logo:hover { + background-color: #202a2f; +} +@media (max-width: 767px) { + .skin-black-pink .main-header .logo { + background-color: #181f23; + color: #fff; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-black-pink .main-header .logo:hover { + background-color: #161d20; + } +} +.skin-black-pink .main-header li.user-header { + background-color: #222d32; +} +.skin-black-pink .main-header .nav-addtabs > li > a, +.skin-black-pink .main-header .nav-addtabs > li.active > a { + border-right-color: transparent; +} +.skin-black-pink .content-header { + background: transparent; + box-shadow: none; +} +.skin-black-pink .wrapper, +.skin-black-pink .main-sidebar, +.skin-black-pink .left-side { + background-color: #222d32; +} +.skin-black-pink .user-panel > .info, +.skin-black-pink .user-panel > .info > a { + color: #fff; +} +.skin-black-pink .sidebar-menu .treeview-menu { + padding-left: 3px; +} +.skin-black-pink .sidebar-menu > li.header { + color: #4b646f; + background: #1a2226; +} +.skin-black-pink .sidebar-menu > li:hover > a, +.skin-black-pink .sidebar-menu > li.active > a { + color: #fff; + background: #1e282c; + border-left-color: #fff; +} +.skin-black-pink .sidebar-menu > li > .treeview-menu { + background: #181f23; +} +.skin-black-pink .sidebar a { + color: #b8c7ce; +} +.skin-black-pink .sidebar a:hover { + text-decoration: none; +} +.skin-black-pink .treeview-menu > li > a { + color: #6c8c9b; +} +.skin-black-pink .treeview-menu > li.active > a, +.skin-black-pink .treeview-menu > li > a:hover { + color: #fff; +} +.skin-black-pink .sidebar-form { + border-radius: 3px; + border: 1px solid #374850; + background-color: #374850; + margin: 10px 10px; +} +.skin-black-pink .sidebar-form input[type="text"], +.skin-black-pink .sidebar-form .btn { + box-shadow: none; + background-color: #374850; + border: 1px solid transparent; + height: 35px; +} +.skin-black-pink .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-black-pink .sidebar-form input[type="text"]:focus, +.skin-black-pink .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-black-pink .sidebar-form input[type="text"]:focus + .input-group-btn { + background: #fff; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black-pink .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-black-pink .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black-pink .treeview-menu > li > a { + padding-left: 18px; +} +.skin-black-pink .treeview-menu > li.active > a { + background-color: #f5549f; +} +.skin-black-pink .sidebar-menu > li.active > a { + color: #fff; + background: #f5549f; + border-left-color: #f5549f; +} +.skin-black-pink .sidebar-menu > li:hover > a { + border-left-color: transparent; +} +.skin-black-pink .sidebar-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +.skin-black-pink .sidebar-menu li.treeview.active > a, +.skin-black-pink .sidebar-menu li.treeview.treeview-open > a { + background-color: #181f23; + border-left-color: #181f23; +} +.skin-black-pink .sidebar-menu .treeview-menu { + padding-left: 0; +} +.skin-black-pink .sidebar-menu .treeview-menu .treeview-menu { + padding-left: 0; +} +.skin-black-pink .sidebar-menu .treeview-menu .treeview-menu > li > a { + padding-left: 30px; +} +.skin-black-pink .sidebar-menu .treeview-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +.skin-black-pink.sidebar-collapse .sidebar-menu li:hover > a, +.skin-black-pink.sidebar-collapse .sidebar-menu li.active > a { + color: #fff; + background: #f5549f; +} +.skin-black-pink.sidebar-collapse .sidebar-menu .treeview-menu li.active > a { + color: #fff; + background: #f5549f; +} +.skin-black-pink.sidebar-collapse .sidebar-menu .treeview-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +@media (max-width: 767px) { + .skin-black-pink.multiplenav .sidebar .mobilenav a.btn-app { + background: #374850; + color: #fff; + } + .skin-black-pink.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #f5549f; + color: #fff; + } +} +/*# sourceMappingURL=skin-black-pink.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-black-purple.css b/public/static/css/skins/skin-black-purple.css new file mode 100644 index 0000000..f81d581 --- /dev/null +++ b/public/static/css/skins/skin-black-purple.css @@ -0,0 +1,242 @@ +/* + * Skin: Black purple + * ----------- + */ +.skin-black-purple .main-header { + background: #222d32; + -webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); +} +.skin-black-purple .main-header .navbar { + background-color: #fff; +} +.skin-black-purple .main-header .navbar .nav > li > a { + color: #666; +} +.skin-black-purple .main-header .navbar .nav > li > a:hover, +.skin-black-purple .main-header .navbar .nav > li > a:active, +.skin-black-purple .main-header .navbar .nav > li > a:focus, +.skin-black-purple .main-header .navbar .nav .open > a, +.skin-black-purple .main-header .navbar .nav .open > a:hover, +.skin-black-purple .main-header .navbar .nav .open > a:focus, +.skin-black-purple .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.02); + color: #333; +} +.skin-black-purple .main-header .navbar .nav-addtabs li > .close-tab { + color: #333; +} +.skin-black-purple .main-header .navbar .sidebar-toggle { + color: #666; +} +.skin-black-purple .main-header .navbar .sidebar-toggle:hover { + color: #333; + background: rgba(0, 0, 0, 0.02); +} +.skin-black-purple .main-header .navbar .navbar-nav > li > a { + border-right: none; +} +.skin-black-purple .main-header .navbar .navbar-custom-menu .navbar-nav > li > a, +.skin-black-purple .main-header .navbar .navbar-right > li > a { + border-left: none; + border-right-width: 0; +} +@media (max-width: 767px) { + .skin-black-purple .main-header .navbar { + background-color: #181f23; + } + .skin-black-purple .main-header .navbar .nav > li > a { + color: #fff; + } + .skin-black-purple .main-header .navbar .nav > li > a:hover, + .skin-black-purple .main-header .navbar .nav > li > a:active, + .skin-black-purple .main-header .navbar .nav > li > a:focus, + .skin-black-purple .main-header .navbar .nav .open > a, + .skin-black-purple .main-header .navbar .nav .open > a:hover, + .skin-black-purple .main-header .navbar .nav .open > a:focus, + .skin-black-purple .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.1); + color: #f6f6f6; + } + .skin-black-purple .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; + } + .skin-black-purple .main-header .navbar .sidebar-toggle { + color: #fff; + } + .skin-black-purple .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.1); + } +} +.skin-black-purple .main-header .logo { + background-color: #222d32; + color: #fff; + border-bottom: 0 solid transparent; + border-right: 1px solid #222d32; +} +.skin-black-purple .main-header .logo:hover { + background-color: #202a2f; +} +@media (max-width: 767px) { + .skin-black-purple .main-header .logo { + background-color: #181f23; + color: #fff; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-black-purple .main-header .logo:hover { + background-color: #161d20; + } +} +.skin-black-purple .main-header li.user-header { + background-color: #222d32; +} +.skin-black-purple .main-header .nav-addtabs > li > a, +.skin-black-purple .main-header .nav-addtabs > li.active > a { + border-right-color: transparent; +} +.skin-black-purple .content-header { + background: transparent; + box-shadow: none; +} +.skin-black-purple .wrapper, +.skin-black-purple .main-sidebar, +.skin-black-purple .left-side { + background-color: #222d32; +} +.skin-black-purple .user-panel > .info, +.skin-black-purple .user-panel > .info > a { + color: #fff; +} +.skin-black-purple .sidebar-menu .treeview-menu { + padding-left: 3px; +} +.skin-black-purple .sidebar-menu > li.header { + color: #4b646f; + background: #1a2226; +} +.skin-black-purple .sidebar-menu > li:hover > a, +.skin-black-purple .sidebar-menu > li.active > a { + color: #fff; + background: #1e282c; + border-left-color: #fff; +} +.skin-black-purple .sidebar-menu > li > .treeview-menu { + background: #181f23; +} +.skin-black-purple .sidebar a { + color: #b8c7ce; +} +.skin-black-purple .sidebar a:hover { + text-decoration: none; +} +.skin-black-purple .treeview-menu > li > a { + color: #6c8c9b; +} +.skin-black-purple .treeview-menu > li.active > a, +.skin-black-purple .treeview-menu > li > a:hover { + color: #fff; +} +.skin-black-purple .sidebar-form { + border-radius: 3px; + border: 1px solid #374850; + background-color: #374850; + margin: 10px 10px; +} +.skin-black-purple .sidebar-form input[type="text"], +.skin-black-purple .sidebar-form .btn { + box-shadow: none; + background-color: #374850; + border: 1px solid transparent; + height: 35px; +} +.skin-black-purple .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-black-purple .sidebar-form input[type="text"]:focus, +.skin-black-purple .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-black-purple .sidebar-form input[type="text"]:focus + .input-group-btn { + background: #fff; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black-purple .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-black-purple .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black-purple .treeview-menu > li > a { + padding-left: 18px; +} +.skin-black-purple .treeview-menu > li.active > a { + background-color: #605ca8; +} +.skin-black-purple .sidebar-menu > li.active > a { + color: #fff; + background: #605ca8; + border-left-color: #605ca8; +} +.skin-black-purple .sidebar-menu > li:hover > a { + border-left-color: transparent; +} +.skin-black-purple .sidebar-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +.skin-black-purple .sidebar-menu li.treeview.active > a, +.skin-black-purple .sidebar-menu li.treeview.treeview-open > a { + background-color: #181f23; + border-left-color: #181f23; +} +.skin-black-purple .sidebar-menu .treeview-menu { + padding-left: 0; +} +.skin-black-purple .sidebar-menu .treeview-menu .treeview-menu { + padding-left: 0; +} +.skin-black-purple .sidebar-menu .treeview-menu .treeview-menu > li > a { + padding-left: 30px; +} +.skin-black-purple .sidebar-menu .treeview-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +.skin-black-purple.sidebar-collapse .sidebar-menu li:hover > a, +.skin-black-purple.sidebar-collapse .sidebar-menu li.active > a { + color: #fff; + background: #605ca8; +} +.skin-black-purple.sidebar-collapse .sidebar-menu .treeview-menu li.active > a { + color: #fff; + background: #605ca8; +} +.skin-black-purple.sidebar-collapse .sidebar-menu .treeview-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +@media (max-width: 767px) { + .skin-black-purple.multiplenav .sidebar .mobilenav a.btn-app { + background: #374850; + color: #fff; + } + .skin-black-purple.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #605ca8; + color: #fff; + } +} +/*# sourceMappingURL=skin-black-purple.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-black-red.css b/public/static/css/skins/skin-black-red.css new file mode 100644 index 0000000..ef2ec20 --- /dev/null +++ b/public/static/css/skins/skin-black-red.css @@ -0,0 +1,242 @@ +/* + * Skin: Black red + * ----------- + */ +.skin-black-red .main-header { + background: #222d32; + -webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); +} +.skin-black-red .main-header .navbar { + background-color: #fff; +} +.skin-black-red .main-header .navbar .nav > li > a { + color: #666; +} +.skin-black-red .main-header .navbar .nav > li > a:hover, +.skin-black-red .main-header .navbar .nav > li > a:active, +.skin-black-red .main-header .navbar .nav > li > a:focus, +.skin-black-red .main-header .navbar .nav .open > a, +.skin-black-red .main-header .navbar .nav .open > a:hover, +.skin-black-red .main-header .navbar .nav .open > a:focus, +.skin-black-red .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.02); + color: #333; +} +.skin-black-red .main-header .navbar .nav-addtabs li > .close-tab { + color: #333; +} +.skin-black-red .main-header .navbar .sidebar-toggle { + color: #666; +} +.skin-black-red .main-header .navbar .sidebar-toggle:hover { + color: #333; + background: rgba(0, 0, 0, 0.02); +} +.skin-black-red .main-header .navbar .navbar-nav > li > a { + border-right: none; +} +.skin-black-red .main-header .navbar .navbar-custom-menu .navbar-nav > li > a, +.skin-black-red .main-header .navbar .navbar-right > li > a { + border-left: none; + border-right-width: 0; +} +@media (max-width: 767px) { + .skin-black-red .main-header .navbar { + background-color: #181f23; + } + .skin-black-red .main-header .navbar .nav > li > a { + color: #fff; + } + .skin-black-red .main-header .navbar .nav > li > a:hover, + .skin-black-red .main-header .navbar .nav > li > a:active, + .skin-black-red .main-header .navbar .nav > li > a:focus, + .skin-black-red .main-header .navbar .nav .open > a, + .skin-black-red .main-header .navbar .nav .open > a:hover, + .skin-black-red .main-header .navbar .nav .open > a:focus, + .skin-black-red .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.1); + color: #f6f6f6; + } + .skin-black-red .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; + } + .skin-black-red .main-header .navbar .sidebar-toggle { + color: #fff; + } + .skin-black-red .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.1); + } +} +.skin-black-red .main-header .logo { + background-color: #222d32; + color: #fff; + border-bottom: 0 solid transparent; + border-right: 1px solid #222d32; +} +.skin-black-red .main-header .logo:hover { + background-color: #202a2f; +} +@media (max-width: 767px) { + .skin-black-red .main-header .logo { + background-color: #181f23; + color: #fff; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-black-red .main-header .logo:hover { + background-color: #161d20; + } +} +.skin-black-red .main-header li.user-header { + background-color: #222d32; +} +.skin-black-red .main-header .nav-addtabs > li > a, +.skin-black-red .main-header .nav-addtabs > li.active > a { + border-right-color: transparent; +} +.skin-black-red .content-header { + background: transparent; + box-shadow: none; +} +.skin-black-red .wrapper, +.skin-black-red .main-sidebar, +.skin-black-red .left-side { + background-color: #222d32; +} +.skin-black-red .user-panel > .info, +.skin-black-red .user-panel > .info > a { + color: #fff; +} +.skin-black-red .sidebar-menu .treeview-menu { + padding-left: 3px; +} +.skin-black-red .sidebar-menu > li.header { + color: #4b646f; + background: #1a2226; +} +.skin-black-red .sidebar-menu > li:hover > a, +.skin-black-red .sidebar-menu > li.active > a { + color: #fff; + background: #1e282c; + border-left-color: #fff; +} +.skin-black-red .sidebar-menu > li > .treeview-menu { + background: #181f23; +} +.skin-black-red .sidebar a { + color: #b8c7ce; +} +.skin-black-red .sidebar a:hover { + text-decoration: none; +} +.skin-black-red .treeview-menu > li > a { + color: #6c8c9b; +} +.skin-black-red .treeview-menu > li.active > a, +.skin-black-red .treeview-menu > li > a:hover { + color: #fff; +} +.skin-black-red .sidebar-form { + border-radius: 3px; + border: 1px solid #374850; + background-color: #374850; + margin: 10px 10px; +} +.skin-black-red .sidebar-form input[type="text"], +.skin-black-red .sidebar-form .btn { + box-shadow: none; + background-color: #374850; + border: 1px solid transparent; + height: 35px; +} +.skin-black-red .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-black-red .sidebar-form input[type="text"]:focus, +.skin-black-red .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-black-red .sidebar-form input[type="text"]:focus + .input-group-btn { + background: #fff; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black-red .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-black-red .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black-red .treeview-menu > li > a { + padding-left: 18px; +} +.skin-black-red .treeview-menu > li.active > a { + background-color: #f75444; +} +.skin-black-red .sidebar-menu > li.active > a { + color: #fff; + background: #f75444; + border-left-color: #f75444; +} +.skin-black-red .sidebar-menu > li:hover > a { + border-left-color: transparent; +} +.skin-black-red .sidebar-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +.skin-black-red .sidebar-menu li.treeview.active > a, +.skin-black-red .sidebar-menu li.treeview.treeview-open > a { + background-color: #181f23; + border-left-color: #181f23; +} +.skin-black-red .sidebar-menu .treeview-menu { + padding-left: 0; +} +.skin-black-red .sidebar-menu .treeview-menu .treeview-menu { + padding-left: 0; +} +.skin-black-red .sidebar-menu .treeview-menu .treeview-menu > li > a { + padding-left: 30px; +} +.skin-black-red .sidebar-menu .treeview-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +.skin-black-red.sidebar-collapse .sidebar-menu li:hover > a, +.skin-black-red.sidebar-collapse .sidebar-menu li.active > a { + color: #fff; + background: #f75444; +} +.skin-black-red.sidebar-collapse .sidebar-menu .treeview-menu li.active > a { + color: #fff; + background: #f75444; +} +.skin-black-red.sidebar-collapse .sidebar-menu .treeview-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +@media (max-width: 767px) { + .skin-black-red.multiplenav .sidebar .mobilenav a.btn-app { + background: #374850; + color: #fff; + } + .skin-black-red.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #f75444; + color: #fff; + } +} +/*# sourceMappingURL=skin-black-red.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-black-yellow.css b/public/static/css/skins/skin-black-yellow.css new file mode 100644 index 0000000..0c02df8 --- /dev/null +++ b/public/static/css/skins/skin-black-yellow.css @@ -0,0 +1,242 @@ +/* + * Skin: Black yellow + * ----------- + */ +.skin-black-yellow .main-header { + background: #222d32; + -webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); +} +.skin-black-yellow .main-header .navbar { + background-color: #fff; +} +.skin-black-yellow .main-header .navbar .nav > li > a { + color: #666; +} +.skin-black-yellow .main-header .navbar .nav > li > a:hover, +.skin-black-yellow .main-header .navbar .nav > li > a:active, +.skin-black-yellow .main-header .navbar .nav > li > a:focus, +.skin-black-yellow .main-header .navbar .nav .open > a, +.skin-black-yellow .main-header .navbar .nav .open > a:hover, +.skin-black-yellow .main-header .navbar .nav .open > a:focus, +.skin-black-yellow .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.02); + color: #333; +} +.skin-black-yellow .main-header .navbar .nav-addtabs li > .close-tab { + color: #333; +} +.skin-black-yellow .main-header .navbar .sidebar-toggle { + color: #666; +} +.skin-black-yellow .main-header .navbar .sidebar-toggle:hover { + color: #333; + background: rgba(0, 0, 0, 0.02); +} +.skin-black-yellow .main-header .navbar .navbar-nav > li > a { + border-right: none; +} +.skin-black-yellow .main-header .navbar .navbar-custom-menu .navbar-nav > li > a, +.skin-black-yellow .main-header .navbar .navbar-right > li > a { + border-left: none; + border-right-width: 0; +} +@media (max-width: 767px) { + .skin-black-yellow .main-header .navbar { + background-color: #181f23; + } + .skin-black-yellow .main-header .navbar .nav > li > a { + color: #fff; + } + .skin-black-yellow .main-header .navbar .nav > li > a:hover, + .skin-black-yellow .main-header .navbar .nav > li > a:active, + .skin-black-yellow .main-header .navbar .nav > li > a:focus, + .skin-black-yellow .main-header .navbar .nav .open > a, + .skin-black-yellow .main-header .navbar .nav .open > a:hover, + .skin-black-yellow .main-header .navbar .nav .open > a:focus, + .skin-black-yellow .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.1); + color: #f6f6f6; + } + .skin-black-yellow .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; + } + .skin-black-yellow .main-header .navbar .sidebar-toggle { + color: #fff; + } + .skin-black-yellow .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.1); + } +} +.skin-black-yellow .main-header .logo { + background-color: #222d32; + color: #fff; + border-bottom: 0 solid transparent; + border-right: 1px solid #222d32; +} +.skin-black-yellow .main-header .logo:hover { + background-color: #202a2f; +} +@media (max-width: 767px) { + .skin-black-yellow .main-header .logo { + background-color: #181f23; + color: #fff; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-black-yellow .main-header .logo:hover { + background-color: #161d20; + } +} +.skin-black-yellow .main-header li.user-header { + background-color: #222d32; +} +.skin-black-yellow .main-header .nav-addtabs > li > a, +.skin-black-yellow .main-header .nav-addtabs > li.active > a { + border-right-color: transparent; +} +.skin-black-yellow .content-header { + background: transparent; + box-shadow: none; +} +.skin-black-yellow .wrapper, +.skin-black-yellow .main-sidebar, +.skin-black-yellow .left-side { + background-color: #222d32; +} +.skin-black-yellow .user-panel > .info, +.skin-black-yellow .user-panel > .info > a { + color: #fff; +} +.skin-black-yellow .sidebar-menu .treeview-menu { + padding-left: 3px; +} +.skin-black-yellow .sidebar-menu > li.header { + color: #4b646f; + background: #1a2226; +} +.skin-black-yellow .sidebar-menu > li:hover > a, +.skin-black-yellow .sidebar-menu > li.active > a { + color: #fff; + background: #1e282c; + border-left-color: #fff; +} +.skin-black-yellow .sidebar-menu > li > .treeview-menu { + background: #181f23; +} +.skin-black-yellow .sidebar a { + color: #b8c7ce; +} +.skin-black-yellow .sidebar a:hover { + text-decoration: none; +} +.skin-black-yellow .treeview-menu > li > a { + color: #6c8c9b; +} +.skin-black-yellow .treeview-menu > li.active > a, +.skin-black-yellow .treeview-menu > li > a:hover { + color: #fff; +} +.skin-black-yellow .sidebar-form { + border-radius: 3px; + border: 1px solid #374850; + background-color: #374850; + margin: 10px 10px; +} +.skin-black-yellow .sidebar-form input[type="text"], +.skin-black-yellow .sidebar-form .btn { + box-shadow: none; + background-color: #374850; + border: 1px solid transparent; + height: 35px; +} +.skin-black-yellow .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-black-yellow .sidebar-form input[type="text"]:focus, +.skin-black-yellow .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-black-yellow .sidebar-form input[type="text"]:focus + .input-group-btn { + background: #fff; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black-yellow .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-black-yellow .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black-yellow .treeview-menu > li > a { + padding-left: 18px; +} +.skin-black-yellow .treeview-menu > li.active > a { + background-color: #f39c12; +} +.skin-black-yellow .sidebar-menu > li.active > a { + color: #fff; + background: #f39c12; + border-left-color: #f39c12; +} +.skin-black-yellow .sidebar-menu > li:hover > a { + border-left-color: transparent; +} +.skin-black-yellow .sidebar-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +.skin-black-yellow .sidebar-menu li.treeview.active > a, +.skin-black-yellow .sidebar-menu li.treeview.treeview-open > a { + background-color: #181f23; + border-left-color: #181f23; +} +.skin-black-yellow .sidebar-menu .treeview-menu { + padding-left: 0; +} +.skin-black-yellow .sidebar-menu .treeview-menu .treeview-menu { + padding-left: 0; +} +.skin-black-yellow .sidebar-menu .treeview-menu .treeview-menu > li > a { + padding-left: 30px; +} +.skin-black-yellow .sidebar-menu .treeview-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +.skin-black-yellow.sidebar-collapse .sidebar-menu li:hover > a, +.skin-black-yellow.sidebar-collapse .sidebar-menu li.active > a { + color: #fff; + background: #f39c12; +} +.skin-black-yellow.sidebar-collapse .sidebar-menu .treeview-menu li.active > a { + color: #fff; + background: #f39c12; +} +.skin-black-yellow.sidebar-collapse .sidebar-menu .treeview-menu li.treeview > a { + background: transparent; + border-left-color: transparent; +} +@media (max-width: 767px) { + .skin-black-yellow.multiplenav .sidebar .mobilenav a.btn-app { + background: #374850; + color: #fff; + } + .skin-black-yellow.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #f39c12; + color: #fff; + } +} +/*# sourceMappingURL=skin-black-yellow.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-black.css b/public/static/css/skins/skin-black.css new file mode 100644 index 0000000..ea95165 --- /dev/null +++ b/public/static/css/skins/skin-black.css @@ -0,0 +1,219 @@ +/* + * Skin: Black + * ----------- + */ +.skin-black .main-header { + -webkit-box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.05); +} +.skin-black .main-header .navbar-toggle { + color: #333; +} +.skin-black .main-header .navbar-brand { + color: #333; + border-right: 1px solid #eee; +} +.skin-black .main-header .navbar { + background-color: #fff; +} +.skin-black .main-header .navbar .nav > li > a { + color: #666; +} +.skin-black .main-header .navbar .nav > li > a:hover, +.skin-black .main-header .navbar .nav > li > a:active, +.skin-black .main-header .navbar .nav > li > a:focus, +.skin-black .main-header .navbar .nav .open > a, +.skin-black .main-header .navbar .nav .open > a:hover, +.skin-black .main-header .navbar .nav .open > a:focus, +.skin-black .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.02); + color: #444; +} +.skin-black .main-header .navbar .nav-addtabs li > .close-tab { + color: #444; +} +.skin-black .main-header .navbar .sidebar-toggle { + color: #666; +} +.skin-black .main-header .navbar .sidebar-toggle:hover { + color: #444; + background: rgba(0, 0, 0, 0.02); +} +.skin-black .main-header .navbar > .sidebar-toggle { + color: #333; + border-right: 1px solid #eee; +} +.skin-black .main-header .navbar .navbar-nav > li > a { + border-right: 1px solid #eee; +} +.skin-black .main-header .navbar .navbar-custom-menu .navbar-nav > li > a, +.skin-black .main-header .navbar .navbar-right > li > a { + border-left: 1px solid #eee; + border-left: none; + border-right-width: 0; +} +.skin-black .main-header .logo { + background-color: #222d32; + color: #fff; + border-bottom: 0 solid transparent; + border-right: 1px solid #222d32; +} +.skin-black .main-header .logo:hover { + background-color: #202a2f; +} +@media (max-width: 767px) { + .skin-black .main-header .logo { + background-color: #fff; + color: #222; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-black .main-header .logo:hover { + background-color: #fcfcfc; + } +} +.skin-black .main-header li.user-header { + background-color: #222; +} +.skin-black .main-header .nav-addtabs > li > a, +.skin-black .main-header .nav-addtabs > li.active > a { + border-right-color: transparent; +} +.skin-black .content-header { + background: transparent; + box-shadow: none; +} +.skin-black .wrapper, +.skin-black .main-sidebar, +.skin-black .left-side { + background-color: #222d32; +} +.skin-black .user-panel > .info, +.skin-black .user-panel > .info > a { + color: #fff; +} +.skin-black .sidebar-menu .treeview-menu { + padding-left: 3px; +} +.skin-black .sidebar-menu > li.header { + color: #4b646f; + background: #1a2226; +} +.skin-black .sidebar-menu > li:hover > a, +.skin-black .sidebar-menu > li.active > a { + color: #fff; + background: #1e282c; + border-left-color: #fff; +} +.skin-black .sidebar-menu > li > .treeview-menu { + background: #1c2529; +} +.skin-black .sidebar a { + color: #b8c7ce; +} +.skin-black .sidebar a:hover { + text-decoration: none; +} +.skin-black .treeview-menu > li > a { + color: #72919f; +} +.skin-black .treeview-menu > li.active > a, +.skin-black .treeview-menu > li > a:hover { + color: #fff; +} +.skin-black .sidebar-form { + border-radius: 3px; + border: 1px solid #374850; + background-color: #374850; + margin: 10px 10px; +} +.skin-black .sidebar-form input[type="text"], +.skin-black .sidebar-form .btn { + box-shadow: none; + background-color: #374850; + border: 1px solid transparent; + height: 35px; +} +.skin-black .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-black .sidebar-form input[type="text"]:focus, +.skin-black .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-black .sidebar-form input[type="text"]:focus + .input-group-btn { + background: #fff; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-black .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-black .sidebar-menu > li > a { + border-left: 3px solid transparent; + padding-left: 12px; +} +@media (min-width: 768px) { + .skin-black.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right) { + margin-left: -3px; + } +} +@media (max-width: 767px) { + .skin-black.multiplenav .main-header .navbar { + background-color: #222d32; + } + .skin-black.multiplenav .main-header .navbar .nav > li > a { + color: #fff; + } + .skin-black.multiplenav .main-header .navbar .nav > li > a:hover, + .skin-black.multiplenav .main-header .navbar .nav > li > a:active, + .skin-black.multiplenav .main-header .navbar .nav > li > a:focus, + .skin-black.multiplenav .main-header .navbar .nav .open > a, + .skin-black.multiplenav .main-header .navbar .nav .open > a:hover, + .skin-black.multiplenav .main-header .navbar .nav .open > a:focus, + .skin-black.multiplenav .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.1); + color: #f6f6f6; + } + .skin-black.multiplenav .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; + } + .skin-black.multiplenav .main-header .navbar .sidebar-toggle { + color: #fff; + } + .skin-black.multiplenav .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.1); + } + .skin-black.multiplenav .main-header > .logo { + background-color: #222d32; + color: #fff; + border-bottom: 0 solid transparent; + } + .skin-black.multiplenav .main-header > .logo:hover { + background-color: #202a2f; + } + .skin-black.multiplenav .sidebar .mobilenav a.btn-app { + background: #374850; + color: #fff; + } + .skin-black.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #fff; + color: #374850; + } +} +/*# sourceMappingURL=skin-black.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-blue-light.css b/public/static/css/skins/skin-blue-light.css new file mode 100644 index 0000000..4fa2473 --- /dev/null +++ b/public/static/css/skins/skin-blue-light.css @@ -0,0 +1,184 @@ +/* + * Skin: Blue + * ---------- + */ +.skin-blue-light .main-header { + background-color: #4e73df; +} +.skin-blue-light .main-header .navbar { + background-color: #4e73df; +} +.skin-blue-light .main-header .navbar .nav > li > a { + color: #fff; +} +.skin-blue-light .main-header .navbar .nav > li > a:hover, +.skin-blue-light .main-header .navbar .nav > li > a:active, +.skin-blue-light .main-header .navbar .nav > li > a:focus, +.skin-blue-light .main-header .navbar .nav .open > a, +.skin-blue-light .main-header .navbar .nav .open > a:hover, +.skin-blue-light .main-header .navbar .nav .open > a:focus, +.skin-blue-light .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.05); + color: #f6f6f6; +} +.skin-blue-light .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; +} +.skin-blue-light .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-blue-light .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.05); +} +.skin-blue-light .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-blue-light .main-header .navbar .sidebar-toggle:hover { + background-color: #3862db; +} +@media (max-width: 767px) { + .skin-blue-light .main-header .navbar .dropdown-menu li.divider { + background-color: rgba(255, 255, 255, 0.1); + } + .skin-blue-light .main-header .navbar .dropdown-menu li a { + color: #fff; + } + .skin-blue-light .main-header .navbar .dropdown-menu li a:hover { + background: #3862db; + } +} +.skin-blue-light .main-header .logo { + background-color: #4e73df; + color: #fff; + border-bottom: 0 solid transparent; +} +.skin-blue-light .main-header .logo:hover { + background-color: #4a70de; +} +.skin-blue-light .main-header li.user-header { + background-color: #4e73df; +} +.skin-blue-light .content-header { + background: transparent; +} +.skin-blue-light .wrapper, +.skin-blue-light .main-sidebar, +.skin-blue-light .left-side { + background-color: #f9fafc; +} +.skin-blue-light .content-wrapper, +.skin-blue-light .main-footer { + border-left: 1px solid #d2d6de; +} +.skin-blue-light .user-panel > .info, +.skin-blue-light .user-panel > .info > a { + color: #444; +} +.skin-blue-light .sidebar-menu > li { + -webkit-transition: border-left-color 0.3s ease; + -o-transition: border-left-color 0.3s ease; + transition: border-left-color 0.3s ease; +} +.skin-blue-light .sidebar-menu > li.header { + color: #848484; + background: #f9fafc; +} +.skin-blue-light .sidebar-menu > li:hover > a, +.skin-blue-light .sidebar-menu > li.active > a { + color: #000; + background: #f4f4f5; + border-left-color: #4e73df; +} +.skin-blue-light .sidebar-menu > li.active { + border-left-color: #4e73df; +} +.skin-blue-light .sidebar-menu > li > .treeview-menu { + background: #f4f4f5; +} +.skin-blue-light .sidebar a { + color: #444; +} +.skin-blue-light .sidebar a:hover { + text-decoration: none; +} +.skin-blue-light .treeview-menu > li > a { + color: #777; +} +.skin-blue-light .treeview-menu > li.active > a, +.skin-blue-light .treeview-menu > li > a:hover { + color: #000; +} +.skin-blue-light .treeview-menu > li.active > a { + font-weight: 600; +} +.skin-blue-light .sidebar-form { + border-radius: 3px; + border: 1px solid #d2d6de; + margin: 10px 10px; +} +.skin-blue-light .sidebar-form input[type="text"], +.skin-blue-light .sidebar-form .btn { + box-shadow: none; + background-color: #fff; + border: 1px solid transparent; + height: 35px; +} +.skin-blue-light .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-blue-light .sidebar-form input[type="text"]:focus, +.skin-blue-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-blue-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-blue-light .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +@media (min-width: 768px) { + .skin-blue-light.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu { + border-left: 1px solid #d2d6de; + } +} +.skin-blue-light .sidebar-menu > li > a { + border-left: 3px solid transparent; + padding-left: 12px; +} +@media (min-width: 768px) { + .skin-blue-light.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right) { + margin-left: -3px; + } +} +.skin-blue-light .main-footer { + border-top-color: #d2d6de; +} +.skin-blue-light .main-sidebar { + -webkit-box-shadow: 7px 0 14px rgba(0, 0, 0, 0.03); + box-shadow: 7px 0 14px rgba(0, 0, 0, 0.03); +} +.skin-blue-light .content-wrapper, +.skin-blue-light .main-footer { + border-left: none; +} +@media (max-width: 767px) { + .skin-blue-light.multiplenav .sidebar .mobilenav a.btn-app { + background: #eceff3; + color: #757575; + } + .skin-blue-light.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #4e73df; + color: #fff; + } +} +/*# sourceMappingURL=skin-blue-light.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-blue.css b/public/static/css/skins/skin-blue.css new file mode 100644 index 0000000..1df808a --- /dev/null +++ b/public/static/css/skins/skin-blue.css @@ -0,0 +1,230 @@ +/* + * Skin: Blue + * ----------- + */ +.skin-blue .main-header .navbar-toggle { + color: #333; +} +.skin-blue .main-header .navbar-brand { + color: #333; + border-right: 1px solid #eee; +} +.skin-blue .main-header .navbar { + background-color: #fff; +} +.skin-blue .main-header .navbar .nav > li > a { + color: #444; +} +.skin-blue .main-header .navbar .nav > li > a:hover, +.skin-blue .main-header .navbar .nav > li > a:active, +.skin-blue .main-header .navbar .nav > li > a:focus, +.skin-blue .main-header .navbar .nav .open > a, +.skin-blue .main-header .navbar .nav .open > a:hover, +.skin-blue .main-header .navbar .nav .open > a:focus, +.skin-blue .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.02); + color: #4e73df; +} +.skin-blue .main-header .navbar .nav-addtabs li > .close-tab { + color: #4e73df; +} +.skin-blue .main-header .navbar .sidebar-toggle { + color: #444; +} +.skin-blue .main-header .navbar .sidebar-toggle:hover { + color: #4e73df; + background: rgba(0, 0, 0, 0.02); +} +.skin-blue .main-header .navbar > .sidebar-toggle { + color: #333; + border-right: 1px solid #eee; +} +.skin-blue .main-header .navbar .navbar-nav > li > a { + border-right: 1px solid #eee; +} +.skin-blue .main-header .navbar .navbar-custom-menu .navbar-nav > li > a, +.skin-blue .main-header .navbar .navbar-right > li > a { + border-left: 1px solid #eee; + border-left: none; + border-right-width: 0; +} +.skin-blue .main-header > .logo { + background-color: #4e73df; + color: #fff; + border-bottom: 0 solid transparent; + border-right: 1px solid #4e73df; + box-shadow: none; +} +.skin-blue .main-header > .logo:hover { + background-color: #4a70de; +} +@media (max-width: 767px) { + .skin-blue .main-header > .logo { + background-color: #fff; + color: #222; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-blue .main-header > .logo:hover { + background-color: #fcfcfc; + } +} +.skin-blue .main-header li.user-header { + background-color: #4e73df; +} +.skin-blue .main-header .nav-addtabs > li > a, +.skin-blue .main-header .nav-addtabs > li.active > a { + border-right-color: transparent; +} +.skin-blue .content-header { + background: transparent; + box-shadow: none; +} +.skin-blue .wrapper, +.skin-blue .main-sidebar, +.skin-blue .left-side { + background-color: #4e73df; +} +.skin-blue .user-panel > .info, +.skin-blue .user-panel > .info > a { + color: #fff; +} +.skin-blue .sidebar-menu .treeview-menu { + padding-left: 3px; +} +.skin-blue .sidebar-menu > li.header { + color: #a4b7ef; + background: #3d65dc; +} +.skin-blue .sidebar-menu > li:hover > a, +.skin-blue .sidebar-menu > li.active > a { + color: #fff; + background: #456cdd; + border-left-color: #fff; +} +.skin-blue .sidebar-menu > li > .treeview-menu { + background: #4169dd; +} +.skin-blue .sidebar a { + color: #ccd9ff; +} +.skin-blue .sidebar a:hover { + text-decoration: none; +} +.skin-blue .treeview-menu > li > a { + color: #ccd9ff; +} +.skin-blue .treeview-menu > li.active > a, +.skin-blue .treeview-menu > li > a:hover { + color: #fff; +} +.skin-blue .sidebar-form { + border-radius: 3px; + border: 1px solid #7995e7; + background-color: #7995e7; + margin: 10px 10px; +} +.skin-blue .sidebar-form input[type="text"], +.skin-blue .sidebar-form .btn { + box-shadow: none; + background-color: #7995e7; + border: 1px solid transparent; + height: 35px; +} +.skin-blue .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-blue .sidebar-form input[type="text"]:focus, +.skin-blue .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-blue .sidebar-form input[type="text"]:focus + .input-group-btn { + background: #fff; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-blue .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-blue .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-blue .sidebar-menu > li > a { + border-left: 3px solid transparent; + padding-left: 12px; +} +@media (min-width: 768px) { + .skin-blue.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right) { + margin-left: -3px; + } +} +.skin-blue .sidebar-form input[type="text"]::-moz-placeholder { + color: #fff; + opacity: 1; +} +.skin-blue .sidebar-form input[type="text"]:-ms-input-placeholder { + color: #fff; +} +.skin-blue .sidebar-form input[type="text"]::-webkit-input-placeholder { + color: #fff; +} +.skin-blue .sidebar-form input[type="text"], +.skin-blue .sidebar-form .btn { + color: #fff; +} +@media (max-width: 767px) { + .skin-blue.multiplenav .main-header .navbar { + background-color: #4e73df; + } + .skin-blue.multiplenav .main-header .navbar .nav > li > a { + color: #fff; + } + .skin-blue.multiplenav .main-header .navbar .nav > li > a:hover, + .skin-blue.multiplenav .main-header .navbar .nav > li > a:active, + .skin-blue.multiplenav .main-header .navbar .nav > li > a:focus, + .skin-blue.multiplenav .main-header .navbar .nav .open > a, + .skin-blue.multiplenav .main-header .navbar .nav .open > a:hover, + .skin-blue.multiplenav .main-header .navbar .nav .open > a:focus, + .skin-blue.multiplenav .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.1); + color: #f6f6f6; + } + .skin-blue.multiplenav .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; + } + .skin-blue.multiplenav .main-header .navbar .sidebar-toggle { + color: #fff; + } + .skin-blue.multiplenav .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.1); + } + .skin-blue.multiplenav .main-header > .logo { + background-color: #4e73df; + color: #fff; + border-bottom: 0 solid transparent; + } + .skin-blue.multiplenav .main-header > .logo:hover { + background-color: #4a70de; + } + .skin-blue.multiplenav .sidebar .mobilenav a.btn-app { + background: #7995e7; + color: #fff; + } + .skin-blue.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #fff; + color: #7995e7; + } +} +/*# sourceMappingURL=skin-blue.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-green-light.css b/public/static/css/skins/skin-green-light.css new file mode 100644 index 0000000..bc4c87e --- /dev/null +++ b/public/static/css/skins/skin-green-light.css @@ -0,0 +1,181 @@ +/* + * Skin: Green + * ----------- + */ +.skin-green-light .main-header { + background-color: #18bc9c; +} +.skin-green-light .main-header .navbar { + background-color: #18bc9c; +} +.skin-green-light .main-header .navbar .nav > li > a { + color: #fff; +} +.skin-green-light .main-header .navbar .nav > li > a:hover, +.skin-green-light .main-header .navbar .nav > li > a:active, +.skin-green-light .main-header .navbar .nav > li > a:focus, +.skin-green-light .main-header .navbar .nav .open > a, +.skin-green-light .main-header .navbar .nav .open > a:hover, +.skin-green-light .main-header .navbar .nav .open > a:focus, +.skin-green-light .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.05); + color: #f6f6f6; +} +.skin-green-light .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; +} +.skin-green-light .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-green-light .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.05); +} +.skin-green-light .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-green-light .main-header .navbar .sidebar-toggle:hover { + background-color: #15a589; +} +@media (max-width: 767px) { + .skin-green-light .main-header .navbar .dropdown-menu li.divider { + background-color: rgba(255, 255, 255, 0.1); + } + .skin-green-light .main-header .navbar .dropdown-menu li a { + color: #fff; + } + .skin-green-light .main-header .navbar .dropdown-menu li a:hover { + background: #15a589; + } +} +.skin-green-light .main-header .logo { + background-color: #18bc9c; + color: #fff; + border-bottom: 0 solid transparent; +} +.skin-green-light .main-header .logo:hover { + background-color: #17b798; +} +.skin-green-light .main-header li.user-header { + background-color: #18bc9c; +} +.skin-green-light .content-header { + background: transparent; +} +.skin-green-light .wrapper, +.skin-green-light .main-sidebar, +.skin-green-light .left-side { + background-color: #f9fafc; +} +.skin-green-light .content-wrapper, +.skin-green-light .main-footer { + border-left: 1px solid #d2d6de; +} +.skin-green-light .user-panel > .info, +.skin-green-light .user-panel > .info > a { + color: #444; +} +.skin-green-light .sidebar-menu > li { + -webkit-transition: border-left-color 0.3s ease; + -o-transition: border-left-color 0.3s ease; + transition: border-left-color 0.3s ease; +} +.skin-green-light .sidebar-menu > li.header { + color: #848484; + background: #f9fafc; +} +.skin-green-light .sidebar-menu > li:hover > a, +.skin-green-light .sidebar-menu > li.active > a { + color: #000; + background: #f4f4f5; + border-left-color: #18bc9c; +} +.skin-green-light .sidebar-menu > li.active { + border-left-color: #18bc9c; +} +.skin-green-light .sidebar-menu > li > .treeview-menu { + background: #f4f4f5; +} +.skin-green-light .sidebar a { + color: #444; +} +.skin-green-light .sidebar a:hover { + text-decoration: none; +} +.skin-green-light .treeview-menu > li > a { + color: #777; +} +.skin-green-light .treeview-menu > li.active > a, +.skin-green-light .treeview-menu > li > a:hover { + color: #000; +} +.skin-green-light .treeview-menu > li.active > a { + font-weight: 600; +} +.skin-green-light .sidebar-form { + border-radius: 3px; + border: 1px solid #d2d6de; + margin: 10px 10px; +} +.skin-green-light .sidebar-form input[type="text"], +.skin-green-light .sidebar-form .btn { + box-shadow: none; + background-color: #fff; + border: 1px solid transparent; + height: 35px; +} +.skin-green-light .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-green-light .sidebar-form input[type="text"]:focus, +.skin-green-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-green-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-green-light .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +@media (min-width: 768px) { + .skin-green-light.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu { + border-left: 1px solid #d2d6de; + } +} +.skin-green-light .sidebar-menu > li > a { + border-left: 3px solid transparent; + padding-left: 12px; +} +@media (min-width: 768px) { + .skin-green-light.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right) { + margin-left: -3px; + } +} +.skin-green-light .main-sidebar { + -webkit-box-shadow: 7px 0 14px rgba(0, 0, 0, 0.03); + box-shadow: 7px 0 14px rgba(0, 0, 0, 0.03); +} +.skin-green-light .content-wrapper, +.skin-green-light .main-footer { + border-left: none; +} +@media (max-width: 767px) { + .skin-green-light.multiplenav .sidebar .mobilenav a.btn-app { + background: #eceff3; + color: #757575; + } + .skin-green-light.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #18bc9c; + color: #fff; + } +} +/*# sourceMappingURL=skin-green-light.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-green.css b/public/static/css/skins/skin-green.css new file mode 100644 index 0000000..aedf03c --- /dev/null +++ b/public/static/css/skins/skin-green.css @@ -0,0 +1,175 @@ +/* + * Skin: Green + * ----------- + */ +.skin-green .main-header { + background-color: #18bc9c; +} +.skin-green .main-header .navbar { + background-color: #18bc9c; +} +.skin-green .main-header .navbar .nav > li > a { + color: #fff; +} +.skin-green .main-header .navbar .nav > li > a:hover, +.skin-green .main-header .navbar .nav > li > a:active, +.skin-green .main-header .navbar .nav > li > a:focus, +.skin-green .main-header .navbar .nav .open > a, +.skin-green .main-header .navbar .nav .open > a:hover, +.skin-green .main-header .navbar .nav .open > a:focus, +.skin-green .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.05); + color: #f6f6f6; +} +.skin-green .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; +} +.skin-green .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-green .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.05); +} +.skin-green .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-green .main-header .navbar .sidebar-toggle:hover { + background-color: #15a589; +} +@media (max-width: 767px) { + .skin-green .main-header .navbar .dropdown-menu li.divider { + background-color: rgba(255, 255, 255, 0.1); + } + .skin-green .main-header .navbar .dropdown-menu li a { + color: #fff; + } + .skin-green .main-header .navbar .dropdown-menu li a:hover { + background: #15a589; + } +} +.skin-green .main-header .logo { + background-color: #15a589; + color: #fff; + border-bottom: 0 solid transparent; +} +.skin-green .main-header .logo:hover { + background-color: #15a185; +} +@media (max-width: 767px) { + .skin-green .main-header .logo { + background-color: #18bc9c; + color: #fff; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-green .main-header .logo:hover { + background-color: #17b798; + } +} +.skin-green .main-header li.user-header { + background-color: #18bc9c; +} +.skin-green .content-header { + background: transparent; +} +.skin-green .wrapper, +.skin-green .main-sidebar, +.skin-green .left-side { + background-color: #222d32; +} +.skin-green .user-panel > .info, +.skin-green .user-panel > .info > a { + color: #fff; +} +.skin-green .sidebar-menu .treeview-menu { + padding-left: 3px; +} +.skin-green .sidebar-menu > li.header { + color: #4b646f; + background: #1a2226; +} +.skin-green .sidebar-menu > li:hover > a, +.skin-green .sidebar-menu > li.active > a { + color: #fff; + background: #1e282c; + border-left-color: #18bc9c; +} +.skin-green .sidebar-menu > li > .treeview-menu { + background: #2c3b41; +} +.skin-green .sidebar a { + color: #b8c7ce; +} +.skin-green .sidebar a:hover { + text-decoration: none; +} +.skin-green .treeview-menu > li > a { + color: #8aa4af; +} +.skin-green .treeview-menu > li.active > a, +.skin-green .treeview-menu > li > a:hover { + color: #fff; +} +.skin-green .sidebar-form { + border-radius: 3px; + border: 1px solid #374850; + background-color: #374850; + margin: 10px 10px; +} +.skin-green .sidebar-form input[type="text"], +.skin-green .sidebar-form .btn { + box-shadow: none; + background-color: #374850; + border: 1px solid transparent; + height: 35px; +} +.skin-green .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-green .sidebar-form input[type="text"]:focus, +.skin-green .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-green .sidebar-form input[type="text"]:focus + .input-group-btn { + background: #fff; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-green .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-green .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-green .sidebar-menu > li > a { + border-left: 3px solid transparent; + padding-left: 12px; +} +@media (min-width: 768px) { + .skin-green.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right) { + margin-left: -3px; + } +} +@media (max-width: 767px) { + .skin-green.multiplenav .sidebar .mobilenav a.btn-app { + background: #374850; + color: #fff; + } + .skin-green.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #18bc9c; + color: #fff; + } +} +/*# sourceMappingURL=skin-green.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-purple-light.css b/public/static/css/skins/skin-purple-light.css new file mode 100644 index 0000000..f243e9b --- /dev/null +++ b/public/static/css/skins/skin-purple-light.css @@ -0,0 +1,181 @@ +/* + * Skin: Purple + * ------------ + */ +.skin-purple-light .main-header { + background-color: #605ca8; +} +.skin-purple-light .main-header .navbar { + background-color: #605ca8; +} +.skin-purple-light .main-header .navbar .nav > li > a { + color: #fff; +} +.skin-purple-light .main-header .navbar .nav > li > a:hover, +.skin-purple-light .main-header .navbar .nav > li > a:active, +.skin-purple-light .main-header .navbar .nav > li > a:focus, +.skin-purple-light .main-header .navbar .nav .open > a, +.skin-purple-light .main-header .navbar .nav .open > a:hover, +.skin-purple-light .main-header .navbar .nav .open > a:focus, +.skin-purple-light .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.05); + color: #f6f6f6; +} +.skin-purple-light .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; +} +.skin-purple-light .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-purple-light .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.05); +} +.skin-purple-light .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-purple-light .main-header .navbar .sidebar-toggle:hover { + background-color: #555299; +} +@media (max-width: 767px) { + .skin-purple-light .main-header .navbar .dropdown-menu li.divider { + background-color: rgba(255, 255, 255, 0.1); + } + .skin-purple-light .main-header .navbar .dropdown-menu li a { + color: #fff; + } + .skin-purple-light .main-header .navbar .dropdown-menu li a:hover { + background: #555299; + } +} +.skin-purple-light .main-header .logo { + background-color: #605ca8; + color: #fff; + border-bottom: 0 solid transparent; +} +.skin-purple-light .main-header .logo:hover { + background-color: #5d59a6; +} +.skin-purple-light .main-header li.user-header { + background-color: #605ca8; +} +.skin-purple-light .content-header { + background: transparent; +} +.skin-purple-light .wrapper, +.skin-purple-light .main-sidebar, +.skin-purple-light .left-side { + background-color: #f9fafc; +} +.skin-purple-light .content-wrapper, +.skin-purple-light .main-footer { + border-left: 1px solid #d2d6de; +} +.skin-purple-light .user-panel > .info, +.skin-purple-light .user-panel > .info > a { + color: #444; +} +.skin-purple-light .sidebar-menu > li { + -webkit-transition: border-left-color 0.3s ease; + -o-transition: border-left-color 0.3s ease; + transition: border-left-color 0.3s ease; +} +.skin-purple-light .sidebar-menu > li.header { + color: #848484; + background: #f9fafc; +} +.skin-purple-light .sidebar-menu > li:hover > a, +.skin-purple-light .sidebar-menu > li.active > a { + color: #000; + background: #f4f4f5; + border-left-color: #605ca8; +} +.skin-purple-light .sidebar-menu > li.active { + border-left-color: #605ca8; +} +.skin-purple-light .sidebar-menu > li > .treeview-menu { + background: #f4f4f5; +} +.skin-purple-light .sidebar a { + color: #444; +} +.skin-purple-light .sidebar a:hover { + text-decoration: none; +} +.skin-purple-light .treeview-menu > li > a { + color: #777; +} +.skin-purple-light .treeview-menu > li.active > a, +.skin-purple-light .treeview-menu > li > a:hover { + color: #000; +} +.skin-purple-light .treeview-menu > li.active > a { + font-weight: 600; +} +.skin-purple-light .sidebar-form { + border-radius: 3px; + border: 1px solid #d2d6de; + margin: 10px 10px; +} +.skin-purple-light .sidebar-form input[type="text"], +.skin-purple-light .sidebar-form .btn { + box-shadow: none; + background-color: #fff; + border: 1px solid transparent; + height: 35px; +} +.skin-purple-light .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-purple-light .sidebar-form input[type="text"]:focus, +.skin-purple-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-purple-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-purple-light .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +@media (min-width: 768px) { + .skin-purple-light.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu { + border-left: 1px solid #d2d6de; + } +} +.skin-purple-light .sidebar-menu > li > a { + border-left: 3px solid transparent; + padding-left: 12px; +} +@media (min-width: 768px) { + .skin-purple-light.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right) { + margin-left: -3px; + } +} +.skin-purple-light .main-sidebar { + -webkit-box-shadow: 7px 0 14px rgba(0, 0, 0, 0.03); + box-shadow: 7px 0 14px rgba(0, 0, 0, 0.03); +} +.skin-purple-light .content-wrapper, +.skin-purple-light .main-footer { + border-left: none; +} +@media (max-width: 767px) { + .skin-purple-light.multiplenav .sidebar .mobilenav a.btn-app { + background: #eceff3; + color: #757575; + } + .skin-purple-light.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #605ca8; + color: #fff; + } +} +/*# sourceMappingURL=skin-purple-light.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-purple.css b/public/static/css/skins/skin-purple.css new file mode 100644 index 0000000..493e167 --- /dev/null +++ b/public/static/css/skins/skin-purple.css @@ -0,0 +1,220 @@ +/* + * Skin: Purple + * ------------ + */ +.skin-purple .main-header .navbar { + background-color: #fff; +} +.skin-purple .main-header .navbar .nav > li > a { + color: #444; +} +.skin-purple .main-header .navbar .nav > li > a:hover, +.skin-purple .main-header .navbar .nav > li > a:active, +.skin-purple .main-header .navbar .nav > li > a:focus, +.skin-purple .main-header .navbar .nav .open > a, +.skin-purple .main-header .navbar .nav .open > a:hover, +.skin-purple .main-header .navbar .nav .open > a:focus, +.skin-purple .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.02); + color: #605ca8; +} +.skin-purple .main-header .navbar .nav-addtabs li > .close-tab { + color: #605ca8; +} +.skin-purple .main-header .navbar .sidebar-toggle { + color: #444; +} +.skin-purple .main-header .navbar .sidebar-toggle:hover { + color: #605ca8; + background: rgba(0, 0, 0, 0.02); +} +@media (max-width: 767px) { + .skin-purple .main-header .navbar .dropdown-menu li.divider { + background-color: rgba(255, 255, 255, 0.1); + } + .skin-purple .main-header .navbar .dropdown-menu li a { + color: #fff; + } + .skin-purple .main-header .navbar .dropdown-menu li a:hover { + background: #555299; + } +} +.skin-purple .main-header > .logo { + background-color: #605ca8; + color: #fff; + border-bottom: 0 solid transparent; + border-right: 1px solid #605ca8; + box-shadow: none; +} +.skin-purple .main-header > .logo:hover { + background-color: #5d59a6; +} +@media (max-width: 767px) { + .skin-purple .main-header > .logo { + background-color: #fff; + color: #222; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-purple .main-header > .logo:hover { + background-color: #fcfcfc; + } +} +.skin-purple .main-header li.user-header { + background-color: #605ca8; +} +.skin-purple .main-header .nav-addtabs > li > a, +.skin-purple .main-header .nav-addtabs > li.active > a { + border-right-color: transparent; +} +.skin-purple .content-header { + background: transparent; +} +.skin-purple .wrapper, +.skin-purple .main-sidebar, +.skin-purple .left-side { + background-color: #605ca8; +} +.skin-purple .user-panel > .info, +.skin-purple .user-panel > .info > a { + color: #fff; +} +.skin-purple .sidebar-menu .treeview-menu { + padding-left: 3px; +} +.skin-purple .sidebar-menu > li.header { + color: #a19fcb; + background: #57539c; +} +.skin-purple .sidebar-menu > li:hover > a, +.skin-purple .sidebar-menu > li.active > a { + color: #fff; + background: #5b57a3; + border-left-color: #fff; +} +.skin-purple .sidebar-menu > li > .treeview-menu { + background: #5955a0; +} +.skin-purple .sidebar a { + color: #c8c5ff; +} +.skin-purple .sidebar a:hover { + text-decoration: none; +} +.skin-purple .treeview-menu > li > a { + color: #c8c5ff; +} +.skin-purple .treeview-menu > li.active > a, +.skin-purple .treeview-menu > li > a:hover { + color: #fff; +} +.skin-purple .sidebar-form { + border-radius: 3px; + border: 1px solid #807dba; + background-color: #807dba; + margin: 10px 10px; +} +.skin-purple .sidebar-form input[type="text"], +.skin-purple .sidebar-form .btn { + box-shadow: none; + background-color: #807dba; + border: 1px solid transparent; + height: 35px; +} +.skin-purple .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-purple .sidebar-form input[type="text"]:focus, +.skin-purple .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-purple .sidebar-form input[type="text"]:focus + .input-group-btn { + background: #fff; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-purple .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-purple .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-purple .sidebar-menu > li > a { + border-left: 3px solid transparent; + padding-left: 12px; +} +@media (min-width: 768px) { + .skin-purple.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right) { + margin-left: -3px; + } +} +.skin-purple .sidebar-form input[type="text"]::-moz-placeholder { + color: #fff; + opacity: 1; +} +.skin-purple .sidebar-form input[type="text"]:-ms-input-placeholder { + color: #fff; +} +.skin-purple .sidebar-form input[type="text"]::-webkit-input-placeholder { + color: #fff; +} +.skin-purple .sidebar-form input[type="text"], +.skin-purple .sidebar-form .btn { + color: #fff; +} +@media (max-width: 767px) { + .skin-purple.multiplenav .main-header .navbar { + background-color: #605ca8; + } + .skin-purple.multiplenav .main-header .navbar .nav > li > a { + color: #fff; + } + .skin-purple.multiplenav .main-header .navbar .nav > li > a:hover, + .skin-purple.multiplenav .main-header .navbar .nav > li > a:active, + .skin-purple.multiplenav .main-header .navbar .nav > li > a:focus, + .skin-purple.multiplenav .main-header .navbar .nav .open > a, + .skin-purple.multiplenav .main-header .navbar .nav .open > a:hover, + .skin-purple.multiplenav .main-header .navbar .nav .open > a:focus, + .skin-purple.multiplenav .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.1); + color: #f6f6f6; + } + .skin-purple.multiplenav .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; + } + .skin-purple.multiplenav .main-header .navbar .sidebar-toggle { + color: #fff; + } + .skin-purple.multiplenav .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.1); + } + .skin-purple.multiplenav .main-header > .logo { + background-color: #605ca8; + color: #fff; + border-bottom: 0 solid transparent; + } + .skin-purple.multiplenav .main-header > .logo:hover { + background-color: #5d59a6; + } + .skin-purple.multiplenav .sidebar .mobilenav a.btn-app { + background: #807dba; + color: #fff; + } + .skin-purple.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #fff; + color: #807dba; + } +} +/*# sourceMappingURL=skin-purple.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-red-light.css b/public/static/css/skins/skin-red-light.css new file mode 100644 index 0000000..ca8ab75 --- /dev/null +++ b/public/static/css/skins/skin-red-light.css @@ -0,0 +1,181 @@ +/* + * Skin: Red + * --------- + */ +.skin-red-light .main-header { + background-color: #f75444; +} +.skin-red-light .main-header .navbar { + background-color: #f75444; +} +.skin-red-light .main-header .navbar .nav > li > a { + color: #fff; +} +.skin-red-light .main-header .navbar .nav > li > a:hover, +.skin-red-light .main-header .navbar .nav > li > a:active, +.skin-red-light .main-header .navbar .nav > li > a:focus, +.skin-red-light .main-header .navbar .nav .open > a, +.skin-red-light .main-header .navbar .nav .open > a:hover, +.skin-red-light .main-header .navbar .nav .open > a:focus, +.skin-red-light .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.05); + color: #f6f6f6; +} +.skin-red-light .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; +} +.skin-red-light .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-red-light .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.05); +} +.skin-red-light .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-red-light .main-header .navbar .sidebar-toggle:hover { + background-color: #f63e2c; +} +@media (max-width: 767px) { + .skin-red-light .main-header .navbar .dropdown-menu li.divider { + background-color: rgba(255, 255, 255, 0.1); + } + .skin-red-light .main-header .navbar .dropdown-menu li a { + color: #fff; + } + .skin-red-light .main-header .navbar .dropdown-menu li a:hover { + background: #f63e2c; + } +} +.skin-red-light .main-header .logo { + background-color: #f75444; + color: #fff; + border-bottom: 0 solid transparent; +} +.skin-red-light .main-header .logo:hover { + background-color: #f7503f; +} +.skin-red-light .main-header li.user-header { + background-color: #f75444; +} +.skin-red-light .content-header { + background: transparent; +} +.skin-red-light .wrapper, +.skin-red-light .main-sidebar, +.skin-red-light .left-side { + background-color: #f9fafc; +} +.skin-red-light .content-wrapper, +.skin-red-light .main-footer { + border-left: 1px solid #d2d6de; +} +.skin-red-light .user-panel > .info, +.skin-red-light .user-panel > .info > a { + color: #444; +} +.skin-red-light .sidebar-menu > li { + -webkit-transition: border-left-color 0.3s ease; + -o-transition: border-left-color 0.3s ease; + transition: border-left-color 0.3s ease; +} +.skin-red-light .sidebar-menu > li.header { + color: #848484; + background: #f9fafc; +} +.skin-red-light .sidebar-menu > li:hover > a, +.skin-red-light .sidebar-menu > li.active > a { + color: #000; + background: #f4f4f5; + border-left-color: #f75444; +} +.skin-red-light .sidebar-menu > li.active { + border-left-color: #f75444; +} +.skin-red-light .sidebar-menu > li > .treeview-menu { + background: #f4f4f5; +} +.skin-red-light .sidebar a { + color: #444; +} +.skin-red-light .sidebar a:hover { + text-decoration: none; +} +.skin-red-light .treeview-menu > li > a { + color: #777; +} +.skin-red-light .treeview-menu > li.active > a, +.skin-red-light .treeview-menu > li > a:hover { + color: #000; +} +.skin-red-light .treeview-menu > li.active > a { + font-weight: 600; +} +.skin-red-light .sidebar-form { + border-radius: 3px; + border: 1px solid #d2d6de; + margin: 10px 10px; +} +.skin-red-light .sidebar-form input[type="text"], +.skin-red-light .sidebar-form .btn { + box-shadow: none; + background-color: #fff; + border: 1px solid transparent; + height: 35px; +} +.skin-red-light .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-red-light .sidebar-form input[type="text"]:focus, +.skin-red-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-red-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-red-light .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +@media (min-width: 768px) { + .skin-red-light.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu { + border-left: 1px solid #d2d6de; + } +} +.skin-red-light .sidebar-menu > li > a { + border-left: 3px solid transparent; + padding-left: 12px; +} +@media (min-width: 768px) { + .skin-red-light.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right) { + margin-left: -3px; + } +} +.skin-red-light .main-sidebar { + -webkit-box-shadow: 7px 0 14px rgba(0, 0, 0, 0.03); + box-shadow: 7px 0 14px rgba(0, 0, 0, 0.03); +} +.skin-red-light .content-wrapper, +.skin-red-light .main-footer { + border-left: none; +} +@media (max-width: 767px) { + .skin-red-light.multiplenav .sidebar .mobilenav a.btn-app { + background: #eceff3; + color: #757575; + } + .skin-red-light.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #f75444; + color: #fff; + } +} +/*# sourceMappingURL=skin-red-light.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-red.css b/public/static/css/skins/skin-red.css new file mode 100644 index 0000000..2182b4e --- /dev/null +++ b/public/static/css/skins/skin-red.css @@ -0,0 +1,175 @@ +/* + * Skin: Red + * --------- + */ +.skin-red .main-header { + background-color: #f75444; +} +.skin-red .main-header .navbar { + background-color: #f75444; +} +.skin-red .main-header .navbar .nav > li > a { + color: #fff; +} +.skin-red .main-header .navbar .nav > li > a:hover, +.skin-red .main-header .navbar .nav > li > a:active, +.skin-red .main-header .navbar .nav > li > a:focus, +.skin-red .main-header .navbar .nav .open > a, +.skin-red .main-header .navbar .nav .open > a:hover, +.skin-red .main-header .navbar .nav .open > a:focus, +.skin-red .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.05); + color: #f6f6f6; +} +.skin-red .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; +} +.skin-red .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-red .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.05); +} +.skin-red .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-red .main-header .navbar .sidebar-toggle:hover { + background-color: #f63e2c; +} +@media (max-width: 767px) { + .skin-red .main-header .navbar .dropdown-menu li.divider { + background-color: rgba(255, 255, 255, 0.1); + } + .skin-red .main-header .navbar .dropdown-menu li a { + color: #fff; + } + .skin-red .main-header .navbar .dropdown-menu li a:hover { + background: #f63e2c; + } +} +.skin-red .main-header .logo { + background-color: #f63e2c; + color: #fff; + border-bottom: 0 solid transparent; +} +.skin-red .main-header .logo:hover { + background-color: #f63927; +} +@media (max-width: 767px) { + .skin-red .main-header .logo { + background-color: #f75444; + color: #fff; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-red .main-header .logo:hover { + background-color: #f7503f; + } +} +.skin-red .main-header li.user-header { + background-color: #f75444; +} +.skin-red .content-header { + background: transparent; +} +.skin-red .wrapper, +.skin-red .main-sidebar, +.skin-red .left-side { + background-color: #222d32; +} +.skin-red .user-panel > .info, +.skin-red .user-panel > .info > a { + color: #fff; +} +.skin-red .sidebar-menu .treeview-menu { + padding-left: 3px; +} +.skin-red .sidebar-menu > li.header { + color: #4b646f; + background: #1a2226; +} +.skin-red .sidebar-menu > li:hover > a, +.skin-red .sidebar-menu > li.active > a { + color: #fff; + background: #1e282c; + border-left-color: #f75444; +} +.skin-red .sidebar-menu > li > .treeview-menu { + background: #2c3b41; +} +.skin-red .sidebar a { + color: #b8c7ce; +} +.skin-red .sidebar a:hover { + text-decoration: none; +} +.skin-red .treeview-menu > li > a { + color: #8aa4af; +} +.skin-red .treeview-menu > li.active > a, +.skin-red .treeview-menu > li > a:hover { + color: #fff; +} +.skin-red .sidebar-form { + border-radius: 3px; + border: 1px solid #374850; + background-color: #374850; + margin: 10px 10px; +} +.skin-red .sidebar-form input[type="text"], +.skin-red .sidebar-form .btn { + box-shadow: none; + background-color: #374850; + border: 1px solid transparent; + height: 35px; +} +.skin-red .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-red .sidebar-form input[type="text"]:focus, +.skin-red .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-red .sidebar-form input[type="text"]:focus + .input-group-btn { + background: #fff; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-red .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-red .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-red .sidebar-menu > li > a { + border-left: 3px solid transparent; + padding-left: 12px; +} +@media (min-width: 768px) { + .skin-red.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right) { + margin-left: -3px; + } +} +@media (max-width: 767px) { + .skin-red.multiplenav .sidebar .mobilenav a.btn-app { + background: #374850; + color: #fff; + } + .skin-red.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #f75444; + color: #fff; + } +} +/*# sourceMappingURL=skin-red.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-yellow-light.css b/public/static/css/skins/skin-yellow-light.css new file mode 100644 index 0000000..41d572f --- /dev/null +++ b/public/static/css/skins/skin-yellow-light.css @@ -0,0 +1,181 @@ +/* + * Skin: Yellow light + * ------------ + */ +.skin-yellow-light .main-header { + background-color: #f39c12; +} +.skin-yellow-light .main-header .navbar { + background-color: #f39c12; +} +.skin-yellow-light .main-header .navbar .nav > li > a { + color: #fff; +} +.skin-yellow-light .main-header .navbar .nav > li > a:hover, +.skin-yellow-light .main-header .navbar .nav > li > a:active, +.skin-yellow-light .main-header .navbar .nav > li > a:focus, +.skin-yellow-light .main-header .navbar .nav .open > a, +.skin-yellow-light .main-header .navbar .nav .open > a:hover, +.skin-yellow-light .main-header .navbar .nav .open > a:focus, +.skin-yellow-light .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.05); + color: #f6f6f6; +} +.skin-yellow-light .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; +} +.skin-yellow-light .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-yellow-light .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.05); +} +.skin-yellow-light .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-yellow-light .main-header .navbar .sidebar-toggle:hover { + background-color: #e08e0b; +} +@media (max-width: 767px) { + .skin-yellow-light .main-header .navbar .dropdown-menu li.divider { + background-color: rgba(255, 255, 255, 0.1); + } + .skin-yellow-light .main-header .navbar .dropdown-menu li a { + color: #fff; + } + .skin-yellow-light .main-header .navbar .dropdown-menu li a:hover { + background: #e08e0b; + } +} +.skin-yellow-light .main-header .logo { + background-color: #f39c12; + color: #fff; + border-bottom: 0 solid transparent; +} +.skin-yellow-light .main-header .logo:hover { + background-color: #f39a0d; +} +.skin-yellow-light .main-header li.user-header { + background-color: #f39c12; +} +.skin-yellow-light .content-header { + background: transparent; +} +.skin-yellow-light .wrapper, +.skin-yellow-light .main-sidebar, +.skin-yellow-light .left-side { + background-color: #f9fafc; +} +.skin-yellow-light .content-wrapper, +.skin-yellow-light .main-footer { + border-left: 1px solid #d2d6de; +} +.skin-yellow-light .user-panel > .info, +.skin-yellow-light .user-panel > .info > a { + color: #444; +} +.skin-yellow-light .sidebar-menu > li { + -webkit-transition: border-left-color 0.3s ease; + -o-transition: border-left-color 0.3s ease; + transition: border-left-color 0.3s ease; +} +.skin-yellow-light .sidebar-menu > li.header { + color: #848484; + background: #f9fafc; +} +.skin-yellow-light .sidebar-menu > li:hover > a, +.skin-yellow-light .sidebar-menu > li.active > a { + color: #000; + background: #f4f4f5; + border-left-color: #f39c12; +} +.skin-yellow-light .sidebar-menu > li.active { + border-left-color: #f39c12; +} +.skin-yellow-light .sidebar-menu > li > .treeview-menu { + background: #f4f4f5; +} +.skin-yellow-light .sidebar a { + color: #444; +} +.skin-yellow-light .sidebar a:hover { + text-decoration: none; +} +.skin-yellow-light .treeview-menu > li > a { + color: #777; +} +.skin-yellow-light .treeview-menu > li.active > a, +.skin-yellow-light .treeview-menu > li > a:hover { + color: #000; +} +.skin-yellow-light .treeview-menu > li.active > a { + font-weight: 600; +} +.skin-yellow-light .sidebar-form { + border-radius: 3px; + border: 1px solid #d2d6de; + margin: 10px 10px; +} +.skin-yellow-light .sidebar-form input[type="text"], +.skin-yellow-light .sidebar-form .btn { + box-shadow: none; + background-color: #fff; + border: 1px solid transparent; + height: 35px; +} +.skin-yellow-light .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-yellow-light .sidebar-form input[type="text"]:focus, +.skin-yellow-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-yellow-light .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-yellow-light .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +@media (min-width: 768px) { + .skin-yellow-light.sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu { + border-left: 1px solid #d2d6de; + } +} +.skin-yellow-light .sidebar-menu > li > a { + border-left: 3px solid transparent; + padding-left: 12px; +} +@media (min-width: 768px) { + .skin-yellow-light.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right) { + margin-left: -3px; + } +} +.skin-yellow-light .main-sidebar { + -webkit-box-shadow: 7px 0 14px rgba(0, 0, 0, 0.03); + box-shadow: 7px 0 14px rgba(0, 0, 0, 0.03); +} +.skin-yellow-light .content-wrapper, +.skin-yellow-light .main-footer { + border-left: none; +} +@media (max-width: 767px) { + .skin-yellow-light.multiplenav .sidebar .mobilenav a.btn-app { + background: #eceff3; + color: #757575; + } + .skin-yellow-light.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #f39c12; + color: #fff; + } +} +/*# sourceMappingURL=skin-yellow-light.css.map */ \ No newline at end of file diff --git a/public/static/css/skins/skin-yellow.css b/public/static/css/skins/skin-yellow.css new file mode 100644 index 0000000..fed08cd --- /dev/null +++ b/public/static/css/skins/skin-yellow.css @@ -0,0 +1,175 @@ +/* + * Skin: Yellow + * ------------ + */ +.skin-yellow .main-header { + background-color: #f39c12; +} +.skin-yellow .main-header .navbar { + background-color: #f39c12; +} +.skin-yellow .main-header .navbar .nav > li > a { + color: #fff; +} +.skin-yellow .main-header .navbar .nav > li > a:hover, +.skin-yellow .main-header .navbar .nav > li > a:active, +.skin-yellow .main-header .navbar .nav > li > a:focus, +.skin-yellow .main-header .navbar .nav .open > a, +.skin-yellow .main-header .navbar .nav .open > a:hover, +.skin-yellow .main-header .navbar .nav .open > a:focus, +.skin-yellow .main-header .navbar .nav > .active > a { + background: rgba(0, 0, 0, 0.05); + color: #f6f6f6; +} +.skin-yellow .main-header .navbar .nav-addtabs li > .close-tab { + color: #f6f6f6; +} +.skin-yellow .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-yellow .main-header .navbar .sidebar-toggle:hover { + color: #f6f6f6; + background: rgba(0, 0, 0, 0.05); +} +.skin-yellow .main-header .navbar .sidebar-toggle { + color: #fff; +} +.skin-yellow .main-header .navbar .sidebar-toggle:hover { + background-color: #e08e0b; +} +@media (max-width: 767px) { + .skin-yellow .main-header .navbar .dropdown-menu li.divider { + background-color: rgba(255, 255, 255, 0.1); + } + .skin-yellow .main-header .navbar .dropdown-menu li a { + color: #fff; + } + .skin-yellow .main-header .navbar .dropdown-menu li a:hover { + background: #e08e0b; + } +} +.skin-yellow .main-header .logo { + background-color: #e08e0b; + color: #fff; + border-bottom: 0 solid transparent; +} +.skin-yellow .main-header .logo:hover { + background-color: #db8b0b; +} +@media (max-width: 767px) { + .skin-yellow .main-header .logo { + background-color: #f39c12; + color: #fff; + border-bottom: 0 solid transparent; + border-right: none; + } + .skin-yellow .main-header .logo:hover { + background-color: #f39a0d; + } +} +.skin-yellow .main-header li.user-header { + background-color: #f39c12; +} +.skin-yellow .content-header { + background: transparent; +} +.skin-yellow .wrapper, +.skin-yellow .main-sidebar, +.skin-yellow .left-side { + background-color: #222d32; +} +.skin-yellow .user-panel > .info, +.skin-yellow .user-panel > .info > a { + color: #fff; +} +.skin-yellow .sidebar-menu .treeview-menu { + padding-left: 3px; +} +.skin-yellow .sidebar-menu > li.header { + color: #4b646f; + background: #1a2226; +} +.skin-yellow .sidebar-menu > li:hover > a, +.skin-yellow .sidebar-menu > li.active > a { + color: #fff; + background: #1e282c; + border-left-color: #f39c12; +} +.skin-yellow .sidebar-menu > li > .treeview-menu { + background: #2c3b41; +} +.skin-yellow .sidebar a { + color: #b8c7ce; +} +.skin-yellow .sidebar a:hover { + text-decoration: none; +} +.skin-yellow .treeview-menu > li > a { + color: #8aa4af; +} +.skin-yellow .treeview-menu > li.active > a, +.skin-yellow .treeview-menu > li > a:hover { + color: #fff; +} +.skin-yellow .sidebar-form { + border-radius: 3px; + border: 1px solid #374850; + background-color: #374850; + margin: 10px 10px; +} +.skin-yellow .sidebar-form input[type="text"], +.skin-yellow .sidebar-form .btn { + box-shadow: none; + background-color: #374850; + border: 1px solid transparent; + height: 35px; +} +.skin-yellow .sidebar-form input[type="text"] { + color: #666; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 2px; +} +.skin-yellow .sidebar-form input[type="text"]:focus, +.skin-yellow .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + background-color: #fff; + color: #666; +} +.skin-yellow .sidebar-form input[type="text"]:focus + .input-group-btn { + background: #fff; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-yellow .sidebar-form input[type="text"]:focus + .input-group-btn .btn { + border-left-color: #fff; +} +.skin-yellow .sidebar-form .btn { + color: #999; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-bottom-left-radius: 0; +} +.skin-yellow .sidebar-menu > li > a { + border-left: 3px solid transparent; + padding-left: 12px; +} +@media (min-width: 768px) { + .skin-yellow.sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right) { + margin-left: -3px; + } +} +@media (max-width: 767px) { + .skin-yellow.multiplenav .sidebar .mobilenav a.btn-app { + background: #374850; + color: #fff; + } + .skin-yellow.multiplenav .sidebar .mobilenav a.btn-app.active { + background: #f39c12; + color: #fff; + } +} +/*# sourceMappingURL=skin-yellow.css.map */ \ No newline at end of file diff --git a/public/static/images/aliyun.ico b/public/static/images/aliyun.ico new file mode 100644 index 0000000000000000000000000000000000000000..a566910127486459f94263068146e62eeddea8cd GIT binary patch literal 4286 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 b9%@2g4mXrEG+)c995e2Gda5g*uA2HkY<|N@ literal 0 HcmV?d00001 diff --git a/public/static/images/cloudflare.ico b/public/static/images/cloudflare.ico new file mode 100644 index 0000000000000000000000000000000000000000..3c1743067126d27bf0b2faee3963411fe3148b7d GIT binary patch literal 34494 zcmeHQ36K=k8E%eXlCp%dEQ+#Hx=}R55Mqq6h%vB1f{2M?Bm@mAQc6}sQdGPxmDMN$ z0ChgGeu>7EL-^0_?g*h+#L_?w5JASe8m?7?5sEOR!;qdrsz4+_H`c0ii`f50T z*SGxQAD;xoLsJ9dpVL(_c$O;uJ69D2r6KWMz!W714e`P{UHoN%CMImxhf~|t_|41y zJxeX*GGak0_pue>x*uMym7NKimvY-L+pYDEmCqSJe~(_U;-Jwlq?ibGW$Zr-NCh`GFfmdFnC~9j((XT|hp^<4RFO4%8suT=I3XNZ} zF4Hudle`Hgf^%AKBhC{m-YVBFANPsik`^m(T%7616lDIG7UnZnJU?f8I9;rGtK39n z;!G1)CQPfdZl)*QaQAVe(`t+@sfMFx%$^&L8BxPgpPBQond(eA-n>*NawyQ4-Vn~u z0YBNOiF+1fY@HRV7si(9Z;xFS%6E=u$>2X5<`bI^>Z0PbDIQ#Q_Wi-{kdqBq-io84}~xhQy?GA+d0WCj222O(uj- zGsV1ph8VY17Y`JL`B`|t$fGtsTw~-6nXOK{VU({rS^4}PbnL4(#H$

    J9~q8;*U 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 AfdBvi literal 0 HcmV?d00001 diff --git a/public/static/images/dnspod.ico b/public/static/images/dnspod.ico new file mode 100644 index 0000000000000000000000000000000000000000..362fa8bf1573d1f8a9f4fa6c0d9f26b279d7c9a0 GIT binary patch literal 67646 zcmeHQ4Uil~6<$OQ8a0ZFzjzd=HNCrcNsNjSbz_NDB9@5-QOg4Vpj1i}C`E&cw*@M3 zd-skzkPu6ZAYzP&K(w@!$d!ne1!@9Tz_JPtq9y*H(MS|R`@J_iyOXKiyScfU*S(kC ztG(Vg)6?DW`(FP{PxqTr=`j4&>m~d@rW71;Sm~%zsTAOgLv)aj(@*+!L)B#`v4Xb zi;DXqY&o>2Ul?7ko3ZLkjWL*QT^t|NsJy}RKhO40t3SdPT4r+O`Gal+X3Lr*&<6a+ z+rT_+fZ7?Y{)g|?)JF`m9iZ>~uIE1k|50B<{exEDKwJ9kL9_$#|3T0H0{HLPf%*r= zjAsto_`r-0AM5$gf&a)38fwZks>cmdTLAv=^)`^B4QR9lTAes3Hh{8@d;W9epW6bS zgE)H-Yykb%>plN@^B<+BHkn)3Jl179Fq0=OK^yRIZvzo$Ifq)^;Jgj!;AYQ%&b)WV zgq-fR#?&9W9KpV|YAwVkzrhT83IK)?nXj>NwI;}AeYCpBsWzY)ywCG5X#YBR1pV$xS8Twvsz-bN1^MTD!r)G`ZT;cS*nn1d zdm9k8fu=goA^sble_{UV`O8G*1uoct(bYAce_{T)A5h;e0K9J2$h-kwK2SV$UNZ=`Y2!H$KLIqS8i zS$P@SgYP?I2WSJb>XPSmz+{&wCiGln^7yCZsl$BI;&pJezen2cd*z2UdGjfI5phkk ze2F|3<@H7Ak~U4+#{r#xB(Ha(4?=sCw#-GvLw$ISI1XBUr6_&Urb}z}Fh<-iu6w*4 z;PI*5eFPy6!Hh5te|F)S814JEJ~q^9V_KUnDjvoF-xTKGn3j4)QTog$T{FJosnC6o zxc;4XKs{(M7c-wS=N%W%rrs;AzgC~gTaT>iVXyaEas4~|V@%Mhyg6&x^SF-hlcncM zbg(mzvgefs`T_a5u#OF=ZF%XDH67^xOYu73kbeb?gNHC4d{`WV&;}l|c~49>1HC^h zuDdS3KdZeKaUJRa=8Y5gXi{=BcvlfRrA-s}#3#t>uC}KwpF}+HU$ywm;3f$j`{hAv zQ_%kXUDO81FO6fqw}62iUnzve=2cJZ$B)Eu=)P5ye`;H`I$1)uw0Rgjn-#|(>SN%K zE^RrBh-c6T$?L8*6`@PkG{bh#(tLpBc~Ns|^;zQmpH>fK<*KObfWfGIJ)m)?`m60V zqR{jVxe6bPi^a1CImX(K6;A z@+g0vY0&(XJPyH?dFqfQE%X6bi|gG`7iTGJk=I!9o$SCqDeTpJn>hbk{i;YVv!vbj zoh&;SNWMe$$kHt3&FdPz|D|#i-R39LcW8fDgeC5W_R$)Qs0=QI zm{%H>0@)(dXz!>1m;<{^fMI3+IziFSo zI0iH>cEDc_d}*$i*InIjoAY@7cKSi^@4#3%^p#}cIq2B%aGV31zcCIzL%t3$|C2WL zj`GI+?~ldx*TDr*{zOby+75)JQ(vI+~))a zt;%w7{%QQ{!2U4keUk;<+v}s%J{S0>G5~`=h~t1gNjCL|pX3jS>wNHh_yL>x$MZ&C z^d)&L)Yf?*iis7?amiNjE@V>)>uH8K`-8Nv4r0%oj z#d9FEPP1FKUggdI7`?NK-ups()X85N`S7Oq7)_qEB;2bvvJ~<%Ubm`8jxv|6d@j9j z%Zv{nYsRYzepZ)b{`Tc&to&+zmXEnbycgnB)bDq49dDLDg0}5KaDF9p`<=Lcv*GE$ zI)J!M0Ha%-!e=(@7Q;CmTp!2Z_HWdek9q!aUoK}`8*FnP&mZk%RZw?HoZZYzs}tk+ zyYL$}@PM}gi8cUp?s!ju3!KNx0PZ(?{ss7Va2*WU0rteK^ZX0&@8EtY=Kl+oCt)1; zUvC3N+5miV^jbdjq~3@jZk00S(}IJS~S=NJF_U0o+-gTIC3$?vJKJcT1HDp?S9Q?kO_vQM&cy59UjM0AI z&&&e(p8>bK@VyzlUIw3WA7#IBwC~!{wX6j~I#5ZYK90@GJdMRbKvzCIA(vQw zv~zu_Mh9XtClHgD@CDuYVS-&5{$laz%B9hSTqC*OjW9Ha%mtY0#^(aWWG+BV<^sfI z)^NJi{ZM{!c{Cx{AkTE8Ga_+$C~-b1Q-Sy6`k{6zRNzqNpcIoCCz6REx^4;~DHO@m z37N`43ex!~9g>NlC>>Hbl9{-e%o#$akby(U3`KIizuW<~hU*b8l{}5~h7f-WAp!I37b`>azsEzg!Pi+ghjwb z<%;BpuwHURXvflH`F4P9mpd+Z2x`ag$fGz=j}h2MX2PbBFrB9m0f%w99y?FRBYC=g z906b7mf0XF9?7*3=gxT?;t!oC!lF+anFxzM6hAIQoR7>n#ja;LRvzXdDNje4hZT|a zYae1end+V&qVmM#8p-wU`O$<-B3Iln3Ku6Plex2 + + + Group 3 + Created with Sketch. + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/static/images/huawei.ico b/public/static/images/huawei.ico new file mode 100644 index 0000000000000000000000000000000000000000..32085d8c196a0ad9d18dead6551565bbcfed4939 GIT binary patch literal 1150 zcmY+Ec}P@I7{$+B94ed1{z_lxYC$pl-o5WT=X~FLmze<+e#~a@8jrOG zAQHeh!V)V(buIukt7(YAdtPi&j$$&4tRh>;QL>T9dJ$Pe%E&sBPv(#+GMf~TI&y$W zP39&Nnb}Dy$r5scI7uOq+HsOVc9U%4Ao3YzlF?)uNh4CrAd|=fBI^su4kGJPS2h&` z!KM<$pg&^NDdkFFP@a4*i9&R?m}ta|1ww-JbwS3`fT*!4dV6fN-eylw6gYWqH33}L zkVYNq3j%O67B~bG?(+;kAOv?1j@KhX(N<`}qec@Rd{k$YxkzIqJTvpTq1jJVNi z!o%_~ymW-&`C#6Rj}9~5m51X^YZzYLV;@&2o+J=vPX{WfT{a9?uLq-*`iuMFcw57{ z8CD2G1iB3tbY_qm(rUry77IGAQD0`pduE-vdR*`aqebI9uNmzZ>8Yo;#ES0BKgfMO zxnxC`*McsM9zXjqd%i6YO?{zwc7;7Fn0rZ2C%x62UrWvqxo1sK6BX31(({wvr^C=# z#`j&xY^Cf;ZGbe;*G_I(6>&SlAl^pkMFaQL1U;gXo>in=flJS`+019@XHSi_HtH^V zwc$bHZmh$7FFwhmjY{>nVn(>1MTQEE+An(Y=+*Nqb)4t!{cnof$&M3@rG>UW2nsSl_j($I!JWq{FoT=^~ne2&GmS5#d tD{%Td_SOAx?yC0Nc02w5W&XY4-vjnG14TvuR{!7cQ2@!YAfPuK_zkXETzLQh literal 0 HcmV?d00001 diff --git a/public/static/images/info.svg b/public/static/images/info.svg new file mode 100644 index 0000000..fe91e8e --- /dev/null +++ b/public/static/images/info.svg @@ -0,0 +1,18 @@ + + + + Group 3 + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/static/images/login-head.png b/public/static/images/login-head.png new file mode 100644 index 0000000000000000000000000000000000000000..544958c8174a5e393162b603f9a52b084d586279 GIT binary patch literal 32292 zcmeFa2UwHK_BV=R0}CnwHUyE55PEMah;-@FjSvta1QI#~R1g#elpd;uUZs~%1f)ag zVCXgUUIK)2-{9HhaQ5-}-}`;{xzD{<9(TgLYu1{X->kJ}&6;`HZyu`1oh83YPC`O* zR{nvEItdA>6bZ=@u2Uy~Cm*HLG=VQNn+LiG5|Y!D#Q%;i95x;$mqcV#**TNiOar3J8Eg?7;L+P%CSMsFMW4fm~7Gcj99Z1N}i2J4*?M zJH!U*A1ObizXyXu=moe0IZb%@ck^{eq!%fXZ)n)Ggt2v+~!SK}1&PEgja&&a$a^&NJ!Oa175fKnKFNl|y6R5$7 zaJIGsJ8@bgZv7PUha4FQ!US$%V`l-grYFh;KY`iXNiZ-F8~XF-U*m$>{MnE-;$PSS zD1w~8HXt4@ZqPq5nVS5`V`C4uI_R3I2?$~ZfkLe95C9*~Kl0f;h1tOnPhtP1$v?^e zwP9dRl$HN%`ycxYh5lpH2s>E^0D^x(`j4ClO=lYjNF9QJ*~3jBvJSvdZvE5f?JUgx znw)==M5O%JzC)ZW{tFwC@{{dA6@Jc;I51YxdvFNY4hGkR!K@^IYT3g-Af&%{kEm4w zTmtm0%3u=AsNarQwuZae~`h$Bg!ZIcNu@Hc~}NuL#ALm@c&54-|PNOj;V>L84L~u+eunL z!R8Q9y;}hnGmKKk|6K?IW@hIIhC}X{13K|PwfCQr|DE-46XGD^Dqv;tf5T)Tzz+Xw zQ(?x-#}5`Ug8mrY9}oWDG<*LuPx!xPNdLB~{C{Njep=+e`^P`r`hWUUabjR0 z3ix8cFMtnxAdficKc4-iH$Uq?BKlM-`-A#IyxhPKh==(3FV?@453}n2n)UDG!>oUC zYFS&@NdmTe(9uJW|Heg(ets^?8bF{9krWgV;1duB9e#Y6c9%y5H zrpObY-(WL}-U#_d6q?!w9|4<%#}|kW4beRxt>osjYtghXH*OhQ9VhD;urHg`T;H)l7jeo-ktdQe2J9!Ka=!u;oCQYMAPxq=()@ZEh?#9Y)hzJ zO}d2H{ludrB;&Uzg4@6QE(J}>J9qfO4I*TtkSf_ciwhoksG>zJZ5=lbm7A}LYAd~Y zbLY(Xv7M;K`|P>PyoACy(h0lgarnlx5;}=Cw&_gxM#;D~+o_n=47B8Qgo^6ABO$Qf zo0e+ZRY}k`GL{RkRHUf1zcseMu5(}$BR)$SGvGv9+oG3wl;Z+w31sjMu-?4;A-tD)Yv5kvy(hHkZs{QDw zKk&GOm=c-H{y@GvX}TdI|K&;R3lN)4m}L)g(M~ysH!%3R(Cke1gi6Q8SHi>^NU8Fv?J>zRU=*aZvC=-Se z8xWQTAD#MK%c#B!5!2&g#t#I{+qL?nxH`2Z?55nM_Lk=@4}3{=>br}<52jEa)pr`q zXxPpKRky~_Wf*^PI~MCVa#tYPKZAoYy5a%gqF9ZNFtM(*n&8rw+gC#xcXid(j>YD4 zC(@OC7z*My5*0v25pLc;0{}L1()NtxX|91geqrK_t2%3o;JCKj!U+NBsVX-e4sJT5 z+9W_8{SLi#MdI>`Dw~N%pq&y=-fX;`f|P|N=fgIu{>|mHXW!ibWK~j(UUb8hjq|e= z+|3?%n-1;Cv<}r7p(e2zG!9jY(XM6%G#U^!1Bhy0rRtr}9@TFe&Dzl3h3UwFXIc6b zCD#|er8#+Da75SaLv@ zEU$Si-G6J;XnG7_pJH%xiW$MvYfqqq*NV~>428b7&O8=b{5iaD>%pw3MC8oX@h6tKJH7jlI{}!_yK}QvF3R_!!}Y^gj0(~XX+xSt zVC`{51nvbu#3`xE(%nwWMZA%^bMqyueqDNzjrYIc5*nmNlU#%Z*fNE zU^wJ;n6foK-bn4a`5g@%pP0F)0Z&<`T0=wQSFiXTjOEfZ%%(AFm%BTnW9k~Z+Qp$2 zWW=%DDPzX^y=`QQHU@es$DHod+g+W8u!8f7%sSm?10;-`+#2o{tg~tXMqAm{+<>YE zMY%XakVuW=q*O#l<2gSuzxD(+nkm}5hQ^#-?sv-B?M^dVmp#D_G$1bgb_BGrYn_Hz zM(GF{l_lPGljYS(+r7|W*Q*GcibdH)$!WPl?5o|S2-v`v>D><%2&@3#OVd`*55a6M{!)vJiu?wLmdg{DahbFv+gORO(Uo39L)=!o2$B<^OJ1P zi`-zMdq4gBiS?MWWklBqGHdP8Frk#662Rr3cW;gC?=XE~I`%dX8IV^n(_%rU8xZ1~ow#mu+#q)*&L<`epZ2EKAqUz%WtSt3LR2sOPIr|&hVq(-jGpWr)Sm1v22 z%e!;i%2|tTHNNAmh@rW5KSlCEzaNX4H##P zJHw^SO_Rt1brn}CeRLVRxQLO^fkL|W=JI*-Wgo!elxQ{iRM&RBzAAlo%^)R}zbXyO zHJ={6U-9jygy<5El$>J&gR}X0nPGNe5m@K?ad`r7;ZN>9C0$u6_k~AjJ=i!relV44 z1!Z}q|6oF_*e*~jZ#r{Ewvo>Ev?m5O*;(<5SY8YPh(O1hb>Yhf8xFfOW{{?-j^?|L zP+qKNcWjvG?ann-f0XcB7N@smey&ar2sk_829zo0_PI5 z;ZVDhPMHn~FQGe_&D{U<#e=pBzk3%7jlAg2b771A3>xZ7Qqrld4hFgmgr13yd}7bh z0j85WU3()ur>3~r``%BXiQiqTp3u5mL!Aww;0ID0m)w=e8n-Ny4_Zv@bTvU52<&o~7luf&TS^U2ni_vU2SgN#9R5Y;Px!vjZ(l zZ?Zu^-=Ur!d7lhDruwB@)|qzd28UL*bBqr7q30@QT(&1`+H{9zOQIC0Y6nqkzZ3ZN%f_% zcEPaV{(eK;biv*g>oNkle4@JVCMrA%k&A!EKm91EfoZ=x;HVMY8k%9A^ycX5%v#z~zJ%ez#R@r{jFL$Y z@)caaPl%&NLR2<_IYiggjE`Wmy8ona9j&EMdd%)~4wA#7f1H4Gd&G$mZEPTbxoKKEPG41}66Gz5c~KPQ9S!sWPGN zR)OQD?PQd-EmstoKHo$|^*uJrIo;7Cm}R{)2mB2lV)e_bZ(%I>xQMQQzNGXj*OS? zZ?wt93cpl1<4;yEvZ}njM)GPPpf2;-=b4|)=x^rHFz(uXEg1XMZSNx4rR;MiEn0(C zm-)Nr$Bcz>WV7AGH}@2zeWe#AMdJ1WkA9^gd(j=&h^GbkV(9$rS{40L`^zsi%>w}n zXQFg-+{3wJiyE7}&pln^3EAQ{0D9*_RZ4UZiKa!@%J*`kZd^}mDM!vfOK+T*dR?LR zLCuL1a# zdQ=n_-lDbL8u}pR^4x&Lq9X!8l=V}v#q5I# zx@mn%mY8hPkh*fy>=6yKg|`<@mmq@bb!$7s4qEF`rs=;~#6rHyLy_ij50t3UDW;b* z@&PP}B(tw`TtZ1T-StQ`{UAoImlVmOD(P(Q0z?Xxs`79Q%3zdHewKXw%C*Xej-^=< zPvrPWkPhvIloavjoX3X>wX=~7#r9$lbyVauBN3ALYtOCs@E)wK7O!0P^}9lI*rjxX z?nUk;T9Ur}G(#rpqcqf8FU3HxATBE_D{Al<(E^K)OyM#m66u8%;7Fq{E{0sdUZw5s1(Ui) zl?ZN!1-WFIMaCcmCS*D(oTaeJ$SGr9Kj4i8i(| zCnAyJC@bMN3RZ^5UE~|?FKEWIZ2pou44Q>;WqYT))(%`>`#I?zBr-3>J0J`}0h@(o z8V}sI*5!IBDdd42uV~mC^C&4&yHu7X^u-U`daVZ|=|}Q&0|bTO$d{8aSp&y+>A( zC&qF51FuJ>lB?C;eml;7MX@E7DH1}#8j}^RK73BEXeCA`spfwDxP=zAg9Ov`@aVkb zu42Xed%!C9#eTSoX43Bn$#NAc_DSp|&|WW$->%MQJlAw}zrYlFx+3w%-3;B35<^+0 z{L2JzPki-tH^B|GgU%0oiPEzq(xAzcQCn=E$W}@kYXuU~Fp=H($qm)jRHzzx!^L_k zj)gr)a?huX3~))yD-Onx?<$KIGr$uKu8UWOzcrsbN%DHg;LXM0hwX+tivh7~?Ff&X zo0n|AHE+#EL_{dKl*b6pzZ(f%bqrNl`oQRnzKIft>TCcm@RZaK)6q>4lTz#%cD3&# zavK#P0TMlr8U&ugW_L2`H`tTih34sp>^WQy0;UJgo;@RnoAs!@Q9mWU_gOyZs-;5K zy!{wXi4T?-Vp<;Quk0U<5Im?H8(6SHlZpw%`XtN9|6mKVuw>7>PlsHa7IR)L2)1hx z+mEgvQyGi|rVmiIdeQAEO1W^XtmbFCaEm*J1M(+>)g#fOVl;}qMc)a?M|vnR#oaQ{ zfkRD0^ErZ(Rml}?t{N;<&2`1M_l_5OYd|7Y$`yI90bz=Hxx!5n5+|Y1VlKFxUnJVN zrqY~|!@Mvo=G*iSs(>N<1D*og_Bf4=CWyLfWU}{-A-6OQy%%Cn07Uoi3OsKvKmE0x zjRdoEsWk1C4yBvIR-=)Qkf2~F4UEtP;Y;o#lU$s^E4j)jS3I@NAQ?Xz?obJ;H49+cedne5~G1O%W~%lA%&l~N^| zW+yl8q$ENd&R3OucZ4TuAAhr}ol)Wnwe?%}CY{*bkIy_Rz1 zF}E%D=I57uQnHcHbddhTo_@x{DFTacXU<3i0W$Mq*m<{nEdEVvC7K!V)T~{^kX9p@ zSw$Rja&i4E`-=jzift>yfjJ6lWkjXc5P#0CsUJqiKO%DmrY(t4u2<~m;Kl?{h!tbV zH)@UHZ}8&$%X)!I7?Da5!c}CitC47`^;{a8=27BSQ4Phv@cmx&oD%yB$7(uV_|7JF z-PZaZa+fA$0{RBkFx6Ieg5I$Y*uhT7T_8r~)wfdT^2`(-l9kYy7xSXTIrH)LxoPg} za6Ym3F>^XQv>n(RT%XSo9g6Q=UXjUTp}VpH9mYBMdPk&)f1f1Spz0V3^M$71%RU4V zI0l4!Oe7@nzVR7vzXQRA4z{bvB}B=UFD=V&_hU{;`~3cD>`=$`FlY>aau#!>HBzrV zW^LF(Uq_AV`qjj}ljl8d+xsOAH>rM@S}@q9dP(83b)26+GM{5Cw;5bK@A6W0@LfZ~ z4xW{ign9!r+@2}Cv+iJEqPWtp8Z@V{_m-1R81{5*;zE*1AC z+&SubqT29C2HW0-+Ql-yls+N%{io&7QES_nu$nG%A2n_iFP>MfwF*$sw9Zkv%6sP*LhtZVK{q|B4TeRA!uzEOfWmd z+-804i|<{2v8!=23wm*8jUyj zd?$;^sVE32*zP`zWn4m2Y|KpWld#|6K*=Y6C79^ zA-a%efz^cK4E40dN;>=bPu#8_P|*y!?li{m?XaLS5s&-xhMu8f>>h3`GXXsU%trmoj`nuTM`ip0MXYmEJW8?dcaS@dZ*)BCALeRaY z-mp_r(nDW6?Uf)M*i1^d_pu;Gt%Q)hmL#i|24iu;@s};q6h~=$SGH3cS-oJpMg zRyoLN-2~@dU3HU;2b?@+o7#oDAAPmaorU0b@uzRN3Azt|2yNH{FSmDBonY?FbJxv2 zc^cqY$QJ#sSZ-Wshop7oY^|lE5MHH}st53|?_=jneRArSal=t%r@1hE`sF5QQmUo! z_sS(UKCSj!r0!m8To>K}!Owzm2rhsGN6iUEx0@Q@@LFU>;39Cb4-slv-Hs#V*And0 z_aO<%o=eLEcZOA>rM_(VymDG4#ANw~YNZP)irSxN7A*QUU9!dZ4CY%QSp%m2@C_9! z>@M%>Ay9F0D|B_?AV282zUAlVHzB#EcuLaK!IbRwnj>@2sv;b_^Qy6z>&m;~91$ny ztJ#fo{*3BQ2aUdr4Mn>R*MNWguaAJqs=|yJ!MW0U$)eYhC0K9xLiKYGx~#p zsF}5^OW<9Yg=mQMkuur+^mvHH*kk1O>6W}*pC(BqsWUT|f7I^u&MKsLy$#K84#6Jx zq`PQ`{TvUir3NE2>l&X~_i5RMQ7bzRN13Z30HQ##YB&(efCz2jYkbOUF(*>B$4B6K;e`@KqJF5so(r&OOpElU=o^q?bDX5+HNFZR?^Qec&{L`}8$`?CL z$r{&uHlqe)m)^7r+w66}p;X0w`qAf1AW!98#mlj7K4^b!z=f|OG(9Pox~cn|>-^w_7KYhTfIR`Ue1=&drDivc`SRQ#pV*}DXFZm##}>I3l{blN5VHlC*mwmjOH-=!-N}@ zR+C*ASu$8U{UVVHS^2QGd+E27i|LEk3lgd+dfyjz;}a&*uXq#sw)0Ni6HR@~l=^zXJ@ua6 zji(Y?Kv-!z0mNm2AsS?7rf8lf?ORz{-TqO?H&oiHgw~j5^?BSC(K1LqFK;yjE$OMn z_-{LiVx7&X(TmfvjbeMsW|R!&pD>a`Jz=-q3Qcra1Y|r$Ken7E8Da4ctjET-(St7d z21ai$>{lYvV>!Ny1<*;Mjm!|qw%5I1_(#0A63z^d2-YhH2gZGBqlnF4{d`i;jltm_ zGtCVepLx54@zGd)iAR5bTnT^>1YbJBjz^4t<0S>zU+oemQ8K`So6#oI|c}1 z0g3l)iv*qfc=2*BNL53bIl73kJg6u`zd4t*%P-_6_`YKoa8CDnKRjQ$z4M3FSB*60 zuctja^L(1ly;ZxoU>~kqSm}-8=ef_e=5&O9=X*5}*pvmu!5)&G*~TaKTnVaa-m;M# zwA|SgF-J{5O1WBPOHcR_(S@(w3%6Tc!Q3;=SA195>rRv@XO$h%qWrq+xy{V(Mt(k$ z!B^1{hFmIC9mFfy(U<|V?r6f({t2<4EM_oNl4kbug5FLCrPcE&OSus~U>}vCe)ATzs zM#LC1qUVa{(F+ml{^{3xS{Kb7_yq)x7uhYS@SXh%wpM7OV9&ar)nuz(I=6}(gfIgkyTqfOTa316LMjwg5e$?r^UiYLYU--B= z5DRPsct9GTg9fPTE3pJZJ?TJl3_M1 zG+vC(Xp2}WcD~7BCY8RGgf9+om&^!U0+wG5^3c8 z@Ljo}x>|Q?F`T#yTUNB@GJIXYIi87s)r&g{wVIo`R!HB~DCK9^7nKtXYDYWN@eD#uQ^_&^qH6U+)NqX~5uS`3tV79X=b4ofmuETIeGPq>Fd&EaI#n~|&wwa5< zB&f&R(RZvZkD15b@KH9j*?I4wuwCv}4%?um{E^q}p|Sq8cRoNe+c;JdX=-WU{qmZ~ z4o}ezsP!uZP^@54y`H2raf*OQ^0^VCfatONI~5{5>UH@jimqZ@Y)V@1-swA02&o0= zS5gJ}D@>OS?1A7gWKE6zg>c*ze?QWWIZ*?mM#i>2#GJzd>x;D7w?8>ssYTQ?7gZ1`2x`@yH7QoZN zI(gBObPFe4F?7xRozqRwNH)g)wn6cpT9ALUC9LX zu#vixl@!~Is3@tXonA#q=g~HET!>3;P+jwmt`Du?v^Q|h-li28yfE`9>8Ql1^J;W- zDfMRR1(8_BNrSk6XIwUooVhUEy3Y$MJ>0##bZ97EL`$2Zv5~-hu}|oQ;o6stEJ+$n zXooEhf%XX;7sBfnPJ4J4kL-1aP4utGd_=dPj8+NrN@0zV(4nQA>A5@`4vf# zuzV~mfz*!q1{z=pIuEm#;0{I8&Y*&yuGJq;A^fc$b33T zNmMd%ZUom1MO})2NUgw`s@DfZUAtMw_3~Gj1r*IiXvklaak*Yoa-SD69X(?D`juv} zqS<2M%SuhI(`9I$rj{6!Y!S_rV9NK*j6r8(1GddDu||Yo#6n2P4NO&<`T(uox{q8g zzQTEXVsN@;HKAu?Rx;=nMcRJrSw(#h9AacFkh(6{ZxVqWgAD8GDl#xO;x+XdkqYaKS);v z%Db!=_aBxGZnQbe73B}^EvHLaT+3V9%TJA8TV+N+%D&Z#84`w+m_8 zoeh{IIaNvF!tdN)@2a>Bc*yIfIaemK^@}PicH#m&b~+MupPo*>6orkiH?4Z{VMxWC zW@2@>k~=Xmw$Pa1&do+MK1q%7vIEDiCZfe905NO962iLZbLSH1PH7Px-=&Sr%xT^%PP55=B*>@&tS z)2=wDwwz7%OzE9=)|BIXseyRK!1{y-#@a~CTCZ4ihw(O*9b9+IF|8(K#!7>EAU)ba zirzSM6ormLTO3Eg>CKJOmP)HLV&3ZH4bQg;g(dtOH;%y2wP za82k;iAGAQA$rc)#)$gEkIu44n(I0pnIZcP?3NkRi>vS8*x;r?cde(z=zI6P1KMBH z){I-u-Hw*Z!4;Hlb;ttIwb7>=JUJhnf8Yb^^9yzzMpgv1w~vjSgbCU1q=^R6sxqBF zIc+zIE=w!WR5OaFf3Wn9-AaT^v=W;$e<%wPcvb1z z^uq2Akmz~M3LD!&2~da?(cvfax~iV#ZFH5FL67Qdi!iDNAsq1{d~!R*piJGojCr(~ zw$4XPl>1nAx1`Ujk*fO!^HHwJbQPMsiT>Sw0ZC+4e&)R|WnyqsFVIU-SE>pu>t~`9 zdirrut|?NPoSA9bmW}#H>RdBrVtR3Lvo1OCp-KoeHecMhtf0C~N>s_*-EJtTCJYG0 z-*@NVj!qN@WszTciT~7&TDVbemYV8~v*=>F1m0u|DqsR`0lZ#2R;M*BGudxU*e*`F zd8-p!rk#xO!v_-#RKVdrAs*3t;%-jOx_~O3rO3ssm`z?) z;*G^_(N4NU;y~BVN(V0;J8&%~h`tH3^3cd}=;f6>9q1yV3C^YY`AKn<{y%r#6Ui{>PQo($STDIyKBra!Zsptr#<1vhp@r=fu5KNQHKAeTH(T`RSXJHC1aq;J z)0#6!8L&U(HW}=kk(6M}pV->SX|{?zGOdX9p_XWsEXd3hGp~8=!??b+mooDyPa#gUT}w zMaBf=Mu)&`{(1qhycVG%gBZgN(MPk|`-b3fweaTkOlf$gK1y+8 zU6M{7J}7j~Dq?K6tKhx?rkU5GRl|59;v9`t!HAFa_?@sxzFDE zqlkmMODr*?tYiUsk}kPCb9+7^AF|z-U(UuVwlX*7Bh}YP;u=xkaMHTu={7ON^rng) zNNusQ7@9C=T(}#zj)NC8G(0XuG0%bJ>e%f^KL{zg5D zcQK@SZEJ=_WHKhjhKf!EzZo&KzMl7%?kTcd-sg;!ak1)PQ5w=`ufz_>5JfgKF^f!g zZ@2^oK6si*8W7ys!Y75{x z4Qf8Taa*6UdNgbpk8+B=54hM9<(4hwCCOsZre zZ>t`s?HCF(YmZJzyCFCnOUU2GT;KZUOSLhaVh=SBpA+Xp4og%)tozpORSbFY@3k1Y zL>+sV%ul$^MTwPe@bHN}X$$C`eDu`VPQ|CZN5L7!ITk%{F&78fSe0Se+(_WTwwxa| zkuUimCiq014qX&>*=$)Y4b;D} zUCTJYIlZ7C>M$Q;i?!et!^FjzQeErI4|zOkkQyX07o~56O4_PN)fS!YE0qAw3(oF1 zec*qx>?tUt9tI4}wlR)3OhNFa0(}F#=v_9}PStogC1n&YG|sbMm!ZNuDP9bpkjVUQ zfo>5t+q^1YAYa_v)UQloH#cr*-4uZSUck$2Kl#5w+o$hd$_>wX;*t2Rq2?fv%B^m*|(I@WuPU#${@DR z4@E70EaA!3D>&QWWb3{UZU9!bO9k>{I5%NS2O!NE$MUJPxE~rGHMSu=-evP@&p#m{ zflOIhST(mou%2@yMMfxI%>?c3ywdYxs zdhf%Q1Dn^NCBhmx#A#LZkL1%gGf6(iK--#QG2v43LUgF=6Hi0bd zgcJP657;)LUCC_BH2;geaxC2=s}~X?AG_?WO$vjlj5lp767s3s=L*%T_E;y|`}mA1 z4YZT}yUYA&&dxajXBwnw#It&{Jq7j`4^%~vNp{7PjRPsE-tzEEr;nQ?D9~*)0bVOh zvh;GXpSk<^3BeuBlLAtq2IUL!b#cYOiDGA4_vaN~NvnKBx=&~K4*W64+{wAQI{NE= zLitdV8q7=4o{_lPZ80Op^(~x3togm#x1KM{S9$3Kvv}Nc7?ZBjKoEBe!j``Rv*Xq-8Sp9uisB zDyCEI?GcjHee)F1CFV)4!n7931@6>!%e_x( z=mjR4wTZcm)jJOzs_A9CDvHu<9=Gp5&rf&JY{o}-NC9zT#@X3C_hu=9&jIF0rQ&CU z7q~cpyi}a=FnB{j9=LD#xqp_GrH5#P?WkC#+3m5oN_Z=G-A4%5)7b=l%h{dDX8 zdR~a-MJlSH>v36X-_6|xW4hp^!Vb8Wq*6td^1<#QEiHKd7)rhZ)K-orj>T6u^b+itChbc)1*_hE+%*=Bn3+Y&3V;TZUCI2MG?F zH${Q7%Qw01Svs^vc$9uL5bPU^&s^kr(|iI_(S%4i=WK5?gJv@j)$ux+^rAerUSyJ^ zvBBJWc14JWahy|AZuTmq1Gt>>o`bq6tu*Y*)l*Wk&nh>)JDTTCvA;+nuZrSDX$E*` zXw_$TU*5TVLC?t*$XY^6?)Ks8w}v^Z-7xPiP!xSDD@iZ!TSwBha-_Ns_$-Z;LI{!ct(uUQs1NJbp4Cs6?ubInx^AOshk=CGzVOvE@s`0`XZ2Te$=;(frVS>03&ZOEuKIYc6q2WHUQgA*-z)AZ{HMn z2V~qO1t}lVM8}8I0C)*KD9nOyuXgX5tquApP?0ZChhQ3TLrzpKCRr&|u154F2jv3Do6(K6hQd+&Nz$s_^o%OayRD<2Xe zcmQ@s<&C`oaztRDF5ztFv!uZeCIIwG?vGqnZ$^axj@@&wRMf*|UgNY`=M83>sL?3b z2}Au^M6ceqExd(gT;&mW&PLsFKJQH52QNps_S3@7gTkA|GMTud!DO2dPyQZIE}} z=I+1Q1Q|#$-tGxs^9|bVJZ`k)lx&C*P~6t4Jl>dk|D1FF7wsn;@}nc-3jXKUN2nHAr?3cPichg*-I49A{K zI>sQP#h`r_4l%SWw$Of+Q90o#bS>P_RNP{VjI+=_XdlysA4K7EHOif)~kym%$;e56` zfn#WVNRssswNQFvn4HJUsS+){5^9Ph7xTK?S5;v7$;HKDfylrIcA5%-LKobL5~mmZ zPc!*_zWDmHm0-F7Maz>@FTGOOeIBxY2a%x4pAzpv`fZFGtYitVeqooVYLkr2hiv9G z_?bw*0j_@gGMwHBfzg(KajuWUCM+v&9vMkoQ;KpLtq6=(W;!nmm{g)`S$}%=v!tl8 zZ0L7&Sqxn9v+$O^zCrP&w|wl@CgDyi^)zEVC;_}#p+R|B(GTWfSU%?&Bx4`-u_C__ zz7O=k{RoX`a4c}~Chfh?Da_d>LBoaobrzaX9nIw16-%=3YK!JPEw!aw)q+{RzNp5< z&_Q^M!j;VCn{7~ykd(Jp4`COgkTNYhh02Y#h!zT98yIgrHwOf~zJN(&V{tr9 zK-8hy>S&DOw#Kl04q+O#$JIhbS2ZpKD6Wm?C&6A(yxnM0)ug#(gZ&Ec@cOVsTB(|x zlnG1WHYe_MKKx9t>?cG(($&P5S(eNkm1ErC!6()uDStSLzebFKw!mko%^xsFHZ-l_ zF1CV;Kq+LKIQpv-!&VqAS!V(e4IN2?I&Z9+^@b_X!;KZp6yinWff-IsOVj=~Va=Lg z3v%@k4Ji^8?OW|ey%Fxev;ZCR>LUm%nduMaSL!QK2Tvi+57>zZnD$i`9KAYn5>P>I z+b30AgR|EFUld%QaLHTWLj}z6;i2sDAsyC+@gZUG&fJ$<*#a=-$DW%}TW_jBTajV9 z{w~r#{9o*Jqhe(=37)P*JzO&Cb=jJ$ul|#o_mg&`9ww?3bt~;CF-go>i>i6en z2=9oNIXh2W_M+<>y&`o@sK|+V7^U=R-9PJkGoMr>sM(}~6o}XQh_A0P6BvOM%{W{a z;#$(r`H(6V{VCX~d@1P*?%kCVvSRj80g(c~^6}c?PayzegABWuT8@=)>|%_QK4bHn z&D{&<&U(d;0^!csc~m*DZGmf0uPVfgx$Z=!0BHw*!)r`==I@#k=JP8y$G-$fW~v9e zt||(gGuMbp?ROH-61JM{Yw6j$^mV#P z)s5QRiDR6)kUq56+af!iluuLxFqpA!c>bAQj3zQkPnipW2Of}>H){; zSlo0DIJfL(KAG9dh(kJ#a-d#|06s{VrJBPjFry;7i8AUY>*^m??=gQV{L3t zIrWRoeoX9-DB5YcJ~yjg?L23XtFIO1k5sCDD!+={cqUH;2sBfQNEYj2Tem6FcXrNu z`Mh!9Idt)1ul}B&Lzn<|OlzA`vQ19BN#AIUKjod45hfAF8rR8T92EWAv%KRPc zWt+p&XvJPdq83;mH(u4Ry)W^Bbqp@_5hleN1@vmKNm>c>#obs&r)MUm5EvsBXD^>r z78wR6L8A}?_9yya1EwHl$S178nIkgtmvO<<%W$E@6m~90((R_%ZqsaVZAtk&n)xer zXOEEV#7YKOzfkyDC#Pox{Vy@B30b2tRXAgmVhfnPyVO@(m^9H7`Py3T4TzUYQ@}DY&R{y5DYN*P}IqL)D<-0)c(G`#1Gub(3R09~O?>crjL__H%_)ympd=Mq6bXSkT zr@X9^-~;4y5+<9JOwKu%N&rCVDXB9*b#)EzGjCT)gdapCi|2AdcdEUIYp9*8t{QTX zDd1UDy_84A~1A^fP_-gQbP&S3^{}_AQFP4AdON=4@h@NcL<1d zOaABc{oTGd@5MRi;_S2c*=w)0*YiAk#p>&-kr2`o0ssIK4RvJ$%(L&m3m+GAuQaX7 z0RW%?4P^zRx0d_C1R0F>^%sF<*)opVj1efR#JG z#=a@Q!@4P;Pes8O$Qmyn&tJt)7@kL~9J`}!LZ*(=IVQwnhKOcX?LN6IHS4q!ovaU@ zvXDKUI^ERB`6YemH*zzzP#^q;RKYz3s~=rQjM`Kch05m63qwJyWMute z5ad%_cIOg>P03H6g!))x;5>Trha~;Cz zx;p(@kYcOmZ{mHW-4^%W$a$wHol;z<5?iPknTTk4DlwU~V0)UvKAdWU>A}f(wlV)j;SifM|;Yqqsy0O=|g;I8W+tiV2WGPHq< zy)nujM#v7e&4EHBYq=EWu+i=SIMdi;CWj$vio1kN<|@8Sdp+u%DIc7)1Mbf-`k^HE z`5T0PDEU62^%oyK`=cGCzGF|sUeh3?pqaOOZ=<8tF}(=V_xYcte#2#n7%BTI4A5xi zC3Q=WUJ_hv#(S4Iz~3*e|Iq*nI4PRf)jrG3;ijDxA@>%W*$DxzRF=$tI%xxCOaaHW zMii8#K6b>6E^f$rIaE`6$lCv6z@>ig_fwwlyBQZsMYd%bwZ*LCk;L3OmzG6_Ehw@A zBU}>JA7jpOa~-Bf_Xx?!u|};)p0i#|{wACfV&L|9$^#U5M=NFk zZCqYsPH{{qW`yGeM0BK2X|y_VwgqKB1NNuyB?+%R1w3*Y7-zxDL<8je(J5ugts$J_ zqP92%Sr>C?q*RUA>+pHubea4k%5uJ&8;OMAPpAb;=qCp^wWw6@j@$lBVHPp=82T`d z%)N50>(Rx{O5c&vN>GZ>l&)v&2%B}GZ%!l~gUlL1y2rG2`bE6&@HYWa$|2K%oyxJ` z7rDu*uF--Y7Q(siRJAMaz1a)8Q0ZFVr|&Ec+$ItuN9Qv#t3DMv=vuX9EIV`K}cS;D~y$kzPLlo-9O}=1MUEl%T|j*Z9_l zqt3V_6sy2l+5~@nCtG2^AyjtnDCv0{BAKV212NBehhx^7{&MND{+tbMRM#5 z90?941$U_)%Q)seXa`6;@e&EGo-eKC`{xbyczp2J)+9BWQAo9o) zIfiv zd;rp!X%%trpS%3H$bRa!u&Z{zsKnQ;^W65cIhmt|H#7EErP>~dG-=~(`9!5GJEb9x z@h(n5`aT?S{Dz{xo-m@rhb}Dk;2(onmhibZ;DM%NwZ! zM}fkPX@{ihtdV5E%EX?hN@BW1@@G}d3S9&P>mRL<72k5wFBLM-8zKj`Fi92%R!+fYaODw5z z7WJu0;PXQ4u1nWan9pP*cvWfR3kBV)$9w~sQ&mIu0j0itNSlWfKF#32h$`vOSjK1C zy(5(HD%7bsK!6%@N}>z$UIwYP z{PT#Pn{3q2?3h`k=cZe`KVE35E)>_gy#%kjD^(r>|OCZ4kSlhf}Bn{6Lp%pJp<@6xjd4MFu>1 z2arJ0`EmQ%EdHcBH!6=e*7h}@t#uYt8@x}mk)!7r;%^ zr6r$V=TywKoLg0w=t|;mcl{(i)Ipn3DK$e|9DS0C3G5)R(7uq(&T`aYGJc*^_?WKOQvqj~!bp%OWA^*@N;_#$??< zq7GPnxvsq*W~i5}JfQJGace*|#(deQ%I1i`lS~UY_?vS{DUW|)`o1?>O48lZI@^(| zo@b_8V5eN5thp{VOyyfI0jWMm!(}yO#${l=rx;)P&|8iu9Zou;5TrHJ-4?O*E*`}H zBvhMOQsY$j#?%u~6b92UL_qHqJ$SbeInY8@dSCOc<4GX(`w62%)I^4Dj6<;df0GQw&&UIdZWbc(-euDtbKE17^`4%gbffq=!;N+1#f;7ZICRg-H`+^cs?U6v#%hF7?qgoi=&0_m zkn|l?NBA|{v$uw8?7XP#*SWfA$@kjUj9DFn<*E`Mk2-$3Z)l(Yxi(b%=$R6j@qFh; zA)S9Tosy)B74}Z2u-xQr;{B}XFFjDlAAS96T)%2Rr`0%=W*{tj?M)9m9*COl=?%?|7?|qK-%0!?} zoUx1UdtTlNsOW~cK7+^_Z747w#=hpX9XEC?S#g*`Ix>U`N-o~ryC#D=a;$#e@Z+MZ{1QYqWxYM zDQin)FmxEGFS+H#x4@+o;Z1+;nvU@lWpsV5@8g~iSyC`?u>cT0BQ!ohX`j=+!bVwfdp0?}uWYyR`gZbAWCEd6QWnY2Iu( z2*zy&s+4j5T9CFTNuLX|Dx=-?E9{Y))60N;^s1b*w$P_l^r^iF3wh$7>{oSxn(5-Y;M9fMZ%a7n)|jG41(f0~ zW?5DSU)HW00fu4+nZ=ka1~S4D7EQxSzEszGUAFwbJW?WHDXMuiFZtbFpZ*SsZP;T?0t!k(<4vt`sY{j(g}=q# z5VT~JCTpsQyxy2^740Tf4zfO$5{dF7oU~W$;(AUv7devl@B(Im=hU!lE21?;uXr|aO33(3*mbZY@l_42+ zlgZCg?hMJ5#cyvv**nRojg~j&_)mspApRRbMOnU{`0<5o*UpO{$y$|>WzCb`KOeF( z+t&?Fj473uZHSa5-40_Xu#(xF_M~=Z>w|N4%^o-?t^!6GPVNXMv;k9SlD_1noG zeUZj*GHWKzyK+fGTKY=YDrMiG9;d%xJ1k7S0fabG@(XXAIX{c9Hx)~RQK#-(nD^AM zr<@A+mOCRm5BDrulM3uwtSV<2u%pWI&%1G*DPdLSGKh>SN|9{j4eD4*x#zKp`}4uE zGb!m_N{r)JdS@kd6Ief4VQ0?Y8on+iHc|in+~#sDwkRTH6~s?Tx)k&Mb1pEaAibGd}c%88_<} zr1E^k%A51q<1;M9#&~@MAH!rEy2JSa+Gnj!#aW%1WJ5vnnlOf6#q z&w&KTg)FI&U#;bsdO3eaQL0zjt>{GtclM;V$c9dd*0AoH|BI%#gaSm|t0DD2gFBSy z)e({Gu3g#bW~vv33bNQlc3C+ll6zwkLDcA$yw%}4@ZGykpKodueSLN0p^Y#41gZLC zA?oZBZYutNTd^$;iH&L`zQVk=r+kZv?<5S=b-bKa8MaD*SVxqQH%X;W_En422-#V^ z2}!>;)xq3qB8a*wn3VFU&m_qdfdAoI4kH|E@kCl6Rz|xcRc$U=@-rnv9+Z=IbmKfe z|9|0}wDQI63!{M1v84u$cRUBVkVS!QMR-62a;ON#T6?85I7Ujc&ZG)mz8pfp-NT7< zB1tGP)9YFxPwJ(A30-Zsb9GF*&pE%Rmki}Wl@L#erRBSWyJS!>YNm%D4FRY7D>x_; z;JkB|G~M|pjaK~xAyl%=g-b;NeKT7HME#6SU`Hk&1{@#V-hbwIPb-_f6%bd^B_-{} z0z9s&gFLC3plY3urb)*%-H2PfmiTZWJ$l8016KbZ6urRK8V$Kmw6{yrVr6~?#QO2# z%T%+x+3e9&iKiw)*?uHYQYFSXZkOziJe;7b!U7+4ND`3o1v>$oWqUX=U1zKl{p0SSH@i@&r& z@SAsLO)>S#L|nNWK-(aXMNKhD*+K!b)7yug0*vkUgF0FvB42w#L6pc-Rn^wC{7+zr z3L!hU;rMNQAmu-K3jFsiUj?Kub@JE+kbiAR-cbUnt6AC9L|lnLLfflhUaj>)DT*s3 zqN$L+CVu~HR6(SGlW@Y5Lx)fA?}FKui(ui5AC6svKn3Z}TnO&5%Vh(oArVeo4KtQw zbS5ur(-#AMvg}ykaoa8NPnDF0kRntNW{00?*WC-@Q%C*R*zO>(W^4C@uRQED;^?Y@ zBy>r%hDK+5vdR(V!N~5&w5ir-0`;GipydV;7!uk!BaE750#59=^&Q&8@RK$qZ~_Vw zud60M5T{_Qxdmy!l0#fjsb@T|Gk{JKbuAQT)&B)N;oPj#z40%BsH=0%JZ|q3t*e$) zOa>D4d(Qqo0EdbOPnNIwRjcHVXRvL5&L^4m5%9ey{Q2Q!WZqJiRjw!6gZRu z9*24To+s$48|he~U>%Cxen#&lHq*>V-gT1S^ zmM+4<#rX^G``nKfA;7s~9D}mpOk@=?Wn2)MXm@4(-<-d#+}Vlk=5uWswE4VQ!be7` z&-^^+{wX-q@6@euO!E$oO<&4X1q*#UvkVO7{xL(=w;%+fw1ftbjYc@gla8e+NLkt{ z`Ou;L|My$MTQmY}HwyA_jMx8<>(QNITs-q*K2)B*NjeCUw+M;csCUIDD^h^wZ|IJ( z91W25fH9eBTnJ)?a2@~YJw21nA`j(3?EsITo_p;(2nS2xkAhuWyuQldoWK4OV5H#v z(Ury&ipGRVa3`G63X!0jbLS^4ag0rL;_@d(WWPS(&_i$akk`P-OoW?@D9{9MVj`M^ z{Z`E=@%HvJY}#hWW^hdRbb}uSJ1M^7#(r4Cqdv1f`kCn*inPM5E_Sqe=c6pw{W05d zx#H769$amW3z-Dz!$~v!hk>$JzOJO0y}-vE>q@;{0|hio&;OdesdaIetzT%wgZjR$ z_U!8+Ed7G0-S$ZaY{2&sZTua&lbJZ=E%Eu=Q>xr&%( z-?TjHN8qFgNvjDTSB6*{K#xbEY?ndB`@wk*SI11g?T|kDo@fE3EO2By3}`khQ)h4S z>|q^`8^o##Z8q=oerO!>VJ3no+F$SB_8~@^8TZV>nI3=wgMC{ae@1FjYFj6Q(|?^bU~C{0-Js z<_h~~TlpntI_KH%69`4JJ7%06f{9(1rVek1ySL%Z;`$zPsu~1c8(mS&Uy!u<+{7~$ zH$SqkLN^}Vk3vI)QkkAF9hKJpu~Jwk;YWdjTfY5$QVqg#Yb03J3r?PON`jt#J67Gt?m>$R@Z4x1sd@-O9PU5`LH0$?u;X&ZF zeoL%xB{@S`I`f@F7nf=KEXB5peg4KH^$**a=kKx1GUtokCgujA305p$*~f` zMRm(@fDRLbi8GRRGbN202*6N_cYVg4g+8egf!&@cpGW-HJOyMO+m<0;_Z|nU$fO7E zu}xp*2o_Eomop|~Tou_n1;(ri)xl2eZ$cdQzz!&fIngVgscGNC!~FF3^kQdp>|2Hv z{r)?}`;`~6k2OPTEuc8R>*A6drHK6~a13OUGlS9zVh9vb`|U6(G_O-TMWiH$b~&i# z2pE!N=pCYh_I-7ly$>wq+fCE+9ru3qmPi2Qrn{AxsFOYQ3Rh!34NWDSYsllv9uf+9 z0R=LjRs~X*1~ca|be=pJ1f94Hj`@-enmHj7mSd#&0LxGItULE(Em@C##}!*HhH|!Y zFoqJM#qsT2N!@``V*v%n;ttnpSX{r`EZ{0Rt1vr%@sx9 zKIXrrdXxR=20XIJ_NpNo@r3TKzc&3df1kF#2f9$W)>c^gddWy%ic zLkP>3K0^6LD0Eck+PV(EH&Rz7hMBx@>?|f1sD}J%E>Nb=^llf0ZFD5em3qK;4s&i? zQ)$1PQ1Ft&0j)+dB+4|ggdUoVonUY0-KzfpORA?bRg6QA>{NlTbt>)0-|vNFVnk0r z0eb>t^A1c!b{@U@c2ew35TQr#RU6sQ9mSF zm!wL^=2Rab?+X7TEB@xyIsdhl{DSfRjMh&r*nkD^YO!RmSDh@qd+9&s5t*8v1V8o%$-!G zC6ib<7-5*-!ujlP1nrMJXD8N>{KBFYG#{K)$c{S{fQlv3{T~ur{-BU2;0{WIMI_LP zoc2%IT+|55DY${b>Ib*^WCpUQ`aAb43T(O7y@DeofwkFUE+&*agA~y(7dSdXke;@a zI@_jU)v@u|W16#YH<~lsdWUH}wpBGM3>8nS@5mIB3!Y>VKZMA5eQcc<{RIwpC`|t( z6!z~r?_zRc{H3d-MCrv?*73J4)*Xj^`Y>SnoGWT$DJ?%lRNW_FPB46&q02aIShMKh zK-NRIHw;k0!$K(&k&rZ9!9`oRF|N1b=13Y`62mCpNu3(A-CTj+=wLs_RTdpky^=A! zC_ho;+;`6gTj*g8=CkieoU;B^wX0 zmuknlF-y#EvUI(D-MoF(#x*|Z3nG?vH^=#2ZQ}!3Uq_yiy)^H1+`AJ{y76aYSn{dD zzM@T*7VpvADxKOC0n;EQ^OpCPS(SxEHcZ>C-n80T;e^A*{sG=Imu?vV7W+7xUgwgm z-u3}p82zK{?Y>m*WCq5F_Xp z;L?x7F@7~E7crv~C?+-2RJdIO{ z0EEBD#oYN_swg2(n&yj^*$JyDbSE*#7@RyZ-z6^7dtC4k3$eTLcuiZ{b48Ml^GV>Z z+=6qj<^#H!21i$3TCSru&b`b=N2lQrK9?r{Qi5^8f=8!%)}ht*PTTBZG8}e>AW>Gz z$$M~E@%=jBjK+aKXE!RxvSAcU@}QO0PBdk2l-BMxRw7{TA8`h#rN#X6#Cb1e7byH- zGW)}30UW%-TcXy}Lx45rgZMwy)Xy?@L4Zd&5v-GL8r|@AJ#=%R{!{Fq?-a+&zFOlq zS(BTC3iX)(KJ8kisTP)RL??* zJ%qj`Bxd#Asnq*qynnXR7$nk4AtLz7z0sgD7fIa(Vr*|Y8OSbh7vdZn_Y^7oH_01y z1;z&LuQ}b1x4vK{7g`)=Xwm+u7BfCcxZ3}Ni0<6Qn5L5ajjT?do-y(H0ick}A?0s* zFw*=aExl_|RjAtQ_qC19j0>{ql{UKXpwj$sS`_it^|$88E9IbQvF=!#_R-N8DGugKP-8i0&3P{(u=)A#E!@3Jj)1W$IN>*P2B6fZdl*#QNTt*o1TjROEPm%8Yt=An?cP5@M$vo9%lYQe8Nm$3 z;-qB5964cj+0ckEqx4^|#VP1amde_*B0uCFXZie}NFL(*XF+e&ZgHq>c$1eHuav3} zsjgX11}-`@;ed8v&cQfscv=rVmVZ+rTD}hn1ZHkCZ2rP+@3)(}D-fSakg|08ZbZ~I z=+Mm3Qu@NL4XFBbxIV#I_8Al|@M5QOa`TcWvJ(Hiaxoy- z#X$5Wu!RcQ06Z(sO7z*%TPo2K!>oC>H>{H2}@r1K#Lb5zj)e3Ui*8z2Rbnz5|+}lbm>NIO`O(c}bGKjcqtX<8h*r@fOk}+}O%9+^N!mdGVHTNzHi! z=mz`t;5j(cqMC85XJ7S}KlbtsYj+7mG&XHZBW19G8mTs9>Obrb$kj;Uj%E6YkimC{ zckeh&#dzjp=M3cUgG6(Ts?6mPv*&VK@bA5!6gfpzph6-%+s}zIi+JLAytu_wp@ou1 zEhLKplIYx|A*4@22Ve=GWAbls5gj)B^C~e-sLKc^$F{Y>6}zxp4sU~_vvB0iY!P3X z%6YGtKsOx^>R4k!Ys67uuikq0O|g!-=7~R!wu!0Ad0J{0+tUO(0n}r?<^UHf8~e{w z3WmGbM7c$0SaQ08Rvb-BX4ezi9g=^B+3hQsBK$%{+1lpZIsI&H?-)Jc*`}hUAQAC5 zeP*7xnL|5HB5v1D(Q1!B>^CqaxZ_@_wi6z@Wm!g`9gASo<^dm^We^_hO45w0WJ6s9 zi8)|d>@69BpunPx;HOV?0|Q5#5ea%r66r_LOz?TNuztR^hi?}-6SLzFyVQHmf>9;Lc57GA?}61A48U-&8;ttA{wahHre)?$i9Zl;J!=Le}{I?`v=@X9$6cQktt0dTNz>|uAT zzT*}R?Cfax=C5Q&c!jHhU*jMF@fH;}Aov)P_9{wSHP|vPj{uw=y?ZdMVVKBD zhwKS^8lk+Q6EIBqpBCG%JSbj>!JCxtB>z0t!hq6D4zR#vLJtO%iZ6ej;eUluXVbLn ow8iK#$aVbfd&}BL!~^zh*;E + + + Group 2 + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/static/images/user.png b/public/static/images/user.png new file mode 100644 index 0000000000000000000000000000000000000000..27535961c89dfc30aea6292dd9bdff525dfd9d00 GIT binary patch literal 15135 zcmeI3e{dVc6~|W+nAjmrAWY4V(p;6MO#{-MBulmqNjR}W>=3DLtYEutvCpTqeMHio zrE?^E+QdNPhGtp_KO86_xcLKy^ao5}3?#$YEy=hIQz&tuC1etj$rNx(2rz+=Vw*il zme#VI4Ge$o&B%J*{l541KJV@7{<(W<{j27cTw4MFm{(KnU5mblwa*;%2gIMZy^X$# zmFmVA0CN{=A07Dpj;jHvSSAG;)CS)gUX;UTAt<*(b0Vy0Uchy8LJ`FEP-R+SyA*L7 zKioHDWTc?mSa0`nKBWqFNYy=2Sl8nZh&}5?XV7@Fr^J=uQGhU11tt*=MPhuyZA``G zk*y80MkXau*Sn3&wS-KAua>EjqmZ$i9VU@;lr!Z{v&CLsURHi1W92M%mb0-o&SbUm zWgK5-Wipr1Q-Um4G}y+k_1=<6hyHULJ5*KSSvDSzo8vaK9BpSUPN$RQtgO{)LJCu? zJE95+QzW)H9b_tw7skY>q^Ob{VYIkHtK6l!jYcg|_R8E>Sji@e#4_vNVB+UGikR}E2Jyr zLifs7MWLX|(SR(6Jn1g0okGY|Ri(O$S?Uu+DWY-xk&DfD%2hlU4|)X^dQe9?Oq|VR zwFfxVjyB$Ezk#dZISvbwR_4X<$w8^D8;ena!e}up<-Dy7kAW%kW1t-r6jb4&qTpIA zPEh3AJyKX`hpZB5cd@xaOquN~zDf?sQM4@RvAEbm!XSmM@?UltYZNFqf2ft!y z%zZ}aA4es0)(Ig@qpkj{rYI0*MyhHlhB~wx>s-{osne_uc1|Cing~g$Q%Mn`F{tf1 zw{dFIWskA!DW&-T@;Q+ED3G zDb?&jVse`r7ou=^JL-vx+wJMN(;f2@xLEBMAS6vMMS664g{FFTW<_1v!N#L*Kr0hc zRX`0sV=R|Bt#8n(8tO{v%dH%`Sc~>Iad1p&cC4`qJV=sZvh)GX*^xXZ6HpGM?#TVL$4r zTBb+QBLjL`VY81b)61OQ4BxPkyQOb9FdmL3!D$d}ii?N{7f@U{4WdnP5fR}6iVLSf zv?(qkB3wXm;WUUg#YIGf3n(s}2GORth=_0j#f8%#+7uTN5iX#(a2iCL;vyo#1r!%f zgJ@G+L`1lN;=*YVZHkMC2p3RXI1QpraS;*W0*VW#L9{6@A|hNsap5$GHpN9mgbOGx zoCeXRxQK{w0mX&WAleic5fLt+xNsUoo8lrO!UYr;PJ?JuTtq~;fa1bw5N(Q!hzJ)@ zTsRG)O>q$s;R1>ar$MwSE+QgaKyl$Ti1r0>mE>Lkgc0=CUmU&OxBbk{m(i<%j99(a z2SCpf0DA8R;PXlJ{XPI)8~|f20Pqh3P%7WweBc%U^m2`Nc_4A*e@BGhoMaaCy>oQZ zznNLCztVdjqq{=hv#F^6=WXo^_Z?n#?%2X}{~C4IG&a>8E7D#-ytwOw-yM6s{?(DD z(&Wc|69>=TI(MMx*5hqeZ-6;{6OR<1(7ko&-nVYNPC2ycrb`V6{qv7(4Gf3h`^kU% zixWK?Z~yCH@{2#|9hKdk8;y1QbsKu#FwavCz2a}|UGwxSyTGUJ;nn&}#+LqF7Z^2g z>n|lFevLTOYVBr{5^1d?wJ+fiPDxJh>V^7wr$xhE$&e>y(*w-fcN&$4I7MwY!aR24018e6q> z?AQCwkDNNsRvd1&ygzhubkjd~PwZ-%+!$Q8(zEn+;^1620z>RpPm1{W4Qd22e#Kg^tiui@S!K)^HpqNlT@(Ls@lA@s_^6_7hxXSJ{&K5wPbEHIKOT_jR=1 zvnVOuvGY3a^DkbzbiQue6QxdFsp-8FhQPD>Goe3zbVYJt$@M?$U9p%1iLp>UQ9+ E1dk%0J^%m! literal 0 HcmV?d00001 diff --git a/public/static/images/west.ico b/public/static/images/west.ico new file mode 100644 index 0000000000000000000000000000000000000000..589df0883bc3366a8ea61fb7c508703cd51c6c54 GIT binary patch literal 1150 zcmV-^1cCdBP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1QSU_K~z{r&6Zni zR8w6^#{ zNQy{oYg4F~il9~t81Vry-o*!bGa*DYT7k?yW&mAeC!L?YX@f<%k z7R054N1JS!d%{IRkv@UwKn@LWMe-EhBpduUh`%9mZ@DxTnO;gkcmfTF>E_6rSU1|h zCF3^|c|f*5{H60pkea~ygUk5yHmu1uFmCvrIZ`e=NV23eq~PNN_*Ka#xYAsq^9Qz(cW&+dWPtjWSLXM^UVD6 zVH1dX6*T?`L~vO+M^<&;KbnBnD?&2OGIgtIT1oZZ+j+5Rq~KPTPKNoQ%<>xJYEfoG zI&bX}Jdu7Qs_K}=j6H>wrU7-1$7+5-qZ=91aHvk%Q?=AN39v&DhK{N;;^{?!aSPHD zFIGpTUFdq4RK+2hVV@}xCxBL*Xd6elytv*M5 zHRYzaLZM`F`$1<9;}5t>y4RhxE?BbjC}V9-K%icbuA1kqorKDr`5Z!nXeZi$ilW_S zZLqlg6`prk$A^lLVQ~^GV4o9M*d_WSq%yt9MMWxJE`im~6X~oujwT-t!Pg}gYj!0@ zyM}se1ML{jSMq2}+)0x0tn7bgyR${gUz)<74N33%3%+00Jc~2qFcv$gRHE(j;|AqB zX7Y1qrMLc!@0T^_p&h_VInI?VYD$*??Macm9W@^&qO@r`Uz$TD*9PPwtdzH+`>h*5 z>DI|K-j7vi1Br;xRTrV@=2UvRM;5+#x6@iIXv|>+9H2Zmpq&VN(YkpOfTuT5Rv6F* zIm8@@eGUK6#4fqG*NFdEsLt{_v>(X4jd}1E>{p4gRfTGy?o;y6hMTGRXTO1e#z(Noni*l1 z@>lR)-%ATsV7KB2qh>Z|5RW?sklxd)E-oG^!5y`0$fjdd+j z6EMiDp3QR$!*PubTrxE0UcG#=d*nL)zd?8p1d;prUG&6Su3b;!W!4)g|GIVvqeZ^m z_ni%fV{8=~%v^F6&q_F#WXz^@6TBLF@K1P}hQH?h3Dx$>_no5`nzRu48yYN+Y_t_( Qu>b%707*qoM6N<$f{1e;&j0`b literal 0 HcmV?d00001 diff --git a/public/static/js/app.js b/public/static/js/app.js new file mode 100644 index 0000000..b57645b --- /dev/null +++ b/public/static/js/app.js @@ -0,0 +1,738 @@ +/*! AdminLTE app.js +* ================ +* Main JS application file for AdminLTE v2. This file +* should be included in all pages. It controls some layout +* options and implements exclusive AdminLTE plugins. +* +* @author Colorlib +* @support +* @version v2.4.18 +* @repository git://github.com/ColorlibHQ/AdminLTE.git +* @license MIT +*/ + +// Make sure jQuery has been loaded +if (typeof jQuery === 'undefined') { +throw new Error('AdminLTE requires jQuery') +} + +/* ControlSidebar() + * =============== + * Toggles the state of the control sidebar + * + * @Usage: $('#control-sidebar-trigger').controlSidebar(options) + * or add [data-toggle="control-sidebar"] to the trigger + * Pass any option as data-option="value" + */ ++function ($) { + 'use strict'; + + var DataKey = 'lte.controlsidebar'; + + var Default = { + controlsidebarSlide: true + }; + + var Selector = { + sidebar: '.control-sidebar', + data : '[data-toggle="control-sidebar"]', + open : '.control-sidebar-open', + bg : '.control-sidebar-bg', + wrapper: '.wrapper', + content: '.content-wrapper', + boxed : '.layout-boxed' + }; + + var ClassName = { + open: 'control-sidebar-open', + transition: 'control-sidebar-hold-transition', + fixed: 'fixed' + }; + + var Event = { + collapsed: 'collapsed.controlsidebar', + expanded : 'expanded.controlsidebar' + }; + + // ControlSidebar Class Definition + // =============================== + var ControlSidebar = function (element, options) { + this.element = element; + this.options = options; + this.hasBindedResize = false; + + this.init(); + }; + + ControlSidebar.prototype.init = function () { + // Add click listener if the element hasn't been + // initialized using the data API + if (!$(this.element).is(Selector.data)) { + $(this).on('click', this.toggle); + } + + this.fix(); + $(window).resize(function () { + this.fix(); + }.bind(this)); + }; + + ControlSidebar.prototype.toggle = function (event) { + if (event) event.preventDefault(); + + this.fix(); + + if (!$(Selector.sidebar).is(Selector.open) && !$('body').is(Selector.open)) { + this.expand(); + } else { + this.collapse(); + } + }; + + ControlSidebar.prototype.expand = function () { + $(Selector.sidebar).show(); + if (!this.options.controlsidebarSlide) { + $('body').addClass(ClassName.transition).addClass(ClassName.open).delay(50).queue(function(){ + $('body').removeClass(ClassName.transition); + $(this).dequeue() + }) + } else { + $(Selector.sidebar).addClass(ClassName.open); + } + + + $(this.element).trigger($.Event(Event.expanded)); + }; + + ControlSidebar.prototype.collapse = function () { + if (!this.options.controlsidebarSlide) { + $('body').addClass(ClassName.transition).removeClass(ClassName.open).delay(50).queue(function(){ + $('body').removeClass(ClassName.transition); + $(this).dequeue() + }) + } else { + $(Selector.sidebar).removeClass(ClassName.open); + } + $(Selector.sidebar).fadeOut(); + $(this.element).trigger($.Event(Event.collapsed)); + }; + + ControlSidebar.prototype.fix = function () { + if ($('body').is(Selector.boxed)) { + this._fixForBoxed($(Selector.bg)); + } + }; + + // Private + + ControlSidebar.prototype._fixForBoxed = function (bg) { + bg.css({ + position: 'absolute', + height : $(Selector.wrapper).height() + }); + }; + + // Plugin Definition + // ================= + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DataKey); + + if (!data) { + var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option); + $this.data(DataKey, (data = new ControlSidebar($this, options))); + } + + if (typeof option == 'string') data.toggle(); + }); + } + + var old = $.fn.controlSidebar; + + $.fn.controlSidebar = Plugin; + $.fn.controlSidebar.Constructor = ControlSidebar; + + // No Conflict Mode + // ================ + $.fn.controlSidebar.noConflict = function () { + $.fn.controlSidebar = old; + return this; + }; + + // ControlSidebar Data API + // ======================= + $(document).on('click', Selector.data, function (event) { + if (event) event.preventDefault(); + Plugin.call($(this), 'toggle'); + }); + +}(jQuery); + + +/* PushMenu() + * ========== + * Adds the push menu functionality to the sidebar. + * + * @usage: $('.btn').pushMenu(options) + * or add [data-toggle="push-menu"] to any button + * Pass any option as data-option="value" + */ ++function ($) { + 'use strict'; + + var DataKey = 'lte.pushmenu'; + + var Default = { + collapseScreenSize : 767, + expandOnHover : false, + expandTransitionDelay: 200 + }; + + var Selector = { + collapsed : '.sidebar-collapse', + open : '.sidebar-open', + mainSidebar : '.main-sidebar', + contentWrapper: '.content-wrapper', + searchInput : '.sidebar-form .form-control', + button : '[data-toggle="push-menu"]', + mini : '.sidebar-mini', + expanded : '.sidebar-expanded-on-hover', + layoutFixed : '.fixed' + }; + + var ClassName = { + collapsed : 'sidebar-collapse', + open : 'sidebar-open', + mini : 'sidebar-mini', + expanded : 'sidebar-expanded-on-hover', + expandFeature: 'sidebar-mini-expand-feature', + layoutFixed : 'fixed' + }; + + var Event = { + expanded : 'expanded.pushMenu', + collapsed: 'collapsed.pushMenu' + }; + + // PushMenu Class Definition + // ========================= + var PushMenu = function (options) { + this.options = options; + this.init(); + }; + + PushMenu.prototype.init = function () { + if (this.options.expandOnHover + || ($('body').is(Selector.mini + Selector.layoutFixed))) { + this.expandOnHover(); + $('body').addClass(ClassName.expandFeature); + } + + $(Selector.contentWrapper).click(function () { + // Enable hide menu when clicking on the content-wrapper on small screens + if ($(window).width() <= this.options.collapseScreenSize && $('body').hasClass(ClassName.open)) { + this.close(); + } + }.bind(this)); + + // __Fix for android devices + $(Selector.searchInput).click(function (e) { + e.stopPropagation(); + }); + }; + + PushMenu.prototype.toggle = function () { + var windowWidth = $(window).width(); + var isOpen = !$('body').hasClass(ClassName.collapsed); + + if (windowWidth <= this.options.collapseScreenSize) { + isOpen = $('body').hasClass(ClassName.open); + } + + if (!isOpen) { + this.open(); + } else { + this.close(); + } + }; + + PushMenu.prototype.open = function () { + var windowWidth = $(window).width(); + + if (windowWidth > this.options.collapseScreenSize) { + $('body').removeClass(ClassName.collapsed) + .trigger($.Event(Event.expanded)); + } + else { + $('body').addClass(ClassName.open) + .trigger($.Event(Event.expanded)); + } + }; + + PushMenu.prototype.close = function () { + var windowWidth = $(window).width(); + if (windowWidth > this.options.collapseScreenSize) { + $('body').addClass(ClassName.collapsed) + .trigger($.Event(Event.collapsed)); + } else { + $('body').removeClass(ClassName.open + ' ' + ClassName.collapsed) + .trigger($.Event(Event.collapsed)); + } + }; + + PushMenu.prototype.expandOnHover = function () { + $(Selector.mainSidebar).hover(function () { + if ($('body').is(Selector.mini + Selector.collapsed) + && $(window).width() > this.options.collapseScreenSize) { + this.expand(); + } + }.bind(this), function () { + if ($('body').is(Selector.expanded)) { + this.collapse(); + } + }.bind(this)); + }; + + PushMenu.prototype.expand = function () { + setTimeout(function () { + $('body').removeClass(ClassName.collapsed) + .addClass(ClassName.expanded); + }, this.options.expandTransitionDelay); + }; + + PushMenu.prototype.collapse = function () { + setTimeout(function () { + $('body').removeClass(ClassName.expanded) + .addClass(ClassName.collapsed); + }, this.options.expandTransitionDelay); + }; + + // PushMenu Plugin Definition + // ========================== + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DataKey); + + if (!data) { + var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option); + $this.data(DataKey, (data = new PushMenu(options))); + } + + if (option === 'toggle') data.toggle(); + }); + } + + var old = $.fn.pushMenu; + + $.fn.pushMenu = Plugin; + $.fn.pushMenu.Constructor = PushMenu; + + // No Conflict Mode + // ================ + $.fn.pushMenu.noConflict = function () { + $.fn.pushMenu = old; + return this; + }; + + // Data API + // ======== + $(document).on('click', Selector.button, function (e) { + e.preventDefault(); + Plugin.call($(this), 'toggle'); + }); + $(window).on('load', function () { + Plugin.call($(Selector.button)); + }); +}(jQuery); + + +/* Tree() + * ====== + * Converts a nested list into a multilevel + * tree view menu. + * + * @Usage: $('.my-menu').tree(options) + * or add [data-widget="tree"] to the ul element + * Pass any option as data-option="value" + */ ++function ($) { + 'use strict'; + + var DataKey = 'lte.tree'; + + var Default = { + animationSpeed: 300, + accordion : true, + followLink : false, + trigger : '.treeview a' + }; + + var Selector = { + tree : '.tree', + treeview : '.treeview', + treeviewMenu: '.treeview-menu', + open : '.menu-open, .active', + li : 'li', + data : '[data-widget="tree"]', + active : '.active' + }; + + var ClassName = { + open: 'menu-open', + tree: 'tree' + }; + + var Event = { + collapsed: 'collapsed.tree', + expanded : 'expanded.tree' + }; + + // Tree Class Definition + // ===================== + var Tree = function (element, options) { + this.element = element; + this.options = options; + + $(this.element).addClass(ClassName.tree); + + $(Selector.treeview + Selector.active, this.element).addClass(ClassName.open); + + this._setUpListeners(); + }; + + Tree.prototype.toggle = function (link, event) { + var treeviewMenu = link.next(Selector.treeviewMenu); + var parentLi = link.parent(); + var isOpen = parentLi.hasClass(ClassName.open); + + if (!parentLi.is(Selector.treeview)) { + return; + } + + if (!this.options.followLink || link.attr('href') === '#') { + event.preventDefault(); + } + + if (isOpen) { + this.collapse(treeviewMenu, parentLi); + } else { + this.expand(treeviewMenu, parentLi); + } + }; + + Tree.prototype.expand = function (tree, parent) { + var expandedEvent = $.Event(Event.expanded); + + if (this.options.accordion) { + var openMenuLi = parent.siblings(Selector.open); + var openTree = openMenuLi.children(Selector.treeviewMenu); + this.collapse(openTree, openMenuLi); + } + + parent.addClass(ClassName.open); + tree.stop().slideDown(this.options.animationSpeed, function () { + $(this.element).trigger(expandedEvent); + parent.height('auto'); + }.bind(this)); + }; + + Tree.prototype.collapse = function (tree, parentLi) { + var collapsedEvent = $.Event(Event.collapsed); + + //tree.find(Selector.open).removeClass(ClassName.open); + parentLi.removeClass(ClassName.open); + tree.stop().slideUp(this.options.animationSpeed, function () { + //tree.find(Selector.open + ' > ' + Selector.treeview).slideUp(); + $(this.element).trigger(collapsedEvent); + + // Collapse child items + parentLi.find(Selector.treeview).removeClass(ClassName.open).find(Selector.treeviewMenu).hide(); + }.bind(this)); + }; + + // Private + + Tree.prototype._setUpListeners = function () { + var that = this; + + $(this.element).on('click', this.options.trigger, function (event) { + that.toggle($(this), event); + }); + }; + + // Plugin Definition + // ================= + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DataKey); + + if (!data) { + var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option); + $this.data(DataKey, new Tree($this, options)); + } + }); + } + + var old = $.fn.tree; + + $.fn.tree = Plugin; + $.fn.tree.Constructor = Tree; + + // No Conflict Mode + // ================ + $.fn.tree.noConflict = function () { + $.fn.tree = old; + return this; + }; + + // Tree Data API + // ============= + $(window).on('load', function () { + $(Selector.data).each(function () { + Plugin.call($(this)); + }); + }); + +}(jQuery); + + +/* Layout() + * ======== + * Implements AdminLTE layout. + * Fixes the layout height in case min-height fails. + * + * @usage activated automatically upon window load. + * Configure any options by passing data-option="value" + * to the body tag. + */ ++function ($) { + 'use strict'; + + var DataKey = 'lte.layout'; + + var Default = { + slimscroll : true, + resetHeight: true + }; + + var Selector = { + wrapper : '.wrapper', + contentWrapper: '.content-wrapper', + layoutBoxed : '.layout-boxed', + mainFooter : '.main-footer', + mainHeader : '.main-header', + mainSidebar : '.main-sidebar', + slimScrollDiv : 'slimScrollDiv', + sidebar : '.sidebar', + controlSidebar: '.control-sidebar', + fixed : '.fixed', + sidebarMenu : '.sidebar-menu', + logo : '.main-header .logo' + }; + + var ClassName = { + fixed : 'fixed', + holdTransition: 'hold-transition' + }; + + var Layout = function (options) { + this.options = options; + this.bindedResize = false; + this.activate(); + }; + + Layout.prototype.activate = function () { + this.fix(); + this.fixSidebar(); + + $('body').removeClass(ClassName.holdTransition); + + if (this.options.resetHeight) { + $('body, html, ' + Selector.wrapper).css({ + 'height' : 'auto', + 'min-height': '100%' + }); + } + + if (!this.bindedResize) { + $(window).resize(function () { + this.fix(); + this.fixSidebar(); + + $(Selector.logo + ', ' + Selector.sidebar).one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function () { + this.fix(); + this.fixSidebar(); + }.bind(this)); + }.bind(this)); + + this.bindedResize = true; + } + + $(Selector.sidebarMenu).on('expanded.tree', function () { + this.fix(); + this.fixSidebar(); + }.bind(this)); + + $(Selector.sidebarMenu).on('collapsed.tree', function () { + this.fix(); + this.fixSidebar(); + }.bind(this)); + }; + + Layout.prototype.fix = function () { + // Remove overflow from .wrapper if layout-boxed exists + $(Selector.layoutBoxed + ' > ' + Selector.wrapper).css('overflow', 'hidden'); + + // Get window height and the wrapper height + var footerHeight = $(Selector.mainFooter).outerHeight() || 0; + var headerHeight = $(Selector.mainHeader).outerHeight() || 0; + var neg = headerHeight + footerHeight; + var windowHeight = $(window).height(); + var sidebarHeight = $(Selector.sidebar).outerHeight() || 0; + + // Set the min-height of the content and sidebar based on + // the height of the document. + if ($('body').hasClass(ClassName.fixed)) { + $(Selector.contentWrapper).css('min-height', windowHeight - footerHeight); + } else { + var postSetHeight; + + if (windowHeight >= sidebarHeight + headerHeight) { + $(Selector.contentWrapper).css('min-height', windowHeight - neg); + postSetHeight = windowHeight - neg; + } else { + $(Selector.contentWrapper).css('min-height', sidebarHeight); + postSetHeight = sidebarHeight; + } + + // Fix for the control sidebar height + var $controlSidebar = $(Selector.controlSidebar); + if (typeof $controlSidebar !== 'undefined') { + if ($controlSidebar.height() > postSetHeight) + $(Selector.contentWrapper).css('min-height', $controlSidebar.height()); + } + } + }; + + Layout.prototype.fixSidebar = function () { + // Make sure the body tag has the .fixed class + if (!$('body').hasClass(ClassName.fixed)) { + if (typeof $.fn.slimScroll !== 'undefined') { + $(Selector.sidebar).slimScroll({ destroy: true }).height('auto'); + } + return; + } + + // Enable slimscroll for fixed layout + if (this.options.slimscroll) { + if (typeof $.fn.slimScroll !== 'undefined') { + // Destroy if it exists + // $(Selector.sidebar).slimScroll({ destroy: true }).height('auto') + + // Add slimscroll + if ($(Selector.mainSidebar).find(Selector.slimScrollDiv).length === 0) { + $(Selector.sidebar).slimScroll({ + height: ($(window).height() - $(Selector.mainHeader).height()) + 'px' + }); + } + } + } + }; + + // Plugin Definition + // ================= + function Plugin(option) { + return this.each(function () { + var $this = $(this); + var data = $this.data(DataKey); + + if (!data) { + var options = $.extend({}, Default, $this.data(), typeof option === 'object' && option); + $this.data(DataKey, (data = new Layout(options))); + } + + if (typeof option === 'string') { + if (typeof data[option] === 'undefined') { + throw new Error('No method named ' + option); + } + data[option](); + } + }); + } + + var old = $.fn.layout; + + $.fn.layout = Plugin; + $.fn.layout.Constuctor = Layout; + + // No conflict mode + // ================ + $.fn.layout.noConflict = function () { + $.fn.layout = old; + return this; + }; + + // Layout DATA-API + // =============== + $(window).on('load', function () { + Plugin.call($('body')); + }); +}(jQuery); + +//全屏事件 +$(document).on('click', "[data-toggle='fullscreen']", function () { + var doc = document.documentElement; + if ($(document.body).hasClass("full-screen")) { + $(document.body).removeClass("full-screen"); + document.exitFullscreen ? document.exitFullscreen() : document.mozCancelFullScreen ? document.mozCancelFullScreen() : document.webkitExitFullscreen && document.webkitExitFullscreen(); + } else { + $(document.body).addClass("full-screen"); + doc.requestFullscreen ? doc.requestFullscreen() : doc.mozRequestFullScreen ? doc.mozRequestFullScreen() : doc.webkitRequestFullscreen ? doc.webkitRequestFullscreen() : doc.msRequestFullscreen && doc.msRequestFullscreen(); + } +}); + +var my_skins = [ + "skin-blue", + "skin-black", + "skin-red", + "skin-yellow", + "skin-purple", + "skin-green", + "skin-blue-light", + "skin-black-light", + "skin-red-light", + "skin-yellow-light", + "skin-purple-light", + "skin-green-light", + "skin-black-blue", + "skin-black-purple", + "skin-black-red", + "skin-black-green", + "skin-black-yellow", + "skin-black-pink", +]; + +// 皮肤切换 +$("[data-skin]").on('click', function (e) { + var skin = $(this).data('skin'); + if (!$("body").hasClass(skin)) { + $("body").removeClass(my_skins.join(' ')).addClass(skin); + var cssfile = "/static/css/skins/" + skin + ".css"; + $('head').append(''); + $(".skin-list li.active").removeClass("active"); + $(".skin-list li a[data-skin='" + skin + "']").parent().addClass("active"); + $.ajax({ + type : "POST", + url : "/changeskin", + data : {skin:skin}, + dataType : 'json', + async: true, + success : function(data) { + } + }); + } + return false; +}); \ No newline at end of file diff --git a/public/static/js/bootstrapValidator.min.js b/public/static/js/bootstrapValidator.min.js new file mode 100644 index 0000000..4b4112a --- /dev/null +++ b/public/static/js/bootstrapValidator.min.js @@ -0,0 +1 @@ +if("undefined"==typeof jQuery)throw new Error("BootstrapValidator requires jQuery");!function(){var t=window.jQuery.fn.jquery.split(" ")[0].split(".");if(+t[0]<2&&+t[1]<9||1==+t[0]&&9==+t[1]&&+t[2]<1)throw new Error("BootstrapValidator requires jQuery version 1.9.1 or higher")}(),function(V){function s(t,e){this.$form=V(t),this.options=V.extend({},V.fn.bootstrapValidator.DEFAULT_OPTIONS,e),this.$invalidFields=V([]),this.$submitButton=null,this.$hiddenButton=null,this.STATUS_NOT_VALIDATED="NOT_VALIDATED",this.STATUS_VALIDATING="VALIDATING",this.STATUS_INVALID="INVALID",this.STATUS_VALID="VALID",t=function(){for(var t=3,e=document.createElement("div"),a=e.all||[];e.innerHTML="\x3c!--[if gt IE "+ ++t+"]>
    ").attr("type","submit").prependTo(this.$form).addClass("bv-hidden-submit").css({display:"none",width:0,height:0}),this.$form.on("click.bv",'[type="submit"]',function(t){t.isDefaultPrevented()||(t=((t=V(t.target)).is('[type="submit"]')?t:t.parent('[type="submit"]')).eq(0),!i.options.submitButtons)||t.is(i.options.submitButtons)||t.is(i.$hiddenButton)||i.$form.off("submit.bv").submit()}),this.options.fields)this._initField(t);this.$form.trigger(V.Event(this.options.events.formInit),{bv:this,options:this.options}),this.options.onSuccess&&this.$form.on(this.options.events.formSuccess,function(t){V.fn.bootstrapValidator.helpers.call(i.options.onSuccess,[t])}),this.options.onError&&this.$form.on(this.options.events.formError,function(t){V.fn.bootstrapValidator.helpers.call(i.options.onError,[t])})},_parseOptions:function(t){var e,a,i,s,o,r,n,l,d,f=t.attr("name")||t.attr("data-bv-field"),u={};for(a in V.fn.bootstrapValidator.validators)if(e=V.fn.bootstrapValidator.validators[a],i="data-bv-"+a.toLowerCase(),s=t.attr(i)+"",(d="function"==typeof e.enableByHtml5?e.enableByHtml5(t):null)&&"false"!==s||!0!==d&&(""===s||"true"===s||i===s.toLowerCase()))for(l in e.html5Attributes=V.extend({},{message:"message",onerror:"onError",onsuccess:"onSuccess"},e.html5Attributes),u[a]=V.extend({},!0===d?{}:d,u[a]),e.html5Attributes)o=e.html5Attributes[l],r="data-bv-"+a.toLowerCase()+"-"+l,(n=t.attr(r))&&("true"===n||r===n.toLowerCase()?n=!0:"false"===n&&(n=!1),u[a][o]=n);var h={autoFocus:t.attr("data-bv-autofocus"),container:t.attr("data-bv-container"),excluded:t.attr("data-bv-excluded"),feedbackIcons:t.attr("data-bv-feedbackicons"),group:t.attr("data-bv-group"),message:t.attr("data-bv-message"),onError:t.attr("data-bv-onerror"),onStatus:t.attr("data-bv-onstatus"),onSuccess:t.attr("data-bv-onsuccess"),selector:t.attr("data-bv-selector"),threshold:t.attr("data-bv-threshold"),trigger:t.attr("data-bv-trigger"),verbose:t.attr("data-bv-verbose"),validators:u},p=V.isEmptyObject(h);return!V.isEmptyObject(u)||!p&&this.options.fields&&this.options.fields[f]?(h.validators=u,h):null},_initField:function(t){var e,a=V([]);switch(typeof t){case"object":t=(a=t).attr("data-bv-field");break;case"string":(a=this.getFieldElements(t)).attr("data-bv-field",t)}if(0!==a.length&&null!==this.options.fields[t]&&null!==this.options.fields[t].validators){for(e in this.options.fields[t].validators)V.fn.bootstrapValidator.validators[e]||delete this.options.fields[t].validators[e];null===this.options.fields[t].enabled&&(this.options.fields[t].enabled=!0);for(var i=this,s=a.length,o=a.attr("type"),r=1===s||"radio"===o||"checkbox"===o,n="radio"===o||"checkbox"===o||"file"===o||"SELECT"===a.eq(0).get(0).tagName?"change":this._changeEvent,n=(this.options.fields[t].trigger||this.options.trigger||n).split(" "),l=V.map(n,function(t){return t+".update.bv"}).join(" "),d=0;d").css("display","none").addClass("help-block").attr("data-bv-validator",e).attr("data-bv-for",t).attr("data-bv-result",this.STATUS_NOT_VALIDATED).html(this._getMessage(t,e)).appendTo(c),"function"==typeof V.fn.bootstrapValidator.validators[e].init&&V.fn.bootstrapValidator.validators[e].init(this,u,this.options.fields[t].validators[e]);!1!==this.options.fields[t].feedbackIcons&&"false"!==this.options.fields[t].feedbackIcons&&this.options.feedbackIcons&&this.options.feedbackIcons.validating&&this.options.feedbackIcons.invalid&&this.options.feedbackIcons.valid&&(!r||d===s-1)&&(p.addClass("has-feedback"),h=V("").css("display","none").addClass("form-control-feedback").attr("data-bv-icon-for",t).insertAfter(u),"checkbox"!==o&&"radio"!==o||((f=u.parent()).hasClass(o)?h.insertAfter(f):f.parent().hasClass(o)&&h.insertAfter(f.parent())),0===p.find("label").length&&h.addClass("bv-no-label"),0!==p.find(".input-group").length&&h.addClass("bv-icon-input-group").insertAfter(p.find(".input-group").eq(0)),r?d===s-1&&a.data("bv.icon",h):u.data("bv.icon",h),v)&&u.off("focus.container.bv").on("focus.container.bv",function(){switch(v){case"tooltip":V(this).data("bv.icon").tooltip("show");break;case"popover":V(this).data("bv.icon").popover("show")}}).off("blur.container.bv").on("blur.container.bv",function(){switch(v){case"tooltip":V(this).data("bv.icon").tooltip("hide");break;case"popover":V(this).data("bv.icon").popover("hide")}})}switch(a.on(this.options.events.fieldSuccess,function(t,e){var a=i.getOptions(e.field,null,"onSuccess");a&&V.fn.bootstrapValidator.helpers.call(a,[t,e])}).on(this.options.events.fieldError,function(t,e){var a=i.getOptions(e.field,null,"onError");a&&V.fn.bootstrapValidator.helpers.call(a,[t,e])}).on(this.options.events.fieldStatus,function(t,e){var a=i.getOptions(e.field,null,"onStatus");a&&V.fn.bootstrapValidator.helpers.call(a,[t,e])}).on(this.options.events.validatorError,function(t,e){var a=i.getOptions(e.field,e.validator,"onError");a&&V.fn.bootstrapValidator.helpers.call(a,[t,e])}).on(this.options.events.validatorSuccess,function(t,e){var a=i.getOptions(e.field,e.validator,"onSuccess");a&&V.fn.bootstrapValidator.helpers.call(a,[t,e])}),l=V.map(n,function(t){return t+".live.bv"}).join(" "),this.options.live){case"submitted":break;case"disabled":a.off(l);break;default:a.off(l).on(l,function(){i._exceedThreshold(V(this))&&i.validateField(V(this))})}a.trigger(V.Event(this.options.events.fieldInit),{bv:this,field:t,element:a})}},_getMessage:function(t,e){if(!(this.options.fields[t]&&V.fn.bootstrapValidator.validators[e]&&this.options.fields[t].validators&&this.options.fields[t].validators[e]))return"";var a=this.options.fields[t].validators[e];switch(!0){case!!a.message:return a.message;case!!this.options.fields[t].message:return this.options.fields[t].message;case!!V.fn.bootstrapValidator.i18n[e]:return V.fn.bootstrapValidator.i18n[e].default;default:return this.options.message}},_getMessageContainer:function(t,e){var a=t.parent();if(a.is(e))return a;var i=a.attr("class");if(i)for(var s=(i=i.split(" ")).length,o=0;o=e},_onError:function(t){if(!t.isDefaultPrevented()){if("submitted"===this.options.live){this.options.live="enabled";var e,a=this;for(e in this.options.fields)i=e,s=void 0,(i=a.getFieldElements(i)).length&&(s="radio"===(s=V(i[0]).attr("type"))||"checkbox"===s||"file"===s||"SELECT"===V(i[0]).get(0).tagName?"change":a._changeEvent,s=a.options.fields[e].trigger||a.options.trigger||s,s=V.map(s.split(" "),function(t){return t+".live.bv"}).join(" "),i.off(s).on(s,function(){a._exceedThreshold(V(this))&&a.validateField(V(this))}))}for(var i,s,o=0;o").attr("type","hidden").attr("data-bv-submit-hidden","").attr("name",this.$submitButton.attr("name")).val(this.$submitButton.val()).appendTo(this.$form),this.$form.off("submit.bv").submit()},getInvalidFields:function(){return this.$invalidFields},getSubmitButton:function(){return this.$submitButton},getMessages:function(t,e){var a=this,i=[],s=V([]);switch(!0){case t&&"object"==typeof t:s=t;break;case t&&"string"==typeof t:var o,r=this.getFieldElements(t);0parseInt(o,10))&&(t=!1),!0){case!!s&&!!o:r=n.fn.bootstrapValidator.helpers.format(a.message||n.fn.bootstrapValidator.i18n.choice.between,[parseInt(s,10),parseInt(o,10)]);break;case!!s:r=n.fn.bootstrapValidator.helpers.format(a.message||n.fn.bootstrapValidator.i18n.choice.less,parseInt(s,10));break;case!!o:r=n.fn.bootstrapValidator.helpers.format(a.message||n.fn.bootstrapValidator.i18n.choice.more,parseInt(o,10))}return{valid:t,message:r}}}}(window.jQuery),function(l){l.fn.bootstrapValidator.i18n.color=l.extend(l.fn.bootstrapValidator.i18n.color||{},{default:"Please enter a valid color"}),l.fn.bootstrapValidator.validators.color={SUPPORTED_TYPES:["hex","rgb","rgba","hsl","hsla","keyword"],KEYWORD_COLORS:["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","green","greenyellow","grey","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","transparent","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"],validate:function(t,e,a){var i=e.val();if(""===i)return!0;var s=a.type||this.SUPPORTED_TYPES;l.isArray(s)||(s=s.replace(/s/g,"").split(","));for(var o,r=!1,n=0;n=m.getTime(),b=a.message||y.fn.bootstrapValidator.helpers.format(y.fn.bootstrapValidator.i18n.date.min,V);break;case A&&!V&&c:c=l.getTime()<=g.getTime(),b=a.message||y.fn.bootstrapValidator.helpers.format(y.fn.bootstrapValidator.i18n.date.max,A);break;case A&&V&&c:c=l.getTime()<=g.getTime()&&l.getTime()>=m.getTime(),b=a.message||y.fn.bootstrapValidator.helpers.format(y.fn.bootstrapValidator.i18n.date.range,[V,A])}return{valid:c,message:b}},_parseDate:function(t,e,a){var i=0,s=0,o=0,t=t.split(" "),r=t[0],t=1()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;if(!0!==a.multiple&&"true"!==a.multiple)return i.test(e);for(var a=a.separator||/[,;]/,s=this._splitEmailAddresses(e,a),o=0;oparseInt(a.maxFiles,10)||a.minFiles&&lparseInt(a.maxSize,10)||o&&-1===u.inArray(s.toLowerCase(),o)||n[f].type&&r&&-1===u.inArray(n[f].type.toLowerCase(),r))return!1;if(a.maxTotalSize&&d>parseInt(a.maxTotalSize,10)||a.minTotalSize&&dparseInt(o,10))&&(e=!1),!0){case!!s&&!!o:r=n.fn.bootstrapValidator.helpers.format(a.message||n.fn.bootstrapValidator.i18n.stringLength.between,[parseInt(s,10),parseInt(o,10)]);break;case!!s:r=n.fn.bootstrapValidator.helpers.format(a.message||n.fn.bootstrapValidator.i18n.stringLength.more,parseInt(s,10));break;case!!o:r=n.fn.bootstrapValidator.helpers.format(a.message||n.fn.bootstrapValidator.i18n.stringLength.less,parseInt(o,10))}return{valid:e,message:r}}}}(window.jQuery),function(t){t.fn.bootstrapValidator.i18n.uri=t.extend(t.fn.bootstrapValidator.i18n.uri||{},{default:"Please enter a valid URI"}),t.fn.bootstrapValidator.validators.uri={html5Attributes:{message:"message",allowlocal:"allowLocal",protocol:"protocol"},enableByHtml5:function(t){return"url"===t.attr("type")},validate:function(t,e,a){var i,e=e.val();return""===e||(i=!0===a.allowLocal||"true"===a.allowLocal,a=(a.protocol||"http, https, ftp").split(",").join("|").replace(/\s/g,""),new RegExp("^(?:(?:"+a+")://)(?:\\S+(?::\\S*)?@)?(?:"+(i?"":"(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})")+"(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))"+(i?"?":"")+")(?::\\d{2,5})?(?:/[^\\s]*)?$","i").test(e))}}}(window.jQuery),function(o){o.fn.bootstrapValidator.i18n.uuid=o.extend(o.fn.bootstrapValidator.i18n.uuid||{},{default:"Please enter a valid UUID number",version:"Please enter a valid UUID version %s number"}),o.fn.bootstrapValidator.validators.uuid={html5Attributes:{message:"message",version:"version"},validate:function(t,e,a){var i,s,e=e.val();return""===e||{valid:null===(i={3:/^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,4:/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,5:/^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,all:/^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i})[s=a.version?a.version+"":"all"]||i[s].test(e),message:a.version?o.fn.bootstrapValidator.helpers.format(a.message||o.fn.bootstrapValidator.i18n.uuid.version,a.version):a.message||o.fn.bootstrapValidator.i18n.uuid.default}}}}(window.jQuery),function(t){t.fn.bootstrapValidator.i18n=t.extend(!0,t.fn.bootstrapValidator.i18n,{base64:{default:"请输入有效的Base64编码"},between:{default:"请输入在 %s 和 %s 之间的数值",notInclusive:"请输入在 %s 和 %s 之间(不含两端)的数值"},callback:{default:"请输入有效的值"},choice:{default:"请输入有效的值",less:"请至少选中 %s 个选项",more:"最多只能选中 %s 个选项",between:"请选择 %s 至 %s 个选项"},color:{default:"请输入有效的颜色值"},date:{default:"请输入有效的日期",min:"请输入 %s 或之后的日期",max:"请输入 %s 或以前的日期",range:"请输入 %s 和 %s 之间的日期"},different:{default:"请输入不同的值"},digits:{default:"请输入有效的数字"},emailAddress:{default:"请输入有效的邮件地址"},file:{default:"请选择有效的文件"},greaterThan:{default:"请输入大于等于 %s 的数值",notInclusive:"请输入大于 %s 的数值"},hex:{default:"请输入有效的16进制数"},hexColor:{default:"请输入有效的16进制颜色值"},id:{default:"请输入有效的身份证号码"},identical:{default:"请输入相同的值"},integer:{default:"请输入有效的整数值"},ip:{default:"请输入有效的IP地址",ipv4:"请输入有效的IPv4地址",ipv6:"请输入有效的IPv6地址"},lessThan:{default:"请输入小于等于 %s 的数值",notInclusive:"请输入小于 %s 的数值"},mac:{default:"请输入有效的MAC物理地址"},notEmpty:{default:"请填写必填项目"},numeric:{default:"请输入有效的数值,允许小数"},phone:{default:"请输入有效的手机号码"},regexp:{default:"请输入符合正则表达式限制的值"},step:{default:"请输入在基础值上,增加 %s 的整数倍的数值"},stringCase:{default:"只能输入小写字母",upper:"只能输入大写字母"},stringLength:{default:"请输入符合长度限制的值",less:"最多只能输入 %s 个字符",more:"需要输入至少 %s 个字符",between:"请输入 %s 至 %s 个字符"},uri:{default:"请输入一个有效的URL地址"},uuid:{default:"请输入有效的UUID",version:"请输入版本 %s 的UUID"}})}(window.jQuery); \ No newline at end of file diff --git a/public/static/js/custom.js b/public/static/js/custom.js new file mode 100644 index 0000000..59be541 --- /dev/null +++ b/public/static/js/custom.js @@ -0,0 +1,133 @@ +var location_url = window.location.href; +var parameter_str = location_url.split('?')[1]; +if (parameter_str !== undefined) { + parameter_str = parameter_str.split('#')[0]; + var $_GET = {}; + var parameter_arr = parameter_str.split('&'); + var tmp_arr; + for (var i = 0, len = parameter_arr.length; i <= len - 1; i++) { + tmp_arr = parameter_arr[i].split('='); + $_GET[tmp_arr[0]] = decodeURIComponent(tmp_arr[1]); + } + window.$_GET = $_GET; +} else { + window.$_GET = []; +} + +function searchSubmit(){ + $('#listTable').bootstrapTable('refresh'); + return false; +} +function searchClear(){ + $('#searchToolbar').find('input[name]').each(function() { + $(this).val(''); + }); + $('#searchToolbar').find('select[name]').each(function() { + $(this).find('option:first').prop("selected", 'selected'); + }); + $('#listTable').bootstrapTable('refresh'); +} +function updateToolbar(){ + $('#searchToolbar').find(':input[name]').each(function() { + var name = $(this).attr('name'); + if(typeof window.$_GET[name] != 'undefined') + $(this).val(window.$_GET[name]); + }) +} +function updateQueryStr(obj){ + var arr = []; + for (var p in obj){ + if (obj.hasOwnProperty(p) && typeof obj[p] != 'undefined' && obj[p] != '') { + arr.push(p + "=" + encodeURIComponent(obj[p])); + } + } + history.replaceState({}, null, '?'+arr.join("&")); +} + +if (typeof $.fn.bootstrapTable !== "undefined") { + $.fn.bootstrapTable.custom = { + method: 'post', + contentType: "application/x-www-form-urlencoded", + sortable: true, + pagination: true, + sidePagination: 'server', + pageNumber: 1, + pageSize: 20, + pageList: [10, 15, 20, 30, 50, 100], + loadingFontSize: '18px', + toolbar: '#searchToolbar', + showColumns: true, + minimumCountColumns: 2, + showToggle: true, + showFullscreen: true, + paginationPreText: '前页', + paginationNextText: '后页', + showJumpTo: true, + paginationLoop: false, + queryParamsType: '', + queryParams: function(params) { + $('#searchToolbar').find(':input[name]').each(function() { + params[$(this).attr('name')] = $(this).val() + }) + updateQueryStr(params); + params.offset = params.pageSize * (params.pageNumber-1); + params.limit = params.pageSize; + return params; + }, + formatLoadingMessage: function(){ + return ''; + }, + formatShowingRows: function(t,n,r,e){ + return '显示第 '+t+' 到第 '+n+' 条, 总共 '+r+' 条'; + }, + formatRecordsPerPage: function(t){ + return '每页显示 '+t+' 条'; + }, + formatNoMatches: function(){ + return '没有找到匹配的记录'; + } + }; + $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.custom); +} + +function httpGet(url, callback){ + $.ajax({ + url: url, + type: 'get', + dataType: 'json', + success: function (res) { + callback(res) + }, + error: function () { + if (typeof layer !== "undefined") { + layer.closeAll(); + layer.msg('服务器错误'); + } + } + }); +} + +function httpPost(url, data, callback){ + $.ajax({ + url: url, + type: 'post', + data: data, + dataType: 'json', + success: function (res) { + callback(res) + }, + error: function () { + if (typeof layer !== "undefined") { + layer.closeAll(); + layer.msg('服务器错误'); + } + } + }); +} + +var isMobile = function(){ + if( /Android|SymbianOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Windows Phone|Midp/i.test(navigator.userAgent)) { + return true; + } + return false; +} \ No newline at end of file diff --git a/route/app.php b/route/app.php new file mode 100644 index 0000000..b32b677 --- /dev/null +++ b/route/app.php @@ -0,0 +1,78 @@ + +// +---------------------------------------------------------------------- +use think\facade\Route; + +Route::pattern([ + 'id' => '\d+', +]); + +Route::any('/install', 'install/index') +->middleware(\app\middleware\ViewOutput::class); + +Route::get('/verifycode', 'auth/verifycode')->middleware(\think\middleware\SessionInit::class) +->middleware(\app\middleware\ViewOutput::class); +Route::any('/login', 'auth/login')->middleware(\think\middleware\SessionInit::class) +->middleware(\app\middleware\ViewOutput::class); +Route::get('/logout', 'auth/logout'); +Route::any('/quicklogin', 'auth/quicklogin'); + +Route::group(function () { + Route::any('/', 'index/index'); + Route::post('/changeskin', 'index/changeskin'); + Route::get('/cleancache', 'index/cleancache'); + Route::any('/setpwd', 'index/setpwd'); + + Route::post('/user/data', 'user/user_data'); + Route::post('/user/op', 'user/user_op'); + Route::get('/user', 'user/user'); + + Route::post('/log/data', 'user/log_data'); + Route::get('/log', 'user/log'); + + Route::post('/account/data', 'domain/account_data'); + Route::post('/account/op', 'domain/account_op'); + Route::get('/account', 'domain/account'); + + Route::post('/domain/data', 'domain/domain_data'); + Route::post('/domain/op', 'domain/domain_op'); + Route::post('/domain/list', 'domain/domain_list'); + Route::get('/domain', 'domain/domain'); + + Route::post('/record/data/:id', 'domain/record_data'); + Route::post('/record/add/:id', 'domain/record_add'); + Route::post('/record/update/:id', 'domain/record_update'); + Route::post('/record/delete/:id', 'domain/record_delete'); + Route::post('/record/status/:id', 'domain/record_status'); + Route::post('/record/remark/:id', 'domain/record_remark'); + Route::post('/record/batch/:id', 'domain/record_batch'); + Route::any('/record/log/:id', 'domain/record_log'); + Route::get('/record/:id', 'domain/record'); + +})->middleware(\app\middleware\CheckLogin::class) +->middleware(\app\middleware\ViewOutput::class); + +Route::group('api', function () { + Route::post('/domain/:id', 'domain/domain_info'); + Route::post('/domain', 'domain/domain_data'); + + Route::post('/record/data/:id', 'domain/record_data'); + Route::post('/record/add/:id', 'domain/record_add'); + Route::post('/record/update/:id', 'domain/record_update'); + Route::post('/record/delete/:id', 'domain/record_delete'); + Route::post('/record/status/:id', 'domain/record_status'); + Route::post('/record/remark/:id', 'domain/record_remark'); + Route::post('/record/batch/:id', 'domain/record_batch'); + +})->middleware(\app\middleware\AuthApi::class); + +Route::miss(function() { + return response('404 Not Found')->code(404); +}); diff --git a/runtime/.gitignore b/runtime/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/runtime/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/think b/think new file mode 100644 index 0000000..2429d22 --- /dev/null +++ b/think @@ -0,0 +1,10 @@ +#!/usr/bin/env php +console->run(); \ No newline at end of file