This commit is contained in:
阿九 2025-07-03 12:33:52 +08:00 committed by GitHub
commit a1c5876152
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
84 changed files with 13325 additions and 11744 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

BIN
app/.DS_Store vendored Normal file

Binary file not shown.

BIN
app/view/.DS_Store vendored Normal file

Binary file not shown.

310
app/view/auth/login.html Normal file → Executable file
View File

@ -1,180 +1,178 @@
<!DOCTYPE html>
<html lang="zh-cn">
<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]>
<meta charset="utf-8" />
<title>管理中心登录 | 聚合DNS管理系统</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<link rel="stylesheet" href="{$cdnpublic}twitter-bootstrap/3.4.1/css/bootstrap.min.css" type="text/css" />
<link rel="stylesheet" href="{$cdnpublic}animate.css/3.5.2/animate.min.css" type="text/css" />
<link rel="stylesheet" href="{$cdnpublic}font-awesome/4.7.0/css/font-awesome.min.css" type="text/css" />
<link rel="stylesheet" href="{$cdnpublic}simple-line-icons/2.4.1/css/simple-line-icons.min.css" type="text/css" />
<link rel="stylesheet" href="/static/css/font.css" type="text/css" />
<link rel="stylesheet" href="/static/css/app.css" type="text/css" />
<!--[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}
#totp-form{margin-top:20px}
#totp-form .input-group{margin-bottom:15px}
#totp-form .form-control{font-size:14px}
</style>
<![endif]-->
<style>input:-webkit-autofill{-webkit-box-shadow:0 0 0px 1000px white inset;-webkit-text-fill-color:#333;}</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>
{if config_get('vcode', '1')=='1'}<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>{/if}
<div class="form-group">
<button type="submit" class="btn btn-success btn-lg btn-block" id="submit" style="background:#708eea;">登 录</button>
</div>
<div class="pull-right"><a href="javascript:findpwd()">忘记密码</a></div>
</form>
<form action="" id="totp-form" onsubmit="return doTotp()" style="display:none;">
<div class="alert alert-info" role="alert">TOTP二次验证</div>
<div class="input-group">
<div class="input-group-addon"><span class="glyphicon glyphicon-lock" aria-hidden="true"></span></div>
<input type="number" class="form-control input-lg" placeholder="输入动态口令" name="totp_code" id="totp_code" autocomplete="off" required="required"/>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success btn-lg btn-block" id="submit" style="background:#708eea;">登 录</button>
</div>
<div class="pull-right"><a href="javascript:findpwd()">忘记密码</a></div>
</form>
</div>
<div class="modal inmodal fade" id="modal-findpwd" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">关闭</span>
</button>
<h4 class="modal-title">忘记密码</h4>
</div>
<div class="modal-body">
<strong>重置密码</strong>
<p>进入网站根目录,执行命令:<br/><code>php think reset pwd 用户名 密码</code></p>
<strong>关闭TOTP</strong>
<p>进入网站根目录,执行命令:<br/><code>php think reset totp 用户名</code></p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">关闭</button>
</div>
</div>
</div>
</div>
<div class="modal" id="modal-findpwd">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">忘记密码</h4>
</div>
<div class="modal-body">
<strong>重置密码</strong>
<p>进入网站根目录,执行命令:<br/><code>php think reset pwd 用户名 密码</code></p>
<strong>关闭TOTP</strong>
<p>进入网站根目录,执行命令:<br/><code>php think reset totp 用户名</code></p>
</div>
</div>
</div>
<div class="app app-header-fixed ">
<div class="container w-xxl w-auto-xs" ng-controller="SigninFormController" ng-init="app.settings.container = false;">
<span class="navbar-brand block m-t">聚合DNS管理系统</span>
<div class="m-b-lg">
<div class="wrapper text-center">
<strong>管理中心登录</strong>
</div>
<div class="text-danger wrapper text-center" ng-show="authError"></div>
<form action="" class="form-validation" id="login-form" onsubmit="return doLogin()">
<div class="tab-content">
<div class="tab-pane active">
<div class="list-group list-group-sm swaplogin">
<div class="list-group-item">
<input type="text" class="form-control no-border" placeholder="用户名" name="username" required="required"/>
</div>
<div class="list-group-item">
<input type="password" class="form-control no-border" placeholder="密码" name="password" required="required"/>
</div>
{if config_get('vcode', '1')=='1'}
<div class="list-group-item">
<div class="input-group">
<input type="text" name="code" class="form-control no-border" placeholder="输入验证码" autocomplete="off" required="required"/>
<span class="input-group-addon" style="padding: 0">
<img id="verifycode" src="/verifycode" height="33" onclick="this.src='/verifycode?r='+Math.random();" title="点击更换验证码">
</span>
</div>
</div>
{/if}
</div>
<button type="submit" class="btn btn-lg btn-primary btn-block" id="submit">立即登录</button>
</div>
</div>
<div class="line line-dashed"></div>
<div class="form-group">
<a href="javascript:findpwd()" class="btn btn-info btn-rounded"><i class="fa fa-unlock"></i>&nbsp;找回密码</a>
</div>
</form>
<form action="" class="form-validation" id="totp-form" onsubmit="return doTotp()" style="display:none;">
<div class="tab-content">
<div class="tab-pane active">
<div class="list-group list-group-sm swaplogin">
<div class="list-group-item">
<input type="number" class="form-control no-border" placeholder="输入动态口令" name="totp_code" id="totp_code" autocomplete="off" required="required"/>
</div>
</div>
<button type="submit" class="btn btn-lg btn-primary btn-block" id="submit">立即登录</button>
</div>
</div>
<div class="line line-dashed"></div>
<div class="form-group">
<a href="javascript:findpwd()" class="btn btn-info btn-rounded"><i class="fa fa-unlock"></i>&nbsp;找回密码</a>
</div>
</form>
</div>
<div class="text-center">
<p>
<small class="text-muted"><a href="/">聚合DNS管理系统</a><br>&copy; 2016~2024</small>
</p>
</div>
</div>
</div>
<script src="{$cdnpublic}jquery/3.4.1/jquery.min.js"></script>
<script src="{$cdnpublic}twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}layer/3.1.1/layer.min.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});
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())
}else if(data.vcode==2){
$("#totp-form").show();
$("#login-form").hide();
$("#totp_code").focus();
return false;
}
layer.alert(data.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){
function doTotp(){
var code = $("#totp_code").val();
if(code.length != 6){
layer.msg('动态口令格式错误', {icon: 2});
return false;
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/auth/totp', {code:code}, function(res){
layer.close(ii);
if(data.code == 0){
if(res.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())
}else if(data.vcode==2){
$("#totp-form").show();
$("#login-form").hide();
$("#totp_code").focus();
return false;
}
layer.alert(data.msg, {icon: 2});
layer.alert(res.msg, {icon: 2});
}
}
});
return false;
}
function findpwd(){
$('#modal-findpwd').modal('show');
}
$(document).ready(function(){
$("#totp_code").keyup(function(){
var code = $(this).val();
if(code.length == 6){
$("#totp-form").submit();
}
});
});
return false;
}
function doTotp(){
var code = $("#totp_code").val();
if(code.length != 6){
layer.msg('动态口令格式错误', {icon: 2});
return false;
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/auth/totp', {code:code}, function(res){
layer.close(ii);
if(res.code == 0){
layer.msg('登录成功,正在跳转到首页', {icon: 1,shade: 0.01,time: 15000});
window.location.href = '/';
}else{
layer.alert(res.msg, {icon: 2});
}
});
return false;
}
function findpwd(){
$('#modal-findpwd').modal('show');
}
$(document).ready(function(){
$("#totp_code").keyup(function(){
var code = $(this).val();
if(code.length == 6){
$("#totp-form").submit();
}
});
});
</script>
</body>
</html>

597
app/view/cert/account_form.html Normal file → Executable file
View File

@ -2,339 +2,338 @@
{block name="title"}{$title}{/block}
{block name="main"}
<style>
.tips{color: #f6a838; padding-left: 5px;}
.input-note{color: green;}
.control-label[is-required]:before {
content: "*";
color: #f56c6c;
margin-right: 4px;
}
/* 账户类型卡片样式 */
.account-type-container {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin-bottom: 20px;
}
.account-type-category {
width: 100%;
margin-bottom: 10px;
font-size: 18px;
font-weight: bold;
color: #333;
border-bottom: 1px solid #eee;
padding-bottom: 5px;
}
.account-type-card {
width: calc(25% - 15px);
min-width: 200px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s;
background: #fff;
height: 100px;
overflow: hidden;
}
.account-type-card:hover {
border-color: #409EFF;
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
}
.account-type-card .icon {
width: 30px;
margin: 11px 8px;
float: left;
}
.account-type-card .content {
margin-left: 38px;
}
.account-type-card .title {
font-size: 14px;
font-weight: bold;
margin-bottom: 3px;
color: #333;
}
.account-type-card .desc {
font-size: 12px;
color: #999;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
@media (max-width: 768px) {
.account-type-card {
width: calc(50% - 15px);
.tips{color: #f6a838; padding-left: 5px;}
.input-note{color: green;}
.control-label[is-required]:before {
content: "*";
color: #f56c6c;
margin-right: 4px;
}
}
@media (max-width: 480px) {
.account-type-card {
/* 账户类型卡片样式 */
.account-type-container {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin-bottom: 20px;
}
.account-type-category {
width: 100%;
height: 78px;
margin-bottom: 10px;
font-size: 18px;
font-weight: bold;
color: #333;
border-bottom: 1px solid #eee;
padding-bottom: 5px;
}
.account-type-card {
width: calc(25% - 15px);
min-width: 200px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s;
background: #fff;
height: 100px;
overflow: hidden;
}
.account-type-card:hover {
border-color: #409EFF;
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
}
.account-type-card .icon {
width: 30px;
margin: 11px 8px;
float: left;
}
.account-type-card .content {
margin-left: 38px;
}
.account-type-card .title {
font-size: 14px;
font-weight: bold;
margin-bottom: 3px;
color: #333;
}
.account-type-card .desc {
-webkit-line-clamp: 1;
font-size: 12px;
color: #999;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
@media (max-width: 768px) {
.account-type-card {
width: calc(50% - 15px);
}
}
@media (max-width: 480px) {
.account-type-card {
width: 100%;
height: 78px;
}
.account-type-card .desc {
-webkit-line-clamp: 1;
}
}
}
</style>
<div class="row" id="app">
<div class="col-xs-12 center-block" style="float: none;">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title"><a href="javascript:window.history.back()" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}编辑{else}添加{/if}{$title}</h3></div>
<div class="panel-body">
<!-- 账户类型选择视图 -->
<div id="account-type-view" v-if="!selectedType">
<div v-for="(category, classId) in groupedTypes" :key="classId">
<div class="account-type-category">{{ category.label }}</div>
<div class="account-type-container">
<div class="account-type-card" v-for="type in category.types" :key="type.value" @click="selectType(type.value)">
<img class="icon" :src="'/static/images/' + typeList[type.value].icon" :alt="type.label">
<div class="content">
<div class="title">{{ type.label }}</div>
<div class="desc">{{ typeList[type.value].desc || ''}}</div>
</div>
</div>
</div>
</div>
</div>
<!-- 表单视图 -->
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="accountform" v-if="selectedType">
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" is-required>账户类型</label>
<div class="col-sm-6">
<div class="form-control-static">
{{ typeList[set.type].name }}
<a href="javascript:;" @click="selectedType = false" class="pull-right btn btn-default" v-if="action=='add'">重新选择</a>
</div>
<input type="hidden" name="type" v-model="set.type">
</div>
</div>
<div v-for="(item,name) in inputs" v-show="isShow(item.show)">
<div class="form-group" v-if="item.type=='input'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<input type="text" class="form-control" :name="name" v-model="config[name]" :placeholder="item.placeholder" :required="item.required" :disabled="item.disabled" :data-bv-id="item.validator=='id'" :data-bv-phone="item.validator=='phone'" :data-bv-numeric="item.validator=='numeric'" :data-bv-digits="item.validator=='digits'" :data-bv-integer="item.validator=='integer'" :data-bv-email="item.validator=='email'" :data-bv-uri="item.validator=='uri'" :min="item.min" :max="item.max"><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='textarea'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<textarea class="form-control" :name="name" v-model="config[name]" :placeholder="item.placeholder" :required="item.required" :disabled="item.disabled"></textarea><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='select'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<select class="form-control" :name="name" v-model="config[name]" :required="item.required" :disabled="item.disabled" :placeholder="item.placeholder">
<option v-for="option in item.options" :value="option.value">{{option.label}}</option>
</select><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='radio'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="(optionname, optionvalue) in item.options">
<input type="radio" :name="name" :value="optionvalue" v-model="config[name]" :disabled="item.disabled"> {{optionname}}
</label><br/><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='checkbox'">
<div class="col-sm-offset-3 col-sm-7">
<div class="checkbox">
<label>
<input type="checkbox" :name="name" v-model="config[name]" :disabled="item.disabled"> {{item.name}}
</label>
<div id="app">
<div class="panel panel-default">
<div class="panel-heading font-bold"><h3 class="panel-title"><a href="javascript:window.history.back()" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}编辑{else}添加{/if}{$title}</h3></div>
<div class="panel-body">
<!-- 账户类型选择视图 -->
<div id="account-type-view" v-if="!selectedType">
<div v-for="(category, classId) in groupedTypes" :key="classId">
<div class="account-type-category">{{ category.label }}</div>
<div class="account-type-container">
<div class="account-type-card" v-for="type in category.types" :key="type.value" @click="selectType(type.value)">
<img class="icon" :src="'/static/images/' + typeList[type.value].icon" :alt="type.label">
<div class="content">
<div class="title">{{ type.label }}</div>
<div class="desc">{{ typeList[type.value].desc || ''}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="form-group" v-if="item.type=='checkboxes'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<label class="checkbox-inline" v-for="(optionname, optionvalue) in item.options">
<input type="checkbox" :name="name" :value="optionvalue" v-model="config[name]" :disabled="item.disabled"> {{optionname}}
</label><br/><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
<!-- 表单视图 -->
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="accountform" v-if="selectedType">
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" is-required>账户类型</label>
<div class="col-sm-6">
<div class="form-control-static">
{{ typeList[set.type].name }}
<a href="javascript:;" @click="selectedType = false" class="pull-right btn btn-default" v-if="action=='add'">重新选择</a>
</div>
<input type="hidden" name="type" v-model="set.type">
</div>
</div>
<div v-for="(item,name) in inputs" v-show="isShow(item.show)">
<div class="form-group" v-if="item.type=='input'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<input type="text" class="form-control" :name="name" v-model="config[name]" :placeholder="item.placeholder" :required="item.required" :disabled="item.disabled" :data-bv-id="item.validator=='id'" :data-bv-phone="item.validator=='phone'" :data-bv-numeric="item.validator=='numeric'" :data-bv-digits="item.validator=='digits'" :data-bv-integer="item.validator=='integer'" :data-bv-email="item.validator=='email'" :data-bv-uri="item.validator=='uri'" :min="item.min" :max="item.max"><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='textarea'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<textarea class="form-control" :name="name" v-model="config[name]" :placeholder="item.placeholder" :required="item.required" :disabled="item.disabled"></textarea><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='select'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<select class="form-control" :name="name" v-model="config[name]" :required="item.required" :disabled="item.disabled" :placeholder="item.placeholder">
<option v-for="option in item.options" :value="option.value">{{option.label}}</option>
</select><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='radio'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="(optionname, optionvalue) in item.options">
<input type="radio" :name="name" :value="optionvalue" v-model="config[name]" :disabled="item.disabled"> {{optionname}}
</label><br/><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='checkbox'">
<div class="col-sm-offset-3 col-sm-7">
<div class="checkbox">
<label>
<input type="checkbox" :name="name" v-model="config[name]" :disabled="item.disabled"> {{item.name}}
</label>
</div>
</div>
</div>
<div class="form-group" v-if="item.type=='checkboxes'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<label class="checkbox-inline" v-for="(optionname, optionvalue) in item.options">
<input type="checkbox" :name="name" :value="optionvalue" v-model="config[name]" :disabled="item.disabled"> {{optionname}}
</label><br/><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">备注</label>
<div class="col-sm-6">
<input type="text" name="remark" v-model="set.remark" placeholder="可留空" class="form-control">
</div>
</div>
<div class="form-group" v-show="note">
<div class="col-sm-offset-3 col-sm-6">
<div class="alert alert-dismissible alert-info">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<strong>提示:</strong><span v-html="note"></span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">提交</button></div>
</div>
</form>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">备注</label>
<div class="col-sm-6">
<input type="text" name="remark" v-model="set.remark" placeholder="可留空" class="form-control">
</div>
</div>
<div class="form-group" v-show="note">
<div class="col-sm-offset-3 col-sm-6">
<div class="alert alert-dismissible alert-info">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<strong>提示:</strong><span v-html="note"></span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">提交</button></div>
</div>
</form>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}vue/2.6.14/vue.min.js"></script>
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="/static/js/bootstrapValidator.min.js"></script>
<script>
var info = {$info|json_encode|raw};
var typeList = {$typeList|json_encode|raw};
var classList = {$classList|json_encode|raw};
new Vue({
el: '#app',
data: {
action: '{$action}',
selectedType: false,
set: {
deploy: '{$deploy}',
id: '',
type: '',
name: '',
config : '',
remark: '',
var info = {$info|json_encode|raw};
var typeList = {$typeList|json_encode|raw};
var classList = {$classList|json_encode|raw};
new Vue({
el: '#app',
data: {
action: '{$action}',
selectedType: false,
set: {
deploy: '{$deploy}',
id: '',
type: '',
name: '',
config : '',
remark: '',
},
inputs: {},
config: {},
typeList: typeList,
classList: classList,
note: '',
typeOption: [],
},
inputs: {},
config: {},
typeList: typeList,
classList: classList,
note: '',
typeOption: [],
},
watch: {
'set.type': function(val){
if(this.action == 'add' && val && typeList[val]){
this.inputs = typeList[val].inputs;
this.note = typeList[val].note;
this.config = {};
watch: {
'set.type': function(val){
if(this.action == 'add' && val && typeList[val]){
this.inputs = typeList[val].inputs;
this.note = typeList[val].note;
this.config = {};
$.each(this.inputs, (name, item) => {
if(typeof item.value == 'undefined'){
if(item.type == 'checkbox'){
item.value = false;
}else if(item.type == 'checkboxes'){
item.value = [];
}else{
item.value = null;
}
}
this.$set(this.config, name, item.value)
})
}
}
},
computed: {
groupedTypes() {
return Object.keys(classList).map((key) => {
var tempList = [];
Object.keys(typeList).forEach((key2) => {
if(typeList[key2].class == key){
tempList.push({label: typeList[key2].name, value: key2})
}
})
return {label: classList[key], types: tempList}
})
}
},
mounted() {
this.typeOption = this.groupedTypes;
if(this.action == 'edit') {
this.selectedType = true;
}
if(this.action == 'edit'){
Object.keys(info).forEach((key) => {
this.set[key] = info[key]
})
var config = JSON.parse(info.config);
this.inputs = typeList[this.set.type].inputs;
this.note = typeList[this.set.type].note;
$.each(this.inputs, (name, item) => {
item.value = config[name];
if(typeof item.value == 'undefined'){
if(typeof config[name] != 'undefined'){
item.value = config[name];
}
if(item.type == 'checkbox'){
item.value = false;
item.value = false;
}else if(item.type == 'checkboxes'){
item.value = [];
item.value = [];
}else{
item.value = null;
}
}
this.$set(this.config, name, item.value)
})
}else{
this.set.type = Object.keys(typeList)[0]
}
}
},
computed: {
groupedTypes() {
return Object.keys(classList).map((key) => {
var tempList = [];
Object.keys(typeList).forEach((key2) => {
if(typeList[key2].class == key){
tempList.push({label: typeList[key2].name, value: key2})
}
})
return {label: classList[key], types: tempList}
})
}
},
mounted() {
this.typeOption = this.groupedTypes;
if(this.action == 'edit') {
this.selectedType = true;
}
if(this.action == 'edit'){
Object.keys(info).forEach((key) => {
this.set[key] = info[key]
})
var config = JSON.parse(info.config);
this.inputs = typeList[this.set.type].inputs;
this.note = typeList[this.set.type].note;
$.each(this.inputs, (name, item) => {
if(typeof config[name] != 'undefined'){
item.value = config[name];
}
if(typeof item.value == 'undefined'){
if(item.type == 'checkbox'){
item.value = false;
}else if(item.type == 'checkboxes'){
item.value = [];
}else{
item.value = null;
}
}
this.$set(this.config, name, item.value)
})
}else{
this.set.type = Object.keys(typeList)[0]
}
this.$nextTick(function () {
$('[data-toggle="tooltip"]').tooltip();
})
},
methods: {
selectType(type) {
this.set.type = type;
this.selectedType = true;
},
submit(){
var that=this;
Object.keys(this.config).forEach((key) => {
if(this.config[key] && typeof this.config[key] == 'string'){
this.config[key] = this.trim(this.config[key]);
}
this.$nextTick(function () {
$('[data-toggle="tooltip"]').tooltip();
})
this.set.config = JSON.stringify(this.config);
this.set.name = this.config[Object.keys(this.config)[0]];
let loading = layer.msg('正在进行账户有效性检查', {icon: 16,shade: 0.1,time: 0});
$.ajax({
type: "POST",
url: "",
data: this.set,
dataType: 'json',
success: function(data) {
layer.close(loading);
if(data.code == 0){
layer.alert(data.msg, {icon: 1}, function(){
if(data.msg.indexOf('自动部署账户')>0){
window.location.href = '/cert/deployaccount';
}else{
window.location.href = '/cert/certaccount';
}
});
}else{
layer.alert(data.msg, {icon: 2});
}
},
error: function(data){
layer.close(loading);
layer.msg('服务器错误');
}
});
},
isShow(show){
if(typeof show == 'boolean' && show){
return show;
}else if(typeof show == 'string' && show){
methods: {
selectType(type) {
this.set.type = type;
this.selectedType = true;
},
submit(){
var that=this;
Object.keys(this.config).forEach((key) => {
show = show.replace(new RegExp(key, 'g'), 'that.config["'+key+'"]')
if(this.config[key] && typeof this.config[key] == 'string'){
this.config[key] = this.trim(this.config[key]);
}
})
return eval(show);
}else{
return true;
this.set.config = JSON.stringify(this.config);
this.set.name = this.config[Object.keys(this.config)[0]];
let loading = layer.msg('正在进行账户有效性检查', {icon: 16,shade: 0.1,time: 0});
$.ajax({
type: "POST",
url: "",
data: this.set,
dataType: 'json',
success: function(data) {
layer.close(loading);
if(data.code == 0){
layer.alert(data.msg, {icon: 1}, function(){
if(data.msg.indexOf('自动部署账户')>0){
window.location.href = '/cert/deployaccount';
}else{
window.location.href = '/cert/certaccount';
}
});
}else{
layer.alert(data.msg, {icon: 2});
}
},
error: function(data){
layer.close(loading);
layer.msg('服务器错误');
}
});
},
isShow(show){
if(typeof show == 'boolean' && show){
return show;
}else if(typeof show == 'string' && show){
var that=this;
Object.keys(this.config).forEach((key) => {
show = show.replace(new RegExp(key, 'g'), 'that.config["'+key+'"]')
})
return eval(show);
}else{
return true;
}
},
trim(str){
return str.replace(/(^\s*)|(\s*$)/g, "");
}
},
trim(str){
return str.replace(/(^\s*)|(\s*$)/g, "");
}
},
});
});
</script>
{/block}
{/block}

156
app/view/cert/certaccount.html Normal file → Executable file
View File

@ -1,93 +1,91 @@
{extend name="common/layout" /}
{block name="title"}SSL证书账户管理{/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>
<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="刷新SSL证书账户列表"><i class="fa fa-refresh"></i> 刷新</a>
<a href="/cert/account/add?deploy=0" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
</form>
<table id="listTable">
</table>
<style>
#orderItem .orderTitle{word-break:keep-all;}
#orderItem .orderContent{word-break:break-all;}
.fixed-table-toolbar,.fixed-table-pagination{padding: 15px;}
</style>
<div class="panel panel-default">
<div class="panel-heading font-bold">
<h3 class="panel-title">SSL证书账户管理</h3>
</div>
</div>
</div>
<form class="form-inline" id="searchToolbar" method="GET" onsubmit="return searchSubmit()">
<div class="form-group">
<input type="text" class="form-control" name="kw" placeholder="账户名称或备注">
</div>
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
<a class="btn btn-default" href="javascript:searchClear()" title="刷新SSL证书账户列表"><i class="fa fa-refresh"></i> 刷新</a>
<a class="btn btn-success" href="/cert/account/add?deploy=0"><i class="fa fa-plus"></i> 添加</a>
</form>
<table id="listTable">
</table>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/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;
$(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: '/cert/account/data?deploy=0',
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.icon+'" class="type-logo"></img>'+value;
}
},
{
field: 'name',
title: '账户名称'
},
{
field: 'remark',
title: '备注'
},
{
field: 'addtime',
title: '添加时间'
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var html = '<a href="/cert/account/edit?deploy=0&id='+row.id+'" class="btn btn-info btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a> <a href="/cert/certorder?aid='+row.id+'" class="btn btn-default btn-xs">订单</a>';
return html;
}
},
]
})
})
function delItem(id){
layer.confirm('确定要删除此账户吗?', {
btn: ['确定','取消']
}, function(){
$.post('/cert/account/del', {id: id, deploy: 0}, function(data){
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.alert(data.msg, {icon: 2});
}
}, 'json');
});
}
$("#listTable").bootstrapTable({
url: '/cert/account/data?deploy=0',
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.icon+'" class="type-logo"></img>'+value;
}
},
{
field: 'name',
title: '账户名称'
},
{
field: 'remark',
title: '备注'
},
{
field: 'addtime',
title: '添加时间'
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var html = '<a href="/cert/account/edit?deploy=0&id='+row.id+'" class="btn btn-info btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a> <a href="/cert/certorder?aid='+row.id+'" class="btn btn-default btn-xs">订单</a>';
return html;
}
},
]
})
})
function delItem(id){
layer.confirm('确定要删除此账户吗?', {
btn: ['确定','取消']
}, function(){
$.post('/cert/account/del', {id: id, deploy: 0}, function(data){
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.alert(data.msg, {icon: 2});
}
}, 'json');
});
}
</script>
{/block}

900
app/view/cert/certorder.html Normal file → Executable file
View File

@ -2,471 +2,477 @@
{block name="title"}SSL证书订单列表{/block}
{block name="main"}
<style>
tbody tr>td:nth-child(5){overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:180px;}
.tips{cursor:pointer;}
textarea.form-control{margin-bottom: 3px;}
hr{margin-top: 10px;margin-bottom: 15px;border-top: 1px solid #eee;}
.modal-log{padding: 15px 15px 0 15px}
pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51, 51, 51, 1);white-space: pre-line;color: rgba(236, 236, 236, 1)}
#orderItem .orderTitle{word-break:keep-all;}
#orderItem .orderContent{word-break:break-all;}
.fixed-table-toolbar,.fixed-table-pagination{padding: 15px;}
tbody tr>td:nth-child(5){overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:180px;}
.tips{cursor:pointer;}
textarea.form-control{margin-bottom: 3px;}
hr{margin-top: 10px;margin-bottom: 15px;border-top: 1px solid #eee;}
.modal-log{padding: 15px 15px 0 15px}
pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51, 51, 51, 1);white-space: pre-line;color: rgba(236, 236, 236, 1)}
</style>
<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">
<input type="hidden" name="id" value="">
<input type="hidden" name="aid" value="">
<div class="form-group">
<label>搜索</label>
<div class="form-group">
<input type="text" class="form-control" name="domain" placeholder="域名">
</div>
</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>
<div class="form-group">
<select name="status" class="form-control"><option value="">所有状态</option><option value="0">待提交</option><option value="1">待验证</option><option value="2">正在验证</option><option value="5">失败</option><option value="3">已签发</option><option value="4">已吊销</option><option value="6">即将过期</option><option value="7">已过期</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>
<div class="btn-group">
<a href="/cert/order/add" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
</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="javascript:operation('delete')">删除</a></li><li><a href="javascript:operation('reset')">重置订单</a></li><li><a href="javascript:operation('open')">开启续签</a></li><li><a href="javascript:operation('close')">关闭续签</a></li></ul>
</div>
</form>
<table id="listTable">
</table>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading font-bold">
<h3 class="panel-title">SSL证书订单列表</h3>
</div>
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
<input type="hidden" name="id" value="">
<input type="hidden" name="aid" value="">
<div class="form-group">
<input type="text" class="form-control" name="domain" 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>
<div class="form-group">
<select name="status" class="form-control">
<option value="">所有状态</option>
<option value="0">待提交</option>
<option value="1">待验证</option>
<option value="2">正在验证</option>
<option value="5">失败</option>
<option value="3">已签发</option>
<option value="4">已吊销</option>
<option value="6">即将过期</option>
<option value="7">已过期</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>
<div class="btn-group">
<a href="/cert/order/add" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
</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="javascript:operation('delete')">删除</a></li><li><a href="javascript:operation('reset')">重置订单</a></li><li><a href="javascript:operation('open')">开启续签</a></li><li><a href="javascript:operation('close')">关闭续签</a></li></ul>
</div>
</form>
<table id="listTable">
</table>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
<script src="{$cdnpublic}FileSaver.js/2.0.5/FileSaver.min.js"></script>
<script src="/static/js/custom.js"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 10;
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 10;
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: '/cert/order/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
columns: [
{
field: '',
checkbox: true
},
{
field: 'id',
title: 'ID'
},
{
field: 'typename',
title: '证书账户',
formatter: function(value, row, index) {
if(value){
return '<span title="'+row.aremark+'" data-toggle="tooltip" data-placement="right"><img src="/static/images/'+row.icon+'" class="type-logo">'+value+'('+row.aid+')</span>';
}
return '手动续期';
}
},
{
field: 'domains',
title: '绑定域名',
formatter: function(value, row, index) {
return value.join('<br/>');
}
},
{
field: 'keytype',
title: '证书信息',
formatter: function(value, row, index) {
return '<span class="text-muted">签名算法:</span>'+row.keytype+'('+row.keysize+')'+(row.issuer?'<br/><span class="text-muted">颁发机构:</span>'+row.issuer:'');
}
},
{
field: 'isauto',
title: '自动续签',
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="isauto'+row.id+'" type="checkbox" checked onchange="setAuto('+row.id+',0)"/><label for="isauto'+row.id+'" class="label-primary"></label></div>';
}else{
return '<div class="material-switch"><input id="isauto'+row.id+'" type="checkbox" onchange="setAuto('+row.id+',1)"/><label for="isauto'+row.id+'" class="label-primary"></label></div>';
}
}
},
{
field: 'issuetime',
title: '签发时间',
formatter: function(value, row, index) {
return value ? value.substring(0,10) : '暂未签发';
}
},
{
field: 'end_day',
title: '到期时间',
formatter: function(value, row, index) {
if(value){
if(value > 7){
return '<span title="'+row.expiretime+'" data-toggle="tooltip" data-placement="right" style="color:green">剩余' + value + '天<span>';
}else if(value > 0){
return '<span title="'+row.expiretime+'" data-toggle="tooltip" data-placement="right" style="color:#ff7f00">剩余' + value + '天<span>';
}else{
return '<span title="'+row.expiretime+'" data-toggle="tooltip" data-placement="right" style="color:red">已过期<span>';
}
}else{
return '暂未签发';
}
}
},
{
field: 'status',
title: '状态',
formatter: function(value, row, index) {
if(value == 4) {
return '<span class="label" style="background-color: #a5a5a5;">已吊销</span>';
} else if(value == 3) {
return '<span class="label label-success">已签发</span>';
} else if(value == 2) {
if(row.retrytime != null){
var now = new Date().getTime();
var retry = new Date(row.retrytime).getTime();
var diff = retry - now;
if(diff > 0){
var min = Math.floor(diff / 60000);
var sec = Math.floor((diff - min * 60000) / 1000);
return '<span title="'+min+'分'+sec+'秒后自动验证" data-toggle="tooltip" data-placement="top" class="label" style="background-color: #3e76fb;">正在验证</span>';
}
}
return '<span class="label" style="background-color: #3e76fb;">正在验证</span>';
} else if(value == 1) {
if(row.retrytime != null){
var now = new Date().getTime();
var retry = new Date(row.retrytime).getTime();
var diff = retry - now;
if(diff > 0){
var min = Math.floor(diff / 60000);
var sec = Math.floor((diff - min * 60000) / 1000);
return '<span title="'+min+'分'+sec+'秒后自动验证" data-toggle="tooltip" data-placement="top" class="label" style="background-color: #3e76fb;">待验证</span>';
}
}
return '<span class="label" style="background-color: #3e76fb;">待验证</span>';
} else if(value == 0) {
return '<span class="label label-info">待提交</span>';
} else {
var title = '失败';
if(value == -1) title = '购买证书失败';
else if(value == -2) title = '创建订单失败';
else if(value == -3) title = '添加DNS失败';
else if(value == -4) title = '验证DNS失败';
else if(value == -5) title = '验证订单失败';
else if(value == -6) title = '订单验证未通过';
else if(value == -7) title = '签发证书失败';
if(row.retrytime != null){
var now = new Date().getTime();
var retry = new Date(row.retrytime).getTime();
var diff = retry - now;
if(diff > 0){
var min = Math.floor(diff / 60000);
var sec = Math.floor((diff - min * 60000) / 1000);
return '<span title="'+min+'分'+sec+'秒后自动重试" data-toggle="tooltip" data-placement="top" class="label label-danger">'+title+'</span>'+(row.error?' <span onclick="showmsg(\''+row.error+'\')" class="tips" title="失败原因"><i class="fa fa-info-circle"></i></span>':'');
}
}
return '<span class="label label-danger">'+title+'</span>'+(row.error?' <span onclick="showmsg(\''+row.error+'\')" class="tips" title="失败原因"><i class="fa fa-info-circle"></i></span>':'');
}
}
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var html = '';
if(row.status == 0) {
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-play-circle"></i> 立即提交</a>&nbsp;&nbsp;';
}else if(row.status == 1) {
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-check-circle"></i> 提交验证</a>&nbsp;&nbsp;';
}else if(row.status == 2) {
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-check-circle"></i> 继续验证</a>&nbsp;&nbsp;';
}else if(row.status == 3) {
html += '<a href="javascript:download(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-download"></i> 下载</a>&nbsp;&nbsp;';
if(row.aid > 0){
html += '<a href="javascript:renewOrder(\''+row.id+'\')" class="btn btn-warning btn-xs"><i class="fa fa-refresh"></i> 续签</a>&nbsp;&nbsp;';
}
}else if(row.status == 4) {
html += '<a href="javascript:renewOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-play-circle"></i> 重新申请</a>&nbsp;&nbsp;';
}else{
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-repeat"></i> 重试</a>&nbsp;&nbsp;';
}
html += '<a href="/cert/order/edit?id='+row.id+'" class="btn btn-primary btn-xs"><i class="fa fa-edit"></i> 修改</a>&nbsp;&nbsp;';
html += '<div class="btn-group dropdown-group" role="group"><button type="button" class="btn btn-info btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">更多 <span class="caret"></span></button><ul class="dropdown-menu">';
html += '<li><a href="javascript:showLog(\''+row.processid+'\')">查看日志</a></li>';
if(row.status == 3){
html += '<li><a href="/cert/deploytask?oid='+row.id+'">部署任务</a></li>';
if(row.aid > 0){
html += '<li><a href="javascript:revokeOrder(\''+row.id+'\')">吊销证书</a></li>';
}
}else if(row.status < 0){
html += '<li><a href="javascript:resetOrder(\''+row.id+'\')">重置订单</a></li>';
}else if(row.status == 1 || row.status == 2){
html += '<li><a href="javascript:resetOrder(\''+row.id+'\')">取消订单</a></li>';
}
html += '<li><a href="javascript:delItem('+row.id+','+row.status+')">删除</a></li>';
html += '</ul></div>';
return html;
}
},
],
onLoadSuccess: function(data) {
$('[data-toggle="tooltip"]').tooltip()
$('.dropdown-group').on('show.bs.dropdown', function (e) {
var btnPos = $(e.target)[0].getBoundingClientRect();
var screenWidth = $(window).width();
var screenHeight = $(window).height();
var childrenWidth = $(e.target).children('.dropdown-menu').width();
var childrenHeight = $(e.target).children('.dropdown-menu').height();
var top = btnPos.bottom;
if(top + childrenHeight + 12 > screenHeight){
top = btnPos.top - childrenHeight - 12;
}
var left = btnPos.left;
if(left + childrenWidth + 7 > screenWidth){
left = screenWidth - childrenWidth - 7;
}
$(e.target).children('.dropdown-menu').css({position:'fixed', top:top, left:left});
});
}
})
})
function showmsg(msg){
layer.alert(msg, {icon: 0, title: '失败原因'});
}
function setAuto(id, status){
$.post('/cert/order/setauto', {id: id, isauto: status}, function(data){
if(data.code == 0) {
layer.msg('已'+(status==1?'开启':'关闭')+'自动续签', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
}
function delItem(id,status){
var msg = '确定要删除此证书订单吗?';
if(status == 3) msg += '删除后将无法再次下载证书';
layer.confirm(msg, {
btn: ['确定','取消']
}, function(){
$.post('/cert/order/del', {id: id}, function(data){
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
function doOrder(id, reset){
reset = reset || 0;
var ii = layer.msg('正在处理证书订单...', {icon: 16,shade: 0.1,time: 0});
$.ajax({
type: "POST",
url: "/cert/order/process",
data: {id: id, reset: reset},
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0) {
layer.alert(data.msg, {icon: 1});
$('#listTable').bootstrapTable('refresh');
} else {
if(data.msg == '订单正在处理中,请稍后再试'){
layer.alert(data.msg, {icon: 2}, function(){
layer.closeAll();
var row = $("#listTable").bootstrapTable('getRowByUniqueId', id);
showLog(row.processid)
});
}else{
layer.alert(data.msg, {icon: 2});
$('#listTable').bootstrapTable('refresh');
}
}
},
error: function(data){
layer.close(ii);
layer.msg('执行超时,请稍后刷新列表或查看日志', {icon:0});
}
});
}
function resetOrder(id){
layer.confirm('重置订单后,订单将变成待提交状态,是否确定?', {
btn: ['确定','取消'], title: '重置订单', icon: 0
}, function(){
$.post('/cert/order/reset', {id: id}, function(data){
if(data.code == 0) {
layer.msg('重置订单状态成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
function revokeOrder(id){
layer.confirm('是否确定要吊销该证书?吊销后浏览器将不再信任该证书', {
btn: ['确定','取消'], title: '吊销证书', icon: 0
}, function(){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/cert/order/revoke', {id: id}, function(data){
layer.close(ii);
if(data.code == 0) {
layer.alert('吊销证书成功!', {icon: 1});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
function renewOrder(id){
layer.confirm('是否确定重新申请该证书?', {
btn: ['确定','取消'], title: '续签证书', icon: 0
}, function(){
doOrder(id, 1);
});
}
function download(id){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/cert/order/get', {id: id}, function(data){
layer.close(ii);
if(data.code == 0) {
layer.open({
type: 1,
title: '下载证书',
area: [$(window).width() > 768 ? '600px' : '100%', '360px'],
shadeClose: true,
content: '<div class="modal-body"><div class="row text-center"><div class="form-group col-xs-6"><label>证书(PEM格式)</label><textarea rows="6" class="form-control" name="fullchain">'+data.data.fullchain+'</textarea><a onclick="copy(\'fullchain\')" class="btn btn-default"><i class="fa fa-copy"></i> 复制</a>&nbsp;&nbsp;<a onclick="downloadFile(\'fullchain.crt\',\'fullchain\')" class="btn btn-default"><i class="fa fa-download"></i> 下载</a></div><div class="form-group col-xs-6"><label>私钥(PEM格式)</label><textarea rows="6" class="form-control" name="privatekey">'+data.data.privatekey+'</textarea><a onclick="copy(\'privatekey\')" class="btn btn-default"><i class="fa fa-copy"></i> 复制</a>&nbsp;&nbsp;<a onclick="downloadFile(\'private.key\',\'privatekey\')" class="btn btn-default"><i class="fa fa-download"></i> 下载</a></div></div><hr/><label>IIS服务器(pfx格式)</label><input type="hidden" name="pfx" value="'+data.data.pfx+'"><a onclick="downloadPFX()" class="btn btn-default"><i class="fa fa-download"></i> 下载</a>密码为123456</div>',
});
} else {
layer.alert(data.msg, {icon: 2});
}
}, 'json');
}
function copy(obj){
$("textarea[name='"+obj+"']").select();
document.execCommand("Copy");
layer.msg('复制成功', {icon:1, time:600});
}
function downloadFile(filename,obj){
var content = $("textarea[name='"+obj+"']").val();
if(!content) return;
var blob = new Blob([content], {type: "application/force-download"});
saveAs(blob, filename);
}
function downloadPFX(id){
var content = $("input[name='pfx']").val();
if(!content) return;
var bstr = atob(content),
n = bstr.length,
u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
var filename = 'cert.pfx';
var blob = new Blob([u8arr], {type: "application/force-download"});
saveAs(blob, filename);
}
var intverval;
function showLog(processid){
if(processid == '' || processid == 'null'){
layer.msg('暂无日志', {time: 600});
return;
}
$.post('/cert/order/show_log', {processid: processid}, function(data){
if(data.code == 0) {
layer.closeAll();
var filemtime = data.time;
layer.open({
type: 1,
title: '查看日志',
area: [$(window).width() > 768 ? '600px' : '100%', '400px'],
shadeClose: true,
resize: false,
content: '<div class="modal-log"><pre class="pre-log" id="execLog">'+data.data+'</pre></div>',
success: function(){
var exec_log = $('#execLog');
exec_log[0].scrollTop = exec_log[0].scrollHeight
intverval = setInterval(function(){
$.post('/cert/order/show_log', {processid: processid}, function(data){
if(data.code == 0 && data.time != filemtime) {
var exec_log = $('#execLog');
exec_log.html(data.data);
filemtime = data.time;
exec_log[0].scrollTop = exec_log[0].scrollHeight
}
}, 'json');
}, 1500)
$("#listTable").bootstrapTable({
url: '/cert/order/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
columns: [
{
field: '',
checkbox: true
},
end: function(){
clearInterval(intverval);
{
field: 'id',
title: 'ID'
},
{
field: 'typename',
title: '证书账户',
formatter: function(value, row, index) {
if(value){
return '<span title="'+row.aremark+'" data-toggle="tooltip" data-placement="right"><img src="/static/images/'+row.icon+'" class="type-logo">'+value+'('+row.aid+')</span>';
}
return '手动续期';
}
},
{
field: 'domains',
title: '绑定域名',
formatter: function(value, row, index) {
return value.join('<br/>');
}
},
{
field: 'keytype',
title: '证书信息',
formatter: function(value, row, index) {
return '<span class="text-muted">签名算法:</span>'+row.keytype+'('+row.keysize+')'+(row.issuer?'<br/><span class="text-muted">颁发机构:</span>'+row.issuer:'');
}
},
{
field: 'isauto',
title: '自动续签',
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="isauto'+row.id+'" type="checkbox" checked onchange="setAuto('+row.id+',0)"/><label for="isauto'+row.id+'" class="label-primary"></label></div>';
}else{
return '<div class="material-switch"><input id="isauto'+row.id+'" type="checkbox" onchange="setAuto('+row.id+',1)"/><label for="isauto'+row.id+'" class="label-primary"></label></div>';
}
}
},
{
field: 'issuetime',
title: '签发时间',
formatter: function(value, row, index) {
return value ? value.substring(0,10) : '暂未签发';
}
},
{
field: 'end_day',
title: '到期时间',
formatter: function(value, row, index) {
if(value){
if(value > 7){
return '<span title="'+row.expiretime+'" data-toggle="tooltip" data-placement="right" style="color:green">剩余' + value + '天<span>';
}else if(value > 0){
return '<span title="'+row.expiretime+'" data-toggle="tooltip" data-placement="right" style="color:#ff7f00">剩余' + value + '天<span>';
}else{
return '<span title="'+row.expiretime+'" data-toggle="tooltip" data-placement="right" style="color:red">已过期<span>';
}
}else{
return '暂未签发';
}
}
},
{
field: 'status',
title: '状态',
formatter: function(value, row, index) {
if(value == 4) {
return '<span class="label" style="background-color: #a5a5a5;">已吊销</span>';
} else if(value == 3) {
return '<span class="label label-success">已签发</span>';
} else if(value == 2) {
if(row.retrytime != null){
var now = new Date().getTime();
var retry = new Date(row.retrytime).getTime();
var diff = retry - now;
if(diff > 0){
var min = Math.floor(diff / 60000);
var sec = Math.floor((diff - min * 60000) / 1000);
return '<span title="'+min+'分'+sec+'秒后自动验证" data-toggle="tooltip" data-placement="top" class="label" style="background-color: #3e76fb;">正在验证</span>';
}
}
return '<span class="label" style="background-color: #3e76fb;">正在验证</span>';
} else if(value == 1) {
if(row.retrytime != null){
var now = new Date().getTime();
var retry = new Date(row.retrytime).getTime();
var diff = retry - now;
if(diff > 0){
var min = Math.floor(diff / 60000);
var sec = Math.floor((diff - min * 60000) / 1000);
return '<span title="'+min+'分'+sec+'秒后自动验证" data-toggle="tooltip" data-placement="top" class="label" style="background-color: #3e76fb;">待验证</span>';
}
}
return '<span class="label" style="background-color: #3e76fb;">待验证</span>';
} else if(value == 0) {
return '<span class="label label-info">待提交</span>';
} else {
var title = '失败';
if(value == -1) title = '购买证书失败';
else if(value == -2) title = '创建订单失败';
else if(value == -3) title = '添加DNS失败';
else if(value == -4) title = '验证DNS失败';
else if(value == -5) title = '验证订单失败';
else if(value == -6) title = '订单验证未通过';
else if(value == -7) title = '签发证书失败';
if(row.retrytime != null){
var now = new Date().getTime();
var retry = new Date(row.retrytime).getTime();
var diff = retry - now;
if(diff > 0){
var min = Math.floor(diff / 60000);
var sec = Math.floor((diff - min * 60000) / 1000);
return '<span title="'+min+'分'+sec+'秒后自动重试" data-toggle="tooltip" data-placement="top" class="label label-danger">'+title+'</span>'+(row.error?' <span onclick="showmsg(\''+row.error+'\')" class="tips" title="失败原因"><i class="fa fa-info-circle"></i></span>':'');
}
}
return '<span class="label label-danger">'+title+'</span>'+(row.error?' <span onclick="showmsg(\''+row.error+'\')" class="tips" title="失败原因"><i class="fa fa-info-circle"></i></span>':'');
}
}
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var html = '';
if(row.status == 0) {
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-play-circle"></i> 立即提交</a>&nbsp;&nbsp;';
}else if(row.status == 1) {
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-check-circle"></i> 提交验证</a>&nbsp;&nbsp;';
}else if(row.status == 2) {
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-check-circle"></i> 继续验证</a>&nbsp;&nbsp;';
}else if(row.status == 3) {
html += '<a href="javascript:download(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-download"></i> 下载</a>&nbsp;&nbsp;';
if(row.aid > 0){
html += '<a href="javascript:renewOrder(\''+row.id+'\')" class="btn btn-warning btn-xs"><i class="fa fa-refresh"></i> 续签</a>&nbsp;&nbsp;';
}
}else if(row.status == 4) {
html += '<a href="javascript:renewOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-play-circle"></i> 重新申请</a>&nbsp;&nbsp;';
}else{
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-repeat"></i> 重试</a>&nbsp;&nbsp;';
}
html += '<a href="/cert/order/edit?id='+row.id+'" class="btn btn-primary btn-xs"><i class="fa fa-edit"></i> 修改</a>&nbsp;&nbsp;';
html += '<div class="btn-group dropdown-group" role="group"><button type="button" class="btn btn-info btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">更多 <span class="caret"></span></button><ul class="dropdown-menu">';
html += '<li><a href="javascript:showLog(\''+row.processid+'\')">查看日志</a></li>';
if(row.status == 3){
html += '<li><a href="/cert/deploytask?oid='+row.id+'">部署任务</a></li>';
if(row.aid > 0){
html += '<li><a href="javascript:revokeOrder(\''+row.id+'\')">吊销证书</a></li>';
}
}else if(row.status < 0){
html += '<li><a href="javascript:resetOrder(\''+row.id+'\')">重置订单</a></li>';
}else if(row.status == 1 || row.status == 2){
html += '<li><a href="javascript:resetOrder(\''+row.id+'\')">取消订单</a></li>';
}
html += '<li><a href="javascript:delItem('+row.id+','+row.status+')">删除</a></li>';
html += '</ul></div>';
return html;
}
},
],
onLoadSuccess: function(data) {
$('[data-toggle="tooltip"]').tooltip()
$('.dropdown-group').on('show.bs.dropdown', function (e) {
var btnPos = $(e.target)[0].getBoundingClientRect();
var screenWidth = $(window).width();
var screenHeight = $(window).height();
var childrenWidth = $(e.target).children('.dropdown-menu').width();
var childrenHeight = $(e.target).children('.dropdown-menu').height();
var top = btnPos.bottom;
if(top + childrenHeight + 12 > screenHeight){
top = btnPos.top - childrenHeight - 12;
}
var left = btnPos.left;
if(left + childrenWidth + 7 > screenWidth){
left = screenWidth - childrenWidth - 7;
}
$(e.target).children('.dropdown-menu').css({position:'fixed', top:top, left:left});
});
}
})
})
function showmsg(msg){
layer.alert(msg, {icon: 0, title: '失败原因'});
}
function setAuto(id, status){
$.post('/cert/order/setauto', {id: id, isauto: status}, function(data){
if(data.code == 0) {
layer.msg('已'+(status==1?'开启':'关闭')+'自动续签', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
}
function delItem(id,status){
var msg = '确定要删除此证书订单吗?';
if(status == 3) msg += '删除后将无法再次下载证书';
layer.confirm(msg, {
btn: ['确定','取消']
}, function(){
$.post('/cert/order/del', {id: id}, function(data){
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
});
} else {
layer.msg(data.msg, {icon: 2, time: 600});
}
}, 'json');
}
function operation(action){
var rows = $("#listTable").bootstrapTable('getSelections');
if(rows.length == 0){
layer.msg('请选择要操作的订单');
return;
}, 'json');
});
}
var ids = [];
for(var i in rows){
ids.push(rows[i].id);
function doOrder(id, reset){
reset = reset || 0;
var ii = layer.msg('正在处理证书订单...', {icon: 16,shade: 0.1,time: 0});
$.ajax({
type: "POST",
url: "/cert/order/process",
data: {id: id, reset: reset},
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0) {
layer.alert(data.msg, {icon: 1});
$('#listTable').bootstrapTable('refresh');
} else {
if(data.msg == '订单正在处理中,请稍后再试'){
layer.alert(data.msg, {icon: 2}, function(){
layer.closeAll();
var row = $("#listTable").bootstrapTable('getRowByUniqueId', id);
showLog(row.processid)
});
}else{
layer.alert(data.msg, {icon: 2});
$('#listTable').bootstrapTable('refresh');
}
}
},
error: function(data){
layer.close(ii);
layer.msg('执行超时,请稍后刷新列表或查看日志', {icon:0});
}
});
}
if(action == 'delete'){
if(!confirm('确定要删除所选证书吗?删除后将无法再次下载')) return;
}else if(action == 'reset'){
if(!confirm('重置订单后,订单将变成待提交状态,是否确定重置?')) return;
function resetOrder(id){
layer.confirm('重置订单后,订单将变成待提交状态,是否确定?', {
btn: ['确定','取消'], title: '重置订单', icon: 0
}, function(){
$.post('/cert/order/reset', {id: id}, function(data){
if(data.code == 0) {
layer.msg('重置订单状态成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/cert/order/operation',
data : {act: action, ids: ids},
dataType : 'json',
success : function(data) {
function revokeOrder(id){
layer.confirm('是否确定要吊销该证书?吊销后浏览器将不再信任该证书', {
btn: ['确定','取消'], title: '吊销证书', icon: 0
}, function(){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/cert/order/revoke', {id: id}, function(data){
layer.close(ii);
if(data.code == 0) {
layer.alert('吊销证书成功!', {icon: 1});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
function renewOrder(id){
layer.confirm('是否确定重新申请该证书?', {
btn: ['确定','取消'], title: '续签证书', icon: 0
}, function(){
doOrder(id, 1);
});
}
function download(id){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/cert/order/get', {id: id}, function(data){
layer.close(ii);
if(data.code == 0){
layer.closeAll();
layer.alert(data.msg, {icon: 1});
searchRefresh();
}else{
if(data.code == 0) {
layer.open({
type: 1,
title: '下载证书',
area: [$(window).width() > 768 ? '600px' : '100%', '360px'],
shadeClose: true,
content: '<div class="modal-body"><div class="row text-center"><div class="form-group col-xs-6"><label>证书(PEM格式)</label><textarea rows="6" class="form-control" name="fullchain">'+data.data.fullchain+'</textarea><a onclick="copy(\'fullchain\')" class="btn btn-default"><i class="fa fa-copy"></i> 复制</a>&nbsp;&nbsp;<a onclick="downloadFile(\'fullchain.crt\',\'fullchain\')" class="btn btn-default"><i class="fa fa-download"></i> 下载</a></div><div class="form-group col-xs-6"><label>私钥(PEM格式)</label><textarea rows="6" class="form-control" name="privatekey">'+data.data.privatekey+'</textarea><a onclick="copy(\'privatekey\')" class="btn btn-default"><i class="fa fa-copy"></i> 复制</a>&nbsp;&nbsp;<a onclick="downloadFile(\'private.key\',\'privatekey\')" class="btn btn-default"><i class="fa fa-download"></i> 下载</a></div></div><hr/><label>IIS服务器(pfx格式)</label><input type="hidden" name="pfx" value="'+data.data.pfx+'"><a onclick="downloadPFX()" class="btn btn-default"><i class="fa fa-download"></i> 下载</a>密码为123456</div>',
});
} else {
layer.alert(data.msg, {icon: 2});
}
}, 'json');
}
function copy(obj){
$("textarea[name='"+obj+"']").select();
document.execCommand("Copy");
layer.msg('复制成功', {icon:1, time:600});
}
function downloadFile(filename,obj){
var content = $("textarea[name='"+obj+"']").val();
if(!content) return;
var blob = new Blob([content], {type: "application/force-download"});
saveAs(blob, filename);
}
function downloadPFX(id){
var content = $("input[name='pfx']").val();
if(!content) return;
var bstr = atob(content),
n = bstr.length,
u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
});
}
var filename = 'cert.pfx';
var blob = new Blob([u8arr], {type: "application/force-download"});
saveAs(blob, filename);
}
var intverval;
function showLog(processid){
if(processid == '' || processid == 'null'){
layer.msg('暂无日志', {time: 600});
return;
}
$.post('/cert/order/show_log', {processid: processid}, function(data){
if(data.code == 0) {
layer.closeAll();
var filemtime = data.time;
layer.open({
type: 1,
title: '查看日志',
area: [$(window).width() > 768 ? '600px' : '100%', '400px'],
shadeClose: true,
resize: false,
content: '<div class="modal-log"><pre class="pre-log" id="execLog">'+data.data+'</pre></div>',
success: function(){
var exec_log = $('#execLog');
exec_log[0].scrollTop = exec_log[0].scrollHeight
intverval = setInterval(function(){
$.post('/cert/order/show_log', {processid: processid}, function(data){
if(data.code == 0 && data.time != filemtime) {
var exec_log = $('#execLog');
exec_log.html(data.data);
filemtime = data.time;
exec_log[0].scrollTop = exec_log[0].scrollHeight
}
}, 'json');
}, 1500)
},
end: function(){
clearInterval(intverval);
}
});
} else {
layer.msg(data.msg, {icon: 2, time: 600});
}
}, 'json');
}
function operation(action){
var rows = $("#listTable").bootstrapTable('getSelections');
if(rows.length == 0){
layer.msg('请选择要操作的订单');
return;
}
var ids = [];
for(var i in rows){
ids.push(rows[i].id);
}
if(action == 'delete'){
if(!confirm('确定要删除所选证书吗?删除后将无法再次下载')) return;
}else if(action == 'reset'){
if(!confirm('重置订单后,订单将变成待提交状态,是否确定重置?')) return;
}
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/cert/order/operation',
data : {act: action, ids: ids},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.closeAll();
layer.alert(data.msg, {icon: 1});
searchRefresh();
}else{
layer.alert(data.msg, {icon: 2});
}
}
});
}
</script>
{/block}

211
app/view/cert/certset.html Normal file → Executable file
View File

@ -2,119 +2,114 @@
{block name="title"}SSL证书计划任务{/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-warning">
<div class="panel-heading"><h3 class="panel-title">计划任务说明</h3></div>
<div class="panel-body">
<p><li>计划任务将以下命令添加到计划任务1分钟1次</li></p>
<p><code>cd {:app()->getRootPath()} && php think certtask</code></p>
<p><li>上次运行时间:<font color="green">{:config_get('certtask_time', '未运行', true)}</font></li></p>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">自动续签设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">到期前续签天数</label>
<div class="col-sm-9"><input type="text" name="cert_renewdays" value="{:config_get('cert_renewdays', '7')}" class="form-control" placeholder="证书到期前多少天自动续签"/></div>
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
<div class="panel panel-warning">
<div class="panel-heading"><h3 class="panel-title">计划任务说明</h3></div>
<div class="panel-body">
<p>计划任务将以下命令添加到计划任务1分钟1次</p>
<p><code>cd {:app()->getRootPath()} && php think certtask</code></p>
<p>上次运行时间:<font color="green">{:config_get('certtask_time', '未运行', true)}</font></p>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">自动续签设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">到期前续签天数</label>
<div class="col-sm-9"><input type="text" name="cert_renewdays" value="{:config_get('cert_renewdays', '7')}" class="form-control" placeholder="证书到期前多少天自动续签"/></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
</div>
</div>
</form>
</div>
<div class="panel-footer">
提示:只有已开启自动续签的证书,才会自动续签。
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">自动部署设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">部署任务运行时段(小时)</label>
<div class="col-sm-9"><div class="input-group"><select class="form-control" name="deploy_hour_start" default="{:config_get('deploy_hour_start', '0')}">{for start="0" end="24"}<option value="{$i}">{$i}</option>{/for}</select><span class="input-group-addon"></span><select class="form-control" name="deploy_hour_end" default="{:config_get('deploy_hour_end', '23')}">{for start="0" end="24"}<option value="{$i}">{$i}</option>{/for}</select></div></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
</div>
</div>
</form>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">通知设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">邮件通知</label>
<div class="col-sm-9"><select class="form-control" name="cert_notice_mail" default="{:config_get('cert_notice_mail')}"><option value="0">关闭</option><option value="1">开启</option><option value="2">开启(仅失败时)</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">微信公众号通知</label>
<div class="col-sm-9"><select class="form-control" name="cert_notice_wxtpl" default="{:config_get('cert_notice_wxtpl')}"><option value="0">关闭</option><option value="1">开启</option><option value="2">开启(仅失败时)</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Telegram机器人通知</label>
<div class="col-sm-9"><select class="form-control" name="cert_notice_tgbot" default="{:config_get('cert_notice_tgbot')}"><option value="0">关闭</option><option value="1">开启</option><option value="2">开启(仅失败时)</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">群机器人Webhook</label>
<div class="col-sm-9"><select class="form-control" name="cert_notice_webhook" default="{:config_get('cert_notice_webhook')}"><option value="0">关闭</option><option value="1">开启</option><option value="2">开启(仅失败时)</option></select></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9"><input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/></div>
</div>
</form>
</div>
<div class="panel-footer">
开启后,将在证书签发成功/失败,自动部署任务成功/失败时发送通知。只有计划任务执行会发送通知,控制台手动执行的不会发送。
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
</div>
</div>
</form>
</div>
<div class="panel-footer">
<li>提示:只有已开启自动续签的证书,才会自动续签。</li>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">自动部署设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">部署任务运行时段(小时)</label>
<div class="col-sm-9"><div class="input-group"><select class="form-control" name="deploy_hour_start" default="{:config_get('deploy_hour_start', '0')}">{for start="0" end="24"}<option value="{$i}">{$i}</option>{/for}</select><span class="input-group-addon"></span><select class="form-control" name="deploy_hour_end" default="{:config_get('deploy_hour_end', '23')}">{for start="0" end="24"}<option value="{$i}">{$i}</option>{/for}</select></div></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
</div>
</div>
</form>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">通知设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">邮件通知</label>
<div class="col-sm-9"><select class="form-control" name="cert_notice_mail" default="{:config_get('cert_notice_mail')}"><option value="0">关闭</option><option value="1">开启</option><option value="2">开启(仅失败时)</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">微信公众号通知</label>
<div class="col-sm-9"><select class="form-control" name="cert_notice_wxtpl" default="{:config_get('cert_notice_wxtpl')}"><option value="0">关闭</option><option value="1">开启</option><option value="2">开启(仅失败时)</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Telegram机器人通知</label>
<div class="col-sm-9"><select class="form-control" name="cert_notice_tgbot" default="{:config_get('cert_notice_tgbot')}"><option value="0">关闭</option><option value="1">开启</option><option value="2">开启(仅失败时)</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">群机器人Webhook</label>
<div class="col-sm-9"><select class="form-control" name="cert_notice_webhook" default="{:config_get('cert_notice_webhook')}"><option value="0">关闭</option><option value="1">开启</option><option value="2">开启(仅失败时)</option></select></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9"><input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/></div>
</div>
</form>
</div>
<div class="panel-footer">
<li>开启后,将在证书签发成功/失败,自动部署任务成功/失败时发送通知。只有计划任务执行会发送通知,控制台手动执行的不会发送。</li>
</div>
</div>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script>
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default")||0);
}
function saveSetting(obj){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '/system/set',
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})
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default")||0);
}
function saveSetting(obj){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '/system/set',
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('服务器错误');
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
return false;
}
});
return false;
}
</script>
{/block}

390
app/view/cert/cname.html Normal file → Executable file
View File

@ -2,19 +2,22 @@
{block name="title"}CMAME代理记录管理{/block}
{block name="main"}
<style>
.copy-btn{color:#52c41a;cursor:pointer;margin-right: 5px;}
.copy-btn:hover{color:#85ef79;}
.btn-refresh{margin-left:5px;font-size:10px;background-color:#6896cf}
tbody tr>td:nth-child(3){word-break:break-all;max-width:180px;}
tbody tr>td:nth-child(4){word-break:break-all;max-width:260px;}
#orderItem .orderTitle{word-break:keep-all;}
#orderItem .orderContent{word-break:break-all;}
.fixed-table-toolbar,.fixed-table-pagination{padding: 15px;}
.copy-btn{color:#52c41a;cursor:pointer;margin-right: 5px;}
.copy-btn:hover{color:#85ef79;}
.btn-refresh{margin-left:5px;font-size:10px;background-color:#6896cf}
tbody tr>td:nth-child(3){word-break:break-all;max-width:180px;}
tbody tr>td:nth-child(4){word-break:break-all;max-width:260px;}
</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-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span
aria-hidden="true">&times;</span><span
class="sr-only">Close</span></button>
<button aria-label="Close" class="close" data-dismiss="modal" type="button">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="modal-title">添加CNAME代理</h4>
</div>
<div class="modal-body">
@ -29,13 +32,16 @@ tbody tr>td:nth-child(4){word-break:break-all;max-width:260px;}
</div>
<div class="form-group">
<label class="col-sm-3 control-label">CNAME记录值</label>
<div class="col-sm-9"><div class="input-group">
<input type="text" name="rr" placeholder="自定义主机记录" class="form-control" required><span class="input-group-addon">.</span>
<select name="did" class="form-control" required>
{foreach $domains as $k=>$v}
<option value="{$k}">{$v}</option>
{/foreach}
</select></div></div>
<div class="col-sm-9">
<div class="input-group">
<input type="text" name="rr" placeholder="自定义主机记录" class="form-control" required><span class="input-group-addon">.</span>
<select name="did" class="form-control" required>
{foreach $domains as $k=>$v}
<option value="{$k}">{$v}</option>
{/foreach}
</select>
</div>
</div>
</div>
</form>
</div>
@ -46,200 +52,198 @@ tbody tr>td:nth-child(4){word-break:break-all;max-width:260px;}
</div>
</div>
</div>
<div class="panel panel-default"><div class="panel-body"><p>CNAME代理可以让未在本系统添加的域名自动申请SSL证书支持所有DNS服务商。</p><p>仅支持基于ACME的证书类型不支持腾讯云等云厂商SSL证书。</p></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 panel-default">
<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>
<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>
<p>CNAME代理可以让未在本系统添加的域名自动申请SSL证书支持所有DNS服务商。</p>
<p>仅支持基于ACME的证书类型不支持腾讯云等云厂商SSL证书。</p>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading font-bold">
<h3 class="panel-title">CMAME代理记录管理</h3>
</div>
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
<div class="form-group">
<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>
<a href="javascript:addframe()" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
</form>
<table id="listTable">
</table>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}clipboard.js/1.7.1/clipboard.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/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;
$(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: '/cert/cname/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
columns: [
{
field: 'id',
title: 'ID'
},
{
field: 'domain',
title: '被代理域名'
},
{
field: 'host',
title: '主机记录',
formatter: function(value, row, index) {
return value + '<a href="javascript:;" data-clipboard-text="'+value+'" class="copy-btn pull-right"><i class="fa fa-copy"></i></a>';
}
},
{
field: 'record',
title: 'CNAME记录值',
formatter: function(value, row, index) {
return value + '<a href="javascript:;" data-clipboard-text="'+value+'" class="copy-btn pull-right"><i class="fa fa-copy"></i></a>';
}
},
{
field: 'status',
title: '状态',
formatter: function(value, row, index) {
var html = '';
if(value == 1) {
html += '<span class="label label-success">已验证</span>';
} else {
html += '<span class="label label-warning">未验证</span>';
$("#listTable").bootstrapTable({
url: '/cert/cname/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
columns: [
{
field: 'id',
title: 'ID'
},
{
field: 'domain',
title: '被代理域名'
},
{
field: 'host',
title: '主机记录',
formatter: function(value, row, index) {
return value + '<a href="javascript:;" data-clipboard-text="'+value+'" class="copy-btn pull-right"><i class="fa fa-copy"></i></a>';
}
html += '<a href="javascript:checkItem('+row.id+')" title="立即验证" class="btn btn-primary btn-xs btn-refresh"><i class="fa fa-refresh"></i></a>';
return html;
}
},
{
field: 'addtime',
title: '添加时间'
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var html = '<a href="javascript:editframe('+row.id+')" class="btn btn-primary btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a>';
return html;
}
},
],
onLoadSuccess: function(data){
var clipboard = new Clipboard('.copy-btn');
clipboard.on('success', function (e) {
layer.msg('复制成功!', {icon: 1, time: 600});
});
clipboard.on('error', function (e) {
layer.msg('复制失败', {icon: 2});
});
},
})
})
function addframe(){
$("#modal-store").modal('show');
$("#modal-title").html("添加CNAME代理");
$("#form-store input[name=action]").val("add");
$("#form-store input[name=id]").val('');
$("#form-store input[name=domain]").val('');
$("#form-store input[name=domain]").prop('readonly', false);
$("#form-store input[name=rr]").val('');
var defaultDid = getCookie('cname_did');
if(defaultDid){
$("#form-store select[name=did]").val(defaultDid);
}
}
function editframe(id){
var row = $("#listTable").bootstrapTable('getRowByUniqueId', id);
$("#modal-store").modal('show');
$("#modal-title").html("修改CNAME代理");
$("#form-store input[name=action]").val("edit");
$("#form-store input[name=id]").val(id);
$("#form-store input[name=domain]").val(row.domain);
$("#form-store input[name=domain]").prop('readonly', true);
$("#form-store input[name=rr]").val(row.rr);
$("#form-store select[name=did]").val(row.did);
}
function changeDomain(obj){
var domain = $(obj).val();
if(domain == '') {
$("#form-store input[name=rr]").val('');
return;
}
var rr = domain.replace(/\./g, '-') + '.cname';
$("#form-store input[name=rr]").val(rr);
}
function save(){
if($("#form-store input[name=domain]").val()=='' || $("#form-store input[name=rr]").val()==''){
layer.alert('请确保各项不能为空!');return false;
}
var act = $("#form-store input[name=action]").val();
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/cert/cname/'+act,
data : $("#form-store").serialize(),
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
setCookie('cname_did', $("#form-store select[name=did]").val(), 2562000);
layer.alert(data.msg,{
icon: 1,
closeBtn: false
}, function(){
layer.closeAll();
$("#modal-store").modal('hide');
searchRefresh();
},
{
field: 'record',
title: 'CNAME记录值',
formatter: function(value, row, index) {
return value + '<a href="javascript:;" data-clipboard-text="'+value+'" class="copy-btn pull-right"><i class="fa fa-copy"></i></a>';
}
},
{
field: 'status',
title: '状态',
formatter: function(value, row, index) {
var html = '';
if(value == 1) {
html += '<span class="label label-success">已验证</span>';
} else {
html += '<span class="label label-warning">未验证</span>';
}
html += '<a href="javascript:checkItem('+row.id+')" title="立即验证" class="btn btn-primary btn-xs btn-refresh"><i class="fa fa-refresh"></i></a>';
return html;
}
},
{
field: 'addtime',
title: '添加时间'
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var html = '<a href="javascript:editframe('+row.id+')" class="btn btn-primary btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a>';
return html;
}
},
],
onLoadSuccess: function(data){
var clipboard = new Clipboard('.copy-btn');
clipboard.on('success', function (e) {
layer.msg('复制成功!', {icon: 1, time: 600});
});
}else{
layer.alert(data.msg, {icon: 2})
}
clipboard.on('error', function (e) {
layer.msg('复制失败', {icon: 2});
});
},
})
})
function addframe(){
$("#modal-store").modal('show');
$("#modal-title").html("添加CNAME代理");
$("#form-store input[name=action]").val("add");
$("#form-store input[name=id]").val('');
$("#form-store input[name=domain]").val('');
$("#form-store input[name=domain]").prop('readonly', false);
$("#form-store input[name=rr]").val('');
var defaultDid = getCookie('cname_did');
if(defaultDid){
$("#form-store select[name=did]").val(defaultDid);
}
});
}
function delItem(id){
layer.confirm('确定要删除此CNAME代理记录吗', {
btn: ['确定','取消']
}, function(){
$.post('/cert/cname/del', {id: id}, function(data){
}
function editframe(id){
var row = $("#listTable").bootstrapTable('getRowByUniqueId', id);
$("#modal-store").modal('show');
$("#modal-title").html("修改CNAME代理");
$("#form-store input[name=action]").val("edit");
$("#form-store input[name=id]").val(id);
$("#form-store input[name=domain]").val(row.domain);
$("#form-store input[name=domain]").prop('readonly', true);
$("#form-store input[name=rr]").val(row.rr);
$("#form-store select[name=did]").val(row.did);
}
function changeDomain(obj){
var domain = $(obj).val();
if(domain == '') {
$("#form-store input[name=rr]").val('');
return;
}
var rr = domain.replace(/\./g, '-') + '.cname';
$("#form-store input[name=rr]").val(rr);
}
function save(){
if($("#form-store input[name=domain]").val()=='' || $("#form-store input[name=rr]").val()==''){
layer.alert('请确保各项不能为空!');return false;
}
var act = $("#form-store input[name=action]").val();
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/cert/cname/'+act,
data : $("#form-store").serialize(),
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
setCookie('cname_did', $("#form-store select[name=did]").val(), 2562000);
layer.alert(data.msg,{
icon: 1,
closeBtn: false
}, function(){
layer.closeAll();
$("#modal-store").modal('hide');
searchRefresh();
});
}else{
layer.alert(data.msg, {icon: 2})
}
}
});
}
function delItem(id){
layer.confirm('确定要删除此CNAME代理记录吗', {
btn: ['确定','取消']
}, function(){
$.post('/cert/cname/del', {id: id}, function(data){
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
searchRefresh();
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
function checkItem(id){
var ii = layer.load(2);
$.post('/cert/cname/check', {id: id}, function(data){
layer.close(ii);
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
if(data.status == 1){
layer.alert('验证已通过!', {icon: 6});
}else{
layer.alert('验证未通过请按要求添加CNAME解析', {icon: 5});
}
searchRefresh();
} else {
layer.msg(data.msg, {icon: 2});
layer.alert(data.msg, {icon: 2});
}
}, 'json');
});
}
function checkItem(id){
var ii = layer.load(2);
$.post('/cert/cname/check', {id: id}, function(data){
layer.close(ii);
if(data.code == 0) {
if(data.status == 1){
layer.alert('验证已通过!', {icon: 6});
}else{
layer.alert('验证未通过请按要求添加CNAME解析', {icon: 5});
}
searchRefresh();
} else {
layer.alert(data.msg, {icon: 2});
}
}, 'json');
}
}
</script>
{/block}

429
app/view/cert/deploy_form.html Normal file → Executable file
View File

@ -2,146 +2,171 @@
{block name="title"}自动部署任务{/block}
{block name="main"}
<style>
.tips{color: #f6a838; padding-left: 5px;}
.input-note{color: green;}
.control-label[is-required]:before {
content: "*";
color: #f56c6c;
margin-right: 4px;
}
.tips{color: #f6a838; padding-left: 5px;}
.input-note{color: green;}
.control-label[is-required]:before {
content: "*";
color: #f56c6c;
margin-right: 4px;
}
</style>
<div class="row" id="app">
<div class="col-xs-12 center-block" style="float: none;">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title"><a href="/cert/deploytask" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}编辑{else}添加{/if}自动部署任务</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="accountform">
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" is-required>自动部署账户</label>
<div class="col-sm-6"><select name="aid" v-model="set.aid" class="form-control" required :disabled="action=='edit'">
<option value="">--选择自动部署账户--</option>
{foreach $accounts as $k=>$v}
<option value="{$k}" data-type="{$v.type}">{$v.name}</option>
{/foreach}
</select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" is-required>关联SSL证书</label>
<div class="col-sm-6"><select name="oid" v-model="set.oid" class="form-control select2" placeholder="选择要部署的SSL证书">
{foreach $orders as $k=>$v}
<option value="{$k}">{$v.name}</option>
{/foreach}
</select></div>
</div>
<div v-for="(item,name) in inputs" v-show="isShow(item.show)">
<div class="form-group" v-if="item.type=='input'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<input type="text" class="form-control" :name="name" v-model="config[name]" :placeholder="item.placeholder" :required="item.required" :disabled="item.disabled" :data-bv-id="item.validator=='id'" :data-bv-phone="item.validator=='phone'" :data-bv-numeric="item.validator=='numeric'" :data-bv-digits="item.validator=='digits'" :data-bv-integer="item.validator=='integer'" :data-bv-email="item.validator=='email'" :data-bv-uri="item.validator=='uri'" :min="item.min" :max="item.max"><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='textarea'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<textarea class="form-control" :name="name" rows="5" v-model="config[name]" :placeholder="item.placeholder" :required="item.required" :disabled="item.disabled"></textarea><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='select'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<select class="form-control" :name="name" v-model="config[name]" :required="item.required" :disabled="item.disabled" :placeholder="item.placeholder">
<option v-for="option in item.options" :value="option.value">{{option.label}}</option>
</select><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='radio'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="(optionname, optionvalue) in item.options">
<input type="radio" :name="name" :value="optionvalue" v-model="config[name]" :disabled="item.disabled"> {{optionname}}
</label><br/><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='checkbox'">
<div class="col-sm-offset-3 col-sm-7">
<div class="checkbox">
<label>
<input type="checkbox" :name="name" v-model="config[name]" :disabled="item.disabled"> {{item.name}}
</label>
<div id="app">
<div class="panel panel-default">
<div class="panel-heading font-bold"><h3 class="panel-title"><a href="/cert/deploytask" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}编辑{else}添加{/if}自动部署任务</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="accountform">
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" is-required>自动部署账户</label>
<div class="col-sm-6"><select name="aid" v-model="set.aid" class="form-control" required :disabled="action=='edit'">
<option value="">--选择自动部署账户--</option>
{foreach $accounts as $k=>$v}
<option value="{$k}" data-type="{$v.type}">{$v.name}</option>
{/foreach}
</select></div>
</div>
</div>
</div>
<div class="form-group" v-if="item.type=='checkboxes'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<label class="checkbox-inline" v-for="(optionname, optionvalue) in item.options">
<input type="checkbox" :name="name" :value="optionvalue" v-model="config[name]" :disabled="item.disabled"> {{optionname}}
</label><br/><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" is-required>关联SSL证书</label>
<div class="col-sm-6"><select name="oid" v-model="set.oid" class="form-control select2" placeholder="选择要部署的SSL证书">
{foreach $orders as $k=>$v}
<option value="{$k}">{$v.name}</option>
{/foreach}
</select></div>
</div>
<div v-for="(item,name) in inputs" v-show="isShow(item.show)">
<div class="form-group" v-if="item.type=='input'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<input type="text" class="form-control" :name="name" v-model="config[name]" :placeholder="item.placeholder" :required="item.required" :disabled="item.disabled" :data-bv-id="item.validator=='id'" :data-bv-phone="item.validator=='phone'" :data-bv-numeric="item.validator=='numeric'" :data-bv-digits="item.validator=='digits'" :data-bv-integer="item.validator=='integer'" :data-bv-email="item.validator=='email'" :data-bv-uri="item.validator=='uri'" :min="item.min" :max="item.max"><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='textarea'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<textarea class="form-control" :name="name" rows="5" v-model="config[name]" :placeholder="item.placeholder" :required="item.required" :disabled="item.disabled"></textarea><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='select'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<select class="form-control" :name="name" v-model="config[name]" :required="item.required" :disabled="item.disabled" :placeholder="item.placeholder">
<option v-for="option in item.options" :value="option.value">{{option.label}}</option>
</select><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='radio'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="(optionname, optionvalue) in item.options">
<input type="radio" :name="name" :value="optionvalue" v-model="config[name]" :disabled="item.disabled"> {{optionname}}
</label><br/><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
<div class="form-group" v-if="item.type=='checkbox'">
<div class="col-sm-offset-3 col-sm-7">
<div class="checkbox">
<label>
<input type="checkbox" :name="name" v-model="config[name]" :disabled="item.disabled"> {{item.name}}
</label>
</div>
</div>
</div>
<div class="form-group" v-if="item.type=='checkboxes'">
<label class="col-sm-3 control-label no-padding-right" :is-required="item.required">{{item.name}}</label>
<div class="col-sm-6">
<label class="checkbox-inline" v-for="(optionname, optionvalue) in item.options">
<input type="checkbox" :name="name" :value="optionvalue" v-model="config[name]" :disabled="item.disabled"> {{optionname}}
</label><br/><span v-if="item.note" class="input-note" v-html="item.note"></span>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">备注</label>
<div class="col-sm-6">
<input type="text" name="remark" v-model="set.remark" placeholder="可留空" class="form-control">
</div>
</div>
<div class="form-group" v-show="note">
<div class="col-sm-offset-3 col-sm-6">
<div class="alert alert-dismissible alert-info">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<strong>提示:</strong><span v-html="note"></span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">提交</button></div>
</div>
</form>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">备注</label>
<div class="col-sm-6">
<input type="text" name="remark" v-model="set.remark" placeholder="可留空" class="form-control">
</div>
</div>
<div class="form-group" v-show="note">
<div class="col-sm-offset-3 col-sm-6">
<div class="alert alert-dismissible alert-info">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<strong>提示:</strong><span v-html="note"></span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">提交</button></div>
</div>
</form>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}vue/2.6.14/vue.min.js"></script>
<script src="{$cdnpublic}layer/3.1.1/layer.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/bootstrapValidator.min.js"></script>
<script>
var info = {$info|json_encode|raw};
var typeList = {$typeList|json_encode|raw};
new Vue({
el: '#app',
data: {
action: '{$action}',
set: {
id: '',
aid: '',
oid: '',
config : '',
remark: '',
type: '',
var info = {$info|json_encode|raw};
var typeList = {$typeList|json_encode|raw};
new Vue({
el: '#app',
data: {
action: '{$action}',
set: {
id: '',
aid: '',
oid: '',
config : '',
remark: '',
type: '',
},
inputs: {},
config: {},
typeList: typeList,
note: '',
},
inputs: {},
config: {},
typeList: typeList,
note: '',
},
watch: {
'set.aid': function(val){
this.set.type = $('option:selected', 'select[name=aid]').data('type');
watch: {
'set.aid': function(val){
this.set.type = $('option:selected', 'select[name=aid]').data('type');
},
'set.type': function(val){
if(this.action == 'add' && val && typeList[val]){
this.inputs = typeList[val].taskinputs;
this.note = typeList[val].tasknote;
this.config = {};
$.each(this.inputs, (name, item) => {
if(typeof item.value == 'undefined'){
if(item.type == 'checkbox'){
item.value = false;
}else if(item.type == 'checkboxes'){
item.value = [];
}else{
item.value = null;
}
}
this.$set(this.config, name, item.value)
})
}
}
},
'set.type': function(val){
if(this.action == 'add' && val && typeList[val]){
this.inputs = typeList[val].taskinputs;
this.note = typeList[val].tasknote;
this.config = {};
mounted() {
if(this.action == 'edit'){
Object.keys(info).forEach((key) => {
this.set[key] = info[key]
})
var config = JSON.parse(info.config);
this.inputs = typeList[this.set.type].taskinputs;
this.note = typeList[this.set.type].tasknote;
$.each(this.inputs, (name, item) => {
if(typeof config[name] != 'undefined'){
item.value = config[name];
}
if(typeof item.value == 'undefined'){
if(item.type == 'checkbox'){
item.value = false;
item.value = false;
}else if(item.type == 'checkboxes'){
item.value = [];
item.value = [];
}else{
item.value = null;
}
@ -149,107 +174,81 @@ new Vue({
this.$set(this.config, name, item.value)
})
}
}
},
mounted() {
if(this.action == 'edit'){
Object.keys(info).forEach((key) => {
this.set[key] = info[key]
})
var config = JSON.parse(info.config);
this.inputs = typeList[this.set.type].taskinputs;
this.note = typeList[this.set.type].tasknote;
$.each(this.inputs, (name, item) => {
if(typeof config[name] != 'undefined'){
item.value = config[name];
}
if(typeof item.value == 'undefined'){
if(item.type == 'checkbox'){
item.value = false;
}else if(item.type == 'checkboxes'){
item.value = [];
}else{
item.value = null;
}
}
this.$set(this.config, name, item.value)
})
}
var that = this;
this.$nextTick(function () {
$('[data-toggle="tooltip"]').tooltip();
$('select[name=oid]').select2({placeholder: '选择要部署的SSL证书'}).on('select2:select', function(e){
that.set.oid = e.params.data.id
});
if(document.referrer.indexOf('&oid=') > 0){
var oid = document.referrer.split('&oid=')[1].split('&')[0];
if(oid){
$('select[name=oid]').val(oid).trigger('change');
that.set.oid = oid;
}
}
})
},
methods: {
submit(){
var that=this;
if(this.set.aid == ''){
layer.msg('请选择自动部署账户', {icon: 2, time:900});
return false;
}
if(this.set.oid == ''){
layer.msg('请选择要部署的SSL证书', {icon: 2, time:900});
return false;
}
Object.keys(this.config).forEach((key) => {
if(this.config[key] && typeof this.config[key] == 'string'){
this.config[key] = this.trim(this.config[key]);
var that = this;
this.$nextTick(function () {
$('[data-toggle="tooltip"]').tooltip();
$('select[name=oid]').select2({placeholder: '选择要部署的SSL证书'}).on('select2:select', function(e){
that.set.oid = e.params.data.id
});
if(document.referrer.indexOf('&oid=') > 0){
var oid = document.referrer.split('&oid=')[1].split('&')[0];
if(oid){
$('select[name=oid]').val(oid).trigger('change');
that.set.oid = oid;
}
}
})
this.set.config = JSON.stringify(this.config);
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type: "POST",
url: "",
data: this.set,
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1}, function(){
if(document.referrer.indexOf('/cert/deploytask?') > 0)
window.location.href = document.referrer;
else
window.location.href = '/cert/deploytask';
});
}else{
layer.alert(data.msg, {icon: 2});
}
},
error: function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
},
isShow(show){
if(typeof show == 'boolean' && show){
return show;
}else if(typeof show == 'string' && show){
methods: {
submit(){
var that=this;
if(this.set.aid == ''){
layer.msg('请选择自动部署账户', {icon: 2, time:900});
return false;
}
if(this.set.oid == ''){
layer.msg('请选择要部署的SSL证书', {icon: 2, time:900});
return false;
}
Object.keys(this.config).forEach((key) => {
show = show.replace(new RegExp(key, 'g'), 'that.config["'+key+'"]')
if(this.config[key] && typeof this.config[key] == 'string'){
this.config[key] = this.trim(this.config[key]);
}
})
return eval(show);
}else{
return true;
this.set.config = JSON.stringify(this.config);
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type: "POST",
url: "",
data: this.set,
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1}, function(){
if(document.referrer.indexOf('/cert/deploytask?') > 0)
window.location.href = document.referrer;
else
window.location.href = '/cert/deploytask';
});
}else{
layer.alert(data.msg, {icon: 2});
}
},
error: function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
},
isShow(show){
if(typeof show == 'boolean' && show){
return show;
}else if(typeof show == 'string' && show){
var that=this;
Object.keys(this.config).forEach((key) => {
show = show.replace(new RegExp(key, 'g'), 'that.config["'+key+'"]')
})
return eval(show);
}else{
return true;
}
},
trim(str){
return str.replace(/(^\s*)|(\s*$)/g, "");
}
},
trim(str){
return str.replace(/(^\s*)|(\s*$)/g, "");
}
},
});
});
</script>
{/block}

156
app/view/cert/deployaccount.html Normal file → Executable file
View File

@ -1,93 +1,91 @@
{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>
<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="刷新SSL证书账户列表"><i class="fa fa-refresh"></i> 刷新</a>
<a href="/cert/account/add?deploy=1" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
</form>
<table id="listTable">
</table>
<style>
#orderItem .orderTitle{word-break:keep-all;}
#orderItem .orderContent{word-break:break-all;}
.fixed-table-toolbar,.fixed-table-pagination{padding: 15px;}
</style>
<div class="panel panel-default">
<div class="panel-heading font-bold">
<h3 class="panel-title">自动部署任务账户管理</h3>
</div>
</div>
</div>
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
<div class="form-group">
<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="刷新SSL证书账户列表"><i class="fa fa-refresh"></i> 刷新</a>
<a href="/cert/account/add?deploy=1" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
</form>
<table id="listTable">
</table>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/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;
$(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: '/cert/account/data?deploy=1',
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.icon+'" class="type-logo"></img>'+value;
}
},
{
field: 'name',
title: '账户名称'
},
{
field: 'remark',
title: '备注'
},
{
field: 'addtime',
title: '添加时间'
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var html = '<a href="/cert/account/edit?deploy=1&id='+row.id+'" class="btn btn-info btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a> <a href="/cert/deploytask?aid='+row.id+'" class="btn btn-default btn-xs">任务</a>';
return html;
}
},
]
})
})
function delItem(id){
layer.confirm('确定要删除此账户吗?', {
btn: ['确定','取消']
}, function(){
$.post('/cert/account/del', {id: id, deploy: 1}, function(data){
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.alert(data.msg, {icon: 2});
}
}, 'json');
});
}
$("#listTable").bootstrapTable({
url: '/cert/account/data?deploy=1',
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.icon+'" class="type-logo"></img>'+value;
}
},
{
field: 'name',
title: '账户名称'
},
{
field: 'remark',
title: '备注'
},
{
field: 'addtime',
title: '添加时间'
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var html = '<a href="/cert/account/edit?deploy=1&id='+row.id+'" class="btn btn-info btn-xs">编辑</a> <a href="javascript:delItem('+row.id+')" class="btn btn-danger btn-xs">删除</a> <a href="/cert/deploytask?aid='+row.id+'" class="btn btn-default btn-xs">任务</a>';
return html;
}
},
]
})
})
function delItem(id){
layer.confirm('确定要删除此账户吗?', {
btn: ['确定','取消']
}, function(){
$.post('/cert/account/del', {id: id, deploy: 1}, function(data){
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.alert(data.msg, {icon: 2});
}
}, 'json');
});
}
</script>
{/block}

644
app/view/cert/deploytask.html Normal file → Executable file
View File

@ -2,342 +2,322 @@
{block name="title"}SSL证书自动部署任务{/block}
{block name="main"}
<style>
tbody tr>td:nth-child(4){max-width:180px;}
.tips{cursor:pointer;}
pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51, 51, 51, 1);white-space: pre-line;color: rgba(236, 236, 236, 1)}
#orderItem .orderTitle{word-break:keep-all;}
#orderItem .orderContent{word-break:break-all;}
.fixed-table-toolbar,.fixed-table-pagination{padding: 15px;}
tbody tr>td:nth-child(4){max-width:180px;}
.tips{cursor:pointer;}
pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51, 51, 51, 1);white-space: pre-line;color: rgba(236, 236, 236, 1)}
</style>
<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">
<input type="hidden" name="aid" value="">
<input type="hidden" name="oid" value="">
<div class="form-group">
<label>搜索</label>
<div class="form-group">
<input type="text" class="form-control" name="domain" placeholder="域名">
</div>
</div>
<div class="form-group">
<div class="form-group">
<input type="text" class="form-control" name="remark" placeholder="备注">
</div>
</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>
<div class="form-group">
<select name="status" class="form-control"><option value="">所有状态</option><option value="0">待处理</option><option value="1">已完成</option><option value="-1">处理失败</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="/cert/deploy/add" 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('delete')">删除</a></li><li><a href="javascript:operation('reset')">重置任务</a></li><li><a href="javascript:operation('open')">开启任务</a></li><li><a href="javascript:operation('close')">停止任务</a></li><li><a href="javascript:operation('cert')">修改关联证书</a></li></ul>
</div>
</form>
<table id="listTable">
</table>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading font-bold">
<h3 class="panel-title">SSL证书自动部署任务</h3>
</div>
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
<input type="hidden" name="aid" value="">
<input type="hidden" name="oid" value="">
<div class="form-group">
<input type="text" class="form-control" name="domain" placeholder="域名">
</div>
<div class="form-group">
<input type="text" class="form-control" name="remark" 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>
<div class="form-group">
<select name="status" class="form-control">
<option value="">所有状态</option>
<option value="0">待处理</option>
<option value="1">已完成</option>
<option value="-1">处理失败</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="/cert/deploy/add" 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('delete')">删除</a></li><li><a href="javascript:operation('reset')">重置任务</a></li><li><a href="javascript:operation('open')">开启任务</a></li><li><a href="javascript:operation('close')">停止任务</a></li><li><a href="javascript:operation('cert')">修改关联证书</a></li></ul>
</div>
</form>
<table id="listTable">
</table>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
<script src="{$cdnpublic}FileSaver.js/2.0.5/FileSaver.min.js"></script>
<script src="/static/js/custom.js"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 10;
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 10;
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: '/cert/deploy/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
columns: [
{
field: '',
checkbox: true
},
{
field: 'id',
title: 'ID'
},
{
field: 'typename',
title: '自动部署账户',
formatter: function(value, row, index) {
if(!value) return '已被删除'
return '<span title="'+row.aname+'" data-toggle="tooltip" data-placement="right"><img src="/static/images/'+row.icon+'" class="type-logo">'+(row.aremark?row.aremark:value+'('+row.aid+')')+'</span>';
}
},
{
field: 'domains',
title: '关联SSL证书',
formatter: function(value, row, index) {
var html = '<a href="/cert/certorder?id='+row.oid+'" target="_blank">ID:'+row.oid+''+row.certtypename+'</a><br/><span class="text-muted">';
html += value.length > 3 ? value.slice(0, 3).join('、') + ' 等'+value.length+'个域名' : value.join('、');
html += '</span>';
return html;
}
},
{
field: 'remark',
title: '备注'
},
{
field: 'active',
title: '任务开关',
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" checked onchange="setActive('+row.id+',0)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
}else{
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" onchange="setActive('+row.id+',1)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
}
}
},
{
field: 'lasttime',
title: '上次执行时间',
formatter: function(value, row, index) {
return value ? value : '暂未执行'
}
},
{
field: 'status',
title: '状态',
formatter: function(value, row, index) {
if(value == 1) {
return '<span class="label label-success">已完成</span>';
} else if(value == 0) {
if(row.islock == 1) return '<span class="label" style="background-color: #3e76fb;">正在处理</span>';
else return '<span class="label label-info">待处理</span>';
} else {
return '<span class="label label-danger">处理失败</span>'+(row.error?' <span onclick="showmsg(\''+row.error+'\')" class="tips" title="失败原因"><i class="fa fa-info-circle"></i></span>':'');
}
}
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var html = '';
if(row.status == 0) {
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-play-circle"></i> 手动执行</a>&nbsp;&nbsp;';
}else if(row.status == 1) {
html += '<a href="javascript:reDoOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-play-circle"></i> 重新执行</a>&nbsp;&nbsp;';
}else{
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-repeat"></i> 重试</a>&nbsp;&nbsp;';
}
html += '<a href="/cert/deploy/edit?id='+row.id+'" class="btn btn-primary btn-xs"><i class="fa fa-edit"></i> 修改</a>&nbsp;&nbsp;';
html += '<div class="btn-group dropdown-group" role="group"><button type="button" class="btn btn-info btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">更多 <span class="caret"></span></button><ul class="dropdown-menu">';
html += '<li><a href="javascript:showLog(\''+row.processid+'\')">查看日志</a></li>';
if(row.status < 0){
html += '<li><a href="javascript:resetOrder(\''+row.id+'\')">重置任务</a></li>';
}
html += '<li><a href="javascript:delItem('+row.id+','+row.status+')">删除</a></li>';
html += '</ul></div>';
return html;
}
},
],
onLoadSuccess: function(data) {
$('[data-toggle="tooltip"]').tooltip()
$('.dropdown-group').on('show.bs.dropdown', function (e) {
var btnPos = $(e.target)[0].getBoundingClientRect();
var screenWidth = $(window).width();
var screenHeight = $(window).height();
var childrenWidth = $(e.target).children('.dropdown-menu').width();
var childrenHeight = $(e.target).children('.dropdown-menu').height();
var top = btnPos.bottom;
if(top + childrenHeight + 12 > screenHeight){
top = btnPos.top - childrenHeight - 12;
}
var left = btnPos.left;
if(left + childrenWidth + 7 > screenWidth){
left = screenWidth - childrenWidth - 7;
}
$(e.target).children('.dropdown-menu').css({position:'fixed', top:top, left:left});
});
}
})
})
function showmsg(msg){
layer.alert(msg, {icon: 0, title: '失败原因'});
}
function setActive(id, active){
$.post('/cert/deploy/setactive', {id: id, active: active}, function(data){
if(data.code == 0) {
layer.msg('修改成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
}
function delItem(id,status){
layer.confirm('确定要删除此自动部署任务吗?', {
btn: ['确定','取消']
}, function(){
$.post('/cert/deploy/del', {id: id}, function(data){
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
function doOrder(id, reset){
reset = reset || 0;
var ii = layer.msg('正在执行SSL证书部署...', {icon: 16,shade: 0.1,time: 0});
$.ajax({
type: "POST",
url: "/cert/deploy/process",
data: {id: id, reset: reset},
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0) {
layer.alert(data.msg, {icon: 1});
$('#listTable').bootstrapTable('refresh');
} else {
if(data.msg == '部署任务处理中,请稍后再试'){
layer.alert(data.msg, {icon: 2}, function(){
layer.closeAll();
var row = $("#listTable").bootstrapTable('getRowByUniqueId', id);
showLog(row.processid)
});
}else{
layer.alert(data.msg, {icon: 2});
$('#listTable').bootstrapTable('refresh');
}
}
},
error: function(data){
layer.close(ii);
layer.msg('执行超时,请稍后刷新列表或查看日志', {icon:0});
}
});
}
function resetOrder(id){
layer.confirm('重置任务后,任务将变成待处理状态,是否确定?', {
btn: ['确定','取消'], title: '重置任务', icon: 0
}, function(){
$.post('/cert/deploy/reset', {id: id}, function(data){
if(data.code == 0) {
layer.msg('重置任务状态成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
function reDoOrder(id){
layer.confirm('是否确定重新部署该证书?', {
btn: ['确定','取消'], title: '重新执行', icon: 0
}, function(){
doOrder(id, 1);
});
}
var intverval;
function showLog(processid){
if(processid == '' || processid == 'null'){
layer.msg('暂无日志', {time: 600});
return;
}
$.post('/cert/deploy/show_log', {processid: processid}, function(data){
if(data.code == 0) {
var filemtime = data.time;
layer.open({
type: 1,
title: '查看日志',
area: [$(window).width() > 768 ? '600px' : '100%', '400px'],
shadeClose: true,
resize: false,
content: '<div class="modal-log"><pre class="pre-log" id="execLog">'+data.data+'</pre></div>',
success: function(){
var exec_log = $('#execLog');
exec_log[0].scrollTop = exec_log[0].scrollHeight
intverval = setInterval(function(){
$.post('/cert/deploy/show_log', {processid: processid}, function(data){
if(data.code == 0 && data.time != filemtime) {
var exec_log = $('#execLog');
exec_log.html(data.data);
filemtime = data.time;
exec_log[0].scrollTop = exec_log[0].scrollHeight
}
}, 'json');
}, 1500)
$("#listTable").bootstrapTable({
url: '/cert/deploy/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
columns: [
{
field: '',
checkbox: true
},
end: function(){
clearInterval(intverval);
}
});
} else {
layer.msg(data.msg, {icon: 2, time: 600});
}
}, 'json');
}
function operation(action){
var rows = $("#listTable").bootstrapTable('getSelections');
if(rows.length == 0){
layer.msg('请选择要操作的任务');
return;
}
var ids = [];
for(var i in rows){
ids.push(rows[i].id);
}
if(action == 'delete'){
if(!confirm('确定要删除所选自动部署任务吗?')) return;
}else if(action == 'reset'){
if(!confirm('重置任务后,任务将变成待处理状态,是否确定重置?')) return;
}else if(action == 'cert'){
return batch_set_cert(ids);
}
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/cert/deploy/operation',
data : {act: action, ids: ids},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.closeAll();
layer.alert(data.msg, {icon: 1});
searchRefresh();
}else{
layer.alert(data.msg, {icon: 2});
{
field: 'id',
title: 'ID'
},
{
field: 'typename',
title: '自动部署账户',
formatter: function(value, row, index) {
if(!value) return '已被删除'
return '<span title="'+row.aname+'" data-toggle="tooltip" data-placement="right"><img src="/static/images/'+row.icon+'" class="type-logo">'+(row.aremark?row.aremark:value+'('+row.aid+')')+'</span>';
}
},
{
field: 'domains',
title: '关联SSL证书',
formatter: function(value, row, index) {
var html = '<a href="/cert/certorder?id='+row.oid+'" target="_blank">ID:'+row.oid+''+row.certtypename+'</a><br/><span class="text-muted">';
html += value.length > 3 ? value.slice(0, 3).join('、') + ' 等'+value.length+'个域名' : value.join('、');
html += '</span>';
return html;
}
},
{
field: 'remark',
title: '备注'
},
{
field: 'active',
title: '任务开关',
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" checked onchange="setActive('+row.id+',0)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
}else{
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" onchange="setActive('+row.id+',1)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
}
}
},
{
field: 'lasttime',
title: '上次执行时间',
formatter: function(value, row, index) {
return value ? value : '暂未执行'
}
},
{
field: 'status',
title: '状态',
formatter: function(value, row, index) {
if(value == 1) {
return '<span class="label label-success">已完成</span>';
} else if(value == 0) {
if(row.islock == 1) return '<span class="label" style="background-color: #3e76fb;">正在处理</span>';
else return '<span class="label label-info">待处理</span>';
} else {
return '<span class="label label-danger">处理失败</span>'+(row.error?' <span onclick="showmsg(\''+row.error+'\')" class="tips" title="失败原因"><i class="fa fa-info-circle"></i></span>':'');
}
}
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var html = '';
if(row.status == 0) {
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-play-circle"></i> 手动执行</a>&nbsp;&nbsp;';
}else if(row.status == 1) {
html += '<a href="javascript:reDoOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-play-circle"></i> 重新执行</a>&nbsp;&nbsp;';
}else{
html += '<a href="javascript:doOrder(\''+row.id+'\')" class="btn btn-success btn-xs"><i class="fa fa-repeat"></i> 重试</a>&nbsp;&nbsp;';
}
html += '<a href="/cert/deploy/edit?id='+row.id+'" class="btn btn-primary btn-xs"><i class="fa fa-edit"></i> 修改</a>&nbsp;&nbsp;';
html += '<div class="btn-group dropdown-group" role="group"><button type="button" class="btn btn-info btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">更多 <span class="caret"></span></button><ul class="dropdown-menu">';
html += '<li><a href="javascript:showLog(\''+row.processid+'\')">查看日志</a></li>';
if(row.status < 0){
html += '<li><a href="javascript:resetOrder(\''+row.id+'\')">重置任务</a></li>';
}
html += '<li><a href="javascript:delItem('+row.id+','+row.status+')">删除</a></li>';
html += '</ul></div>';
return html;
}
},
],
onLoadSuccess: function(data) {
$('[data-toggle="tooltip"]').tooltip()
$('.dropdown-group').on('show.bs.dropdown', function (e) {
var btnPos = $(e.target)[0].getBoundingClientRect();
var screenWidth = $(window).width();
var screenHeight = $(window).height();
var childrenWidth = $(e.target).children('.dropdown-menu').width();
var childrenHeight = $(e.target).children('.dropdown-menu').height();
var top = btnPos.bottom;
if(top + childrenHeight + 12 > screenHeight){
top = btnPos.top - childrenHeight - 12;
}
var left = btnPos.left;
if(left + childrenWidth + 7 > screenWidth){
left = screenWidth - childrenWidth - 7;
}
$(e.target).children('.dropdown-menu').css({position:'fixed', top:top, left:left});
});
}
})
})
function showmsg(msg){
layer.alert(msg, {icon: 0, title: '失败原因'});
}
function setActive(id, active){
$.post('/cert/deploy/setactive', {id: id, active: active}, function(data){
if(data.code == 0) {
layer.msg('修改成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
}
function delItem(id,status){
layer.confirm('确定要删除此自动部署任务吗?', {
btn: ['确定','取消']
}, function(){
$.post('/cert/deploy/del', {id: id}, function(data){
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
function doOrder(id, reset){
reset = reset || 0;
var ii = layer.msg('正在执行SSL证书部署...', {icon: 16,shade: 0.1,time: 0});
$.ajax({
type: "POST",
url: "/cert/deploy/process",
data: {id: id, reset: reset},
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0) {
layer.alert(data.msg, {icon: 1});
$('#listTable').bootstrapTable('refresh');
} else {
if(data.msg == '部署任务处理中,请稍后再试'){
layer.alert(data.msg, {icon: 2}, function(){
layer.closeAll();
var row = $("#listTable").bootstrapTable('getRowByUniqueId', id);
showLog(row.processid)
});
}else{
layer.alert(data.msg, {icon: 2});
$('#listTable').bootstrapTable('refresh');
}
}
},
error: function(data){
layer.close(ii);
layer.msg('执行超时,请稍后刷新列表或查看日志', {icon:0});
}
});
}
function resetOrder(id){
layer.confirm('重置任务后,任务将变成待处理状态,是否确定?', {
btn: ['确定','取消'], title: '重置任务', icon: 0
}, function(){
$.post('/cert/deploy/reset', {id: id}, function(data){
if(data.code == 0) {
layer.msg('重置任务状态成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
function reDoOrder(id){
layer.confirm('是否确定重新部署该证书?', {
btn: ['确定','取消'], title: '重新执行', icon: 0
}, function(){
doOrder(id, 1);
});
}
var intverval;
function showLog(processid){
if(processid == '' || processid == 'null'){
layer.msg('暂无日志', {time: 600});
return;
}
});
}
function batch_set_cert(ids){
layer.prompt({title: '填写证书ID', value: '', formType: 0}, function(text, index){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/cert/deploy/show_log', {processid: processid}, function(data){
if(data.code == 0) {
var filemtime = data.time;
layer.open({
type: 1,
title: '查看日志',
area: [$(window).width() > 768 ? '600px' : '100%', '400px'],
shadeClose: true,
resize: false,
content: '<div class="modal-log"><pre class="pre-log" id="execLog">'+data.data+'</pre></div>',
success: function(){
var exec_log = $('#execLog');
exec_log[0].scrollTop = exec_log[0].scrollHeight
intverval = setInterval(function(){
$.post('/cert/deploy/show_log', {processid: processid}, function(data){
if(data.code == 0 && data.time != filemtime) {
var exec_log = $('#execLog');
exec_log.html(data.data);
filemtime = data.time;
exec_log[0].scrollTop = exec_log[0].scrollHeight
}
}, 'json');
}, 1500)
},
end: function(){
clearInterval(intverval);
}
});
} else {
layer.msg(data.msg, {icon: 2, time: 600});
}
}, 'json');
}
function operation(action){
var rows = $("#listTable").bootstrapTable('getSelections');
if(rows.length == 0){
layer.msg('请选择要操作的任务');
return;
}
var ids = [];
for(var i in rows){
ids.push(rows[i].id);
}
if(action == 'delete'){
if(!confirm('确定要删除所选自动部署任务吗?')) return;
}else if(action == 'reset'){
if(!confirm('重置任务后,任务将变成待处理状态,是否确定重置?')) return;
}else if(action == 'cert'){
return batch_set_cert(ids);
}
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/cert/deploy/operation',
data : {act: 'cert', ids: ids, certid: text},
data : {act: action, ids: ids},
dataType : 'json',
success : function(data) {
layer.close(ii);
@ -350,7 +330,27 @@ function batch_set_cert(ids){
}
}
});
});
}
}
function batch_set_cert(ids){
layer.prompt({title: '填写证书ID', value: '', formType: 0}, function(text, index){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '/cert/deploy/operation',
data : {act: 'cert', ids: ids, certid: text},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.closeAll();
layer.alert(data.msg, {icon: 1});
searchRefresh();
}else{
layer.alert(data.msg, {icon: 2});
}
}
});
});
}
</script>
{/block}

349
app/view/cert/order_form.html Normal file → Executable file
View File

@ -2,194 +2,191 @@
{block name="title"}SSL证书订单{/block}
{block name="main"}
<style>
.tips{color: #f6a838; padding-left: 5px;}
.control-label[is-required]:before {
content: "*";
color: #f56c6c;
margin-right: 4px;
}
.tips{color: #f6a838; padding-left: 5px;}
.control-label[is-required]:before {
content: "*";
color: #f56c6c;
margin-right: 4px;
}
</style>
<div class="row" id="app">
<div class="col-xs-12 center-block" style="float: none;">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title"><a href="/cert/certorder" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}修改{else}添加{/if}SSL证书订单</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="taskform">
<div class="form-group">
<label class="col-sm-3 col-xs-12 control-label no-padding-right" is-required>证书账户</label>
<div class="col-sm-6"><select name="aid" v-model="set.aid" class="form-control" required>
<option value="">--选择证书账户--</option>
{foreach $accounts as $k=>$v}
<option value="{$k}" data-type="{$v.type}">{$v.name}</option>
{/foreach}
<option value="-1" data-type="">手动续期</option>
</select></div>
</div>
<div class="form-group" v-show="set.aid==-1">
<label class="col-sm-3 control-label no-padding-right" is-required>证书内容</label>
<div class="col-sm-6">
<div class="input-group">
<textarea name="fullchain" v-model="set.fullchain" class="form-control" rows="5" placeholder="输入PEM格式证书链" required></textarea>
<a class="btn btn-default input-group-addon" @click="upload('fullchain')" title="上传证书文件"><i class="fa fa-upload"></i></a>
</div>
<div id="app">
<div class="panel panel-default">
<div class="panel-heading font-bold"><h3 class="panel-title"><a href="/cert/certorder" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}修改{else}添加{/if}SSL证书订单</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="taskform">
<div class="form-group">
<label class="col-sm-3 col-xs-12 control-label no-padding-right" is-required>证书账户</label>
<div class="col-sm-6"><select name="aid" v-model="set.aid" class="form-control" required>
<option value="">--选择证书账户--</option>
{foreach $accounts as $k=>$v}
<option value="{$k}" data-type="{$v.type}">{$v.name}</option>
{/foreach}
<option value="-1" data-type="">手动续期</option>
</select></div>
</div>
<div class="form-group" v-show="set.aid==-1">
<label class="col-sm-3 control-label no-padding-right" is-required>证书内容</label>
<div class="col-sm-6">
<div class="input-group">
<textarea name="fullchain" v-model="set.fullchain" class="form-control" rows="5" placeholder="输入PEM格式证书链" required></textarea>
<a class="btn btn-default input-group-addon" @click="upload('fullchain')" title="上传证书文件"><i class="fa fa-upload"></i></a>
</div>
</div>
</div>
<div class="form-group" v-show="set.aid==-1">
<label class="col-sm-3 control-label no-padding-right" is-required>私钥内容</label>
<div class="col-sm-6">
<div class="input-group">
<textarea name="privatekey" v-model="set.privatekey" class="form-control" rows="5" placeholder="输入PEM格式私钥" required></textarea>
<a class="btn btn-default input-group-addon" @click="upload('privatekey')" title="上传私钥文件"><i class="fa fa-upload"></i></a>
</div>
</div>
</div>
<div class="form-group" v-show="set.aid!=-1">
<label class="col-sm-3 control-label no-padding-right" is-required>签名算法</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="item in keytypeList">
<input type="radio" name="keytype" :value="item" v-model="set.keytype"> {{item}}
</label>
</div>
</div>
<div class="form-group" v-show="set.aid!=-1">
<label class="col-sm-3 control-label no-padding-right" is-required>密钥长度</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="item in keysizeList">
<input type="radio" name="keysize" :value="item.value" v-model="set.keysize"> {{item.label}}
</label>
</div>
</div>
<div class="form-group" v-show="set.aid!=-1">
<label class="col-sm-3 control-label no-padding-right" is-required>绑定域名</label>
<div class="col-sm-6">
<textarea name="domains" v-model="domains" class="form-control" rows="5" placeholder="请输入域名,一行一个" required></textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">提交</button></div>
</div>
<div class="panel panel-default" v-show="set.aid!=-1"><div class="panel-body"><p><b style="color:#39b603;"><i class="fa fa-info-circle fa-fw"></i></b>提示:添加或修改订单信息,点击提交后,不会立即执行签发,只能通过计划任务或列表手动点击来执行</p><p>证书签发之前确保该主域名下没有CAA类型记录避免证书验证失败。</p></div></div>
<div class="panel panel-default" v-show="set.aid==-1"><div class="panel-body"><p><b style="color:#39b603;"><i class="fa fa-info-circle fa-fw"></i></b>提示:选择手动续期,到达设置的续期天数,只会发送消息通知。</p></div></div>
</form>
</div>
</div>
<div class="form-group" v-show="set.aid==-1">
<label class="col-sm-3 control-label no-padding-right" is-required>私钥内容</label>
<div class="col-sm-6">
<div class="input-group">
<textarea name="privatekey" v-model="set.privatekey" class="form-control" rows="5" placeholder="输入PEM格式私钥" required></textarea>
<a class="btn btn-default input-group-addon" @click="upload('privatekey')" title="上传私钥文件"><i class="fa fa-upload"></i></a>
</div>
</div>
</div>
<div class="form-group" v-show="set.aid!=-1">
<label class="col-sm-3 control-label no-padding-right" is-required>签名算法</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="item in keytypeList">
<input type="radio" name="keytype" :value="item" v-model="set.keytype"> {{item}}
</label>
</div>
</div>
<div class="form-group" v-show="set.aid!=-1">
<label class="col-sm-3 control-label no-padding-right" is-required>密钥长度</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="item in keysizeList">
<input type="radio" name="keysize" :value="item.value" v-model="set.keysize"> {{item.label}}
</label>
</div>
</div>
<div class="form-group" v-show="set.aid!=-1">
<label class="col-sm-3 control-label no-padding-right" is-required>绑定域名</label>
<div class="col-sm-6">
<textarea name="domains" v-model="domains" class="form-control" rows="5" placeholder="请输入域名,一行一个" required></textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">提交</button></div>
</div>
<div class="panel panel-default" v-show="set.aid!=-1"><div class="panel-body"><p><b style="color:#39b603;"><i class="fa fa-info-circle fa-fw"></i></b>提示:添加或修改订单信息,点击提交后,不会立即执行签发,只能通过计划任务或列表手动点击来执行</p><p>证书签发之前确保该主域名下没有CAA类型记录避免证书验证失败。</p></div></div>
<div class="panel panel-default" v-show="set.aid==-1"><div class="panel-body"><p><b style="color:#39b603;"><i class="fa fa-info-circle fa-fw"></i></b>提示:选择手动续期,到达设置的续期天数,只会发送消息通知。</p></div></div>
</form>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}vue/2.6.14/vue.min.js"></script>
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="/static/js/bootstrapValidator.min.js"></script>
<script>
var action = '{$action}';
var info = {$info|json_encode|raw};
new Vue({
el: '#app',
data: {
action: '{$action}',
type: '',
domains: '',
set: {
id: '',
aid: '',
fullchain: '',
privatekey: '',
keytype: '',
keysize: '',
domains: [],
var action = '{$action}';
var info = {$info|json_encode|raw};
new Vue({
el: '#app',
data: {
action: '{$action}',
type: '',
domains: '',
set: {
id: '',
aid: '',
fullchain: '',
privatekey: '',
keytype: '',
keysize: '',
domains: [],
},
keytypeList: [
'RSA',
'ECC'
],
keysizeMap: [
{label:'2048 bit',value:'2048',type:'RSA'},
{label:'3072 bit',value:'3072',type:'RSA'},
{label:'P-256',value:'256',type:'ECC'},
{label:'P-384',value:'384',type:'ECC'},
],
keysizeList: [],
},
keytypeList: [
'RSA',
'ECC'
],
keysizeMap: [
{label:'2048 bit',value:'2048',type:'RSA'},
{label:'3072 bit',value:'3072',type:'RSA'},
{label:'P-256',value:'256',type:'ECC'},
{label:'P-384',value:'384',type:'ECC'},
],
keysizeList: [],
},
watch: {
'set.aid': function(val){
this.type = $('option:selected', 'select[name=aid]').data('type');
},
'set.keytype': function(val){
this.keysizeList = this.keysizeMap.filter((item) => {
return item.type == val;
})
if(!this.keysizeList.filter((item) => {return item.value == this.set.keysize}).length)
this.set.keysize = this.keysizeList[0].value;
},
domains: function(val){
this.set.domains = val.split("\n").filter((item) => {
return item.trim() != '';
});
}
},
mounted() {
if(this.action == 'edit'){
Object.keys(info).forEach((key) => {
this.$set(this.set, key, info[key])
})
this.domains = info.domains.join("\n");
}else{
this.set.keytype = 'RSA';
}
$("#taskform").bootstrapValidator({
live: 'submitted',
});
$('[data-toggle="tooltip"]').tooltip();
},
methods: {
submit(){
var that=this;
$("#taskform").data("bootstrapValidator").validate();
if(!$("#taskform").data("bootstrapValidator").isValid()){
return false;
watch: {
'set.aid': function(val){
this.type = $('option:selected', 'select[name=aid]').data('type');
},
'set.keytype': function(val){
this.keysizeList = this.keysizeMap.filter((item) => {
return item.type == val;
})
if(!this.keysizeList.filter((item) => {return item.value == this.set.keysize}).length)
this.set.keysize = this.keysizeList[0].value;
},
domains: function(val){
this.set.domains = val.split("\n").filter((item) => {
return item.trim() != '';
});
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type: "POST",
url: "",
data: this.set,
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1}, function(){
if(document.referrer.indexOf('/cert/certorder?') > 0)
window.location.href = document.referrer;
else
window.location.href = '/cert/certorder';
});
}else{
layer.alert(data.msg, {icon: 2});
}
},
error: function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
},
upload(name){
//读取上传文件并填充到表单
var file = document.createElement('input');
file.type = 'file';
file.accept = '.pem,.crt,.key';
file.style.display = 'none';
file.onchange = function(){
var reader = new FileReader();
reader.onload = function(e){
this.set[name] = e.target.result;
mounted() {
if(this.action == 'edit'){
Object.keys(info).forEach((key) => {
this.$set(this.set, key, info[key])
})
this.domains = info.domains.join("\n");
}else{
this.set.keytype = 'RSA';
}
$("#taskform").bootstrapValidator({
live: 'submitted',
});
$('[data-toggle="tooltip"]').tooltip();
},
methods: {
submit(){
var that=this;
$("#taskform").data("bootstrapValidator").validate();
if(!$("#taskform").data("bootstrapValidator").isValid()){
return false;
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type: "POST",
url: "",
data: this.set,
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1}, function(){
if(document.referrer.indexOf('/cert/certorder?') > 0)
window.location.href = document.referrer;
else
window.location.href = '/cert/certorder';
});
}else{
layer.alert(data.msg, {icon: 2});
}
},
error: function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
},
upload(name){
//读取上传文件并填充到表单
var file = document.createElement('input');
file.type = 'file';
file.accept = '.pem,.crt,.key';
file.style.display = 'none';
file.onchange = function(){
var reader = new FileReader();
reader.onload = function(e){
this.set[name] = e.target.result;
}.bind(this);
reader.readAsText(file.files[0]);
}.bind(this);
reader.readAsText(file.files[0]);
}.bind(this);
document.body.appendChild(file);
file.click();
}
},
});
document.body.appendChild(file);
file.click();
}
},
});
</script>
{/block}

470
app/view/common/layout.html Normal file → Executable file
View File

@ -1,250 +1,250 @@
<!DOCTYPE html>
<html lang="zh-cn">
<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?v=2" rel="stylesheet"/>
<script src="{$cdnpublic}jquery/3.6.4/jquery.min.js"></script>
<!--[if lt IE 9]>
<meta charset="utf-8" />
<title>{block name="title"}标题{/block} | 聚合DNS管理系统</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<link rel="stylesheet" href="{$cdnpublic}twitter-bootstrap/3.3.7/css/bootstrap.min.css" type="text/css" />
<link rel="stylesheet" href="{$cdnpublic}animate.css/3.5.2/animate.min.css" type="text/css" />
<link rel="stylesheet" href="{$cdnpublic}font-awesome/4.7.0/css/font-awesome.min.css" type="text/css" />
<link rel="stylesheet" href="{$cdnpublic}simple-line-icons/2.4.1/css/simple-line-icons.min.css" type="text/css" />
<link rel="stylesheet" href="{$cdnpublic}select2/4.0.13/css/select2.min.css" type="text/css" />
<link rel="stylesheet" href="/static/css/font.css" type="text/css" />
<link rel="stylesheet" href="/static/css/app.css" type="text/css" />
<link rel="stylesheet" href="/static/css/bootstrap-table.css?v=2" />
<!--[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>
<![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>
<body>
<div class="app app-header-fixed ">
<!-- header -->
<header id="header" class="app-header navbar" role="menu">
<!-- navbar header -->
<div class="navbar-header bg-black">
<button class="pull-right visible-xs dk" ui-toggle="show" target=".navbar-collapse">
<i class="glyphicon glyphicon-cog"></i>
</button>
<button class="pull-right visible-xs" ui-toggle="off-screen" target=".app-aside" ui-scroll="app">
<i class="glyphicon glyphicon-align-justify"></i>
</button>
<!-- brand -->
<a href="./" class="navbar-brand text-lt">
<i class="fa fa-meetup"></i>
<span class="hidden-folded m-l-xs">聚合DNS管理</span>
</a>
<!-- / brand -->
</div>
</nav>
<!-- / navbar header -->
<!-- navbar collapse -->
<div class="collapse pos-rlt navbar-collapse box-shadow bg-black">
<!-- buttons -->
<div class="nav navbar-nav hidden-xs">
<a href="#" class="btn no-shadow navbar-btn" ui-toggle="app-aside-folded" target=".app">
<i class="fa fa-dedent fa-fw text"></i>
<i class="fa fa-indent fa-fw text-active"></i>
</a>
</div>
<!-- / buttons -->
<!-- nabar right -->
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" data-toggle="dropdown" class="dropdown-toggle clear" data-toggle="dropdown">
<span class="thumb-sm avatar pull-right m-t-n-sm m-b-n-sm m-l-sm">
<img src="/static/images/user.png">
<i class="on md b-white bottom"></i>
</span>
<span class="hidden-sm hidden-md" style="text-transform:uppercase;">{$user.username}</span> <b class="caret"></b>
</a>
<!-- dropdown -->
<ul class="dropdown-menu animated fadeInRight w">
{if request()->user['type'] eq 'user'}
<li>
<a href="/setpwd">
<span>修改密码</span>
</a>
</li>
{/if}
<li class="divider"></li>
<li>
<a ui-sref="access.signin" href="/logout">
<span>退出登录</span>
</a>
</li>
</ul>
<!-- / dropdown -->
</li>
</ul>
<!-- / navbar right -->
</div>
<!-- / navbar collapse -->
</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>
<!-- / header -->
<!-- aside -->
<aside id="aside" class="app-aside hidden-xs bg-white">
<div class="aside-wrap">
<div class="navi-wrap">
<!-- nav -->
<nav ui-nav class="navi clearfix">
<ul class="nav">
{if request()->user['type'] eq 'user'}
<li class="hidden-folded padder m-t m-b-sm text-muted text-xs">
<span>导航</span>
</li>
<li class="<?php echo checkIfActive('index')?>">
<a href="/">
<i class="fa fa-home fa-fw"></i>
<span class="font-bold">管理中心</span>
</a>
</li>
<li class="line dk"></li>
{/if}
<li class="hidden-folded padder m-t m-b-sm text-muted text-xs">
<span>查询</span>
</li>
<li class="{:checkIfActive('domain,record,record_log,record_batch_add,domain_add,weight,record_batch_add2,record_batch_edit2,expire_notice')}">
<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('overview,task,taskinfo,taskform')}">
<a href class="auto">
<span class="pull-right text-muted">
<i class="fa fa-fw fa-angle-right text"></i>
<i class="fa fa-fw fa-angle-down text-active"></i>
</span>
<i class="fa fa-heartbeat fa-fw"></i>
<span>容灾切换</span>
</a>
<ul class="nav nav-sub dk">
<li><a href="/dmonitor/overview">运行概览</a></li>
<li><a href="/dmonitor/task">切换策略</a></li>
</ul>
</li>
<li class="{:checkIfActive('opipset,opiplist,opipform')}">
<a href class="auto">
<span class="pull-right text-muted">
<i class="fa fa-fw fa-angle-right text"></i>
<i class="fa fa-fw fa-angle-down text-active"></i>
</span>
<i class="fa fa-globe fa-fw"></i>
<span>CF优选IP</span>
</a>
<ul class="nav nav-sub dk">
<li><a href="/optimizeip/opipset">优选设置</a></li>
<li><a href="/optimizeip/opiplist">任务管理</a></li>
</ul>
</li>
<li class="{:checkIfActive('certaccount,account_form,certorder,order_form,order_import,deployaccount,deploytask,deploy_form,certset,cname')}">
<a href class="auto">
<span class="pull-right text-muted">
<i class="fa fa-fw fa-angle-right text"></i>
<i class="fa fa-fw fa-angle-down text-active"></i>
</span>
<i class="fa fa-expeditedssl fa-fw"></i>
<span>SSL证书</span>
</a>
<ul class="nav nav-sub dk">
<li><a href="/cert/certaccount">SSL证书账户</a></li>
<li><a href="/cert/certorder">SSL证书订单</a></li>
<li><a href="/cert/deployaccount">自动部署账户</a></li>
<li><a href="/cert/deploytask">自动部署任务</a></li>
<li><a href="/cert/cname">CNAME代理</a></li>
<li><a href="/cert/certset">计划任务设置</a></li>
</ul>
</li>
<li class="{:checkIfActive('loginset,noticeset,proxyset')}">
<a href class="auto">
<span class="pull-right text-muted">
<i class="fa fa-fw fa-angle-right text"></i>
<i class="fa fa-fw fa-angle-down text-active"></i>
</span>
<i class="fa fa-cogs fa-fw"></i>
<span>系统设置</span>
</a>
<ul class="nav nav-sub dk">
<li><a href="/system/loginset">登录设置</a></li>
<li><a href="/system/noticeset">通知设置</a></li>
<li><a href="/system/proxyset">代理设置</a></li>
<li><a href="https://www.showdoc.com.cn/dnsmgr/11058996709621562" target="_blank" rel="noreferrer">接口文档</a></li>
</ul>
</li>
<li class="{:checkIfActive('user')}">
<a href="/user"><i class="fa fa-user fa-fw"></i> <span>用户管理</span></a>
</li>
{/if}
<li class="line dk hidden-folded"></li>
<li class="hidden-folded padder m-t m-b-sm text-muted text-xs">
<span>其他</span>
</li>
<li class="{:checkIfActive('log')}">
<a href="/log"><i class="fa fa-list fa-fw"></i> <span>操作日志</span></a>
</li>
</ul>
</nav>
<!-- nav -->
<!-- aside footer -->
<div class="wrapper m-t">
<div class="text-center-folded">
<span class="pull-right pull-none-folded">60%</span>
<span class="hidden-folded">Milestone</span>
</div>
<div class="progress progress-xxs m-t-sm dk">
<div class="progress-bar progress-bar-info" style="width: 60%;">
</div>
</div>
<div class="text-center-folded">
<span class="pull-right pull-none-folded">35%</span>
<span class="hidden-folded">Release</span>
</div>
<div class="progress progress-xxs m-t-sm dk">
<div class="progress-bar progress-bar-primary" style="width: 35%;">
</div>
</div>
</div>
<!-- / aside footer -->
</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,record_batch_add,domain_add,weight,record_batch_add2,record_batch_edit2,expire_notice')}">
<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="treeview {:checkIfActive('overview,task,taskinfo,taskform')}">
<a href="javascript:;">
<i class="fa fa-heartbeat fa-fw"></i>
<span>容灾切换</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li class="{:checkIfActive('overview')}"><a href="/dmonitor/overview"><i class="fa fa-circle-o"></i> 运行概览</a></li>
<li class="{:checkIfActive('task,taskform')}"><a href="/dmonitor/task"><i class="fa fa-circle-o"></i> 切换策略</a></li>
</ul>
</li>
<li class="treeview {:checkIfActive('opipset,opiplist,opipform')}">
<a href="javascript:;">
<i class="fa fa-globe fa-fw"></i>
<span>CF优选IP</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li class="{:checkIfActive('opipset')}"><a href="/optimizeip/opipset"><i class="fa fa-circle-o"></i> 优选设置</a></li>
<li class="{:checkIfActive('opiplist,opipform')}"><a href="/optimizeip/opiplist"><i class="fa fa-circle-o"></i> 任务管理</a></li>
</ul>
</li>
<li class="treeview {:checkIfActive('certaccount,account_form,certorder,order_form,order_import,deployaccount,deploytask,deploy_form,certset,cname')}">
<a href="javascript:;">
<i class="fa fa-expeditedssl fa-fw"></i>
<span>SSL证书</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li class="{:checkIfActive('certaccount')}"><a href="/cert/certaccount"><i class="fa fa-circle-o"></i> SSL证书账户</a></li>
<li class="{:checkIfActive('certorder,order_form,order_import')}"><a href="/cert/certorder"><i class="fa fa-circle-o"></i> SSL证书订单</a></li>
<li class="{:checkIfActive('deployaccount')}"><a href="/cert/deployaccount"><i class="fa fa-circle-o"></i> 自动部署账户</a></li>
<li class="{:checkIfActive('deploytask,deploy_form')}"><a href="/cert/deploytask"><i class="fa fa-circle-o"></i> 自动部署任务</a></li>
<li class="{:checkIfActive('cname')}"><a href="/cert/cname"><i class="fa fa-circle-o"></i> CNAME代理</a></li>
<li class="{:checkIfActive('certset')}"><a href="/cert/certset"><i class="fa fa-circle-o"></i> 计划任务设置</a></li>
</ul>
</li>
<li class="treeview {:checkIfActive('loginset,noticeset,proxyset')}">
<a href="javascript:;">
<i class="fa fa-cogs fa-fw"></i>
<span>系统设置</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li class="{:checkIfActive('loginset')}"><a href="/system/loginset"><i class="fa fa-circle-o"></i> 登录设置</a></li>
<li class="{:checkIfActive('noticeset')}"><a href="/system/noticeset"><i class="fa fa-circle-o"></i> 通知设置</a></li>
<li class="{:checkIfActive('proxyset')}"><a href="/system/proxyset"><i class="fa fa-circle-o"></i> 代理设置</a></li>
<li><a href="https://www.showdoc.com.cn/dnsmgr/11058996709621562" target="_blank" rel="noreferrer"><i class="fa fa-circle-o"></i> <span>接口文档</span></a></li>
</ul>
</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>
</ul>
</section>
<!-- /.sidebar -->
</aside>
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Main content -->
<section class="content">
{block name="main"}主内容{/block}
</section>
<!-- /.content -->
<!-- / aside -->
<!-- content -->
<div id="content" class="app-content" role="main">
<div class="app-content-body ">
<div class="bg-light lter b-b wrapper-md hidden-print">
<h1 class="m-n font-thin h3">{block name="title"}标题{/block}</h1>
</div>
<div class="wrapper-md control">
{block name="main"}主内容{/block}
</div>
</div>
</div>
<!-- / content -->
<!-- footer -->
<footer id="footer" class="app-footer" role="footer">
<div class="wrapper b-t bg-light">
<span class="pull-right">Powered by <a href="/" target="_blank">聚合DNS管理系统</a></span>
&copy; 2016-2024 Copyright.
</div>
</footer>
<!-- / footer -->
</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="{$cdnpublic}jquery/3.4.1/jquery.min.js"></script>
<script src="{$cdnpublic}twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="{$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>
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="/static/js/ui-load.js"></script>
<script src="/static/js/ui-jp.config.js"></script>
<script src="/static/js/ui-jp.js"></script>
<script src="/static/js/ui-nav.js"></script>
<script src="/static/js/ui-toggle.js"></script>
{block name="script"}{/block}
</body>
</html>

180
app/view/dispatch_jump.html Normal file → Executable file
View File

@ -1,60 +1,162 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<title>温馨提示</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<meta name="renderer" content="webkit"/>
<meta content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" name="viewport">
<meta content="webkit" name="renderer"/>
<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;}}
* {
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" />
<img alt="" src="/static/images/{$code}.svg" width="150"/>
</div>
<h1>{$msg}</h1>
{if $url}
<p class="jump">
页面将在 <span id="wait">{$wait}</span> 秒后自动跳转
</p>
<p class="jump">
页面将在 <span id="wait">{$wait}</span> 秒后自动跳转
</p>
{/if}
<p class="clearfix">
<a href="javascript:history.go(-1);" class="btn btn-grey">返回上一页</a>
<a class="btn btn-grey" href="javascript:history.go(-1);">返回上一页</a>
{if $url}
<a href="{$url}" class="btn btn-primary">立即跳转</a>
<a class="btn btn-primary" href="{$url}">立即跳转</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>
<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>

389
app/view/dmonitor/overview.html Normal file → Executable file
View File

@ -2,211 +2,208 @@
{block name="title"}容灾切换运行概览{/block}
{block name="main"}
<style>
.info-box-content{padding:18px 10px}
.hbox{display:table;width:100%;height:100%;border-spacing:0;table-layout:fixed;border:1px solid #edf1f2}
.hbox .col{display:table-cell;float:none;height:100%;vertical-align:top;border:1px solid #edf1f2;padding-top:18px;padding-bottom:18px;color:#98a6ad}
.hbox .col .fa{display:block;padding-bottom:3px}
.hbox .col span{font-size:14px}
.hbox .col:hover{background-color:#f9f9f9;color:#6e7173}
.round {
line-height: 53px;
color: #7266ba;
width: 58px;
height: 58px;
font-size: 26px;
margin-left:15px;
display: inline-block;
font-weight: 400;
border: 3px solid #f8f8fe;
text-align: center;
border-radius: 50%;
background: #e3dff9;
}
</style>
<div class="modal" id="modal-clean">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">数据清理</h4>
</div>
<div class="modal-body">
<form id="form-clean" onsubmit="return false;">
<div class="form-group">
<label>清理多少天前的切换记录</label>
<input type="number" class="form-control" name="days" value="30">
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-info" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-danger" onclick="submitClean()">确定</button>
</div>
</div>
</div>
<div aria-hidden="true" aria-labelledby="myModalLabel" class="modal inmodal fade" data-backdrop="static" id="modal-clean" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button aria-label="Close" class="close" data-dismiss="modal" type="button">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">数据清理</h4>
</div>
<div class="modal-body">
<form id="form-clean" onsubmit="return false;">
<div class="form-group">
<label>清理多少天前的切换记录</label>
<input class="form-control" name="days" type="number" value="30">
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-outline-info" data-dismiss="modal" type="button">取消</button>
<button class="btn btn-primary" onclick="submitClean()" type="button">确定</button>
</div>
</div>
</div>
</div>
<div class="modal" id="modal-notice">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">通知设置</h4>
</div>
<div class="modal-body">
<form id="form-notice" onsubmit="return false;" class="form-horizontal">
<div class="form-group">
<label class="col-sm-4 control-label">邮件通知</label>
<div class="col-sm-8"><select class="form-control" name="notice_mail" default="{:config_get('notice_mail')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">微信公众号通知</label>
<div class="col-sm-8"><select class="form-control" name="notice_wxtpl" default="{:config_get('notice_wxtpl')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Telegram机器人通知</label>
<div class="col-sm-8"><select class="form-control" name="notice_tgbot" default="{:config_get('notice_tgbot')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">群机器人Webhook</label>
<div class="col-sm-8"><select class="form-control" name="notice_webhook" default="{:config_get('notice_webhook')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-info" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary" onclick="submitNotice()">确定</button>
</div>
</div>
</div>
<div aria-hidden="true" aria-labelledby="myModalLabel" class="modal inmodal fade" data-backdrop="static" id="modal-notice" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button aria-label="Close" class="close" data-dismiss="modal" type="button">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">通知设置</h4>
</div>
<div class="modal-body">
<form id="form-notice" onsubmit="return false;" class="form-horizontal">
<div class="form-group">
<label class="col-sm-4 control-label">邮件通知</label>
<div class="col-sm-8"><select class="form-control" name="notice_mail" default="{:config_get('notice_mail')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">微信公众号通知</label>
<div class="col-sm-8"><select class="form-control" name="notice_wxtpl" default="{:config_get('notice_wxtpl')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Telegram机器人通知</label>
<div class="col-sm-8"><select class="form-control" name="notice_tgbot" default="{:config_get('notice_tgbot')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">群机器人Webhook</label>
<div class="col-sm-8"><select class="form-control" name="notice_webhook" default="{:config_get('notice_webhook')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-outline-info" data-dismiss="modal" type="button">取消</button>
<button class="btn btn-primary" onclick="submitNotice()" type="button">确定</button>
</div>
</div>
</div>
</div>
<div class="row row-sm text-center">
<div class="col-xs-6 col-sm-3">
<div class="panel padder-v item">
<div class="row">
<div class="col-xs-3"><div class="round"><i class="fa fa-certificate fa-fw"></i></div></div>
<div class="col-xs-9"><div class="h1 text-primary-dk font-thin h1"><span>{$info.run_state==1?'<font color="green">正在运行</font>':'<font color="red">已停止</font>'}</span><span class="text-muted text-md"></span></div><span class="text-muted">运行状态</span></div>
</div>
</div>
</div>
<div class="col-xs-6 col-sm-3">
<div class="panel padder-v item">
<div class="row">
<div class="col-xs-3"><div class="round"><i class="fa fa-heart fa-fw"></i></div></div>
<div class="col-xs-9"><div class="h1 text-dark-dk font-thin h1"><span>{$info.run_count}</span><span class="text-muted text-md"></span></div><span class="text-muted">今日运行次数</span></div>
</div>
</div>
</div>
<div class="col-xs-6 col-sm-3">
<div class="panel padder-v item">
<div class="row">
<div class="col-xs-3"><div class="round"><i class="fa fa-bandcamp fa-fw"></i></div></div>
<div class="col-xs-9"><div class="h1 text-success-dk font-thin h1"><span>{$info.fail_count}</span><span class="text-muted text-md"></span></div><span class="text-muted">24H告警次数</span></div>
</div>
</div>
</div>
<div class="col-xs-6 col-sm-3">
<div class="panel padder-v item">
<div class="row">
<div class="col-xs-3"><div class="round"><i class="fa fa-gratipay fa-fw"></i></div></div>
<div class="col-xs-9"><div class="h1 text-info-dk font-thin h1"><span>{$info.switch_count}</span><span class="text-muted text-md"></span></div><span class="text-muted">24H切换次数</span></div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-aqua"><i class="fa fa-certificate"></i></span>
<div class="info-box-content">
<span class="info-box-text">运行状态</span>
<span class="info-box-number">{$info.run_state==1?'<font color="green">正在运行</font>':'<font color="red">已停止</font>'}</span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-green"><i class="fa fa-heart"></i></span>
<div class="info-box-content">
<span class="info-box-text">今日运行次数</span>
<span class="info-box-number">{$info.run_count}</span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
<!-- fix for small devices only -->
<div class="clearfix visible-sm-block"></div>
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-red"><i class="fa fa-bandcamp"></i></span>
<div class="info-box-content">
<span class="info-box-text">24H告警次数</span>
<span class="info-box-number">{$info.fail_count}</span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="info-box">
<span class="info-box-icon bg-yellow"><i class="fa fa-gratipay"></i></span>
<div class="info-box-content">
<span class="info-box-text">24H切换次数</span>
<span class="info-box-number">{$info.switch_count}</span>
</div>
<!-- /.info-box-content -->
</div>
<!-- /.info-box -->
</div>
<!-- /.col -->
</div>
<div class="row">
<div class="col-xs-12 col-md-6">
<div class="panel panel-success">
<div class="panel-heading"><h3 class="panel-title">运行概览</h3></div>
<div class="panel-body">
<li class="list-group-item"><span class="glyphicon glyphicon-time"></span> <b>上次运行时间:</b> {$info.run_time}</li>
<li class="list-group-item"><span class="glyphicon glyphicon-time"></span> <b>当前时间:</b> {:date('Y-m-d H:i:s')}</li>
<li class="list-group-item"><span class="fa fa-th-large"></span> <b>Swoole组件</b> {$info.swoole|raw}</li>
{if $info.run_error}<li class="list-group-item"><span class="fa fa-times-circle"></span> <b>上次运行错误信息:</b> {$info.run_error}</li>{/if}
<div class="hbox text-center text-sm">
<a href="/dmonitor/task" class="col">
<i class="fa fa-list-alt fa-2x"></i>
<span>切换策略</span>
</a>
<a href="javascript:noticeset()" class="col">
<i class="fa fa-bullhorn fa-2x"></i>
<span>通知设置</span>
</a>
<a href="javascript:clean()" class="col">
<i class="fa fa-trash fa-2x"></i>
<span>数据清理</span>
</a>
</div>
<div class="col-xs-12 col-md-6">
<div class="panel panel-success">
<div class="panel-heading font-bold"><h3 class="panel-title">运行概览</h3></div>
<div class="panel-body">
<li class="list-group-item"><span class="glyphicon glyphicon-time"></span>
<b>上次运行时间:</b>{$info.run_time}
</li>
<li class="list-group-item">
<span class="glyphicon glyphicon-time"></span>
<b>当前时间:</b>{:date('Y-m-d H:i:s')}
</li>
<li class="list-group-item">
<span class="fa fa-th-large"></span>
<b>Swoole组件</b>{$info.swoole|raw}
</li>
{if $info.run_error}
<li class="list-group-item">
<span class="fa fa-times-circle"></span>
<b>上次运行错误信息:</b>{$info.run_error}
</li>
{/if}
<li class="list-group-item">
<div class="hbox text-center b-light text-sm">
<a href="/dmonitor/task" class="col padder-v text-muted b-light">
<i class="fa fa-list-alt block m-b-xs fa-2x"></i>
<span>切换策略</span>
</a>
<a href="javascript:noticeset()" class="col padder-v text-muted b-light">
<i class="fa fa-bullhorn block m-b-xs fa-2x"></i>
<span>通知设置</span>
</a>
<a href="javascript:clean()" class="col padder-v text-muted b-light">
<i class="fa fa-trash block m-b-xs fa-2x"></i>
<span>数据清理</span>
</a>
</div>
</li>
</div>
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6">
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">操作说明</h3></div>
<div class="panel-body">
<p>1、php需要安装swoole组件</p>
<p>2、在命令行执行以下命令启动进程</p>
<p><code>cd {:app()->getRootPath()} && php think dmtask</code></p>
<p>3、也可以使用进程守护管理器添加守护进程运行目录{:app()->getRootPath()}启动命令php think dmtask</p>
<div class="col-xs-12 col-md-6">
<div class="panel panel-info">
<div class="panel-heading font-bold"><h3 class="panel-title">操作说明</h3></div>
<div class="panel-body">
<p>1、php需要安装swoole组件</p>
<p>2、在命令行执行以下命令启动进程<code>cd {:app()->getRootPath()} && php think dmtask</code></p>
<p>3、也可以使用进程守护管理器添加守护进程运行目录<code>{:app()->getRootPath()}</code>,启动命令:<code>php think dmtask</code></p>
</div>
</div>
</div>
</div>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script>
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default")||0);
}
function clean(){
$('#modal-clean').modal('show');
}
function noticeset(){
$('#modal-notice').modal('show');
}
function submitClean(){
var days = $('#form-clean input[name=days]').val();
if(days < 1){
layer.alert('清理天数不能小于1', {icon: 2});
return;
}
$.post('/dmonitor/clean', {days: days}, function(res){
if(res.code == 0){
layer.msg(res.msg, {icon: 1});
$('#modal-clean').modal('hide');
}else{
layer.alert(res.msg, {icon: 2});
}
});
}
function submitNotice(){
$.post('/system/set', $("#form-notice").serialize(), function(res){
if(res.code == 0){
layer.alert('设置保存成功!<br/>重启检测进程或容器后生效', {
icon: 1,
closeBtn: false
}, function(){
window.location.reload()
});
}else{
layer.alert(res.msg, {icon: 2});
}
});
}
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default")||0);
}
function clean() {
$('#modal-clean').modal('show');
}
function noticeset(){
$('#modal-notice').modal('show');
}
function submitClean() {
var days = $('#form-clean input[name=days]').val();
if (days < 1) {
layer.alert('清理天数不能小于1', {icon: 2});
return;
}
$.post('/dmonitor/clean', {days: days}, function (res) {
if (res.code == 0) {
layer.msg(res.msg, {icon: 1});
$('#modal-clean').modal('hide');
} else {
layer.alert(res.msg, {icon: 2});
}
});
}
function submitNotice(){
$.post('/system/set', $("#form-notice").serialize(), function(res){
if(res.code == 0){
layer.alert('设置保存成功!<br/>重启检测进程或容器后生效', {
icon: 1,
closeBtn: false
}, function(){
window.location.reload()
});
}else{
layer.alert(res.msg, {icon: 2});
}
});
}
</script>
{/block}

331
app/view/dmonitor/task.html Normal file → Executable file
View File

@ -2,177 +2,184 @@
{block name="title"}容灾切换策略{/block}
{block name="main"}
<style>
tbody tr>td:nth-child(2){overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:180px;}
#orderItem .orderTitle{word-break:keep-all;}
#orderItem .orderContent{word-break:break-all;}
.fixed-table-toolbar,.fixed-table-pagination{padding: 15px;}
</style>
<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>
<div class="form-group">
<select name="type" class="form-control"><option value="1">域名</option><option value="3">解析记录</option><option value="4">备用解析记录</option><option value="2">解析记录ID</option><option value="5">备注</option></select>
</div>
</div>
<div class="form-group">
<input type="text" class="form-control" name="kw" placeholder="">
</div>
<div class="form-group">
<div class="form-group">
<select name="status" class="form-control"><option value="">健康状况</option><option value="0">正常</option><option value="1">异常</option></select>
</div>
</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="/dmonitor/task/add" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
</form>
<table id="listTable">
</table>
<div class="panel panel-default">
<div class="panel-heading font-bold">
<h3 class="panel-title">容灾切换策略</h3>
</div>
</div>
</div>
<form class="form-inline" id="searchToolbar" method="GET" onsubmit="return searchSubmit()">
<div class="form-group">
<div class="form-group">
<select class="form-control" name="type">
<option value="1">域名</option>
<option value="3">解析记录</option>
<option value="4">备用解析记录</option>
<option value="2">解析记录ID</option>
<option value="5">备注</option>
</select>
</div>
</div>
<div class="form-group">
<input class="form-control" name="kw" placeholder="" type="text">
</div>
<div class="form-group">
<div class="form-group">
<select name="status" class="form-control">
<option value="">健康状况</option>
<option value="0">正常</option>
<option value="1">异常</option>
</select>
</div>
</div>
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
<a class="btn btn-default" href="javascript:searchClear()" title="刷新容灾切换策略"><i class="fa fa-refresh"></i> 刷新</a>
<a class="btn btn-success" href="/dmonitor/task/add"><i class="fa fa-plus"></i> 添加</a>
</form>
<table id="listTable">
</table>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/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;
$(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: '/dmonitor/task/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
columns: [
{
field: 'id',
title: 'ID'
},
{
field: 'rr',
title: '域名',
formatter: function(value, row, index) {
return '<span title="'+row.remark+'" data-toggle="tooltip" data-placement="right">' + value + '.' + row.domain + '</span>';
}
},
{
field: 'main_value',
title: '解析记录',
formatter: function(value, row, index) {
return value;
}
},
{
field: 'type',
title: '切换设置',
formatter: function(value, row, index) {
if(value == 1) {
return '暂停解析';
} else if(value == 2) {
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="备用:'+row.backup_value+'" class="tips">切换备用</span>';
} else if(value == 3) {
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="同域名正常数量<='+row.cycle+'" class="tips">条件开启</span>';
} else {
return '无操作';
}
}
},
{
field: 'frequency',
title: '检测间隔',
formatter: function(value, row, index) {
if(row.type <= 2){
var checktype = 'PING';
if(row.checktype == 2){
checktype = row.checkurl;
}else if(row.checktype == 1){
checktype = 'TCP('+row.tcpport+'端口)';
}
}else{
var checktype = '';
}
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="'+checktype+'" class="tips">' + value + '秒</span>';
}
},
{
field: 'status',
title: '健康状况',
formatter: function(value, row, index) {
if(value == 0) {
return '<span class="label label-success">正常</span>';
} else {
return '<span class="label label-danger">异常</span>';
}
}
},
{
field: 'active',
title: '运行开关',
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" checked onchange="setActive('+row.id+',0)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
}else{
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" onchange="setActive('+row.id+',1)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
}
}
},
{
field: 'checktime',
title: '上次检测时间',
formatter: function(value, row, index) {
return value > 0 ? row.checktimestr : '未运行';
}
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var html = '<a href="/dmonitor/task/info/'+row.id+'" class="btn btn-info btn-xs">切换日志</a>&nbsp;&nbsp;';
html += '<a href="/dmonitor/task/edit?id='+row.id+'" class="btn btn-primary btn-xs">修改</a>&nbsp;&nbsp;';
html += '<a href="/record/'+row.did+'?keyword='+row.rr+'" class="btn btn-default btn-xs" target="_blank">解析</a>&nbsp;&nbsp;';
html += '<a href="javascript:delItem(\''+row.id+'\')" class="btn btn-danger btn-xs">删除</a>&nbsp;&nbsp;';
return html;
}
},
],
onLoadSuccess: function(data) {
$('[data-toggle="tooltip"]').tooltip()
}
})
})
function setActive(id, active){
$.post('/dmonitor/task/setactive', {id: id, active: active}, function(data){
if(data.code == 0) {
layer.msg('修改成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
}
function delItem(id){
layer.confirm('确定要删除此切换策略吗?', {
btn: ['确定','取消']
}, function(){
$.post('/dmonitor/task/del', {id: id}, function(data){
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
$("#listTable").bootstrapTable({
url: '/dmonitor/task/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
columns: [
{
field: 'id',
title: 'ID'
},
{
field: 'rr',
title: '域名',
formatter: function (value, row, index) {
return '<span title="' + row.remark + '" data-toggle="tooltip" data-placement="right">' + value + '.' + row.domain + '</span>';
}
},
{
field: 'main_value',
title: '解析记录',
formatter: function (value, row, index) {
return value;
}
},
{
field: 'type',
title: '切换设置',
formatter: function (value, row, index) {
if (value == 1) {
return '暂停解析';
} else if (value == 2) {
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="备用:' + row.backup_value + '" class="tips">切换备用</span>';
} else if (value == 3) {
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="同域名正常数量<=' + row.cycle + '" class="tips">条件开启</span>';
} else {
return '无操作';
}
}
},
{
field: 'frequency',
title: '检测间隔',
formatter: function (value, row, index) {
if (row.type <= 2) {
var checktype = 'PING';
if (row.checktype == 2) {
checktype = row.checkurl;
} else if (row.checktype == 1) {
checktype = 'TCP(' + row.tcpport + '端口)';
}
} else {
var checktype = '';
}
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="' + checktype + '" class="tips">' + value + '秒</span>';
}
},
{
field: 'status',
title: '健康状况',
formatter: function (value, row, index) {
if (value == 0) {
return '<span class="label label-success">正常</span>';
} else {
return '<span class="label label-danger">异常</span>';
}
}
},
{
field: 'active',
title: '运行开关',
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="active' + row.id + '" type="checkbox" checked onchange="setActive(' + row.id + ',0)"/><label for="active' + row.id + '" class="label-primary"></label></div>';
}else{
return '<div class="material-switch"><input id="active' + row.id + '" type="checkbox" onchange="setActive(' + row.id + ',1)"/><label for="active' + row.id + '" class="label-primary"></label></div>';
}
}
},
{
field: 'checktime',
title: '上次检测时间',
formatter: function (value, row, index) {
return value > 0 ? row.checktimestr : '未运行';
}
},
{
field: 'action',
title: '操作',
formatter: function (value, row, index) {
var html = '<a href="/dmonitor/task/info/' + row.id + '" class="btn btn-info btn-xs">切换日志</a>&nbsp;&nbsp;';
html += '<a href="/dmonitor/task/edit?id=' + row.id + '" class="btn btn-primary btn-xs">修改</a>&nbsp;&nbsp;';
html += '<a href="/record/' + row.did + '?keyword=' + row.rr + '" class="btn btn-default btn-xs" target="_blank">解析</a>&nbsp;&nbsp;';
html += '<a href="javascript:delItem(\'' + row.id + '\')" class="btn btn-danger btn-xs">删除</a>&nbsp;&nbsp;';
return html;
}
},
],
onLoadSuccess: function (data) {
$('[data-toggle="tooltip"]').tooltip()
}
})
})
function setActive(id, active) {
$.post('/dmonitor/task/setactive', {id: id, active: active}, function (data) {
if (data.code == 0) {
layer.msg('修改成功', {icon: 1, time: 800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
}
function delItem(id) {
layer.confirm('确定要删除此切换策略吗?', {
btn: ['确定', '取消']
}, function () {
$.post('/dmonitor/task/del', {id: id}, function (data) {
if (data.code == 0) {
layer.msg('删除成功', {icon: 1, time: 800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
</script>
{/block}

553
app/view/dmonitor/taskform.html Normal file → Executable file
View File

@ -2,149 +2,160 @@
{block name="title"}容灾切换策略{/block}
{block name="main"}
<style>
.dselect::before{
.dselect::before {
content: '.';
position: absolute;
left: 0;
}
.control-label[is-required]:before {
content: "*";
color: #f56c6c;
margin-right: 4px;
}
.tips{color: #f6a838; padding-left: 5px;}
.tips {
color: #f6a838;
padding-left: 5px;
}
</style>
<div class="row" id="app">
<div class="col-xs-12 center-block" style="float: none;">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title"><a href="/dmonitor/task" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}编辑{else}添加{/if}容灾切换策略</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="taskform">
<div class="form-group">
<label class="col-sm-3 col-xs-12 control-label no-padding-right" is-required>域名选择</label>
<div class="col-sm-6">
<div class="input-group">
<input type="text" name="rr" v-model="set.rr" placeholder="主机记录" class="form-control" required>
<span class="input-group-addon">.</span>
<select name="did" v-model="set.did" class="form-control" required>
<option value="">--主域名--</option>
<option v-for="option in domainList" :value="option.id">{{option.name}}</option>
</select>
</div>
<div id="app">
<div class="panel panel-default">
<div class="panel-heading font-bold"><h3 class="panel-title"><a class="btn btn-sm btn-default pull-right" href="/dmonitor/task" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}编辑{else}添加{/if}容灾切换策略</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="taskform">
<div class="form-group">
<label class="col-sm-3 col-xs-12 control-label no-padding-right is-required">域名选择</label>
<div class="col-sm-6">
<div class="input-group">
<input type="text" name="rr" v-model="set.rr" placeholder="主机记录" class="form-control" required>
<span class="input-group-addon">.</span>
<select name="did" v-model="set.did" class="form-control" required>
<option value="">--主域名--</option>
<option v-for="option in domainList" :value="option.id">{{option.name}}</option>
</select>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right is-required">解析记录</label>
<div class="col-sm-6">
<div class="input-group">
<select name="recordid" v-model="set.recordid" id="recordid" class="form-control" required>
<option v-for="option in recordList" :value="option.RecordId">{{option.Value}}
(线路:{{option.LineName}})
</option>
</select>
<div class="input-group-btn">
<button type="button" @click="getRecordList" class="btn btn-info">点击获取</button>
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right is-required">切换设置</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="option in typeList">
<input type="radio" name="type" :value="option.value" v-model="set.type" :disabled="option.disabled"> {{option.label}}
</label>
</div>
</div>
<div class="form-group" v-show="set.type==2">
<label class="col-sm-3 control-label no-padding-right is-required">备用解析记录</label>
<div class="col-sm-6">
<input type="text" name="backup_value" v-model="set.backup_value" placeholder="支持填写IPv4或CNAME地址" class="form-control" required>
</div>
</div>
<div class="form-group" v-show="set.type==2&&dnstype=='cloudflare'">
<div class="col-sm-offset-3 col-sm-7">
<div class="checkbox">
<label>
<input type="checkbox" name="name" v-model="set.cdn"> 切换时同时开启Cloudflare代理模式
</label>
</div>
</div>
</div>
<div class="form-group" v-show="set.type<=2">
<label class="col-sm-3 control-label no-padding-right is-required">检测协议</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="option in checktypeList">
<input type="radio" name="checktype" :value="option.value" v-model="set.checktype" :disabled="option.disabled"> {{option.label}}
</label>
</div>
</div>
<div class="form-group" v-show="set.type<=2&&set.checktype<2">
<label class="col-sm-3 control-label no-padding-right is-required">指定检测IP</label>
<div class="col-sm-6">
<input type="text" name="checkip" v-model="set.checkurl" placeholder="留空默认为解析记录值IP" class="form-control">
</div>
</div>
<div class="form-group" v-show="set.type<=2&&set.checktype==1">
<label class="col-sm-3 control-label no-padding-right is-required">TCP检测端口</label>
<div class="col-sm-6">
<input type="text" name="tcpport" v-model="set.tcpport" placeholder="填写TCP端口号" class="form-control" data-bv-integer="true" min="1" max="65535" required>
</div>
</div>
<div class="form-group" v-show="set.type<=2&&set.checktype==2">
<label class="col-sm-3 control-label no-padding-right is-required">检测URL地址</label>
<div class="col-sm-6">
<input type="text" name="checkurl" v-model="set.checkurl" placeholder="填写以http(s)://开头的完整地址http状态码须为2xx/3xx" class="form-control" data-bv-uri="true" required>
</div>
</div>
<div class="form-group" v-show="set.type<=2&&set.checktype==2">
<label class="col-sm-3 control-label no-padding-right">使用代理请求</label>
<div class="col-sm-6">
<label class="radio-inline">
<input type="radio" name="proxy" value="0" v-model="set.proxy">
</label>
<label class="radio-inline">
<input type="radio" name="proxy" value="1" v-model="set.proxy">
</label>
</div>
</div>
<div class="form-group" v-show="set.type<=2&&set.checktype>0">
<label class="col-sm-3 control-label no-padding-right is-required">最大超时时间</label>
<div class="col-sm-3">
<div class="input-group">
<input type="text" name="timeout" v-model="set.timeout" placeholder="填写请求最大超时时间" class="form-control" data-bv-integer="true" min="1" required>
<span class="input-group-addon"></span>
</div>
</div>
</div>
<div class="form-group" v-show="set.type==3">
<label class="col-sm-3 control-label no-padding-right is-required">同域名正常数量<span class="tips" title="" data-toggle="tooltip" data-placement="bottom" data-original-title="与暂停解析配合使用,当同域名正常记录数量&lt;=几条时开启解析"><i class="fa fa-question-circle"></i></span></label>
<div class="col-sm-3">
<input type="text" name="cycle" v-model="set.cycle" placeholder="同域名正常记录数量&lt;=几条时开启解析" class="form-control" data-bv-integer="true" min="0" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right is-required">检测间隔</label>
<div class="col-sm-3">
<div class="input-group">
<input type="text" name="frequency" v-model="set.frequency" placeholder="每次检测的间隔时间" class="form-control" data-bv-integer="true" min="1" required>
<span class="input-group-addon"></span>
</div>
</div>
</div>
<div class="form-group" v-show="set.type<=2">
<label class="col-sm-3 control-label no-padding-right is-required">确认次数</label>
<div class="col-sm-3">
<input type="text" name="cycle" v-model="set.cycle" placeholder="连续失败几次后进行切换" class="form-control" data-bv-integer="true" min="1" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">备注</label>
<div class="col-sm-6">
<input type="text" name="remark" v-model="set.remark" placeholder="可留空" class="form-control">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="button" class="btn btn-primary" @click="submit">提交</button>
</div>
</div>
</form>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" is-required>解析记录</label>
<div class="col-sm-6"><div class="input-group">
<select name="recordid" v-model="set.recordid" id="recordid" class="form-control" required>
<option v-for="option in recordList" :value="option.RecordId">{{option.Value}} (线路:{{option.LineName}})</option>
</select>
<div class="input-group-btn">
<button type="button" @click="getRecordList" class="btn btn-info">点击获取</button>
</div>
</div></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" is-required>切换设置</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="option in typeList">
<input type="radio" name="type" :value="option.value" v-model="set.type" :disabled="option.disabled"> {{option.label}}
</label>
</div>
</div>
<div class="form-group" v-show="set.type==2">
<label class="col-sm-3 control-label no-padding-right" is-required>备用解析记录</label>
<div class="col-sm-6">
<input type="text" name="backup_value" v-model="set.backup_value" placeholder="支持填写IPv4或CNAME地址" class="form-control" required>
</div>
</div>
<div class="form-group" v-show="set.type==2&&dnstype=='cloudflare'">
<div class="col-sm-offset-3 col-sm-7">
<div class="checkbox">
<label>
<input type="checkbox" name="name" v-model="set.cdn"> 切换时同时开启Cloudflare代理模式
</label>
</div>
</div>
</div>
<div class="form-group" v-show="set.type<=2">
<label class="col-sm-3 control-label no-padding-right" is-required>检测协议</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="option in checktypeList">
<input type="radio" name="checktype" :value="option.value" v-model="set.checktype" :disabled="option.disabled"> {{option.label}}
</label>
</div>
</div>
<div class="form-group" v-show="set.type<=2&&set.checktype<2">
<label class="col-sm-3 control-label no-padding-right">指定检测IP</label>
<div class="col-sm-6">
<input type="text" name="checkip" v-model="set.checkurl" placeholder="留空默认为解析记录值IP" class="form-control" data-bv-ip="true">
</div>
</div>
<div class="form-group" v-show="set.type<=2&&set.checktype==1">
<label class="col-sm-3 control-label no-padding-right" is-required>TCP检测端口</label>
<div class="col-sm-6">
<input type="text" name="tcpport" v-model="set.tcpport" placeholder="填写TCP端口号" class="form-control" data-bv-integer="true" min="1" max="65535" required>
</div>
</div>
<div class="form-group" v-show="set.type<=2&&set.checktype==2">
<label class="col-sm-3 control-label no-padding-right" is-required>检测URL地址</label>
<div class="col-sm-6">
<input type="text" name="checkurl" v-model="set.checkurl" placeholder="填写以http(s)://开头的完整地址http状态码须为2xx/3xx" class="form-control" data-bv-uri="true" required>
</div>
</div>
<div class="form-group" v-show="set.type<=2&&set.checktype==2">
<label class="col-sm-3 control-label no-padding-right">使用代理请求</label>
<div class="col-sm-6">
<label class="radio-inline">
<input type="radio" name="proxy" value="0" v-model="set.proxy">
</label>
<label class="radio-inline">
<input type="radio" name="proxy" value="1" v-model="set.proxy">
</label>
</div>
</div>
<div class="form-group" v-show="set.type<=2&&set.checktype>0">
<label class="col-sm-3 control-label no-padding-right" is-required>最大超时时间</label>
<div class="col-sm-3">
<div class="input-group">
<input type="text" name="timeout" v-model="set.timeout" placeholder="填写请求最大超时时间" class="form-control" data-bv-integer="true" min="1" required>
<span class="input-group-addon"></span>
</div>
</div>
</div>
<div class="form-group" v-show="set.type==3">
<label class="col-sm-3 control-label no-padding-right" is-required>同域名正常数量<span class="tips" title="" data-toggle="tooltip" data-placement="bottom" data-original-title="与暂停解析配合使用,当同域名正常记录数量&lt;=几条时开启解析"><i class="fa fa-question-circle"></i></span></label>
<div class="col-sm-3">
<input type="text" name="cycle" v-model="set.cycle" placeholder="同域名正常记录数量&lt;=几条时开启解析" class="form-control" data-bv-integer="true" min="0" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" is-required>检测间隔</label>
<div class="col-sm-3">
<div class="input-group">
<input type="text" name="frequency" v-model="set.frequency" placeholder="每次检测的间隔时间" class="form-control" data-bv-integer="true" min="1" required>
<span class="input-group-addon"></span>
</div>
</div>
</div>
<div class="form-group" v-show="set.type<=2">
<label class="col-sm-3 control-label no-padding-right" is-required>确认次数</label>
<div class="col-sm-3">
<input type="text" name="cycle" v-model="set.cycle" placeholder="连续失败几次后进行切换" class="form-control" data-bv-integer="true" min="1" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">备注</label>
<div class="col-sm-6">
<input type="text" name="remark" v-model="set.remark" placeholder="可留空" class="form-control">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">提交</button></div>
</div>
</form>
</div>
</div>
{/block}
{block name="script"}
@ -152,146 +163,162 @@
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="/static/js/bootstrapValidator.min.js"></script>
<script>
var action = '{$action}';
var info = {$info|json_encode|raw};
var domainList = {$domains|json_encode|raw};
var support_ping = '{$support_ping}';
new Vue({
el: '#app',
data: {
action: '{$action}',
set: {
id: '',
remark: '',
rr: '',
did: '',
recordid: '',
recordinfo: '',
main_value: '',
type: 1,
backup_value: '',
checktype: 1,
tcpport: 80,
checkurl: '',
frequency: 5,
timeout: 2,
cycle: 3,
proxy: 0,
cdn: 0,
var action = '{$action}';
var info = {$info | json_encode | raw};
var domainList = {$domains | json_encode | raw};
var support_ping = '{$support_ping}';
new Vue({
el: '#app',
data: {
action: '{$action}',
set: {
id: '',
remark: '',
rr: '',
did: '',
recordid: '',
recordinfo: '',
main_value: '',
type: 1,
backup_value: '',
checktype: 1,
tcpport: 80,
checkurl: '',
frequency: 5,
timeout: 2,
cycle: 3,
proxy: 0,
cdn: 0,
},
dnstype: null,
domainList: domainList,
recordList: [],
typeList: [
{value: 0, label: '无操作'},
{value: 1, label: '暂停解析'},
{value: 2, label: '切换备用解析'},
{value: 3, label: '条件开启解析'},
],
checktypeList: [
{value: 0, label: 'PING', disabled: support_ping == '0'},
{value: 1, label: 'TCP'},
{value: 2, label: 'HTTP(S)'},
]
},
dnstype: null,
domainList: domainList,
recordList: [],
typeList: [
{value:0, label:'无操作'},
{value:1, label:'暂停解析'},
{value:2, label:'切换备用解析'},
{value:3, label:'条件开启解析'},
],
checktypeList: [
{value:0, label:'PING', disabled: support_ping=='0'},
{value:1, label:'TCP'},
{value:2, label:'HTTP(S)'},
]
},
watch: {
'set.recordid': function(val){
if(val == '') return;
var record = this.recordList.find(item => item.RecordId == val);
if(record){
this.set.recordinfo = JSON.stringify({Line:record.Line, LineName:record.LineName, TTL:record.TTL});
if(typeof record.Value == 'object') this.set.main_value = record.Value[0];
else this.set.main_value = record.Value;
watch: {
'set.recordid': function (val) {
if (val == '') return;
var record = this.recordList.find(item => item.RecordId == val);
if (record) {
this.set.recordinfo = JSON.stringify({
Line: record.Line,
LineName: record.LineName,
TTL: record.TTL
});
if (typeof record.Value == 'object') this.set.main_value = record.Value[0];
else this.set.main_value = record.Value;
}
},
'set.did': function (val) {
if (val == '') return;
this.dnstype = this.domainList.find(item => item.id == val).type;
}
},
'set.did': function(val){
if(val == '') return;
this.dnstype = this.domainList.find(item => item.id == val).type;
}
},
mounted() {
if(this.action == 'edit'){
Object.keys(info).forEach((key) => {
this.$set(this.set, key, info[key])
})
var recordinfo = JSON.parse(this.set.recordinfo);
this.recordList = [{RecordId:this.set.recordid, Value:this.set.main_value, Line:recordinfo.Line, LineName:recordinfo.LineName, TTL:recordinfo.TTL}];
}
$("#taskform").bootstrapValidator({
live: 'submitted',
});
$('[data-toggle="tooltip"]').tooltip();
},
methods: {
getRecordList(){
var that = this;
if(this.set.did == ''){
layer.msg('请先选择域名', {time: 800});return;
mounted() {
if (this.action == 'edit') {
Object.keys(info).forEach((key) => {
this.$set(this.set, key, info[key])
})
var recordinfo = JSON.parse(this.set.recordinfo);
this.recordList = [{
RecordId: this.set.recordid,
Value: this.set.main_value,
Line: recordinfo.Line,
LineName: recordinfo.LineName,
TTL: recordinfo.TTL
}];
}
if(this.set.rr == ''){
layer.msg('主机记录不能为空', {time: 800});return;
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '/record/list',
data : {id:this.set.did, rr:this.set.rr},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.msg('成功获取到'+data.data.length+'条解析记录', {icon:1, time:800});
that.recordList = data.data;
if(that.set.recordid){
var record = that.recordList.find(item => item.RecordId == that.set.recordid);
if(record){
that.set.recordinfo = JSON.stringify({Line:record.Line, LineName:record.LineName, TTL:record.TTL});
if(typeof record.Value == 'object') that.set.main_value = record.Value[0];
else that.set.main_value = record.Value;
$("#taskform").bootstrapValidator({
live: 'submitted',
});
$('[data-toggle="tooltip"]').tooltip();
},
methods: {
getRecordList() {
var that = this;
if (this.set.did == '') {
layer.msg('请先选择域名', {time: 800});
return;
}
if (this.set.rr == '') {
layer.msg('主机记录不能为空', {time: 800});
return;
}
var ii = layer.load(2, {shade: [0.1, '#fff']});
$.ajax({
type: 'POST',
url: '/record/list',
data: {id: this.set.did, rr: this.set.rr},
dataType: 'json',
success: function (data) {
layer.close(ii);
if (data.code == 0) {
layer.msg('成功获取到' + data.data.length + '条解析记录', {icon: 1, time: 800});
that.recordList = data.data;
if (that.set.recordid) {
var record = that.recordList.find(item => item.RecordId == that.set.recordid);
if (record) {
that.set.recordinfo = JSON.stringify({
Line: record.Line,
LineName: record.LineName,
TTL: record.TTL
});
if (typeof record.Value == 'object') that.set.main_value = record.Value[0];
else that.set.main_value = record.Value;
}
}
} else {
layer.alert(data.msg, {icon: 2});
}
}else{
layer.alert(data.msg, {icon:2});
},
error: function (data) {
layer.close(ii);
layer.msg('服务器错误');
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
});
},
submit() {
var that = this;
$("#taskform").data("bootstrapValidator").validate();
if (!$("#taskform").data("bootstrapValidator").isValid()) {
return false;
}
});
},
submit(){
var that=this;
$("#taskform").data("bootstrapValidator").validate();
if(!$("#taskform").data("bootstrapValidator").isValid()){
return false;
var ii = layer.load(2, {shade: [0.1, '#fff']});
$.ajax({
type: "POST",
url: "",
data: this.set,
dataType: 'json',
success: function (data) {
layer.close(ii);
if (data.code == 0) {
layer.alert(data.msg, {icon: 1}, function () {
if (document.referrer.indexOf('task?') > 0)
window.location.href = document.referrer;
else
window.location.href = '/dmonitor/task';
});
} else {
layer.alert(data.msg, {icon: 2});
}
},
error: function (data) {
layer.close(ii);
layer.msg('服务器错误');
}
});
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type: "POST",
url: "",
data: this.set,
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1}, function(){
if(document.referrer.indexOf('task?') > 0)
window.location.href = document.referrer;
else
window.location.href = '/dmonitor/task';
});
}else{
layer.alert(data.msg, {icon: 2});
}
},
error: function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
},
});
},
});
</script>
{/block}

112
app/view/dmonitor/taskinfo.html Normal file → Executable file
View File

@ -2,72 +2,70 @@
{block name="title"}切换记录{/block}
{block name="main"}
<style>
tbody tr>td:nth-child(4){overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:180px;}
#orderItem .orderTitle{word-break:keep-all;}
#orderItem .orderContent{word-break:break-all;}
.fixed-table-toolbar,.fixed-table-pagination{padding: 15px;}
</style>
<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>
<div class="form-group">
<select name="action" class="form-control"><option value="0">操作类型</option><option value="1">发生异常</option><option value="2">恢复正常</option></select>
</div>
</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>
&nbsp;&nbsp;24H告警次数<strong>{$info.fail_count}</strong>&nbsp;&nbsp;切换次数:<strong>{$info.switch_count}</strong>
</form>
<table id="listTable">
</table>
<div class="panel panel-default">
<div class="panel-heading font-bold">
<h3 class="panel-title">切换记录</h3>
</div>
</div>
</div>
<form class="form-inline" id="searchToolbar" method="GET" onsubmit="return searchSubmit()">
<div class="form-group">
<div class="form-group">
<select class="form-control" name="action">
<option value="0">操作类型</option>
<option value="1">发生异常</option>
<option value="2">恢复正常</option>
</select>
</div>
</div>
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
<a class="btn btn-default" href="javascript:searchClear()" title="刷新切换记录列表"><i class="fa fa-refresh"></i> 刷新</a>&nbsp;&nbsp;24H告警次数<strong>{$info.fail_count}</strong>&nbsp;&nbsp;切换次数:<strong>{$info.switch_count}</strong>
</form>
<table id="listTable">
</table>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
<script src="/static/js/custom.js"></script>
<script>
var action_name = {$info.action_name|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;
var action_name = {$info.action_name | 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: '/dmonitor/task/log/data/{$info.id}',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
columns: [
{
field: 'id',
title: 'ID'
},
{
field: 'action',
title: '操作类型',
formatter: function(value, row, index) {
return action_name[value];
}
},
{
field: 'date',
title: '时间'
},
{
field: 'errmsg',
title: '异常原因'
}
],
})
})
$("#listTable").bootstrapTable({
url: '/dmonitor/task/log/data/{$info.id}',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
columns: [
{
field: 'id',
title: 'ID'
},
{
field: 'action',
title: '操作类型',
formatter: function (value, row, index) {
return action_name[value];
}
},
{
field: 'date',
title: '时间'
},
{
field: 'errmsg',
title: '异常原因'
}
],
})
})
</script>
{/block}

466
app/view/domain/account.html Normal file → Executable file
View File

@ -1,248 +1,250 @@
{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">&times;</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" id="ext_name_div" style="display:none;">
<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" id="ext_name">使用代理</label>
<div class="col-sm-9">
<label class="radio-inline"><input type="radio" name="proxy" value="0">
</label><label class="radio-inline"><input type="radio" name="proxy" value="1">
</label>
</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 aria-hidden="true" class="modal inmodal fade" data-backdrop="static" id="modal-store" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close" data-dismiss="modal" type="button"><span aria-hidden="true">&times;</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 name="action" type="hidden"/>
<input name="id" type="hidden"/>
<div class="form-group">
<label class="col-sm-3 control-label">所属平台</label>
<div class="col-sm-9">
<select class="form-control" name="type">
{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 class="form-control" name="ak" required type="text">
</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 class="form-control" name="sk" required type="text">
</div>
</div>
<div class="form-group" id="ext_name_div" style="display:none;">
<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" id="ext_name">使用代理</label>
<div class="col-sm-9">
<label class="radio-inline"><input type="radio" name="proxy" value="0">
</label><label class="radio-inline"><input type="radio" name="proxy" value="1">
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">备注</label>
<div class="col-sm-9">
<input class="form-control" name="remark" placeholder="备注选填" type="text">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-white" data-dismiss="modal" type="button">关闭</button>
<button class="btn btn-primary" id="store" onclick="save()" type="button">保存</button>
</div>
</div>
</div>
</div>
</div>
<style>
#orderItem .orderTitle{word-break:keep-all;}
#orderItem .orderContent{word-break:break-all;}
.fixed-table-toolbar,.fixed-table-pagination{padding: 15px;}
</style>
<div class="panel panel-default">
<div class="panel-heading font-bold">
<h3 class="panel-title">域名账户</h3>
</div>
<form class="form-inline" id="searchToolbar" method="GET" onsubmit="return searchSubmit()">
<div class="form-group">
<input class="form-control" name="kw" placeholder="AccessKey或备注" type="text">
</div>
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
<a class="btn btn-default" href="javascript:searchClear()" title="刷新域名账户列表"><i class="fa fa-refresh"></i> 刷新</a>
<a class="btn btn-success" href="javascript:addframe()"><i class="fa fa-plus"></i> 添加</a>
</form>
<table id="listTable">
</table>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/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;
var dnsconfig = {$dnsconfig | json_encode | raw}
$("#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: 'action',
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;
}
},
],
})
$(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;
$("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){
$("#ext_name_div").hide();
}else{
$("#ext_name_div").show();
$("#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=proxy]").eq(0).prop('checked',true);
$("#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=proxy]").eq(data.data.proxy).prop('checked',true);
$("#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');
searchRefresh();
});
}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();
searchRefresh();
}else{
layer.alert(data.msg, {icon: 2});
}
}
});
}, function(){
layer.close(confirmobj);
});
}
$("#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: 'action',
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){
$("#ext_name_div").hide();
}else{
$("#ext_name_div").show();
$("#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=proxy]").eq(0).prop('checked',true);
$("#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=proxy]").eq(data.data.proxy).prop('checked',true);
$("#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');
searchRefresh();
});
} 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();
searchRefresh();
} else {
layer.alert(data.msg, {icon: 2});
}
}
});
}, function () {
layer.close(confirmobj);
});
}
</script>
{/block}

253
app/view/domain/batchadd.html Normal file → Executable file
View File

@ -1,138 +1,143 @@
{extend name="common/layout" /}
{block name="title"}批量添加解析 - {$domainName}{/block}
{block name="main"}
<div class="row" id="app">
<div class="col-xs-12 center-block" style="float: none;">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title"><a href="/record/{$domainId}" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>批量添加解析 - {$domainName}</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="form-store">
<div class="form-group">
<label class="col-sm-3 col-xs-12 control-label no-padding-right">主机记录&记录值</label>
<div class="col-sm-6">
<textarea name="record" placeholder="主机记录和记录值用空格隔开,一行一个" class="form-control" rows="8" required></textarea>
<div id="app">
<div class="panel panel-default">
<div class="panel-heading font-bold"><h3 class="panel-title"><a class="btn btn-sm btn-default pull-right" href="/record/{$domainId}" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>批量添加解析 - {$domainName}</h3></div>
<div class="panel-body">
<form class="form-horizontal" id="form-store" method="post" onsubmit="return false" role="form">
<div class="form-group">
<label class="col-sm-3 col-xs-12 control-label no-padding-right">主机记录&记录值</label>
<div class="col-sm-6">
<textarea class="form-control" name="record" placeholder="主机记录和记录值用空格隔开,一行一个" required rows="8"></textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">记录类型</label>
<div class="col-sm-6">
<select class="form-control" name="type">
<option value="">A / CNAME / AAAA 自动识别</option>
<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 no-padding-right">线路类型</label>
<div class="col-sm-6" id="line_list">
</div>
</div>
<div class="form-group" id="mx_type" style="display:none">
<label class="col-sm-3 control-label no-padding-right">MX优先级</label>
<div class="col-sm-6">
<input class="form-control" name="mx" type="text" value="10">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">TTL</label>
<div class="col-sm-6">
<input class="form-control" min="{$minTTL}" name="ttl" placeholder="指解析结果在DNS服务器中的缓存时间" required type="text" value="600">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button class="btn btn-primary" onclick="save()" type="button">添加</button></div>
</div>
</form>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">记录类型</label>
<div class="col-sm-6">
<select name="type" class="form-control">
<option value="">A / CNAME / AAAA 自动识别</option>
<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 no-padding-right">线路类型</label>
<div class="col-sm-6" id="line_list">
</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-6">
<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-6">
<input type="text" class="form-control" name="ttl" value="600" placeholder="指解析结果在DNS服务器中的缓存时间" required min="{$minTTL}">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" onclick="save()">添加</button></div>
</div>
</form>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="/static/js/bootstrapValidator.min.js"></script>
<script>
var recordLine = {$recordLine|json_encode|raw};
var dnsconfig = {$dnsconfig|json_encode|raw};
var defaultLine = recordLine[0].id;
$(document).ready(function(){
$("select[name=type]").change(function(){
if($(this).val() == 'MX'){
$("#mx_type").show();
}else{
$("#mx_type").hide();
}
});
var recordLine = {$recordLine | json_encode | raw}
$("#form-store").bootstrapValidator();
initLine();
});
var dnsconfig = {$dnsconfig | json_encode | raw}
function initLine(option, elem){
option = option || '';
elem = elem || 'line_list';
$("#"+elem).empty();
$.each(recordLine, function(index, item){
if(item.parent == null){
option += '<option value="'+item.id+'">'+item.name+'</option>';
}
})
$("#"+elem).append('<select name="line" class="form-control" onchange="changeLine(this, \''+elem+'\')">'+option+'</select>');
}
function changeLine(obj, elem){
var line = $(obj).val();
var flag = false;
$("#"+elem).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>';
})
$("#"+elem).append('<select name="line" class="form-control" onchange="changeLine(this, \''+elem+'\')">'+option+'</select>');
}
}
function save(){
$("#form-store").data("bootstrapValidator").validate();
if(!$("#form-store").data("bootstrapValidator").isValid()){
return;
}
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/record/batchadd/{$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(){
if(document.referrer.indexOf('/record?') > 0)
window.location.href = document.referrer;
else
window.location.href = '/record/{$domainId}';
});
}else{
layer.alert(data.msg, {icon: 2})
}
}
});
}
var defaultLine = recordLine[0].id;
$(document).ready(function () {
$("select[name=type]").change(function () {
if ($(this).val() == 'MX') {
$("#mx_type").show();
} else {
$("#mx_type").hide();
}
});
$("#form-store").bootstrapValidator();
initLine();
});
function initLine(option, elem) {
option = option || '';
elem = elem || 'line_list';
$("#" + elem).empty();
$.each(recordLine, function (index, item) {
if (item.parent == null) {
option += '<option value="' + item.id + '">' + item.name + '</option>';
}
})
$("#" + elem).append('<select name="line" class="form-control" onchange="changeLine(this, \'' + elem + '\')">' + option + '</select>');
}
function changeLine(obj, elem) {
var line = $(obj).val();
var flag = false;
$("#" + elem).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>';
})
$("#" + elem).append('<select name="line" class="form-control" onchange="changeLine(this, \'' + elem + '\')">' + option + '</select>');
}
}
function save() {
$("#form-store").data("bootstrapValidator").validate();
if (!$("#form-store").data("bootstrapValidator").isValid()) {
return;
}
var ii = layer.load(2);
$.ajax({
type: 'POST',
url: '/record/batchadd/{$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 () {
if (document.referrer.indexOf('/record?') > 0)
window.location.href = document.referrer;
else
window.location.href = '/record/{$domainId}';
});
} else {
layer.alert(data.msg, {icon: 2})
}
}
});
}
</script>
{/block}

318
app/view/domain/batchadd2.html Normal file → Executable file
View File

@ -2,175 +2,175 @@
{block name="title"}批量添加解析{/block}
{block name="main"}
<style>
tbody tr>td:nth-child(3){min-width:300px;word-break:break-all;}
tbody tr>td:nth-child(3){min-width:300px;word-break:break-all;}
</style>
<div class="row" id="app">
<div class="col-xs-12 center-block" style="float: none;">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title"><a href="/domain" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>批量添加解析</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="form-store">
<div class="form-group">
<label class="col-sm-3 col-xs-12 control-label no-padding-right">主机记录&记录值</label>
<div class="col-sm-6">
<textarea name="record" v-model="set.record" placeholder="主机记录和记录值用空格隔开,一行一个" class="form-control" rows="8" required></textarea>
<div id="app">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title"><a href="/domain" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>批量添加解析</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="form-store">
<div class="form-group">
<label class="col-sm-3 col-xs-12 control-label no-padding-right">主机记录&记录值</label>
<div class="col-sm-6">
<textarea name="record" v-model="set.record" placeholder="主机记录和记录值用空格隔开,一行一个" class="form-control" rows="8" required></textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">记录类型</label>
<div class="col-sm-6">
<select name="type" class="form-control" v-model="set.type">
<option value="">A / CNAME / AAAA 自动识别</option>
<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>
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">线路类型</label>
<div class="col-sm-6">
<select name="line" class="form-control" disabled><option value="default">默认</option></select>
</div>
</div>
<div class="form-group" v-if="existCF">
<label class="col-sm-3 control-label no-padding-right">开启反代</label>
<div class="col-sm-6">
<label class="radio-inline">
<input type="radio" name="proxy" value="0" v-model="set.proxy">
</label>
<label class="radio-inline">
<input type="radio" name="proxy" value="1" v-model="set.proxy">仅Cloudflare域名
</label>
</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-6">
<input type="text" class="form-control" name="mx" v-model="set.mx">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">TTL</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="ttl" v-model="set.ttl" placeholder="指解析结果在DNS服务器中的缓存时间" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">确定添加</button></div>
</div>
</form>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">记录类型</label>
<div class="col-sm-6">
<select name="type" class="form-control" v-model="set.type">
<option value="">A / CNAME / AAAA 自动识别</option>
<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>
</select>
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">解析记录添加结果</h3></div>
<div class="panel-body">
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>ID</th>
<th>域名</th>
<th>添加结果</th>
</tr>
</thead>
<tbody>
<tr v-for="item in domainList">
<td>{{item.id}}</td>
<td><img :src="'/static/images/'+item.type+'.ico'" class="type-logo"></img><a :href="'/record/'+item.id" target="_blank">{{item.name}}</a></td>
<td v-html="item.result"></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">线路类型</label>
<div class="col-sm-6">
<select name="line" class="form-control" disabled><option value="default">默认</option></select>
</div>
</div>
<div class="form-group" v-if="existCF">
<label class="col-sm-3 control-label no-padding-right">开启反代</label>
<div class="col-sm-6">
<label class="radio-inline">
<input type="radio" name="proxy" value="0" v-model="set.proxy">
</label>
<label class="radio-inline">
<input type="radio" name="proxy" value="1" v-model="set.proxy">仅Cloudflare域名
</label>
</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-6">
<input type="text" class="form-control" name="mx" v-model="set.mx">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">TTL</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="ttl" v-model="set.ttl" placeholder="指解析结果在DNS服务器中的缓存时间" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">确定添加</button></div>
</div>
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">解析记录添加结果</h3></div>
<div class="panel-body">
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>ID</th>
<th>域名</th>
<th>添加结果</th>
</tr>
</thead>
<tbody>
<tr v-for="item in domainList">
<td>{{item.id}}</td>
<td><img :src="'/static/images/'+item.type+'.ico'" class="type-logo"></img><a :href="'/record/'+item.id" target="_blank">{{item.name}}</a></td>
<td v-html="item.result"></td>
</tr>
</tbody>
</table>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}vue/2.6.14/vue.min.js"></script>
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script>
new Vue({
el: '#app',
data: {
domainList: [],
set: {
record: '',
type: '',
mx: 10,
ttl: 600,
proxy: 0,
},
existCF: false,
},
watch: {
'set.type': function(val){
if(val == 'MX'){
$("#mx_type").show();
}else{
$("#mx_type").hide();
}
}
},
mounted() {
this.domainList = JSON.parse(sessionStorage.getItem('domains')) || [];
if(this.domainList.length == 0){
layer.alert('请先选中要添加解析的域名', {icon: 2}, function(){
window.location.href = '/domain';
});
}
for(var i=0; i<this.domainList.length; i++){
this.$set(this.domainList[i], 'result', '<span class="text-muted">待添加</span>');
}
this.existCF = this.domainList.some(item => item.type === 'cloudflare');
},
methods: {
async save(id){
var that = this;
return new Promise((resolve, reject) => {
$.ajax({
type: "POST",
url: '/record/batchadd/'+id,
data: that.set,
dataType: 'json',
success: function(data) {
resolve(data);
},
error: function() {
reject('服务器错误');
}
});
});
},
async submit(){
if(this.set.record == ''){
layer.alert('请填写主机记录和记录值', {icon: 2});
return;
}
if(this.set.ttl == ''){
layer.alert('请填写TTL', {icon: 2});
return;
}
if(this.set.type == 'MX' && this.set.mx == ''){
layer.alert('请填写MX优先级', {icon: 2});
return;
}
var ii = layer.load(2);
for(var i=0; i<this.domainList.length; i++){
this.domainList[i].result = '<span class="text-yellow"><i class="fa fa-refresh fa-spin fa-fw"></i> 正在添加</span>';
var res = await this.save(this.domainList[i].id);
if(res.code == 0){
this.domainList[i].result = '<span class="text-green">'+res.msg+'</span>';
}else{
this.domainList[i].result = '<span class="text-red">'+res.msg+'</span>';
}
}
layer.close(ii);
}
},
});
new Vue({
el: '#app',
data: {
domainList: [],
set: {
record: '',
type: '',
mx: 10,
ttl: 600,
proxy: 0,
},
existCF: false,
},
watch: {
'set.type': function(val){
if(val == 'MX'){
$("#mx_type").show();
}else{
$("#mx_type").hide();
}
}
},
mounted() {
this.domainList = JSON.parse(sessionStorage.getItem('domains')) || [];
if(this.domainList.length == 0){
layer.alert('请先选中要添加解析的域名', {icon: 2}, function(){
window.location.href = '/domain';
});
}
for(var i=0; i<this.domainList.length; i++){
this.$set(this.domainList[i], 'result', '<span class="text-muted">待添加</span>');
}
this.existCF = this.domainList.some(item => item.type === 'cloudflare');
},
methods: {
async save(id){
var that = this;
return new Promise((resolve, reject) => {
$.ajax({
type: "POST",
url: '/record/batchadd/'+id,
data: that.set,
dataType: 'json',
success: function(data) {
resolve(data);
},
error: function() {
reject('服务器错误');
}
});
});
},
async submit(){
if(this.set.record == ''){
layer.alert('请填写主机记录和记录值', {icon: 2});
return;
}
if(this.set.ttl == ''){
layer.alert('请填写TTL', {icon: 2});
return;
}
if(this.set.type == 'MX' && this.set.mx == ''){
layer.alert('请填写MX优先级', {icon: 2});
return;
}
var ii = layer.load(2);
for(var i=0; i<this.domainList.length; i++){
this.domainList[i].result = '<span class="text-yellow"><i class="fa fa-refresh fa-spin fa-fw"></i> 正在添加</span>';
var res = await this.save(this.domainList[i].id);
if(res.code == 0){
this.domainList[i].result = '<span class="text-green">'+res.msg+'</span>';
}else{
this.domainList[i].result = '<span class="text-red">'+res.msg+'</span>';
}
}
layer.close(ii);
}
},
});
</script>
{/block}

280
app/view/domain/batchedit.html Normal file → Executable file
View File

@ -2,156 +2,156 @@
{block name="title"}批量修改解析{/block}
{block name="main"}
<style>
tbody tr>td:nth-child(3){min-width:300px;word-break:break-all;}
tbody tr>td:nth-child(3){min-width:300px;word-break:break-all;}
</style>
<div class="row" id="app">
<div class="col-xs-12 center-block" style="float: none;">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title"><a href="/domain" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>批量修改解析</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="form-store">
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">主机记录</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="name" v-model="set.name" placeholder="填写已有的主机记录" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">记录类型</label>
<div class="col-sm-6">
<select name="type" class="form-control" v-model="set.type">
<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>
</select>
<div id="app">
<div class="panel panel-default">
<div class="panel-heading font-bold"><h3 class="panel-title"><a href="/domain" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>批量修改解析</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="form-store">
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">主机记录</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="name" v-model="set.name" placeholder="填写已有的主机记录" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">记录类型</label>
<div class="col-sm-6">
<select name="type" class="form-control" v-model="set.type">
<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>
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">线路类型</label>
<div class="col-sm-6">
<select name="line" class="form-control" disabled><option value="default">默认</option></select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">记录值</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="value" v-model="set.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-6">
<input type="text" class="form-control" name="mx" v-model="set.mx" placeholder="留空则不修改">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">TTL</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="ttl" v-model="set.ttl" placeholder="留空则不修改">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">确定修改</button></div>
</div>
</form>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">线路类型</label>
<div class="col-sm-6">
<select name="line" class="form-control" disabled><option value="default">默认</option></select>
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">解析记录修改结果</h3></div>
<div class="panel-body">
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>ID</th>
<th>域名</th>
<th>修改结果</th>
</tr>
</thead>
<tbody>
<tr v-for="item in domainList">
<td>{{item.id}}</td>
<td><img :src="'/static/images/'+item.type+'.ico'" class="type-logo"></img><a :href="'/record/'+item.id" target="_blank">{{item.name}}</a></td>
<td v-html="item.result"></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">记录值</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="value" v-model="set.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-6">
<input type="text" class="form-control" name="mx" v-model="set.mx" placeholder="留空则不修改">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">TTL</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="ttl" v-model="set.ttl" placeholder="留空则不修改">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">确定修改</button></div>
</div>
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">解析记录修改结果</h3></div>
<div class="panel-body">
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>ID</th>
<th>域名</th>
<th>修改结果</th>
</tr>
</thead>
<tbody>
<tr v-for="item in domainList">
<td>{{item.id}}</td>
<td><img :src="'/static/images/'+item.type+'.ico'" class="type-logo"></img><a :href="'/record/'+item.id" target="_blank">{{item.name}}</a></td>
<td v-html="item.result"></td>
</tr>
</tbody>
</table>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}vue/2.6.14/vue.min.js"></script>
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script>
new Vue({
el: '#app',
data: {
domainList: [],
set: {
id: '',
name: '',
type: 'A',
value: '',
mx: '',
ttl: '',
}
},
mounted() {
this.domainList = JSON.parse(sessionStorage.getItem('domains')) || [];
if(this.domainList.length == 0){
layer.alert('请先选中要修改解析的域名', {icon: 2}, function(){
window.location.href = '/domain';
});
}
for(var i=0; i<this.domainList.length; i++){
this.$set(this.domainList[i], 'result', '<span class="text-muted">待修改</span>');
}
},
methods: {
async save(id){
var that = this;
return new Promise((resolve, reject) => {
that.set.id = id;
$.ajax({
type: "POST",
url: '/record/batchedit',
data: that.set,
dataType: 'json',
success: function(data) {
resolve(data);
},
error: function() {
reject('服务器错误');
}
});
});
},
async submit(){
if(this.set.name == ''){
layer.alert('请填写主机记录', {icon: 2});
return;
}
if(this.set.value == ''){
layer.alert('请填写记录值', {icon: 2});
return;
}
var ii = layer.load(2);
for(var i=0; i<this.domainList.length; i++){
this.domainList[i].result = '<span class="text-yellow"><i class="fa fa-refresh fa-spin fa-fw"></i> 正在修改</span>';
var res = await this.save(this.domainList[i].id);
if(res.code == 0){
this.domainList[i].result = '<span class="text-green">'+res.msg+'</span>';
}else{
this.domainList[i].result = '<span class="text-red">'+res.msg+'</span>';
}
}
layer.close(ii);
}
},
});
new Vue({
el: '#app',
data: {
domainList: [],
set: {
id: '',
name: '',
type: 'A',
value: '',
mx: '',
ttl: '',
}
},
mounted() {
this.domainList = JSON.parse(sessionStorage.getItem('domains')) || [];
if(this.domainList.length == 0){
layer.alert('请先选中要修改解析的域名', {icon: 2}, function(){
window.location.href = '/domain';
});
}
for(var i=0; i<this.domainList.length; i++){
this.$set(this.domainList[i], 'result', '<span class="text-muted">待修改</span>');
}
},
methods: {
async save(id){
var that = this;
return new Promise((resolve, reject) => {
that.set.id = id;
$.ajax({
type: "POST",
url: '/record/batchedit',
data: that.set,
dataType: 'json',
success: function(data) {
resolve(data);
},
error: function() {
reject('服务器错误');
}
});
});
},
async submit(){
if(this.set.name == ''){
layer.alert('请填写主机记录', {icon: 2});
return;
}
if(this.set.value == ''){
layer.alert('请填写记录值', {icon: 2});
return;
}
var ii = layer.load(2);
for(var i=0; i<this.domainList.length; i++){
this.domainList[i].result = '<span class="text-yellow"><i class="fa fa-refresh fa-spin fa-fw"></i> 正在修改</span>';
var res = await this.save(this.domainList[i].id);
if(res.code == 0){
this.domainList[i].result = '<span class="text-green">'+res.msg+'</span>';
}else{
this.domainList[i].result = '<span class="text-red">'+res.msg+'</span>';
}
}
layer.close(ii);
}
},
});
</script>
{/block}

1199
app/view/domain/domain.html Normal file → Executable file

File diff suppressed because it is too large Load Diff

276
app/view/domain/domain_add.html Normal file → Executable file
View File

@ -1,158 +1,158 @@
{extend name="common/layout" /}
{block name="title"}批量添加域名{/block}
{block name="main"}
<div class="row" id="app">
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title"><a href="/domain" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>批量添加域名</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="form-store">
<div class="form-group">
<label class="col-sm-3 control-label">域名账户</label>
<div class="col-sm-9">
<div class="input-group">
<select name="aid" class="form-control" v-model="aid">
{foreach $accounts as $k=>$v}
<option value="{$k}">{$v}</option>
{/foreach}
</select>
<div class="input-group-btn">
<button type="button" @click="getDomainList" class="btn btn-info">获取域名</button>
</div>
</div>
<div id="app">
<div class="panel panel-default">
<div class="panel-heading font-bold"><h3 class="panel-title"><a href="/domain" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>批量添加域名</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="form-store">
<div class="form-group">
<label class="col-sm-3 control-label">域名账户</label>
<div class="col-sm-6">
<div class="input-group">
<select name="aid" class="form-control" v-model="aid">
{foreach $accounts as $k=>$v}
<option value="{$k}">{$v}</option>
{/foreach}
</select>
<div class="input-group-btn">
<button type="button" @click="getDomainList" class="btn btn-info">获取域名</button>
</div>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">选择域名</label>
<div class="col-sm-6">
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th><input type="checkbox" v-model="checkall"></th>
<th>域名</th>
</tr>
</thead>
<tbody>
<tr v-for="item in domainList">
<td><input type="checkbox" name="domain[]" :value="item.DomainId" v-model="item.checked" :disabled="item.disabled"></td>
<td><span :title="item.DomainId">{{item.Domain}}</span><font color="#888" v-if="item.disabled"> (已添加)</font></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">确定添加</button></div>
</div>
</form>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">选择域名</label>
<div class="col-sm-9">
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th><input type="checkbox" v-model="checkall"></th>
<th>域名</th>
</tr>
</thead>
<tbody>
<tr v-for="item in domainList">
<td><input type="checkbox" name="domain[]" :value="item.DomainId" v-model="item.checked" :disabled="item.disabled"></td>
<td><span :title="item.DomainId">{{item.Domain}}</span><font color="#888" v-if="item.disabled"> (已添加)</font></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9"><button type="button" class="btn btn-primary" @click="submit">确定添加</button></div>
</div>
</form>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}vue/2.6.14/vue.min.js"></script>
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script>
new Vue({
el: '#app',
data: {
aid: '',
domainList: [],
page: 1,
pagesize: 10,
checkall: false,
},
watch: {
aid: function(val){
this.domainList = [];
new Vue({
el: '#app',
data: {
aid: '',
domainList: [],
page: 1,
pagesize: 10,
checkall: false,
},
checkall: function(val){
this.domainList.forEach(function(item){
item.checked = val&&!item.disabled;
});
}
},
mounted() {
this.aid = '{$accounts|@key}';
},
methods: {
async getDomainListPaged(){
var that = this;
return new Promise((resolve, reject) => {
$.ajax({
type: "POST",
url: "/domain/list",
data: {aid: that.aid, page: that.page, pagesize: that.pagesize},
dataType: 'json',
success: function(data) {
if(data.code == 0){
resolve(data.data);
}else{
reject(data.msg);
watch: {
aid: function(val){
this.domainList = [];
},
checkall: function(val){
this.domainList.forEach(function(item){
item.checked = val&&!item.disabled;
});
}
},
mounted() {
this.aid = '{$accounts|@key}';
},
methods: {
async getDomainListPaged(){
var that = this;
return new Promise((resolve, reject) => {
$.ajax({
type: "POST",
url: "/domain/list",
data: {aid: that.aid, page: that.page, pagesize: that.pagesize},
dataType: 'json',
success: function(data) {
if(data.code == 0){
resolve(data.data);
}else{
reject(data.msg);
}
}
});
});
},
async getDomainList(){
this.domainList = [];
while(true){
try{
layer.msg('正在获取第'+this.page+'页域名', {icon: 16, shade: 0.01});
var data = await this.getDomainListPaged();
if(data.total == 0 || data.list.length == 0){
layer.closeAll();
break;
}
this.domainList = this.domainList.concat(data.list);
if(this.domainList.length >= data.total){
layer.closeAll();
break;
}
this.page++;
}catch(e){
layer.alert(e, {icon: 2});
break;
}
}
},
submit(){
var domains = [];
this.domainList.forEach(function(item){
if(item.checked && !item.disabled){
domains.push({name: item.Domain, id: item.DomainId, recordcount:item.RecordCount});
}
});
});
},
async getDomainList(){
this.domainList = [];
while(true){
try{
layer.msg('正在获取第'+this.page+'页域名', {icon: 16, shade: 0.01});
var data = await this.getDomainListPaged();
if(data.total == 0 || data.list.length == 0){
layer.closeAll();
break;
}
this.domainList = this.domainList.concat(data.list);
if(this.domainList.length >= data.total){
layer.closeAll();
break;
}
this.page++;
}catch(e){
layer.alert(e, {icon: 2});
break;
if(this.aid == ''){
layer.alert('请选择域名账户');
return;
}
if(domains.length == 0){
layer.alert('请选择要添加的域名');
return;
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type: "POST",
url: "/domain/op/act/batchadd",
data: {aid: this.aid, domains: domains},
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1}, function(){
window.location.href = '/domain';
});
}else{
layer.alert(data.msg, {icon: 2});
}
},
error: function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
},
submit(){
var domains = [];
this.domainList.forEach(function(item){
if(item.checked && !item.disabled){
domains.push({name: item.Domain, id: item.DomainId, recordcount:item.RecordCount});
}
});
if(this.aid == ''){
layer.alert('请选择域名账户');
return;
}
if(domains.length == 0){
layer.alert('请选择要添加的域名');
return;
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type: "POST",
url: "/domain/op/act/batchadd",
data: {aid: this.aid, domains: domains},
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1}, function(){
window.location.href = '/domain';
});
}else{
layer.alert(data.msg, {icon: 2});
}
},
error: function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
},
});
});
</script>
{/block}

141
app/view/domain/expire_notice.html Normal file → Executable file
View File

@ -2,84 +2,81 @@
{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-info">
<div class="panel-heading"><h3 class="panel-title"><a href="/domain" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>域名到期提醒设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">到期提醒天数</label>
<div class="col-sm-9"><input type="text" name="expire_noticedays" value="{:config_get('expire_noticedays')}" class="form-control" placeholder="留空则不开启到期提醒"/><font color="green">域名到期前多少天发送通知可填写多个天数用英文逗号隔开。例如填写7,14则在域名到期前7天与14天分别发送通知。</font></div>
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
<div class="panel panel-info">
<div class="panel-heading font-bold"><h3 class="panel-title"><a href="/domain" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>域名到期提醒设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">到期提醒天数</label>
<div class="col-sm-9"><input type="text" name="expire_noticedays" value="{:config_get('expire_noticedays')}" class="form-control" placeholder="留空则不开启到期提醒"/><font color="green">域名到期前多少天发送通知可填写多个天数用英文逗号隔开。例如填写7,14则在域名到期前7天与14天分别发送通知。</font></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">邮件通知</label>
<div class="col-sm-9"><select class="form-control" name="expire_notice_mail" default="{:config_get('expire_notice_mail')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">微信公众号通知</label>
<div class="col-sm-9"><select class="form-control" name="expire_notice_wxtpl" default="{:config_get('expire_notice_wxtpl')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Telegram机器人通知</label>
<div class="col-sm-9"><select class="form-control" name="expire_notice_tgbot" default="{:config_get('expire_notice_tgbot')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">群机器人Webhook</label>
<div class="col-sm-9"><select class="form-control" name="expire_notice_webhook" default="{:config_get('expire_notice_webhook')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
</div>
</div>
</form>
</div>
</div>
<div class="panel panel-warning">
<div class="panel-heading"><h3 class="panel-title">计划任务说明</h3></div>
<div class="panel-body">
<p>支持域名到期提醒+域名列表到期时间自动刷新。与SSL证书共用计划任务不需要单独添加计划任务。</p><p><a href="/cert/certset">查看计划任务说明</a></p>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">邮件通知</label>
<div class="col-sm-9"><select class="form-control" name="expire_notice_mail" default="{:config_get('expire_notice_mail')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">微信公众号通知</label>
<div class="col-sm-9"><select class="form-control" name="expire_notice_wxtpl" default="{:config_get('expire_notice_wxtpl')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Telegram机器人通知</label>
<div class="col-sm-9"><select class="form-control" name="expire_notice_tgbot" default="{:config_get('expire_notice_tgbot')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">群机器人Webhook</label>
<div class="col-sm-9"><select class="form-control" name="expire_notice_webhook" default="{:config_get('expire_notice_webhook')}"><option value="0">关闭</option><option value="1">开启</option></select></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
</div>
</div>
</form>
</div>
</div>
<div class="panel panel-warning">
<div class="panel-heading"><h3 class="panel-title">计划任务说明</h3></div>
<div class="panel-body">
<p>支持域名到期提醒+域名列表到期时间自动刷新。与SSL证书共用计划任务不需要单独添加计划任务。</p><p><a href="/cert/certset">查看计划任务说明</a></p>
</div>
</div>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script>
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default")||0);
}
function saveSetting(obj){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '',
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})
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default")||0);
}
function saveSetting(obj){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '',
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('服务器错误');
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
return false;
}
});
return false;
}
</script>
{/block}

65
app/view/domain/log.html Normal file → Executable file
View File

@ -1,47 +1,46 @@
{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>
<style>
#orderItem .orderTitle{word-break:keep-all;}
#orderItem .orderContent{word-break:break-all;}
.fixed-table-toolbar,.fixed-table-pagination{padding: 15px;}
</style>
<div class="panel panel-default">
<div class="panel-heading font-bold">
<h3 class="panel-title">域名日志</h3>
</div>
</div>
</div>
<table id="listTable">
</table>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/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;
$(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: '操作行为'
}
],
})
})
$("#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}

1446
app/view/domain/record.html Normal file → Executable file

File diff suppressed because it is too large Load Diff

609
app/view/domain/weight.html Normal file → Executable file
View File

@ -2,15 +2,13 @@
{block name="title"}权重配置 - {$domainName}{/block}
{block name="main"}
<style>
.table-bordered>tbody>tr>td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:200px;vertical-align:middle;}
.table-bordered>tbody>tr>td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:200px;vertical-align:middle;}
</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">&times;</span><span
class="sr-only">Close</span></button>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="modal-title">设置权重</h4>
</div>
<div class="modal-body">
@ -32,10 +30,17 @@
</div>
<table class="table table-striped table-hover table-bordered">
<thead>
<tr><th>主机记录</th><th>记录类型</th><th>记录值</th><th>权重</th></tr>
<tr>
<th>主机记录</th>
<th>记录类型</th>
<th>记录值</th>
<th>权重</th>
</tr>
</thead>
<tbody id="weight-list">
<tr><td colspan="4" class="text-center">正在加载...</td></tr>
<tr>
<td colspan="4" class="text-center">正在加载...</td>
</tr>
</tbody>
</table>
<span class="text-muted">提示权重范围为数字0-100</span>
@ -50,26 +55,20 @@
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12 center-block" style="float: none;">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title"><a href="/record/{$domainId}" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>权重配置 - {$domainName}</h3></div>
<div class="panel panel-default">
<div class="panel-heading font-bold"><h3 class="panel-title"><a href="/record/{$domainId}" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>权重配置 - {$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>
<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>
<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>
<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>
{/block}
{block name="script"}
@ -78,175 +77,423 @@
<script src="{$cdnpublic}bootstrap-table/1.21.4/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};
var recordLine = {$recordLine|json_encode|raw};
var domainId = {$domainId};
var weightList = [];
var lineList = [];
$(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;
var dnsconfig = {$dnsconfig|json_encode|raw};
var recordLine = {$recordLine|json_encode|raw};
var domainId = {$domainId};
var weightList = [];
var lineList = [];
$(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/weight/data/{$domainId}',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
columns: [
{
field: 'SubDomain',
title: '子域名'
},
{
field: 'Type',
title: '记录类型'
},
{
field: 'RecordCount',
title: '记录数量'
},
{
field: 'Open',
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="#b5bbc8"><i class="fa fa-pause-circle"></i>已关闭</font>';
}
}
},
{
field: '',
title: '操作',
formatter: function(value, row, index) {
var html = '';
if(row.Open == 1){
if(row.Type == 'CNAME'){
html += '<a class="btn btn-warning btn-xs" title="CNAME类型解析默认必须开权重模式每次解析应答只返回一条解析结果记录值" disabled>关闭权重</a>&nbsp;&nbsp;';
$("#listTable").bootstrapTable({
url: '/record/weight/data/{$domainId}',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
columns: [
{
field: 'SubDomain',
title: '子域名'
},
{
field: 'Type',
title: '记录类型'
},
{
field: 'RecordCount',
title: '记录数量'
},
{
field: 'Open',
title: '权重配置状态',
formatter: function(value, row, index) {
if(value == 1){
return '<font color="green"><i class="fa fa-check-circle"></i>已开启</font>';
}else{
html += '<a href="javascript:setWeightStatus(\''+row.SubDomain+'\', \'0\')" class="btn btn-warning btn-xs">关闭权重</a>&nbsp;&nbsp;';
return '<font color="#b5bbc8"><i class="fa fa-pause-circle"></i>已关闭</font>';
}
}else{
html += '<a href="javascript:setWeightStatus(\''+row.SubDomain+'\', \'1\')" class="btn btn-success btn-xs">开启权重</a>&nbsp;&nbsp;';
}
html += '<a href="javascript:editframe('+row.id+')" class="btn btn-primary btn-xs">设置权重</a>';
return html;
}
},
],
},
{
field: '',
title: '操作',
formatter: function(value, row, index) {
var html = '';
if(row.Open == 1){
if(row.Type == 'CNAME'){
html += '<a class="btn btn-warning btn-xs" title="CNAME类型解析默认必须开权重模式每次解析应答只返回一条解析结果记录值" disabled>关闭权重</a>&nbsp;&nbsp;';
}else{
html += '<a href="javascript:setWeightStatus(\''+row.SubDomain+'\', \'0\')" class="btn btn-warning btn-xs">关闭权重</a>&nbsp;&nbsp;';
}
}else{
html += '<a href="javascript:setWeightStatus(\''+row.SubDomain+'\', \'1\')" class="btn btn-success btn-xs">开启权重</a>&nbsp;&nbsp;';
}
html += '<a href="javascript:editframe('+row.id+')" class="btn btn-primary btn-xs">设置权重</a>';
return html;
}
},
],
})
})
})
function editframe(id){
var row = $("#listTable").bootstrapTable('getRowByUniqueId', id);
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/record/list',
data : {id: domainId, rr: row.rr},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
$("#modal-store").modal('show');
$("#modal-title").html("设置权重 - "+row.SubDomain);
$("#form-store input[name=id]").val(id);
$("#form-store input[name=subdomain]").val(row.SubDomain);
$("#form-store input[name=type]").val(row.Type);
if(row.Type == 'CNAME') $("#weight-switch").prop("disabled", true);
else $("#weight-switch").prop("disabled", false);
lineList = [];
$.each(recordLine, function(i, item){
if(data.data.find(x => x.Line == item.id)){
item.open = row.Open;
if(row.LineAlgorithms && row.LineAlgorithms.LineAlgorithm.length > 0){
var tmpLine = row.LineAlgorithms.LineAlgorithm.find(x => x.Line == item.id);
if(tmpLine) item.open = tmpLine.Open;
}
lineList.push(item);
}
});
$("#line").empty();
$.each(lineList, function(i, item){
$("#line").append('<option value="'+item.id+'">'+item.name+'</option>');
});
function editframe(id){
var row = $("#listTable").bootstrapTable('getRowByUniqueId', id);
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/record/list',
data : {id: domainId, rr: row.rr},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
$("#modal-store").modal('show');
$("#modal-title").html("设置权重 - "+row.SubDomain);
$("#form-store input[name=id]").val(id);
$("#form-store input[name=subdomain]").val(row.SubDomain);
$("#form-store input[name=type]").val(row.Type);
if(row.Type == 'CNAME') $("#weight-switch").prop("disabled", true);
else $("#weight-switch").prop("disabled", false);
weightList = data.data;
changeLine();
}else{
layer.alert(data.msg, {icon: 2})
lineList = [];
$.each(recordLine, function(i, item){
if(data.data.find(x => x.Line == item.id)){
item.open = row.Open;
if(row.LineAlgorithms && row.LineAlgorithms.LineAlgorithm.length > 0){
var tmpLine = row.LineAlgorithms.LineAlgorithm.find(x => x.Line == item.id);
if(tmpLine) item.open = tmpLine.Open;
}
lineList.push(item);
}
});
$("#line").empty();
$.each(lineList, function(i, item){
$("#line").append('<option value="'+item.id+'">'+item.name+'</option>');
});
weightList = data.data;
changeLine();
}else{
layer.alert(data.msg, {icon: 2})
}
}
}
});
}
function changeLine(){
var line = $("#line").val();
$("#weight-switch").prop("checked", lineList.find(x => x.id == line).open);
$("#weight-list").empty();
$.each(weightList, function(i, item){
if(item.Line == line){
$("#weight-list").append('<tr><td>'+item.Name+'</td><td>'+item.Type+'</td><td>'+item.Value+'</td><td><input type="number" class="form-control" name="weight['+item.RecordId+']" value="'+item.Weight+'" style="width:80px;" min="0" max="100"/></td></tr>');
}
});
changeOpen();
}
function changeOpen(){
if($("#weight-switch").is(':checked')){
$("#weight-list input[name^='weight']").prop("disabled", false);
}else{
$("#weight-list input[name^='weight']").prop("disabled", true);
});
}
}
function save(){
if($("#form-store input[name=username]").val()==''){
layer.alert('请确保各项不能为空!');return false;
function changeLine(){
var line = $("#line").val();
$("#weight-switch").prop("checked", lineList.find(x => x.id == line).open);
$("#weight-list").empty();
$.each(weightList, function(i, item){
if(item.Line == line){
$("#weight-list").append('<tr><td>'+item.Name+'</td><td>'+item.Type+'</td><td>'+item.Value+'</td><td><input type="number" class="form-control" name="weight['+item.RecordId+']" value="'+item.Weight+'" style="width:80px;" min="0" max="100"/></td></tr>');
}
});
changeOpen();
}
var act = $("#form-store input[name=action]").val();
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/record/weight/{$domainId}/act/update',
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(){
function changeOpen(){
if($("#weight-switch").is(':checked')){
$("#weight-list input[name^='weight']").prop("disabled", false);
}else{
$("#weight-list input[name^='weight']").prop("disabled", true);
}
}
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 : '/record/weight/{$domainId}/act/update',
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');
searchRefresh();
});
}else{
layer.alert(data.msg, {icon: 2})
}
}
});
return false;
}
function setWeightStatus(subdomain, status){
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/record/weight/{$domainId}/act/status',
data : {subdomain: subdomain, status: status},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.closeAll();
$("#modal-store").modal('hide');
searchRefresh();
});
}else{
layer.alert(data.msg, {icon: 2})
}else{
layer.alert(data.msg, {icon: 2});
}
}
}
});
return false;
}
function setWeightStatus(subdomain, status){
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/record/weight/{$domainId}/act/status',
data : {subdomain: subdomain, status: status},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.closeAll();
searchRefresh();
}else{
layer.alert(data.msg, {icon: 2});
});
}
</script>
{/block}{extend name="common/layout" /}
{block name="title"}权重配置 - {$domainName}{/block}
{block name="main"}
<style>
.table-bordered>tbody>tr>td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:200px;vertical-align:middle;}
</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">&times;</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" onsubmit="return save(this)">
<input type="hidden" name="id"/>
<input type="hidden" name="subdomain"/>
<input type="hidden" name="type"/>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">选择线路</label>
<div class="col-sm-9">
<select name="line" id="line" class="form-control" onchange="changeLine()"></select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">线路权重开关</label>
<div class="col-sm-9">
<div class="material-switch" style="padding-top:7px"><input id="weight-switch" name="status" type="checkbox" value="1" checked onchange="changeOpen()"/><label for="weight-switch" class="label-primary"></label></div>
</div>
</div>
<table class="table table-striped table-hover table-bordered">
<thead>
<tr>
<th>主机记录</th>
<th>记录类型</th>
<th>记录值</th>
<th>权重</th>
</tr>
</thead>
<tbody id="weight-list">
<tr>
<td colspan="4" class="text-center">正在加载...</td>
</tr>
</tbody>
</table>
<span class="text-muted">提示权重范围为数字0-100</span>
<div class="form-group">
<div class="col-sm-12 text-right">
<button type="submit" class="btn btn-primary">保存</button>
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading font-bold"><h3 class="panel-title"><a href="/record/{$domainId}" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>权重配置 - {$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>
<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>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/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};
var recordLine = {$recordLine|json_encode|raw};
var domainId = {$domainId};
var weightList = [];
var lineList = [];
$(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/weight/data/{$domainId}',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
columns: [
{
field: 'SubDomain',
title: '子域名'
},
{
field: 'Type',
title: '记录类型'
},
{
field: 'RecordCount',
title: '记录数量'
},
{
field: 'Open',
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="#b5bbc8"><i class="fa fa-pause-circle"></i>已关闭</font>';
}
}
},
{
field: '',
title: '操作',
formatter: function(value, row, index) {
var html = '';
if(row.Open == 1){
if(row.Type == 'CNAME'){
html += '<a class="btn btn-warning btn-xs" title="CNAME类型解析默认必须开权重模式每次解析应答只返回一条解析结果记录值" disabled>关闭权重</a>&nbsp;&nbsp;';
}else{
html += '<a href="javascript:setWeightStatus(\''+row.SubDomain+'\', \'0\')" class="btn btn-warning btn-xs">关闭权重</a>&nbsp;&nbsp;';
}
}else{
html += '<a href="javascript:setWeightStatus(\''+row.SubDomain+'\', \'1\')" class="btn btn-success btn-xs">开启权重</a>&nbsp;&nbsp;';
}
html += '<a href="javascript:editframe('+row.id+')" class="btn btn-primary btn-xs">设置权重</a>';
return html;
}
},
],
})
})
function editframe(id){
var row = $("#listTable").bootstrapTable('getRowByUniqueId', id);
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/record/list',
data : {id: domainId, rr: row.rr},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
$("#modal-store").modal('show');
$("#modal-title").html("设置权重 - "+row.SubDomain);
$("#form-store input[name=id]").val(id);
$("#form-store input[name=subdomain]").val(row.SubDomain);
$("#form-store input[name=type]").val(row.Type);
lineList = [];
$.each(recordLine, function(i, item){
if(data.data.find(x => x.Line == item.id)){
item.open = row.Open;
if(row.LineAlgorithms && row.LineAlgorithms.LineAlgorithm.length > 0){
var tmpLine = row.LineAlgorithms.LineAlgorithm.find(x => x.Line == item.id);
if(tmpLine) item.open = tmpLine.Open;
}
lineList.push(item);
}
});
$("#line").empty();
$.each(lineList, function(i, item){
$("#line").append('<option value="'+item.id+'">'+item.name+'</option>');
});
weightList = data.data;
changeLine();
}else{
layer.alert(data.msg, {icon: 2})
}
}
});
}
function changeLine(){
var line = $("#line").val();
$("#weight-switch").prop("checked", lineList.find(x => x.id == line).open);
$("#weight-list").empty();
$.each(weightList, function(i, item){
if(item.Line == line){
$("#weight-list").append('<tr><td>'+item.Name+'</td><td>'+item.Type+'</td><td>'+item.Value+'</td><td><input type="number" class="form-control" name="weight['+item.RecordId+']" value="'+item.Weight+'" style="width:80px;" min="0" max="100"/></td></tr>');
}
});
changeOpen();
}
function changeOpen(){
if($("#weight-switch").is(':checked')){
$("#weight-list input[name^='weight']").prop("disabled", false);
}else{
$("#weight-list input[name^='weight']").prop("disabled", true);
}
});
}
}
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 : '/record/weight/{$domainId}/act/update',
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');
searchRefresh();
});
}else{
layer.alert(data.msg, {icon: 2})
}
}
});
return false;
}
function setWeightStatus(subdomain, status){
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/record/weight/{$domainId}/act/status',
data : {subdomain: subdomain, status: status},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.closeAll();
searchRefresh();
}else{
layer.alert(data.msg, {icon: 2});
}
}
});
}
</script>
{/block}

635
app/view/exception.tpl Normal file → Executable file
View File

@ -13,80 +13,80 @@ if (!function_exists('parse_class')) {
{
$names = explode('\\', $name);
return '<abbr title="'.$name.'">'.end($names).'</abbr>';
}
}
}
if (!function_exists('parse_file')) {
function parse_file($file, $line)
{
return '<a class="toggle" title="'."{$file} line {$line}".'">'.basename($file)." line {$line}".'</a>';
}
function parse_file($file, $line)
{
return '<a class="toggle" title="'."{$file} line {$line}".'">'.basename($file)." line {$line}".'</a>';
}
}
if (!function_exists('parse_args')) {
function parse_args($args)
{
$result = [];
foreach ($args as $key => $item) {
switch (true) {
case is_object($item):
$value = sprintf('<em>object</em>(%s)', parse_class(get_class($item)));
break;
case is_array($item):
if (count($item) > 3) {
$value = sprintf('[%s, ...]', parse_args(array_slice($item, 0, 3)));
} else {
$value = sprintf('[%s]', parse_args($item));
}
break;
case is_string($item):
if (strlen($item) > 20) {
$value = sprintf(
'\'<a class="toggle" title="%s">%s...</a>\'',
htmlentities($item),
htmlentities(substr($item, 0, 20))
);
} else {
$value = sprintf("'%s'", htmlentities($item));
}
break;
case is_int($item):
case is_float($item):
$value = $item;
break;
case is_null($item):
$value = '<em>null</em>';
break;
case is_bool($item):
$value = '<em>' . ($item ? 'true' : 'false') . '</em>';
break;
case is_resource($item):
$value = '<em>resource</em>';
break;
default:
$value = htmlentities(str_replace("\n", '', var_export(strval($item), true)));
break;
}
function parse_args($args)
{
$result = [];
foreach ($args as $key => $item) {
switch (true) {
case is_object($item):
$value = sprintf('<em>object</em>(%s)', parse_class(get_class($item)));
break;
case is_array($item):
if (count($item) > 3) {
$value = sprintf('[%s, ...]', parse_args(array_slice($item, 0, 3)));
} else {
$value = sprintf('[%s]', parse_args($item));
}
break;
case is_string($item):
if (strlen($item) > 20) {
$value = sprintf(
'\'<a class="toggle" title="%s">%s...</a>\'',
htmlentities($item),
htmlentities(substr($item, 0, 20))
);
} else {
$value = sprintf("'%s'", htmlentities($item));
}
break;
case is_int($item):
case is_float($item):
$value = $item;
break;
case is_null($item):
$value = '<em>null</em>';
break;
case is_bool($item):
$value = '<em>' . ($item ? 'true' : 'false') . '</em>';
break;
case is_resource($item):
$value = '<em>resource</em>';
break;
default:
$value = htmlentities(str_replace("\n", '', var_export(strval($item), true)));
break;
}
$result[] = is_int($key) ? $value : sprintf('\'%s\' => %s', htmlentities($key), $value);
}
$result[] = is_int($key) ? $value : "'{$key}' => {$value}";
}
return implode(', ', $result);
}
return implode(', ', $result);
}
}
if (!function_exists('echo_value')) {
function echo_value($val)
{
if (is_array($val) || is_object($val)) {
echo htmlentities(json_encode($val, JSON_PRETTY_PRINT));
} elseif (is_bool($val)) {
echo $val ? 'true' : 'false';
} elseif (is_scalar($val)) {
echo htmlentities($val);
} else {
echo 'Resource';
}
}
function echo_value($val)
{
if (is_array($val) || is_object($val)) {
echo htmlentities(json_encode($val, JSON_PRETTY_PRINT));
} elseif (is_bool($val)) {
echo $val ? 'true' : 'false';
} elseif (is_scalar($val)) {
echo htmlentities($val);
} else {
echo 'Resource';
}
}
}
?>
<!DOCTYPE html>
@ -94,7 +94,7 @@ if (!function_exists('echo_value')) {
<head>
<meta charset="UTF-8">
<title>系统发生错误</title>
<meta name="robots" content="noindex,nofollow" />
<meta name="robots" content="noindex,nofollow"/>
<style>
/* Base */
body {
@ -103,13 +103,15 @@ if (!function_exists('echo_value')) {
margin: 0;
padding: 0 20px 20px;
}
h1{
h1 {
margin: 10px 0 0;
font-size: 28px;
font-weight: 500;
line-height: 32px;
}
h2{
h2 {
color: #4288ce;
font-weight: 400;
padding: 6px 0;
@ -117,29 +119,36 @@ if (!function_exists('echo_value')) {
font-size: 18px;
border-bottom: 1px solid #eee;
}
h3{
h3 {
margin: 12px;
font-size: 16px;
font-weight: bold;
}
abbr{
abbr {
cursor: help;
text-decoration: underline;
text-decoration-style: dotted;
}
a{
a {
color: #868686;
cursor: pointer;
}
a:hover{
a:hover {
text-decoration: underline;
}
.line-error{
.line-error {
background: #f8cbcb;
}
.echo table {
width: 100%;
}
.echo pre {
padding: 16px;
overflow: auto;
@ -150,25 +159,29 @@ if (!function_exists('echo_value')) {
border-radius: 3px;
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
}
.echo pre > pre {
padding: 0;
margin: 0;
}
/* Exception Info */
.exception {
margin-top: 20px;
}
.exception .message{
.exception .message {
padding: 12px;
border: 1px solid #ddd;
border-bottom: 0 none;
line-height: 18px;
font-size:16px;
font-size: 16px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑",serif;
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
}
.exception .code{
.exception .code {
float: left;
text-align: center;
color: #fff;
@ -177,7 +190,8 @@ if (!function_exists('echo_value')) {
border-radius: 4px;
background: #999;
}
.exception .source-code{
.exception .source-code {
padding: 6px;
border: 1px solid #ddd;
@ -185,140 +199,205 @@ if (!function_exists('echo_value')) {
overflow-x: auto;
}
.exception .source-code pre{
.exception .source-code pre {
margin: 0;
}
.exception .source-code pre ol{
.exception .source-code pre ol {
margin: 0;
color: #4288ce;
display: inline-block;
min-width: 100%;
box-sizing: border-box;
font-size:14px;
font-family: "Century Gothic",Consolas,"Liberation Mono",Courier,Verdana,serif;
padding-left: <?php echo (isset($source) && !empty($source)) ? parse_padding($source) : 40; ?>px;
font-size: 14px;
font-family: "Century Gothic", Consolas, "Liberation Mono", Courier, Verdana, serif;
padding-left: < ? php echo (isset($ source) & & ! empty($ source)) ? parse_padding($ source): 40;
? > px;
}
.exception .source-code pre li{
.exception .source-code pre li {
border-left: 1px solid #ddd;
height: 18px;
line-height: 18px;
}
.exception .source-code pre code{
.exception .source-code pre code {
color: #333;
height: 100%;
display: inline-block;
border-left: 1px solid #fff;
font-size:14px;
font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑",serif;
font-size: 14px;
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
}
.exception .trace{
.exception .trace {
padding: 6px;
border: 1px solid #ddd;
border-top: 0 none;
line-height: 16px;
font-size:14px;
font-family: Consolas,"Liberation Mono",Courier,Verdana,"微软雅黑",serif;
font-size: 14px;
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
}
.exception .trace h2:hover {
text-decoration: underline;
cursor: pointer;
}
.exception .trace ol{
.exception .trace ol {
margin: 12px;
}
.exception .trace ol li{
.exception .trace ol li {
padding: 2px 4px;
}
.exception div:last-child{
.exception div:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
/* Exception Variables */
.exception-var table{
.exception-var table {
width: 100%;
margin: 12px 0;
box-sizing: border-box;
table-layout:fixed;
word-wrap:break-word;
table-layout: fixed;
word-wrap: break-word;
}
.exception-var table caption{
.exception-var table caption {
text-align: left;
font-size: 16px;
font-weight: bold;
padding: 6px 0;
}
.exception-var table caption small{
.exception-var table caption small {
font-weight: 300;
display: inline-block;
margin-left: 10px;
color: #ccc;
}
.exception-var table tbody{
.exception-var table tbody {
font-size: 13px;
font-family: Consolas, "Liberation Mono", Courier, "微软雅黑",serif;
font-family: Consolas, "Liberation Mono", Courier, "微软雅黑", serif;
}
.exception-var table td{
.exception-var table td {
padding: 0 6px;
vertical-align: top;
word-break: break-all;
}
.exception-var table td:first-child{
.exception-var table td:first-child {
width: 28%;
font-weight: bold;
white-space: nowrap;
}
.exception-var table td pre{
.exception-var table td pre {
margin: 0;
}
/* Copyright Info */
.copyright{
.copyright {
margin-top: 24px;
padding: 12px 0;
border-top: 1px solid #eee;
}
/* SPAN elements with the classes below are added by prettyprint. */
pre.prettyprint .pln { color: #000 } /* plain text */
pre.prettyprint .str { color: #080 } /* string content */
pre.prettyprint .kwd { color: #008 } /* a keyword */
pre.prettyprint .com { color: #800 } /* a comment */
pre.prettyprint .typ { color: #606 } /* a type name */
pre.prettyprint .lit { color: #066 } /* a literal value */
pre.prettyprint .pln {
color: #000
}
/* plain text */
pre.prettyprint .str {
color: #080
}
/* string content */
pre.prettyprint .kwd {
color: #008
}
/* a keyword */
pre.prettyprint .com {
color: #800
}
/* a comment */
pre.prettyprint .typ {
color: #606
}
/* a type name */
pre.prettyprint .lit {
color: #066
}
/* a literal value */
/* punctuation, lisp open bracket, lisp close bracket */
pre.prettyprint .pun, pre.prettyprint .opn, pre.prettyprint .clo { color: #660 }
pre.prettyprint .tag { color: #008 } /* a markup tag name */
pre.prettyprint .atn { color: #606 } /* a markup attribute name */
pre.prettyprint .atv { color: #080 } /* a markup attribute value */
pre.prettyprint .dec, pre.prettyprint .var { color: #606 } /* a declaration; a variable name */
pre.prettyprint .fun { color: red } /* a function name */
pre.prettyprint .pun, pre.prettyprint .opn, pre.prettyprint .clo {
color: #660
}
pre.prettyprint .tag {
color: #008
}
/* a markup tag name */
pre.prettyprint .atn {
color: #606
}
/* a markup attribute name */
pre.prettyprint .atv {
color: #080
}
/* a markup attribute value */
pre.prettyprint .dec, pre.prettyprint .var {
color: #606
}
/* a declaration; a variable name */
pre.prettyprint .fun {
color: red
}
/* a function name */
</style>
</head>
<body>
<?php if (\think\facade\App::isDebug()) { ?>
<?php foreach ($traces as $index => $trace) { ?>
<div class="exception">
<div class="message">
<div class="info">
<div>
<h2><?php echo "#{$index} [{$trace['code']}]" . sprintf('%s in %s', parse_class($trace['name']), parse_file($trace['file'], $trace['line'])); ?></h2>
</div>
<div><h1><?php echo nl2br(htmlentities($trace['message'])); ?></h1></div>
<?php if (\think\facade\App::isDebug()) { ?>
<?php foreach ($traces as $index => $trace) { ?>
<div class="exception">
<div class="message">
<div class="info">
<div>
<h2><?php echo "#{$index} [{$trace['code']}]" . sprintf('%s in %s', parse_class($trace['name']), parse_file($trace['file'], $trace['line'])); ?></h2>
</div>
<div><h1><?php echo nl2br(htmlentities($trace['message'])); ?></h1></div>
</div>
<?php if (!empty($trace['source'])) { ?>
<div class="source-code">
<pre class="prettyprint lang-php"><ol start="<?php echo $trace['source']['first']; ?>"><?php foreach ((array) $trace['source']['source'] as $key => $value) { ?><li class="line-<?php echo "{$index}-"; echo $key + $trace['source']['first']; echo $trace['line'] === $key + $trace['source']['first'] ? ' line-error' : ''; ?>"><code><?php echo htmlentities($value); ?></code></li><?php } ?></ol></pre>
</div>
<?php }?>
<div class="trace">
<h2 data-expand="<?php echo 0 === $index ? '1' : '0'; ?>">Call Stack</h2>
<ol>
<li><?php echo sprintf('in %s', parse_file($trace['file'], $trace['line'])); ?></li>
<?php foreach ((array) $trace['trace'] as $value) { ?>
<li>
<?php
</div>
<?php if (!empty($trace['source'])) { ?>
<div class="source-code">
<pre class="prettyprint lang-php"><ol
start="<?php echo $trace['source']['first']; ?>"><?php foreach ((array) $trace['source']['source'] as $key =>
$value) { ?><li class="line-<?php echo " {$index}-"; echo $key + $trace['source']['first']; echo $trace['line'] === $key + $trace['source']['first'] ? ' line-error' : ''; ?>"><code><?php echo htmlentities($value); ?></code></li><?php } ?></ol></pre>
</div>
<?php }?>
<div class="trace">
<h2 data-expand="<?php echo 0 === $index ? '1' : '0'; ?>">Call Stack</h2>
<ol>
<li><?php echo sprintf('in %s', parse_file($trace['file'], $trace['line'])); ?></li>
<?php foreach ((array) $trace['trace'] as $value) { ?>
<li>
<?php
// Show Function
if ($value['function']) {
echo sprintf(
@ -335,168 +414,168 @@ if (!function_exists('echo_value')) {
echo sprintf(' in %s', parse_file($value['file'], $value['line']));
}
?>
</li>
<?php } ?>
</ol>
</div>
</div>
<?php } ?>
<?php } else { ?>
<div class="exception">
<div class="info"><h1><?php echo htmlentities($message); ?></h1></div>
</div>
<?php } ?>
<?php if (!empty($datas)) { ?>
<div class="exception-var">
<h2>Exception Datas</h2>
<?php foreach ((array) $datas as $label => $value) { ?>
<table>
<?php if (empty($value)) { ?>
<caption><?php echo $label; ?><small>empty</small></caption>
<?php } else { ?>
<caption><?php echo $label; ?></caption>
<tbody>
<?php foreach ((array) $value as $key => $val) { ?>
<tr>
<td><?php echo htmlentities($key); ?></td>
<td><?php echo_value($val); ?></td>
</tr>
<?php } ?>
</tbody>
</li>
<?php } ?>
</table>
<?php } ?>
</ol>
</div>
<?php } ?>
</div>
<?php } ?>
<?php } else { ?>
<div class="exception">
<div class="info"><h1><?php echo htmlentities($message); ?></h1></div>
</div>
<?php } ?>
<?php if (!empty($tables)) { ?>
<div class="exception-var">
<h2>Environment Variables</h2>
<?php foreach ((array) $tables as $label => $value) { ?>
<table>
<?php if (empty($value)) { ?>
<caption><?php echo $label; ?><small>empty</small></caption>
<?php } else { ?>
<caption><?php echo $label; ?></caption>
<tbody>
<?php foreach ((array) $value as $key => $val) { ?>
<tr>
<td><?php echo htmlentities($key); ?></td>
<td><?php echo_value($val); ?></td>
</tr>
<?php } ?>
</tbody>
<?php } ?>
</table>
<?php if (!empty($datas)) { ?>
<div class="exception-var">
<h2>Exception Datas</h2>
<?php foreach ((array) $datas as $label => $value) { ?>
<table>
<?php if (empty($value)) { ?>
<caption><?php echo $label; ?><small>empty</small></caption>
<?php } else { ?>
<caption><?php echo $label; ?></caption>
<tbody>
<?php foreach ((array) $value as $key => $val) { ?>
<tr>
<td><?php echo htmlentities($key); ?></td>
<td><?php echo_value($val); ?></td>
</tr>
<?php } ?>
</div>
</tbody>
<?php } ?>
</table>
<?php } ?>
</div>
<?php } ?>
<?php if (\think\facade\App::isDebug()) { ?>
<div class="copyright">
<a title="官方网站" href="http://www.thinkphp.cn">ThinkPHP</a>
<span>V<?php echo \think\facade\App::version(); ?></span>
<span>{ -API开发设计的高性能框架 }</span>
<span>- <a title="官方手册" href="https://www.kancloud.cn/manual/thinkphp6_0/content">官方手册</a></span>
</div>
<script>
function $(selector, node){
var elements;
<?php if (!empty($tables)) { ?>
<div class="exception-var">
<h2>Environment Variables</h2>
<?php foreach ((array) $tables as $label => $value) { ?>
<table>
<?php if (empty($value)) { ?>
<caption><?php echo $label; ?><small>empty</small></caption>
<?php } else { ?>
<caption><?php echo $label; ?></caption>
<tbody>
<?php foreach ((array) $value as $key => $val) { ?>
<tr>
<td><?php echo htmlentities($key); ?></td>
<td><?php echo_value($val); ?></td>
</tr>
<?php } ?>
</tbody>
<?php } ?>
</table>
<?php } ?>
</div>
<?php } ?>
<?php if (\think\facade\App::isDebug()) { ?>
<div class="copyright">
<a title="官方网站" href="http://www.thinkphp.cn">ThinkPHP</a>
<span>V<?php echo \think\facade\App::version(); ?></span>
<span>{ -API开发设计的高性能框架 }</span>
<span>- <a title="官方手册" href="https://www.kancloud.cn/manual/thinkphp6_0/content">官方手册</a></span>
</div>
<script>
function $(selector, node) {
var elements;
node = node || document;
if (document.querySelectorAll) {
elements = node.querySelectorAll(selector);
} else {
switch (selector.substr(0, 1)) {
case '#':
elements = [node.getElementById(selector.substr(1))];
break;
case '.':
if (document.getElementsByClassName) {
elements = node.getElementsByClassName(selector.substr(1));
} else {
elements = get_elements_by_class(selector.substr(1), node);
}
break;
default:
elements = node.getElementsByTagName();
}
}
return elements;
function get_elements_by_class(search_class, node, tag) {
var elements = [], eles,
pattern = new RegExp('(^|\\s)' + search_class + '(\\s|$)');
node = node || document;
if(document.querySelectorAll){
elements = node.querySelectorAll(selector);
} else {
switch(selector.substr(0, 1)){
case '#':
elements = [node.getElementById(selector.substr(1))];
break;
case '.':
if(document.getElementsByClassName){
elements = node.getElementsByClassName(selector.substr(1));
} else {
elements = get_elements_by_class(selector.substr(1), node);
}
break;
default:
elements = node.getElementsByTagName();
tag = tag || '*';
eles = node.getElementsByTagName(tag);
for (var i = 0; i < eles.length; i++) {
if (pattern.test(eles[i].className)) {
elements.push(eles[i])
}
}
return elements;
}
}
function get_elements_by_class(search_class, node, tag) {
var elements = [], eles,
pattern = new RegExp('(^|\\s)' + search_class + '(\\s|$)');
$.getScript = function (src, func) {
var script = document.createElement('script');
node = node || document;
tag = tag || '*';
script.async = 'async';
script.src = src;
script.onload = func || function (){};
eles = node.getElementsByTagName(tag);
for(var i = 0; i < eles.length; i++) {
if(pattern.test(eles[i].className)) {
elements.push(eles[i])
}
}
$('head')[0].appendChild(script);
}
return elements;
;(function () {
var files = $('.toggle');
var ol = $('ol', $('.prettyprint')[0]);
var li = $('li', ol[0]);
// 短路径和长路径变换
for (var i = 0; i < files.length; i++) {
files[i].ondblclick = function () {
var title = this.title;
this.title = this.innerHTML;
this.innerHTML = title;
}
}
$.getScript = function(src, func){
var script = document.createElement('script');
script.async = 'async';
script.src = src;
script.onload = func || function(){};
$('head')[0].appendChild(script);
}
;(function(){
var files = $('.toggle');
var ol = $('ol', $('.prettyprint')[0]);
var li = $('li', ol[0]);
// 短路径和长路径变换
for(var i = 0; i < files.length; i++){
files[i].ondblclick = function(){
var title = this.title;
this.title = this.innerHTML;
this.innerHTML = title;
(function () {
var expand = function (dom, expand) {
var ol = $('ol', dom.parentNode)[0];
expand = undefined === expand ? dom.attributes['data-expand'].value === '0' : undefined;
if (expand) {
dom.attributes['data-expand'].value = '1';
ol.style.display = 'none';
dom.innerText = 'Call Stack (展开)';
} else {
dom.attributes['data-expand'].value = '0';
ol.style.display = 'block';
dom.innerText = 'Call Stack (折叠)';
}
}
(function () {
var expand = function (dom, expand) {
var ol = $('ol', dom.parentNode)[0];
expand = undefined === expand ? dom.attributes['data-expand'].value === '0' : undefined;
if (expand) {
dom.attributes['data-expand'].value = '1';
ol.style.display = 'none';
dom.innerText = 'Call Stack (展开)';
} else {
dom.attributes['data-expand'].value = '0';
ol.style.display = 'block';
dom.innerText = 'Call Stack (折叠)';
}
};
var traces = $('.trace');
for (var i = 0; i < traces.length; i++) {
var h2 = $('h2', traces[i])[0];
expand(h2);
h2.onclick = function () {
expand(this);
};
var traces = $('.trace');
for (var i = 0; i < traces.length; i ++) {
var h2 = $('h2', traces[i])[0];
expand(h2);
h2.onclick = function () {
expand(this);
};
}
})();
$.getScript('//cdn.bootcdn.net/ajax/libs/prettify/r298/prettify.min.js', function(){
prettyPrint();
});
}
})();
</script>
<?php } ?>
$.getScript('//cdn.bootcdn.net/ajax/libs/prettify/r298/prettify.min.js', function () {
prettyPrint();
});
})();
</script>
<?php } ?>
</body>
</html>

488
app/view/index/index.html Normal file → Executable file
View File

@ -1,240 +1,312 @@
{extend name="common/layout" /}
{block name="title"}聚合DNS管理系统{/block}
{block name="title"}管理中心{/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;
}
.round {
line-height: 53px;
color: #7266ba;
width: 58px;
height: 58px;
font-size: 26px;
margin-left:15px;
display: inline-block;
font-weight: 400;
border: 3px solid #f8f8fe;
text-align: center;
border-radius: 50%;
background: #e3dff9;
}
</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-heartbeat"></i>
</div>
<a href="/dmonitor/task" 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>SSL证书订单</p>
</div>
<div class="icon">
<i class="fa fa-expeditedssl"></i>
</div>
<a href="/cert/certorder" 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>SSL部署任务</p>
</div>
<div class="icon">
<i class="fa fa-connectdevelop"></i>
</div>
<a href="/cert/deploytask" class="small-box-footer">More info <i class="fa fa-arrow-circle-right"></i></a>
</div>
</div>
<!-- ./col -->
{if request()->user['level'] eq 2}
<div class="row row-sm text-center">
<div class="col-xs-6 col-sm-3">
<div class="panel padder-v item">
<div class="top text-right w-full"><i class="fa fa-caret-down text-warning m-r-sm"></i></div>
<div class="row">
<div class="col-xs-3"><div class="round"><i class="fa fa-cubes fa-fw"></i></div></div>
<div class="col-xs-9"><div class="h1 text-primary-dk font-thin h1"><span id="count1"></span><span class="text-muted text-md"></span></div><span class="text-muted">域名数量</span></div>
</div>
</div>
</div>
<div class="col-xs-6 col-sm-3">
<div class="panel padder-v item">
<div class="top text-right w-full"><i class="fa fa-caret-down text-warning m-r-sm"></i></div>
<div class="row">
<div class="col-xs-3"><div class="round"><i class="fa fa-heartbeat fa-fw"></i></div></div>
<div class="col-xs-9"><div class="h1 text-dark-dk font-thin h1"><span id="count2"></span><span class="text-muted text-md"></span></div><span class="text-muted">容灾切换策略</span></div>
</div>
</div>
</div>
<div class="col-xs-6 col-sm-3">
<div class="panel padder-v item">
<div class="top text-right w-full"><i class="fa fa-caret-down text-warning m-r-sm"></i></div>
<div class="row">
<div class="col-xs-3"><div class="round"><i class="fa fa-expeditedssl fa-fw"></i></div></div>
<div class="col-xs-9"><div class="h1 text-success-dk font-thin h1"><span id="count3"></span><span class="text-muted text-md"></span></div><span class="text-muted">SSL证书订单</span></div>
</div>
</div>
</div>
<div class="col-xs-6 col-sm-3">
<div class="panel padder-v item">
<div class="top text-right w-full"><i class="fa fa-caret-down text-warning m-r-sm"></i></div>
<div class="row">
<div class="col-xs-3"><div class="round"><i class="fa fa-plus-circle fa-fw"></i></div></div>
<div class="col-xs-9"><div class="h1 text-info-dk font-thin h1"><span id="count4"></span><span class="text-muted text-md"></span></div><span class="text-muted">SSL部署任务</span></div>
</div>
</div>
</div>
</div>
<!-- /.row -->
<div class="row">
<div class="col-md-12">
<div id="browser-notice"></div>
</div>
<div class="col-md-4 col-sm-12">
<div class="box box-primary">
<div class="box-header with-border">
<i class="fa fa-heartbeat fa-fw"></i>
<h3 class="box-title">容灾切换概览</h3>
</div>
<ul class="nav nav-pills nav-stacked">
<li><a href="/dmonitor/overview">运行状态<b><span class="pull-right" id="dmonitor_state"></span></b></a></li>
<li><a href="/dmonitor/task">切换策略(已开启)<span class="pull-right badge bg-blue" id="dmonitor_active">0</span></a>
<div class="panel panel-primary">
<div class="panel-heading font-bold"><h3 class="panel-title">容灾切换概览</h3></div>
<div class="panel-body">
<li href="/dmonitor/overview" class="list-group-item">
<span class="badge badge-empty" id="dmonitor_state"></span>
运行状态
</li>
<li><a href="/dmonitor/task?status=0">健康状况正常<span class="pull-right badge bg-green" id="dmonitor_status_0">0</span></a></li>
<li><a href="/dmonitor/task?status=1">健康状况异常<span class="pull-right badge bg-red" id="dmonitor_status_1">0</span></a></li>
</ul>
<li href="/dmonitor/task" class="list-group-item">
<span class="badge bg-info" id="dmonitor_active">0</span>
切换策略(已开启)
</li>
<li href="/dmonitor/task?status=0" class="list-group-item">
<span class="badge bg-success" id="dmonitor_status_0">0</span>
健康状况正常
</li>
<li href="/dmonitor/task?status=1" class="list-group-item">
<span class="badge bg-danger" id="dmonitor_status_1">0</span>
健康状况异常
</li>
</div>
</div>
<div class="box box-info">
<div class="box-header with-border">
<i class="fa fa-globe fa-fw"></i>
<h3 class="box-title">CF优选IP概览</h3>
</div>
<ul class="nav nav-pills nav-stacked">
<li><a href="/optimizeip/opiplist">任务数量(已开启)<span class="pull-right badge bg-blue" id="optimizeip_active">0</span></a>
<div class="panel panel-info">
<div class="panel-heading font-bold"><h3 class="panel-title">CF优选IP概览</h3></div>
<div class="panel-body">
<li href="/dmonitor/task" class="list-group-item">
<span class="badge bg-info" id="optimizeip_active">0</span>
任务数量(已开启)
</li>
<li><a href="/optimizeip/opiplist?status=1">更新成功<span class="pull-right badge bg-green" id="optimizeip_status_1">0</span></a></li>
<li><a href="/optimizeip/opiplist?status=2">更新失败<span class="pull-right badge bg-red" id="optimizeip_status_2">0</span></a></li>
</ul>
</div>
</div>
<div class="col-md-4 col-sm-12">
<div class="box box-success">
<div class="box-header with-border">
<i class="fa fa-globe fa-fw"></i>
<h3 class="box-title">SSL证书概览</h3>
</div>
<ul class="nav nav-pills nav-stacked">
<li class="text-center"><a href="/cert/certorder"><b>SSL证书订单</b></a></li>
<li><a href="/cert/certorder?status=3">已签发<span class="pull-right badge bg-green" id="certorder_status_3">0</span></a>
<li href="/dmonitor/task?status=0" class="list-group-item">
<span class="badge bg-success" id="optimizeip_status_1">0</span>
更新成功
</li>
<li><a href="/cert/certorder?status=5">签发失败<span class="pull-right badge bg-red" id="certorder_status_5">0</span></a></li>
<li><a href="/cert/certorder?status=6">即将过期<span class="pull-right badge bg-orange" id="certorder_status_6">0</span></a></li>
<li><a href="/cert/certorder?status=7">已过期<span class="pull-right badge bg-gray" id="certorder_status_7">0</span></a></li>
<li class="text-center"><a href="/cert/deploytask"><b>自动部署任务</b></a></li>
<li><a href="/cert/deploytask?status=0">待处理<span class="pull-right badge bg-aqua" id="certdeploy_status_0">0</span></a></li>
<li><a href="/cert/deploytask?status=1">部署成功<span class="pull-right badge bg-green" id="certdeploy_status_1">0</span></a></li>
<li><a href="/cert/deploytask?status=-1">部署失败<span class="pull-right badge bg-red" id="certdeploy_status_2">0</span></a></li>
</ul>
<li href="/dmonitor/task?status=1" class="list-group-item">
<span class="badge bg-danger" id="optimizeip_status_2">0</span>
更新失败
</li>
</div>
</div>
</div>
<div class="col-md-4 col-sm-12">
<div class="box box-primary">
<div class="box-header with-border">
<i class="fa fa-cloud"></i>
<h3 class="box-title">服务器信息</h3>
<div class="panel panel-success">
<div class="panel-heading font-bold"><h3 class="panel-title">SSL证书概览</h3></div>
<div class="panel-body">
<li class="list-group-item text-center">
<a href="/cert/certorder"><b>SSL证书订单</b></a>
</li>
<li href="/cert/certorder?status=3" class="list-group-item">
<span class="badge bg-success" id="certorder_status_3">0</span>
已签发
</li>
<li href="/cert/certorder?status=5" class="list-group-item">
<span class="badge bg-danger" id="certorder_status_5">0</span>
签发失败
</li>
<li href="/cert/certorder?status=6" class="list-group-item">
<span class="badge bg-warning" id="certorder_status_6">0</span>
即将过期
</li>
<li href="/cert/certorder?status=7" class="list-group-item">
<span class="badge badge-empty" id="certorder_status_7">0</span>
已过期
</li>
<li class="list-group-item text-center">
<a href="/cert/deploytask"><b>自动部署任务</b></a>
</li>
<li href="/cert/deploytask?status=0" class="list-group-item">
<span class="badge bg-info" id="certdeploy_status_0">0</span>
待处理
</li>
<li href="/cert/deploytask?status=1" class="list-group-item">
<span class="badge bg-success" id="certdeploy_status_1">0</span>
部署成功
</li>
<li href="/cert/deploytask?status=-1" class="list-group-item">
<span class="badge bg-danger" id="certdeploy_status_2">0</span>
部署失败
</li>
</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">数据库版本</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.date}</td>
</tr>
</tbody>
</table>
</div>
<div class="box box-default">
<div class="box-header with-border">
<i class="fa fa-volume-up"></i>
<h3 class="box-title">版本信息</h3>
</div>
<div class="col-md-4 col-sm-12">
<div class="panel panel-info">
<div class="panel-heading font-bold"><h3 class="panel-title">服务器信息</h3></div>
<div class="panel-body">
<li class="list-group-item">
<b>框架版本:</b>{$info.framework_version}
</li>
<li class="list-group-item">
<b>PHP版本</b>{$info.php_version}
</li>
<li class="list-group-item">
<b>数据库版本:</b>{$info.mysql_version}
</li>
<li class="list-group-item">
<b>Web服务器</b>{$info.software}
</li>
<li class="list-group-item">
<b>服务器时间:</b>{$info.date}
</li>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading font-bold"><h3 class="panel-title">版本信息</h3></div>
<div class="panel-body">
<ul class="list-group text-dark" id="checkupdate"></ul>
</div>
<div class="panel-footer">
<button class="btn btn-default btn-block" onclick="cleancache()"><i class="fa fa-trash"></i>清理缓存</button>
</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>
{/if}
{if request()->user['level'] eq 1}
<div class="row">
<div class="col-md-6 col-sm-12">
<div class="panel padder-v item text-center">
<div class="top text-right w-full"><i class="fa fa-caret-down text-warning m-r-sm"></i></div>
<div class="row">
<div class="col-xs-3"><div class="round"><i class="fa fa-cubes fa-fw"></i></div></div>
<div class="col-xs-9"><div class="h1 text-primary-dk font-thin h1"><span id="count1"></span><span class="text-muted text-md"></span></div><span class="text-muted">域名数量</span></div>
</div>
</div>
<div class="panel b-a">
<div class="panel-heading bg-info dk no-border wrapper-lg">
<a class="btn btn-sm btn-rounded btn-info pull-right m-r" href="javascript:;"><i class="fa fa-cog fa-fw"></i></a>
<a class="btn btn-sm btn-rounded btn-info m-l" href="javascript:;"><i class="fa fa-lock fa-fw"></i></a>
</div>
<div class="text-center m-b clearfix">
<div class="thumb-lg avatar m-t-n-xxl">
<img src="/static/images/user.png" alt="..." class="b b-3x b-white">
</div>
<div class="h2 font-thin m-t-sm">{$user.username}</div>
</div>
<div class="hbox text-center b-b b-light text-sm">
<a href="/setpwd" class="col padder-v text-muted b-r b-light">
<i class="icon-settings block m-b-xs fa-2x"></i>
<span>修改密码</span>
</a>
<a href="/domain" class="col padder-v text-muted b-r b-light">
<i class="icon-list block m-b-xs fa-2x"></i>
<span>域名列表</span>
</a>
</div>
</div>
</div>
<div class="col-md-6 col-sm-12">
<div class="panel panel-default">
<div class="panel-heading font-bold"><h3 class="panel-title">系统信息</h3></div>
<div class="panel-body">
<ul class="list-group text-dark">
<li class="list-group-item">
<b>框架版本:</b>{$info.framework_version}
</li>
<li class="list-group-item">
<b>PHP版本</b>{$info.php_version}
</li>
<li class="list-group-item">
<b>数据库版本:</b>{$info.mysql_version}
</li>
<li class="list-group-item">
<b>Web服务器</b>{$info.software}
</li>
<li class="list-group-item">
<b>服务器时间:</b>{$info.date}
</li>
</ul>
</div>
</div>
</div>
</div>
{/if}
{/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.tasks);
$('#count3').html(data.certs);
$('#count4').html(data.deploys);
$('#dmonitor_state').html(data.dmonitor_state==1?'<font color="green">正在运行</font>':'<font color="red">已停止</font>');
$('#dmonitor_active').html(data.dmonitor_active);
$('#dmonitor_status_0').html(data.dmonitor_status_0);
$('#dmonitor_status_1').html(data.dmonitor_status_1);
$('#optimizeip_active').html(data.optimizeip_active);
$('#optimizeip_status_1').html(data.optimizeip_status_1);
$('#optimizeip_status_2').html(data.optimizeip_status_2);
$('#certorder_status_3').html(data.certorder_status_3);
$('#certorder_status_5').html(data.certorder_status_5);
$('#certorder_status_6').html(data.certorder_status_6);
$('#certorder_status_7').html(data.certorder_status_7);
$('#certdeploy_status_0').html(data.certdeploy_status_0);
$('#certdeploy_status_1').html(data.certdeploy_status_1);
$('#certdeploy_status_2').html(data.certdeploy_status_2);
$('.badge').each(function() {
if ($(this).text().trim() === '0') {
$(this).css('opacity', '0.4');
}
});
$.ajax({
url: '{$checkupdate}',
type: 'get',
dataType: 'jsonp',
jsonpCallback: 'callback'
}).done(function(data){
$("#checkupdate").html(data.msg);
})
}
$(document).ready(function () {
$.ajax({
type: "POST",
url: "/",
data: {do: 'stat'},
dataType: 'json',
success: function (data) {
$('#count1').html(data.domains);
$('#count2').html(data.tasks);
$('#count3').html(data.certs);
$('#count4').html(data.deploys);
$('#dmonitor_state').html(data.dmonitor_state==1?'<font color="green">正在运行</font>':'<font color="red">已停止</font>');
$('#dmonitor_active').html(data.dmonitor_active);
$('#dmonitor_status_0').html(data.dmonitor_status_0);
$('#dmonitor_status_1').html(data.dmonitor_status_1);
$('#optimizeip_active').html(data.optimizeip_active);
$('#optimizeip_status_1').html(data.optimizeip_status_1);
$('#optimizeip_status_2').html(data.optimizeip_status_2);
$('#certorder_status_3').html(data.certorder_status_3);
$('#certorder_status_5').html(data.certorder_status_5);
$('#certorder_status_6').html(data.certorder_status_6);
$('#certorder_status_7').html(data.certorder_status_7);
$('#certdeploy_status_0').html(data.certdeploy_status_0);
$('#certdeploy_status_1').html(data.certdeploy_status_1);
$('#certdeploy_status_2').html(data.certdeploy_status_2);
$('.badge').each(function() {
if ($(this).text().trim() === '0') {
$(this).css('opacity', '0.4');
}
});
$.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('服务器错误');
}
});
}
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)
}else if(window.location.protocol.indexOf("https")==-1){
var html = "<div class=\"panel panel-default\"><div class=\"panel-body\"><b style='color:#CC3022;'><i class='fa fa-info-circle fa-fw'></i></b>当前正在使用HTTP访问可能存在被窃取敏感信息风险请使用HTTPS访问</div></div>";
$("#browser-notice").html(html)
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)
} else if (window.location.protocol.indexOf("https") == -1) {
var html = "<div class=\"panel panel-default\"><div class=\"panel-body\"><b style='color:#CC3022;'><i class='fa fa-info-circle fa-fw'></i></b>当前正在使用HTTP访问可能存在被窃取敏感信息风险请使用HTTPS访问</div></div>";
$("#browser-notice").html(html)
}
}
}
speedModeNotice();
speedModeNotice();
</script>
{/block}

349
app/view/index/setpwd.html Normal file → Executable file
View File

@ -2,186 +2,187 @@
{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>
<div class="panel panel-warning">
<div class="panel-heading"><h3 class="panel-title">TOTP二次验证</h3></div>
<div class="panel-body">
<form onsubmit="return saveAccount(this)" method="post" class="form" role="form">
<div class="form-group">
<div class="input-group">
{if $user.totp_open == 1}
<input type="text" name="totp_status" value="已开启" style="color:green" class="form-control" readonly/>
<div class="input-group-btn"><button type="button" class="btn btn-info" onclick="open_totp()">重置</button></div>
<div class="input-group-btn"><button type="button" class="btn btn-danger" onclick="close_totp()">关闭</button></div>
{else}
<input type="text" name="totp_status" value="未开启" style="color:blue" class="form-control" readonly/>
<div class="input-group-btn"><button type="button" class="btn btn-info" onclick="open_totp()">开启</button></div>
{/if}
</div>
</div>
</form>
</div>
<div class="panel-footer">
<p><span class="glyphicon glyphicon-info-sign"></span> 开启后登录时需使用支持TOTP的认证软件进行二次验证提高账号安全性。开启前需确保服务器时间正确。</p>
<p>支持TOTP的认证软件<a href="https://sj.qq.com/appdetail/com.tencent.authenticator" target="_blank" rel="noreferrer">腾讯身份验证器</a><a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2" target="_blank" rel="noreferrer">谷歌身份验证器</a><a href="https://www.microsoft.com/zh-cn/security/mobile-authenticator-app" target="_blank" rel="noreferrer">微软身份验证器</a><a href="https://github.com/freeotp" target="_blank" rel="noreferrer">FreeOTP</a></p>
</div>
</div>
<div class="modal" id="modal-totp" data-backdrop="static" data-keyboard="false" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">TOTP绑定</h4>
</div>
<div class="modal-body text-center">
<p>使用支持TOTP的认证软件扫描以下二维码</p>
<div class="qr-image mt-4" id="qrcode"></div>
<p><a href="javascript:;" data-clipboard-text="" id="copy-btn">复制密钥</a></p>
<form id="form-totp" style="text-align: left;" onsubmit="return bind_totp()">
<div class="form-group mt-4">
<div class="input-group"><input type="number" class="form-control input-lg" name="code" id="code" value="" placeholder="填写动态口令" autocomplete="off" required><div class="input-group-btn"><input type="submit" name="submit" value="完成绑定" class="btn btn-success btn-lg btn-block"/></div></div>
</div>
</form>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
<div class="panel panel-info">
<div class="panel-heading font-bold"><h3 class="panel-title">修改密码</h3></div>
<div class="panel-body">
<form class="form" method="post" onsubmit="return saveAccount(this)" role="form">
<div class="form-group">
<label>旧密码:</label>
<input class="form-control" name="oldpwd" placeholder="请输入当前的密码" required type="password" value=""/>
</div>
<div class="form-group">
<label>新密码:</label>
<input class="form-control" name="newpwd" placeholder="" required type="password" value=""/>
</div>
<div class="form-group">
<label>重输密码:</label>
<input class="form-control" name="newpwd2" placeholder="" required type="password" value=""/>
</div>
<div class="form-group text-center">
<input class="btn btn-primary btn-block" name="submit" type="submit" value="确定"/>
</div>
</form>
</div>
</div>
<div class="panel panel-warning">
<div class="panel-heading"><h3 class="panel-title">TOTP二次验证</h3></div>
<div class="panel-body">
<form onsubmit="return saveAccount(this)" method="post" class="form" role="form">
<div class="form-group">
<div class="input-group">
{if $user.totp_open == 1}
<input type="text" name="totp_status" value="已开启" style="color:green" class="form-control" readonly/>
<div class="input-group-btn"><button type="button" class="btn btn-info" onclick="open_totp()">重置</button></div>
<div class="input-group-btn"><button type="button" class="btn btn-danger" onclick="close_totp()">关闭</button></div>
{else}
<input type="text" name="totp_status" value="未开启" style="color:blue" class="form-control" readonly/>
<div class="input-group-btn"><button type="button" class="btn btn-info" onclick="open_totp()">开启</button></div>
{/if}
</div>
</div>
</form>
</div>
<div class="panel-footer">
<p><span class="glyphicon glyphicon-info-sign"></span> 开启后登录时需使用支持TOTP的认证软件进行二次验证提高账号安全性。开启前需确保服务器时间正确。</p>
<p>支持TOTP的认证软件<a href="https://sj.qq.com/appdetail/com.tencent.authenticator" target="_blank" rel="noreferrer">腾讯身份验证器</a><a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2" target="_blank" rel="noreferrer">谷歌身份验证器</a><a href="https://www.microsoft.com/zh-cn/security/mobile-authenticator-app" target="_blank" rel="noreferrer">微软身份验证器</a><a href="https://github.com/freeotp" target="_blank" rel="noreferrer">FreeOTP</a></p>
</div>
</div>
<div aria-hidden="true" aria-labelledby="myModalLabel" class="modal inmodal fade" data-backdrop="static" id="modal-totp" data-keyboard="false" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button aria-label="Close" class="close" data-dismiss="modal" type="button">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title">TOTP绑定</h4>
</div>
<div class="modal-body">
<p>使用支持TOTP的认证软件扫描以下二维码</p>
<div class="qr-image mt-4" id="qrcode"></div>
<p><a href="javascript:;" data-clipboard-text="" id="copy-btn">复制密钥</a></p>
<form id="form-totp" style="text-align: left;" onsubmit="return bind_totp()">
<div class="form-group mt-4">
<div class="input-group"><input type="number" class="form-control input-lg" name="code" id="code" value="" placeholder="填写动态口令" autocomplete="off" required><div class="input-group-btn"><input type="submit" name="submit" value="完成绑定" class="btn btn-success btn-lg btn-block"/></div></div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}jquery.qrcode/1.0/jquery.qrcode.min.js"></script>
<script src="{$cdnpublic}clipboard.js/1.7.1/clipboard.min.js"></script>
<script>
var commonData = {secret:null,qrcode:null};
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){
var commonData = {secret:null,qrcode:null};
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;
}
function open_totp(){
if(!commonData.qrcode || !commonData.secret){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/totp/generate', {}, function(res){
layer.close(ii);
if(res.code == 0){
commonData.secret = res.data.secret;
commonData.qrcode = res.data.qrcode;
$('#qrcode').qrcode({
text: commonData.qrcode,
width: 150,
height: 150,
foreground: "#000000",
background: "#ffffff",
typeNumber: -1
});
$("#copy-btn").attr('data-clipboard-text', commonData.secret);
$('#modal-totp').modal('show');
$("#code").focus();
}else{
layer.alert(res.msg, {icon: 2});
}
});
}else{
$('#modal-totp').modal('show');
$("#code").focus();
}
}
function bind_totp(){
var code = $("#code").val();
if(code.length != 6){
layer.msg('动态口令格式错误', {icon: 2});
return false;
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/totp/bind', {secret:commonData.secret, code:code}, function(res){
layer.close(ii);
layer.msg('服务器错误');
}
});
return false;
}
function open_totp(){
if(!commonData.qrcode || !commonData.secret){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/totp/generate', {}, function(res){
layer.close(ii);
if(res.code == 0){
commonData.secret = res.data.secret;
commonData.qrcode = res.data.qrcode;
$('#qrcode').qrcode({
text: commonData.qrcode,
width: 150,
height: 150,
foreground: "#000000",
background: "#ffffff",
typeNumber: -1
});
$("#copy-btn").attr('data-clipboard-text', commonData.secret);
$('#modal-totp').modal('show');
$("#code").focus();
}else{
layer.alert(res.msg, {icon: 2});
}
});
}else{
$('#modal-totp').modal('show');
$("#code").focus();
}
}
function bind_totp(){
var code = $("#code").val();
if(code.length != 6){
layer.msg('动态口令格式错误', {icon: 2});
return false;
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/totp/bind', {secret:commonData.secret, code:code}, function(res){
layer.close(ii);
if(res.code == 0){
layer.alert('TOTP绑定成功', {icon: 1}, function(){
window.location.reload();
});
}else{
layer.alert(res.msg, {icon: 2});
}
});
return false;
}
function close_totp(){
layer.confirm('确定要关闭TOTP二次验证吗', {
btn: ['确定','取消']
}, function(){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/totp/close', {}, function(res){
layer.close(ii);
if(res.code == 0){
layer.alert('TOTP已关闭', {icon: 1}, function(){
window.location.reload();
});
}else{
layer.alert(res.msg, {icon: 2});
}
});
});
}
$(document).ready(function(){
var clipboard = new Clipboard('#copy-btn');
clipboard.on('success', function (e) {
layer.msg('复制成功!', {icon: 1, time: 600});
});
clipboard.on('error', function (e) {
layer.msg('复制失败', {icon: 2});
});
$("#code").keyup(function(){
var code = $(this).val();
if(code.length == 6){
$("#form-totp").submit();
}
});
});
if(res.code == 0){
layer.alert('TOTP绑定成功', {icon: 1}, function(){
window.location.reload();
});
}else{
layer.alert(res.msg, {icon: 2});
}
});
return false;
}
function close_totp(){
layer.confirm('确定要关闭TOTP二次验证吗', {
btn: ['确定','取消']
}, function(){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.post('/totp/close', {}, function(res){
layer.close(ii);
if(res.code == 0){
layer.alert('TOTP已关闭', {icon: 1}, function(){
window.location.reload();
});
}else{
layer.alert(res.msg, {icon: 2});
}
});
});
}
$(document).ready(function(){
var clipboard = new Clipboard('#copy-btn');
clipboard.on('success', function (e) {
layer.msg('复制成功!', {icon: 1, time: 600});
});
clipboard.on('error', function (e) {
layer.msg('复制失败', {icon: 2});
});
$("#code").keyup(function(){
var code = $(this).val();
if(code.length == 6){
$("#form-totp").submit();
}
});
});
</script>
{/block}

28
app/view/install/index.html Normal file → Executable file
View File

@ -2,10 +2,10 @@
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<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">
<meta content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<meta content="webkit" name="renderer">
<style>
body {
background: #f1f6fd;
@ -153,7 +153,11 @@
<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 class="icon" data-spm-anchor-id="a313x.7781069.0.i0" height="100%" p-id="2750" t="1671271578323"
version="1.1" viewBox="0 0 1024 1024" width="20%" xmlns="http://www.w3.org/2000/svg">
<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>
@ -166,44 +170,44 @@
<div class="form-group">
<div class="form-field">
<label>MySQL 数据库地址</label>
<input type="text" name="mysql_host" value="localhost" required="">
<input name="mysql_host" required="" type="text" value="localhost">
</div>
<div class="form-field">
<label>MySQL 数据库端口</label>
<input type="number" name="mysql_port" value="3306">
<input name="mysql_port" type="number" value="3306">
</div>
<div class="form-field">
<label>MySQL 用户名</label>
<input type="text" name="mysql_user" value="" required="">
<input name="mysql_user" required="" type="text" value="">
</div>
<div class="form-field">
<label>MySQL 密码</label>
<input type="text" name="mysql_pwd" value="" required="">
<input name="mysql_pwd" required="" type="text" value="">
</div>
<div class="form-field">
<label>MySQL 数据库名</label>
<input type="text" name="mysql_name" value="" required="">
<input name="mysql_name" required="" type="text" value="">
</div>
<div class="form-field">
<label>MySQL 数据表前缀</label>
<input type="text" name="mysql_prefix" value="dnsmgr_">
<input name="mysql_prefix" type="text" value="dnsmgr_">
</div>
</div>
<div class="form-group">
<div class="form-field">
<label>管理员用户名</label>
<input type="text" name="admin_username" value="admin" required=""/>
<input name="admin_username" required="" type="text" value="admin"/>
</div>
<div class="form-field">
<label>管理员密码</label>
<input type="text" name="admin_password" value="123456" required="">
<input name="admin_password" required="" type="text" value="123456">
</div>
</div>

339
app/view/optimizeip/opipform.html Normal file → Executable file
View File

@ -2,187 +2,194 @@
{block name="title"}优选IP任务{/block}
{block name="main"}
<style>
.dselect::before{
.dselect::before {
content: '.';
position: absolute;
left: 0;
}
.tips{color: #f6a838; padding-left: 5px;}
.tips {
color: #f6a838;
padding-left: 5px;
}
</style>
<div class="row" id="app">
<div class="col-xs-12 center-block" style="float: none;">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title"><a href="/optimizeip/opiplist" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}编辑{else}添加{/if}优选IP任务</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="taskform">
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">域名选择</label>
<div class="col-sm-6">
<div class="input-group">
<input type="text" name="rr" v-model="set.rr" placeholder="主机记录" class="form-control" required>
<span class="input-group-addon">.</span>
<select name="did" v-model="set.did" class="form-control" required>
<option value="">--主域名--</option>
{foreach $domains as $k=>$v}
<option value="{$k}">{$v}</option>
{/foreach}
</select>
<a tabindex="0" class="input-group-addon" role="button" data-toggle="popover" data-trigger="focus" title="" data-placement="bottom" data-content="不支持对CloudFlare里的域名添加优选必须使用其他DNS服务商。" data-original-title="说明"><span class="glyphicon glyphicon-info-sign"></span></a>
</div>
<div id="app">
<div class="panel panel-default">
<div class="panel-heading font-bold"><h3 class="panel-title"><a class="btn btn-sm btn-default pull-right" href="/optimizeip/opiplist" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}编辑{else}添加{/if}优选IP任务</h3></div>
<div class="panel-body">
<form class="form-horizontal" id="taskform" method="post" onsubmit="return false" role="form">
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">域名选择</label>
<div class="col-sm-6">
<div class="input-group">
<input type="text" name="rr" v-model="set.rr" placeholder="主机记录" class="form-control" required>
<span class="input-group-addon">.</span>
<select name="did" v-model="set.did" class="form-control" required>
<option value="">--主域名--</option>
{foreach $domains as $k=>$v}
<option value="{$k}">{$v}</option>
{/foreach}
</select>
<a tabindex="0" class="input-group-addon" role="button" data-toggle="popover" data-trigger="focus" title="" data-placement="bottom" data-content="不支持对CloudFlare里的域名添加优选必须使用其他DNS服务商。" 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 no-padding-right">CDN服务商</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="(value,key) in cdntypeList">
<input :value="key" name="cdntype" type="radio" v-model="set.cdn_type"> {{value}}
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">解析线路类型</label>
<div class="col-sm-6">
<label class="radio-inline">
<input name="type" type="radio" v-model="set.type" value="0"> 电信/联通/移动线路<span class="tips" data-original-title="" data-placement="bottom" data-toggle="tooltip" title="用于已在CF添加需优化三网访问速度的域名"><i class="fa fa-question-circle"></i></span>
</label>
<label class="radio-inline">
<input name="type" type="radio" v-model="set.type" value="1"> 默认/联通/移动线路<span class="tips" data-original-title="" data-placement="bottom" data-toggle="tooltip" title="将电信优选IP解析到默认线路用于给其他域名提供CNAME服务"><i class="fa fa-question-circle"></i></span>
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">解析IP类型<span class="tips" data-original-title="同时开启IPv6&IPv4将会请求2次接口消耗双倍积分" data-placement="bottom" data-toggle="tooltip" title=""><i class="fa fa-question-circle"></i></span></label>
<div class="col-sm-6">
<label class="checkbox-inline" v-for="option in iptypeList">
<input :value="option.value" name="ip_type" required type="checkbox" v-model="set.ip_type_select"> {{option.label}}
</label>
<br/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">每线路解析数量<span class="tips" data-original-title="数量不要超过当前域名套餐允许的最大数量,否则会添加解析失败" data-placement="bottom" data-toggle="tooltip" title=""><i class="fa fa-question-circle"></i></span></label>
<div class="col-sm-6">
<input class="form-control" data-bv-integer="true" max="5" min="1" name="recordnum" placeholder="填写每线路解析数量" required type="text" v-model="set.recordnum">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">TTL<span class="tips" data-original-title="TTL不要低于当前域名套餐允许的最小值否则会添加解析失败" data-placement="bottom" data-toggle="tooltip" title=""><i class="fa fa-question-circle"></i></span></label>
<div class="col-sm-6">
<input class="form-control" data-bv-integer="true" max="3600" min="1" name="ttl" placeholder="填写TTL" required type="text" v-model="set.ttl">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">备注</label>
<div class="col-sm-6">
<input class="form-control" name="remark" placeholder="可留空" type="text" v-model="set.remark">
</div>
</div>
<div class="form-group" v-show="set.type==0">
<div class="col-sm-offset-3 col-sm-6">
<div class="alert alert-dismissible alert-info">
<button aria-label="Close" class="close" data-dismiss="alert" type="button"><span aria-hidden="true">&times;</span></button>
<strong>提示:</strong>所选域名需保留一个默认线路的解析记录,指向{{cdntypeList[set.cdn_type]}}提供的CNAME地址其他线路的解析记录需要删除添加任务后将自动为当前域名添加电信/联通/移动线路的解析记录。
</div>
</div>
</div>
<div class="form-group" v-show="set.type==1">
<div class="col-sm-offset-3 col-sm-6">
<div class="alert alert-dismissible alert-info">
<button aria-label="Close" class="close" data-dismiss="alert" type="button"><span aria-hidden="true">&times;</span></button>
<strong>提示:</strong>所选域名需删除全部解析记录,添加任务后将自动为当前域名添加解析记录。
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button @click="submit" class="btn btn-primary" type="button">提交</button>
</div>
</div>
</form>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">CDN服务商</label>
<div class="col-sm-6">
<label class="radio-inline" v-for="(value,key) in cdntypeList">
<input type="radio" name="cdntype" :value="key" v-model="set.cdn_type"> {{value}}
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">解析线路类型</label>
<div class="col-sm-6">
<label class="radio-inline">
<input type="radio" name="type" value="0" v-model="set.type"> 电信/联通/移动线路<span class="tips" title="用于已在CF添加需优化三网访问速度的域名" data-toggle="tooltip" data-placement="bottom" data-original-title=""><i class="fa fa-question-circle"></i></span>
</label>
<label class="radio-inline">
<input type="radio" name="type" value="1" v-model="set.type"> 默认/联通/移动线路<span class="tips" title="将电信优选IP解析到默认线路用于给其他域名提供CNAME服务" data-toggle="tooltip" data-placement="bottom" data-original-title=""><i class="fa fa-question-circle"></i></span>
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">解析IP类型<span class="tips" title="" data-toggle="tooltip" data-placement="bottom" data-original-title="同时开启IPv6&IPv4将会请求2次接口消耗双倍积分"><i class="fa fa-question-circle"></i></span></label>
<div class="col-sm-6">
<label class="checkbox-inline" v-for="option in iptypeList">
<input type="checkbox" name="ip_type" :value="option.value" v-model="set.ip_type_select" required> {{option.label}}
</label><br/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">每线路解析数量<span class="tips" title="" data-toggle="tooltip" data-placement="bottom" data-original-title="数量不要超过当前域名套餐允许的最大数量,否则会添加解析失败"><i class="fa fa-question-circle"></i></span></label>
<div class="col-sm-6">
<input type="text" name="recordnum" v-model="set.recordnum" placeholder="填写每线路解析数量" class="form-control" data-bv-integer="true" min="1" max="5" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">TTL<span class="tips" title="" data-toggle="tooltip" data-placement="bottom" data-original-title="TTL不要低于当前域名套餐允许的最小值否则会添加解析失败"><i class="fa fa-question-circle"></i></span></label>
<div class="col-sm-6">
<input type="text" name="ttl" v-model="set.ttl" placeholder="填写TTL" class="form-control" data-bv-integer="true" min="1" max="3600" required>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">备注</label>
<div class="col-sm-6">
<input type="text" name="remark" v-model="set.remark" placeholder="可留空" class="form-control">
</div>
</div>
<div class="form-group" v-show="set.type==0">
<div class="col-sm-offset-3 col-sm-6">
<div class="alert alert-dismissible alert-info">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<strong>提示:</strong>所选域名需保留一个默认线路的解析记录,指向{{cdntypeList[set.cdn_type]}}提供的CNAME地址其他线路的解析记录需要删除添加任务后将自动为当前域名添加电信/联通/移动线路的解析记录。
</div>
</div>
</div>
<div class="form-group" v-show="set.type==1">
<div class="col-sm-offset-3 col-sm-6">
<div class="alert alert-dismissible alert-info">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<strong>提示:</strong>所选域名需删除全部解析记录,添加任务后将自动为当前域名添加解析记录。
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">提交</button></div>
</div>
</form>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}vue/2.6.14/vue.min.js"></script>
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="/static/js/bootstrapValidator.min.js"></script>
<script>
var action = '{$action}';
var info = {$info|json_encode|raw};
new Vue({
el: '#app',
data: {
action: '{$action}',
set: {
id: '',
remark: '',
rr: '',
did: '',
type: 0,
cdn_type: 1,
ip_type_select: ['v4'],
ip_type: 'v4',
recordnum: 2,
ttl: 600,
var action = '{$action}';
var info = {$info | json_encode | raw}
new Vue({
el: '#app',
data: {
action: '{$action}',
set: {
id: '',
remark: '',
rr: '',
did: '',
type: 0,
cdn_type: 1,
ip_type_select: ['v4'],
ip_type: 'v4',
recordnum: 2,
ttl: 600,
},
iptypeList: [
{value: 'v4', label: 'IPv4(A记录)'},
{value: 'v6', label: 'IPv6(AAAA记录)'},
],
cdntypeList: {
1: 'CloudFlare',
2: "CloudFront",
3: 'Gcore'
},
},
iptypeList: [
{value:'v4', label:'IPv4(A记录)'},
{value:'v6', label:'IPv6(AAAA记录)'},
],
cdntypeList: {
1:'CloudFlare',
2:"CloudFront",
3:'Gcore'
},
},
watch: {
'set.ip_type_select': function(val){
this.set.ip_type = val.join(',');
}
},
mounted() {
if(this.action == 'edit'){
Object.keys(info).forEach((key) => {
this.$set(this.set, key, info[key])
})
this.set.ip_type_select = this.set.ip_type.split(',')
}
$("#taskform").bootstrapValidator({
live: 'submitted',
});
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="popover"]').popover()
},
methods: {
submit(){
var that=this;
$("#taskform").data("bootstrapValidator").validate();
if(!$("#taskform").data("bootstrapValidator").isValid()){
return false;
watch: {
'set.ip_type_select': function (val) {
this.set.ip_type = val.join(',');
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type: "POST",
url: "",
data: this.set,
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1}, function(){
if(document.referrer.indexOf('/opiplist?') > 0)
window.location.href = document.referrer;
else
window.location.href = '/optimizeip/opiplist';
});
}else{
layer.alert(data.msg, {icon: 2});
}
},
error: function(data){
layer.close(ii);
layer.msg('服务器错误');
}
},
mounted() {
if (this.action == 'edit') {
Object.keys(info).forEach((key) => {
this.$set(this.set, key, info[key])
})
this.set.ip_type_select = this.set.ip_type.split(',')
}
$("#taskform").bootstrapValidator({
live: 'submitted',
});
}
},
});
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="popover"]').popover()
},
methods: {
submit() {
var that = this;
$("#taskform").data("bootstrapValidator").validate();
if (!$("#taskform").data("bootstrapValidator").isValid()) {
return false;
}
var ii = layer.load(2, {shade: [0.1, '#fff']});
$.ajax({
type: "POST",
url: "",
data: this.set,
dataType: 'json',
success: function (data) {
layer.close(ii);
if (data.code == 0) {
layer.alert(data.msg, {icon: 1}, function () {
if (document.referrer.indexOf('/opiplist?') > 0)
window.location.href = document.referrer;
else
window.location.href = '/optimizeip/opiplist';
});
} else {
layer.alert(data.msg, {icon: 2});
}
},
error: function (data) {
layer.close(ii);
layer.msg('服务器错误');
}
});
}
},
});
</script>
{/block}

347
app/view/optimizeip/opiplist.html Normal file → Executable file
View File

@ -2,186 +2,191 @@
{block name="title"}CF优选IP任务管理{/block}
{block name="main"}
<style>
tbody tr>td:nth-child(2){overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:180px;}
#orderItem .orderTitle{word-break:keep-all;}
#orderItem .orderContent{word-break:break-all;}
.fixed-table-toolbar,.fixed-table-pagination{padding: 15px;}
</style>
<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>
<div class="form-group">
<select name="type" class="form-control"><option value="1">域名</option><option value="2">备注</option></select>
</div>
</div>
<div class="form-group">
<input type="text" class="form-control" name="kw" placeholder="">
</div>
<div class="form-group">
<div class="form-group">
<select name="status" class="form-control"><option value="">更新结果</option><option value="1">成功</option><option value="2">失败</option></select>
</div>
</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="/optimizeip/opipform/add" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
</form>
<table id="listTable">
</table>
<div class="panel panel-default">
<div class="panel-heading font-bold">
<h3 class="panel-title">CF优选IP任务管理</h3>
</div>
</div>
</div>
<form class="form-inline" id="searchToolbar" method="GET" onsubmit="return searchSubmit()">
<div class="form-group">
<div class="form-group">
<select class="form-control" name="type">
<option value="1">域名</option>
<option value="2">备注</option>
</select>
</div>
</div>
<div class="form-group">
<input class="form-control" name="kw" placeholder="" type="text">
</div>
<div class="form-group">
<div class="form-group">
<select name="status" class="form-control">
<option value="">更新结果</option>
<option value="1">成功</option>
<option value="2">失败</option>
</select>
</div>
</div>
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
<a class="btn btn-default" href="javascript:searchClear()" title="刷新CF优选IP任务列表"><i class="fa fa-refresh"></i> 刷新</a>
<a class="btn btn-success" href="/optimizeip/opipform/add"><i class="fa fa-plus"></i> 添加</a>
</form>
<table id="listTable">
</table>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/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;
$(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: '/optimizeip/opiplist/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
columns: [
{
field: 'id',
title: 'ID'
},
{
field: 'rr',
title: '域名',
formatter: function(value, row, index) {
return '<span title="'+row.remark+'" data-toggle="tooltip" data-placement="right">' + value + '.' + row.domain + '</span>';
}
},
{
field: 'cdn_type',
title: 'CDN运营商',
formatter: function(value, row, index) {
if(value == 1){
return 'CloudFlare';
}else if(value == 2){
return 'CloudFront';
}else if(value == 3){
return 'Gcore';
}else{
return '未知';
}
}
},
{
field: 'recordnum',
title: '解析数量',
formatter: function(value, row, index) {
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="TTL'+row.ttl+'" class="tips">'+value+'</span>';
}
},
{
field: 'ip_type',
title: '解析IP类型',
formatter: function(value, row, index) {
var value = value.split(',')
value.forEach((element, index) => {
if(element == 'v4') value[index] = 'IPv4'
else if(element == 'v6') value[index] = 'IPv6'
});
return value.join(',');
}
},
{
field: 'active',
title: '任务开关',
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" checked onchange="setActive('+row.id+',0)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
}else{
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" onchange="setActive('+row.id+',1)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
}
}
},
{
field: 'updatetime',
title: '上次更新时间',
formatter: function(value, row, index) {
return value ? value : '无';
}
},
{
field: 'status',
title: '上次更新结果',
formatter: function(value, row, index) {
if(value == 1) {
return '<span class="label label-success">成功</span>';
} else if(value == 2) {
return '<span class="label label-danger">失败</span> <span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="'+row.errmsg+'" class="tips"><i class="fa fa-info-circle"></i></span>';
} else {
return '<span class="label label-warning">未运行</span>';
}
}
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var html = '<a href="javascript:runTask(\''+row.id+'\')" class="btn btn-success btn-xs">手动更新</a>&nbsp;&nbsp;';
html += '<a href="/optimizeip/opipform/edit?id='+row.id+'" class="btn btn-primary btn-xs">修改</a>&nbsp;&nbsp;';
html += '<a href="/record/'+row.did+'?keyword='+row.rr+'" class="btn btn-default btn-xs" target="_blank">解析</a>&nbsp;&nbsp;';
html += '<a href="javascript:delItem(\''+row.id+'\')" class="btn btn-danger btn-xs">删除</a>&nbsp;&nbsp;';
return html;
}
},
],
onLoadSuccess: function(data) {
$('[data-toggle="tooltip"]').tooltip()
}
})
})
function setActive(id, active){
$.post('/optimizeip/opipform/setactive', {id: id, active: active}, function(data){
if(data.code == 0) {
layer.msg('修改成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
}
function delItem(id){
layer.confirm('确定要删除此任务吗?', {
btn: ['确定','取消']
}, function(){
$.post('/optimizeip/opipform/del', {id: id}, function(data){
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
function runTask(id){
var ii = layer.msg('正在更新中...', {icon: 16,shade: 0.1,time: 0});
$.post('/optimizeip/opipform/run', {id: id}, function(data){
layer.close(ii);
if(data.code == 0) {
layer.alert(data.msg, {icon: 1});
$('#listTable').bootstrapTable('refresh');
} else {
layer.alert(data.msg, {icon: 2});
}
}, 'json');
}
$("#listTable").bootstrapTable({
url: '/optimizeip/opiplist/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
columns: [
{
field: 'id',
title: 'ID'
},
{
field: 'rr',
title: '域名',
formatter: function (value, row, index) {
return '<span title="' + row.remark + '" data-toggle="tooltip" data-placement="right">' + value + '.' + row.domain + '</span>';
}
},
{
field: 'cdn_type',
title: 'CDN运营商',
formatter: function (value, row, index) {
if (value == 1) {
return 'CloudFlare';
} else if (value == 2) {
return 'CloudFront';
} else if (value == 3) {
return 'Gcore';
} else {
return '未知';
}
}
},
{
field: 'recordnum',
title: '解析数量',
formatter: function (value, row, index) {
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="TTL' + row.ttl + '" class="tips">' + value + '</span>';
}
},
{
field: 'ip_type',
title: '解析IP类型',
formatter: function (value, row, index) {
var value = value.split(',')
value.forEach((element, index) => {
if (element == 'v4') value[index] = 'IPv4'
else if (element == 'v6') value[index] = 'IPv6'
});
return value.join(',');
}
},
{
field: 'active',
title: '任务开关',
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="active' + row.id + '" type="checkbox" checked onchange="setActive(' + row.id + ',0)"/><label for="active' + row.id + '" class="label-primary"></label></div>';
}else{
return '<div class="material-switch"><input id="active' + row.id + '" type="checkbox" onchange="setActive(' + row.id + ',1)"/><label for="active' + row.id + '" class="label-primary"></label></div>';
}
}
},
{
field: 'updatetime',
title: '上次更新时间',
formatter: function (value, row, index) {
return value ? value : '无';
}
},
{
field: 'status',
title: '上次更新结果',
formatter: function (value, row, index) {
if (value == 1) {
return '<span class="label label-success">成功</span>';
} else if (value == 2) {
return '<span class="label label-danger">失败</span> <span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="' + row.errmsg + '" class="tips"><i class="fa fa-info-circle"></i></span>';
} else {
return '<span class="label label-warning">未运行</span>';
}
}
},
{
field: 'action',
title: '操作',
formatter: function (value, row, index) {
var html = '<a href="javascript:runTask(\'' + row.id + '\')" class="btn btn-success btn-xs">手动更新</a>&nbsp;&nbsp;';
html += '<a href="/optimizeip/opipform/edit?id=' + row.id + '" class="btn btn-primary btn-xs">修改</a>&nbsp;&nbsp;';
html += '<a href="/record/' + row.did + '?keyword=' + row.rr + '" class="btn btn-default btn-xs" target="_blank">解析</a>&nbsp;&nbsp;';
html += '<a href="javascript:delItem(\'' + row.id + '\')" class="btn btn-danger btn-xs">删除</a>&nbsp;&nbsp;';
return html;
}
},
],
onLoadSuccess: function (data) {
$('[data-toggle="tooltip"]').tooltip()
}
})
})
function setActive(id, active) {
$.post('/optimizeip/opipform/setactive', {id: id, active: active}, function (data) {
if (data.code == 0) {
layer.msg('修改成功', {icon: 1, time: 800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
}
function delItem(id) {
layer.confirm('确定要删除此任务吗?', {
btn: ['确定', '取消']
}, function () {
$.post('/optimizeip/opipform/del', {id: id}, function (data) {
if (data.code == 0) {
layer.msg('删除成功', {icon: 1, time: 800});
$('#listTable').bootstrapTable('refresh');
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
function runTask(id) {
var ii = layer.msg('正在更新中...', {icon: 16, shade: 0.1, time: 0});
$.post('/optimizeip/opipform/run', {id: id}, function (data) {
layer.close(ii);
if (data.code == 0) {
layer.alert(data.msg, {icon: 1});
$('#listTable').bootstrapTable('refresh');
} else {
layer.alert(data.msg, {icon: 2});
}
}, 'json');
}
</script>
{/block}

207
app/view/optimizeip/opipset.html Normal file → Executable file
View File

@ -2,105 +2,120 @@
{block name="title"}CF优选IP设置{/block}
{block name="main"}
<div class="row">
<div class="col-xs-12 col-md-6">
<div class="panel panel-success">
<div class="panel-heading"><h3 class="panel-title">功能简介</h3></div>
<div class="panel-body">
<p>由于CloudFlare官方IP是泛播路由同一个IP在不同地区不同运营商所链接的机房是不同的速度或延迟也会有区别。目前网上也有很多CF优选CNAME服务然而公共的CNAME可能无法满足稳定性和安全性的需要。</p>
<p>本功能可以获取CloudFlare最新的优选IP地址分为电信/联通/移动线路),并自动更新到域名解析记录。</p>
</div>
</div>
<div class="panel panel-warning">
<div class="panel-heading"><h3 class="panel-title">使用说明</h3></div>
<div class="panel-body">
<p><li>不支持对CloudFlare里的域名添加优选必须使用其他DNS服务商。需开通Cloudflare for SaaS且域名使用CNAME的方式解析到CloudFlare。</li></p>
<p><li>数据接口:<a href="https://www.wetest.vip/" target="_blank" rel="noreferrer">wetest.vip</a> 数据接口支持CloudFlare、CloudFront、Gcore<a href="https://stock.hostmonit.com/" target="_blank" rel="noreferrer">HostMonit</a> 只支持CloudFlare。</li></p>
<p><li>接口密钥默认o1zrmHAF为免费KEY可永久免费使用。</li></p>
<p><li>计划任务将以下命令添加到计划任务周期设置为15分钟以上</li></p>
<p><code>cd {:app()->getRootPath()} && php think opiptask</code></p>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6">
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">数据接口设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">数据接口</label>
<div class="col-sm-9"><select class="form-control" name="optimize_ip_api" default="{:config_get('optimize_ip_api')}"><option value="0">wetest.vip</option><option value="1">HostMonit</option></select></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">接口密钥</label>
<div class="col-sm-9"><input type="text" name="optimize_ip_key" value="{:config_get('optimize_ip_key', 'o1zrmHAF')}" class="form-control"/></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
<a href="javascript:queryapi()" class="btn btn-default btn-block">查询积分</a>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6">
<div class="panel panel-success">
<div class="panel-heading font-bold"><h3 class="panel-title">功能简介</h3></div>
<div class="panel-body">
<p>由于CloudFlare官方IP是泛播路由同一个IP在不同地区不同运营商所链接的机房是不同的速度或延迟也会有区别。目前网上也有很多CF优选CNAME服务然而公共的CNAME可能无法满足稳定性和安全性的需要。</p>
<p>本功能可以获取CloudFlare最新的优选IP地址分为电信/联通/移动线路),并自动更新到域名解析记录。</p>
</div>
</div>
<div class="panel panel-warning">
<div class="panel-heading font-bold"><h3 class="panel-title">使用说明</h3></div>
<div class="panel-body">
<p>
不支持对CloudFlare里的域名添加优选必须使用其他DNS服务商。需开通Cloudflare for SaaS且域名使用CNAME的方式解析到CloudFlare。
</p>
<p>
数据接口:<a href="https://www.wetest.vip/" rel="noreferrer" target="_blank">wetest.vip</a>数据接口支持CloudFlare、CloudFront、Gcore<a href="https://stock.hostmonit.com/" rel="noreferrer" target="_blank">HostMonit</a> 只支持CloudFlare。
</p>
<p>
接口密钥默认o1zrmHAF为免费KEY可永久免费使用。
</p>
<p>
计划任务将以下命令添加到计划任务周期设置为15分钟以上
</p>
<p><code>cd {:app()->getRootPath()} && php think opiptask</code></p>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6">
<div class="panel panel-info">
<div class="panel-heading font-bold"><h3 class="panel-title">数据接口设置</h3></div>
<div class="panel-body">
<form class="form-horizontal" method="post" onsubmit="return saveSetting(this)" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">数据接口</label>
<div class="col-sm-9">
<select class="form-control" default="{:config_get('optimize_ip_api')}" name="optimize_ip_api">
<option value="0">wetest.vip</option>
<option value="1">HostMonit</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">接口密钥</label>
<div class="col-sm-9">
<input class="form-control" name="optimize_ip_key" type="text" value="{:config_get('optimize_ip_key', 'o1zrmHAF')}"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input class="btn btn-primary btn-block" name="submit" type="submit" value="保存"/>
<a class="btn btn-default btn-block" href="javascript:queryapi()">查询积分</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script>
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default")||0);
}
function saveSetting(obj){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '',
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;
}
function queryapi(){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '/optimizeip/queryapi',
data : $("form").serialize(),
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1});
}else{
layer.alert(data.msg, {icon: 2})
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default") || 0);
}
function saveSetting(obj) {
var ii = layer.load(2, {shade: [0.1, '#fff']});
$.ajax({
type: 'POST',
url: '',
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;
}
function queryapi() {
var ii = layer.load(2, {shade: [0.1, '#fff']});
$.ajax({
type: 'POST',
url: '/optimizeip/queryapi',
data: $("form").serialize(),
dataType: 'json',
success: function (data) {
layer.close(ii);
if (data.code == 0) {
layer.alert(data.msg, {icon: 1});
} else {
layer.alert(data.msg, {icon: 2})
}
},
error: function (data) {
layer.close(ii);
layer.msg('服务器错误');
}
});
}
</script>
{/block}

54
app/view/system/loginset.html Normal file → Executable file
View File

@ -2,38 +2,38 @@
{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-info">
<div class="panel-heading"><h3 class="panel-title">登录验证码设置</h3></div>
<div class="panel-body">
<div class="form-group">
<div class="form-group">
<label class="col-sm-3 control-label">开启图形验证码</label>
<div class="col-sm-9"><div class="material-switch"><input id="vocde_switch" type="checkbox" {if config_get('vcode', '1')=='1'}checked{/if} onchange="setvcode()"><label for="vocde_switch" class="label-primary"></label></div></div>
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">登录验证码设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveAccount(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">开启图形验证码</label>
<div class="col-sm-9" style="margin-top:6.5px"><div class="material-switch"><input id="vocde_switch" type="checkbox" {if config_get('vcode', '1')=='1'}checked{/if} onchange="setvcode()"><label for="vocde_switch" class="label-primary"></label></div></div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script>
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default")||0);
}
function setvcode(){
var status = $("#vocde_switch").is(':checked') ? '1' : '2';
$.post('/system/set', {vcode: status}, function(res){
if(res.code == 0){
layer.msg(status == '1' ? '图形验证码已开启' : '图形验证码已关闭', {icon: 1, time: 1000});
}else{
layer.alert(res.msg, {icon: 2});
$("#vocde_switch").prop('checked', !status);
}
});
}
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default") || 0);
}
function setvcode() {
var status = $("#vocde_switch").is(':checked') ? '1' : '2';
$.post('/system/set', {vcode: status}, function (res) {
if (res.code == 0) {
layer.msg(status == '1' ? '图形验证码已开启' : '图形验证码已关闭', {icon: 1, time: 1000});
} else {
layer.alert(res.msg, {icon: 2});
$("#vocde_switch").prop('checked', !status);
}
});
}
</script>
{/block}

494
app/view/system/noticeset.html Normal file → Executable file
View File

@ -2,251 +2,273 @@
{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-info">
<div class="panel-heading"><h3 class="panel-title">发信邮箱设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">发信模式</label>
<div class="col-sm-9"><select class="form-control" name="mail_type" default="{:config_get('mail_type')}"><option value="0">SMTP发信</option><option value="1">搜狐Sendcloud</option><option value="2">阿里云邮件推送</option></select></div>
<div class="col-xs-12 col-md-6">
<div class="panel panel-info">
<div class="panel-heading font-bold"><h3 class="panel-title">发信邮箱设置</h3></div>
<div class="panel-body">
<form class="form-horizontal" method="post" onsubmit="return saveSetting(this)" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">发信模式</label>
<div class="col-sm-9">
<select class="form-control" default="{:config_get('mail_type')}" name="mail_type">
<option value="0">SMTP发信</option>
<option value="1">搜狐Sendcloud</option>
<option value="2">阿里云邮件推送</option>
</select>
</div>
</div>
<div id="frame_set1">
<div class="form-group">
<label class="col-sm-3 control-label">SMTP服务器</label>
<div class="col-sm-9">
<input class="form-control" name="mail_smtp" type="text" value="{:config_get('mail_smtp')}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">SMTP端口</label>
<div class="col-sm-9">
<input class="form-control" name="mail_port" type="text" value="{:config_get('mail_port')}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">邮箱账号</label>
<div class="col-sm-9">
<input class="form-control" name="mail_name" type="text" value="{:config_get('mail_name')}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">邮箱密码</label>
<div class="col-sm-9">
<input class="form-control" name="mail_pwd" type="text" value="{:config_get('mail_pwd')}"/>
</div>
</div>
</div>
<div id="frame_set2">
<div class="form-group">
<label class="col-sm-3 control-label">API_USER</label>
<div class="col-sm-9">
<input class="form-control" name="mail_apiuser" type="text" value="{:config_get('mail_apiuser')}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">API_KEY</label>
<div class="col-sm-9">
<input class="form-control" name="mail_apikey" type="text" value="{:config_get('mail_apikey')}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">发信邮箱</label>
<div class="col-sm-9">
<input class="form-control" name="mail_name2" type="text" value="{:config_get('mail_name')}"/>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">收信邮箱</label>
<div class="col-sm-9">
<input class="form-control" name="mail_recv" placeholder="不填默认为发信邮箱" type="text" value="{:config_get('mail_recv')}"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input class="btn btn-primary btn-block" name="submit" type="submit" value="保存"/>
<a class="btn btn-default btn-block" href="javascript:mailtest()">发送测试邮件</a>
</div>
</div>
</form>
</div>
<div class="panel-footer">
<span class="glyphicon glyphicon-info-sign"></span>
使用普通模式发信时建议使用QQ邮箱SMTP服务器smtp.qq.com端口465或587密码是QQ邮箱设置界面生成的<a href="https://service.mail.qq.com/detail/0/75" rel="noreferrer" target="_blank">授权码</a><br/>阿里云邮件推送:<a href="https://www.aliyun.com/product/directmail" rel="noreferrer" target="_blank">点此进入</a><a href="https://usercenter.console.aliyun.com/#/manage/ak" rel="noreferrer" target="_blank">获取AK/SK</a>
</div>
</div>
</div>
<div id="frame_set1">
<div class="form-group">
<label class="col-sm-3 control-label">SMTP服务器</label>
<div class="col-sm-9"><input type="text" name="mail_smtp" value="{:config_get('mail_smtp')}" class="form-control"/></div>
<div class="col-xs-12 col-md-6">
<div class="panel panel-info">
<div class="panel-heading font-bold"><h3 class="panel-title">微信公众号消息接口设置</h3></div>
<div class="panel-body">
<form class="form-horizontal" method="post" onsubmit="return saveSetting(this)" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">appToken</label>
<div class="col-sm-9">
<input class="form-control" name="wechat_apptoken" type="text" value="{:config_get('wechat_apptoken')}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">用户UID</label>
<div class="col-sm-9">
<input class="form-control" name="wechat_appuid" type="text" value="{:config_get('wechat_appuid')}"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9"><input class="btn btn-primary btn-block" name="submit" type="submit" value="保存"/></div>
</div>
</form>
</div>
<div class="panel-footer">
<b>WxPusher</b><a href="https://wxpusher.zjiecode.com/admin/" rel="noopener noreferrer" target="_blank">点此进入</a> ,注册并且创建应用 -> 将appToken填写到上方输入框 -> 扫码关注应用 -> 在用户列表查看自己的UID填写到上方输入框<br/>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading font-bold"><h3 class="panel-title">Telegram机器人接口设置</h3></div>
<div class="panel-body">
<form class="form-horizontal" method="post" onsubmit="return saveSetting(this)" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">Token</label>
<div class="col-sm-9">
<input class="form-control" name="tgbot_token" type="text" value="{:config_get('tgbot_token')}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Chat Id</label>
<div class="col-sm-9">
<input class="form-control" name="tgbot_chatid" type="text" value="{:config_get('tgbot_chatid')}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">使用代理服务器</label>
<div class="col-sm-9">
<select class="form-control" default="{:config_get('tgbot_proxy')}" name="tgbot_proxy">
<option value="0"></option>
<option value="1"></option>
<option value="2">自定义反代URL</option>
</select>
</div>
</div>
<div class="form-group" id="tgbot_url_div" style="display:none;">
<label class="col-sm-3 control-label">自定义反代URL</label>
<div class="col-sm-9">
<input type="text" name="tgbot_url" value="{:config_get('tgbot_url')}" class="form-control" placeholder="默认为https://api.telegram.org"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input class="btn btn-primary btn-block" name="submit" type="submit" value="保存"/>
<a class="btn btn-default btn-block" href="javascript:tgbottest()">发送测试消息</a>
</div>
</div>
</form>
</div>
<div class="panel-footer">
<a href="https://t.me/BotFather" rel="noopener noreferrer" target="_blank">@BotFather</a>对话,使用/newbot命令创建一个新的机器人根据提示输入机器人的名称和用户名可得到Token或使用/mybots命令查看已创建的机器人<a href="https://t.me/getmyid_bot" rel="noopener noreferrer" target="_blank">@getmyid_bot</a>对话可得到Chat Id<br/>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">群机器人Webhook</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">Webhook地址</label>
<div class="col-sm-9"><input type="text" name="webhook_url" value="{:config_get('webhook_url')}" class="form-control"/></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
<a href="javascript:webhooktest()" class="btn btn-default btn-block">发送测试消息</a>
</div>
</div>
</form>
</div>
<div class="panel-footer">
仅支持填写企业微信、钉钉、飞书群机器人的Webhook地址
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">SMTP端口</label>
<div class="col-sm-9"><input type="text" name="mail_port" value="{:config_get('mail_port')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">邮箱账号</label>
<div class="col-sm-9"><input type="text" name="mail_name" value="{:config_get('mail_name')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">邮箱密码</label>
<div class="col-sm-9"><input type="text" name="mail_pwd" value="{:config_get('mail_pwd')}" class="form-control"/></div>
</div>
</div>
<div id="frame_set2">
<div class="form-group">
<label class="col-sm-3 control-label">API_USER</label>
<div class="col-sm-9"><input type="text" name="mail_apiuser" value="{:config_get('mail_apiuser')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">API_KEY</label>
<div class="col-sm-9"><input type="text" name="mail_apikey" value="{:config_get('mail_apikey')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">发信邮箱</label>
<div class="col-sm-9"><input type="text" name="mail_name2" value="{:config_get('mail_name')}" class="form-control"/></div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">收信邮箱</label>
<div class="col-sm-9"><input type="text" name="mail_recv" value="{:config_get('mail_recv')}" class="form-control" placeholder="不填默认为发信邮箱"/></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
<a href="javascript:mailtest()" class="btn btn-default btn-block">发送测试邮件</a>
</div>
</div>
</form>
</div>
<div class="panel-footer">
<span class="glyphicon glyphicon-info-sign"></span>
使用普通模式发信时建议使用QQ邮箱SMTP服务器smtp.qq.com端口465或587密码是QQ邮箱设置界面生成的<a href="https://service.mail.qq.com/detail/0/75" target="_blank" rel="noreferrer">授权码</a><br/>阿里云邮件推送:<a href="https://www.aliyun.com/product/directmail" target="_blank" rel="noreferrer">点此进入</a><a href="https://usercenter.console.aliyun.com/#/manage/ak" target="_blank" rel="noreferrer">获取AK/SK</a>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">微信公众号消息接口设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">appToken</label>
<div class="col-sm-9"><input type="text" name="wechat_apptoken" value="{:config_get('wechat_apptoken')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">用户UID</label>
<div class="col-sm-9"><input type="text" name="wechat_appuid" value="{:config_get('wechat_appuid')}" class="form-control"/></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9"><input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/></div>
</div>
</form>
</div>
<div class="panel-footer">
<b>WxPusher</b><a href="https://wxpusher.zjiecode.com/admin/" target="_blank" rel="noopener noreferrer">点此进入</a> ,注册并且创建应用 -> 将appToken填写到上方输入框 -> 扫码关注应用 -> 在用户列表查看自己的UID填写到上方输入框<br/>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">Telegram机器人接口设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">Token</label>
<div class="col-sm-9"><input type="text" name="tgbot_token" value="{:config_get('tgbot_token')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Chat Id</label>
<div class="col-sm-9"><input type="text" name="tgbot_chatid" value="{:config_get('tgbot_chatid')}" class="form-control"/></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">使用代理服务器</label>
<div class="col-sm-9"><select class="form-control" name="tgbot_proxy" default="{:config_get('tgbot_proxy')}"><option value="0"></option><option value="1"></option><option value="2">自定义反代URL</option></select></div>
</div>
<div class="form-group" id="tgbot_url_div" style="display:none;">
<label class="col-sm-3 control-label">自定义反代URL</label>
<div class="col-sm-9"><input type="text" name="tgbot_url" value="{:config_get('tgbot_url')}" class="form-control" placeholder="默认为https://api.telegram.org"/></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
<a href="javascript:tgbottest()" class="btn btn-default btn-block">发送测试消息</a>
</div>
</div>
</form>
</div>
<div class="panel-footer">
<a href="https://t.me/BotFather" target="_blank" rel="noopener noreferrer">@BotFather</a>对话,使用/newbot命令创建一个新的机器人根据提示输入机器人的名称和用户名可得到Token或使用/mybots命令查看已创建的机器人<a href="https://t.me/getmyid_bot" target="_blank" rel="noopener noreferrer">@getmyid_bot</a>对话可得到Chat Id<br/>
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">群机器人Webhook</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">Webhook地址</label>
<div class="col-sm-9"><input type="text" name="webhook_url" value="{:config_get('webhook_url')}" class="form-control"/></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/>
<a href="javascript:webhooktest()" class="btn btn-default btn-block">发送测试消息</a>
</div>
</div>
</form>
</div>
<div class="panel-footer">
仅支持填写企业微信、钉钉、飞书群机器人的Webhook地址
</div>
</div>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script>
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default")||0);
}
$("select[name='mail_type']").change(function(){
if($(this).val() == 0){
$("#frame_set1").show();
$("#frame_set2").hide();
}else{
$("#frame_set1").hide();
$("#frame_set2").show();
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default") || 0);
}
});
$("select[name='tgbot_proxy']").change(function(){
if($(this).val() == 2){
$("#tgbot_url_div").show();
}else{
$("#tgbot_url_div").hide();
$("select[name='mail_type']").change(function () {
if ($(this).val() == 0) {
$("#frame_set1").show();
$("#frame_set2").hide();
} else {
$("#frame_set1").hide();
$("#frame_set2").show();
}
});
$("select[name='tgbot_proxy']").change(function(){
if($(this).val() == 2){
$("#tgbot_url_div").show();
}else{
$("#tgbot_url_div").hide();
}
});
$("select[name='mail_type']").change();
$("select[name='tgbot_proxy']").change();
function saveSetting(obj) {
var ii = layer.load(2, {shade: [0.1, '#fff']});
$.ajax({
type: 'POST',
url : '/system/set',
data: $(obj).serialize(),
dataType: 'json',
success: function (data) {
layer.close(ii);
if (data.code == 0) {
layer.alert('设置保存成功!<br/>重启检测进程或容器后生效', {
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;
}
});
$("select[name='mail_type']").change();
$("select[name='tgbot_proxy']").change();
function saveSetting(obj){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '/system/set',
data : $(obj).serialize(),
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert('设置保存成功!<br/>如有使用容灾切换,重启检测进程后生效', {
icon: 1,
closeBtn: false
}, function(){
window.location.reload()
});
}else{
layer.alert(data.msg, {icon: 2})
function mailtest() {
var ii = layer.load(2, {shade: [0.1, '#fff']});
$.ajax({
type: 'GET',
url: '/system/mailtest',
dataType: 'json',
success: function (data) {
layer.close(ii);
if (data.code == 0) {
layer.alert(data.msg, {icon: 1});
} else {
layer.alert(data.msg, {icon: 2})
}
},
error: function (data) {
layer.close(ii);
layer.msg('服务器错误');
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
return false;
}
function mailtest(){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'GET',
url : '/system/mailtest',
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1});
}else{
layer.alert(data.msg, {icon: 2})
});
}
function tgbottest() {
var ii = layer.load(2, {shade: [0.1, '#fff']});
$.ajax({
type: 'GET',
url: '/system/tgbottest',
dataType: 'json',
success: function (data) {
layer.close(ii);
if (data.code == 0) {
layer.alert(data.msg, {icon: 1});
} else {
layer.alert(data.msg, {icon: 2})
}
},
error: function (data) {
layer.close(ii);
layer.msg('服务器错误');
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
function tgbottest(){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'GET',
url : '/system/tgbottest',
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1});
}else{
layer.alert(data.msg, {icon: 2})
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
function webhooktest(){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'GET',
url : '/system/webhooktest',
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1});
}else{
layer.alert(data.msg, {icon: 2})
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
});
}
</script>
{/block}

214
app/view/system/proxyset.html Normal file → Executable file
View File

@ -2,113 +2,129 @@
{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-info">
<div class="panel-heading"><h3 class="panel-title">代理服务器设置</h3></div>
<div class="panel-body">
<form onsubmit="return saveSetting(this)" method="post" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">代理IP</label>
<div class="col-sm-9"><input type="text" name="proxy_server" value="{:config_get('proxy_server')}" class="form-control"/></div>
</div><br/>
<div class="form-group">
<label class="col-sm-3 control-label">代理端口</label>
<div class="col-sm-9"><input type="text" name="proxy_port" value="{:config_get('proxy_port')}" class="form-control"/></div>
</div><br/>
<div class="form-group">
<label class="col-sm-3 control-label">代理账号</label>
<div class="col-sm-9"><input type="text" name="proxy_user" value="{:config_get('proxy_user')}" class="form-control" placeholder="没有请留空"/></div>
</div><br/>
<div class="form-group">
<label class="col-sm-3 control-label">代理密码</label>
<div class="col-sm-9"><input type="text" name="proxy_pwd" value="{:config_get('proxy_pwd')}" class="form-control" placeholder="没有请留空"/></div>
</div><br/>
<div class="form-group">
<label class="col-sm-3 control-label">代理协议</label>
<div class="col-sm-9"><select class="form-control" name="proxy_type" default="{:config_get('proxy_type')}">
<option value="http">HTTP</option>
<option value="https">HTTPS</option>
<option value="sock4">SOCK4</option>
<option value="sock5">SOCK5</option>
<option value="sock5h">SOCK5H</option>
</select></div>
</div><br/>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9"><input type="submit" name="submit" value="保存" class="btn btn-primary btn-block"/><br/>
<a href="javascript:proxytest()" class="btn btn-default btn-block">测试连通性</a></div>
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
<div class="panel panel-info">
<div class="panel-heading font-bold"><h3 class="panel-title">代理服务器设置</h3></div>
<div class="panel-body">
<form class="form-horizontal" method="post" onsubmit="return saveSetting(this)" role="form">
<div class="form-group">
<label class="col-sm-3 control-label">代理IP</label>
<div class="col-sm-9">
<input class="form-control" name="proxy_server" type="text" value="{:config_get('proxy_server')}"/>
</div>
</div>
<br/>
<div class="form-group">
<label class="col-sm-3 control-label">代理端口</label>
<div class="col-sm-9">
<input class="form-control" name="proxy_port" type="text" value="{:config_get('proxy_port')}"/>
</div>
</div>
<br/>
<div class="form-group">
<label class="col-sm-3 control-label">代理账号</label>
<div class="col-sm-9">
<input class="form-control" name="proxy_user" placeholder="没有请留空" type="text" value="{:config_get('proxy_user')}"/>
</div>
</div>
<br/>
<div class="form-group">
<label class="col-sm-3 control-label">代理密码</label>
<div class="col-sm-9">
<input class="form-control" name="proxy_pwd" placeholder="没有请留空" type="text" value="{:config_get('proxy_pwd')}"/>
</div>
</div>
<br/>
<div class="form-group">
<label class="col-sm-3 control-label">代理协议</label>
<div class="col-sm-9">
<select class="form-control" default="{:config_get('proxy_type')}" name="proxy_type">
<option value="http">HTTP</option>
<option value="https">HTTPS</option>
<option value="sock4">SOCK4</option>
<option value="sock5">SOCK5</option>
<option value="sock5h">SOCK5H</option>
</select>
</div>
</div>
<br/>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9"><input class="btn btn-primary btn-block" name="submit" type="submit" value="保存"/><br/>
<a href="javascript:proxytest()" class="btn btn-default btn-block">测试连通性</a>
</div>
</div>
</form>
</div>
<div class="panel-footer">
为保证代理稳定性建议在本机安装Xray入站代理使用普通http协议仅监听本地IP出站代理使用加密协议连接其他服务器。
</div>
</div>
</div>
</form>
</div>
<div class="panel-footer">
为保证代理稳定性建议在本机安装Xray入站代理使用普通http协议仅监听本地IP出站代理使用加密协议连接其他服务器。
</div>
</div>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script>
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default")||0);
}
function saveSetting(obj){
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '/system/set',
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})
var items = $("select[default]");
for (i = 0; i < items.length; i++) {
$(items[i]).val($(items[i]).attr("default") || 0);
}
function saveSetting(obj) {
var ii = layer.load(2, {shade: [0.1, '#fff']});
$.ajax({
type: 'POST',
url : '/system/set',
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('服务器错误');
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
return false;
}
function proxytest(){
var proxy_server = $("input[name='proxy_server']").val();
var proxy_port = $("input[name='proxy_port']").val();
var proxy_user = $("input[name='proxy_user']").val();
var proxy_pwd = $("input[name='proxy_pwd']").val();
var proxy_type = $("select[name='proxy_type']").val();
if(proxy_server=='' || proxy_port==''){
layer.alert('代理服务器和端口不能为空!');
});
return false;
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '/system/proxytest',
data : {proxy_server:proxy_server, proxy_port:proxy_port, proxy_user:proxy_user, proxy_pwd:proxy_pwd, proxy_type:proxy_type},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert('连通性测试成功!', {icon: 1})
}else{
layer.alert('连通性测试失败:'+data.msg, {icon: 2})
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
function proxytest(){
var proxy_server = $("input[name='proxy_server']").val();
var proxy_port = $("input[name='proxy_port']").val();
var proxy_user = $("input[name='proxy_user']").val();
var proxy_pwd = $("input[name='proxy_pwd']").val();
var proxy_type = $("select[name='proxy_type']").val();
if(proxy_server=='' || proxy_port==''){
layer.alert('代理服务器和端口不能为空!');
return false;
}
});
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '/system/proxytest',
data : {proxy_server:proxy_server, proxy_port:proxy_port, proxy_user:proxy_user, proxy_pwd:proxy_pwd, proxy_type:proxy_type},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert('连通性测试成功!', {icon: 1})
}else{
layer.alert('连通性测试失败:'+data.msg, {icon: 2})
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
</script>
{/block}

125
app/view/user/log.html Normal file → Executable file
View File

@ -1,77 +1,76 @@
{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>
<style>
#orderItem .orderTitle{word-break:keep-all;}
#orderItem .orderContent{word-break:break-all;}
.fixed-table-toolbar,.fixed-table-pagination{padding: 15px;}
</style>
<div class="panel panel-default">
<div class="panel-heading font-bold">
<h3 class="panel-title">操作日志</h3>
</div>
</div>
</div>
<form class="form-inline" id="searchToolbar" method="GET" onsubmit="return searchSubmit()">
<div class="form-group">
{if request()->user['level'] eq 2}
<input class="form-control" name="uid" placeholder="UID" type="text">
{/if}
<input class="form-control" name="domain" placeholder="域名" type="text">
<input class="form-control" name="kw" placeholder="操作类型/操作详情" type="text">
</div>
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
<a class="btn btn-default" href="javascript:searchClear()" title="刷新日志列表"><i class="fa fa-refresh"></i> 刷新</a>
</form>
<table id="listTable">
</table>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/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;
$(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: '时间'
}
],
})
})
$("#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}

655
app/view/user/user.html Normal file → Executable file
View File

@ -1,338 +1,351 @@
{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">&times;</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 aria-hidden="true" aria-labelledby="myModalLabel" class="modal" data-backdrop="static" id="modal-store" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button class="close" data-dismiss="modal" type="button"><span aria-hidden="true">&times;</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 name="action" type="hidden"/>
<input name="id" type="hidden"/>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">用户名</label>
<div class="col-sm-9">
<input class="form-control" name="username" required type="text">
</div>
</div>
<div class="form-group" id="password_input" style="display:none">
<label class="col-sm-3 control-label no-padding-right">密码</label>
<div class="col-sm-9">
<div class="input-group">
<input autocomplete="off" class="form-control" name="password" type="text">
<a class="input-group-addon" href="javascript:" id="create_password">随机生成</a>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">API接口</label>
<div class="col-sm-9">
<select class="form-control" name="is_api">
<option value="0">关闭</option>
<option value="1">开启</option>
</select>
</div>
</div>
<div class="form-group" id="apikey_input" style="display:none">
<label class="col-sm-3 control-label no-padding-right">API接口密钥</label>
<div class="col-sm-9">
<div class="input-group">
<input autocomplete="off" class="form-control" name="apikey" readonly type="text">
<a class="input-group-addon" href="javascript:" id="create_apikey">生成密钥</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 class="form-control" name="level">
<option value="1">普通用户</option>
<option value="2">管理员</option>
</select>
<a class="input-group-addon" data-content="普通用户只能管理指定的域名解析,管理员拥有和你相同的权限" data-original-title="用户权限说明" data-placement="bottom" data-toggle="popover" data-trigger="focus" role="button" tabindex="0" title=""><span class="glyphicon glyphicon-info-sign"></span></a>
</div>
</div>
</div>
<div class="form-group" id="permission_input" style="display:none">
<label class="col-sm-3 control-label">域名权限</label>
<div class="col-sm-9">
<select class="form-control select2" id="permission" multiple="multiple" name="permission[]" placeholder="留空">
{foreach $domains as $v}
<option value="{$v}">{$v}</option>
{/foreach}
</select>
</div>
</div>
<div class="form-group" id="repwd_input" style="display:none">
<label class="col-sm-3 control-label no-padding-right">重置密码</label>
<div class="col-sm-9">
<input autocomplete="off" class="form-control" name="repwd" placeholder="不重置密码请留空" type="text">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-white" data-dismiss="modal" type="button">关闭</button>
<button class="btn btn-primary" id="store" onclick="save()" type="button">保存</button>
</div>
</div>
</div>
</div>
</div>
<style>
#orderItem .orderTitle{word-break:keep-all;}
#orderItem .orderContent{word-break:break-all;}
.fixed-table-toolbar,.fixed-table-pagination{padding: 15px;}
</style>
<div class="panel panel-default">
<div class="panel-heading font-bold">
<h3 class="panel-title">用户管理</h3>
</div>
<form class="form-inline" id="searchToolbar" method="GET" onsubmit="return searchSubmit()">
<div class="form-group">
<input class="form-control" name="kw" placeholder="UID或用户名" type="text">
</div>
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
<a class="btn btn-default" href="javascript:searchClear()" title="刷新用户列表"><i class="fa fa-refresh"></i> 刷新</a>
<a class="btn btn-success" href="javascript:addframe()"><i class="fa fa-plus"></i> 添加</a>
</form>
<table id="listTable">
</table>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/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;
$(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: 'action',
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');
searchRefresh();
});
}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){
searchRefresh();
}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();
searchRefresh();
}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()
})
$("#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: 'action',
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');
searchRefresh();
});
} 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) {
searchRefresh();
} 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();
searchRefresh();
} 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}

BIN
public/.DS_Store vendored Normal file

Binary file not shown.

BIN
public/static/.DS_Store vendored Normal file

Binary file not shown.

BIN
public/static/css/.DS_Store vendored Normal file

Binary file not shown.

6
public/static/css/animate.min.css vendored Executable file

File diff suppressed because one or more lines are too long

5177
public/static/css/app.css Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

18
public/static/css/font.css Executable file
View File

@ -0,0 +1,18 @@
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 300;
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url('../fonts/sourcesanspro/sourcesanspro-light.woff') format('woff');
}
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url('../fonts/sourcesanspro/sourcesanspro.woff') format('woff');
}
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url('../fonts/sourcesanspro/sourcesanspro-bold.woff') format('woff');
}

View File

@ -1,242 +0,0 @@
/*
* 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 */

View File

@ -1,242 +0,0 @@
/*
* 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 */

View File

@ -1,192 +0,0 @@
/*
* 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 */

View File

@ -1,242 +0,0 @@
/*
* 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 */

View File

@ -1,242 +0,0 @@
/*
* 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 */

View File

@ -1,242 +0,0 @@
/*
* 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 */

View File

@ -1,242 +0,0 @@
/*
* 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 */

View File

@ -1,219 +0,0 @@
/*
* 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 */

View File

@ -1,184 +0,0 @@
/*
* 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 */

View File

@ -1,230 +0,0 @@
/*
* 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 */

View File

@ -1,181 +0,0 @@
/*
* 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 */

View File

@ -1,175 +0,0 @@
/*
* 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 */

View File

@ -1,181 +0,0 @@
/*
* 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 */

View File

@ -1,220 +0,0 @@
/*
* 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 */

View File

@ -1,181 +0,0 @@
/*
* 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 */

View File

@ -1,175 +0,0 @@
/*
* 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 */

View File

@ -1,181 +0,0 @@
/*
* 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 */

View File

@ -1,175 +0,0 @@
/*
* 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 */

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/static/images/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
public/static/js/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -1,738 +0,0 @@
/*! AdminLTE app.js
* ================
* Main JS application file for AdminLTE v2. This file
* should be included in all pages. It controls some layout
* options and implements exclusive AdminLTE plugins.
*
* @author Colorlib
* @support <https://github.com/ColorlibHQ/AdminLTE/issues>
* @version v2.4.18
* @repository git://github.com/ColorlibHQ/AdminLTE.git
* @license MIT <http://opensource.org/licenses/MIT>
*/
// Make sure jQuery has been loaded
if (typeof jQuery === 'undefined') {
throw new Error('AdminLTE requires jQuery')
}
/* ControlSidebar()
* ===============
* Toggles the state of the control sidebar
*
* @Usage: $('#control-sidebar-trigger').controlSidebar(options)
* or add [data-toggle="control-sidebar"] to the trigger
* Pass any option as data-option="value"
*/
+function ($) {
'use strict';
var DataKey = 'lte.controlsidebar';
var Default = {
controlsidebarSlide: true
};
var Selector = {
sidebar: '.control-sidebar',
data : '[data-toggle="control-sidebar"]',
open : '.control-sidebar-open',
bg : '.control-sidebar-bg',
wrapper: '.wrapper',
content: '.content-wrapper',
boxed : '.layout-boxed'
};
var ClassName = {
open: 'control-sidebar-open',
transition: 'control-sidebar-hold-transition',
fixed: 'fixed'
};
var Event = {
collapsed: 'collapsed.controlsidebar',
expanded : 'expanded.controlsidebar'
};
// ControlSidebar Class Definition
// ===============================
var ControlSidebar = function (element, options) {
this.element = element;
this.options = options;
this.hasBindedResize = false;
this.init();
};
ControlSidebar.prototype.init = function () {
// Add click listener if the element hasn't been
// initialized using the data API
if (!$(this.element).is(Selector.data)) {
$(this).on('click', this.toggle);
}
this.fix();
$(window).resize(function () {
this.fix();
}.bind(this));
};
ControlSidebar.prototype.toggle = function (event) {
if (event) event.preventDefault();
this.fix();
if (!$(Selector.sidebar).is(Selector.open) && !$('body').is(Selector.open)) {
this.expand();
} else {
this.collapse();
}
};
ControlSidebar.prototype.expand = function () {
$(Selector.sidebar).show();
if (!this.options.controlsidebarSlide) {
$('body').addClass(ClassName.transition).addClass(ClassName.open).delay(50).queue(function(){
$('body').removeClass(ClassName.transition);
$(this).dequeue()
})
} else {
$(Selector.sidebar).addClass(ClassName.open);
}
$(this.element).trigger($.Event(Event.expanded));
};
ControlSidebar.prototype.collapse = function () {
if (!this.options.controlsidebarSlide) {
$('body').addClass(ClassName.transition).removeClass(ClassName.open).delay(50).queue(function(){
$('body').removeClass(ClassName.transition);
$(this).dequeue()
})
} else {
$(Selector.sidebar).removeClass(ClassName.open);
}
$(Selector.sidebar).fadeOut();
$(this.element).trigger($.Event(Event.collapsed));
};
ControlSidebar.prototype.fix = function () {
if ($('body').is(Selector.boxed)) {
this._fixForBoxed($(Selector.bg));
}
};
// Private
ControlSidebar.prototype._fixForBoxed = function (bg) {
bg.css({
position: 'absolute',
height : $(Selector.wrapper).height()
});
};
// Plugin Definition
// =================
function Plugin(option) {
return this.each(function () {
var $this = $(this);
var data = $this.data(DataKey);
if (!data) {
var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
$this.data(DataKey, (data = new ControlSidebar($this, options)));
}
if (typeof option == 'string') data.toggle();
});
}
var old = $.fn.controlSidebar;
$.fn.controlSidebar = Plugin;
$.fn.controlSidebar.Constructor = ControlSidebar;
// No Conflict Mode
// ================
$.fn.controlSidebar.noConflict = function () {
$.fn.controlSidebar = old;
return this;
};
// ControlSidebar Data API
// =======================
$(document).on('click', Selector.data, function (event) {
if (event) event.preventDefault();
Plugin.call($(this), 'toggle');
});
}(jQuery);
/* PushMenu()
* ==========
* Adds the push menu functionality to the sidebar.
*
* @usage: $('.btn').pushMenu(options)
* or add [data-toggle="push-menu"] to any button
* Pass any option as data-option="value"
*/
+function ($) {
'use strict';
var DataKey = 'lte.pushmenu';
var Default = {
collapseScreenSize : 767,
expandOnHover : false,
expandTransitionDelay: 200
};
var Selector = {
collapsed : '.sidebar-collapse',
open : '.sidebar-open',
mainSidebar : '.main-sidebar',
contentWrapper: '.content-wrapper',
searchInput : '.sidebar-form .form-control',
button : '[data-toggle="push-menu"]',
mini : '.sidebar-mini',
expanded : '.sidebar-expanded-on-hover',
layoutFixed : '.fixed'
};
var ClassName = {
collapsed : 'sidebar-collapse',
open : 'sidebar-open',
mini : 'sidebar-mini',
expanded : 'sidebar-expanded-on-hover',
expandFeature: 'sidebar-mini-expand-feature',
layoutFixed : 'fixed'
};
var Event = {
expanded : 'expanded.pushMenu',
collapsed: 'collapsed.pushMenu'
};
// PushMenu Class Definition
// =========================
var PushMenu = function (options) {
this.options = options;
this.init();
};
PushMenu.prototype.init = function () {
if (this.options.expandOnHover
|| ($('body').is(Selector.mini + Selector.layoutFixed))) {
this.expandOnHover();
$('body').addClass(ClassName.expandFeature);
}
$(Selector.contentWrapper).click(function () {
// Enable hide menu when clicking on the content-wrapper on small screens
if ($(window).width() <= this.options.collapseScreenSize && $('body').hasClass(ClassName.open)) {
this.close();
}
}.bind(this));
// __Fix for android devices
$(Selector.searchInput).click(function (e) {
e.stopPropagation();
});
};
PushMenu.prototype.toggle = function () {
var windowWidth = $(window).width();
var isOpen = !$('body').hasClass(ClassName.collapsed);
if (windowWidth <= this.options.collapseScreenSize) {
isOpen = $('body').hasClass(ClassName.open);
}
if (!isOpen) {
this.open();
} else {
this.close();
}
};
PushMenu.prototype.open = function () {
var windowWidth = $(window).width();
if (windowWidth > this.options.collapseScreenSize) {
$('body').removeClass(ClassName.collapsed)
.trigger($.Event(Event.expanded));
}
else {
$('body').addClass(ClassName.open)
.trigger($.Event(Event.expanded));
}
};
PushMenu.prototype.close = function () {
var windowWidth = $(window).width();
if (windowWidth > this.options.collapseScreenSize) {
$('body').addClass(ClassName.collapsed)
.trigger($.Event(Event.collapsed));
} else {
$('body').removeClass(ClassName.open + ' ' + ClassName.collapsed)
.trigger($.Event(Event.collapsed));
}
};
PushMenu.prototype.expandOnHover = function () {
$(Selector.mainSidebar).hover(function () {
if ($('body').is(Selector.mini + Selector.collapsed)
&& $(window).width() > this.options.collapseScreenSize) {
this.expand();
}
}.bind(this), function () {
if ($('body').is(Selector.expanded)) {
this.collapse();
}
}.bind(this));
};
PushMenu.prototype.expand = function () {
setTimeout(function () {
$('body').removeClass(ClassName.collapsed)
.addClass(ClassName.expanded);
}, this.options.expandTransitionDelay);
};
PushMenu.prototype.collapse = function () {
setTimeout(function () {
$('body').removeClass(ClassName.expanded)
.addClass(ClassName.collapsed);
}, this.options.expandTransitionDelay);
};
// PushMenu Plugin Definition
// ==========================
function Plugin(option) {
return this.each(function () {
var $this = $(this);
var data = $this.data(DataKey);
if (!data) {
var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
$this.data(DataKey, (data = new PushMenu(options)));
}
if (option === 'toggle') data.toggle();
});
}
var old = $.fn.pushMenu;
$.fn.pushMenu = Plugin;
$.fn.pushMenu.Constructor = PushMenu;
// No Conflict Mode
// ================
$.fn.pushMenu.noConflict = function () {
$.fn.pushMenu = old;
return this;
};
// Data API
// ========
$(document).on('click', Selector.button, function (e) {
e.preventDefault();
Plugin.call($(this), 'toggle');
});
$(window).on('load', function () {
Plugin.call($(Selector.button));
});
}(jQuery);
/* Tree()
* ======
* Converts a nested list into a multilevel
* tree view menu.
*
* @Usage: $('.my-menu').tree(options)
* or add [data-widget="tree"] to the ul element
* Pass any option as data-option="value"
*/
+function ($) {
'use strict';
var DataKey = 'lte.tree';
var Default = {
animationSpeed: 300,
accordion : true,
followLink : false,
trigger : '.treeview a'
};
var Selector = {
tree : '.tree',
treeview : '.treeview',
treeviewMenu: '.treeview-menu',
open : '.menu-open, .active',
li : 'li',
data : '[data-widget="tree"]',
active : '.active'
};
var ClassName = {
open: 'menu-open',
tree: 'tree'
};
var Event = {
collapsed: 'collapsed.tree',
expanded : 'expanded.tree'
};
// Tree Class Definition
// =====================
var Tree = function (element, options) {
this.element = element;
this.options = options;
$(this.element).addClass(ClassName.tree);
$(Selector.treeview + Selector.active, this.element).addClass(ClassName.open);
this._setUpListeners();
};
Tree.prototype.toggle = function (link, event) {
var treeviewMenu = link.next(Selector.treeviewMenu);
var parentLi = link.parent();
var isOpen = parentLi.hasClass(ClassName.open);
if (!parentLi.is(Selector.treeview)) {
return;
}
if (!this.options.followLink || link.attr('href') === '#') {
event.preventDefault();
}
if (isOpen) {
this.collapse(treeviewMenu, parentLi);
} else {
this.expand(treeviewMenu, parentLi);
}
};
Tree.prototype.expand = function (tree, parent) {
var expandedEvent = $.Event(Event.expanded);
if (this.options.accordion) {
var openMenuLi = parent.siblings(Selector.open);
var openTree = openMenuLi.children(Selector.treeviewMenu);
this.collapse(openTree, openMenuLi);
}
parent.addClass(ClassName.open);
tree.stop().slideDown(this.options.animationSpeed, function () {
$(this.element).trigger(expandedEvent);
parent.height('auto');
}.bind(this));
};
Tree.prototype.collapse = function (tree, parentLi) {
var collapsedEvent = $.Event(Event.collapsed);
//tree.find(Selector.open).removeClass(ClassName.open);
parentLi.removeClass(ClassName.open);
tree.stop().slideUp(this.options.animationSpeed, function () {
//tree.find(Selector.open + ' > ' + Selector.treeview).slideUp();
$(this.element).trigger(collapsedEvent);
// Collapse child items
parentLi.find(Selector.treeview).removeClass(ClassName.open).find(Selector.treeviewMenu).hide();
}.bind(this));
};
// Private
Tree.prototype._setUpListeners = function () {
var that = this;
$(this.element).on('click', this.options.trigger, function (event) {
that.toggle($(this), event);
});
};
// Plugin Definition
// =================
function Plugin(option) {
return this.each(function () {
var $this = $(this);
var data = $this.data(DataKey);
if (!data) {
var options = $.extend({}, Default, $this.data(), typeof option == 'object' && option);
$this.data(DataKey, new Tree($this, options));
}
});
}
var old = $.fn.tree;
$.fn.tree = Plugin;
$.fn.tree.Constructor = Tree;
// No Conflict Mode
// ================
$.fn.tree.noConflict = function () {
$.fn.tree = old;
return this;
};
// Tree Data API
// =============
$(window).on('load', function () {
$(Selector.data).each(function () {
Plugin.call($(this));
});
});
}(jQuery);
/* Layout()
* ========
* Implements AdminLTE layout.
* Fixes the layout height in case min-height fails.
*
* @usage activated automatically upon window load.
* Configure any options by passing data-option="value"
* to the body tag.
*/
+function ($) {
'use strict';
var DataKey = 'lte.layout';
var Default = {
slimscroll : true,
resetHeight: true
};
var Selector = {
wrapper : '.wrapper',
contentWrapper: '.content-wrapper',
layoutBoxed : '.layout-boxed',
mainFooter : '.main-footer',
mainHeader : '.main-header',
mainSidebar : '.main-sidebar',
slimScrollDiv : 'slimScrollDiv',
sidebar : '.sidebar',
controlSidebar: '.control-sidebar',
fixed : '.fixed',
sidebarMenu : '.sidebar-menu',
logo : '.main-header .logo'
};
var ClassName = {
fixed : 'fixed',
holdTransition: 'hold-transition'
};
var Layout = function (options) {
this.options = options;
this.bindedResize = false;
this.activate();
};
Layout.prototype.activate = function () {
this.fix();
this.fixSidebar();
$('body').removeClass(ClassName.holdTransition);
if (this.options.resetHeight) {
$('body, html, ' + Selector.wrapper).css({
'height' : 'auto',
'min-height': '100%'
});
}
if (!this.bindedResize) {
$(window).resize(function () {
this.fix();
this.fixSidebar();
$(Selector.logo + ', ' + Selector.sidebar).one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function () {
this.fix();
this.fixSidebar();
}.bind(this));
}.bind(this));
this.bindedResize = true;
}
$(Selector.sidebarMenu).on('expanded.tree', function () {
this.fix();
this.fixSidebar();
}.bind(this));
$(Selector.sidebarMenu).on('collapsed.tree', function () {
this.fix();
this.fixSidebar();
}.bind(this));
};
Layout.prototype.fix = function () {
// Remove overflow from .wrapper if layout-boxed exists
$(Selector.layoutBoxed + ' > ' + Selector.wrapper).css('overflow', 'hidden');
// Get window height and the wrapper height
var footerHeight = $(Selector.mainFooter).outerHeight() || 0;
var headerHeight = $(Selector.mainHeader).outerHeight() || 0;
var neg = headerHeight + footerHeight;
var windowHeight = $(window).height();
var sidebarHeight = $(Selector.sidebar).outerHeight() || 0;
// Set the min-height of the content and sidebar based on
// the height of the document.
if ($('body').hasClass(ClassName.fixed)) {
$(Selector.contentWrapper).css('min-height', windowHeight - footerHeight);
} else {
var postSetHeight;
if (windowHeight >= sidebarHeight + headerHeight) {
$(Selector.contentWrapper).css('min-height', windowHeight - neg);
postSetHeight = windowHeight - neg;
} else {
$(Selector.contentWrapper).css('min-height', sidebarHeight);
postSetHeight = sidebarHeight;
}
// Fix for the control sidebar height
var $controlSidebar = $(Selector.controlSidebar);
if (typeof $controlSidebar !== 'undefined') {
if ($controlSidebar.height() > postSetHeight)
$(Selector.contentWrapper).css('min-height', $controlSidebar.height());
}
}
};
Layout.prototype.fixSidebar = function () {
// Make sure the body tag has the .fixed class
if (!$('body').hasClass(ClassName.fixed)) {
if (typeof $.fn.slimScroll !== 'undefined') {
$(Selector.sidebar).slimScroll({ destroy: true }).height('auto');
}
return;
}
// Enable slimscroll for fixed layout
if (this.options.slimscroll) {
if (typeof $.fn.slimScroll !== 'undefined') {
// Destroy if it exists
// $(Selector.sidebar).slimScroll({ destroy: true }).height('auto')
// Add slimscroll
if ($(Selector.mainSidebar).find(Selector.slimScrollDiv).length === 0) {
$(Selector.sidebar).slimScroll({
height: ($(window).height() - $(Selector.mainHeader).height()) + 'px'
});
}
}
}
};
// Plugin Definition
// =================
function Plugin(option) {
return this.each(function () {
var $this = $(this);
var data = $this.data(DataKey);
if (!data) {
var options = $.extend({}, Default, $this.data(), typeof option === 'object' && option);
$this.data(DataKey, (data = new Layout(options)));
}
if (typeof option === 'string') {
if (typeof data[option] === 'undefined') {
throw new Error('No method named ' + option);
}
data[option]();
}
});
}
var old = $.fn.layout;
$.fn.layout = Plugin;
$.fn.layout.Constuctor = Layout;
// No conflict mode
// ================
$.fn.layout.noConflict = function () {
$.fn.layout = old;
return this;
};
// Layout DATA-API
// ===============
$(window).on('load', function () {
Plugin.call($('body'));
});
}(jQuery);
//全屏事件
$(document).on('click', "[data-toggle='fullscreen']", function () {
var doc = document.documentElement;
if ($(document.body).hasClass("full-screen")) {
$(document.body).removeClass("full-screen");
document.exitFullscreen ? document.exitFullscreen() : document.mozCancelFullScreen ? document.mozCancelFullScreen() : document.webkitExitFullscreen && document.webkitExitFullscreen();
} else {
$(document.body).addClass("full-screen");
doc.requestFullscreen ? doc.requestFullscreen() : doc.mozRequestFullScreen ? doc.mozRequestFullScreen() : doc.webkitRequestFullscreen ? doc.webkitRequestFullscreen() : doc.msRequestFullscreen && doc.msRequestFullscreen();
}
});
var my_skins = [
"skin-blue",
"skin-black",
"skin-red",
"skin-yellow",
"skin-purple",
"skin-green",
"skin-blue-light",
"skin-black-light",
"skin-red-light",
"skin-yellow-light",
"skin-purple-light",
"skin-green-light",
"skin-black-blue",
"skin-black-purple",
"skin-black-red",
"skin-black-green",
"skin-black-yellow",
"skin-black-pink",
];
// 皮肤切换
$("[data-skin]").on('click', function (e) {
var skin = $(this).data('skin');
if (!$("body").hasClass(skin)) {
$("body").removeClass(my_skins.join(' ')).addClass(skin);
var cssfile = "/static/css/skins/" + skin + ".css";
$('head').append('<link rel="stylesheet" href="' + cssfile + '" type="text/css" />');
$(".skin-list li.active").removeClass("active");
$(".skin-list li a[data-skin='" + skin + "']").parent().addClass("active");
$.ajax({
type : "POST",
url : "/changeskin",
data : {skin:skin},
dataType : 'json',
async: true,
success : function(data) {
}
});
}
return false;
});

4
public/static/js/app.min.js vendored Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

10
public/static/js/bootstrap-table.min.js vendored Executable file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,46 @@
// lazyload config
var jp_config = {
easyPieChart: [ './assets/vendor/jquery.easy-pie-chart/dist/jquery.easypiechart.fill.js'],
sparkline: [ './assets/vendor/jquery.sparkline/dist/jquery.sparkline.retina.js'],
plot: [ './assets/vendor/flot/jquery.flot.js',
'./assets/vendor/flot/jquery.flot.pie.js',
'./assets/vendor/flot/jquery.flot.resize.js',
'./assets/vendor/flot.tooltip/js/jquery.flot.tooltip.min.js',
'./assets/vendor/flot.orderbars/js/jquery.flot.orderBars.js',
'./assets/vendor/flot-spline/js/jquery.flot.spline.min.js'],
moment: [ './assets/vendor/moment/moment.js'],
screenfull: [ './assets/vendor/screenfull/dist/screenfull.min.js'],
slimScroll: [ './assets/vendor/slimscroll/jquery.slimscroll.min.js'],
sortable: [ './assets/vendor/html5sortable/jquery.sortable.js'],
nestable: [ './assets/vendor/nestable/jquery.nestable.js',
'./assets/vendor/nestable/jquery.nestable.css'],
filestyle: [ './assets/vendor/bootstrap-filestyle/src/bootstrap-filestyle.js'],
slider: [ './assets/vendor/bootstrap-slider/bootstrap-slider.js',
'./assets/vendor/bootstrap-slider/bootstrap-slider.css'],
chosen: [ './assets/vendor/chosen/chosen.jquery.min.js',
'./assets/vendor/bootstrap-chosen/bootstrap-chosen.css'],
TouchSpin: [ './assets/vendor/bootstrap-touchspin/dist/jquery.bootstrap-touchspin.min.js',
'./assets/vendor/bootstrap-touchspin/dist/jquery.bootstrap-touchspin.min.css'],
wysiwyg: [ './assets/vendor/bootstrap-wysiwyg/bootstrap-wysiwyg.js',
'./assets/vendor/bootstrap-wysiwyg/external/jquery.hotkeys.js'],
dataTable: [ './assets/vendor/datatables/media/js/jquery.dataTables.min.js',
'./assets/vendor/plugins/integration/bootstrap/3/dataTables.bootstrap.js',
'./assets/vendor/plugins/integration/bootstrap/3/dataTables.bootstrap.css'],
vectorMap: [ './assets/vendor/bower-jvectormap/jquery-jvectormap-1.2.2.min.js',
'./assets/vendor/bower-jvectormap/jquery-jvectormap-world-mill-en.js',
'./assets/vendor/bower-jvectormap/jquery-jvectormap-us-aea-en.js',
'./assets/vendor/bower-jvectormap/jquery-jvectormap-1.2.2.css'],
footable: [ './assets/vendor/footable/dist/footable.all.min.js',
'./assets/vendor/footable/css/footable.core.css'],
fullcalendar: [ './assets/vendor/moment/moment.js',
'./assets/vendor/fullcalendar/dist/fullcalendar.min.js',
'./assets/vendor/fullcalendar/dist/fullcalendar.css',
'./assets/vendor/fullcalendar/dist/fullcalendar.theme.css'],
daterangepicker:[ './assets/vendor/moment/moment.js',
'./assets/vendor/bootstrap-daterangepicker/daterangepicker.js',
'./assets/vendor/bootstrap-daterangepicker/daterangepicker-bs3.css'],
tagsinput: [ './assets/vendor/bootstrap-tagsinput/dist/bootstrap-tagsinput.js',
'./assets/vendor/bootstrap-tagsinput/dist/bootstrap-tagsinput.css']
};

19
public/static/js/ui-jp.js Executable file
View File

@ -0,0 +1,19 @@
+function ($) {
$(function(){
$("[ui-jq]").each(function(){
var self = $(this);
var options = eval('[' + self.attr('ui-options') + ']');
if ($.isPlainObject(options[0])) {
options[0] = $.extend({}, options[0]);
}
uiLoad.load(jp_config[self.attr('ui-jq')]).then( function(){
self[self.attr('ui-jq')].apply(self, options);
});
});
});
}(jQuery);

86
public/static/js/ui-load.js Executable file
View File

@ -0,0 +1,86 @@
/**
* 0.1.0
* Deferred load js/css file, used for ui-jq.js and Lazy Loading.
*
* @ flatfull.com All Rights Reserved.
* Author url: http://themeforest.net/user/flatfull
*/
var uiLoad = uiLoad || {};
(function($, $document, uiLoad) {
"use strict";
var loaded = [],
promise = false,
deferred = $.Deferred();
/**
* Chain loads the given sources
* @param srcs array, script or css
* @returns {*} Promise that will be resolved once the sources has been loaded.
*/
uiLoad.load = function (srcs) {
srcs = $.isArray(srcs) ? srcs : srcs.split(/\s+/);
if(!promise){
promise = deferred.promise();
}
$.each(srcs, function(index, src) {
promise = promise.then( function(){
return src.indexOf('.css') >=0 ? loadCSS(src) : loadScript(src);
} );
});
deferred.resolve();
return promise;
};
/**
* Dynamically loads the given script
* @param src The url of the script to load dynamically
* @returns {*} Promise that will be resolved once the script has been loaded.
*/
var loadScript = function (src) {
if(loaded[src]) return loaded[src].promise();
var deferred = $.Deferred();
var script = $document.createElement('script');
script.src = src;
script.onload = function (e) {
deferred.resolve(e);
};
script.onerror = function (e) {
deferred.reject(e);
};
$document.body.appendChild(script);
loaded[src] = deferred;
return deferred.promise();
};
/**
* Dynamically loads the given CSS file
* @param href The url of the CSS to load dynamically
* @returns {*} Promise that will be resolved once the CSS file has been loaded.
*/
var loadCSS = function (href) {
if(loaded[href]) return loaded[href].promise();
var deferred = $.Deferred();
var style = $document.createElement('link');
style.rel = 'stylesheet';
style.type = 'text/css';
style.href = href;
style.onload = function (e) {
deferred.resolve(e);
};
style.onerror = function (e) {
deferred.reject(e);
};
$document.head.appendChild(style);
loaded[href] = deferred;
return deferred.promise();
}
})(jQuery, document, uiLoad);

20
public/static/js/ui-nav.js Executable file
View File

@ -0,0 +1,20 @@
+function ($) {
$(function(){
// nav
$(document).on('click', '[ui-nav] a', function (e) {
var $this = $(e.target), $active;
$this.is('a') || ($this = $this.closest('a'));
$active = $this.parent().siblings( ".active" );
$active && $active.toggleClass('active').find('> ul:visible').slideUp(200);
($this.parent().hasClass('active') && $this.next().slideUp(200)) || $this.next().slideDown(200);
$this.parent().toggleClass('active');
$this.next().is('ul') && e.preventDefault();
});
});
}(jQuery);

14
public/static/js/ui-toggle.js Executable file
View File

@ -0,0 +1,14 @@
+function ($) {
$(function(){
$(document).on('click', '[ui-toggle]', function (e) {
e.preventDefault();
var $this = $(e.target);
$this.attr('ui-toggle') || ($this = $this.closest('[ui-toggle]'));
var $target = $($this.attr('target')) || $this;
$target.toggleClass($this.attr('ui-toggle'));
});
});
}(jQuery);