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 0000000..0d0c2ae Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..e3c0fe9 --- /dev/null +++ b/public/index.php @@ -0,0 +1,24 @@ + +// +---------------------------------------------------------------------- + +// [ 应用入口文件 ] +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 0000000..a566910 Binary files /dev/null and b/public/static/images/aliyun.ico differ diff --git a/public/static/images/baidu.ico b/public/static/images/baidu.ico new file mode 100644 index 0000000..32070ff Binary files /dev/null and b/public/static/images/baidu.ico differ diff --git a/public/static/images/cloudflare.ico b/public/static/images/cloudflare.ico new file mode 100644 index 0000000..3c17430 Binary files /dev/null and b/public/static/images/cloudflare.ico differ diff --git a/public/static/images/dnspod.ico b/public/static/images/dnspod.ico new file mode 100644 index 0000000..362fa8b Binary files /dev/null and b/public/static/images/dnspod.ico differ diff --git a/public/static/images/error.svg b/public/static/images/error.svg new file mode 100644 index 0000000..d422a34 --- /dev/null +++ b/public/static/images/error.svg @@ -0,0 +1,22 @@ + + + + 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 0000000..32085d8 Binary files /dev/null and b/public/static/images/huawei.ico differ 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 0000000..544958c Binary files /dev/null and b/public/static/images/login-head.png differ diff --git a/public/static/images/logo.png b/public/static/images/logo.png new file mode 100644 index 0000000..f5157ac Binary files /dev/null and b/public/static/images/logo.png differ diff --git a/public/static/images/success.svg b/public/static/images/success.svg new file mode 100644 index 0000000..1c2d586 --- /dev/null +++ b/public/static/images/success.svg @@ -0,0 +1,18 @@ + + + + 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 0000000..2753596 Binary files /dev/null and b/public/static/images/user.png differ diff --git a/public/static/images/west.ico b/public/static/images/west.ico new file mode 100644 index 0000000..589df08 Binary files /dev/null and b/public/static/images/west.ico differ 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