Initial
19
.example.env
Normal file
|
@ -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
|
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/.idea
|
||||
/.vscode
|
||||
/vendor
|
||||
*.log
|
||||
.env
|
72
README.md
Normal file
|
@ -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
|
||||
|
||||
```
|
||||
<IfModule mod_rewrite.c>
|
||||
Options +FollowSymlinks -Multiviews
|
||||
RewriteEngine On
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
|
||||
</IfModule>
|
||||
```
|
||||
|
||||
### 版权信息
|
||||
|
||||
版权所有Copyright © 2023~2024 by 消失的彩虹海(https://blog.cccyun.cn)
|
||||
|
||||
### 其他推荐
|
||||
|
||||
- [彩虹云主机 - 免备案CDN/虚拟主机](https://www.cccyun.net/)
|
||||
- [小白云高防云服务器](https://www.xiaobaiyun.cn/aff/GMLPMFOV)
|
||||
|
1
app/.htaccess
Normal file
|
@ -0,0 +1 @@
|
|||
deny from all
|
22
app/AppService.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app;
|
||||
|
||||
use think\Service;
|
||||
|
||||
/**
|
||||
* 应用服务类
|
||||
*/
|
||||
class AppService extends Service
|
||||
{
|
||||
public function register()
|
||||
{
|
||||
// 服务注册
|
||||
}
|
||||
|
||||
public function boot()
|
||||
{
|
||||
// 服务启动
|
||||
}
|
||||
}
|
122
app/BaseController.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app;
|
||||
|
||||
use think\App;
|
||||
use think\exception\ValidateException;
|
||||
use think\Validate;
|
||||
use think\facade\View;
|
||||
|
||||
/**
|
||||
* 控制器基础类
|
||||
*/
|
||||
abstract class BaseController
|
||||
{
|
||||
/**
|
||||
* Request实例
|
||||
* @var \think\Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* 应用实例
|
||||
* @var \think\App
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* 是否批量验证
|
||||
* @var bool
|
||||
*/
|
||||
protected $batchValidate = false;
|
||||
|
||||
/**
|
||||
* 控制器中间件
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [];
|
||||
|
||||
protected $clientip;
|
||||
|
||||
/**
|
||||
* 构造方法
|
||||
* @access public
|
||||
* @param App $app 应用对象
|
||||
*/
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->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');
|
||||
}
|
||||
}
|
58
app/ExceptionHandle.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
namespace app;
|
||||
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
use think\exception\Handle;
|
||||
use think\exception\HttpException;
|
||||
use think\exception\HttpResponseException;
|
||||
use think\exception\ValidateException;
|
||||
use think\Response;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* 应用异常处理类
|
||||
*/
|
||||
class ExceptionHandle extends Handle
|
||||
{
|
||||
/**
|
||||
* 不需要记录信息(日志)的异常类列表
|
||||
* @var array
|
||||
*/
|
||||
protected $ignoreReport = [
|
||||
HttpException::class,
|
||||
HttpResponseException::class,
|
||||
ModelNotFoundException::class,
|
||||
DataNotFoundException::class,
|
||||
ValidateException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* 记录异常信息(包括日志或者其它方式记录)
|
||||
*
|
||||
* @access public
|
||||
* @param Throwable $exception
|
||||
* @return void
|
||||
*/
|
||||
public function report(Throwable $exception): void
|
||||
{
|
||||
// 使用内置的方式记录异常日志
|
||||
parent::report($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
*
|
||||
* @access public
|
||||
* @param \think\Request $request
|
||||
* @param Throwable $e
|
||||
* @return Response
|
||||
*/
|
||||
public function render($request, Throwable $e): Response
|
||||
{
|
||||
// 添加自定义异常处理机制
|
||||
|
||||
// 其他错误交给系统处理
|
||||
return parent::render($request, $e);
|
||||
}
|
||||
}
|
8
app/Request.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
namespace app;
|
||||
|
||||
// 应用请求对象类
|
||||
class Request extends \think\Request
|
||||
{
|
||||
|
||||
}
|
210
app/common.php
Normal file
|
@ -0,0 +1,210 @@
|
|||
<?php
|
||||
// 应用公共文件
|
||||
use think\facade\Db;
|
||||
|
||||
function get_curl($url, $post=0, $referer=0, $cookie=0, $header=0, $ua=0, $nobody=0, $addheader=0)
|
||||
{
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
$httpheader[] = "Accept: */*";
|
||||
$httpheader[] = "Accept-Encoding: gzip,deflate,sdch";
|
||||
$httpheader[] = "Accept-Language: zh-CN,zh;q=0.8";
|
||||
$httpheader[] = "Connection: close";
|
||||
if($addheader){
|
||||
$httpheader = array_merge($httpheader, $addheader);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
|
||||
if ($post) {
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
|
||||
}
|
||||
if ($header) {
|
||||
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||
}
|
||||
if ($cookie) {
|
||||
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
|
||||
}
|
||||
if($referer){
|
||||
curl_setopt($ch, CURLOPT_REFERER, $referer);
|
||||
}
|
||||
if ($ua) {
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, $ua);
|
||||
}
|
||||
else {
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Linux; U; Android 4.0.4; es-mx; HTC_One_X Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0");
|
||||
}
|
||||
if ($nobody) {
|
||||
curl_setopt($ch, CURLOPT_NOBODY, 1);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
$ret = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function real_ip($type=0){
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
if($type<=0 && isset($_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
|
||||
foreach ($matches[0] AS $xip) {
|
||||
if (filter_var($xip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
$ip = $xip;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} elseif ($type<=0 && isset($_SERVER['HTTP_CLIENT_IP']) && filter_var($_SERVER['HTTP_CLIENT_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||
} elseif ($type<=1 && isset($_SERVER['HTTP_CF_CONNECTING_IP']) && filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
|
||||
} elseif ($type<=1 && isset($_SERVER['HTTP_X_REAL_IP']) && filter_var($_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
$ip = $_SERVER['HTTP_X_REAL_IP'];
|
||||
}
|
||||
return $ip;
|
||||
}
|
||||
|
||||
function strexists($string, $find) {
|
||||
return !(strpos($string, $find) === FALSE);
|
||||
}
|
||||
|
||||
function dstrpos($string, $arr) {
|
||||
if(empty($string)) return false;
|
||||
foreach((array)$arr as $v) {
|
||||
if(strpos($string, $v) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkmobile() {
|
||||
$useragent = strtolower($_SERVER['HTTP_USER_AGENT']);
|
||||
$ualist = array('android', 'midp', 'nokia', 'mobile', 'iphone', 'ipod', 'blackberry', 'windows phone');
|
||||
if((dstrpos($useragent, $ualist) || strexists($_SERVER['HTTP_ACCEPT'], "VND.WAP") || strexists($_SERVER['HTTP_VIA'],"wap")))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
|
||||
$ckey_length = 4;
|
||||
$key = md5($key);
|
||||
$keya = md5(substr($key, 0, 16));
|
||||
$keyb = md5(substr($key, 16, 16));
|
||||
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
|
||||
$cryptkey = $keya.md5($keya.$keyc);
|
||||
$key_length = strlen($cryptkey);
|
||||
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
|
||||
$string_length = strlen($string);
|
||||
$result = '';
|
||||
$box = range(0, 255);
|
||||
$rndkey = array();
|
||||
for($i = 0; $i <= 255; $i++) {
|
||||
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
|
||||
}
|
||||
for($j = $i = 0; $i < 256; $i++) {
|
||||
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
|
||||
$tmp = $box[$i];
|
||||
$box[$i] = $box[$j];
|
||||
$box[$j] = $tmp;
|
||||
}
|
||||
for($a = $j = $i = 0; $i < $string_length; $i++) {
|
||||
$a = ($a + 1) % 256;
|
||||
$j = ($j + $box[$a]) % 256;
|
||||
$tmp = $box[$a];
|
||||
$box[$a] = $box[$j];
|
||||
$box[$j] = $tmp;
|
||||
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
|
||||
}
|
||||
if($operation == 'DECODE') {
|
||||
if(((int)substr($result, 0, 10) == 0 || (int)substr($result, 0, 10) - time() > 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;
|
||||
}
|
115
app/controller/Auth.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
namespace app\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use Exception;
|
||||
use think\facade\Db;
|
||||
use think\facade\View;
|
||||
use app\lib\DnsHelper;
|
||||
|
||||
class Auth extends BaseController
|
||||
{
|
||||
|
||||
public function verifycode()
|
||||
{
|
||||
return captcha();
|
||||
}
|
||||
|
||||
public function login(){
|
||||
$login_limit_count = 5;//登录失败次数
|
||||
$login_limit_file = app()->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']);
|
||||
}
|
||||
}
|
561
app/controller/Domain.php
Normal file
|
@ -0,0 +1,561 @@
|
|||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use think\facade\Db;
|
||||
use think\facade\View;
|
||||
use think\facade\Request;
|
||||
use app\lib\DnsHelper;
|
||||
|
||||
class Domain extends BaseController
|
||||
{
|
||||
|
||||
public function account(){
|
||||
if(!checkPermission(2)) return $this->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")]);
|
||||
}
|
||||
}
|
96
app/controller/Index.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
namespace app\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use Exception;
|
||||
use think\facade\Db;
|
||||
use think\facade\View;
|
||||
use think\facade\Cache;
|
||||
use app\lib\DnsHelper;
|
||||
|
||||
class Index extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
if(request()->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();
|
||||
}
|
||||
|
||||
}
|
84
app/controller/Install.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
namespace app\controller;
|
||||
|
||||
use PDO;
|
||||
use Exception;
|
||||
use app\BaseController;
|
||||
use think\facade\View;
|
||||
use think\facade\Cache;
|
||||
|
||||
class Install extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
if (file_exists(app()->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();
|
||||
}
|
||||
|
||||
}
|
164
app/controller/User.php
Normal file
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
namespace app\controller;
|
||||
|
||||
use app\BaseController;
|
||||
use think\facade\Db;
|
||||
use think\facade\View;
|
||||
use think\facade\Request;
|
||||
|
||||
class User extends BaseController
|
||||
{
|
||||
|
||||
public function user(){
|
||||
if(!checkPermission(2)) return $this->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]);
|
||||
}
|
||||
|
||||
}
|
1
app/data/huawei_line.json
Normal file
17
app/event.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
// 事件定义文件
|
||||
return [
|
||||
'bind' => [
|
||||
],
|
||||
|
||||
'listen' => [
|
||||
'AppInit' => [],
|
||||
'HttpRun' => [],
|
||||
'HttpEnd' => [],
|
||||
'LogLevel' => [],
|
||||
'LogWrite' => [],
|
||||
],
|
||||
|
||||
'subscribe' => [
|
||||
],
|
||||
];
|
91
app/lib/DnsHelper.php
Normal file
|
@ -0,0 +1,91 @@
|
|||
<?php
|
||||
|
||||
namespace app\lib;
|
||||
use think\facade\Db;
|
||||
|
||||
class DnsHelper
|
||||
{
|
||||
public static $dns_config = [
|
||||
'aliyun' => [
|
||||
'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;
|
||||
}
|
||||
}
|
35
app/lib/DnsInterface.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace app\lib;
|
||||
|
||||
interface DnsInterface
|
||||
{
|
||||
function getError();
|
||||
|
||||
function check();
|
||||
|
||||
function getDomainList($KeyWord=null, $PageNumber=1, $PageSize=20);
|
||||
|
||||
function getDomainRecords($PageNumber=1, $PageSize=20, $KeyWord = null, $SubDomain = null, $Type = null, $Line = null, $Status = null);
|
||||
|
||||
function getSubDomainRecords($SubDomain, $PageNumber=1, $PageSize=20, $Type = null, $Line = null);
|
||||
|
||||
function getDomainRecordInfo($RecordId);
|
||||
|
||||
function addDomainRecord($Name, $Type, $Value, $Line = 'default', $TTL = 600, $MX = 1, $Remark = null);
|
||||
|
||||
function updateDomainRecord($RecordId, $Name, $Type, $Value, $Line = 'default', $TTL = 600, $MX = 1, $Remark = null);
|
||||
|
||||
function updateDomainRecordRemark($RecordId, $Remark);
|
||||
|
||||
function deleteDomainRecord($RecordId);
|
||||
|
||||
function setDomainRecordStatus($RecordId, $Status);
|
||||
|
||||
function getDomainRecordLog($PageNumber = 1, $PageSize = 20, $KeyWord = null, $StartDate = null, $endDate = null);
|
||||
|
||||
function getRecordLine();
|
||||
|
||||
function getMinTTL();
|
||||
|
||||
}
|
314
app/lib/dns/aliyun.php
Normal file
|
@ -0,0 +1,314 @@
|
|||
<?php
|
||||
namespace app\lib\dns;
|
||||
|
||||
use app\lib\DnsInterface;
|
||||
|
||||
class aliyun implements DnsInterface {
|
||||
private $AccessKeyId;
|
||||
private $AccessKeySecret;
|
||||
private $Endpoint = 'alidns.aliyuncs.com'; //API接入域名
|
||||
private $Version = '2015-01-09'; //API版本号
|
||||
private $error;
|
||||
private $domain;
|
||||
private $domainid;
|
||||
private $domainInfo;
|
||||
|
||||
function __construct($config){
|
||||
$this->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);
|
||||
}
|
||||
}
|
330
app/lib/dns/baidu.php
Normal file
|
@ -0,0 +1,330 @@
|
|||
<?php
|
||||
namespace app\lib\dns;
|
||||
|
||||
use app\lib\DnsInterface;
|
||||
|
||||
class baidu implements DnsInterface {
|
||||
private $AccessKeyId;
|
||||
private $SecretAccessKey;
|
||||
private $endpoint = "dns.baidubce.com";
|
||||
private $service = "dnspod";
|
||||
private $version = "2021-03-23";
|
||||
private $error;
|
||||
private $domain;
|
||||
private $domainid;
|
||||
|
||||
function __construct($config){
|
||||
$this->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);
|
||||
}
|
||||
}
|
237
app/lib/dns/cloudflare.php
Normal file
|
@ -0,0 +1,237 @@
|
|||
<?php
|
||||
namespace app\lib\dns;
|
||||
|
||||
use app\lib\DnsInterface;
|
||||
|
||||
class cloudflare implements DnsInterface {
|
||||
private $Email;
|
||||
private $ApiKey;
|
||||
private $baseUrl = 'https://api.cloudflare.com/client/v4';
|
||||
private $error;
|
||||
private $domain;
|
||||
private $domainid;
|
||||
|
||||
function __construct($config){
|
||||
$this->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);
|
||||
}
|
||||
}
|
362
app/lib/dns/dnspod.php
Normal file
|
@ -0,0 +1,362 @@
|
|||
<?php
|
||||
namespace app\lib\dns;
|
||||
|
||||
use app\lib\DnsInterface;
|
||||
|
||||
class dnspod implements DnsInterface {
|
||||
private $SecretId;
|
||||
private $SecretKey;
|
||||
private $endpoint = "dnspod.tencentcloudapi.com";
|
||||
private $service = "dnspod";
|
||||
private $version = "2021-03-23";
|
||||
private $error;
|
||||
private $domain;
|
||||
private $domainid;
|
||||
|
||||
function __construct($config){
|
||||
$this->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);
|
||||
}
|
||||
}
|
345
app/lib/dns/huawei.php
Normal file
|
@ -0,0 +1,345 @@
|
|||
<?php
|
||||
namespace app\lib\dns;
|
||||
|
||||
use app\lib\DnsInterface;
|
||||
|
||||
class huawei implements DnsInterface {
|
||||
private $AccessKeyId;
|
||||
private $SecretAccessKey;
|
||||
private $endpoint = "dns.myhuaweicloud.com";
|
||||
private $service = "dnspod";
|
||||
private $version = "2021-03-23";
|
||||
private $error;
|
||||
private $domain;
|
||||
private $domainid;
|
||||
|
||||
function __construct($config){
|
||||
$this->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);
|
||||
}
|
||||
}
|
226
app/lib/dns/west.php
Normal file
|
@ -0,0 +1,226 @@
|
|||
<?php
|
||||
namespace app\lib\dns;
|
||||
|
||||
use app\lib\DnsInterface;
|
||||
|
||||
class west implements DnsInterface {
|
||||
private $username;
|
||||
private $api_password;
|
||||
private $baseUrl = 'https://api.west.cn/api/v2';
|
||||
private $error;
|
||||
private $domain;
|
||||
private $domainid;
|
||||
|
||||
function __construct($config){
|
||||
$this->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);
|
||||
}
|
||||
}
|
12
app/middleware.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
// 全局中间件定义文件
|
||||
return [
|
||||
// 全局请求缓存
|
||||
// \think\middleware\CheckRequestCache::class,
|
||||
// 多语言加载
|
||||
// \think\middleware\LoadLangPack::class,
|
||||
// Session初始化
|
||||
// \think\middleware\SessionInit::class
|
||||
\app\middleware\LoadConfig::class,
|
||||
\app\middleware\AuthUser::class
|
||||
];
|
40
app/middleware/AuthApi.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
use think\facade\Db;
|
||||
|
||||
class AuthApi
|
||||
{
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
$uid = input('post.uid/d');
|
||||
$timestamp = input('post.timestamp');
|
||||
$sign = input('post.sign');
|
||||
if(!$uid || empty($timestamp) || empty($sign)){
|
||||
return json(['code'=>-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);
|
||||
}
|
||||
}
|
52
app/middleware/AuthUser.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
use think\facade\Db;
|
||||
|
||||
class AuthUser
|
||||
{
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
$islogin = false;
|
||||
$cookie = cookie('user_token');
|
||||
$user = null;
|
||||
if($cookie){
|
||||
$token=authcode($cookie, 'DECODE', env('app.sys_key'));
|
||||
if($token){
|
||||
list($type, $uid, $sid, $expiretime) = explode("\t", $token);
|
||||
if($type == 'user'){
|
||||
$user = Db::name('user')->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);
|
||||
}
|
||||
}
|
19
app/middleware/CheckLogin.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
|
||||
class CheckLogin
|
||||
{
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
if (!request()->islogin) {
|
||||
if ($request->isAjax() || !$request->isGet()) {
|
||||
return json(['code'=>-1, 'msg'=>'未登录'])->code(401);
|
||||
}
|
||||
return redirect((string)url('/login'));
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
39
app/middleware/LoadConfig.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
use think\facade\Db;
|
||||
use think\facade\Config;
|
||||
|
||||
class LoadConfig
|
||||
{
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param \Closure $next
|
||||
* @return Response
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
if (!file_exists(app()->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',
|
||||
]);
|
||||
}
|
||||
}
|
24
app/middleware/RefererCheck.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
use think\facade\View;
|
||||
|
||||
class RefererCheck
|
||||
{
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param \Closure $next
|
||||
* @return Response
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
if(!checkRefererHost()){
|
||||
return response('Access Denied', 403);
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
25
app/middleware/ViewOutput.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
declare (strict_types=1);
|
||||
|
||||
namespace app\middleware;
|
||||
|
||||
use think\facade\View;
|
||||
|
||||
class ViewOutput
|
||||
{
|
||||
/**
|
||||
* 处理请求
|
||||
*
|
||||
* @param \think\Request $request
|
||||
* @param \Closure $next
|
||||
* @return Response
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
View::assign('islogin', $request->islogin);
|
||||
View::assign('user', $request->user);
|
||||
View::assign('cdnpublic', '//lib.baomitu.com/');
|
||||
View::assign('skin', getAdminSkin());
|
||||
return $next($request);
|
||||
}
|
||||
}
|
9
app/provider.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
use app\ExceptionHandle;
|
||||
use app\Request;
|
||||
|
||||
// 容器Provider定义文件
|
||||
return [
|
||||
'think\Request' => Request::class,
|
||||
'think\exception\Handle' => ExceptionHandle::class,
|
||||
];
|
9
app/service.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
use app\AppService;
|
||||
|
||||
// 系统服务定义文件
|
||||
// 服务在完成全局初始化之后执行
|
||||
return [
|
||||
AppService::class,
|
||||
];
|
63
app/sql/install.sql
Normal file
|
@ -0,0 +1,63 @@
|
|||
DROP TABLE IF EXISTS `dnsmgr_account`;
|
||||
CREATE TABLE `dnsmgr_account` (
|
||||
`id` int(11) unsigned NOT NULL auto_increment,
|
||||
`type` varchar(20) NOT NULL,
|
||||
`ak` varchar(256) DEFAULT NULL,
|
||||
`sk` varchar(256) DEFAULT NULL,
|
||||
`ext` varchar(256) DEFAULT NULL,
|
||||
`remark` varchar(100) DEFAULT NULL,
|
||||
`addtime` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
DROP TABLE IF EXISTS `dnsmgr_domain`;
|
||||
CREATE TABLE `dnsmgr_domain` (
|
||||
`id` int(11) unsigned NOT NULL auto_increment,
|
||||
`aid` int(11) unsigned NOT NULL,
|
||||
`name` varchar(128) NOT NULL,
|
||||
`thirdid` varchar(60) DEFAULT NULL,
|
||||
`addtime` datetime DEFAULT NULL,
|
||||
`is_hide` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`is_sso` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`recordcount` int(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `name` (`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
DROP TABLE IF EXISTS `dnsmgr_user`;
|
||||
CREATE TABLE `dnsmgr_user` (
|
||||
`id` int(11) unsigned NOT NULL auto_increment,
|
||||
`username` varchar(64) NOT NULL,
|
||||
`password` varchar(80) NOT NULL,
|
||||
`is_api` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`apikey` varchar(32) DEFAULT NULL,
|
||||
`level` int(11) NOT NULL DEFAULT '0',
|
||||
`regtime` datetime DEFAULT NULL,
|
||||
`lasttime` datetime DEFAULT NULL,
|
||||
`status` tinyint(1) NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `username` (`username`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1000;
|
||||
|
||||
DROP TABLE IF EXISTS `dnsmgr_permission`;
|
||||
CREATE TABLE `dnsmgr_permission` (
|
||||
`id` int(11) unsigned NOT NULL auto_increment,
|
||||
`uid` int(11) unsigned NOT NULL,
|
||||
`domain` varchar(128) NOT NULL,
|
||||
`sub` varchar(80) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `uid` (`uid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
DROP TABLE IF EXISTS `dnsmgr_log`;
|
||||
CREATE TABLE `dnsmgr_log` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`uid` int(11) unsigned NOT NULL,
|
||||
`action` varchar(40) NOT NULL,
|
||||
`domain` varchar(128) NOT NULL DEFAULT '',
|
||||
`data` varchar(500) DEFAULT NULL,
|
||||
`addtime` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `uid` (`uid`),
|
||||
KEY `domain` (`domain`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
112
app/view/auth/login.html
Normal file
|
@ -0,0 +1,112 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, shrink-to-fit=no">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>聚合DNS管理系统 - 登录</title>
|
||||
<link href="{$cdnpublic}twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
|
||||
<link href="{$cdnpublic}font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
|
||||
<link href="/static/css/app.min.css" rel="stylesheet">
|
||||
<link href="/static/css/skins/{$skin}.css" rel="stylesheet">
|
||||
<link href="/static/css/bootstrap-table.css" rel="stylesheet"/>
|
||||
<script src="{$cdnpublic}jquery/3.6.4/jquery.min.js"></script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="{$cdnpublic}html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
<script src="{$cdnpublic}respond.js/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
<style type="text/css">
|
||||
body{color:#999;background-color:#f1f4fd;background-size:cover}
|
||||
a{color:#444}
|
||||
.login-screen{max-width:430px;padding:0;margin:100px auto 0 auto}
|
||||
.login-screen .well{border-radius:3px;-webkit-box-shadow:0 0 30px rgba(0,0,0,.1);box-shadow:0 0 30px rgba(0,0,0,.1);background:#fff;border:none;padding:0}
|
||||
@media (max-width:767px){.login-screen{padding:20px 0}
|
||||
}
|
||||
.profile-img-card{width:100px;height:100px;display:block;-moz-border-radius:50%;-webkit-border-radius:50%;border-radius:50%;margin:-93px auto 30px;border:5px solid #fff}
|
||||
.profile-name-card{text-align:center}
|
||||
.login-head{background:#899fe1;border-radius:3px 3px 0 0}
|
||||
.login-form{padding:40px 30px;position:relative;z-index:99}
|
||||
#login-form{margin-top:20px}
|
||||
#login-form .input-group{margin-bottom:15px}
|
||||
#login-form .form-control{font-size:14px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="login-wrapper">
|
||||
<div class="login-screen">
|
||||
<div class="well">
|
||||
<div class="login-head">
|
||||
<img src="/static/images/login-head.png" style="width:100%;"/>
|
||||
</div>
|
||||
<div class="login-form">
|
||||
<img id="profile-img" class="profile-img-card" src="/static/images/user.png"/>
|
||||
<p id="profile-name" class="profile-name-card"></p>
|
||||
<form action="" id="login-form" onsubmit="return doLogin()">
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon"><span class="glyphicon glyphicon-user" aria-hidden="true"></span></div>
|
||||
<input type="text" class="form-control" placeholder="用户名" name="username" required="required"/>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon"><span class="glyphicon glyphicon-lock" aria-hidden="true"></span></div>
|
||||
<input type="password" class="form-control" placeholder="密码" name="password" required="required"/>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon"><span class="glyphicon glyphicon-lock" aria-hidden="true"></span></div>
|
||||
<input type="text" class="form-control input-lg" placeholder="验证码" name="code" autocomplete="off" required="required"/>
|
||||
<span class="input-group-addon" style="padding: 0">
|
||||
<img id="verifycode" src="/verifycode" height="45" onclick="this.src='/verifycode?r='+Math.random();" title="点击更换验证码">
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-success btn-lg btn-block" id="submit" style="background:#708eea;">登 录</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script>
|
||||
function doLogin(){
|
||||
var username = $("input[name='username']").val();
|
||||
var password = $("input[name='password']").val();
|
||||
var code = $("input[name='code']").val();
|
||||
if(username == ''){
|
||||
layer.msg('用户名不能为空', {icon: 2});
|
||||
return false;
|
||||
}
|
||||
if(password == ''){
|
||||
layer.msg('密码不能为空', {icon: 2});
|
||||
return false;
|
||||
}
|
||||
if(code == ''){
|
||||
layer.msg('验证码不能为空', {icon: 2});
|
||||
return false;
|
||||
}
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/login",
|
||||
data: $("#login-form").serialize(),
|
||||
dataType: 'json',
|
||||
success: function(data){
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.msg('登录成功,正在跳转到首页', {icon: 1,shade: 0.01,time: 15000});
|
||||
window.location.href = '/';
|
||||
}else{
|
||||
if(data.vcode==1){
|
||||
$("#verifycode").attr('src', '/verifycode?r='+Math.random())
|
||||
}
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
196
app/view/common/layout.html
Normal file
|
@ -0,0 +1,196 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-cn">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, shrink-to-fit=no">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>{block name="title"}标题{/block}</title>
|
||||
<link href="{$cdnpublic}twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
|
||||
<link href="{$cdnpublic}font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
|
||||
<link href="{$cdnpublic}select2/4.0.13/css/select2.min.css" rel="stylesheet"/>
|
||||
<link href="/static/css/app.min.css" rel="stylesheet">
|
||||
<link href="/static/css/skins/{$skin}.css" rel="stylesheet">
|
||||
<link href="/static/css/bootstrap-table.css" rel="stylesheet"/>
|
||||
<script src="{$cdnpublic}jquery/3.6.4/jquery.min.js"></script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="{$cdnpublic}html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
<script src="{$cdnpublic}respond.js/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
<style>
|
||||
.type-logo{width: 18px;margin-top: -2px;padding-right: 4px;}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="hold-transition {$skin} sidebar-mini">
|
||||
<div class="wrapper">
|
||||
<header class="main-header">
|
||||
<!-- Logo -->
|
||||
<a href="javascript:;" class="logo">
|
||||
<!-- mini logo for sidebar mini 50x50 pixels -->
|
||||
<span class="logo-mini"><i class="fa fa-cube"></i></span>
|
||||
<!-- logo for regular state and mobile devices -->
|
||||
<span class="logo-lg"></span>聚合DNS管理系统
|
||||
</a>
|
||||
<!-- Header Navbar: style can be found in header.less -->
|
||||
<nav class="navbar navbar-static-top">
|
||||
<!-- Sidebar toggle button-->
|
||||
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
|
||||
<span class="visible-xs-inline">菜单</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</a>
|
||||
|
||||
<div class="navbar-custom-menu">
|
||||
<ul class="nav navbar-nav">
|
||||
<li>
|
||||
<a href="/" title="平台首页"><i class="fa fa-home fa-fw"></i></a>
|
||||
</li>
|
||||
<li class="hidden-xs">
|
||||
<a href="#" data-toggle="fullscreen" title="全屏"><i class="fa fa-arrows-alt fa-fw"></i></a>
|
||||
</li>
|
||||
<li class="hidden-xs">
|
||||
<a href="#" data-toggle="control-sidebar" title="更换皮肤"><i class="fa fa-wrench fa-fw"></i></a>
|
||||
</li>
|
||||
<!-- User Account: style can be found in dropdown.less -->
|
||||
<li class="dropdown user user-menu">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<img src="/static/images/user.png" class="user-image" alt="User Image">
|
||||
<span class="hidden-xs">{$user.username}</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<!-- User image -->
|
||||
<li class="user-header">
|
||||
<img src="/static/images/user.png" class="img-circle" alt="User Image">
|
||||
<p>
|
||||
{$user.username}
|
||||
<small>{$user.regtime}</small>
|
||||
</p>
|
||||
</li>
|
||||
<!-- Menu Footer-->
|
||||
<li class="user-footer">
|
||||
{if request()->user['type'] eq 'user'}<div class="pull-left">
|
||||
<a href="/setpwd" class="btn btn-primary"><i class="fa fa-lock"></i> 修改密码</a>
|
||||
</div>{/if}
|
||||
<div class="pull-right">
|
||||
<a href="/logout" class="btn btn-danger"><i class="fa fa-sign-out"></i> 退出登录</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<!-- Left side column. contains the logo and sidebar -->
|
||||
<aside class="main-sidebar">
|
||||
<!-- sidebar: style can be found in sidebar.less -->
|
||||
<section class="sidebar">
|
||||
<!-- Sidebar user panel -->
|
||||
<div class="user-panel">
|
||||
<div class="pull-left image">
|
||||
<img src="/static/images/user.png" class="img-circle" alt="User Image">
|
||||
</div>
|
||||
<div class="pull-left info">
|
||||
<p>{$user.username}</p>
|
||||
<i class="fa fa-circle text-success"></i> Online
|
||||
</div>
|
||||
</div>
|
||||
<!-- sidebar menu: : style can be found in sidebar.less -->
|
||||
<ul class="sidebar-menu" data-widget="tree">
|
||||
<li class="header">功能导航</li>
|
||||
{if request()->user['type'] eq 'user'}<li class="{:checkIfActive('index')}">
|
||||
<a href="/"><i class="fa fa-home fa-fw"></i> <span>后台首页</span></a>
|
||||
</li>{/if}
|
||||
<li class="{:checkIfActive('domain,record,record_log')}">
|
||||
<a href="/domain"><i class="fa fa-list-ul fa-fw"></i> <span>域名管理</span></a>
|
||||
</li>
|
||||
{if request()->user['level'] eq 2}<li class="{:checkIfActive('account')}">
|
||||
<a href="/account"><i class="fa fa-lock fa-fw"></i> <span>域名账户</span></a>
|
||||
</li>
|
||||
<li class="{:checkIfActive('user')}">
|
||||
<a href="/user"><i class="fa fa-user fa-fw"></i> <span>用户管理</span></a>
|
||||
</li>{/if}
|
||||
<li class="{:checkIfActive('log')}">
|
||||
<a href="/log"><i class="fa fa-list fa-fw"></i> <span>操作日志</span></a>
|
||||
</li>
|
||||
{if request()->user['type'] eq 'user'}
|
||||
<li class="">
|
||||
<a href="https://www.showdoc.com.cn/dnsmgr/11058996709621562" target="_blank"><i class="fa fa-book fa-fw"></i> <span>接口文档</span></a>
|
||||
</li>
|
||||
{/if}
|
||||
</ul>
|
||||
</section>
|
||||
<!-- /.sidebar -->
|
||||
</aside>
|
||||
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
{block name="main"}主内容{/block}
|
||||
</section>
|
||||
<!-- /.content -->
|
||||
</div>
|
||||
<!-- Control Sidebar -->
|
||||
<aside class="control-sidebar control-sidebar-dark" style="display: none;">
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<!-- Home tab content -->
|
||||
<div class="tab-pane active">
|
||||
<h4 class="control-sidebar-heading">皮肤</h4>
|
||||
<ul class="list-unstyled clearfix skin-list">
|
||||
<li><a href="javascript:;" data-skin="skin-blue" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #4e73df;"></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Blue</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-black" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-purple" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #605ca8;"></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Purple</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-green" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 7px;" class="bg-green-active"></span><span class="bg-green" style="width: 80%; height: 7px;"></span></div><div><span style="width: 20%; height: 20px; background: #000;"></span><span style="width: 80%; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Green</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-red" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 7px;" class="bg-red-active"></span><span class="bg-red" style="width: 80%; height: 7px;"></span></div><div><span style="width: 20%; height: 20px; background: #000;"></span><span style="width: 80%; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Red</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-yellow" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 7px;" class="bg-yellow-active"></span><span class="bg-yellow" style="width: 80%; height: 7px;"></span></div><div><span style="width: 20%; height: 20px; background: #000;"></span><span style="width: 80%; height: 20px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Yellow</p></li>
|
||||
|
||||
<li><a href="javascript:;" data-skin="skin-blue-light" class="clearfix full-opacity-hover"><div><span style="width: 100%; height: 7px; background: #4e73df;"></span></div><div><span style="width: 100%; height: 20px; background: #f9fafc;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Blue Light</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-black-light" class="clearfix full-opacity-hover"><div><span style="width: 100%; height: 7px; background: #000;"></span></div><div><span style="width: 100%; height: 20px; background: #f9fafc;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Black Light</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-purple-light" class="clearfix full-opacity-hover"><div><span style="width: 100%; height: 7px; background: #605ca8;"></span></div><div><span style="width: 100%; height: 20px; background: #f9fafc;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Purple Light</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-green-light" class="clearfix full-opacity-hover"><div><span style="width: 100%; height: 7px;" class="bg-green"></span></div><div><span style="width: 100%; height: 20px; background: #f9fafc;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Green Light</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-red-light" class="clearfix full-opacity-hover"><div><span style="width: 100%; height: 7px;" class="bg-red"></span></div><div><span style="width: 100%; height: 20px; background: #f9fafc;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Red Light</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-yellow-light" class="clearfix full-opacity-hover"><div><span style="width: 100%; height: 7px;" class="bg-yellow"></span></div><div><span style="width: 100%; height: 20px; background: #f9fafc;"></span></div></a><p class="text-center no-margin" style="font-size: 12px">Yellow Light</p></li>
|
||||
|
||||
<li><a href="javascript:;" data-skin="skin-black-blue" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"><span style="width: 100%; height: 3px; margin-top:10px; background: #4e73df;"></span></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black Blue</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-black-purple" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"><span style="width: 100%; height: 3px; margin-top:10px; background: #605ca8;"></span></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black Purple</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-black-green" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"><span style="width: 100%; height: 3px; margin-top:10px;" class="bg-green"></span></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black Green</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-black-red" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"><span style="width: 100%; height: 3px; margin-top:10px;" class="bg-red"></span></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black Red</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-black-yellow" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"><span style="width: 100%; height: 3px; margin-top:10px;" class="bg-yellow"></span></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black Yellow</p></li>
|
||||
<li><a href="javascript:;" data-skin="skin-black-pink" class="clearfix full-opacity-hover"><div><span style="width: 20%; height: 27px; background: #000;"><span style="width: 100%; height: 3px; margin-top:10px; background: #f5549f;"></span></span><span style="width: 80%; height: 27px; background: #f4f5f7;"></span></div></a><p class="text-center no-margin">Black Pink</p></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- /.tab-pane -->
|
||||
</div>
|
||||
</aside>
|
||||
<!-- /.control-sidebar -->
|
||||
<!-- Add the sidebar's background. This div must be placed
|
||||
immediately after the control sidebar -->
|
||||
<div class="control-sidebar-bg"></div>
|
||||
</div>
|
||||
<!-- ./wrapper -->
|
||||
|
||||
<script src="<?php echo $cdnpublic?>twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
||||
<script src="<?php echo $cdnpublic?>fastclick/1.0.6/fastclick.min.js"></script>
|
||||
<script src="/static/js/app.js"></script>
|
||||
<script>
|
||||
document.addEventListener('pointerdown', function(e) {
|
||||
if (e.target.closest('table')) {
|
||||
return;
|
||||
}
|
||||
|
||||
startX = e.clientX;
|
||||
|
||||
// 如果触摸开始于屏幕左边缘的10%区域内
|
||||
if (startX < window.innerWidth * 0.1) {
|
||||
e.preventDefault(); // 尝试阻止默认行为
|
||||
}
|
||||
}, false);
|
||||
|
||||
</script>
|
||||
{block name="script"}{/block}
|
||||
</body>
|
||||
</html>
|
60
app/view/dispatch_jump.html
Normal file
|
@ -0,0 +1,60 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>温馨提示</title>
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
||||
<meta name="renderer" content="webkit"/>
|
||||
<style type="text/css">
|
||||
*{box-sizing:border-box;margin:0;padding:0;font-family:Lantinghei SC,Open Sans,Arial,Hiragino Sans GB,Microsoft YaHei,"微软雅黑",STHeiti,WenQuanYi Micro Hei,SimSun,sans-serif;-webkit-font-smoothing:antialiased}
|
||||
body{padding:70px 0;background:#edf1f4;font-weight:400;font-size:1pc;-webkit-text-size-adjust:none;color:#333}
|
||||
a{outline:0;color:#3498db;text-decoration:none;cursor:pointer}
|
||||
.system-message{margin:20px 5%;padding:40px 20px;background:#fff;box-shadow:1px 1px 1px hsla(0,0%,39%,.1);text-align:center}
|
||||
.system-message h1{margin:0;margin-bottom:9pt;color:#444;font-weight:400;font-size:40px}
|
||||
.system-message .jump,.system-message .image{margin:20px 0;padding:0;padding:10px 0;font-weight:400}
|
||||
.system-message .jump{font-size:14px}
|
||||
.system-message .jump a{color:#333}
|
||||
.system-message p{font-size:9pt;line-height:20px}
|
||||
.system-message .btn{display:inline-block;margin-right:10px;width:138px;height:2pc;border:1px solid #44a0e8;border-radius:30px;color:#44a0e8;text-align:center;font-size:1pc;line-height:2pc;margin-bottom:5px;}
|
||||
.success .btn{border-color:#69bf4e;color:#69bf4e}
|
||||
.error .btn{border-color:#ff8992;color:#ff8992}
|
||||
.info .btn{border-color:#3498db;color:#3498db}
|
||||
.copyright p{width:100%;color:#919191;text-align:center;font-size:10px}
|
||||
.system-message .btn-grey{border-color:#bbb;color:#bbb}
|
||||
.clearfix:after{clear:both;display:block;visibility:hidden;height:0;content:"."}
|
||||
@media (max-width:768px){body {padding:20px 0;}}
|
||||
@media (max-width:480px){.system-message h1{font-size:30px;}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="system-message {$code}">
|
||||
<div class="image">
|
||||
<img src="/static/images/{$code}.svg" alt="" width="150" />
|
||||
</div>
|
||||
<h1>{$msg}</h1>
|
||||
{if $url}
|
||||
<p class="jump">
|
||||
页面将在 <span id="wait">{$wait}</span> 秒后自动跳转
|
||||
</p>
|
||||
{/if}
|
||||
<p class="clearfix">
|
||||
<a href="javascript:history.go(-1);" class="btn btn-grey">返回上一页</a>
|
||||
{if $url}
|
||||
<a href="{$url}" class="btn btn-primary">立即跳转</a>
|
||||
{/if}
|
||||
</p>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
(function () {
|
||||
var wait = document.getElementById('wait');
|
||||
var interval = setInterval(function () {
|
||||
var time = --wait.innerHTML;
|
||||
if (time <= 0) {
|
||||
location.href = "{$url}";
|
||||
clearInterval(interval);
|
||||
}
|
||||
}, 1000);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
234
app/view/domain/account.html
Normal file
|
@ -0,0 +1,234 @@
|
|||
{extend name="common/layout" /}
|
||||
{block name="title"}域名账户{/block}
|
||||
{block name="main"}
|
||||
<div class="modal" id="modal-store" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="static">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content animated flipInX">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span
|
||||
aria-hidden="true">×</span><span
|
||||
class="sr-only">Close</span></button>
|
||||
<h4 class="modal-title" id="modal-title">添加/修改域名账户</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" id="form-store">
|
||||
<input type="hidden" name="action"/>
|
||||
<input type="hidden" name="id"/>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">所属平台</label>
|
||||
<div class="col-sm-9">
|
||||
<select name="type" class="form-control">
|
||||
{foreach $dnsconfig as $k=>$v}
|
||||
<option value="{$k}">{$v['name']}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right" id="ak_name">AccessKey</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="ak" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right" id="sk_name">SecretKey</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="sk" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right" id="ext_name">扩展字段</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="ext" placeholder="没有请勿填写">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">备注</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="remark" placeholder="备注选填">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">关闭</button>
|
||||
<button type="button" class="btn btn-primary" id="store" onclick="save()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 center-block" style="float: none;">
|
||||
<div class="panel panel-default panel-intro">
|
||||
<div class="panel-body">
|
||||
|
||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
|
||||
<div class="form-group">
|
||||
<label>搜索</label>
|
||||
<input type="text" class="form-control" name="kw" placeholder="AccessKey或备注">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
|
||||
<a href="javascript:searchClear()" class="btn btn-default" title="刷新域名账户列表"><i class="fa fa-refresh"></i> 刷新</a>
|
||||
<a href="javascript:addframe()" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
|
||||
</form>
|
||||
|
||||
<table id="listTable">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/bootstrap-table.min.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||
<script src="/static/js/custom.js"></script>
|
||||
<script>
|
||||
var dnsconfig = {$dnsconfig|json_encode|raw};
|
||||
$(document).ready(function(){
|
||||
updateToolbar();
|
||||
const defaultPageSize = 15;
|
||||
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
||||
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
||||
|
||||
$("#listTable").bootstrapTable({
|
||||
url: '/account/data',
|
||||
pageNumber: pageNumber,
|
||||
pageSize: pageSize,
|
||||
classes: 'table table-striped table-hover table-bordered',
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'ID'
|
||||
},
|
||||
{
|
||||
field: 'typename',
|
||||
title: '所属平台',
|
||||
formatter: function(value, row, index) {
|
||||
return '<img src="/static/images/'+row.type+'.ico" class="type-logo"></img>'+value;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'ak',
|
||||
title: 'AccessKey'
|
||||
},
|
||||
{
|
||||
field: 'remark',
|
||||
title: '备注'
|
||||
},
|
||||
{
|
||||
field: 'addtime',
|
||||
title: '添加时间'
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '<a href="javascript:editframe('+row.id+')" class="btn btn-info btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a>';
|
||||
return html;
|
||||
}
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
$("select[name=type]").change(function(){
|
||||
var type = $(this).val();
|
||||
if(dnsconfig[type] == undefined) return;
|
||||
$("#ak_name").html(dnsconfig[type].config.ak);
|
||||
$("#sk_name").html(dnsconfig[type].config.sk);
|
||||
if(dnsconfig[type].config.ext == undefined) dnsconfig[type].config.ext = '扩展字段';
|
||||
else $("#ext_name").html(dnsconfig[type].config.ext);
|
||||
});
|
||||
})
|
||||
function addframe(){
|
||||
$("#modal-store").modal('show');
|
||||
$("#modal-title").html("添加域名账户");
|
||||
$("#form-store input[name=action]").val("add");
|
||||
$("#form-store input[name=id]").val('');
|
||||
$("#form-store input[name=ak]").val('');
|
||||
$("#form-store input[name=sk]").val('');
|
||||
$("#form-store input[name=ext]").val('');
|
||||
$("#form-store input[name=remark]").val('');
|
||||
$("select[name=type]").change();
|
||||
}
|
||||
function editframe(id){
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/account/op/act/get',
|
||||
data : {id: id},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
$("#modal-store").modal('show');
|
||||
$("#modal-title").html("修改域名账户");
|
||||
$("#form-store input[name=action]").val("edit");
|
||||
$("#form-store input[name=id]").val(data.data.id);
|
||||
$("#form-store select[name=type]").val(data.data.type);
|
||||
$("#form-store input[name=ak]").val(data.data.ak);
|
||||
$("#form-store input[name=sk]").val(data.data.sk);
|
||||
$("#form-store input[name=ext]").val(data.data.ext);
|
||||
$("#form-store input[name=remark]").val(data.data.remark);
|
||||
$("select[name=type]").change();
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function save(){
|
||||
if($("#form-store input[name=username]").val()==''){
|
||||
layer.alert('请确保各项不能为空!');return false;
|
||||
}
|
||||
var act = $("#form-store input[name=action]").val();
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/account/op/act/'+act,
|
||||
data : $("#form-store").serialize(),
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.alert(data.msg,{
|
||||
icon: 1,
|
||||
closeBtn: false
|
||||
}, function(){
|
||||
layer.closeAll();
|
||||
$("#modal-store").modal('hide');
|
||||
searchSubmit();
|
||||
});
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function delItem(id) {
|
||||
var confirmobj = layer.confirm('确定要删除此域名账户吗?', {
|
||||
btn: ['确定','取消']
|
||||
}, function(){
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/account/op/act/del',
|
||||
data : {id: id},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.closeAll();
|
||||
searchSubmit();
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, function(){
|
||||
layer.close(confirmobj);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{/block}
|
361
app/view/domain/domain.html
Normal file
|
@ -0,0 +1,361 @@
|
|||
{extend name="common/layout" /}
|
||||
{block name="title"}域名管理{/block}
|
||||
{block name="main"}
|
||||
<div class="modal" id="modal-store" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="static">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content animated flipInX">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span
|
||||
aria-hidden="true">×</span><span
|
||||
class="sr-only">Close</span></button>
|
||||
<h4 class="modal-title" id="modal-title">添加域名</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" id="form-store">
|
||||
<input type="hidden" name="recordcount"/>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">域名账户</label>
|
||||
<div class="col-sm-9">
|
||||
<select name="aid" class="form-control">
|
||||
{foreach $accounts as $k=>$v}
|
||||
<option value="{$k}">{$v}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">选择域名</label>
|
||||
<div class="col-sm-9">
|
||||
<select name="domain" id="domainList" class="form-control"></select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">关闭</button>
|
||||
<button type="button" class="btn btn-primary" id="store" onclick="saveAdd()">添加</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal" id="modal-store2" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="static">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content animated flipInX">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span
|
||||
aria-hidden="true">×</span><span
|
||||
class="sr-only">Close</span></button>
|
||||
<h4 class="modal-title" id="modal-title">修改域名配置</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" id="form-store2">
|
||||
<input type="hidden" name="id"/>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">是否隐藏</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<select name="is_hide" class="form-control">
|
||||
<option value="0">否</option>
|
||||
<option value="1">是</option>
|
||||
</select>
|
||||
<a tabindex="0" class="input-group-addon" role="button" data-toggle="popover" data-trigger="focus" title="" data-placement="bottom" data-content="隐藏后仅管理员可见,普通用户在列表不可见" data-original-title="说明"><span class="glyphicon glyphicon-info-sign"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">对接开关</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<select name="is_sso" class="form-control">
|
||||
<option value="0">否</option>
|
||||
<option value="1">是</option>
|
||||
</select>
|
||||
<a tabindex="0" class="input-group-addon" role="button" data-toggle="popover" data-trigger="focus" title="" data-placement="bottom" data-content="对接开关开启后,将允许通过API接口一键登录该域名独立管理面板" data-original-title="说明"><span class="glyphicon glyphicon-info-sign"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">关闭</button>
|
||||
<button type="button" class="btn btn-primary" id="store" onclick="saveEdit()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 center-block" style="float: none;">
|
||||
<div class="panel panel-default panel-intro">
|
||||
<div class="panel-body">
|
||||
|
||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
|
||||
<div class="form-group">
|
||||
<label>搜索</label>
|
||||
<input type="text" class="form-control" name="kw" placeholder="域名">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<select name="type" class="form-control"><option value="">所有平台</option>{foreach $types as $k=>$v}
|
||||
<option value="{$k}">{$v}</option>
|
||||
{/foreach}</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
|
||||
<a href="javascript:searchClear()" class="btn btn-default" title="刷新域名列表"><i class="fa fa-refresh"></i> 刷新</a>
|
||||
{if request()->user['level'] eq 2}<a href="javascript:addframe()" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>{/if}
|
||||
</form>
|
||||
|
||||
<table id="listTable">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/bootstrap-table.min.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||
<script src="{$cdnpublic}select2/4.0.13/js/select2.min.js"></script>
|
||||
<script src="{$cdnpublic}select2/4.0.13/js/i18n/zh-CN.min.js"></script>
|
||||
<script src="/static/js/custom.js"></script>
|
||||
<script>
|
||||
var userLevel = "{:request()->user['level']}";
|
||||
$(document).ready(function(){
|
||||
updateToolbar();
|
||||
const defaultPageSize = 15;
|
||||
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
||||
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
||||
|
||||
$("#listTable").bootstrapTable({
|
||||
url: '/domain/data',
|
||||
pageNumber: pageNumber,
|
||||
pageSize: pageSize,
|
||||
classes: 'table table-striped table-hover table-bordered',
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'ID'
|
||||
},
|
||||
{
|
||||
field: 'typename',
|
||||
title: '平台账户',
|
||||
formatter: function(value, row, index) {
|
||||
return '<span title="'+row.remark+'" data-toggle="tooltip" data-placement="right" title="Tooltip on right"><img src="/static/images/'+row.type+'.ico" class="type-logo"></img>'+value+'('+row.aid+')</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
title: '域名',
|
||||
formatter: function(value, row, index) {
|
||||
return '<a href="/record/'+row.id+'" title="进入解析记录管理" onclick="loading()">'+value+'</a>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'recordcount',
|
||||
title: '记录数'
|
||||
},
|
||||
{
|
||||
field: 'addtime',
|
||||
title: '添加时间'
|
||||
},
|
||||
{
|
||||
field: 'is_hide',
|
||||
title: '是否隐藏',
|
||||
formatter: function(value, row, index) {
|
||||
return value==1?'<font color="grey">是</font>':'<font color="blue">否</font>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'is_sso',
|
||||
title: '对接开关',
|
||||
formatter: function(value, row, index) {
|
||||
return value==1?'<font color="green">是</font>':'<font color="red">否</font>';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '<a href="/record/'+row.id+'" class="btn btn-success btn-xs" onclick="loading()">解析</a>';
|
||||
if(userLevel == '2'){
|
||||
html += ' <a href="javascript:editframe('+row.id+')" class="btn btn-info btn-xs">配置</a>';
|
||||
html += ' <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a>';
|
||||
}
|
||||
return html;
|
||||
}
|
||||
},
|
||||
],
|
||||
onLoadSuccess: function(data) {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
}
|
||||
})
|
||||
|
||||
$("#form-store select[name=aid]").change(function(){
|
||||
getDomainList()
|
||||
})
|
||||
|
||||
$('#domainList').on('select2:select', function (e) {
|
||||
var data = e.params.data;
|
||||
$("#form-store input[name=recordcount]").val(data.recordcount);
|
||||
});
|
||||
|
||||
$('[data-toggle="popover"]').popover()
|
||||
})
|
||||
function addframe(){
|
||||
$("#modal-store").modal('show');
|
||||
var aid = $("#form-store select[name=aid]").val();
|
||||
if(aid != ''){
|
||||
getDomainList()
|
||||
}
|
||||
}
|
||||
function saveAdd(){
|
||||
var aid = $("#form-store select[name=aid]").val();
|
||||
var select = $('#domainList').select2('data');
|
||||
if(select.length == 0){
|
||||
layer.alert('请选择域名!');return false;
|
||||
}
|
||||
var name = select[0].text;
|
||||
var thirdid = select[0].id;
|
||||
var recordcount = $("#form-store input[name=recordcount]").val();
|
||||
if(aid=='' || thirdid==''){
|
||||
layer.alert('请确保各项不能为空!');return false;
|
||||
}
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/domain/op/act/add',
|
||||
data : {aid: aid, thirdid: thirdid, name: name, recordcount: recordcount},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.alert(data.msg,{
|
||||
icon: 1,
|
||||
closeBtn: false
|
||||
}, function(){
|
||||
layer.closeAll();
|
||||
$("#modal-store").modal('hide');
|
||||
searchSubmit();
|
||||
});
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function editframe(id){
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/domain/op/act/get',
|
||||
data : {id: id},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
$("#modal-store2").modal('show');
|
||||
$("#form-store2 input[name=id]").val(data.data.id);
|
||||
$("#form-store2 select[name=is_hide]").val(data.data.is_hide);
|
||||
$("#form-store2 select[name=is_sso]").val(data.data.is_sso);
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function saveEdit(){
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/domain/op/act/edit',
|
||||
data : $("#form-store2").serialize(),
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.alert(data.msg,{
|
||||
icon: 1,
|
||||
closeBtn: false
|
||||
}, function(){
|
||||
layer.closeAll();
|
||||
$("#modal-store2").modal('hide');
|
||||
searchSubmit();
|
||||
});
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function delItem(id) {
|
||||
var confirmobj = layer.confirm('确定要删除此域名吗?删除域名不会影响已添加的解析', {
|
||||
btn: ['确定','取消']
|
||||
}, function(){
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/domain/op/act/del',
|
||||
data : {id: id},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.closeAll();
|
||||
searchSubmit();
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, function(){
|
||||
layer.close(confirmobj);
|
||||
});
|
||||
}
|
||||
function getDomainList(){
|
||||
$('#domainList').empty();
|
||||
$('#domainList').select2({
|
||||
placeholder: '请选择域名',
|
||||
language: "zh-CN",
|
||||
ajax:{
|
||||
url: '/domain/list',
|
||||
type: "post",
|
||||
dataType: 'json',
|
||||
delay: 300,
|
||||
data: function(params) {
|
||||
var aid = $("#form-store select[name=aid]").val();
|
||||
var data = {
|
||||
aid: aid,
|
||||
kw: params.term,
|
||||
page: params.page || 1,
|
||||
pagesize: 10
|
||||
};
|
||||
return data;
|
||||
},
|
||||
processResults: function (data, params) {
|
||||
params.page = params.page || 1
|
||||
if(data.code == 0){
|
||||
var resultData = [];
|
||||
for (var i = 0; i < data.data.list.length; i++) {
|
||||
resultData.push({'id': data.data.list[i].DomainId, 'text': data.data.list[i].Domain, 'recordcount': data.data.list[i].RecordCount});
|
||||
}
|
||||
return {
|
||||
results: resultData,
|
||||
pagination: {
|
||||
more: data.data.total > params.page * 10
|
||||
}
|
||||
};
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
return {
|
||||
results: []
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
cache:false
|
||||
});
|
||||
}
|
||||
function loading(){
|
||||
layer.load(2);
|
||||
}
|
||||
</script>
|
||||
{/block}
|
47
app/view/domain/log.html
Normal file
|
@ -0,0 +1,47 @@
|
|||
{extend name="common/layout" /}
|
||||
{block name="title"}域名日志{/block}
|
||||
{block name="main"}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12 center-block" style="float: none;">
|
||||
<div class="panel panel-default panel-intro">
|
||||
<div class="panel-body">
|
||||
|
||||
<table id="listTable">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/bootstrap-table.min.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||
<script src="/static/js/custom.js"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
updateToolbar();
|
||||
const defaultPageSize = 15;
|
||||
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
||||
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
||||
|
||||
$("#listTable").bootstrapTable({
|
||||
url: '/record/log/{$domainId}',
|
||||
pageNumber: pageNumber,
|
||||
pageSize: pageSize,
|
||||
classes: 'table table-striped table-hover table-bordered',
|
||||
columns: [
|
||||
{
|
||||
field: 'time',
|
||||
title: '操作时间'
|
||||
},
|
||||
{
|
||||
field: 'data',
|
||||
title: '操作行为'
|
||||
}
|
||||
],
|
||||
})
|
||||
})
|
||||
</script>
|
||||
{/block}
|
436
app/view/domain/record.html
Normal file
|
@ -0,0 +1,436 @@
|
|||
{extend name="common/layout" /}
|
||||
{block name="title"}解析管理 - {$domainName}{/block}
|
||||
{block name="main"}
|
||||
<style>
|
||||
td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:360px;}
|
||||
</style>
|
||||
<div class="modal" id="modal-store" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="static">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content animated flipInX">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span
|
||||
aria-hidden="true">×</span><span
|
||||
class="sr-only">Close</span></button>
|
||||
<h4 class="modal-title" id="modal-title">添加/修改解析</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" id="form-store">
|
||||
<input type="hidden" name="action"/>
|
||||
<input type="hidden" name="recordid"/>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">主机记录</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="name" placeholder="填写域名前缀,支持多级" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">记录类型</label>
|
||||
<div class="col-sm-9">
|
||||
<select name="type" class="form-control">
|
||||
<option value="A">A</option>
|
||||
<option value="CNAME">CNAME</option>
|
||||
<option value="AAAA">AAAA</option>
|
||||
<option value="NS">NS</option>
|
||||
<option value="MX">MX</option>
|
||||
<option value="SRV">SRV</option>
|
||||
<option value="TXT">TXT</option>
|
||||
<option value="CAA">CAA</option>
|
||||
{if $dnsconfig.redirect}<option value="REDIRECT_URL">显性URL</option>
|
||||
<option value="FORWARD_URL">隐性URL</option>{/if}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">线路类型</label>
|
||||
<div class="col-sm-9" id="line_list">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">记录值</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="value" placeholder="输入记录值" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" style="display:none" id="mx_type">
|
||||
<label class="col-sm-3 control-label no-padding-right">MX优先级</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="mx" value="10">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">TTL</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="ttl" value="600" placeholder="指解析结果在DNS服务器中的缓存时间" required min="{$minTTL}">
|
||||
</div>
|
||||
</div>
|
||||
{if $dnsconfig.remark == 2}<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">备注</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="remark" placeholder="">
|
||||
</div>
|
||||
</div>{/if}
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">关闭</button>
|
||||
<button type="button" class="btn btn-primary" id="store" onclick="save()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 center-block" style="float: none;">
|
||||
<div class="panel panel-default panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{if request()->user['type'] eq 'user'}<a href="/domain" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{/if}{$domainName}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
|
||||
<div class="form-group">
|
||||
<label>搜索</label>
|
||||
<input type="text" class="form-control" name="keyword" placeholder="输入关键字">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<select name="status" class="form-control"><option value="">所有状态</option><option value="1">启用</option><option value="0">暂停</option></select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
|
||||
<a href="javascript:searchClear()" class="btn btn-default" title="刷新解析记录列表"><i class="fa fa-refresh"></i> 刷新</a>
|
||||
<a href="javascript:addframe()" class="btn btn-success"><i class="fa fa-plus"></i> 添加记录</a>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">批量操作 <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu"><li><a href="javascript:operation('open')">启用</a></li><li><a href="javascript:operation('pause')">暂停</a></li><li><a href="javascript:operation('delete')">删除</a></li></ul>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">日志 <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu"><li><a href="/log?domain={$domainName}">本站日志</a></li>{if $dnsconfig.log}<li><a href="/record/log/{$domainId}">域名日志</a></li>{/if}</ul>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<table id="listTable">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/bootstrap-table.min.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||
<script src="/static/js/bootstrapValidator.min.js"></script>
|
||||
<script src="/static/js/custom.js"></script>
|
||||
<script>
|
||||
var recordLine = {$recordLine|json_encode|raw};
|
||||
var dnsconfig = {$dnsconfig|json_encode|raw};
|
||||
var defaultLine = recordLine[0].id;
|
||||
$(document).ready(function(){
|
||||
updateToolbar();
|
||||
const defaultPageSize = 15;
|
||||
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
||||
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
||||
|
||||
$("#listTable").bootstrapTable({
|
||||
url: '/record/data/{$domainId}',
|
||||
pageNumber: pageNumber,
|
||||
pageSize: pageSize,
|
||||
classes: 'table table-striped table-hover table-bordered',
|
||||
uniqueId: 'RecordId',
|
||||
sidePagination: "{if $dnsconfig.type=='baidu'}client{else}server{/if}",
|
||||
columns: [
|
||||
{
|
||||
field: '',
|
||||
checkbox: true
|
||||
},
|
||||
{
|
||||
field: 'RecordId',
|
||||
visible: false,
|
||||
title: '记录ID'
|
||||
},
|
||||
{
|
||||
field: 'Name',
|
||||
title: '主机记录'
|
||||
},
|
||||
{
|
||||
field: 'Type',
|
||||
title: '记录类型'
|
||||
},
|
||||
{
|
||||
field: 'LineName',
|
||||
title: '线路类型'
|
||||
},
|
||||
{
|
||||
field: 'Value',
|
||||
title: '记录值',
|
||||
formatter: function(value, row, index) {
|
||||
if(row.Type == 'MX') return value + ' | '+row.MX;
|
||||
return value;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'TTL',
|
||||
title: 'TTL'
|
||||
},
|
||||
{
|
||||
field: 'Remark',
|
||||
visible: dnsconfig.remark > 0,
|
||||
title: '备注'
|
||||
},
|
||||
{
|
||||
field: 'UpdateTime',
|
||||
visible: false,
|
||||
title: '最后更新时间'
|
||||
},
|
||||
{
|
||||
field: 'Status',
|
||||
title: '状态',
|
||||
formatter: function(value, row, index) {
|
||||
if(value == '1'){
|
||||
return '<font color="green"><i class="fa fa-check-circle"></i>启用</font>';
|
||||
}else{
|
||||
return '<font color="orange"><i class="fa fa-pause-circle"></i>暂停</font>';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
if((row.Type == 'NS' || row.Type == 'SOA') && row.Name == '@') return '-';
|
||||
var html = '<a href="javascript:editframe(\''+row.RecordId+'\')" class="btn btn-primary btn-xs">修改</a> ';
|
||||
if(dnsconfig.status){
|
||||
if(row.Status == '1'){
|
||||
html += '<a href="javascript:setStatus(\''+row.RecordId+'\', \'0\')" class="btn btn-warning btn-xs">暂停</a> ';
|
||||
}else{
|
||||
html += '<a href="javascript:setStatus(\''+row.RecordId+'\', \'1\')" class="btn btn-success btn-xs">启用</a> ';
|
||||
}
|
||||
}
|
||||
html += '<a href="javascript:delItem(\''+row.RecordId+'\')" class="btn btn-danger btn-xs">删除</a> ';
|
||||
if(dnsconfig.remark == 1){
|
||||
html += '<a href="javascript:setRemark(\''+row.RecordId+'\')" class="btn btn-info btn-xs">备注</a>';
|
||||
}
|
||||
return html;
|
||||
}
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
$("select[name=type]").change(function(){
|
||||
if($(this).val() == 'MX'){
|
||||
$("#mx_type").show();
|
||||
}else{
|
||||
$("#mx_type").hide();
|
||||
}
|
||||
});
|
||||
|
||||
$("#form-store").bootstrapValidator();
|
||||
})
|
||||
function initLine(option){
|
||||
option = option || '';
|
||||
$("#line_list").empty();
|
||||
$.each(recordLine, function(index, item){
|
||||
if(item.parent == null){
|
||||
option += '<option value="'+item.id+'">'+item.name+'</option>';
|
||||
}
|
||||
})
|
||||
$("#line_list").append('<select name="line" class="form-control" onchange="changeLine(this)">'+option+'</select>');
|
||||
}
|
||||
function changeLine(obj){
|
||||
var line = $(obj).val();
|
||||
var flag = false;
|
||||
$("#line_list").children().each(function(index, elem){
|
||||
if(flag) $(elem).remove()
|
||||
if(obj == elem){
|
||||
flag = true;
|
||||
}
|
||||
})
|
||||
if($(obj).find("option:selected").text() == '子集线路(非必填)') return;
|
||||
var tempLine = recordLine.filter((x) => x.parent == line)
|
||||
if(tempLine.length > 0){
|
||||
var option = '<option value="'+line+'">子集线路(非必填)</option>';
|
||||
$.each(tempLine, function(index, item){
|
||||
option += '<option value="'+item.id+'">'+item.name+'</option>';
|
||||
})
|
||||
$("#line_list").append('<select name="line" class="form-control" onchange="changeLine(this)">'+option+'</select>');
|
||||
}
|
||||
}
|
||||
function addframe(){
|
||||
$("#modal-store").modal('show');
|
||||
$("#modal-title").html("添加记录");
|
||||
$("#form-store input[name=action]").val("add");
|
||||
$("#form-store input[name=recordid]").val('');
|
||||
$("#form-store input[name=name]").val('');
|
||||
$("#form-store select[name=type]").val('A');
|
||||
$("select[name=type]").change();
|
||||
initLine();
|
||||
$("#form-store input[name=value]").val('');
|
||||
$("#form-store input[name=ttl]").val('600');
|
||||
$("#form-store input[name=remark]").val('');
|
||||
$("#form-store").data("bootstrapValidator").resetForm();
|
||||
}
|
||||
function editframe(recordid){
|
||||
var row = $("#listTable").bootstrapTable('getRowByUniqueId', recordid);
|
||||
$("#modal-store").modal('show');
|
||||
$("#modal-title").html("修改记录");
|
||||
$("#form-store input[name=action]").val("update");
|
||||
$("#form-store input[name=recordid]").val(recordid);
|
||||
$("#form-store input[name=name]").val(row.Name);
|
||||
$("#form-store select[name=type]").val(row.Type);
|
||||
$("select[name=type]").change();
|
||||
initLine();
|
||||
if($('#form-store select[name=line] option[value="'+row.Line+'"]').length > 0){
|
||||
$("#form-store select[name=line]").val(row.Line);
|
||||
$("#form-store select[name=line]").change();
|
||||
}else{
|
||||
initLine('<option value="'+row.Line+'">'+row.LineName+'</option>');
|
||||
}
|
||||
$("#form-store input[name=value]").val(row.Value);
|
||||
$("#form-store input[name=mx]").val(row.MX);
|
||||
$("#form-store input[name=ttl]").val(row.TTL);
|
||||
$("#form-store input[name=remark]").val(row.Remark);
|
||||
$("#form-store").data("bootstrapValidator").resetForm();
|
||||
}
|
||||
function save(){
|
||||
$("#form-store").data("bootstrapValidator").validate();
|
||||
if(!$("#form-store").data("bootstrapValidator").isValid()){
|
||||
return;
|
||||
}
|
||||
var act = $("#form-store input[name=action]").val();
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/record/'+act+'/{$domainId}',
|
||||
data : $("#form-store").serialize(),
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.alert(data.msg,{
|
||||
icon: 1,
|
||||
closeBtn: false
|
||||
}, function(){
|
||||
layer.closeAll();
|
||||
$("#modal-store").modal('hide');
|
||||
searchSubmit();
|
||||
});
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function setStatus(recordid, status){
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/record/status/{$domainId}',
|
||||
data : {recordid: recordid, status: status},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.closeAll();
|
||||
layer.msg(status=='1'?'开启成功':'暂停成功', {icon: 1, time:500});
|
||||
searchSubmit();
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function delItem(recordid) {
|
||||
var confirmobj = layer.confirm('确定要删除此解析记录吗?', {
|
||||
btn: ['确定','取消']
|
||||
}, function(){
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/record/delete/{$domainId}',
|
||||
data : {recordid: recordid},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.closeAll();
|
||||
layer.msg('删除成功', {icon: 1, time:800});
|
||||
searchSubmit();
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, function(){
|
||||
layer.close(confirmobj);
|
||||
});
|
||||
}
|
||||
function setRemark(recordid) {
|
||||
var row = $("#listTable").bootstrapTable('getRowByUniqueId', recordid);
|
||||
layer.open({
|
||||
type: 1,
|
||||
area: ['350px'],
|
||||
closeBtn: 2,
|
||||
title: '编辑备注',
|
||||
content: '<div style="padding:15px"><div class="form-group"><input class="form-control" type="text" name="remark" value="'+(row.Remark==null?'':row.Remark)+'" autocomplete="off" placeholder="备注信息"></div></div>',
|
||||
btn: ['确认', '取消'],
|
||||
yes: function(){
|
||||
var remark = $("input[name='remark']").val();
|
||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/record/remark/{$domainId}',
|
||||
data : {recordid:recordid, remark:remark},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.closeAll();
|
||||
layer.msg('保存成功', {icon: 1, time:800});
|
||||
searchSubmit();
|
||||
}else{
|
||||
layer.alert(data.msg, {icon:2});
|
||||
}
|
||||
},
|
||||
error:function(data){
|
||||
layer.close(ii);
|
||||
layer.msg('服务器错误');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
function operation(action){
|
||||
var rows = $("#listTable").bootstrapTable('getSelections');
|
||||
if(rows.length == 0){
|
||||
layer.msg('请选择要操作的记录');
|
||||
return;
|
||||
}
|
||||
var ids = [];
|
||||
$.each(rows, function(index, item){
|
||||
ids.push(item.RecordId);
|
||||
})
|
||||
var confirmobj = layer.confirm('确定要'+(action=='open'?'启用':(action=='pause'?'暂停':'删除'))+'所选记录吗?', {
|
||||
btn: ['确定','取消']
|
||||
}, function(){
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/record/batch/{$domainId}',
|
||||
data : {action: action, recordids: ids},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.closeAll();
|
||||
layer.alert(data.msg, {icon: 1});
|
||||
searchSubmit();
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, function(){
|
||||
layer.close(confirmobj);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{/block}
|
23
app/view/index/error.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta id="viewport" name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<title>抱歉,出错了</title>
|
||||
<link href="//res.wx.qq.com/open/libs/weui/0.4.3/weui.css" rel="stylesheet">
|
||||
<style>.page{position:absolute;top:0;right:0;bottom:0;left:0;overflow-y:auto;-webkit-overflow-scrolling:touch;box-sizing:border-box}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="weui_msg">
|
||||
<div class="weui_icon_area"><i class="weui_icon_info weui_icon_msg"></i></div>
|
||||
<div class="weui_text_area">
|
||||
<h4 class="weui_msg_title">{$errmsg}</h4>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.body.addEventListener('touchmove', function (event) {
|
||||
event.preventDefault();
|
||||
},{ passive: false });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
175
app/view/index/index.html
Normal file
|
@ -0,0 +1,175 @@
|
|||
{extend name="common/layout" /}
|
||||
{block name="title"}聚合DNS管理系统{/block}
|
||||
{block name="main"}
|
||||
<style>
|
||||
.table>tbody>tr>td{white-space: normal;}
|
||||
.query-title {
|
||||
background-color:#f5fafe;
|
||||
word-break: keep-all;
|
||||
}
|
||||
.query-result{
|
||||
word-break: break-all;
|
||||
}
|
||||
</style>
|
||||
<div class="row">
|
||||
<div class="col-md-3 col-xs-6">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-aqua">
|
||||
<div class="inner">
|
||||
<h3 id="count1">0</h3>
|
||||
<p>域名数量</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-list-ul"></i>
|
||||
</div>
|
||||
<a href="/domain" class="small-box-footer">More info <i class="fa fa-arrow-circle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
<div class="col-md-3 col-xs-6">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-green">
|
||||
<div class="inner">
|
||||
<h3 id="count2">0</h3>
|
||||
<p>用户数量</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-users"></i>
|
||||
</div>
|
||||
<a href="/user" class="small-box-footer">More info <i class="fa fa-arrow-circle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
<div class="col-md-3 col-xs-6">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-yellow">
|
||||
<div class="inner">
|
||||
<h3 id="count3">0</h3>
|
||||
<p>解析数量</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-globe"></i>
|
||||
</div>
|
||||
<a href="#" class="small-box-footer">More info <i class="fa fa-arrow-circle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
<div class="col-md-3 col-xs-6">
|
||||
<!-- small box -->
|
||||
<div class="small-box bg-red">
|
||||
<div class="inner">
|
||||
<h3 id="count4">0</h3>
|
||||
<p>平台数量</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-connectdevelop"></i>
|
||||
</div>
|
||||
<a href="#" class="small-box-footer">More info <i class="fa fa-arrow-circle-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ./col -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
<div class="row">
|
||||
<div class="col-md-7 col-sm-12">
|
||||
<div id="browser-notice"></div>
|
||||
<div class="box box-primary">
|
||||
<div class="box-header with-border">
|
||||
<i class="fa fa-cloud"></i>
|
||||
<h3 class="box-title">服务器信息</h3>
|
||||
</div>
|
||||
<table class="table table-bordered">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="query-title">框架版本</td>
|
||||
<td class="query-result">{$info.framework_version}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="query-title">PHP版本</td>
|
||||
<td class="query-result">{$info.php_version}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="query-title">MySQL版本</td>
|
||||
<td class="query-result">{$info.mysql_version}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="query-title">WEB软件</td>
|
||||
<td class="query-result">{$info.software}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="query-title">操作系统</td>
|
||||
<td class="query-result">{$info.os}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="query-title">服务器时间</td>
|
||||
<td class="query-result">{$info.date}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5 col-sm-12">
|
||||
<div class="box box-default">
|
||||
<div class="box-header with-border">
|
||||
<i class="fa fa-volume-up"></i>
|
||||
<h3 class="box-title">版本信息</h3>
|
||||
</div>
|
||||
<ul class="list-group text-dark" id="checkupdate"></ul>
|
||||
</div>
|
||||
<button class="btn btn-default btn-block" onclick="cleancache()"><i class="fa fa-trash"></i>清理缓存</button><br/>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url : "/",
|
||||
data : {do: 'stat'},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
$('#count1').html(data.domains);
|
||||
$('#count2').html(data.users);
|
||||
$('#count3').html(data.records);
|
||||
$('#count4').html(data.types);
|
||||
$.ajax({
|
||||
url: '{$checkupdate}',
|
||||
type: 'get',
|
||||
dataType: 'jsonp',
|
||||
jsonpCallback: 'callback'
|
||||
}).done(function(data){
|
||||
$("#checkupdate").html(data.msg);
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
function cleancache(){
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'GET',
|
||||
url : '/cleancache',
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
layer.msg('清理缓存成功', {icon: 1});
|
||||
},
|
||||
error:function(data){
|
||||
layer.close(ii);
|
||||
layer.msg('服务器错误');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
function speedModeNotice(){
|
||||
var ua = window.navigator.userAgent;
|
||||
if(ua.indexOf('Windows NT')>-1 && ua.indexOf('Trident/')>-1){
|
||||
var html = "<div class=\"panel panel-default\"><div class=\"panel-body\">当前浏览器是兼容模式,为确保后台功能正常使用,请切换到<b style='color:#51b72f'>极速模式</b>!<br>操作方法:点击浏览器地址栏右侧的IE符号<b style='color:#51b72f;'><i class='fa fa-internet-explorer fa-fw'></i></b>→选择“<b style='color:#51b72f;'><i class='fa fa-flash fa-fw'></i></b><b style='color:#51b72f;'>极速模式</b>”</div></div>";
|
||||
$("#browser-notice").html(html)
|
||||
}
|
||||
}
|
||||
speedModeNotice();
|
||||
</script>
|
||||
{/block}
|
60
app/view/index/setpwd.html
Normal file
|
@ -0,0 +1,60 @@
|
|||
{extend name="common/layout" /}
|
||||
{block name="title"}修改密码{/block}
|
||||
{block name="main"}
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-8 col-lg-6 center-block" style="float: none;">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading"><h3 class="panel-title">修改密码</h3></div>
|
||||
<div class="panel-body">
|
||||
<form onsubmit="return saveAccount(this)" method="post" class="form" role="form">
|
||||
<div class="form-group">
|
||||
<label>旧密码:</label>
|
||||
<input type="password" name="oldpwd" value="" class="form-control" placeholder="请输入当前的密码" required/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>新密码:</label>
|
||||
<input type="password" name="newpwd" value="" class="form-control" placeholder="" required/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>重输密码:</label>
|
||||
<input type="password" name="newpwd2" value="" class="form-control" placeholder="" required/>
|
||||
</div>
|
||||
<div class="form-group text-center">
|
||||
<input type="submit" name="submit" value="确定" class="btn btn-success btn-block"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script>
|
||||
function saveAccount(obj){
|
||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/setpwd',
|
||||
data : $(obj).serialize(),
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.alert('密码修改成功!请重新登录。', {
|
||||
icon: 1,
|
||||
closeBtn: false
|
||||
}, function(){
|
||||
window.location.reload()
|
||||
});
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2})
|
||||
}
|
||||
},
|
||||
error:function(data){
|
||||
layer.close(ii);
|
||||
layer.msg('服务器错误');
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
{/block}
|
266
app/view/install/index.html
Normal file
|
@ -0,0 +1,266 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>聚合DNS管理系统 - 安装程序</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="renderer" content="webkit">
|
||||
<style>
|
||||
body {
|
||||
background: #f1f6fd;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 1.5;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
body, input, button {
|
||||
font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, 'Microsoft Yahei', Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
color: #7E96B3;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 480px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #4e73df;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 28px;
|
||||
font-weight: normal;
|
||||
color: #3C5675;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.form-group .form-field:first-child input {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.form-group .form-field:last-child input {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.form-field input {
|
||||
background: #fff;
|
||||
margin: 0 0 2px;
|
||||
border: 2px solid transparent;
|
||||
transition: background 0.2s, border-color 0.2s, color 0.2s;
|
||||
width: 100%;
|
||||
padding: 15px 15px 15px 180px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-field input:focus {
|
||||
border-color: #4e73df;
|
||||
background: #fff;
|
||||
color: #444;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.form-field label {
|
||||
float: left;
|
||||
width: 160px;
|
||||
text-align: right;
|
||||
margin-right: -160px;
|
||||
position: relative;
|
||||
margin-top: 15px;
|
||||
font-size: 14px;
|
||||
pointer-events: none;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
button, .btn {
|
||||
background: #3C5675;
|
||||
color: #fff;
|
||||
border: 0;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
padding: 15px 30px;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
button[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.form-buttons {
|
||||
height: 52px;
|
||||
line-height: 52px;
|
||||
}
|
||||
|
||||
.form-buttons .btn {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
#error, .error, #success, .success, #warmtips, .warmtips {
|
||||
background: #D83E3E;
|
||||
color: #fff;
|
||||
padding: 15px 20px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#success {
|
||||
background: #3C5675;
|
||||
}
|
||||
|
||||
#error a, .error a {
|
||||
color: white;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#warmtips {
|
||||
background: #fff;
|
||||
font-size: 14px;
|
||||
color: #3C5675;
|
||||
border: 2px solid #4e73df;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>
|
||||
<svg t="1671271578323" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2750" data-spm-anchor-id="a313x.7781069.0.i0" width="20%" height="100%"><path d="M571.904 682.496h57.344V388.096h-59.904v183.296L452.096 390.144v-2.048H392.704v294.4h59.904V497.152l117.248 183.296v2.048h2.048zM200.704 320c34.304-55.296 82.944-100.352 140.8-130.048-12.8 36.352-27.648 85.504-38.4 142.848H399.36c8.704-57.856 23.552-119.296 45.056-179.2H440.32c23.552-4.096 47.104-6.144 72.704-6.144s49.152 2.048 72.704 8.704c21.504 59.904 34.304 123.904 45.056 179.2h95.744c-10.752-57.344-25.6-104.448-38.4-140.8 55.296 29.696 102.4 74.752 136.704 128 0 4.096 2.048 6.656 2.048 10.752H947.2c-70.144-170.496-239.104-290.304-435.2-290.304C313.344 42.496 144.896 162.304 74.752 332.8h121.856c-0.512-4.096 2.048-10.752 4.096-12.8z m780.8 185.856h-177.152V448h170.496c-2.048-21.504-6.144-42.496-10.752-57.344h-217.6v177.152h177.152v59.904h-177.152v55.296h204.8c19.456-49.152 25.6-98.304 27.648-142.848v25.6l2.56-59.904zM275.456 623.104V448S271.36 388.096 215.552 388.096H59.904c-16.896 66.048-31.744 181.248 10.752 294.4h144.896c2.048 0 59.904 0 59.904-59.392z m-57.856 2.048H100.352v-179.2h117.248v179.2z m471.552 202.752c10.752-27.648 16.896-57.344 23.552-82.944h-93.696c-14.848 68.096-31.744 113.152-36.352 125.952-23.552 4.096-47.104 6.656-72.704 6.656-23.552 0-45.056-2.048-66.048-6.656-2.048-4.096-21.504-49.152-36.352-125.952H313.344c6.144 29.696 14.848 57.344 25.6 87.552-42.496-21.504-78.848-53.248-108.544-87.552H102.4c80.896 140.8 232.448 236.544 409.6 236.544 175.104 0 328.704-96.256 409.6-236.544h-132.096c-27.648 33.792-59.904 61.44-100.352 82.944z" fill="#2B85FB" p-id="2751"></path></svg>
|
||||
</svg>
|
||||
</h1>
|
||||
<h2>聚合DNS管理系统 - 安装程序</h2>
|
||||
<div>
|
||||
|
||||
<form method="post">
|
||||
<div id="error" style="display:none"></div>
|
||||
<div id="success" style="display:none"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-field">
|
||||
<label>MySQL 数据库地址</label>
|
||||
<input type="text" name="mysql_host" value="localhost" required="">
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label>MySQL 数据库端口</label>
|
||||
<input type="number" name="mysql_port" value="3306">
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label>MySQL 用户名</label>
|
||||
<input type="text" name="mysql_user" value="" required="">
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label>MySQL 密码</label>
|
||||
<input type="text" name="mysql_pwd" value="" required="">
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label>MySQL 数据库名</label>
|
||||
<input type="text" name="mysql_name" value="" required="">
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label>MySQL 数据表前缀</label>
|
||||
<input type="text" name="mysql_prefix" value="dnsmgr_">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-field">
|
||||
<label>管理员用户名</label>
|
||||
<input type="text" name="admin_username" value="admin" required=""/>
|
||||
</div>
|
||||
|
||||
<div class="form-field">
|
||||
<label>管理员密码</label>
|
||||
<input type="text" name="admin_password" value="123456" required="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<!--@formatter:off-->
|
||||
<button type="submit" >点击安装</button>
|
||||
<!--@formatter:on-->
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script src="//cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
|
||||
<script>
|
||||
$(function () {
|
||||
$('form').on('submit', function (e) {
|
||||
e.preventDefault();
|
||||
var form = this;
|
||||
var $error = $("#error");
|
||||
var $success = $("#success");
|
||||
var $button = $(this).find('button')
|
||||
.text("安装中...")
|
||||
.prop('disabled', true);
|
||||
$.ajax({
|
||||
url: "",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: $(this).serialize(),
|
||||
success: function (ret) {
|
||||
if (ret.code == 1) {
|
||||
$error.hide();
|
||||
$(".form-group", form).remove();
|
||||
$button.remove();
|
||||
$("#success").text(ret.msg).show();
|
||||
$("#warmtips").show();
|
||||
|
||||
$buttons = $(".form-buttons", form);
|
||||
$('<a class="btn" href="/" style="background:#4e73df">进入后台</a>').appendTo($buttons);
|
||||
|
||||
} else {
|
||||
$error.show().text(ret.msg);
|
||||
$button.prop('disabled', false).text("点击安装");
|
||||
$("html,body").animate({
|
||||
scrollTop: 0
|
||||
}, 500);
|
||||
}
|
||||
},
|
||||
error: function (xhr) {
|
||||
$error.show().text(xhr.responseText);
|
||||
$button.prop('disabled', false).text("点击安装");
|
||||
$("html,body").animate({
|
||||
scrollTop: 0
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
77
app/view/user/log.html
Normal file
|
@ -0,0 +1,77 @@
|
|||
{extend name="common/layout" /}
|
||||
{block name="title"}操作日志{/block}
|
||||
{block name="main"}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12 center-block" style="float: none;">
|
||||
<div class="panel panel-default panel-intro">
|
||||
<div class="panel-body">
|
||||
|
||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
|
||||
<div class="form-group">
|
||||
<label>搜索</label>
|
||||
{if request()->user['level'] eq 2}<input type="text" class="form-control" name="uid" placeholder="UID">{/if}
|
||||
<input type="text" class="form-control" name="domain" placeholder="域名">
|
||||
<input type="text" class="form-control" name="kw" placeholder="操作类型/操作详情">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
|
||||
<a href="javascript:searchClear()" class="btn btn-default" title="刷新日志列表"><i class="fa fa-refresh"></i> 刷新</a>
|
||||
</form>
|
||||
|
||||
<table id="listTable">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/bootstrap-table.min.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||
<script src="/static/js/custom.js"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
updateToolbar();
|
||||
const defaultPageSize = 15;
|
||||
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
||||
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
||||
|
||||
$("#listTable").bootstrapTable({
|
||||
url: '/log/data',
|
||||
pageNumber: pageNumber,
|
||||
pageSize: pageSize,
|
||||
classes: 'table table-striped table-hover table-bordered',
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'ID'
|
||||
},
|
||||
{
|
||||
field: 'uid',
|
||||
title: 'UID',
|
||||
formatter: function(value, row, index) {
|
||||
return value>0?'<a href="/user?kw='+value+'" target="_blank">'+value+'</a>':'管理员';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'domain',
|
||||
title: '域名'
|
||||
},
|
||||
{
|
||||
field: 'action',
|
||||
title: '操作类型'
|
||||
},
|
||||
{
|
||||
field: 'data',
|
||||
title: '操作详情'
|
||||
},
|
||||
{
|
||||
field: 'addtime',
|
||||
title: '时间'
|
||||
}
|
||||
],
|
||||
})
|
||||
})
|
||||
</script>
|
||||
{/block}
|
338
app/view/user/user.html
Normal file
|
@ -0,0 +1,338 @@
|
|||
{extend name="common/layout" /}
|
||||
{block name="title"}用户管理{/block}
|
||||
{block name="main"}
|
||||
<div class="modal" id="modal-store" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="static">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content animated flipInX">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span
|
||||
aria-hidden="true">×</span><span
|
||||
class="sr-only">Close</span></button>
|
||||
<h4 class="modal-title" id="modal-title">用户修改/添加</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" id="form-store">
|
||||
<input type="hidden" name="action"/>
|
||||
<input type="hidden" name="id"/>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label no-padding-right">用户名</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="username" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" style="display:none" id="password_input">
|
||||
<label class="col-sm-3 control-label no-padding-right">密码</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" name="password" autocomplete="off">
|
||||
<a class="input-group-addon" id="create_password" href="javascript:">随机生成</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">API接口</label>
|
||||
<div class="col-sm-9">
|
||||
<select name="is_api" class="form-control">
|
||||
<option value="0">关闭</option>
|
||||
<option value="1">开启</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" style="display:none" id="apikey_input">
|
||||
<label class="col-sm-3 control-label no-padding-right">API接口密钥</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" name="apikey" autocomplete="off" readonly>
|
||||
<a class="input-group-addon" id="create_apikey" href="javascript:">生成密钥</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">用户等级</label>
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group">
|
||||
<select name="level" class="form-control">
|
||||
<option value="1">普通用户</option>
|
||||
<option value="2">管理员</option>
|
||||
</select>
|
||||
<a tabindex="0" class="input-group-addon" role="button" data-toggle="popover" data-trigger="focus" title="" data-placement="bottom" data-content="普通用户只能管理指定的域名解析,管理员拥有和你相同的权限" data-original-title="用户权限说明"><span class="glyphicon glyphicon-info-sign"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" style="display:none" id="permission_input">
|
||||
<label class="col-sm-3 control-label">域名权限</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control select2" id="permission" name="permission[]" multiple="multiple" placeholder="留空">
|
||||
{foreach $domains as $v}
|
||||
<option value="{$v}">{$v}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" style="display:none" id="repwd_input">
|
||||
<label class="col-sm-3 control-label no-padding-right">重置密码</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" name="repwd" autocomplete="off" placeholder="不重置密码请留空">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-white" data-dismiss="modal">关闭</button>
|
||||
<button type="button" class="btn btn-primary" id="store" onclick="save()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12 center-block" style="float: none;">
|
||||
<div class="panel panel-default panel-intro">
|
||||
<div class="panel-body">
|
||||
|
||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
|
||||
<div class="form-group">
|
||||
<label>搜索</label>
|
||||
<input type="text" class="form-control" name="kw" placeholder="UID或用户名">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
|
||||
<a href="javascript:searchClear()" class="btn btn-default" title="刷新域名列表"><i class="fa fa-refresh"></i> 刷新</a>
|
||||
<a href="javascript:addframe()" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
|
||||
</form>
|
||||
|
||||
<table id="listTable">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/bootstrap-table.min.js"></script>
|
||||
<script src="{$cdnpublic}bootstrap-table/1.20.2/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||
<script src="{$cdnpublic}select2/4.0.13/js/select2.min.js"></script>
|
||||
<script src="{$cdnpublic}select2/4.0.13/js/i18n/zh-CN.min.js"></script>
|
||||
<script src="/static/js/custom.js"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
updateToolbar();
|
||||
const defaultPageSize = 15;
|
||||
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
||||
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
||||
|
||||
$("#listTable").bootstrapTable({
|
||||
url: '/user/data',
|
||||
pageNumber: pageNumber,
|
||||
pageSize: pageSize,
|
||||
classes: 'table table-striped table-hover table-bordered',
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'UID'
|
||||
},
|
||||
{
|
||||
field: 'username',
|
||||
title: '用户名'
|
||||
},
|
||||
{
|
||||
field: 'level',
|
||||
title: '用户等级',
|
||||
formatter: function(value, row, index) {
|
||||
switch(value){
|
||||
case 1: return '<font color="blue">普通用户</font>';break;
|
||||
case 2: return '<font color="orange">管理员</font>';break;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'is_api',
|
||||
title: 'API接口',
|
||||
formatter: function(value, row, index) {
|
||||
switch(value){
|
||||
case 0: return '<font color="grey">关闭</font>';break;
|
||||
case 1: return '<font color="green">开启</font>';break;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'regtime',
|
||||
title: '添加时间'
|
||||
},
|
||||
{
|
||||
field: 'lasttime',
|
||||
title: '上次登录时间'
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
title: '状态',
|
||||
formatter: function(value, row, index) {
|
||||
switch(value){
|
||||
case 0: return '<a href="javascript:setStatus('+row.id+',1)"><font color=red><i class="fa fa-times-circle"></i>封禁</font></a>';break;
|
||||
case 1: return '<a href="javascript:setStatus('+row.id+',0)"><font color=green><i class="fa fa-check-circle"></i>正常</font></a>';break;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: '',
|
||||
title: '操作',
|
||||
formatter: function(value, row, index) {
|
||||
var html = '<a href="javascript:editframe('+row.id+')" class="btn btn-info btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a>';
|
||||
return html;
|
||||
}
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
function addframe(){
|
||||
$("#modal-store").modal('show');
|
||||
$("#modal-title").html("添加用户");
|
||||
$("#form-store input[name=action]").val("add");
|
||||
$("#form-store input[name=id]").val('');
|
||||
$("#form-store input[name=username]").val('');
|
||||
$("#form-store input[name=password]").val('');
|
||||
$("#form-store select[name=is_api]").val(0);
|
||||
$("#form-store select[name=level]").val(1);
|
||||
$("#password_input").show();
|
||||
$("#repwd_input").hide();
|
||||
$("#create_apikey").click();
|
||||
$('#permission').val(null).trigger("change");
|
||||
$("select[name=is_api]").change();
|
||||
$("select[name=level]").change();
|
||||
}
|
||||
function editframe(id){
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/user/op/act/get',
|
||||
data : {id: id},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
$("#modal-store").modal('show');
|
||||
$("#modal-title").html("修改用户");
|
||||
$("#form-store input[name=action]").val("edit");
|
||||
$("#form-store input[name=id]").val(data.data.id);
|
||||
$("#form-store input[name=username]").val(data.data.username);
|
||||
$("#form-store select[name=is_api]").val(data.data.is_api);
|
||||
$("#form-store input[name=apikey]").val(data.data.apikey);
|
||||
$("#form-store select[name=level]").val(data.data.level);
|
||||
$("#form-store input[name=repwd]").val('');
|
||||
$("#password_input").hide();
|
||||
$("#repwd_input").show();
|
||||
$('#permission').val(null).trigger("change");
|
||||
if(data.data.permission != null && data.data.permission.length > 0){
|
||||
$('#permission').val(data.data.permission).trigger('change');
|
||||
}
|
||||
$("select[name=is_api]").change();
|
||||
$("select[name=level]").change();
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function save(){
|
||||
if($("#form-store input[name=username]").val()==''){
|
||||
layer.alert('请确保各项不能为空!');return false;
|
||||
}
|
||||
var act = $("#form-store input[name=action]").val();
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/user/op/act/'+act,
|
||||
data : $("#form-store").serialize(),
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.alert(data.msg,{
|
||||
icon: 1,
|
||||
closeBtn: false
|
||||
}, function(){
|
||||
layer.closeAll();
|
||||
$("#modal-store").modal('hide');
|
||||
searchSubmit();
|
||||
});
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function setStatus(id,status) {
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/user/op/act/set',
|
||||
data : {id:id, status:status},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
searchSubmit();
|
||||
}else{
|
||||
layer.msg(data.msg, {icon:2, time:1500});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
function delItem(id) {
|
||||
var confirmobj = layer.confirm('确定要删除此用户吗?', {
|
||||
btn: ['确定','取消']
|
||||
}, function(){
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '/user/op/act/del',
|
||||
data : {id: id},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.closeAll();
|
||||
searchSubmit();
|
||||
}else{
|
||||
layer.alert(data.msg, {icon: 2});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, function(){
|
||||
layer.close(confirmobj);
|
||||
});
|
||||
}
|
||||
var CreatePassword = function (len)
|
||||
{
|
||||
var str = "abcdefhjmnpqrstuvwxyz23456789ABCDEFGHJKLMNPQRSTUVWYXZ";
|
||||
var pass = '';
|
||||
for (var i = 0; i < len; i++ )
|
||||
pass += str.charAt(Math.floor( Math.random() * str.length));
|
||||
return pass;
|
||||
}
|
||||
$(document).ready(function(){
|
||||
$("select[name=is_api]").change(function(){
|
||||
if($(this).val() == 1){
|
||||
$("#apikey_input").show();
|
||||
}else{
|
||||
$("#apikey_input").hide();
|
||||
}
|
||||
});
|
||||
$("select[name=level]").change(function(){
|
||||
if($(this).val() == 2){
|
||||
$("#permission_input").hide();
|
||||
}else{
|
||||
$("#permission_input").show();
|
||||
$('#permission').select2({placeholder: '请选择该用户可管理解析的域名'});
|
||||
}
|
||||
});
|
||||
$("#create_password").click(function(){
|
||||
$("input[name='password']").val(CreatePassword(12));
|
||||
});
|
||||
$("#create_apikey").click(function(){
|
||||
$("input[name='apikey']").val(CreatePassword(16));
|
||||
});
|
||||
$('[data-toggle="popover"]').popover()
|
||||
})
|
||||
</script>
|
||||
{/block}
|
50
composer.json
Normal file
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
34
config/app.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 应用设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 应用地址
|
||||
'app_host' => 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',
|
||||
];
|
29
config/cache.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 缓存设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 默认缓存驱动
|
||||
'default' => env('cache.driver', 'file'),
|
||||
|
||||
// 缓存连接方式配置
|
||||
'stores' => [
|
||||
'file' => [
|
||||
// 驱动方式
|
||||
'type' => 'File',
|
||||
// 缓存保存目录
|
||||
'path' => '',
|
||||
// 缓存前缀
|
||||
'prefix' => '',
|
||||
// 缓存有效期 0表示永久缓存
|
||||
'expire' => 0,
|
||||
// 缓存标签前缀
|
||||
'tag_prefix' => 'tag:',
|
||||
// 序列化机制 例如 ['serialize', 'unserialize']
|
||||
'serialize' => [],
|
||||
],
|
||||
// 更多的缓存连接
|
||||
],
|
||||
];
|
39
config/captcha.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Captcha配置文件
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
//验证码位数
|
||||
'length' => 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,
|
||||
// ...
|
||||
//],
|
||||
];
|
9
config/console.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 控制台配置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 指令定义
|
||||
'commands' => [
|
||||
],
|
||||
];
|
20
config/cookie.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Cookie设置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// cookie 保存时间
|
||||
'expire' => 0,
|
||||
// cookie 保存路径
|
||||
'path' => '/',
|
||||
// cookie 有效域名
|
||||
'domain' => '',
|
||||
// cookie 启用安全传输
|
||||
'secure' => false,
|
||||
// httponly设置
|
||||
'httponly' => false,
|
||||
// 是否使用 setcookie
|
||||
'setcookie' => true,
|
||||
// samesite 设置,支持 'strict' 'lax'
|
||||
'samesite' => '',
|
||||
];
|
63
config/database.php
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
// 默认使用的数据库连接配置
|
||||
'default' => 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,
|
||||
],
|
||||
|
||||
// 更多的数据库配置信息
|
||||
],
|
||||
];
|
24
config/filesystem.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
// 默认磁盘
|
||||
'default' => 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',
|
||||
],
|
||||
// 更多的磁盘配置信息
|
||||
],
|
||||
];
|
27
config/lang.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 多语言设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 默认语言
|
||||
'default_lang' => 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,
|
||||
];
|
45
config/log.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
// +----------------------------------------------------------------------
|
||||
// | 日志设置
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 默认日志记录通道
|
||||
'default' => 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,
|
||||
],
|
||||
// 其它日志通道配置
|
||||
],
|
||||
|
||||
];
|
8
config/middleware.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
// 中间件配置
|
||||
return [
|
||||
// 别名或分组
|
||||
'alias' => [],
|
||||
// 优先级设置,此数组中的中间件会按照数组中的顺序优先执行
|
||||
'priority' => [],
|
||||
];
|
45
config/route.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 路由设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// pathinfo分隔符
|
||||
'pathinfo_depr' => '/',
|
||||
// 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',
|
||||
];
|
19
config/session.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 会话设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// session name
|
||||
'name' => 'PHPSESSID',
|
||||
// SESSION_ID的提交变量,解决flash上传跨域
|
||||
'var_session_id' => '',
|
||||
// 驱动方式 支持file cache
|
||||
'type' => 'file',
|
||||
// 存储连接标识 当type使用cache的时候有效
|
||||
'store' => null,
|
||||
// 过期时间
|
||||
'expire' => 1440,
|
||||
// 前缀
|
||||
'prefix' => '',
|
||||
];
|
10
config/trace.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | Trace设置 开启调试模式后有效
|
||||
// +----------------------------------------------------------------------
|
||||
return [
|
||||
// 内置Html和Console两种方式 支持扩展
|
||||
'type' => 'Html',
|
||||
// 读取的日志通道名
|
||||
'channel' => '',
|
||||
];
|
25
config/view.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | 模板设置
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
return [
|
||||
// 模板引擎类型使用Think
|
||||
'type' => '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' => '}',
|
||||
];
|
8
public/.htaccess
Normal file
|
@ -0,0 +1,8 @@
|
|||
<IfModule mod_rewrite.c>
|
||||
Options +FollowSymlinks -Multiviews
|
||||
RewriteEngine On
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
|
||||
</IfModule>
|
BIN
public/favicon.ico
Normal file
After Width: | Height: | Size: 16 KiB |
24
public/index.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2019 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
// [ 应用入口文件 ]
|
||||
namespace think;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// 执行HTTP应用并响应
|
||||
$http = (new App())->http;
|
||||
|
||||
$response = $http->run();
|
||||
|
||||
$response->send();
|
||||
|
||||
$http->end($response);
|
2
public/robots.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
User-agent: *
|
||||
Disallow: /
|
19
public/router.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
|
||||
if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SCRIPT_NAME"])) {
|
||||
return false;
|
||||
} else {
|
||||
$_SERVER["SCRIPT_FILENAME"] = __DIR__ . '/index.php';
|
||||
|
||||
require __DIR__ . "/index.php";
|
||||
}
|
10
public/static/css/app.min.css
vendored
Normal file
7
public/static/css/bootstrap-table.css
vendored
Normal file
1
public/static/css/select2.min.css
vendored
Normal file
242
public/static/css/skins/skin-black-blue.css
Normal file
|
@ -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 */
|
242
public/static/css/skins/skin-black-green.css
Normal file
|
@ -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 */
|
192
public/static/css/skins/skin-black-light.css
Normal file
|
@ -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 */
|
242
public/static/css/skins/skin-black-pink.css
Normal file
|
@ -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 */
|
242
public/static/css/skins/skin-black-purple.css
Normal file
|
@ -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 */
|
242
public/static/css/skins/skin-black-red.css
Normal file
|
@ -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 */
|
242
public/static/css/skins/skin-black-yellow.css
Normal file
|
@ -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 */
|
219
public/static/css/skins/skin-black.css
Normal file
|
@ -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 */
|
184
public/static/css/skins/skin-blue-light.css
Normal file
|
@ -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 */
|
230
public/static/css/skins/skin-blue.css
Normal file
|
@ -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 */
|
181
public/static/css/skins/skin-green-light.css
Normal file
|
@ -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 */
|
175
public/static/css/skins/skin-green.css
Normal file
|
@ -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 */
|
181
public/static/css/skins/skin-purple-light.css
Normal file
|
@ -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 */
|
220
public/static/css/skins/skin-purple.css
Normal file
|
@ -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 */
|
181
public/static/css/skins/skin-red-light.css
Normal file
|
@ -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 */
|
175
public/static/css/skins/skin-red.css
Normal file
|
@ -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 */
|
181
public/static/css/skins/skin-yellow-light.css
Normal file
|
@ -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 */
|
175
public/static/css/skins/skin-yellow.css
Normal file
|
@ -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 */
|
BIN
public/static/images/aliyun.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
public/static/images/baidu.ico
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
public/static/images/cloudflare.ico
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
public/static/images/dnspod.ico
Normal file
After Width: | Height: | Size: 66 KiB |
22
public/static/images/error.svg
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="1000px" height="1000px" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.7.1 (28215) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Group 3</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-2" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Group-3">
|
||||
<path d="M811.766606,296.607029 C725.516404,296.607029 655.657643,226.748269 655.657643,140.498066 C655.657643,101.665961 670.390426,66.541445 693.904339,39.2223769 C634.095092,13.9522389 568.43176,0 499.548681,0 C223.626089,0 0,223.723657 0,499.54868 C0,775.471271 223.626089,999.097361 499.548681,999.097361 C775.471273,999.097361 999.097362,775.471272 999.097361,499.54868 C999.097361,405.980871 972.851541,318.65742 928.067783,243.725117 C899.480329,275.922591 858.209022,296.607028 811.766606,296.607029 Z" id="Shape" fill="#FFC4C8"></path>
|
||||
<path d="M238.675291,767.256916 C232.468717,780.47076 238.148444,796.222193 251.355655,802.404131 C264.478533,808.562379 280.221438,802.931927 286.455491,789.773041 C289.099207,784.249664 352.329513,654.941609 499.098414,654.941609 C659.240351,654.941609 708.869257,784.171015 710.929271,789.665018 C715.974126,803.3318 731.081212,810.308748 744.787792,805.392762 C758.446046,800.396232 765.522488,785.331786 760.580917,771.641316 C759.949837,769.980228 697.138357,602.112764 499.098413,602.112764 C318.202829,602.112764 241.820271,760.519703 238.675291,767.256916" id="Shape" fill="#FF8992"></path>
|
||||
<g id="Group" transform="translate(267.388813, 340.579181)" fill="#FF8992">
|
||||
<path d="M67.8347682,135.646149 C105.298876,135.646149 135.669536,105.280725 135.669536,67.8230747 C135.669536,30.3654249 105.298876,0 67.8347682,0 C30.3706602,0 0,30.3654249 0,67.8230747 C0,105.280725 30.3706602,135.646149 67.8347682,135.646149 Z" id="Oval-1"></path>
|
||||
<ellipse id="Oval-1-Copy" cx="396.70349" cy="67.8230747" rx="67.8347682" ry="67.8230747"></ellipse>
|
||||
</g>
|
||||
<g id="Group-2" transform="translate(671.314741, 0.000000)">
|
||||
<path d="M140.582972,0 C63.016331,0 0.0849062373,62.9314257 0.0849052614,140.498066 C0.0849042856,218.064706 63.016331,280.996132 140.582972,280.996133 C218.149613,280.996134 281.081038,218.064707 281.081038,140.498066 C281.081038,62.9314248 218.149612,0 140.582972,0 L140.582972,0 Z" id="Shape" fill="#FF8992"></path>
|
||||
<path d="M140.87809,227.034331 C132.934307,227.034331 126.494024,220.60824 126.494024,212.68075 C126.494024,204.752278 132.934307,198.325203 140.87809,198.325203 C148.821872,198.325203 155.262155,204.752278 155.262155,212.68075 C155.262155,220.60824 148.821872,227.034331 140.87809,227.034331 L140.87809,227.034331 Z" id="Path" fill="#FFFFFF"></path>
|
||||
<path d="M140.87809,179.186222 C132.934307,179.186222 126.494024,172.760131 126.494024,164.831658 L126.494024,69.1354403 C126.494024,61.2079508 132.934307,54.7808765 140.87809,54.7808765 C148.821872,54.7808765 155.262155,61.2079508 155.262155,69.1354403 L155.262155,164.831658 C155.262155,172.760131 148.821872,179.186222 140.87809,179.186222 Z" id="Path" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
BIN
public/static/images/huawei.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |
18
public/static/images/info.svg
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="1000px" height="1000px" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.7.1 (28215) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Group 3</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-3" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Group-3">
|
||||
<path d="M811.766606,296.607029 C725.516404,296.607029 655.657643,226.748269 655.657643,140.498066 C655.657643,101.665961 670.390426,66.541445 693.904339,39.2223769 C634.095092,13.9522389 568.43176,0 499.548681,0 C223.626089,0 0,223.723657 0,499.54868 C0,775.471271 223.626089,999.097361 499.548681,999.097361 C775.471273,999.097361 999.097362,775.471272 999.097361,499.54868 C999.097361,405.980871 972.851541,318.65742 928.067783,243.725117 C899.480329,275.922591 858.209022,296.607028 811.766606,296.607029 Z" id="Shape" fill="#A5DBFF"></path>
|
||||
<g id="Group-2" transform="translate(671.314741, 0.000000)">
|
||||
<path d="M140.582972,0 C63.016331,0 0.0849062373,62.9314257 0.0849052614,140.498066 C0.0849042856,218.064706 63.016331,280.996132 140.582972,280.996133 C218.149613,280.996134 281.081038,218.064707 281.081038,140.498066 C281.081038,62.9314248 218.149612,0 140.582972,0 L140.582972,0 Z" id="Shape" fill="#5EB7F3"></path>
|
||||
<path d="M140.87809,227.034331 C132.934307,227.034331 126.494024,220.60824 126.494024,212.68075 C126.494024,204.752278 132.934307,198.325203 140.87809,198.325203 C148.821872,198.325203 155.262155,204.752278 155.262155,212.68075 C155.262155,220.60824 148.821872,227.034331 140.87809,227.034331 L140.87809,227.034331 Z" id="Path" fill="#FFFFFF"></path>
|
||||
<path d="M140.87809,179.186222 C132.934307,179.186222 126.494024,172.760131 126.494024,164.831658 L126.494024,69.1354403 C126.494024,61.2079508 132.934307,54.7808765 140.87809,54.7808765 C148.821872,54.7808765 155.262155,61.2079508 155.262155,69.1354403 L155.262155,164.831658 C155.262155,172.760131 148.821872,179.186222 140.87809,179.186222 Z" id="Path" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
<path d="M325.314744,308.474056 C318.121595,301.280319 306.453832,301.280319 299.267743,308.474056 C292.071653,315.668382 292.071653,327.33085 299.267743,334.527528 L325.314744,360.574529 C332.510834,367.769443 344.168596,367.769443 351.365275,360.574529 C358.558424,353.384322 358.558424,341.723619 351.365275,334.527528 L325.314744,308.474056 L325.314744,308.474056 L325.314744,308.474056 Z M675.316427,308.474056 L649.26825,334.527528 C642.073924,341.723619 642.073924,353.384322 649.26825,360.574529 C656.454339,367.769443 668.11916,367.769443 675.316427,360.574529 L701.362251,334.527528 C708.560107,327.331438 708.560107,315.668971 701.362251,308.474056 C694.170867,301.283849 682.510753,301.283849 675.316427,308.474056 L675.316427,308.474056 L675.316427,308.474056 Z M279.264353,454.262547 L242.422039,454.262547 C232.249148,454.262547 224,462.509931 224,472.682821 C224,482.858653 232.24856,491.10486 242.422039,491.10486 L279.264353,491.10486 C289.437243,491.10486 297.68345,482.858653 297.68345,472.682821 C297.68345,462.510519 289.437243,454.262547 279.264353,454.262547 L279.264353,454.262547 L279.264353,454.262547 Z M758.20972,454.262547 L721.367995,454.262547 C711.195693,454.262547 702.946544,462.509931 702.946544,472.682821 C702.946544,482.858653 711.195693,491.10486 721.367995,491.10486 L758.20972,491.10486 C768.382022,491.10486 776.634113,482.858653 776.634113,472.682821 C776.634113,462.510519 768.382023,454.262547 758.20972,454.262547 L758.20972,454.262547 L758.20972,454.262547 Z M481.895605,242.421451 L481.895605,279.262588 C481.895605,289.436655 490.140635,297.681685 500.313526,297.681685 C510.486417,297.681685 518.737919,289.436655 518.737919,279.262588 L518.737919,242.421451 C518.737919,232.24856 510.486417,224 500.313526,224 C490.140635,224 481.895605,232.24856 481.895605,242.421451 L481.895605,242.421451 L481.895605,242.421451 Z M371.368077,500.314703 C371.368077,429.100938 429.09682,371.368077 500.313526,371.368077 C571.533174,371.368077 629.26427,429.100938 629.26427,500.314703 C629.26427,571.530822 571.532586,629.265447 500.313526,629.265447 C429.09682,629.266036 371.368077,571.530822 371.368077,500.314703 L371.368077,500.314703 L371.368077,500.314703 Z M334.527528,500.314703 C334.527528,591.885428 408.749862,666.112467 500.313526,666.112467 C591.881897,666.112467 666.104819,591.885427 666.104819,500.314703 C666.104819,408.748685 591.881897,334.52694 500.313526,334.52694 C408.749273,334.527528 334.527528,408.749273 334.527528,500.314703 L334.527528,500.314703 L334.527528,500.314703 Z M463.473566,758.215603 C463.473566,768.381434 471.722126,776.637054 481.895605,776.637054 L518.737919,776.637054 C528.911398,776.637054 537.159958,768.382022 537.159958,758.215603 C537.159958,748.036241 528.911398,739.793564 518.737919,739.793564 L481.895605,739.793564 C471.722715,739.793564 463.473566,748.036241 463.473566,758.215603 L463.473566,758.215603 L463.473566,758.215603 Z M426.633018,702.953604 C426.633018,713.118259 434.879225,721.373878 445.052115,721.373878 L555.579056,721.373878 C565.751947,721.373878 574.000507,713.118847 574.000507,702.953604 C574.000507,692.771889 565.751947,684.528624 555.579056,684.528624 L445.052115,684.528624 C434.878636,684.528035 426.633018,692.771889 426.633018,702.953604 L426.633018,702.953604 L426.633018,702.953604 Z" id="Shape" fill="#5EB7F3"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.5 KiB |
BIN
public/static/images/login-head.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
public/static/images/logo.png
Normal file
After Width: | Height: | Size: 8.9 KiB |
18
public/static/images/success.svg
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="1000px" height="1000px" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.7.1 (28215) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Group 2</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Group-2">
|
||||
<path d="M928.424049,243.818679 C899.825622,276.028512 858.538471,296.72089 812.078227,296.720891 C725.794915,296.720891 655.909337,226.835313 655.909337,140.552 C655.909337,101.704989 670.647776,66.5669889 694.170715,39.2374336 C634.338509,13.9575949 568.649969,5.68434189e-14 499.740447,5.68434189e-14 C223.711934,5.68434189e-14 0,223.80954 0,499.740447 C0,775.768959 223.711934,999.480894 499.740447,999.480894 C775.768961,999.480894 999.480895,775.76896 999.480894,499.740447 C999.480894,406.136718 973.225,318.779746 928.424049,243.818679 L928.424049,243.818679 Z" id="Shape" fill="#E3FCD9"></path>
|
||||
<path d="M812.078227,0.195211166 C734.481809,0.195211166 671.526226,63.150795 671.526225,140.747211 C671.526224,218.343628 734.481809,281.299212 812.078227,281.299213 C889.674644,281.299214 952.630227,218.343629 952.630227,140.747211 C952.630227,63.150794 889.674643,0.195211166 812.078227,0.195211166 L812.078227,0.195211166 Z M894.35971,102.193017 L796.949365,199.603362 C791.385848,205.166879 782.308531,205.166879 776.842621,199.603362 L729.796742,152.557484 C724.233226,146.993968 724.233226,137.916651 729.796742,132.450739 C735.360259,126.887223 744.437576,126.887223 749.903487,132.450739 L781.527688,164.074939 C784.455854,167.003106 789.238526,167.003106 792.166693,164.074939 L874.15536,82.0862722 C879.718877,76.5227555 888.796193,76.5227555 894.262105,82.0862722 C899.923227,87.5521829 899.923227,96.6294997 894.35971,102.193017 L894.35971,102.193017 Z" id="Shape" fill="#9AD388"></path>
|
||||
<g id="Group" transform="translate(222.536413, 340.709923)" fill="#9AD388">
|
||||
<ellipse id="Oval-1" cx="112.815854" cy="67.8491107" rx="67.8608086" ry="67.8491107"></ellipse>
|
||||
<ellipse id="Oval-1-Copy" cx="441.810822" cy="67.8491107" rx="67.8608086" ry="67.8491107"></ellipse>
|
||||
<path d="M2.6939078,297.641001 C-3.83805327,283.709963 2.13943932,267.103606 16.0390529,260.586137 C29.8499119,254.093644 46.4181552,260.029694 52.9790356,273.902791 C55.7613514,279.725955 122.306574,416.052327 276.769992,416.052327 C445.307541,416.052327 497.538297,279.808873 499.706308,274.016677 C505.015645,259.608118 520.914737,252.25249 535.339899,257.435296 C549.714202,262.703017 557.161634,278.5851 551.960996,293.018633 C551.29683,294.769878 485.192391,471.748507 276.769991,471.748507 C86.3907615,471.748507 6.0037667,304.743882 2.6939078,297.641001 Z" id="Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
BIN
public/static/images/user.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
public/static/images/west.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |