Initial commit (code only without large binaries)
This commit is contained in:
1
EdgeAdmin/web/views/@default/@blank.html
Normal file
1
EdgeAdmin/web/views/@default/@blank.html
Normal file
@@ -0,0 +1 @@
|
||||
{$layout}
|
||||
9
EdgeAdmin/web/views/@default/@code_editor.html
Normal file
9
EdgeAdmin/web/views/@default/@code_editor.html
Normal file
@@ -0,0 +1,9 @@
|
||||
{$var "header"}
|
||||
<!-- code editor -->
|
||||
<script src="/codemirror/lib/codemirror.js" type="text/javascript"></script>
|
||||
<script src="/codemirror/mode/meta.js" type="text/javascript"></script>
|
||||
<script src="/codemirror/addon/edit/matchbrackets.js" type="text/javascript"></script>
|
||||
<script src="/codemirror/addon/mode/loadmode.js" type="text/javascript"></script>
|
||||
<link rel="stylesheet" href="/codemirror/lib/codemirror.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="/codemirror/theme/idea.css" type="text/css"/>
|
||||
{$end}
|
||||
8
EdgeAdmin/web/views/@default/@datepicker.html
Normal file
8
EdgeAdmin/web/views/@default/@datepicker.html
Normal file
@@ -0,0 +1,8 @@
|
||||
{$var "header"}
|
||||
<!-- datepicker -->
|
||||
<script type="text/javascript" src="/js/moment.min.js"></script>
|
||||
<script type="text/javascript" src="/js/pikaday.js"></script>
|
||||
<link rel="stylesheet" href="/js/pikaday.css"/>
|
||||
<link rel="stylesheet" href="/js/pikaday.theme.css"/>
|
||||
<link rel="stylesheet" href="/js/pikaday.triangle.css"/>
|
||||
{$end}
|
||||
4
EdgeAdmin/web/views/@default/@echarts.html
Normal file
4
EdgeAdmin/web/views/@default/@echarts.html
Normal file
@@ -0,0 +1,4 @@
|
||||
{$var "header"}
|
||||
<!-- echart -->
|
||||
<script type="text/javascript" src="/js/echarts/echarts.min.js"></script>
|
||||
{$end}
|
||||
9
EdgeAdmin/web/views/@default/@footer.html
Normal file
9
EdgeAdmin/web/views/@default/@footer.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<div id="footer" class="ui menu inverted light-blue borderless small" v-if="teaShowOpenSourceInfo" v-cloak>
|
||||
<a href="/settings/upgrade" class="item" title="点击进入检查版本更新页面"><span v-if="teaName && teaVersion">{{teaName}} v{{teaVersion}}</span><span v-else style="display:none;"></span></a>
|
||||
<a href="https://goedge.cn" target="_blank" class="item">官网</a>
|
||||
<a href="https://goedge.cn/docs" target="_blank" class="item">文档</a>
|
||||
<a href="https://github.com/TeaOSLab/EdgeAdmin" target="_blank" class="item">GitHub</a>
|
||||
<a href="https://github.com/TeaOSLab/EdgeAdmin/issues" target="_blank" class="item">提Bug</a>
|
||||
<a class="item" href="https://goedge.cn/community/telegram" target="_blank" title="点击跳转到加群页面">Telegram群 <i class="icon paper plane"></i></a>
|
||||
<a class="item right" href="https://goedge.cn/commercial" target="_blank" v-if="!teaIsPlus">企业版</a>
|
||||
</div>
|
||||
42
EdgeAdmin/web/views/@default/@grids.css
Normal file
42
EdgeAdmin/web/views/@default/@grids.css
Normal file
@@ -0,0 +1,42 @@
|
||||
.grid.counter-chart {
|
||||
margin-top: 1em !important;
|
||||
margin-left: 0.4em !important;
|
||||
}
|
||||
.grid.counter-chart .column {
|
||||
margin-bottom: 1em;
|
||||
font-size: 0.85em;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
border: 1px rgba(0, 0, 0, 0.1) solid;
|
||||
border-right: 0;
|
||||
}
|
||||
.grid.counter-chart .column div.value {
|
||||
margin-top: 1.5em;
|
||||
font-weight: normal;
|
||||
}
|
||||
.grid.counter-chart .column div.value span {
|
||||
font-size: 1.5em;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
.grid.counter-chart .column.with-border {
|
||||
border-right: 1px rgba(0, 0, 0, 0.1) solid;
|
||||
}
|
||||
.grid.counter-chart h4 {
|
||||
color: grey;
|
||||
position: relative;
|
||||
font-size: 1em;
|
||||
text-align: left;
|
||||
}
|
||||
.grid.counter-chart h4 a {
|
||||
position: absolute;
|
||||
right: 0.1em;
|
||||
font-size: 1.26em;
|
||||
display: none;
|
||||
}
|
||||
.grid.counter-chart .column:hover {
|
||||
background: rgba(0, 0, 0, 0.03) !important;
|
||||
}
|
||||
.grid.counter-chart .column:hover a {
|
||||
display: inline;
|
||||
}
|
||||
/*# sourceMappingURL=@grids.css.map */
|
||||
1
EdgeAdmin/web/views/@default/@grids.css.map
Normal file
1
EdgeAdmin/web/views/@default/@grids.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["@grids.less"],"names":[],"mappings":"AAAA,KAAK;EACJ,0BAAA;EACA,kBAAA;;AAFD,KAAK,cAIJ;EACC,kBAAA;EACA,iBAAA;EACA,kBAAA;EACA,kBAAA;EACA,oCAAA;EACA,eAAA;;AAVF,KAAK,cAIJ,QAQC,IAAG;EACF,iBAAA;EACA,mBAAA;;AAdH,KAAK,cAIJ,QAQC,IAAG,MAIF;EACC,gBAAA;EACA,mBAAA;;AAlBJ,KAAK,cAuBJ,QAAO;EACN,0CAAA;;AAxBF,KAAK,cA2BJ;EACC,WAAA;EACA,kBAAA;EASA,cAAA;EACA,gBAAA;;AAvCF,KAAK,cA2BJ,GAIC;EACC,kBAAA;EACA,YAAA;EACA,iBAAA;EACA,aAAA;;AAnCH,KAAK,cA0CJ,QAAO;EACN,+BAAA;;AA3CF,KAAK,cA0CJ,QAAO,MAGN;EACC,eAAA","file":"@grids.css"}
|
||||
77
EdgeAdmin/web/views/@default/@grids.less
Normal file
77
EdgeAdmin/web/views/@default/@grids.less
Normal file
@@ -0,0 +1,77 @@
|
||||
.grid.counter-chart {
|
||||
margin-top: 1em !important;
|
||||
margin-left: 0.4em !important;
|
||||
|
||||
.column {
|
||||
margin-bottom: 1em;
|
||||
font-size: 0.85em;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
border: 1px rgba(0, 0, 0, .1) solid;
|
||||
border-right: 0;
|
||||
|
||||
div.value {
|
||||
margin-top: 1.5em;
|
||||
font-weight: normal;
|
||||
|
||||
span {
|
||||
font-size: 1.5em;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.column.with-border {
|
||||
border-right: 1px rgba(0, 0, 0, .1) solid;
|
||||
}
|
||||
|
||||
h4 {
|
||||
color: grey;
|
||||
position: relative;
|
||||
|
||||
a {
|
||||
position: absolute;
|
||||
right: 0.1em;
|
||||
font-size: 1.26em;
|
||||
display: none;
|
||||
}
|
||||
|
||||
font-size: 1.0em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.column:hover {
|
||||
background: rgba(0, 0, 0, .03) !important;
|
||||
|
||||
a {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.grid.chart-grid {
|
||||
margin-top: 1em !important;
|
||||
margin-left: 0.4em !important;
|
||||
|
||||
.column {
|
||||
margin-bottom: 1em;
|
||||
border: 1px rgba(0, 0, 0, .1) solid;
|
||||
border-right: 0;
|
||||
|
||||
.menu {
|
||||
margin-top: -0.6em !important;
|
||||
margin-bottom: -0.6em !important;
|
||||
}
|
||||
|
||||
h4 {
|
||||
span {
|
||||
font-size: 0.8em;
|
||||
color: grey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.column.with-border {
|
||||
border-right: 1px rgba(0, 0, 0, .1) solid;
|
||||
}
|
||||
}
|
||||
937
EdgeAdmin/web/views/@default/@layout.css
Normal file
937
EdgeAdmin/web/views/@default/@layout.css
Normal file
@@ -0,0 +1,937 @@
|
||||
.left-box {
|
||||
width: 8.5em;
|
||||
position: fixed;
|
||||
top: 7.5em;
|
||||
bottom: 2.4em;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
border-right: 1px #ddd solid;
|
||||
}
|
||||
.left-box .menu {
|
||||
width: 95% !important;
|
||||
}
|
||||
.left-box .menu .item {
|
||||
line-height: 1.2;
|
||||
position: relative;
|
||||
padding-left: 1em !important;
|
||||
}
|
||||
.left-box .menu .item .icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
margin-top: -0.4em !important;
|
||||
}
|
||||
.left-box .menu .item.separator {
|
||||
border-bottom: 1px #eee solid !important;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.left-box .menu .item.on span {
|
||||
border-bottom: 1px #666 dashed;
|
||||
}
|
||||
.left-box .menu .item.off span var {
|
||||
font-style: normal;
|
||||
background: #db2828;
|
||||
color: white;
|
||||
font-size: 8px;
|
||||
padding: 2px;
|
||||
border-radius: 2px;
|
||||
margin-left: 1em;
|
||||
}
|
||||
.left-box .menu .item.active {
|
||||
background: rgba(230, 230, 230, 0.35) !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.left-box .menu .header {
|
||||
border-bottom: 1px #ddd solid;
|
||||
padding-left: 0 !important;
|
||||
padding-bottom: 1em !important;
|
||||
}
|
||||
.left-box::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.left-box.disabled {
|
||||
opacity: 0.1;
|
||||
}
|
||||
.left-box.tiny {
|
||||
top: 10em;
|
||||
}
|
||||
.left-box.without-tabbar {
|
||||
top: 3em;
|
||||
}
|
||||
.left-box.with-menu {
|
||||
top: 8.7em;
|
||||
}
|
||||
.left-box.without-menu {
|
||||
top: 6em;
|
||||
}
|
||||
.right-box {
|
||||
position: fixed;
|
||||
top: 7em;
|
||||
bottom: 1.3em;
|
||||
right: 0;
|
||||
left: 18em;
|
||||
padding-right: 2em;
|
||||
padding-bottom: 2em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.right-box h4:first-child {
|
||||
margin-top: 1em;
|
||||
}
|
||||
.right-box > .comment:first-child {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
.right-box {
|
||||
left: 13em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
}
|
||||
body.expanded .right-box {
|
||||
left: 10em;
|
||||
}
|
||||
.right-box.tiny {
|
||||
top: 10em;
|
||||
left: 26.5em;
|
||||
}
|
||||
.right-box::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.right-box.without-tabbar {
|
||||
top: 3em;
|
||||
}
|
||||
.right-box.with-menu {
|
||||
top: 8.6em;
|
||||
}
|
||||
.right-box.without-menu {
|
||||
top: 6em;
|
||||
}
|
||||
.main.without-footer .left-box {
|
||||
bottom: 0.2em;
|
||||
}
|
||||
.narrow-scrollbar::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.grid.counter-chart {
|
||||
margin-top: 1em !important;
|
||||
margin-left: 0.4em !important;
|
||||
}
|
||||
.grid.counter-chart .column {
|
||||
margin-bottom: 1em;
|
||||
font-size: 0.85em;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
border: 1px rgba(0, 0, 0, 0.1) solid;
|
||||
border-right: 0;
|
||||
}
|
||||
.grid.counter-chart .column div.value {
|
||||
margin-top: 1.5em;
|
||||
font-weight: normal;
|
||||
}
|
||||
.grid.counter-chart .column div.value span {
|
||||
font-size: 1.5em;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
.grid.counter-chart .column.with-border {
|
||||
border-right: 1px rgba(0, 0, 0, 0.1) solid;
|
||||
}
|
||||
.grid.counter-chart h4 {
|
||||
color: grey;
|
||||
position: relative;
|
||||
font-size: 1em;
|
||||
text-align: left;
|
||||
}
|
||||
.grid.counter-chart h4 a {
|
||||
position: absolute;
|
||||
right: 0.1em;
|
||||
font-size: 1.26em;
|
||||
display: none;
|
||||
}
|
||||
.grid.counter-chart .column:hover {
|
||||
background: rgba(0, 0, 0, 0.03) !important;
|
||||
}
|
||||
.grid.counter-chart .column:hover a {
|
||||
display: inline;
|
||||
}
|
||||
.grid.chart-grid {
|
||||
margin-top: 1em !important;
|
||||
margin-left: 0.4em !important;
|
||||
}
|
||||
.grid.chart-grid .column {
|
||||
margin-bottom: 1em;
|
||||
border: 1px rgba(0, 0, 0, 0.1) solid;
|
||||
border-right: 0;
|
||||
}
|
||||
.grid.chart-grid .column .menu {
|
||||
margin-top: -0.6em !important;
|
||||
margin-bottom: -0.6em !important;
|
||||
}
|
||||
.grid.chart-grid .column h4 span {
|
||||
font-size: 0.8em;
|
||||
color: grey;
|
||||
}
|
||||
.grid.chart-grid .column.with-border {
|
||||
border-right: 1px rgba(0, 0, 0, 0.1) solid;
|
||||
}
|
||||
/** 通用 **/
|
||||
* {
|
||||
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
a.disabled,
|
||||
a.disabled:hover,
|
||||
a.disabled:active,
|
||||
span.disabled {
|
||||
color: #ccc !important;
|
||||
}
|
||||
a.enabled,
|
||||
span.enabled,
|
||||
span.green {
|
||||
color: #21ba45;
|
||||
}
|
||||
span.grey,
|
||||
label.grey,
|
||||
p.grey {
|
||||
color: grey !important;
|
||||
}
|
||||
p.grey {
|
||||
margin-top: 0.8em;
|
||||
}
|
||||
span.red,
|
||||
pre.red {
|
||||
color: #db2828;
|
||||
}
|
||||
span.blue {
|
||||
color: #4183c4;
|
||||
}
|
||||
span.orange {
|
||||
color: #ff851b;
|
||||
}
|
||||
pre:not(.CodeMirror-line) {
|
||||
font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
|
||||
}
|
||||
tbody {
|
||||
background: transparent;
|
||||
}
|
||||
.table-box {
|
||||
margin-top: 1em;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.table-box::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
}
|
||||
.table.width30 {
|
||||
width: 30em !important;
|
||||
}
|
||||
.table.width35 {
|
||||
width: 35em !important;
|
||||
}
|
||||
.table.width40 {
|
||||
width: 40em !important;
|
||||
}
|
||||
.table.width1024 {
|
||||
width: 1024px !important;
|
||||
}
|
||||
.table th,
|
||||
.table td {
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
.table tr.active td {
|
||||
background: rgba(0, 0, 0, 0.01) !important;
|
||||
}
|
||||
p.comment,
|
||||
div.comment {
|
||||
color: #959da6;
|
||||
padding-top: 0.4em;
|
||||
font-size: 1em;
|
||||
}
|
||||
p.comment em,
|
||||
div.comment em {
|
||||
font-style: italic !important;
|
||||
}
|
||||
.truncate {
|
||||
white-space: nowrap;
|
||||
-ms-text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
div.margin,
|
||||
p.margin {
|
||||
margin-top: 1em;
|
||||
}
|
||||
.opacity-mask {
|
||||
opacity: 0.3;
|
||||
}
|
||||
/** 操作按钮容器 **/
|
||||
.op.one {
|
||||
width: 4em;
|
||||
}
|
||||
.op.two {
|
||||
width: 7.4em;
|
||||
}
|
||||
.op.three {
|
||||
width: 9em;
|
||||
}
|
||||
.op.four {
|
||||
width: 12em;
|
||||
}
|
||||
/** 主菜单 **/
|
||||
.main-menu {
|
||||
width: 8em !important;
|
||||
}
|
||||
.main-menu .ui.menu {
|
||||
width: 100% !important;
|
||||
}
|
||||
.main-menu .ui.menu .item.separator {
|
||||
border-top: 1px rgba(0, 0, 0, 0.2) solid;
|
||||
height: 1px;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
.main-menu {
|
||||
width: auto !important;
|
||||
}
|
||||
.main-menu .ui.menu {
|
||||
width: 3.6em !important;
|
||||
}
|
||||
.main-menu .ui.menu .item.separator {
|
||||
display: none;
|
||||
}
|
||||
.main-menu .ui.menu .item {
|
||||
padding-top: 2em;
|
||||
padding-bottom: 2.4em;
|
||||
}
|
||||
}
|
||||
.main-menu .ui.labeled.icon.menu .item {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.main-menu .ui.menu {
|
||||
padding-bottom: 3em;
|
||||
}
|
||||
.main-menu .ui.menu .item .subtitle {
|
||||
display: none;
|
||||
}
|
||||
.main-menu .ui.menu .item.expend .subtitle {
|
||||
display: block;
|
||||
font-size: 10px;
|
||||
padding-left: 2em;
|
||||
margin-top: 0.5em;
|
||||
color: grey;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
.main-menu .ui.menu .item.expend .subtitle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.main-menu .ui.menu .sub-items .item {
|
||||
padding-left: 2.8em !important;
|
||||
padding-right: 0.4em !important;
|
||||
}
|
||||
.main-menu .ui.menu .sub-items .item .icon {
|
||||
position: absolute;
|
||||
left: 1.1em;
|
||||
top: 0.93em;
|
||||
}
|
||||
.main-menu .ui.menu .sub-items .item .label {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
padding-left: 0.4em;
|
||||
padding-right: 0.4em;
|
||||
min-width: 2em;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
.main-menu .ui.menu .sub-items .item {
|
||||
padding-left: 1em !important;
|
||||
}
|
||||
}
|
||||
.main-menu .ui.menu .sub-items .item.active {
|
||||
background-color: #2185d0 !important;
|
||||
}
|
||||
/** 扩展UI **/
|
||||
.field.text {
|
||||
padding: 0.5em;
|
||||
}
|
||||
.form .fields:not(.inline) .field {
|
||||
margin-bottom: 0.5em !important;
|
||||
}
|
||||
.form .fields:not(.inline) .field .button {
|
||||
min-width: 5em;
|
||||
}
|
||||
/** body **/
|
||||
@keyframes blink {
|
||||
from {
|
||||
opacity: 0.1;
|
||||
}
|
||||
to {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
@keyframes rotation {
|
||||
from {
|
||||
transform: rotate(0);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
body .ui.menu .item .blink {
|
||||
animation: blink 1s infinite;
|
||||
}
|
||||
body .ui.menu .item:not(:hover) span.rotate {
|
||||
animation: rotation 3s infinite;
|
||||
}
|
||||
body.expanded .main-menu {
|
||||
display: none;
|
||||
}
|
||||
body.expanded .main {
|
||||
left: 1em;
|
||||
}
|
||||
/** 布局相关 */
|
||||
.top-nav {
|
||||
border-radius: 0 !important;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
overflow-x: auto;
|
||||
border: 0 !important;
|
||||
}
|
||||
.top-nav img.avatar {
|
||||
width: 1.6em !important;
|
||||
height: 1.6em !important;
|
||||
padding: 0.2em;
|
||||
background: #fff;
|
||||
border-radius: 0.9em;
|
||||
margin-right: 0.5em !important;
|
||||
}
|
||||
.top-nav em {
|
||||
font-style: normal;
|
||||
font-size: 0.9em;
|
||||
padding-left: 0.2em;
|
||||
}
|
||||
.top-nav .item .hover-span span {
|
||||
display: none;
|
||||
}
|
||||
.top-nav .item:hover .hover-span span {
|
||||
display: inline;
|
||||
}
|
||||
.top-nav .item.red {
|
||||
color: red !important;
|
||||
}
|
||||
.top-nav.theme1 {
|
||||
background: #14539A !important;
|
||||
}
|
||||
.top-nav.theme2 {
|
||||
background: #276AC6 !important;
|
||||
}
|
||||
.top-nav.theme3 {
|
||||
background: #007D9C !important;
|
||||
}
|
||||
.top-nav.theme4 {
|
||||
background: #A12568 !important;
|
||||
}
|
||||
.top-nav.theme5 {
|
||||
background: #1C7947 !important;
|
||||
}
|
||||
.top-nav.theme6 {
|
||||
background: #1D365D !important;
|
||||
}
|
||||
.top-nav.theme7 {
|
||||
background: black !important;
|
||||
}
|
||||
.top-nav::-webkit-scrollbar {
|
||||
height: 2px;
|
||||
}
|
||||
/** 顶部菜单 **/
|
||||
.top-secondary-menu {
|
||||
position: fixed;
|
||||
top: 2.6em;
|
||||
left: 8.2em;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
}
|
||||
.top-secondary-menu .menu {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
.top-secondary-menu .menu var {
|
||||
font-style: normal;
|
||||
}
|
||||
.top-secondary-menu .divider {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
.top-secondary-menu {
|
||||
left: 4em;
|
||||
}
|
||||
}
|
||||
/** 右侧主操作区 **/
|
||||
.main {
|
||||
position: absolute;
|
||||
left: 22em;
|
||||
top: 5.6em;
|
||||
padding-bottom: 5em;
|
||||
padding-right: 0.2em;
|
||||
right: 1em;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
.main {
|
||||
left: 4em;
|
||||
}
|
||||
.main .main-box {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.main.without-menu {
|
||||
left: 9em;
|
||||
}
|
||||
.main.without-secondary-menu {
|
||||
top: 2.9em;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
.main.without-menu {
|
||||
left: 4em;
|
||||
}
|
||||
}
|
||||
.main table td.title {
|
||||
width: 10em;
|
||||
}
|
||||
.main table td.middle-title {
|
||||
width: 14em;
|
||||
}
|
||||
.main table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
.main table td.color-border {
|
||||
border-left: 1px #276ac6 solid !important;
|
||||
}
|
||||
.main table td.vertical-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
.main table td.vertical-middle {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.main table td[colspan="2"] a {
|
||||
font-weight: normal;
|
||||
}
|
||||
.main table td em {
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.main table td em.grey {
|
||||
color: grey;
|
||||
}
|
||||
.main h3 {
|
||||
font-weight: normal;
|
||||
margin-top: 1em !important;
|
||||
position: relative;
|
||||
}
|
||||
.main h3 span {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.main h3 span.label {
|
||||
color: #6435c9;
|
||||
}
|
||||
.main h3 a {
|
||||
margin-left: 1em;
|
||||
font-size: 14px !important;
|
||||
right: 1em;
|
||||
}
|
||||
.main h4 {
|
||||
font-weight: normal;
|
||||
}
|
||||
.main form h4 {
|
||||
margin-top: 0.6em;
|
||||
}
|
||||
.main td span.small {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.main .button.mini {
|
||||
font-size: 0.8em;
|
||||
padding: 0.2em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
.main-menu {
|
||||
position: fixed;
|
||||
/**top: 1.05em;**/
|
||||
top: 2em;
|
||||
bottom: 0;
|
||||
overflow-y: auto;
|
||||
z-index: 10;
|
||||
}
|
||||
.main-menu .menu {
|
||||
border: 0 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.main-menu.theme1 {
|
||||
background: #14539A !important;
|
||||
}
|
||||
.main-menu.theme1 .menu {
|
||||
background: #14539A !important;
|
||||
}
|
||||
.main-menu.theme2 {
|
||||
background: #276AC6 !important;
|
||||
}
|
||||
.main-menu.theme2 .menu {
|
||||
background: #276AC6 !important;
|
||||
}
|
||||
.main-menu.theme3 {
|
||||
background: #007D9C !important;
|
||||
}
|
||||
.main-menu.theme3 .menu {
|
||||
background: #007D9C !important;
|
||||
}
|
||||
.main-menu.theme4 {
|
||||
background: #A12568 !important;
|
||||
}
|
||||
.main-menu.theme4 .menu {
|
||||
background: #A12568 !important;
|
||||
}
|
||||
.main-menu.theme5 {
|
||||
background: #1C7947 !important;
|
||||
}
|
||||
.main-menu.theme5 .menu {
|
||||
background: #1C7947 !important;
|
||||
}
|
||||
.main-menu.theme6 {
|
||||
background: #1D365D !important;
|
||||
}
|
||||
.main-menu.theme6 .menu {
|
||||
background: #1D365D !important;
|
||||
}
|
||||
.main-menu.theme7 {
|
||||
background: black !important;
|
||||
}
|
||||
.main-menu.theme7 .menu {
|
||||
background: black !important;
|
||||
}
|
||||
.main-menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.main .tab-menu {
|
||||
margin-top: 0.3em !important;
|
||||
margin-bottom: 0 !important;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
.main .tab-menu .item {
|
||||
padding: 0 1em !important;
|
||||
}
|
||||
.main .tab-menu .item var {
|
||||
font-style: normal;
|
||||
}
|
||||
.main .tab-menu .item span {
|
||||
font-size: 0.8em;
|
||||
padding-left: 0.3em;
|
||||
}
|
||||
.main .tab-menu .item .icon {
|
||||
margin-left: 0.6em;
|
||||
}
|
||||
.main .tab-menu .item.active.title {
|
||||
font-weight: normal !important;
|
||||
margin-right: 1em !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
.main .tab-menu .item:hover {
|
||||
background: #f8f8f9 !important;
|
||||
border-width: 1px;
|
||||
}
|
||||
.main .tab-menu .item.active:not(.title) {
|
||||
font-weight: normal !important;
|
||||
border: none;
|
||||
border-radius: 0 !important;
|
||||
color: #2185d0 !important;
|
||||
}
|
||||
.main .tab-menu .item.active:not(.title) .bottom-indicator {
|
||||
border-bottom: 1px #2185d0 solid;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 1px;
|
||||
}
|
||||
.main .tab-menu .item.active:not(.title).icon .bottom-indicator {
|
||||
border-bottom: 1px #2185d0 solid;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0.6em;
|
||||
bottom: 1px;
|
||||
}
|
||||
.main .tab-menu .item.active.blue {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
.main .tab-menu::-webkit-scrollbar {
|
||||
height: 4px;
|
||||
}
|
||||
.main .go-top-btn {
|
||||
position: fixed;
|
||||
right: 2.6em;
|
||||
bottom: 2em;
|
||||
font-size: 2em;
|
||||
line-height: 1.4em;
|
||||
border-radius: 1em;
|
||||
z-index: 999999;
|
||||
background: white;
|
||||
}
|
||||
/** 右侧文本子菜单 **/
|
||||
.text.menu {
|
||||
overflow-x: auto;
|
||||
}
|
||||
.text.menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
}
|
||||
/** 脚部相关样式 **/
|
||||
#footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
text-align: left;
|
||||
color: gray;
|
||||
width: 100%;
|
||||
border-radius: 0 !important;
|
||||
z-index: 10;
|
||||
overflow-x: auto;
|
||||
}
|
||||
#footer::-webkit-scrollbar {
|
||||
height: 2px;
|
||||
}
|
||||
#footer a {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
#footer a form {
|
||||
display: none;
|
||||
}
|
||||
#footer a:hover span,
|
||||
#footer a:active span {
|
||||
display: none;
|
||||
}
|
||||
#footer a:hover form,
|
||||
#footer a:active form {
|
||||
display: block;
|
||||
}
|
||||
#footer form input {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
#footer-outer-box {
|
||||
z-index: 999999;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
bottom: 2.6em;
|
||||
}
|
||||
#footer-outer-box .qrcode {
|
||||
width: 20em;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -14em;
|
||||
margin-left: -10em;
|
||||
}
|
||||
#footer-outer-box .qrcode img {
|
||||
width: 100%;
|
||||
}
|
||||
#footer-outer-box .qrcode a {
|
||||
position: absolute;
|
||||
right: 0.5em;
|
||||
top: 0.5em;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
#footer-outer-box .qrcode {
|
||||
margin-left: 0;
|
||||
left: 3.5em;
|
||||
}
|
||||
}
|
||||
/** Vue **/
|
||||
[v-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
/** auto complete **/
|
||||
.autocomplete-box .menu {
|
||||
background: #eee !important;
|
||||
}
|
||||
.autocomplete-box .menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.autocomplete-box .menu .item {
|
||||
border-top: none !important;
|
||||
}
|
||||
select.auto-width {
|
||||
width: auto !important;
|
||||
}
|
||||
/** column **/
|
||||
@media screen and (max-width: 512px) {
|
||||
.column:not(.one) {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
label[for] {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
label.blue {
|
||||
color: #2185d0 !important;
|
||||
}
|
||||
/** Menu **/
|
||||
.first-menu .menu.text {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.first-menu .divider {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.second-menu .menu.text {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.second-menu .menu.text em {
|
||||
font-style: normal;
|
||||
}
|
||||
.second-menu .divider {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
.menu a {
|
||||
outline: none;
|
||||
}
|
||||
/** var **/
|
||||
span.olive,
|
||||
var.olive {
|
||||
color: #b5cc18 !important;
|
||||
}
|
||||
span.dash {
|
||||
border-bottom: 1px dashed grey;
|
||||
}
|
||||
span.hover:hover {
|
||||
background: #eee;
|
||||
}
|
||||
var.normal {
|
||||
font-style: normal;
|
||||
}
|
||||
/** checkbox **/
|
||||
.checkbox label a,
|
||||
.checkbox label {
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
/** page **/
|
||||
.page {
|
||||
margin-top: 1em;
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
.page a {
|
||||
display: inline-block;
|
||||
background: #fafafa;
|
||||
color: #666;
|
||||
padding: 6px 12px;
|
||||
margin: 0;
|
||||
font-size: 0.9em;
|
||||
border: 1px solid #ddd;
|
||||
border-left: 0;
|
||||
}
|
||||
.page a.active {
|
||||
background: #2185d0 !important;
|
||||
color: white;
|
||||
}
|
||||
.page a:hover {
|
||||
background: #eee;
|
||||
}
|
||||
.page select {
|
||||
padding-top: 0.3em !important;
|
||||
padding-bottom: 0.3em !important;
|
||||
}
|
||||
/** popup **/
|
||||
.swal2-html-container {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.swal2-close,
|
||||
.swal2-close:focus {
|
||||
border: 0;
|
||||
}
|
||||
.swal2-confirm:focus,
|
||||
.swal2-cancel:focus {
|
||||
border: 3px #ddd solid !important;
|
||||
}
|
||||
.swal2-confirm,
|
||||
.swal2-cancel {
|
||||
border: 3px #fff solid !important;
|
||||
}
|
||||
.swal2-cancel {
|
||||
margin-left: 2em !important;
|
||||
}
|
||||
/** 排序 **/
|
||||
.sortable-ghost {
|
||||
background: #ddd !important;
|
||||
opacity: 0.1;
|
||||
}
|
||||
.sortable-drag {
|
||||
opacity: 1;
|
||||
}
|
||||
.icon.handle {
|
||||
cursor: pointer;
|
||||
}
|
||||
.label.port-label {
|
||||
margin-top: 0.4em !important;
|
||||
margin-bottom: 0.4em !important;
|
||||
display: block;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.label {
|
||||
word-break: break-all;
|
||||
}
|
||||
td .label.small {
|
||||
margin-bottom: 0.2em !important;
|
||||
}
|
||||
td {
|
||||
word-break: break-all;
|
||||
}
|
||||
.source-code-box .CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto !important;
|
||||
}
|
||||
.source-code-box .CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
.source-code-box .CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
.scroll-box {
|
||||
overflow-y: auto;
|
||||
}
|
||||
.scroll-box::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
input.error {
|
||||
border: 1px #e0b4b4 solid !important;
|
||||
}
|
||||
textarea.wide-code {
|
||||
font-family: Menlo, Monaco, "Courier New", monospace !important;
|
||||
line-height: 1.6 !important;
|
||||
}
|
||||
.combo-box .menu {
|
||||
max-height: 17em;
|
||||
overflow-y: auto;
|
||||
position: absolute;
|
||||
border: rgba(129, 177, 210, 0.81) 1px solid;
|
||||
border-top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
.combo-box .menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
/*# sourceMappingURL=@layout.css.map */
|
||||
1
EdgeAdmin/web/views/@default/@layout.css.map
Normal file
1
EdgeAdmin/web/views/@default/@layout.css.map
Normal file
File diff suppressed because one or more lines are too long
157
EdgeAdmin/web/views/@default/@layout.html
Normal file
157
EdgeAdmin/web/views/@default/@layout.html
Normal file
@@ -0,0 +1,157 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<title>{$ htmlEncode .teaTitle}</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
|
||||
{$if eq .teaFaviconFileId 0}
|
||||
<link rel="shortcut icon" href="/images/favicon.png"/>
|
||||
{$else}
|
||||
<link rel="shortcut icon" href="/ui/image/{$.teaFaviconFileId}"/>
|
||||
{$end}
|
||||
<link rel="stylesheet" type="text/css" href="/_/@default/@layout.css" media="all"/>
|
||||
{$TEA.SEMANTIC}
|
||||
|
||||
{$TEA.VUE}
|
||||
{$echo "header"}
|
||||
<!-- 品牌配置 -->
|
||||
<script type="text/javascript">
|
||||
window.BRAND_OFFICIAL_SITE = {$ jsonEncode .brandConfig.officialSite};
|
||||
window.BRAND_DOCS_SITE = {$ jsonEncode .brandConfig.docsSite};
|
||||
window.BRAND_DOCS_PREFIX = {$ jsonEncode .brandConfig.docsPathPrefix};
|
||||
window.BRAND_PRODUCT_NAME = {$ jsonEncode .brandConfig.productName};
|
||||
|
||||
// 确保 teaName 和 teaVersion 在 Vue 初始化前可用
|
||||
if (typeof window.TEA === "undefined") {
|
||||
window.TEA = {};
|
||||
}
|
||||
if (typeof window.TEA.ACTION === "undefined") {
|
||||
window.TEA.ACTION = {};
|
||||
}
|
||||
if (typeof window.TEA.ACTION.data === "undefined") {
|
||||
window.TEA.ACTION.data = {};
|
||||
}
|
||||
window.TEA.ACTION.data.teaName = {$ jsonEncode .teaName};
|
||||
window.TEA.ACTION.data.teaVersion = {$ jsonEncode .teaVersion};
|
||||
</script>
|
||||
<script type="text/javascript" src="/js/config/brand.js"></script>
|
||||
<script type="text/javascript" src="/_/@default/@layout.js"></script>
|
||||
<script type="text/javascript" src="/js/components.js"></script>
|
||||
<script type="text/javascript" src="/js/utils.min.js"></script>
|
||||
<script type="text/javascript" src="/js/sweetalert2/dist/sweetalert2.all.min.js" async></script>
|
||||
<script type="text/javascript" src="/js/date.tea.js"></script>
|
||||
<script type="text/javascript" src="/js/langs/base.js?v={$ .teaVersion}"></script>
|
||||
<script type="text/javascript" src="/js/langs/{$.teaLang}.js?v={$ .teaVersion}"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/js/langs/{$.teaLang}.css?v={$ .teaVersion}"/>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/_/@default/@layout_override.css" media="all"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div>
|
||||
<!-- 顶部导航 -->
|
||||
<div class="ui menu top-nav blue inverted small borderless" :class="(teaTheme == null || teaTheme.length == 0) ? 'theme2': teaTheme" v-cloak="">
|
||||
<a href="/" class="item">
|
||||
<i class="ui icon leaf" v-if="teaLogoFileId == 0"></i><img alt="logo" v-if="teaLogoFileId > 0" :src="'/ui/image/' + teaLogoFileId" style="width: auto;height: 1.6em"/> {{teaTitle}} <sup v-if="teaShowVersion">v{{teaVersion}}<span v-if="teaVersion.split('.').length == 4" title="当前版本为测试版,再次感谢您参与测试"> beta</span></sup>
|
||||
</a>
|
||||
|
||||
<div class="right menu">
|
||||
<!-- 集群同步 -->
|
||||
<a href="" class="item" v-if="teaCheckNodeTasks && doingNodeTasks.isUpdated" @click.prevent="showNodeTasks()">
|
||||
<span v-if="!doingNodeTasks.isDoing && !doingNodeTasks.hasError" class="hover-span"><i class="icon cloud disabled"></i><span class="disabled">已同步节点</span></span>
|
||||
<span v-if="doingNodeTasks.isDoing && !doingNodeTasks.hasError" class="hover-span rotate"><i class="icon cloud"></i><span>正在同步节点...</span></span>
|
||||
<span v-if="doingNodeTasks.hasError" class="red"><i class="icon cloud"></i>节点同步失败</span>
|
||||
</a>
|
||||
|
||||
<!-- DNS同步 -->
|
||||
<a href="" class="item" v-if="teaCheckDNSTasks && doingDNSTasks.isUpdated" @click.prevent="showDNSTasks()">
|
||||
<span v-if="!doingDNSTasks.isDoing && !doingDNSTasks.hasError" class="hover-span"><i class="icon globe disabled"></i><span class="disabled">已同步DNS</span></span>
|
||||
<span v-if="doingDNSTasks.isDoing && !doingDNSTasks.hasError" class="hover-span rotate"><i class="icon globe"></i><span>正在同步DNS...</span></span>
|
||||
<span v-if="doingDNSTasks.hasError" class="red"><i class="icon globe"></i>DNS同步失败</span>
|
||||
</a>
|
||||
|
||||
<!-- 消息 -->
|
||||
<a href="" class="item" :class="{active:teaMenu == 'message'}" @click.prevent="showMessages()">
|
||||
<span v-if="globalMessageBadge > 0" class="blink hover-span"><i class="icon bell"></i><span>消息({{globalMessageBadge}}) </span></span>
|
||||
<span v-if="globalMessageBadge == 0" class="hover-span"><i class="icon bell disabled"></i><span class="disabled">消息(0)</span></span>
|
||||
</a>
|
||||
|
||||
<!-- 用户信息 -->
|
||||
<a href="/settings/profile" class="item">
|
||||
<i class="icon user" v-if="teaUserAvatar.length == 0"></i>
|
||||
<img class="avatar" alt="" :src="teaUserAvatar" v-if="teaUserAvatar.length > 0"/>
|
||||
<span class="hover-span"><span class="disabled">{{teaUsername}}</span></span>
|
||||
</a>
|
||||
|
||||
<a href="" class="item" title="switch language" @click.prevent="switchLang" v-show="false"><i class="icon language"></i> </a>
|
||||
|
||||
<!-- 背景颜色 -->
|
||||
<a href="" class="item" title="点击切换界面风格" @click.prevent="changeTheme()" v-if="false"><i class="icon adjust"></i></a>
|
||||
|
||||
<!-- 企业版 -->
|
||||
<!-- <a :href="'/settings/authority'" class="item" title="商业版" :v-if="teaIsPlus"><i class="icon gem outline yellow"></i></a>-->
|
||||
|
||||
<!-- 退出登录 -->
|
||||
<a :href="Tea.url('logout')" class="item" title="安全退出登录"><i class="icon sign out"></i>
|
||||
<span class="hover-span"><span class="disabled">退出登录</span></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 左侧主菜单 -->
|
||||
<div class="main-menu" :class="(teaTheme == null || teaTheme.length == 0) ? 'theme2': teaTheme" v-cloak="">
|
||||
<div class="ui labeled menu vertical blue inverted tiny borderless">
|
||||
<div class="item"></div>
|
||||
<!--<a :href="Tea.url('dashboard')" class="item" :class="{active:teaMenu == 'dashboard'}">
|
||||
<i class="ui dashboard icon"></i>
|
||||
<span>仪表板</span>
|
||||
</a>-->
|
||||
|
||||
<!-- 模块 -->
|
||||
<div v-for="module in teaModules">
|
||||
<a class="item" :href="Tea.url(module.code)" :class="{active:teaMenu == module.code && teaSubMenu.length == 0, separator:module.code.length == 0, expend: teaMenu == module.code}" :style="(teaMenu == module.code && teaSubMenu.length == 0) ? 'background: rgba(230, 230, 230, 0.45) !important;' : ''" v-if="module.isOn !== false">
|
||||
<span v-if="module.code.length > 0">
|
||||
<i class="window restore outline icon" v-if="module.icon == null"></i>
|
||||
<i class="ui icon" v-if="module.icon != null" :class="module.icon"></i>
|
||||
<span class="module-name">{{module.name}}</span>
|
||||
</span>
|
||||
<div class="subtitle" v-if="module.subtitle != null && module.subtitle.length > 0">{{module.subtitle}}</div>
|
||||
</a>
|
||||
<div v-if="teaMenu == module.code" class="sub-items">
|
||||
<a class="item" :class="{separator:subItem.name == '-', active: subItem.code == teaSubMenu}" v-for="subItem in module.subItems" v-if="subItem.isOn !== false" :href="subItem.url" :style="(subItem.code == teaSubMenu) ? 'background: rgba(230, 230, 230, 0.55) !important;' : ''"><i class="icon angle right" v-if="subItem.name != '-' && subItem.code == teaSubMenu"></i> <span v-if="subItem.name != '-'">{{subItem.name}}</span>
|
||||
<span class="ui label tiny red" v-if="subItem.badge != null && subItem.badge > 0">
|
||||
<span v-if="subItem.badge < 100">{{subItem.badge}}</span>
|
||||
<span v-else>99+</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧主操作栏 -->
|
||||
<div class="main" :class="{'without-menu':teaSubMenus.menus == null || teaSubMenus.menus.length == 0 || (teaSubMenus.menus.length == 1 && teaSubMenus.menus[0].alwaysActive), 'without-secondary-menu':teaSubMenus.alwaysMenu == null || teaSubMenus.alwaysMenu.items.length <= 1, 'without-footer':!teaShowOpenSourceInfo}" v-cloak="">
|
||||
<!-- 操作菜单 -->
|
||||
<div class="ui top menu tabular tab-menu small" v-if="teaTabbar.length > 1">
|
||||
<a class="item" v-for="item in teaTabbar" :class="{'active':item.isActive && !item.isDisabled, right:item.isRight, title: item.isTitle, icon: item.icon != null && item.icon.length > 0, disabled: item.isDisabled}" :href="item.url">
|
||||
<var>{{item.name}}<span v-if="item.subName.length > 0">({{item.subName}})</span><i class="icon small" :class="item.icon" v-if="item.icon != null && item.icon.length > 0"></i> </var>
|
||||
<var v-if="item.isTitle && typeof _data.node == 'object'">{{node.name}}</var>
|
||||
<div class="bottom-indicator" v-if="item.isActive && !item.isTitle"></div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- 功能区 -->
|
||||
<div class="main-box">
|
||||
{$TEA.VIEW}
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部 -->
|
||||
{$template "/footer"}
|
||||
</div>
|
||||
|
||||
{$echo "footer"}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
276
EdgeAdmin/web/views/@default/@layout.js
Normal file
276
EdgeAdmin/web/views/@default/@layout.js
Normal file
@@ -0,0 +1,276 @@
|
||||
Tea.context(function () {
|
||||
this.moreOptionsVisible = false
|
||||
this.globalMessageBadge = 0
|
||||
|
||||
if (typeof this.leftMenuItemIsDisabled == "undefined") {
|
||||
this.leftMenuItemIsDisabled = false
|
||||
}
|
||||
|
||||
this.$delay(function () {
|
||||
if (this.$refs.focus != null) {
|
||||
this.$refs.focus.focus()
|
||||
}
|
||||
|
||||
if (!window.IS_POPUP) {
|
||||
// 检查消息
|
||||
this.checkMessages()
|
||||
|
||||
// 检查集群节点同步
|
||||
this.loadNodeTasks();
|
||||
|
||||
// 检查DNS同步
|
||||
this.loadDNSTasks()
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 切换模板
|
||||
*/
|
||||
this.changeTheme = function () {
|
||||
this.$post("/ui/theme")
|
||||
.success(function (resp) {
|
||||
teaweb.successToast("界面风格已切换")
|
||||
this.teaTheme = resp.data.theme
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 左侧子菜单
|
||||
*/
|
||||
this.showSubMenu = function (menu) {
|
||||
if (menu.alwaysActive) {
|
||||
return
|
||||
}
|
||||
if (this.teaSubMenus.menus != null && this.teaSubMenus.menus.length > 0) {
|
||||
this.teaSubMenus.menus.$each(function (k, v) {
|
||||
if (menu.id == v.id) {
|
||||
return
|
||||
}
|
||||
v.isActive = false
|
||||
})
|
||||
}
|
||||
menu.isActive = !menu.isActive
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查消息
|
||||
*/
|
||||
this.checkMessages = function () {
|
||||
this.$post("/messages/badge")
|
||||
.params({})
|
||||
.success(function (resp) {
|
||||
this.globalMessageBadge = resp.data.count
|
||||
|
||||
// add dot to title
|
||||
let dots = "••• "
|
||||
if (typeof document.title == "string") {
|
||||
if (resp.data.count > 0) {
|
||||
if (!document.title.startsWith(dots)) {
|
||||
document.title = dots + document.title
|
||||
}
|
||||
} else if (document.title.startsWith(dots)) {
|
||||
document.title = document.title.substring(dots.length)
|
||||
}
|
||||
}
|
||||
})
|
||||
.done(function () {
|
||||
let delay = 6000
|
||||
if (this.globalMessageBadge > 0) {
|
||||
delay = 30000
|
||||
}
|
||||
this.$delay(function () {
|
||||
this.checkMessages()
|
||||
}, delay)
|
||||
})
|
||||
}
|
||||
|
||||
this.checkMessagesOnce = function () {
|
||||
this.$post("/messages/badge")
|
||||
.params({})
|
||||
.success(function (resp) {
|
||||
this.globalMessageBadge = resp.data.count
|
||||
})
|
||||
}
|
||||
|
||||
this.showMessages = function () {
|
||||
teaweb.popup("/messages", {
|
||||
height: "28em",
|
||||
width: "50em"
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 底部伸展框
|
||||
*/
|
||||
this.showQQGroupQrcode = function () {
|
||||
teaweb.popup("/about/qq", {
|
||||
width: "21em",
|
||||
height: "30em"
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 弹窗中默认成功回调
|
||||
*/
|
||||
if (window.IS_POPUP === true) {
|
||||
this.success = window.NotifyPopup
|
||||
}
|
||||
|
||||
/**
|
||||
* 节点同步任务
|
||||
*/
|
||||
this.doingNodeTasks = {
|
||||
isDoing: false,
|
||||
hasError: false,
|
||||
isUpdated: false
|
||||
}
|
||||
|
||||
this.loadNodeTasks = function () {
|
||||
if (!Tea.Vue.teaCheckNodeTasks) {
|
||||
return
|
||||
}
|
||||
let isStream = false
|
||||
this.$post("/clusters/tasks/check")
|
||||
.params({
|
||||
isDoing: this.doingNodeTasks.isDoing ? 1 : 0,
|
||||
hasError: this.doingNodeTasks.hasError ? 1 : 0,
|
||||
isUpdated: this.doingNodeTasks.isUpdated ? 1 : 0
|
||||
})
|
||||
.timeout(60)
|
||||
.success(function (resp) {
|
||||
this.doingNodeTasks.isDoing = resp.data.isDoing
|
||||
this.doingNodeTasks.hasError = resp.data.hasError
|
||||
this.doingNodeTasks.isUpdated = true
|
||||
isStream = resp.data.shouldWait
|
||||
})
|
||||
.done(function () {
|
||||
this.$delay(function () {
|
||||
this.loadNodeTasks()
|
||||
}, isStream ? 5000 : 30000)
|
||||
})
|
||||
}
|
||||
|
||||
this.showNodeTasks = function () {
|
||||
teaweb.popup("/clusters/tasks/listPopup", {
|
||||
height: "28em",
|
||||
width: "54em"
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* DNS同步任务
|
||||
*/
|
||||
this.doingDNSTasks = {
|
||||
isDoing: false,
|
||||
hasError: false,
|
||||
isUpdated: false
|
||||
}
|
||||
|
||||
this.loadDNSTasks = function () {
|
||||
if (!Tea.Vue.teaCheckDNSTasks) {
|
||||
return
|
||||
}
|
||||
let isStream = false
|
||||
this.$post("/dns/tasks/check")
|
||||
.params({
|
||||
isDoing: this.doingDNSTasks.isDoing ? 1 : 0,
|
||||
hasError: this.doingDNSTasks.hasError ? 1 : 0,
|
||||
isUpdated: this.doingDNSTasks.isUpdated ? 1 : 0
|
||||
})
|
||||
.timeout(60)
|
||||
.success(function (resp) {
|
||||
this.doingDNSTasks.isDoing = resp.data.isDoing
|
||||
this.doingDNSTasks.hasError = resp.data.hasError
|
||||
this.doingDNSTasks.isUpdated = true
|
||||
isStream = resp.data.isStream
|
||||
})
|
||||
.done(function () {
|
||||
this.$delay(function () {
|
||||
this.loadDNSTasks()
|
||||
}, isStream ? 5000 : 30000)
|
||||
})
|
||||
}
|
||||
|
||||
this.showDNSTasks = function () {
|
||||
teaweb.popup("/dns/tasks/listPopup", {
|
||||
height: "28em",
|
||||
width: "54em"
|
||||
})
|
||||
}
|
||||
|
||||
this.LANG = function (code) {
|
||||
if (window.LANG_MESSAGES != null) {
|
||||
let message = window.LANG_MESSAGES[code]
|
||||
if (typeof message == "string") {
|
||||
return message
|
||||
}
|
||||
}
|
||||
if (window.LANG_MESSAGES_BASE != null) {
|
||||
let message = window.LANG_MESSAGES_BASE[code]
|
||||
if (typeof message == "string") {
|
||||
return message
|
||||
}
|
||||
}
|
||||
return "{{ LANG('" + code + "') }}"
|
||||
}
|
||||
|
||||
this.switchLang = function () {
|
||||
this.$post("/settings/lang/switch")
|
||||
.success(function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
window.NotifySuccess = function (message, url, params) {
|
||||
if (typeof (url) == "string" && url.length > 0) {
|
||||
if (url[0] != "/") {
|
||||
url = Tea.url(url, params);
|
||||
}
|
||||
}
|
||||
return function () {
|
||||
teaweb.success(message, function () {
|
||||
window.location = url;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
window.NotifyReloadSuccess = function (message) {
|
||||
return function () {
|
||||
teaweb.success(message, function () {
|
||||
window.location.reload()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
window.NotifyDelete = function (message, url, params) {
|
||||
teaweb.confirm(message, function () {
|
||||
Tea.Vue.$post(url)
|
||||
.params(params)
|
||||
.refresh();
|
||||
});
|
||||
};
|
||||
|
||||
window.NotifyPopup = function (resp) {
|
||||
window.parent.teaweb.popupFinish(resp);
|
||||
};
|
||||
|
||||
window.ChangePageSize = function (size) {
|
||||
let url = window.location.toString();
|
||||
url = url.replace(/page=\d+/g, "page=1")
|
||||
if (url.indexOf("pageSize") > 0) {
|
||||
url = url.replace(/pageSize=\d+/g, "pageSize=" + size)
|
||||
} else {
|
||||
if (url.indexOf("?") > 0) {
|
||||
let anchorIndex = url.indexOf("#")
|
||||
if (anchorIndex < 0) {
|
||||
url += "&pageSize=" + size;
|
||||
} else {
|
||||
url = url.substring(0, anchorIndex) + "&pageSize=" + size + url.substr(anchorIndex);
|
||||
}
|
||||
} else {
|
||||
url += "?pageSize=" + size;
|
||||
}
|
||||
}
|
||||
window.location = url;
|
||||
};
|
||||
975
EdgeAdmin/web/views/@default/@layout.less
Normal file
975
EdgeAdmin/web/views/@default/@layout.less
Normal file
@@ -0,0 +1,975 @@
|
||||
@import "./@left_menu";
|
||||
@import "./@grids";
|
||||
|
||||
/** 通用 **/
|
||||
* {
|
||||
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
a.disabled, a.disabled:hover, a.disabled:active, span.disabled {
|
||||
color: #ccc !important;
|
||||
}
|
||||
|
||||
a.enabled, span.enabled, span.green {
|
||||
color: #21ba45;
|
||||
}
|
||||
|
||||
span.grey, label.grey, p.grey {
|
||||
color: grey !important;
|
||||
}
|
||||
|
||||
p.grey {
|
||||
margin-top: 0.8em;
|
||||
}
|
||||
|
||||
span.red, pre.red {
|
||||
color: #db2828;
|
||||
}
|
||||
|
||||
span.blue {
|
||||
color: #4183c4;
|
||||
}
|
||||
|
||||
span.orange {
|
||||
color: #ff851b;
|
||||
}
|
||||
|
||||
pre:not(.CodeMirror-line) {
|
||||
font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
|
||||
}
|
||||
|
||||
tbody {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.table-box {
|
||||
margin-top: 1em;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.table-box::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.table.width30 {
|
||||
width: 30em !important;
|
||||
}
|
||||
|
||||
.table.width35 {
|
||||
width: 35em !important;
|
||||
}
|
||||
|
||||
.table.width40 {
|
||||
width: 40em !important;
|
||||
}
|
||||
|
||||
.table.width1024 {
|
||||
width: 1024px !important;
|
||||
}
|
||||
|
||||
.table th, .table td {
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
|
||||
.table tr.active td {
|
||||
background: rgba(0, 0, 0, 0.01) !important;
|
||||
}
|
||||
|
||||
p.comment, div.comment {
|
||||
color: #959da6;
|
||||
padding-top: 0.4em;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
p.comment em, div.comment em {
|
||||
font-style: italic !important;
|
||||
}
|
||||
|
||||
.truncate {
|
||||
white-space: nowrap;
|
||||
-ms-text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
div.margin, p.margin {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.opacity-mask {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/** 操作按钮容器 **/
|
||||
.op.one {
|
||||
width: 4em;
|
||||
}
|
||||
|
||||
.op.two {
|
||||
width: 7.4em;
|
||||
}
|
||||
|
||||
.op.three {
|
||||
width: 9em;
|
||||
}
|
||||
|
||||
.op.four {
|
||||
width: 12em;
|
||||
}
|
||||
|
||||
/** 主菜单 **/
|
||||
.main-menu {
|
||||
width: 8em !important;
|
||||
|
||||
.ui.menu {
|
||||
width: 100% !important;
|
||||
|
||||
// menu
|
||||
.item.separator {
|
||||
border-top: 1px rgba(0, 0, 0, 0.2) solid;
|
||||
height: 1px;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.main-menu {
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
.main-menu .ui.menu {
|
||||
width: 3.6em !important;
|
||||
|
||||
.item.separator {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu .ui.menu .item {
|
||||
padding-top: 2em;
|
||||
padding-bottom: 2.4em;
|
||||
}
|
||||
|
||||
.main-menu .ui.menu .item span {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu .ui.labeled.icon.menu .item {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.main-menu {
|
||||
.ui.menu {
|
||||
padding-bottom: 3em;
|
||||
|
||||
.item {
|
||||
.subtitle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.item.expend .subtitle {
|
||||
display: block;
|
||||
font-size: 10px;
|
||||
padding-left: 2.0em;
|
||||
margin-top: 0.5em;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.item.expend .subtitle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sub-items {
|
||||
.item {
|
||||
padding-left: 2.8em !important;
|
||||
padding-right: 0.4em !important;
|
||||
|
||||
.icon {
|
||||
position: absolute;
|
||||
left: 1.1em;
|
||||
top: 0.93em;
|
||||
}
|
||||
|
||||
.label {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
padding-left: 0.4em;
|
||||
padding-right: 0.4em;
|
||||
min-width: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.item {
|
||||
padding-left: 1em !important;
|
||||
}
|
||||
}
|
||||
|
||||
.item.active {
|
||||
background-color: #2185d0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 扩展UI **/
|
||||
.field.text {
|
||||
padding: .5em;
|
||||
}
|
||||
|
||||
.form .fields:not(.inline) {
|
||||
.field {
|
||||
margin-bottom: 0.5em !important;
|
||||
|
||||
.button {
|
||||
min-width: 5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** body **/
|
||||
@keyframes blink {
|
||||
from {
|
||||
opacity: 0.1;
|
||||
}
|
||||
to {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotation {
|
||||
from {
|
||||
transform: rotate(0);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
body .ui.menu .item .blink {
|
||||
animation: blink 1s infinite;
|
||||
}
|
||||
|
||||
body .ui.menu .item:not(:hover) span.rotate {
|
||||
animation: rotation 3s infinite;
|
||||
}
|
||||
|
||||
body.expanded .main-menu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.expanded .main {
|
||||
left: 1em;
|
||||
}
|
||||
|
||||
/** 布局相关 */
|
||||
.top-nav {
|
||||
border-radius: 0 !important;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
overflow-x: auto;
|
||||
border: 0 !important;
|
||||
|
||||
img.avatar {
|
||||
width: 1.6em !important;
|
||||
height: 1.6em !important;
|
||||
padding: 0.2em;
|
||||
background: #fff;
|
||||
border-radius: 0.9em;
|
||||
margin-right: 0.5em !important;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: normal;
|
||||
font-size: 0.9em;
|
||||
padding-left: 0.2em;
|
||||
}
|
||||
|
||||
.item {
|
||||
.hover-span {
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item:hover {
|
||||
.hover-span {
|
||||
span {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item.red {
|
||||
color: red !important;
|
||||
}
|
||||
}
|
||||
|
||||
.top-nav.theme1 {
|
||||
background: #14539A !important;
|
||||
}
|
||||
|
||||
.top-nav.theme2 {
|
||||
background: #276AC6 !important;
|
||||
}
|
||||
|
||||
.top-nav.theme3 {
|
||||
background: #007D9C !important;
|
||||
}
|
||||
|
||||
.top-nav.theme4 {
|
||||
background: #A12568 !important;
|
||||
}
|
||||
|
||||
.top-nav.theme5 {
|
||||
background: #1C7947 !important;
|
||||
}
|
||||
|
||||
.top-nav.theme6 {
|
||||
background: #1D365D !important;
|
||||
}
|
||||
|
||||
.top-nav.theme7 {
|
||||
background: black !important;
|
||||
}
|
||||
|
||||
.top-nav::-webkit-scrollbar {
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
/** 顶部菜单 **/
|
||||
.top-secondary-menu {
|
||||
position: fixed;
|
||||
top: 2.6em;
|
||||
left: 8.2em;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.top-secondary-menu .menu {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.top-secondary-menu .menu var {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.top-secondary-menu .divider {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.top-secondary-menu {
|
||||
left: 4em;
|
||||
}
|
||||
}
|
||||
|
||||
/** 右侧主操作区 **/
|
||||
.main {
|
||||
position: absolute;
|
||||
left: 22em;
|
||||
top: 5.6em;
|
||||
padding-bottom: 5em;
|
||||
padding-right: 0.2em;
|
||||
right: 1em;
|
||||
|
||||
|
||||
.main-box {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.main {
|
||||
left: 4em;
|
||||
|
||||
.main-box {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main.without-menu {
|
||||
left: 9em;
|
||||
}
|
||||
|
||||
.main.without-secondary-menu {
|
||||
top: 2.9em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.main.without-menu {
|
||||
left: 4em;
|
||||
}
|
||||
}
|
||||
|
||||
.main table td.title {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
.main table td.middle-title {
|
||||
width: 14em;
|
||||
}
|
||||
|
||||
.main table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.main table td.color-border {
|
||||
border-left: 1px #276ac6 solid !important;
|
||||
}
|
||||
|
||||
.main table td.vertical-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.main table td.vertical-middle {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.main table td[colspan="2"] a {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.main table td em {
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
|
||||
.main table td em.grey {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.main h3 {
|
||||
font-weight: normal;
|
||||
margin-top: 1em !important;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.main h3 span {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.main h3 span.label {
|
||||
color: #6435c9;
|
||||
}
|
||||
|
||||
.main h3 a {
|
||||
margin-left: 1em;
|
||||
font-size: 14px !important;
|
||||
right: 1em;
|
||||
}
|
||||
|
||||
.main h4 {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.main form h4 {
|
||||
margin-top: 0.6em;
|
||||
}
|
||||
|
||||
.main td span.small {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.main .button.mini {
|
||||
font-size: 0.8em;
|
||||
padding: 0.2em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.main-menu {
|
||||
position: fixed;
|
||||
/**top: 1.05em;**/
|
||||
top: 2em;
|
||||
bottom: 0;
|
||||
overflow-y: auto;
|
||||
z-index: 10;
|
||||
|
||||
.menu {
|
||||
border: 0 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu.theme1 {
|
||||
background: #14539A !important;
|
||||
|
||||
.menu {
|
||||
background: #14539A !important;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu.theme2 {
|
||||
background: #276AC6 !important;
|
||||
|
||||
.menu {
|
||||
background: #276AC6 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu.theme3 {
|
||||
background: #007D9C !important;
|
||||
|
||||
.menu {
|
||||
background: #007D9C !important;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu.theme4 {
|
||||
background: #A12568 !important;
|
||||
|
||||
.menu {
|
||||
background: #A12568 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu.theme5 {
|
||||
background: #1C7947 !important;
|
||||
|
||||
.menu {
|
||||
background: #1C7947 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu.theme6 {
|
||||
background: #1D365D !important;
|
||||
|
||||
.menu {
|
||||
background: #1D365D !important;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu.theme7 {
|
||||
background: black !important;
|
||||
|
||||
.menu {
|
||||
background: black !important;
|
||||
}
|
||||
}
|
||||
|
||||
.main-menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.main {
|
||||
.tab-menu {
|
||||
margin-top: 0.3em !important;
|
||||
margin-bottom: 0 !important;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
|
||||
.item {
|
||||
padding: 0 1em !important;
|
||||
|
||||
var {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 0.8em;
|
||||
padding-left: 0.3em;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-left: 0.6em;
|
||||
}
|
||||
}
|
||||
|
||||
.item.active.title {
|
||||
font-weight: normal !important;
|
||||
margin-right: 1em !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.item:hover {
|
||||
background: #f8f8f9 !important;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.item.active:not(.title) {
|
||||
font-weight: normal !important;
|
||||
border: none;
|
||||
border-radius: 0 !important;
|
||||
color: #2185d0 !important;
|
||||
|
||||
.bottom-indicator {
|
||||
border-bottom: 1px #2185d0 solid;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.item.active:not(.title).icon {
|
||||
.bottom-indicator {
|
||||
border-bottom: 1px #2185d0 solid;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0.6em;
|
||||
bottom: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.item.active.blue {
|
||||
font-weight: bold !important;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-menu::-webkit-scrollbar {
|
||||
height: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.main .go-top-btn {
|
||||
position: fixed;
|
||||
right: 2.6em;
|
||||
bottom: 2em;
|
||||
font-size: 2em;
|
||||
line-height: 1.4em;
|
||||
border-radius: 1em;
|
||||
z-index: 999999;
|
||||
background: white;
|
||||
}
|
||||
|
||||
/** 右侧文本子菜单 **/
|
||||
.text.menu {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.text.menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
/** 脚部相关样式 **/
|
||||
#footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
text-align: left;
|
||||
color: gray;
|
||||
width: 100%;
|
||||
border-radius: 0 !important;
|
||||
z-index: 10;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
#footer::-webkit-scrollbar {
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
#footer a {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
#footer a form {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#footer a:hover span, #footer a:active span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#footer a:hover form, #footer a:active form {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#footer form input {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#footer-outer-box {
|
||||
z-index: 999999;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
bottom: 2.6em;
|
||||
}
|
||||
|
||||
#footer-outer-box .qrcode {
|
||||
width: 20em;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -14em;
|
||||
margin-left: -10em;
|
||||
}
|
||||
|
||||
#footer-outer-box .qrcode img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#footer-outer-box .qrcode a {
|
||||
position: absolute;
|
||||
right: 0.5em;
|
||||
top: 0.5em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
#footer-outer-box .qrcode {
|
||||
margin-left: 0;
|
||||
left: 3.5em;
|
||||
}
|
||||
}
|
||||
|
||||
/** Vue **/
|
||||
[v-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/** auto complete **/
|
||||
.autocomplete-box .menu {
|
||||
background: #eee !important;
|
||||
}
|
||||
|
||||
.autocomplete-box .menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.autocomplete-box .menu .item {
|
||||
border-top: none !important;
|
||||
}
|
||||
|
||||
select.auto-width {
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
/** column **/
|
||||
@media screen and (max-width: 512px) {
|
||||
.column:not(.one) {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
// label
|
||||
label[for] {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
label.blue {
|
||||
color: #2185d0 !important;
|
||||
}
|
||||
|
||||
/** Menu **/
|
||||
.first-menu .menu.text {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.first-menu .divider {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.second-menu .menu.text {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.second-menu .menu.text em {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.second-menu .divider {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.menu a {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/** var **/
|
||||
span.olive, var.olive {
|
||||
color: #b5cc18 !important;
|
||||
}
|
||||
|
||||
span.dash {
|
||||
border-bottom: 1px dashed grey;
|
||||
}
|
||||
|
||||
span.hover:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
var.normal {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/** checkbox **/
|
||||
.checkbox label a, .checkbox label {
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
|
||||
.checkbox label {
|
||||
|
||||
}
|
||||
|
||||
/** page **/
|
||||
.page {
|
||||
margin-top: 1em;
|
||||
|
||||
border-left: 1px solid #ddd;
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
background: #fafafa;
|
||||
color: #666;
|
||||
padding: 6px 12px;
|
||||
margin: 0;
|
||||
font-size: 0.9em;
|
||||
border: 1px solid #ddd;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
a.active {
|
||||
background: #2185d0 !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
select {
|
||||
padding-top: 0.3em !important;
|
||||
padding-bottom: 0.3em !important;
|
||||
}
|
||||
}
|
||||
|
||||
/** popup **/
|
||||
.swal2-html-container {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.swal2-close, .swal2-close:focus {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.swal2-confirm:focus, .swal2-cancel:focus {
|
||||
border: 3px #ddd solid !important;
|
||||
}
|
||||
|
||||
.swal2-confirm, .swal2-cancel {
|
||||
border: 3px #fff solid !important;
|
||||
}
|
||||
|
||||
.swal2-cancel {
|
||||
margin-left: 2em !important;
|
||||
}
|
||||
|
||||
/** 排序 **/
|
||||
.sortable-ghost {
|
||||
background: #ddd !important;
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.sortable-drag {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.icon.handle {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.label.port-label {
|
||||
margin-top: 0.4em !important;
|
||||
margin-bottom: 0.4em !important;
|
||||
display: block;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
// .label
|
||||
.label {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
td .label.small {
|
||||
margin-bottom: 0.2em !important;
|
||||
}
|
||||
|
||||
// td
|
||||
td {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
// codemirror
|
||||
.source-code-box {
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
// 表格
|
||||
.scroll-box {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.scroll-box::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
// input
|
||||
input.error {
|
||||
border: 1px #e0b4b4 solid !important;
|
||||
}
|
||||
|
||||
// textarea
|
||||
textarea.wide-code {
|
||||
font-family: Menlo, Monaco, "Courier New", monospace !important;
|
||||
line-height: 1.6 !important;
|
||||
}
|
||||
|
||||
// combo-box
|
||||
.combo-box .menu {
|
||||
max-height: 17em;
|
||||
overflow-y: auto;
|
||||
position: absolute;
|
||||
border: rgba(129, 177, 210, 0.81) 1px solid;
|
||||
border-top: 0;
|
||||
z-index: 100
|
||||
}
|
||||
|
||||
.combo-box .menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
128
EdgeAdmin/web/views/@default/@layout_override.css
Normal file
128
EdgeAdmin/web/views/@default/@layout_override.css
Normal file
@@ -0,0 +1,128 @@
|
||||
/* 全局字体大小调整 - 增加 10% */
|
||||
html {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
body {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
.ui.toggle.checkbox input:focus:checked ~ .box:before,
|
||||
.ui.toggle.checkbox input:focus:checked ~ label:before {
|
||||
background-color: #21ba45 !important;
|
||||
}
|
||||
.ui.toggle.checkbox input:checked ~ .box:before,
|
||||
.ui.toggle.checkbox input:checked ~ label:before {
|
||||
background-color: #21ba45 !important;
|
||||
}
|
||||
.ui.label.basic {
|
||||
background-color: white !important;
|
||||
}
|
||||
.ui.label.basic.grey {
|
||||
border: 1px #ccc solid !important;
|
||||
}
|
||||
.disabled .ui.label {
|
||||
color: #ccc !important;
|
||||
}
|
||||
.ui.basic.grey.label.border-grey {
|
||||
border-color: #ddd !important;
|
||||
}
|
||||
form .fields {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.link.grey {
|
||||
color: grey !important;
|
||||
}
|
||||
.link.grey:hover {
|
||||
color: #4183c4 !important;
|
||||
}
|
||||
table th.center,
|
||||
table td.center {
|
||||
text-align: center !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
table th.width10 {
|
||||
width: 10em;
|
||||
}
|
||||
table th.width5 {
|
||||
width: 5em;
|
||||
}
|
||||
table th.width6 {
|
||||
width: 6em;
|
||||
}
|
||||
.ui.table tbody[style*="display: none;"],
|
||||
.ui.table tr[style*="display: none;"],
|
||||
.ui.table tr > td[style*="display: none;"],
|
||||
.ui.table tr > th[style*="display: none;"] {
|
||||
display: none!important;
|
||||
}
|
||||
textarea::-webkit-scrollbar {
|
||||
width: 6px !important;
|
||||
}
|
||||
select.dropdown {
|
||||
height: auto !important;
|
||||
}
|
||||
.message .icon.warning {
|
||||
font-size: 2em !important;
|
||||
}
|
||||
body.swal2-shown {
|
||||
overflow: auto !important;
|
||||
}
|
||||
.grid {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
.fields button {
|
||||
min-width: 5em;
|
||||
}
|
||||
.left-box .menu .item.active {
|
||||
background: rgba(230, 230, 230, 0.35) !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
:root {
|
||||
--admin-top-nav-bg: #0a1f3f;
|
||||
--admin-side-menu-bg: #102a4d;
|
||||
}
|
||||
.top-nav.theme1,
|
||||
.top-nav.theme2,
|
||||
.top-nav.theme3,
|
||||
.top-nav.theme4,
|
||||
.top-nav.theme5,
|
||||
.top-nav.theme6,
|
||||
.top-nav.theme7 {
|
||||
background: var(--admin-top-nav-bg) !important;
|
||||
}
|
||||
.main-menu.theme1,
|
||||
.main-menu.theme2,
|
||||
.main-menu.theme3,
|
||||
.main-menu.theme4,
|
||||
.main-menu.theme5,
|
||||
.main-menu.theme6,
|
||||
.main-menu.theme7,
|
||||
.main-menu.theme1 .menu,
|
||||
.main-menu.theme2 .menu,
|
||||
.main-menu.theme3 .menu,
|
||||
.main-menu.theme4 .menu,
|
||||
.main-menu.theme5 .menu,
|
||||
.main-menu.theme6 .menu,
|
||||
.main-menu.theme7 .menu {
|
||||
background: var(--admin-side-menu-bg) !important;
|
||||
}
|
||||
.main-menu .ui.menu .item.separator,
|
||||
.main-menu .ui.menu .sub-items .item.separator {
|
||||
display: none !important;
|
||||
border: 0 !important;
|
||||
height: 0 !important;
|
||||
min-height: 0 !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
.main-menu {
|
||||
top: 2.6em !important;
|
||||
}
|
||||
.main-menu > .ui.menu > .item:first-child:empty {
|
||||
display: none !important;
|
||||
height: 0 !important;
|
||||
min-height: 0 !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
/*# sourceMappingURL=@layout_override.css.map */
|
||||
1
EdgeAdmin/web/views/@default/@layout_override.css.map
Normal file
1
EdgeAdmin/web/views/@default/@layout_override.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["@layout_override.less"],"names":[],"mappings":"AACA,GAAG,OAAO,SAAU,MAAK,MAAM,QAAS,OAAM;AAAS,GAAG,OAAO,SAAU,MAAK,MAAM,QAAS,QAAO;EACrG,yBAAA;;AAGD,GAAG,OAAO,SAAU,MAAK,QAAS,OAAM;AAAS,GAAG,OAAO,SAAU,MAAK,QAAS,QAAO;EACzF,yBAAA;;AAGD,GAAG,MAAM;EACR,kCAAA;;AAGD,GAAG,MAAM,MAAM;EACd,sBAAA;;AAGD,SAAU,IAAG;EACZ,WAAA;;AAGD,GAAG,MAAM,KAAK,MAAM;EACnB,kBAAA;;AAID,IACC;EACC,2BAAA;;AAKF,KAAK;EACJ,sBAAA;;AAGD,KAAK,KAAK;EACT,cAAA;;AAID,KACC,GAAE;AADH,KACY,GAAE;EACZ,6BAAA;EACA,0BAAA;EACA,2BAAA;;AAJF,KAOC,GAAE;EACD,WAAA;;AARF,KAWC,GAAE;EACD,UAAA;;AAZF,KAeC,GAAE;EACD,UAAA;;AAIF,GAAG,MAAO,MAAK;AAA2B,GAAG,MAAO,GAAE;AAA2B,GAAG,MAAO,GAAE,KAAG;AAA2B,GAAG,MAAO,GAAE,KAAG;EACzI,uBAAA;;AAID,QAAQ;EACP,qBAAA;;AAID,MAAM;EACL,uBAAA;;AAID,QACC,MAAK;EACJ,yBAAA;;AAKF,IAAI;EACH,yBAAA;;AAID;EACC,0BAAA;;AAID,OACC;EACC,cAAA","file":"@layout_override.css"}
|
||||
165
EdgeAdmin/web/views/@default/@layout_override.less
Normal file
165
EdgeAdmin/web/views/@default/@layout_override.less
Normal file
@@ -0,0 +1,165 @@
|
||||
// 全局字体大小调整 - 增加 10%
|
||||
html {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
// labels
|
||||
.ui.toggle.checkbox input:focus:checked ~ .box:before, .ui.toggle.checkbox input:focus:checked ~ label:before {
|
||||
background-color: #21ba45 !important;
|
||||
}
|
||||
|
||||
.ui.toggle.checkbox input:checked ~ .box:before, .ui.toggle.checkbox input:checked ~ label:before {
|
||||
background-color: #21ba45 !important;
|
||||
}
|
||||
|
||||
.ui.label.basic {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.ui.label.basic.grey {
|
||||
border: 1px #ccc solid !important;
|
||||
}
|
||||
|
||||
.disabled .ui.label {
|
||||
color: #ccc !important;
|
||||
}
|
||||
|
||||
.ui.basic.grey.label.border-grey {
|
||||
border-color: #ddd!important;
|
||||
}
|
||||
|
||||
// fields
|
||||
form {
|
||||
.fields {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// links
|
||||
.link.grey {
|
||||
color: grey !important;
|
||||
}
|
||||
|
||||
.link.grey:hover {
|
||||
color: #4183c4 !important;
|
||||
}
|
||||
|
||||
// table
|
||||
table {
|
||||
th.center, td.center {
|
||||
text-align: center !important;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
th.width10 {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
th.width5 {
|
||||
width: 5em;
|
||||
}
|
||||
|
||||
th.width6 {
|
||||
width: 6em;
|
||||
}
|
||||
}
|
||||
|
||||
.ui.table tbody[style*="display: none;"], .ui.table tr[style*="display: none;"], .ui.table tr>td[style*="display: none;"], .ui.table tr>th[style*="display: none;"] {
|
||||
display: none!important;
|
||||
}
|
||||
|
||||
// textarea
|
||||
textarea::-webkit-scrollbar {
|
||||
width: 6px !important;
|
||||
}
|
||||
|
||||
// dropdown
|
||||
select.dropdown {
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
// message
|
||||
.message {
|
||||
.icon.warning {
|
||||
font-size: 2em !important;
|
||||
}
|
||||
}
|
||||
|
||||
// popup
|
||||
body.swal2-shown {
|
||||
overflow: auto !important;
|
||||
}
|
||||
|
||||
// grid
|
||||
.grid {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
// fields
|
||||
.fields {
|
||||
button {
|
||||
min-width: 5em;
|
||||
}
|
||||
}
|
||||
|
||||
// Menu background colors only
|
||||
:root {
|
||||
--admin-top-nav-bg: #0a1f3f;
|
||||
--admin-side-menu-bg: #102a4d;
|
||||
}
|
||||
|
||||
.top-nav.theme1,
|
||||
.top-nav.theme2,
|
||||
.top-nav.theme3,
|
||||
.top-nav.theme4,
|
||||
.top-nav.theme5,
|
||||
.top-nav.theme6,
|
||||
.top-nav.theme7 {
|
||||
background: var(--admin-top-nav-bg) !important;
|
||||
}
|
||||
|
||||
.main-menu.theme1,
|
||||
.main-menu.theme2,
|
||||
.main-menu.theme3,
|
||||
.main-menu.theme4,
|
||||
.main-menu.theme5,
|
||||
.main-menu.theme6,
|
||||
.main-menu.theme7,
|
||||
.main-menu.theme1 .menu,
|
||||
.main-menu.theme2 .menu,
|
||||
.main-menu.theme3 .menu,
|
||||
.main-menu.theme4 .menu,
|
||||
.main-menu.theme5 .menu,
|
||||
.main-menu.theme6 .menu,
|
||||
.main-menu.theme7 .menu {
|
||||
background: var(--admin-side-menu-bg) !important;
|
||||
}
|
||||
|
||||
// Hide menu separators
|
||||
.main-menu .ui.menu .item.separator,
|
||||
.main-menu .ui.menu .sub-items .item.separator {
|
||||
display: none !important;
|
||||
border: 0 !important;
|
||||
height: 0 !important;
|
||||
min-height: 0 !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
// Align left menu with top nav and remove leading spacer item
|
||||
.main-menu {
|
||||
top: 2.6em !important;
|
||||
}
|
||||
|
||||
.main-menu > .ui.menu > .item:first-child:empty {
|
||||
display: none !important;
|
||||
height: 0 !important;
|
||||
min-height: 0 !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
336
EdgeAdmin/web/views/@default/@layout_popup.css
Normal file
336
EdgeAdmin/web/views/@default/@layout_popup.css
Normal file
@@ -0,0 +1,336 @@
|
||||
/** 通用 **/
|
||||
* {
|
||||
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
a.disabled,
|
||||
a.disabled:hover,
|
||||
a.disabled:active,
|
||||
span.disabled {
|
||||
color: #ccc !important;
|
||||
}
|
||||
a.enabled,
|
||||
span.enabled,
|
||||
span.green {
|
||||
color: #21ba45;
|
||||
}
|
||||
span.grey,
|
||||
label.grey,
|
||||
p.grey {
|
||||
color: grey !important;
|
||||
}
|
||||
p.grey {
|
||||
margin-top: 0.8em;
|
||||
}
|
||||
span.red,
|
||||
pre.red {
|
||||
color: #db2828;
|
||||
}
|
||||
span.blue {
|
||||
color: #4183c4;
|
||||
}
|
||||
pre:not(.CodeMirror-line) {
|
||||
font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
|
||||
}
|
||||
tbody {
|
||||
background: transparent;
|
||||
}
|
||||
.table.width30 {
|
||||
width: 30em !important;
|
||||
}
|
||||
.table.width35 {
|
||||
width: 35em !important;
|
||||
}
|
||||
.table.width40 {
|
||||
width: 40em !important;
|
||||
}
|
||||
.table th,
|
||||
.table td {
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
p.comment,
|
||||
div.comment {
|
||||
color: #959da6;
|
||||
padding-top: 0.4em;
|
||||
font-weight: normal;
|
||||
word-break: break-all;
|
||||
line-height: 1.8;
|
||||
}
|
||||
p.comment em,
|
||||
div.comment em {
|
||||
font-style: italic !important;
|
||||
}
|
||||
.truncate {
|
||||
white-space: nowrap;
|
||||
-ms-text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
div.margin,
|
||||
p.margin {
|
||||
margin-top: 1em;
|
||||
}
|
||||
/** 操作按钮容器 **/
|
||||
.op.one {
|
||||
width: 4em;
|
||||
}
|
||||
.op.two {
|
||||
width: 7.4em;
|
||||
}
|
||||
.op.three {
|
||||
width: 9em;
|
||||
}
|
||||
.op.four {
|
||||
width: 10em;
|
||||
}
|
||||
/** 扩展UI **/
|
||||
.field.text {
|
||||
padding: 0.5em;
|
||||
}
|
||||
/** 右侧主操作区 **/
|
||||
.main {
|
||||
position: absolute;
|
||||
left: 22em;
|
||||
top: 5.6em;
|
||||
padding-bottom: 5em;
|
||||
padding-right: 1em;
|
||||
right: 1em;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
.main {
|
||||
left: 4em;
|
||||
}
|
||||
}
|
||||
.main.without-menu {
|
||||
left: 9em;
|
||||
}
|
||||
.main.without-secondary-menu {
|
||||
top: 2.9em;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
.main.without-menu {
|
||||
left: 4em;
|
||||
}
|
||||
}
|
||||
.main table td.title {
|
||||
width: 10em;
|
||||
}
|
||||
.main table td.middle-title {
|
||||
width: 14em;
|
||||
}
|
||||
.main table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
table td.color-border {
|
||||
border-left: 1px #276ac6 solid !important;
|
||||
}
|
||||
.main table td.vertical-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
.main table td.vertical-middle {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.main table td[colspan="2"] a {
|
||||
font-weight: normal;
|
||||
}
|
||||
.main table td em {
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.main h3 {
|
||||
font-weight: normal;
|
||||
margin-top: 0.5em !important;
|
||||
}
|
||||
.main h3 span {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.main h3 span.label {
|
||||
color: #6435c9;
|
||||
}
|
||||
.main h3 a {
|
||||
margin-left: 1em;
|
||||
font-size: 14px !important;
|
||||
right: 1em;
|
||||
}
|
||||
.main h3 a::before {
|
||||
content: "[";
|
||||
}
|
||||
.main h3 a::after {
|
||||
content: "]";
|
||||
}
|
||||
.main h4 {
|
||||
font-weight: normal;
|
||||
}
|
||||
.main td span.small {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.main .button.mini {
|
||||
font-size: 0.8em;
|
||||
padding: 0.2em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
/** 右侧文本子菜单 **/
|
||||
.text.menu {
|
||||
overflow-x: auto;
|
||||
}
|
||||
.text.menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
}
|
||||
/** Vue **/
|
||||
[v-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
/** auto complete **/
|
||||
.autocomplete-box .menu {
|
||||
background: #eee !important;
|
||||
}
|
||||
.autocomplete-box .menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.autocomplete-box .menu .item {
|
||||
border-top: none !important;
|
||||
}
|
||||
select.auto-width {
|
||||
width: auto !important;
|
||||
}
|
||||
/** column **/
|
||||
@media screen and (max-width: 512px) {
|
||||
.column:not(.one) {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
/** label **/
|
||||
label[for] {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
label.blue {
|
||||
color: #2185d0 !important;
|
||||
}
|
||||
/** Menu **/
|
||||
.first-menu .menu.text {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.first-menu .divider {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.second-menu .menu.text {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.second-menu .menu.text em {
|
||||
font-style: normal;
|
||||
}
|
||||
.second-menu .divider {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
.menu a {
|
||||
outline: none;
|
||||
}
|
||||
/** var **/
|
||||
span.olive,
|
||||
var.olive {
|
||||
color: #b5cc18 !important;
|
||||
}
|
||||
span.dash {
|
||||
border-bottom: 1px dashed grey;
|
||||
}
|
||||
span.hover:hover {
|
||||
background: #eee;
|
||||
}
|
||||
/** Message **/
|
||||
.message .gopher {
|
||||
width: 30px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
/** checkbox **/
|
||||
.checkbox label a,
|
||||
.checkbox label {
|
||||
font-size: 0.8em !important;
|
||||
}
|
||||
/** page **/
|
||||
.page {
|
||||
margin-top: 1em;
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
.page a {
|
||||
display: inline-block;
|
||||
background: #fafafa;
|
||||
color: #666;
|
||||
padding: 6px 12px;
|
||||
margin: 0;
|
||||
font-size: 0.9em;
|
||||
border: 1px solid #ddd;
|
||||
border-left: 0;
|
||||
}
|
||||
.page a.active {
|
||||
background: #2185d0 !important;
|
||||
color: white;
|
||||
}
|
||||
.page a:hover {
|
||||
background: #eee;
|
||||
}
|
||||
.page select {
|
||||
padding-top: 0.3em !important;
|
||||
padding-bottom: 0.3em !important;
|
||||
}
|
||||
.swal2-html-container {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.swal2-confirm:focus,
|
||||
.swal2-cancel:focus,
|
||||
.swal2-close:focus {
|
||||
border: 3px #ddd solid !important;
|
||||
}
|
||||
.swal2-confirm,
|
||||
.swal2-cancel,
|
||||
.swal2-close {
|
||||
border: 3px #fff solid !important;
|
||||
}
|
||||
.swal2-cancel {
|
||||
margin-left: 2em !important;
|
||||
}
|
||||
input.error {
|
||||
border: 1px #e0b4b4 solid !important;
|
||||
}
|
||||
textarea.wide-code {
|
||||
font-family: Menlo, Monaco, "Courier New", monospace !important;
|
||||
line-height: 1.6 !important;
|
||||
}
|
||||
.combo-box .menu {
|
||||
max-height: 17em;
|
||||
overflow-y: auto;
|
||||
position: absolute;
|
||||
border: rgba(129, 177, 210, 0.81) 1px solid;
|
||||
border-top: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
.combo-box .menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
code-label {
|
||||
background: #fff;
|
||||
border: 1px solid rgba(34, 36, 38, 0.15);
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
font-size: 0.71428571rem;
|
||||
padding: 3px;
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
font-weight: 700;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/*# sourceMappingURL=@layout_popup.css.map */
|
||||
1
EdgeAdmin/web/views/@default/@layout_popup.css.map
Normal file
1
EdgeAdmin/web/views/@default/@layout_popup.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["@layout_popup.less"],"names":[],"mappings":";AACA;EACC,+CAAA;EACA,qBAAA;;AAGD;EACC,WAAA;;AAGD;EACC,aAAA;;AAGD;EACC,qBAAA;;AAGD,CAAC;AAAW,CAAC,SAAS;AAAQ,CAAC,SAAS;AAAS,IAAI;EACpD,WAAA;;AAGD,CAAC;AAAU,IAAI;AAAU,IAAI;EAC5B,cAAA;;AAGD,IAAI;AAAO,KAAK;AAAO,CAAC;EACvB,sBAAA;;AAGD,CAAC;EACA,iBAAA;;AAGD,IAAI;AAAM,GAAG;EACZ,cAAA;;AAGD,IAAI;EACH,cAAA;;AAGD,GAAG,IAAI;EACN,mBAAmB,8CAAnB;;AAGD;EACC,uBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAM;EACL,sBAAA;;AAGD,MAAO;AAAI,MAAO;EACjB,gBAAA;;AAGD,CAAC;AAAU,GAAG;EACb,cAAA;EACA,kBAAA;EACA,mBAAA;EACA,qBAAA;EACA,gBAAA;;AAGD,CAAC,QAAS;AAAI,GAAG,QAAS;EACzB,6BAAA;;AAGD;EACC,mBAAA;EACA,2BAAA;EACA,gBAAA;EACA,uBAAA;;AAGD,GAAG;AAAS,CAAC;EACZ,eAAA;;;AAID,GAAG;EACF,UAAA;;AAGD,GAAG;EACF,YAAA;;AAGD,GAAG;EACF,UAAA;;AAGD,GAAG;EACF,WAAA;;;AAID,MAAM;EACL,cAAA;;;AAID;EACC,kBAAA;EACA,UAAA;EACA,UAAA;EACA,mBAAA;EACA,kBAAA;EACA,UAAA;;AAGD,mBAAqC;EACpC;IACC,SAAA;;;AAIF,KAAK;EACJ,SAAA;;AAGD,KAAK;EACJ,UAAA;;AAGD,mBAAqC;EACpC,KAAK;IACJ,SAAA;;;AAIF,KAAM,MAAM,GAAE;EACb,WAAA;;AAGD,KAAM,MAAM,GAAE;EACb,WAAA;;AAGD,KAAM,MAAM;EACX,mBAAA;;AAGD,KAAM,GAAE;EACP,8BAAA;;AAGD,KAAM,MAAM,GAAE;EACb,mBAAA;;AAGD,KAAM,MAAM,GAAE;EACb,sBAAA;;AAGD,KAAM,MAAM,GAAE,aAAc;EAC3B,mBAAA;;AAGD,KAAM,MAAM,GAAG;EACd,mBAAA;EACA,kBAAA;EACA,gBAAA;;AAGD,KAAM;EACL,mBAAA;EACA,iBAAA;;AAGD,KAAM,GAAG;EACR,gBAAA;;AAGD,KAAM,GAAG,KAAI;EACZ,cAAA;;AAGD,KAAM,GAAG;EACR,gBAAA;EACA,0BAAA;EACA,UAAA;;AAGD,KAAM,GAAG,EAAC;EACT,SAAS,GAAT;;AAGD,KAAM,GAAG,EAAC;EACT,SAAS,GAAT;;AAGD,KAAM;EACL,mBAAA;;AAGD,KAAM,GAAG,KAAI;EACZ,gBAAA;;AAGD,KAAM,QAAO;EACZ,gBAAA;EACA,cAAA;EACA,gBAAA;;;AAID,KAAK;EACJ,gBAAA;;AAGD,KAAK,KAAK;EACT,UAAA;EACA,WAAA;;;AAID;EACC,wBAAA;;;AAID,iBAAkB;EACjB,gBAAA;;AAGD,iBAAkB,MAAK;EACtB,UAAA;;AAGD,iBAAkB,MAAM;EACvB,2BAAA;;AAGD,MAAM;EACL,sBAAA;;;AAID,mBAAqC;EACpC,OAAO,IAAI;IACV,sBAAA;;;;AAKF,KAAK;EACJ,0BAAA;;AAGD,KAAK;EACJ,cAAA;;;AAOD,WAAY,MAAK;EAChB,wBAAA;EACA,2BAAA;;AAGD,WAAY;EACX,wBAAA;EACA,2BAAA;;AAGD,YAAa,MAAK;EACjB,wBAAA;EACA,2BAAA;;AAGD,YAAa,MAAK,KAAM;EACvB,kBAAA;;AAGD,YAAa;EACZ,wBAAA;;AAGD,KAAM;EACL,aAAA;;;AAID,IAAI;AAAQ,GAAG;EACd,cAAA;;AAGD,IAAI;EACH,8BAAA;;AAGD,IAAI,MAAM;EACT,gBAAA;;;AAID,QAAS;EACR,WAAA;EACA,kBAAA;;;AAID,SAAU,MAAM;AAAG,SAAU;EAC5B,gBAAA;;;AAID;EACC,eAAA;EAEA,2BAAA;;AAHD,KAKC;EACC,qBAAA;EACA,mBAAA;EACA,WAAA;EACA,iBAAA;EACA,SAAA;EACA,gBAAA;EACA,sBAAA;EACA,cAAA;;AAbF,KAgBC,EAAC;EACA,mBAAA;EACA,YAAA;;AAlBF,KAqBC,EAAC;EACA,gBAAA;;AAtBF,KAyBC;EACC,kBAAA;EACA,qBAAA;;AAKF;EACC,kBAAA;;AAGD,cAAc;AAAQ,aAAa;AAAQ,YAAY;EACtD,sBAAA;;AAGD;AAAgB;AAAe;EAC9B,sBAAA;;AAGD;EACC,2BAAA;;AAID,KAAK;EACJ,yBAAA;;AAID,QAAQ;EACP,4BAA4B,wBAA5B;EACA,gBAAA;;AAID,UAAW;EACV,gBAAA;EACA,gBAAA;EACA,kBAAA;EACA,2CAAA;EACA,aAAA;EACA,YAAA;;AAGD,UAAW,MAAK;EACf,UAAA;;AAID;EACC,gBAAA;EACA,wCAAA;EACA,0BAAA;EACA,wBAAA;EACA,YAAA;EACA,gBAAA;EACA,iBAAA;EACA,cAAA;EACA,qBAAA;EACA,gBAAA;EACA,wBAAA","file":"@layout_popup.css"}
|
||||
50
EdgeAdmin/web/views/@default/@layout_popup.html
Normal file
50
EdgeAdmin/web/views/@default/@layout_popup.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{$ htmlEncode .teaTitle}控制台</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
|
||||
{$if eq .teaFaviconFileId 0}
|
||||
<link rel="shortcut icon" href="/images/favicon.png"/>
|
||||
{$else}
|
||||
<link rel="shortcut icon" href="/ui/image/{$.teaFaviconFileId}"/>
|
||||
{$end}
|
||||
<link rel="stylesheet" type="text/css" href="/_/@default/@layout_popup.css" media="all"/>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/css/semantic.iframe.min.css?v=bRafhK" media="all"/>
|
||||
{$TEA.VUE}
|
||||
<link rel="stylesheet" type="text/css" href="/_/@default/@layout_override.css" media="all"/>
|
||||
{$echo "header"}
|
||||
<script type="text/javascript" src="/_/@default/@layout.js"></script>
|
||||
<script type="text/javascript" src="/js/components.js"></script>
|
||||
<script type="text/javascript" src="/js/utils.min.js"></script>
|
||||
<script type="text/javascript" src="/js/sweetalert2/dist/sweetalert2.all.min.js"></script>
|
||||
<script type="text/javascript" src="/js/date.tea.js"></script>
|
||||
<script type="text/javascript" src="/js/langs/{$.teaLang}.js?v=1.2.0"></script>
|
||||
<style type="text/css">
|
||||
.main {
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.main::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
window.IS_POPUP = true
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="main">
|
||||
<!-- 功能区 -->
|
||||
{$TEA.VIEW}
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
407
EdgeAdmin/web/views/@default/@layout_popup.less
Normal file
407
EdgeAdmin/web/views/@default/@layout_popup.less
Normal file
@@ -0,0 +1,407 @@
|
||||
/** 通用 **/
|
||||
* {
|
||||
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
a.disabled, a.disabled:hover, a.disabled:active, span.disabled {
|
||||
color: #ccc !important;
|
||||
}
|
||||
|
||||
a.enabled, span.enabled, span.green {
|
||||
color: #21ba45;
|
||||
}
|
||||
|
||||
span.grey, label.grey, p.grey {
|
||||
color: grey !important;
|
||||
}
|
||||
|
||||
p.grey {
|
||||
margin-top: 0.8em;
|
||||
}
|
||||
|
||||
span.red, pre.red {
|
||||
color: #db2828;
|
||||
}
|
||||
|
||||
span.blue {
|
||||
color: #4183c4;
|
||||
}
|
||||
|
||||
pre:not(.CodeMirror-line) {
|
||||
font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif !important;
|
||||
}
|
||||
|
||||
tbody {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.table.width30 {
|
||||
width: 30em !important;
|
||||
}
|
||||
|
||||
.table.width35 {
|
||||
width: 35em !important;
|
||||
}
|
||||
|
||||
.table.width40 {
|
||||
width: 40em !important;
|
||||
}
|
||||
|
||||
.table th, .table td {
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
|
||||
p.comment, div.comment {
|
||||
color: #959da6;
|
||||
padding-top: 0.4em;
|
||||
font-weight: normal;
|
||||
word-break: break-all;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
p.comment em, div.comment em {
|
||||
font-style: italic !important;
|
||||
}
|
||||
|
||||
.truncate {
|
||||
white-space: nowrap;
|
||||
-ms-text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
div.margin, p.margin {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
/** 操作按钮容器 **/
|
||||
.op.one {
|
||||
width: 4em;
|
||||
}
|
||||
|
||||
.op.two {
|
||||
width: 7.4em;
|
||||
}
|
||||
|
||||
.op.three {
|
||||
width: 9em;
|
||||
}
|
||||
|
||||
.op.four {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
/** 扩展UI **/
|
||||
.field.text {
|
||||
padding: .5em;
|
||||
}
|
||||
|
||||
/** 右侧主操作区 **/
|
||||
.main {
|
||||
position: absolute;
|
||||
left: 22em;
|
||||
top: 5.6em;
|
||||
padding-bottom: 5em;
|
||||
padding-right: 1em;
|
||||
right: 1em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.main {
|
||||
left: 4em;
|
||||
}
|
||||
}
|
||||
|
||||
.main.without-menu {
|
||||
left: 9em;
|
||||
}
|
||||
|
||||
.main.without-secondary-menu {
|
||||
top: 2.9em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.main.without-menu {
|
||||
left: 4em;
|
||||
}
|
||||
}
|
||||
|
||||
.main table td.title {
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
.main table td.middle-title {
|
||||
width: 14em;
|
||||
}
|
||||
|
||||
.main table td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table td.color-border {
|
||||
border-left: 1px #276ac6 solid !important;
|
||||
}
|
||||
|
||||
.main table td.vertical-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.main table td.vertical-middle {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.main table td[colspan="2"] a {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.main table td em {
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.main h3 {
|
||||
font-weight: normal;
|
||||
margin-top: 0.5em !important;
|
||||
}
|
||||
|
||||
.main h3 span {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.main h3 span.label {
|
||||
color: #6435c9;
|
||||
}
|
||||
|
||||
.main h3 a {
|
||||
margin-left: 1em;
|
||||
font-size: 14px !important;
|
||||
right: 1em;
|
||||
}
|
||||
|
||||
.main h3 a::before {
|
||||
content: "[";
|
||||
}
|
||||
|
||||
.main h3 a::after {
|
||||
content: "]";
|
||||
}
|
||||
|
||||
.main h4 {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.main td span.small {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.main .button.mini {
|
||||
font-size: 0.8em;
|
||||
padding: 0.2em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
/** 右侧文本子菜单 **/
|
||||
.text.menu {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.text.menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
/** Vue **/
|
||||
[v-cloak] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/** auto complete **/
|
||||
.autocomplete-box .menu {
|
||||
background: #eee !important;
|
||||
}
|
||||
|
||||
.autocomplete-box .menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.autocomplete-box .menu .item {
|
||||
border-top: none !important;
|
||||
}
|
||||
|
||||
select.auto-width {
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
/** column **/
|
||||
@media screen and (max-width: 512px) {
|
||||
.column:not(.one) {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
/** label **/
|
||||
label[for] {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
label.blue {
|
||||
color: #2185d0 !important;
|
||||
}
|
||||
|
||||
td .label.tiny {
|
||||
}
|
||||
|
||||
/** Menu **/
|
||||
.first-menu .menu.text {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.first-menu .divider {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.second-menu .menu.text {
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.second-menu .menu.text em {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.second-menu .divider {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.menu a {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/** var **/
|
||||
span.olive, var.olive {
|
||||
color: #b5cc18 !important;
|
||||
}
|
||||
|
||||
span.dash {
|
||||
border-bottom: 1px dashed grey;
|
||||
}
|
||||
|
||||
span.hover:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
/** Message **/
|
||||
.message .gopher {
|
||||
width: 30px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/** checkbox **/
|
||||
.checkbox label a, .checkbox label {
|
||||
font-size: 0.8em !important;
|
||||
}
|
||||
|
||||
/** page **/
|
||||
.page {
|
||||
margin-top: 1em;
|
||||
|
||||
border-left: 1px solid #ddd;
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
background: #fafafa;
|
||||
color: #666;
|
||||
padding: 6px 12px;
|
||||
margin: 0;
|
||||
font-size: 0.9em;
|
||||
border: 1px solid #ddd;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
a.active {
|
||||
background: #2185d0 !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
select {
|
||||
padding-top: 0.3em !important;
|
||||
padding-bottom: 0.3em !important;
|
||||
}
|
||||
}
|
||||
|
||||
// popup
|
||||
.swal2-html-container {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.swal2-confirm:focus, .swal2-cancel:focus, .swal2-close:focus {
|
||||
border: 3px #ddd solid !important;
|
||||
}
|
||||
|
||||
.swal2-confirm, .swal2-cancel, .swal2-close {
|
||||
border: 3px #fff solid !important;
|
||||
}
|
||||
|
||||
.swal2-cancel {
|
||||
margin-left: 2em !important;
|
||||
}
|
||||
|
||||
// input
|
||||
input.error {
|
||||
border: 1px #e0b4b4 solid !important;
|
||||
}
|
||||
|
||||
// textarea
|
||||
textarea.wide-code {
|
||||
font-family: Menlo, Monaco, "Courier New", monospace !important;
|
||||
line-height: 1.6 !important;
|
||||
}
|
||||
|
||||
// combo-box
|
||||
.combo-box .menu {
|
||||
max-height: 17em;
|
||||
overflow-y: auto;
|
||||
position: absolute;
|
||||
border: rgba(129, 177, 210, 0.81) 1px solid;
|
||||
border-top: 0;
|
||||
z-index: 100
|
||||
}
|
||||
|
||||
.combo-box .menu::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
// code-label
|
||||
code-label {
|
||||
background: #fff;
|
||||
border: 1px solid rgba(34, 36, 38, .15);
|
||||
color: rgba(0, 0, 0, .87);
|
||||
font-size: .71428571rem;
|
||||
padding: 3px;
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
line-height: 1;
|
||||
display: inline-block;
|
||||
font-weight: 700;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
113
EdgeAdmin/web/views/@default/@left_menu.css
Normal file
113
EdgeAdmin/web/views/@default/@left_menu.css
Normal file
@@ -0,0 +1,113 @@
|
||||
.left-box {
|
||||
width: 8em;
|
||||
position: fixed;
|
||||
top: 7.5em;
|
||||
bottom: 2.4em;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
border-right: 1px #ddd solid;
|
||||
}
|
||||
.left-box .menu {
|
||||
width: 90% !important;
|
||||
}
|
||||
.left-box .menu .item {
|
||||
line-height: 1.2;
|
||||
position: relative;
|
||||
padding-left: 1em !important;
|
||||
}
|
||||
.left-box .menu .item .icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
margin-top: -0.4em !important;
|
||||
}
|
||||
.left-box .menu .item.separator {
|
||||
border-bottom: 1px #eee solid !important;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
.left-box .menu .item.on span {
|
||||
border-bottom: 1px #666 dashed;
|
||||
}
|
||||
.left-box .menu .item.off span var {
|
||||
font-style: normal;
|
||||
background: #db2828;
|
||||
color: white;
|
||||
font-size: 8px;
|
||||
padding: 2px;
|
||||
border-radius: 2px;
|
||||
margin-left: 1em;
|
||||
}
|
||||
.left-box .menu .header {
|
||||
border-bottom: 1px #ddd solid;
|
||||
padding-left: 0 !important;
|
||||
padding-bottom: 1em !important;
|
||||
}
|
||||
.left-box::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.left-box.disabled {
|
||||
opacity: 0.1;
|
||||
}
|
||||
.left-box.tiny {
|
||||
top: 10em;
|
||||
}
|
||||
.left-box.without-tabbar {
|
||||
top: 3em;
|
||||
}
|
||||
.left-box.with-menu {
|
||||
top: 8.7em;
|
||||
}
|
||||
.left-box.without-menu {
|
||||
top: 6em;
|
||||
}
|
||||
.right-box {
|
||||
position: fixed;
|
||||
top: 7em;
|
||||
bottom: 1.3em;
|
||||
right: 0;
|
||||
left: 18em;
|
||||
padding-right: 2em;
|
||||
padding-bottom: 2em;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.right-box h4:first-child {
|
||||
margin-top: 1em;
|
||||
}
|
||||
.right-box > .comment:first-child {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
@media screen and (max-width: 512px) {
|
||||
.right-box {
|
||||
left: 13em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
}
|
||||
body.expanded .right-box {
|
||||
left: 10em;
|
||||
}
|
||||
.right-box.tiny {
|
||||
top: 10em;
|
||||
left: 26.5em;
|
||||
}
|
||||
.right-box::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
.right-box.without-tabbar {
|
||||
top: 3em;
|
||||
}
|
||||
.right-box.with-menu {
|
||||
top: 8.6em;
|
||||
}
|
||||
.right-box.without-menu {
|
||||
top: 6em;
|
||||
}
|
||||
.main.without-footer .left-box {
|
||||
bottom: 0.2em;
|
||||
}
|
||||
.narrow-scrollbar::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
/*# sourceMappingURL=@left_menu.css.map */
|
||||
1
EdgeAdmin/web/views/@default/@left_menu.css.map
Normal file
1
EdgeAdmin/web/views/@default/@left_menu.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["@left_menu.less"],"names":[],"mappings":"AAAA;EACC,UAAA;EACA,eAAA;EACA,UAAA;EACA,aAAA;EACA,gBAAA;EACA,kBAAA;EACA,4BAAA;;AAPD,SASC;EACC,qBAAA;;AAVF,SASC,MAGC;EACC,gBAAA;EACA,kBAAA;EACA,4BAAA;;AAfH,SASC,MAGC,MAKC;EACC,kBAAA;EACA,QAAA;EACA,OAAA;EACA,kBAAA;;AArBJ,SASC,MAgBC,MAAK;EACJ,6BAAA;EACA,cAAA;EACA,iBAAA;EACA,wBAAA;EACA,2BAAA;;AA9BH,SASC,MAwBC,MAAK,GACJ;EACC,8BAAA;;AAnCJ,SASC,MA8BC,MAAK,IACJ,KACC;EACC,kBAAA;EACA,mBAAA;EACA,YAAA;EACA,cAAA;EACA,YAAA;EACA,kBAAA;EACA,gBAAA;;AAhDL,SASC,MA6CC;EACC,6BAAA;EACA,0BAAA;EACA,8BAAA;;AAQH,SAAS;EACR,UAAA;;AAGD,SAAS;EACR,YAAA;;AAGD,SAAS;EACR,SAAA;;AAGD,SAAS;EACR,QAAA;;AAGD,SAAS;EACR,UAAA;;AAGD,SAAS;EACR,QAAA;;AAGD;EACC,eAAA;EACA,QAAA;EACA,aAAA;EACA,QAAA;EACA,UAAA;EACA,kBAAA;EACA,mBAAA;EACA,gBAAA;;AARD,UAUC,GAAE;EACD,eAAA;;AAIF,UAAW,WAAU;EACpB,iBAAA;;AAGD,mBAAqC;EACpC;IACC,UAAA;IACA,kBAAA;;;AAIF,IAAI,SAAU;EACb,UAAA;;AAGD,UAAU;EACT,SAAA;EACA,YAAA;;AAGD,UAAU;EACT,UAAA;;AAGD,UAAU;EACT,QAAA;;AAGD,UAAU;EACT,UAAA;;AAGD,UAAU;EACT,QAAA;;AAID,KAAK,eAAgB;EACpB,aAAA;;AAID,iBAAiB;EAChB,UAAA","file":"@left_menu.css"}
|
||||
9
EdgeAdmin/web/views/@default/@left_menu.html
Normal file
9
EdgeAdmin/web/views/@default/@left_menu.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<div class="margin"></div>
|
||||
|
||||
<div class="left-box" :class="{disabled:leftMenuItemIsDisabled}">
|
||||
<div class="ui menu text blue vertical small">
|
||||
<a class="item" v-for="item in leftMenuItems" :href="item.url" :class="{active:item.isActive, separator:item.name == '-', on:item.isOn, off:item.isOff||item.isImportant, 'has-divider':item.hasDivider}" :style="item.isActive ? 'background: rgba(230, 230, 230, 0.35) !important; border-radius: 3px;' : ''">
|
||||
<span v-if="item.name != '-'"><i class="icon play tiny" :style="{'visibility':item.isActive ? 'visible' : 'hidden'}"></i>{{item.name}}<var v-if="item.isOff">关</var><var v-if="item.isImportant">开</var></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
157
EdgeAdmin/web/views/@default/@left_menu.less
Normal file
157
EdgeAdmin/web/views/@default/@left_menu.less
Normal file
@@ -0,0 +1,157 @@
|
||||
.left-box {
|
||||
width: 8.5em;
|
||||
position: fixed;
|
||||
top: 7.5em;
|
||||
bottom: 2.4em;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
border-right: 1px #ddd solid;
|
||||
|
||||
.menu {
|
||||
width: 95% !important;
|
||||
|
||||
.item {
|
||||
line-height: 1.2;
|
||||
position: relative;
|
||||
padding-left: 1em !important;
|
||||
|
||||
.icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
margin-top: -0.4em !important;
|
||||
}
|
||||
}
|
||||
|
||||
.item.separator {
|
||||
border-bottom: 1px #eee solid !important;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.item.on {
|
||||
span {
|
||||
border-bottom: 1px #666 dashed;
|
||||
}
|
||||
}
|
||||
|
||||
.item.off {
|
||||
span {
|
||||
var {
|
||||
font-style: normal;
|
||||
background: #db2828;
|
||||
color: white;
|
||||
font-size: 8px;
|
||||
padding: 2px;
|
||||
border-radius: 2px;
|
||||
margin-left: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 菜单项底部虚线(参考 separator 的实现)
|
||||
.item.has-divider {
|
||||
border-bottom: 1px dashed #ddd !important;
|
||||
margin-bottom: 0.3em !important;
|
||||
}
|
||||
|
||||
// .header需要在.item下面
|
||||
.header {
|
||||
border-bottom: 1px #ddd solid;
|
||||
padding-left: 0 !important;
|
||||
padding-bottom: 1em !important;
|
||||
}
|
||||
|
||||
.item.active {
|
||||
background: rgba(230, 230, 230, 0.35) !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.left-box::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.left-box.disabled {
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.left-box.tiny {
|
||||
top: 10em;
|
||||
}
|
||||
|
||||
.left-box.without-tabbar {
|
||||
top: 3em;
|
||||
}
|
||||
|
||||
.left-box.with-menu {
|
||||
top: 8.7em;
|
||||
}
|
||||
|
||||
.left-box.without-menu {
|
||||
top: 6em;
|
||||
}
|
||||
|
||||
.right-box {
|
||||
position: fixed;
|
||||
top: 7em;
|
||||
bottom: 1.3em;
|
||||
right: 0;
|
||||
left: 18em;
|
||||
padding-right: 2em;
|
||||
padding-bottom: 2em;
|
||||
overflow-y: auto;
|
||||
|
||||
h4:first-child {
|
||||
margin-top: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.right-box > .comment:first-child {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 512px) {
|
||||
.right-box {
|
||||
left: 13em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
body.expanded .right-box {
|
||||
left: 10em;
|
||||
}
|
||||
|
||||
.right-box.tiny {
|
||||
top: 10em;
|
||||
left: 26.5em;
|
||||
}
|
||||
|
||||
.right-box::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.right-box.without-tabbar {
|
||||
top: 3em;
|
||||
}
|
||||
|
||||
.right-box.with-menu {
|
||||
top: 8.6em;
|
||||
}
|
||||
|
||||
.right-box.without-menu {
|
||||
top: 6em;
|
||||
}
|
||||
|
||||
// main
|
||||
.main.without-footer .left-box {
|
||||
bottom: 0.2em;
|
||||
}
|
||||
|
||||
// scrollbar
|
||||
.narrow-scrollbar::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
9
EdgeAdmin/web/views/@default/@left_menu_top.html
Normal file
9
EdgeAdmin/web/views/@default/@left_menu_top.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<div class="margin"></div>
|
||||
|
||||
<div class="left-box without-tabbar" :class="{disabled:leftMenuItemIsDisabled}">
|
||||
<div class="ui menu text blue vertical small">
|
||||
<a class="item" v-for="item in leftMenuItems" :href="item.url" :class="{active:item.isActive, separator:item.name == '-', on:item.isOn, off:item.isOff||item.isImportant}">
|
||||
<span v-if="item.name != '-'"><i class="icon play tiny" :style="{'visibility':item.isActive ? 'visible' : 'hidden'}"></i>{{item.name}}<var v-if="item.isOff">关</var><var v-if="item.isImportant">开</var></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
9
EdgeAdmin/web/views/@default/@left_menu_with_menu.html
Normal file
9
EdgeAdmin/web/views/@default/@left_menu_with_menu.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<div class="margin"></div>
|
||||
|
||||
<div class="left-box with-menu" :class="{disabled:leftMenuItemIsDisabled}">
|
||||
<div class="ui menu text blue vertical small">
|
||||
<a class="item" v-for="item in leftMenuItems" :href="item.url" :class="{active:item.isActive, separator:item.name == '-', on:item.isOn, off:item.isOff||item.isImportant}">
|
||||
<span v-if="item.name != '-'"><i class="icon play tiny" :style="{'visibility':item.isActive ? 'visible' : 'hidden'}"></i>{{item.name}}<var v-if="item.isOff">关</var><var v-if="item.isImportant">开</var></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="margin"></div>
|
||||
|
||||
<div class="left-box without-menu" :class="{disabled:leftMenuItemIsDisabled}">
|
||||
<div class="ui menu text blue vertical small">
|
||||
<a class="item" v-for="item in leftMenuItems" :href="item.url" :class="{active:item.isActive, separator:item.name == '-', on:item.isOn, off:item.isOff||item.isImportant}">
|
||||
<span v-if="item.name != '-'"><i class="icon play tiny" :style="{'visibility':item.isActive ? 'visible' : 'hidden'}"></i>{{item.name}}<var v-if="item.isOff">关</var><var v-if="item.isImportant">开</var></span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
1
EdgeAdmin/web/views/@default/@menu.html
Normal file
1
EdgeAdmin/web/views/@default/@menu.html
Normal file
@@ -0,0 +1 @@
|
||||
<!-- 预留的菜单位置 -->
|
||||
7
EdgeAdmin/web/views/@default/admins/@admin_menu.html
Normal file
7
EdgeAdmin/web/views/@default/admins/@admin_menu.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<first-menu>
|
||||
<menu-item href="/admins">系统用户</menu-item>
|
||||
<span class="item">|</span>
|
||||
<menu-item :href="'/admins/admin?adminId=' + admin.id" code="index">"{{admin.fullname}}" 详情</menu-item>
|
||||
<menu-item :href="'/admins/update?adminId=' + admin.id" code="update">修改</menu-item>
|
||||
<menu-item :href="'/admins/accesskeys?adminId=' + admin.id" code="accessKey">API AccessKey({{admin.countAccessKeys}})</menu-item>
|
||||
</first-menu>
|
||||
3
EdgeAdmin/web/views/@default/admins/@menu.html
Normal file
3
EdgeAdmin/web/views/@default/admins/@menu.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<first-menu>
|
||||
<menu-item @click.prevent="createAdmin">[创建管理员]</menu-item>
|
||||
</first-menu>
|
||||
@@ -0,0 +1,28 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>创建新AccessKey</h3>
|
||||
|
||||
<form class="ui form" method="post" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="adminId" :value="adminId"/>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">AccessKey ID</td>
|
||||
<td><span class="disabled">自动生成</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AccessKey密钥</td>
|
||||
<td><span class="disabled">自动生成</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">备注 *</td>
|
||||
<td>
|
||||
<textarea rows="2" name="description" maxlength="100" ref="focus"></textarea>
|
||||
<p class="comment">描述AccessKey的用途等。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
39
EdgeAdmin/web/views/@default/admins/accesskeys/index.html
Normal file
39
EdgeAdmin/web/views/@default/admins/accesskeys/index.html
Normal file
@@ -0,0 +1,39 @@
|
||||
{$layout}
|
||||
{$template "../admin_menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item @click.prevent="createAccessKey()">[创建AccessKey]</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="accessKeys.length == 0">暂时还没有AccessKey。</p>
|
||||
|
||||
<table class="ui table selectable" v-if="accessKeys.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>AccessKey ID</th>
|
||||
<th>AccessKey密钥</th>
|
||||
<th>备注</th>
|
||||
<th>最后访问</th>
|
||||
<th>状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="accessKey in accessKeys">
|
||||
<td :class="{disabled: !accessKey.isOn}">{{accessKey.uniqueId}}</td>
|
||||
<td :class="{disabled: !accessKey.isOn}">{{accessKey.secret}}</td>
|
||||
<td :class="{disabled: !accessKey.isOn}">{{accessKey.description}}</td>
|
||||
<td :class="{disabled: !accessKey.isOn}">
|
||||
<span v-if="accessKey.accessedTime.length > 0">{{accessKey.accessedTime}}</span>
|
||||
<span v-else class="disabled">尚无访问</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="accessKey.isOn" class="green">已启用</span>
|
||||
<span v-else class="disabled">已禁用</span>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" v-if="accessKey.isOn" @click.prevent="updateAccessKeyIsOn(accessKey.id, false)">禁用</a>
|
||||
<a href="" v-if="!accessKey.isOn" @click.prevent="updateAccessKeyIsOn(accessKey.id, true)">启用</a>
|
||||
<a href="" @click.prevent="deleteAccessKey(accessKey.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
41
EdgeAdmin/web/views/@default/admins/accesskeys/index.js
Normal file
41
EdgeAdmin/web/views/@default/admins/accesskeys/index.js
Normal file
@@ -0,0 +1,41 @@
|
||||
Tea.context(function () {
|
||||
this.createAccessKey = function () {
|
||||
teaweb.popup("/admins/accesskeys/createPopup?adminId=" + this.admin.id, {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.updateAccessKeyIsOn = function (accessKeyId, isOn) {
|
||||
let that = this
|
||||
|
||||
let message = ""
|
||||
if (isOn) {
|
||||
message = "确定要启用此AccessKey吗?"
|
||||
} else {
|
||||
message = "确定要禁用此AccessKey吗?"
|
||||
}
|
||||
teaweb.confirm(message, function () {
|
||||
that.$post(".updateIsOn")
|
||||
.params({
|
||||
accessKeyId: accessKeyId,
|
||||
isOn: isOn ? 1 : 0
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteAccessKey = function (accessKeyId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此AccessKey吗?", function () {
|
||||
that.$post(".delete")
|
||||
.params({
|
||||
accessKeyId: accessKeyId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
})
|
||||
7
EdgeAdmin/web/views/@default/admins/admin.css
Normal file
7
EdgeAdmin/web/views/@default/admins/admin.css
Normal file
@@ -0,0 +1,7 @@
|
||||
.modules-box .module-box {
|
||||
float: left;
|
||||
width: 9em;
|
||||
margin-top: 0.3em;
|
||||
margin-bottom: 0.3em;
|
||||
}
|
||||
/*# sourceMappingURL=admin.css.map */
|
||||
1
EdgeAdmin/web/views/@default/admins/admin.css.map
Normal file
1
EdgeAdmin/web/views/@default/admins/admin.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["admin.less"],"names":[],"mappings":"AAAA,YACC;EACC,WAAA;EACA,UAAA;EACA,iBAAA;EACA,oBAAA","file":"admin.css"}
|
||||
75
EdgeAdmin/web/views/@default/admins/admin.html
Normal file
75
EdgeAdmin/web/views/@default/admins/admin.html
Normal file
@@ -0,0 +1,75 @@
|
||||
{$layout}
|
||||
{$template "admin_menu"}
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">全名</td>
|
||||
<td>
|
||||
{{admin.fullname}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>状态</td>
|
||||
<td>
|
||||
<label-on :v-is-on="admin.isOn"></label-on>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>登录用户名</td>
|
||||
<td>
|
||||
{{admin.username}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>允许登录</td>
|
||||
<td>
|
||||
<span class="green" v-if="admin.canLogin">Y</span>
|
||||
<span class="disabled" v-else>N</span>
|
||||
<p class="comment" v-if="admin.canLogin">允许登录当前管理平台。</p>
|
||||
<p class="comment" v-else="">不允许登录当前管理平台。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>超级管理员</td>
|
||||
<td>
|
||||
<span v-if="admin.isSuper" class="green">Y</span>
|
||||
<span v-else class="disabled">N</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="!admin.isSuper">
|
||||
<td>权限</td>
|
||||
<td>
|
||||
<div class="modules-box" v-if="modules.length > 0">
|
||||
<div class="module-box" v-for="module in modules">
|
||||
<i class="icon circle small grey"></i> {{module.name}}
|
||||
</div>
|
||||
</div>
|
||||
<span v-else class="disabled">暂时还没有可以管理的模块。</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3>OTP认证</h3>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">状态</td>
|
||||
<td>
|
||||
<span v-if="otp != null && otp.isOn" class="green">已启用</span>
|
||||
<span v-else class="disabled">未启用</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="otp != null && otp.isOn">
|
||||
<td colspan="2"><more-options-indicator>更多信息</more-options-indicator></td>
|
||||
</tr>
|
||||
<tr v-if="otp != null && otp.isOn && moreOptionsVisible">
|
||||
<td>认证二维码</td>
|
||||
<td>
|
||||
<img alt="qrcode" :src="'./otpQrcode?adminId=' + admin.id"/>
|
||||
<p class="comment"><a :href="'./otpQrcode?adminId=' + admin.id + '&download=true'">[下载]</a> 可以通过二维码快速添加OTP认证信息到认证App中。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="otp != null && otp.isOn && moreOptionsVisible">
|
||||
<td>密钥</td>
|
||||
<td>{{otp.params.secret}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
8
EdgeAdmin/web/views/@default/admins/admin.less
Normal file
8
EdgeAdmin/web/views/@default/admins/admin.less
Normal file
@@ -0,0 +1,8 @@
|
||||
.modules-box {
|
||||
.module-box {
|
||||
float: left;
|
||||
width: 9em;
|
||||
margin-top: 0.3em;
|
||||
margin-bottom: 0.3em;
|
||||
}
|
||||
}
|
||||
7
EdgeAdmin/web/views/@default/admins/createPopup.css
Normal file
7
EdgeAdmin/web/views/@default/admins/createPopup.css
Normal file
@@ -0,0 +1,7 @@
|
||||
.modules-box .module-box {
|
||||
float: left;
|
||||
width: 10em;
|
||||
margin-top: 0.3em;
|
||||
margin-bottom: 0.3em;
|
||||
}
|
||||
/*# sourceMappingURL=createPopup.css.map */
|
||||
1
EdgeAdmin/web/views/@default/admins/createPopup.css.map
Normal file
1
EdgeAdmin/web/views/@default/admins/createPopup.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["createPopup.less"],"names":[],"mappings":"AAAA,YACC;EACC,WAAA;EACA,WAAA;EACA,iBAAA;EACA,oBAAA","file":"createPopup.css"}
|
||||
69
EdgeAdmin/web/views/@default/admins/createPopup.html
Normal file
69
EdgeAdmin/web/views/@default/admins/createPopup.html
Normal file
@@ -0,0 +1,69 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>创建系统用户</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">全名 *</td>
|
||||
<td>
|
||||
<input type="text" name="fullname" maxlength="100" ref="focus"/>
|
||||
<p class="comment">可以输入姓名、公司名等容易识别的名称。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>登录用户名 *</td>
|
||||
<td>
|
||||
<input type="text" name="username" maxlength="100"/>
|
||||
<p class="comment">用户名只能英文、数字、下划线的组合。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>登录密码 *</td>
|
||||
<td>
|
||||
<input type="password" name="pass1" maxlength="100"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>确认登录密码 *</td>
|
||||
<td>
|
||||
<input type="password" name="pass2" maxlength="100"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>允许登录</td>
|
||||
<td>
|
||||
<checkbox name="canLogin" value="1"></checkbox>
|
||||
<p class="comment">选中后,当前管理员才可以登录当前的管理平台。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>超级管理员</td>
|
||||
<td>
|
||||
<checkbox name="isSuper" v-model="isSuper"></checkbox>
|
||||
<p class="comment">选中后,表示当前管理员为超级管理员;超级管理员自动拥有所有的管理权限。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="!isSuper">
|
||||
<td>权限</td>
|
||||
<td>
|
||||
<div class="modules-box">
|
||||
<div class="module-box" v-for="module in modules">
|
||||
<checkbox name="moduleCodes" :v-value="module.code">{{module.name}}</checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>OTP认证</td>
|
||||
<td>
|
||||
<checkbox name="otpOn">启用OTP</checkbox>
|
||||
<p class="comment">启用OTP认证后,在用户登录的时候需要同时填写OTP动态密码。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
3
EdgeAdmin/web/views/@default/admins/createPopup.js
Normal file
3
EdgeAdmin/web/views/@default/admins/createPopup.js
Normal file
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.isSuper = false
|
||||
})
|
||||
8
EdgeAdmin/web/views/@default/admins/createPopup.less
Normal file
8
EdgeAdmin/web/views/@default/admins/createPopup.less
Normal file
@@ -0,0 +1,8 @@
|
||||
.modules-box {
|
||||
.module-box {
|
||||
float: left;
|
||||
width: 10em;
|
||||
margin-top: 0.3em;
|
||||
margin-bottom: 0.3em;
|
||||
}
|
||||
}
|
||||
63
EdgeAdmin/web/views/@default/admins/index.html
Normal file
63
EdgeAdmin/web/views/@default/admins/index.html
Normal file
@@ -0,0 +1,63 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<div class="margin"></div>
|
||||
<form class="ui form" method="get" action="/admins" v-show="!hasWeakPassword">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" placeholder="用户名、全名 ..." v-model="keyword"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button" type="submit">搜索</button>
|
||||
|
||||
<a href="/admins" v-if="keyword.length > 0">[清除条件]</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div v-if="admins.length == 0">
|
||||
<div class="margin"></div>
|
||||
<p class="comment">暂时还没有<span v-if="keyword.length > 0">跟关键词匹配</span>管理员。</p>
|
||||
</div>
|
||||
|
||||
<div v-if="hasWeakPassword">
|
||||
<span class="ui label small basic blue">当前正在筛选弱密码管理员 <a href="/admins"><i class="icon remove small"></i></a></span>
|
||||
</div>
|
||||
|
||||
<table class="ui table selectable" v-show="admins.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>用户名</th>
|
||||
<th>全名</th>
|
||||
<th>允许登录</th>
|
||||
<th>OTP认证</th>
|
||||
<th class="center width10">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="admin in admins">
|
||||
<td :class="{disabled:!admin.isOn}"><a :href="'/admins/admin?adminId=' + admin.id"><keyword :v-word="keyword">{{admin.username}}</keyword></a>
|
||||
<div v-if="admin.isSuper || admin.hasWeakPassword" style="margin-top: 0.5em">
|
||||
<tiny-basic-label class="olive" v-if="admin.isSuper">超级管理员</tiny-basic-label>
|
||||
<a :href="'/admins/update?adminId=' + admin.id" v-if="admin.hasWeakPassword"><tiny-basic-label class="red" title="当前管理员已设置密码为弱密码,有极大的安全风险,请及时修改">弱密码</tiny-basic-label></a>
|
||||
</div>
|
||||
</td>
|
||||
<td :class="{disabled:!admin.isOn}"><keyword :v-word="keyword">{{admin.fullname}}</keyword></td>
|
||||
<td>
|
||||
<span v-if="admin.canLogin" class="green">Y</span>
|
||||
<span v-else class="disabled">N</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="admin.otpLoginIsOn" class="green">Y</span>
|
||||
<span v-else class="disabled">N</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<label-on :v-is-on="admin.isOn"></label-on>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/admins/admin?adminId=' + admin.id">详情</a> <a href="" @click.prevent="deleteAdmin(admin.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
24
EdgeAdmin/web/views/@default/admins/index.js
Normal file
24
EdgeAdmin/web/views/@default/admins/index.js
Normal file
@@ -0,0 +1,24 @@
|
||||
Tea.context(function () {
|
||||
this.createAdmin = function () {
|
||||
teaweb.popup("/admins/createPopup", {
|
||||
height: "30em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteAdmin = function (adminId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除此系统用户吗?", function () {
|
||||
that.$post(".delete")
|
||||
.params({
|
||||
adminId: adminId
|
||||
})
|
||||
.post()
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
<first-menu>
|
||||
<menu-item href="/admins/recipients" code="recipient">接收人</menu-item>
|
||||
<menu-item href="/admins/recipients/groups" code="group">接收人分组</menu-item>
|
||||
<menu-item href="/admins/recipients/instances" code="instance">媒介</menu-item>
|
||||
<menu-item href="/admins/recipients/logs" code="log">发送记录</menu-item>
|
||||
<menu-item href="/admins/recipients/tasks" code="task">任务队列</menu-item>
|
||||
</first-menu>
|
||||
@@ -0,0 +1,7 @@
|
||||
<first-menu>
|
||||
<menu-item href="/admins/recipients">所有接收人</menu-item>
|
||||
<span class="item">|</span>
|
||||
<menu-item :href="'/admins/recipients/recipient?recipientId=' + recipient.id" code="recipient">"{{recipient.admin.fullname}} <span class="small grey">({{recipient.instance.name}})</span>"详情</menu-item>
|
||||
<menu-item :href="'/admins/recipients/update?recipientId=' + recipient.id" code="update">修改</menu-item>
|
||||
<menu-item :href="'/admins/recipients/test?recipientId=' + recipient.id" code="test">测试</menu-item>
|
||||
</first-menu>
|
||||
@@ -0,0 +1,8 @@
|
||||
.clusters-box .checkbox {
|
||||
margin-bottom: 1em;
|
||||
float: left;
|
||||
width: 23%;
|
||||
height: 1.2em;
|
||||
overflow: hidden;
|
||||
}
|
||||
/*# sourceMappingURL=createPopup.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["createPopup.less"],"names":[],"mappings":"AAAA,aACC;EACC,kBAAA;EACA,WAAA;EACA,UAAA;EACA,aAAA;EACA,gBAAA","file":"createPopup.css"}
|
||||
111
EdgeAdmin/web/views/@default/admins/recipients/createPopup.html
Normal file
111
EdgeAdmin/web/views/@default/admins/recipients/createPopup.html
Normal file
@@ -0,0 +1,111 @@
|
||||
{$layout "layout_popup"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<h3>创建接收人</h3>
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">系统用户 *</td>
|
||||
<td>
|
||||
<admin-selector></admin-selector>
|
||||
<p class="comment">选择关联的系统用户。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>媒介 *</td>
|
||||
<td>
|
||||
<message-media-instance-selector @change="changeInstance"></message-media-instance-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>接收人标识</td>
|
||||
<td>
|
||||
<input type="text" name="user" maxlength="300"/>
|
||||
<p class="comment">{{userDescription}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>分组</td>
|
||||
<td>
|
||||
<message-recipient-group-selector></message-recipient-group-selector>
|
||||
<p class="comment">选择当前接收人所属分组。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="nodeClusters.length > 0">
|
||||
<td>关联的边缘节点集群</td>
|
||||
<td>
|
||||
<div class="clusters-box">
|
||||
<checkbox v-for="nodeCluster in nodeClusters" name="nodeClusterIds" :v-value="nodeCluster.id">{{nodeCluster.name}}</checkbox>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>发送时间</td>
|
||||
<td>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
开始时间:
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="timeFromHour" size="2" maxlength="2" placeholder="" v-model="timeFromHour"/>
|
||||
<span class="ui label">时</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="timeFromMinute" size="2" maxlength="2" placeholder="" v-model="timeFromMinute"/>
|
||||
<span class="ui label">分</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="timeFromSecond" size="2" maxlength="2" placeholder="" v-model="timeFromSecond"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
结束时间:
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="timeToHour" size="2" maxlength="2" placeholder="" v-model="timeToHour"/>
|
||||
<span class="ui label">时</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="timeToMinute" size="2" maxlength="2" placeholder="" v-model="timeToMinute"/>
|
||||
<span class="ui label">分</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="timeToSecond" size="2" maxlength="2" placeholder="" v-model="timeToSecond"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="comment">24小时制,即小时从0到23。如果填写了发送时间,系统只会在这个时间段内给当前接收人发送消息。 <a href="" v-if="timeFromHour.length > 0 || timeFromMinute.length > 0 || timeFromSecond.length > 0 || timeToHour.length > 0 || timeToMinute.length > 0 || timeToSecond.length > 0" @click.prevent="clearTime">[清除]</a></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<textarea rows="3" name="description" maxlength="100"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,30 @@
|
||||
Tea.context(function () {
|
||||
this.userDescription = ""
|
||||
|
||||
this.changeInstance = function (instance) {
|
||||
if (instance != null) {
|
||||
this.userDescription = instance.media.userDescription
|
||||
} else {
|
||||
this.userDescription = ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送时间
|
||||
*/
|
||||
this.timeFromHour = ""
|
||||
this.timeFromMinute = ""
|
||||
this.timeFromSecond = ""
|
||||
this.timeToHour = ""
|
||||
this.timeToMinute = ""
|
||||
this.timeToSecond = ""
|
||||
|
||||
this.clearTime = function () {
|
||||
this.timeFromHour = ""
|
||||
this.timeFromMinute = ""
|
||||
this.timeFromSecond = ""
|
||||
this.timeToHour = ""
|
||||
this.timeToMinute = ""
|
||||
this.timeToSecond = ""
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
.clusters-box {
|
||||
.checkbox {
|
||||
margin-bottom: 1em;
|
||||
float: left;
|
||||
width: 23%;
|
||||
height: 1.2em;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>创建接收人分组</h3>
|
||||
|
||||
<form class="ui form" data-tea-success="success" data-tea-action="$">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">分组名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="50" ref="focus"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,28 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item @click.prevent="createGroup">[创建接收人分组]</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="groups.length == 0">暂时还没有分组。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="groups.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>分组名称</th>
|
||||
<th class="two wide">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="group in groups">
|
||||
<td>{{group.name}}</td>
|
||||
<td>
|
||||
<label-on :v-is-on="group.isOn"></label-on>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="updateGroup(group.id)">修改</a>
|
||||
<a href="" @click.prevent="deleteGroup(group.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1,33 @@
|
||||
Tea.context(function () {
|
||||
this.createGroup = function () {
|
||||
teaweb.popup(Tea.url(".createPopup"), {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.updateGroup = function (groupId) {
|
||||
teaweb.popup(Tea.url(".updatePopup", {groupId: groupId}), {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteGroup = function (groupId) {
|
||||
teaweb.confirm("确定要删除此分组吗?", function () {
|
||||
this.$post(".delete")
|
||||
.params({groupId: groupId})
|
||||
.success(function () {
|
||||
teaweb.success("删除成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,15 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
|
||||
<h3>选择分组</h3>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">选择分组</td>
|
||||
<td>
|
||||
<p class="comment" v-if="groups.length == 0">暂时没有可以选择的分组。</p>
|
||||
<div v-if="groups.length > 0">
|
||||
<a class="ui label small basic" v-for="group in groups" @click.prevent="selectGroup(group)">{{group.name}}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1,10 @@
|
||||
Tea.context(function () {
|
||||
this.selectGroup = function (group) {
|
||||
NotifyPopup({
|
||||
code: 200,
|
||||
data: {
|
||||
group: group
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,24 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改接收人分组</h3>
|
||||
|
||||
<form class="ui form" data-tea-success="success" data-tea-action="$">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="groupId" :value="group.id"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">分组名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="50" ref="focus" v-model="group.name"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前分组</td>
|
||||
<td>
|
||||
<checkbox name="isOn" value="1" v-model="group.isOn"></checkbox>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
51
EdgeAdmin/web/views/@default/admins/recipients/index.html
Normal file
51
EdgeAdmin/web/views/@default/admins/recipients/index.html
Normal file
@@ -0,0 +1,51 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item @click.prevent="createRecipient">[创建接收人]</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="recipients.length == 0">暂时还没有媒介接收人。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="recipients.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>系统用户</th>
|
||||
<th>媒介类型</th>
|
||||
<th>接收人标识</th>
|
||||
<th>所属分组</th>
|
||||
<th>备注</th>
|
||||
<th class="width5">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="recipient in recipients">
|
||||
<td><a :href="'/admins/recipients/recipient?recipientId=' + recipient.id">{{recipient.admin.fullname}}</a> <span class="small grey">({{recipient.admin.username}})</span><link-icon :href="'/admins/admin?adminId=' + recipient.admin.id" size="tiny"></link-icon></td>
|
||||
<td>{{recipient.instance.name}}</td>
|
||||
<td>
|
||||
<span v-if="recipient.user.length > 0">{{recipient.user}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<div v-if="recipient.groups != null && recipient.groups.length > 0">
|
||||
<div v-for="group in recipient.groups" class="ui label small basic">{{group.name}}</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span class="disabled">-</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="recipient.description.length > 0">{{recipient.description}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<label-on :v-is-on="recipient.isOn"></label-on>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/admins/recipients/recipient?recipientId=' + recipient.id">详情</a>
|
||||
<a href="" @click.prevent="deleteRecipient(recipient.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
24
EdgeAdmin/web/views/@default/admins/recipients/index.js
Normal file
24
EdgeAdmin/web/views/@default/admins/recipients/index.js
Normal file
@@ -0,0 +1,24 @@
|
||||
Tea.context(function () {
|
||||
this.createRecipient = function () {
|
||||
teaweb.popup(Tea.url(".createPopup"), {
|
||||
height: "27em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteRecipient = function (recipientId) {
|
||||
teaweb.confirm("确定要删除此接收媒介吗?", function () {
|
||||
this.$post(".delete")
|
||||
.params({recipientId: recipientId})
|
||||
.success(function () {
|
||||
teaweb.success("删除成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
<first-menu>
|
||||
<menu-item href="/admins/recipients/instances">所有媒介</menu-item>
|
||||
<span class="item">|</span>
|
||||
<menu-item :href="'/admins/recipients/instances/instance?instanceId=' + instance.id" code="instance">"{{instance.media.name}}"详情</menu-item>
|
||||
<menu-item :href="'/admins/recipients/instances/update?instanceId=' + instance.id" code="update">修改</menu-item>
|
||||
<menu-item :href="'/admins/recipients/instances/test?instanceId=' + instance.id" code="test">测试</menu-item>
|
||||
</first-menu>
|
||||
@@ -0,0 +1,12 @@
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto !important;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
/*# sourceMappingURL=createPopup.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["createPopup.less"],"names":[],"mappings":"AACA;EACC,sBAAA;EACA,uBAAA;;AAGD;EACC,UAAA;EACA,6BAAA;;AAGD,sBAAsB;EACrB,kBAAA","file":"createPopup.css"}
|
||||
@@ -0,0 +1,414 @@
|
||||
{$layout "layout_popup"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<h3>创建媒介</h3>
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">媒介名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" ref="focus" maxlength="100"/>
|
||||
<p class="comment">给当前媒介填写一个容易识别的名称。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border title">媒介类型 *</td>
|
||||
<td>
|
||||
<message-media-selector @change="changeMediaType"></message-media-selector>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- E-mail -->
|
||||
<tbody v-show="mediaType == 'email'">
|
||||
<tr>
|
||||
<td class="color-border">SMTP *</td>
|
||||
<td>
|
||||
<input type="text" name="emailSmtp" maxlength="100" placeholder="类似于 smtp.example.com:465"/>
|
||||
<p class="comment">只支持SSL(或TLS)连接,端口通常为:465或587。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">账号 *</td>
|
||||
<td>
|
||||
<input type="text" name="emailUsername" v-model="emailUsername" maxlength="500" placeholder="类似于 xxx@example.com" @input="changeEmailUsername()"/>
|
||||
<p class="comment">邮箱账号,比如 123456@qq.com<span v-html="emailUsernameHelp"></span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">密码 *</td>
|
||||
<td>
|
||||
<input type="password" name="emailPassword" maxlength="100"/>
|
||||
<p class="comment">账号对应的密码或者授权码(比如QQ邮箱就需要授权码)。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">发送者Email</td>
|
||||
<td>
|
||||
<input type="text" name="emailFrom" maxlength="500" placeholder="类似于 xxx@example.com"/>
|
||||
<p class="comment">默认和账号一致</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- webHook -->
|
||||
<tbody v-show="mediaType == 'webHook'">
|
||||
<tr>
|
||||
<td class="color-border">URL *</td>
|
||||
<td>
|
||||
<input type="text" name="webHookURL" maxlength="500" placeholder="http://..."/>
|
||||
<p class="comment">可以在URL中使用<code-label>${MessageUser}</code-label>、<code-label>${MessageSubject}</code-label>和<code-label>${MessageBody}</code-label>来代表接收人标识、标题和内容。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">请求方法 *</td>
|
||||
<td>
|
||||
<select name="webHookMethod" v-model="webHookMethod" class="ui dropdown" style="width:10em">
|
||||
<option v-for="method in methods" :value="method">{{method}}</option>
|
||||
</select>
|
||||
<p class="comment" v-if="webHookMethod == 'POST'">将以POST方式发送<code-label>${MessageUser}</code-label>、<code-label>${MessageSubject}</code-label>和<code-label>${MessageBody}</code-label>参数,分别代表接收人标识、标题和内容</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="advancedOptionsVisible">
|
||||
<td class="color-border">自定义报头</td>
|
||||
<td>
|
||||
<div class="webHook-headers-box">
|
||||
<span class="ui label small basic" v-for="(header,index) in webHookHeaders">{{header.name}}:{{header.value}}
|
||||
<input type="hidden" name="webHookHeaderNames" :value="header.name"/>
|
||||
<input type="hidden" name="webHookHeaderValues" :value="header.value"/>
|
||||
<a href="" title="删除" @click.prevent="removeWebHookHeader(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<div style="margin-top: 1em">
|
||||
<button class="ui button tiny" type="button" @click.prevent="addWebHookHeader()" v-if="!webHookHeadersAdding">+</button>
|
||||
</div>
|
||||
<div v-if="webHookHeadersAdding" style="margin-top: 1em">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="webHookHeaderName" v-model="webHookHeadersAddingName" size="8" placeholder="名称" maxlength="100" @keyup.enter="confirmWebHookHeadersAdding" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">:</div>
|
||||
<div class="ui field">
|
||||
<input type="text" placeholder="值" v-model="webHookHeadersAddingValue" size="12" maxlength="256" @keyup.enter="confirmWebHookHeadersAdding" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button tiny" type="button" @click.prevent="confirmWebHookHeadersAdding()">确定</button>
|
||||
<a href="" @click.prevent="cancelWebHookHeadersAdding()">取消</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="webHookMethod == 'POST' && advancedOptionsVisible">
|
||||
<td class="color-border">自定义内容</td>
|
||||
<td>
|
||||
<div class="ui menu tabular small attached">
|
||||
<a href="" class="item" :class="{active:webHookContentType == 'params'}" @click.prevent="selectWebHookContentType('params')">参数对</a>
|
||||
<a href="" class="item" :class="{active:webHookContentType == 'body'}" @click.prevent="selectWebHookContentType('body')">文本内容</a>
|
||||
</div>
|
||||
<div class="ui segment attached" v-if="webHookContentType == 'params'">
|
||||
<input type="hidden" name="webHookContentType" value="params"/>
|
||||
<div class="webHook-headers-box">
|
||||
<span class="ui label small basic" v-for="(param,index) in webHookParams">{{param.name}}:{{param.value}}
|
||||
<input type="hidden" name="webHookParamNames" :value="param.name"/>
|
||||
<input type="hidden" name="webHookParamValues" :value="param.value"/>
|
||||
<a href="" title="删除" @click.prevent="removeWebHookParam(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="addWebHookParam()" v-if="!webHookParamsAdding">+</button>
|
||||
<div v-if="webHookParamsAdding">
|
||||
<input type="hidden" name="webHookContentType" value="params"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="webHookParamName" v-model="webHookParamsAddingName" placeholder="名称" maxlength="100" @keyup.enter="confirmWebHookParamsAdding" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">:</div>
|
||||
<div class="ui field">
|
||||
<textarea type="text" placeholder="值" v-model="webHookParamsAddingValue" cols="50" maxlength="1024" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="confirmWebHookParamsAdding()">确认添加</button>
|
||||
<a href="" @click.prevent="cancelWebHookParamsAdding()">取消</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui segment attached" v-if="webHookContentType == 'body'">
|
||||
<input type="hidden" name="webHookContentType" value="body"/>
|
||||
<textarea name="webHookBody" v-model="webHookBody" rows="5" placeholder="发送的内容"></textarea>
|
||||
<p class="comment">
|
||||
内容中可以使用三个变量:<code-label>${MessageUser}</code-label>、<code-label>${MessageSubject}</code-label>和<code-label>${MessageBody}</code-label>参数,分别代表接收人标识、标题和内容
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 脚本 -->
|
||||
<tbody v-show="mediaType == 'script'">
|
||||
<tr>
|
||||
<td class="color-border">脚本 *</td>
|
||||
<td>
|
||||
<input type="hidden" name="scriptType" :value="scriptTab"/>
|
||||
<input type="hidden" name="scriptLang" :value="scriptLang"/>
|
||||
<div class="ui tabular menu attached small">
|
||||
<a class="item" :class="{active:scriptTab == 'path'}" @click.prevent="selectScriptTab('path')">脚本文件</a>
|
||||
<a class="item" :class="{active:scriptTab == 'code'}" @click.prevent="selectScriptTab('code')">脚本代码</a>
|
||||
</div>
|
||||
<div class="ui bottom segment attached" v-show="scriptTab == 'path'">
|
||||
<input type="text" name="scriptPath" maxlength="500"/>
|
||||
<p class="comment">如果是Shell脚本,请不要忘记在头部添加 <em>#!脚本解释工具</em>,比如 <em>#!/bin/bash</em><br/>
|
||||
执行此脚本时,在脚本中可以使用<code-label>${MessageUser}</code-label>、<code-label>${MessageSubject}</code-label>和<code-label>${MessageBody}</code-label>三个环境变量分别代表通知的接收人标识、标题和内容。
|
||||
</p>
|
||||
</div>
|
||||
<div class="ui bottom segment attached" v-show="scriptTab == 'code'" style="padding-top:0">
|
||||
<div class="ui menu text small">
|
||||
<a class="item" v-for="lang in scriptLangs" :class="{active:lang.code == scriptLang}" @click.prevent="selectScriptLang(lang.code)">{{lang.name}}</a>
|
||||
</div>
|
||||
<textarea name="scriptCode" id="script-code-editor" rows="1"></textarea>
|
||||
<p class="comment">如果是Shell脚本,请不要忘记在头部添加 <em>#!脚本解释工具</em>,比如 <em>#!/bin/bash</em><br/>
|
||||
执行此脚本时,在脚本中可以使用<code-label>${MessageUser}</code-label>、<code-label>${MessageSubject}</code-label>和<code-label>${MessageBody}</code-label>三个环境变量分别代表通知的接收人标识、标题和内容。
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="advancedOptionsVisible">
|
||||
<td class="color-border">当前工作目录<em>(CWD)</em></td>
|
||||
<td>
|
||||
<input type="text" name="scriptCwd" maxlength="500"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="advancedOptionsVisible">
|
||||
<td class="color-border">环境变量<em>(ENV)</em></td>
|
||||
<td>
|
||||
<div class="ui field">
|
||||
<span class="ui label small basic" v-for="(var1, index) in env">
|
||||
<input type="hidden" name="scriptEnvNames" :value="var1.name"/>
|
||||
<input type="hidden" name="scriptEnvValues" :value="var1.value"/>
|
||||
<em>{{var1.name}}</em>: {{var1.value}}
|
||||
<a href="" @click.prevent="removeEnv(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="envAdding" class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="envAddingName" v-model="envAddingName" placeholder="变量名" style="width:9em" @keyup.enter="confirmAddEnv" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="envAddingValue" v-model="envAddingValue" placeholder="变量值" style="width:15em" @keyup.enter="confirmAddEnv" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button" type="button" @click="confirmAddEnv()">添加</button>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<a href="" @click.prevent="cancelEnv()"><i class="icon remove"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button small" type="button" @click="addEnv()">+</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 钉钉群机器人 -->
|
||||
<tbody v-show="mediaType == 'dingTalk'">
|
||||
<tr>
|
||||
<td class="color-border">Hook地址 *</td>
|
||||
<td>
|
||||
<textarea name="dingTalkWebHookURL" maxlength="500" placeholder="https://oapi.dingtalk.com/robot/send?access_token=xxx" rows="2"></textarea>
|
||||
<p class="comment">填入自定义群机器人的Hook地址,<a href="https://open.dingtalk.com/document/orgapp/custom-robot-access" target="_blank">获取方法</a>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 企业微信 -->
|
||||
<tbody v-show="mediaType == 'qyWeixin'">
|
||||
<tr>
|
||||
<td class="color-border">企业ID *</td>
|
||||
<td>
|
||||
<input type="text" name="qyWeixinCorporateId" maxlength="100" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">应用AgentId *</td>
|
||||
<td>
|
||||
<input type="text" name="qyWeixinAgentId" maxlength="100"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">应用Secret *</td>
|
||||
<td>
|
||||
<input type="text" name="qyWeixinAppSecret" maxlength="100"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内容文本格式</td>
|
||||
<td>
|
||||
<select name="qyWeixinTextFormat" v-model="qyWeixinTextFormat" class="ui dropdown" style="width:10em">
|
||||
<option value="text">普通文本</option>
|
||||
<option value="markdown">Markdown</option>
|
||||
</select>
|
||||
<p class="comment" v-if="qyWeixinTextFormat == 'markdown'">企业微信目前只支持少数的Markdown语法,<a href="https://work.weixin.qq.com/api/doc#90000/90135/90236/%E6%94%AF%E6%8C%81%E7%9A%84markdown%E8%AF%AD%E6%B3%95" target="_blank">点击这里了解</a>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 企业微信群机器人 -->
|
||||
<tbody v-show="mediaType == 'qyWeixinRobot'">
|
||||
<tr>
|
||||
<td class="color-border">WebHook地址 *</td>
|
||||
<td>
|
||||
<textarea name="qyWeixinRobotWebHookURL" maxlength="500" placeholder="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx" rows="2"></textarea>
|
||||
<p class="comment">填入自定义群机器人的WebHook地址,<a href="https://open.work.weixin.qq.com/help2/pc/14931" target="_blank">获取方法</a>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内容文本格式</td>
|
||||
<td>
|
||||
<select name="qyWeixinRobotTextFormat" v-model="qyWeixinRobotTextFormat" class="ui dropdown" style="width:10em">
|
||||
<option value="text">普通文本</option>
|
||||
<option value="markdown">Markdown</option>
|
||||
</select>
|
||||
<p class="comment" v-if="qyWeixinRobotTextFormat == 'markdown'">企业微信目前只支持少数的Markdown语法,<a href="https://work.weixin.qq.com/api/doc#90000/90135/91760/markdown%E7%B1%BB%E5%9E%8B" target="_blank">点击这里了解</a>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 阿里云短信 -->
|
||||
<tbody v-show="mediaType == 'aliyunSms'">
|
||||
<tr>
|
||||
<td class="color-border">签名名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsSign" maxlength="100"/>
|
||||
<p class="comment">已经审核通过的短信签名名称</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">模板CODE *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsTemplateCode" maxlength="100" placeholder="类似于SMS_12345"/>
|
||||
<p class="comment">已经审核通过的模板CODE</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">模板变量 *</td>
|
||||
<td>
|
||||
<div class="ui field">
|
||||
<span class="ui label small basic" v-for="(var1, index) in aliyunSmsTemplateVars">
|
||||
<input type="hidden" name="aliyunSmsTemplateVarNames" :value="var1.name"/>
|
||||
<input type="hidden" name="aliyunSmsTemplateVarValues" :value="var1.value"/>
|
||||
<em>{{var1.name}}</em>: {{var1.value}}
|
||||
<a href="" @click.prevent="removeAliyunSmsTemplateVar(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="aliyunSmsTemplateVarAdding" class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="aliyunSmsTemplateVarAddingName" v-model="aliyunSmsTemplateVarAddingName" placeholder="变量名" style="width:9em" @keyup.enter="confirmAddAliyunSmsTemplateVar" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="aliyunSmsTemplateVarAddingValue" v-model="aliyunSmsTemplateVarAddingValue" placeholder="变量值" style="width:15em" @keyup.enter="confirmAddAliyunSmsTemplateVar" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button" type="button" @click="confirmAddAliyunSmsTemplateVar()">添加</button>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<a href="" @click.prevent="cancelAliyunSmsTemplateVar()"><i class="icon remove"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button small" type="button" @click="addAliyunSmsTemplateVar()">+</button>
|
||||
</div>
|
||||
<p class="comment">模板中使用的变量,在变量中可以使用<code-label>${MessageUser}</code-label>、<code-label>${MessageSubject}</code-label>和<code-label>${MessageBody}</code-label>来代表接收人标识、标题和内容。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessKey ID *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsAccessKeyId" maxlength="100"/>
|
||||
<p class="comment">在阿里云控制台中的访问控制中某个用户的AccessKey ID</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessKey Secret *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsAccessKeySecret" maxlength="100"/>
|
||||
<p class="comment">在阿里云控制台中的访问控制中某个用户的AccessKey Secret,和上面的AccessKey ID匹配</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- Telegram -->
|
||||
<tbody v-if="mediaType == 'telegram'">
|
||||
<tr>
|
||||
<td class="color-border">机器人Token *</td>
|
||||
<td>
|
||||
<input type="text" name="telegramToken"/>
|
||||
<p class="comment">创建机器人的时候可以获得,类似于 <code-label>123456:AAAA-AAAAAAAAAAAAAAAAAAAA</code-label>,可以向 <code-label>@BotFather</code-label> 发送 <code-label>/newbot</code-label>指令创建新的机器人。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">代理服务</td>
|
||||
<td>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" name="telegramProxyScheme">
|
||||
<option value="socks5">socks5://</option>
|
||||
<option value="https">https://</option>
|
||||
<option value="http">http://</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="telegramProxyHost" placeholder="HOST:PORT"/>
|
||||
</div>
|
||||
</div>
|
||||
<p class="comment">可选项,仅当API节点所在服务器无法直接连接Telegram API时填写;测试是否能够连接Telegram API的方法:<code-label>curl https://api.telegram.org</code-label>出现2XX、3XX、4XX之类提示时说明能够直接连接;如果你设置了代理,请使用<code-label>curl -x "你的代理服务地址" https://api.telegram.org</code-label>来测试你的代理是否可用。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tr>
|
||||
<td>发送频率<em>(次/分钟)</em></td>
|
||||
<td>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<div class="ui right labeled input">
|
||||
<input type="text" name="rateCount" size="4" maxlength="4"/>
|
||||
<span class="ui label">次</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">/</div>
|
||||
<div class="ui field">
|
||||
<div class="ui right labeled input">
|
||||
<input type="text" name="rateMinutes" size="4" maxlength="4"/>
|
||||
<span class="ui label">分钟</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="comment">用来限制此媒介的发送频率,防止短时间内消息数量过载。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>忽略相似消息周期</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="hashLife" style="width: 5em" maxlength="4"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
<p class="comment">可以在这个时间内忽略相似消息,防止短时间内消息数量过载。默认60秒。</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<textarea rows="3" name="description" maxlength="100"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,334 @@
|
||||
Tea.context(function () {
|
||||
this.mediaType = ""
|
||||
this.advancedOptionsVisible = true
|
||||
|
||||
let that = this
|
||||
this.changeMediaType = function (media) {
|
||||
that.mediaType = media.type
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
this.emailUsername = "";
|
||||
this.emailUsernameHelp = "";
|
||||
|
||||
this.changeEmailUsername = function () {
|
||||
this.emailUsernameHelp = "";
|
||||
if (this.emailUsername.indexOf("qq.com") > 0) {
|
||||
this.emailUsernameHelp = ",<a href=\"https://service.mail.qq.com\" target='_blank'>QQ邮箱相关设置帮助</a>";
|
||||
} else if (this.emailUsername.indexOf("163.com") > 0) {
|
||||
this.emailUsernameHelp = ",<a href=\"https://help.mail.163.com/faqDetail.do?code=d7a5dc8471cd0c0e8b4b8f4f8e49998b374173cfe9171305fa1ce630d7f67ac22dc0e9af8168582a\" target='_blank'>网易邮箱相关设置帮助</a>";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* webHook
|
||||
*/
|
||||
this.methods = ["GET", "POST"]
|
||||
this.webHookMethod = "GET";
|
||||
|
||||
this.webHookHeadersAdding = false;
|
||||
this.webHookHeaders = [];
|
||||
this.webHookHeadersAddingName = "";
|
||||
this.webHookHeadersAddingValue = "";
|
||||
|
||||
this.addWebHookHeader = function () {
|
||||
this.webHookHeadersAdding = true;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='webHookHeaderName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.cancelWebHookHeadersAdding = function () {
|
||||
this.webHookHeadersAdding = false;
|
||||
};
|
||||
|
||||
this.confirmWebHookHeadersAdding = function () {
|
||||
this.webHookHeaders.push({
|
||||
"name": this.webHookHeadersAddingName,
|
||||
"value": this.webHookHeadersAddingValue
|
||||
});
|
||||
this.webHookHeadersAddingName = "";
|
||||
this.webHookHeadersAddingValue = "";
|
||||
this.webHookHeadersAdding = false;
|
||||
};
|
||||
|
||||
this.removeWebHookHeader = function (index) {
|
||||
if (!window.confirm("确定要删除此Header吗?")) {
|
||||
return;
|
||||
}
|
||||
this.webHookHeaders.$remove(index);
|
||||
};
|
||||
|
||||
this.webHookContentType = "params";
|
||||
|
||||
this.selectWebHookContentType = function (contentType) {
|
||||
this.webHookContentType = contentType;
|
||||
this.$delay(function () {
|
||||
if (contentType == "params") {
|
||||
|
||||
} else if (contentType == "body") {
|
||||
this.$find("form textarea[name='webHookBody']").focus();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.webHookParamsAdding = false;
|
||||
this.webHookParams = [];
|
||||
this.webHookParamsAddingName = "";
|
||||
this.webHookParamsAddingValue = "";
|
||||
|
||||
this.addWebHookParam = function () {
|
||||
this.webHookParamsAdding = true;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='webHookParamName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.cancelWebHookParamsAdding = function () {
|
||||
this.webHookParamsAdding = false;
|
||||
};
|
||||
|
||||
this.confirmWebHookParamsAdding = function () {
|
||||
this.webHookParams.push({
|
||||
"name": this.webHookParamsAddingName,
|
||||
"value": this.webHookParamsAddingValue
|
||||
});
|
||||
this.webHookParamsAddingName = "";
|
||||
this.webHookParamsAddingValue = "";
|
||||
this.webHookParamsAdding = false;
|
||||
};
|
||||
|
||||
this.removeWebHookParam = function (index) {
|
||||
if (!window.confirm("确定要删除此参数吗?")) {
|
||||
return;
|
||||
}
|
||||
this.webHookParams.$remove(index);
|
||||
};
|
||||
|
||||
this.webHookBody = "";
|
||||
|
||||
/**
|
||||
* 企业微信
|
||||
*/
|
||||
this.qyWeixinTextFormat = "text";
|
||||
|
||||
/**
|
||||
* 企业微信群机器人
|
||||
*/
|
||||
this.qyWeixinRobotTextFormat = "text";
|
||||
|
||||
/**
|
||||
* 脚本
|
||||
*/
|
||||
let scriptEditor = null
|
||||
this.scriptTab = "path";
|
||||
this.scriptLang = "shell";
|
||||
this.scriptLangs = [
|
||||
{
|
||||
"name": "Shell",
|
||||
"code": "shell"
|
||||
},
|
||||
{
|
||||
"name": "批处理(bat)",
|
||||
"code": "bat"
|
||||
},
|
||||
{
|
||||
"name": "PHP",
|
||||
"code": "php"
|
||||
},
|
||||
{
|
||||
"name": "Python",
|
||||
"code": "python"
|
||||
},
|
||||
{
|
||||
"name": "Ruby",
|
||||
"code": "ruby"
|
||||
},
|
||||
{
|
||||
"name": "NodeJS",
|
||||
"code": "nodejs"
|
||||
}
|
||||
];
|
||||
|
||||
this.selectScriptTab = function (tab) {
|
||||
this.scriptTab = tab;
|
||||
|
||||
if (tab == "path") {
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='scriptPath']").focus();
|
||||
});
|
||||
} else if (tab == "code") {
|
||||
this.$delay(function () {
|
||||
this.loadEditor();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.selectScriptLang = function (lang) {
|
||||
this.scriptLang = lang;
|
||||
switch (lang) {
|
||||
case "shell":
|
||||
scriptEditor.setValue("#!/usr/bin/env bash\n\n# your commands here\n");
|
||||
var info = CodeMirror.findModeByMIME("text/x-sh");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "bat":
|
||||
scriptEditor.setValue("");
|
||||
break;
|
||||
case "php":
|
||||
scriptEditor.setValue("#!/usr/bin/env php\n\n<?php\n// your PHP codes here");
|
||||
var info = CodeMirror.findModeByMIME("text/x-php");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "python":
|
||||
scriptEditor.setValue("#!/usr/bin/env python\n\n''' your Python codes here '''");
|
||||
var info = CodeMirror.findModeByMIME("text/x-python");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "ruby":
|
||||
scriptEditor.setValue("#!/usr/bin/env ruby\n\n# your Ruby codes here");
|
||||
var info = CodeMirror.findModeByMIME("text/x-ruby");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "nodejs":
|
||||
scriptEditor.setValue("#!/usr/bin/env node\n\n// your javascript codes here");
|
||||
var info = CodeMirror.findModeByMIME("text/javascript");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
scriptEditor.save();
|
||||
scriptEditor.focus();
|
||||
};
|
||||
|
||||
this.loadEditor = function () {
|
||||
if (scriptEditor == null) {
|
||||
scriptEditor = CodeMirror.fromTextArea(document.getElementById("script-code-editor"), {
|
||||
theme: "idea",
|
||||
lineNumbers: true,
|
||||
value: "",
|
||||
readOnly: false,
|
||||
showCursorWhenSelecting: true,
|
||||
height: "auto",
|
||||
//scrollbarStyle: null,
|
||||
viewportMargin: Infinity,
|
||||
lineWrapping: true,
|
||||
highlightFormatting: false,
|
||||
indentUnit: 4,
|
||||
indentWithTabs: true
|
||||
});
|
||||
}
|
||||
scriptEditor.setValue("#!/usr/bin/env bash\n\n# your commands here\n");
|
||||
scriptEditor.save();
|
||||
scriptEditor.focus();
|
||||
|
||||
var info = CodeMirror.findModeByMIME("text/x-sh");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
|
||||
scriptEditor.on("change", function () {
|
||||
scriptEditor.save();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 环境变量
|
||||
*/
|
||||
this.env = [];
|
||||
this.envAdding = false;
|
||||
this.envAddingName = "";
|
||||
this.envAddingValue = "";
|
||||
|
||||
this.addEnv = function () {
|
||||
this.envAdding = !this.envAdding;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='envAddingName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.confirmAddEnv = function () {
|
||||
if (this.envAddingName.length == 0) {
|
||||
alert("请输入变量名");
|
||||
this.$find("form input[name='envAddingName']").focus();
|
||||
return;
|
||||
}
|
||||
this.env.push({
|
||||
"name": this.envAddingName,
|
||||
"value": this.envAddingValue
|
||||
});
|
||||
this.envAdding = false;
|
||||
this.envAddingName = "";
|
||||
this.envAddingValue = "";
|
||||
};
|
||||
|
||||
this.removeEnv = function (index) {
|
||||
this.env.$remove(index);
|
||||
};
|
||||
|
||||
this.cancelEnv = function () {
|
||||
this.envAdding = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 阿里云短信模板
|
||||
*/
|
||||
this.aliyunSmsTemplateVars = [];
|
||||
this.aliyunSmsTemplateVarAdding = false;
|
||||
this.aliyunSmsTemplateVarAddingName = "";
|
||||
this.aliyunSmsTemplateVarAddingValue = "";
|
||||
|
||||
this.addAliyunSmsTemplateVar = function () {
|
||||
this.aliyunSmsTemplateVarAdding = !this.aliyunSmsTemplateVarAdding;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='aliyunSmsTemplateVarAddingName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.confirmAddAliyunSmsTemplateVar = function () {
|
||||
if (this.aliyunSmsTemplateVarAddingName.length == 0) {
|
||||
alert("请输入变量名");
|
||||
this.$find("form input[name='aliyunSmsTemplateVarAddingName']").focus();
|
||||
return;
|
||||
}
|
||||
this.aliyunSmsTemplateVars.push({
|
||||
"name": this.aliyunSmsTemplateVarAddingName,
|
||||
"value": this.aliyunSmsTemplateVarAddingValue
|
||||
});
|
||||
this.aliyunSmsTemplateVarAdding = false;
|
||||
this.aliyunSmsTemplateVarAddingName = "";
|
||||
this.aliyunSmsTemplateVarAddingValue = "";
|
||||
};
|
||||
|
||||
this.removeAliyunSmsTemplateVar = function (index) {
|
||||
this.aliyunSmsTemplateVars.$remove(index);
|
||||
};
|
||||
|
||||
this.cancelAliyunSmsTemplateVar = function () {
|
||||
this.aliyunSmsTemplateVarAdding = false;
|
||||
};
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
// code mirror
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item @click.prevent="createInstance">[创建媒介]</menu-item>
|
||||
</second-menu>
|
||||
|
||||
<p class="comment" v-if="instances.length == 0">暂时还没有媒介接收人。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="instances.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>媒介名称</th>
|
||||
<th class="three wide">媒介类型</th>
|
||||
<th>备注</th>
|
||||
<th class="two wide">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="instance in instances">
|
||||
<td><a :href="'/admins/recipients/instances/instance?instanceId=' + instance.id">{{instance.name}}</a></td>
|
||||
<td>{{instance.media.name}}</td>
|
||||
<td>
|
||||
<span v-if="instance.description.length > 0">{{instance.description}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<label-on :v-is-on="instance.isOn"></label-on>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/admins/recipients/instances/instance?instanceId=' + instance.id">详情</a>
|
||||
<a href="" @click.prevent="deleteInstance(instance.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
@@ -0,0 +1,24 @@
|
||||
Tea.context(function () {
|
||||
this.createInstance = function () {
|
||||
teaweb.popup(Tea.url(".createPopup"), {
|
||||
height: "30em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.deleteInstance = function (instanceId) {
|
||||
teaweb.confirm("确定要删除此接收媒介吗?", function () {
|
||||
this.$post(".delete")
|
||||
.params({instanceId: instanceId})
|
||||
.success(function () {
|
||||
teaweb.success("删除成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,12 @@
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto!important;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px!important;
|
||||
}
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
/*# sourceMappingURL=instance.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["instance.less"],"names":[],"mappings":"AACA;EACC,sBAAA;EACA,sBAAA;;AAGD;EACC,UAAA;EACA,4BAAA;;AAGD,sBAAsB;EACrB,kBAAA","file":"instance.css"}
|
||||
@@ -0,0 +1,250 @@
|
||||
{$layout}
|
||||
{$template "instance_menu"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">媒介名称</td>
|
||||
<td>{{instance.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>状态</td>
|
||||
<td>
|
||||
<label-on :v-is-on="instance.isOn"></label-on>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">媒介类型</td>
|
||||
<td>
|
||||
{{instance.media.name}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- E-mail -->
|
||||
<tbody v-if="instance.media.type == 'email'">
|
||||
<tr>
|
||||
<td class="color-border">SMTP</td>
|
||||
<td>
|
||||
{{instance.params.smtp}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">账号</td>
|
||||
<td>
|
||||
{{instance.params.username}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">密码</td>
|
||||
<td>
|
||||
{{instance.params.password}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">发送者Email</td>
|
||||
<td>
|
||||
<span v-if="instance.params.from.length > 0">{{instance.params.from}}</span>
|
||||
<span v-if="instance.params.from.length == 0" class="disabled">没有设置</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- WebHook -->
|
||||
<tbody v-if="instance.media.type == 'webHook'">
|
||||
<tr>
|
||||
<td class="color-border">URL</td>
|
||||
<td>
|
||||
{{instance.params.url}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">请求方法</td>
|
||||
<td>
|
||||
{{instance.params.method}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">自定义报头</td>
|
||||
<td>
|
||||
<span v-if="instance.params.headers == null || instance.params.headers.length == 0" class="disabled">还没有自定义Header</span>
|
||||
<div v-if="instance.params.headers != null && instance.params.headers.length > 0">
|
||||
<span class="ui label small" v-for="header in instance.params.headers">{{header.name}}:{{header.value}}</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="instance.params.contentType != null && instance.params.contentType.length > 0">
|
||||
<td class="color-border">
|
||||
<span v-if="instance.params.contentType == 'params'">自定义参数</span>
|
||||
<span v-if="instance.params.contentType == 'body'">自定义内容</span>
|
||||
</td>
|
||||
<td class="color-border">
|
||||
<div v-if="instance.params.contentType == 'params'">
|
||||
<span v-if="instance.params.params == null || instance.params.params.length == 0" class="disabled">还没有自定义参数</span>
|
||||
<div v-if="instance.params.params != null && instance.params.params.length > 0">
|
||||
<span class="ui label small" v-for="param in instance.params.params">{{param.name}}:{{param.value}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="instance.params.contentType == 'body'">
|
||||
<xmp style="margin-top:0;margin-bottom:0">{{instance.params.body}}</xmp>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 脚本 -->
|
||||
<tbody v-if="instance.media.type == 'script'">
|
||||
<tr>
|
||||
<td class="color-border">脚本</td>
|
||||
<td>
|
||||
<span v-if="instance.params.scriptType == 'path'">{{instance.params.path}}</span>
|
||||
<div id="script-code-editor" v-show="instance.params.scriptType == 'code'"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">当前工作目录<em>(CWD)</em></td>
|
||||
<td>
|
||||
<span v-if="instance.params.cwd.length > 0">{{instance.params.cwd}}</span>
|
||||
<span v-if="instance.params.cwd.length == 0" class="disabled">没有设置</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">环境变量<em>(ENV)</em></td>
|
||||
<td>
|
||||
<span v-if="instance.params.env == null || instance.params.env.length == 0" class="disabled">没有设置</span>
|
||||
<div v-if="instance.params.env != null && instance.params.env.length > 0">
|
||||
<span class="ui label small" v-for="(var1, index) in instance.params.env">
|
||||
<em>{{var1.name}}</em>: {{var1.value}}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody v-if="instance.media.type == 'dingTalk'">
|
||||
<tr>
|
||||
<td class="color-border">Hook地址</td>
|
||||
<td>{{instance.params.webHookURL}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 企业微信 -->
|
||||
<tbody v-if="instance.media.type == 'qyWeixin'">
|
||||
<tr>
|
||||
<td class="color-border">企业ID</td>
|
||||
<td>
|
||||
{{instance.params.corporateId}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">应用AgentId</td>
|
||||
<td>
|
||||
{{instance.params.agentId}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">应用Secret</td>
|
||||
<td>
|
||||
{{instance.params.appSecret}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内容文本格式</td>
|
||||
<td>
|
||||
<span v-if="instance.params.textFormat == null">text</span>
|
||||
{{instance.params.textFormat}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 企业微信群机器人 -->
|
||||
<tbody v-if="instance.media.type == 'qyWeixinRobot'">
|
||||
<tr>
|
||||
<td class="color-border">WebHook地址</td>
|
||||
<td>{{instance.params.webHookURL}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内容文本格式</td>
|
||||
<td>
|
||||
<span v-if="instance.params.textFormat == null">text</span>
|
||||
{{instance.params.textFormat}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 阿里云短信 -->
|
||||
<tbody v-show="instance.media.type == 'aliyunSms'">
|
||||
<tr>
|
||||
<td class="color-border">签名名称</td>
|
||||
<td>
|
||||
{{instance.params.sign}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">模板CODE</td>
|
||||
<td>
|
||||
{{instance.params.templateCode}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">模板变量</td>
|
||||
<td>
|
||||
<div v-if="instance.params.variables != null">
|
||||
<span class="ui label small" v-for="(var1, index) in instance.params.variables">
|
||||
<em>{{var1.name}}</em>: {{var1.value}}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessKey ID</td>
|
||||
<td>
|
||||
{{instance.params.accessKeyId}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessKey Secret</td>
|
||||
<td>
|
||||
{{instance.params.accessKeySecret}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- Telegram机器人 -->
|
||||
<tbody v-show="instance.media.type == 'telegram'">
|
||||
<tr>
|
||||
<td class="color-border">机器人Token</td>
|
||||
<td>{{instance.params.token}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">代理服务</td>
|
||||
<td>
|
||||
<span v-if="instance.params.proxyURL != null && instance.params.proxyURL.length > 0 && instance.params.proxyURL.match(/^\w+:\/\/.+/)">
|
||||
{{instance.params.proxyURL}}
|
||||
</span>
|
||||
<span v-else class="disabled">没有设置</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tr>
|
||||
<td>发送频率<em>(次/分钟)</em></td>
|
||||
<td>
|
||||
<span v-if="instance.rate.minutes <= 0 || instance.rate.count <= 0" class="disabled">没有限制</span>
|
||||
<span v-else>{{instance.rate.count}}次/{{instance.rate.minutes}}分钟</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>忽略相似消息周期</td>
|
||||
<td>
|
||||
<span v-if="instance.hashLife > 0">{{instance.hashLife}}秒</span>
|
||||
<span v-else-if="instance.hashLife == 0" class="disabled">使用默认</span>
|
||||
<span v-else class="disabled">没有设置</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<span v-if="instance.description.length > 0">{{instance.description}}</span>
|
||||
<span v-else class="disabled">没有设置</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1,48 @@
|
||||
Tea.context(function () {
|
||||
let scriptEditor = null
|
||||
|
||||
this.from = encodeURIComponent(window.location.toString())
|
||||
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code") {
|
||||
this.$delay(function () {
|
||||
this.loadEditor()
|
||||
})
|
||||
}
|
||||
|
||||
this.loadEditor = function () {
|
||||
if (scriptEditor == null) {
|
||||
scriptEditor = CodeMirror(document.getElementById("script-code-editor"), {
|
||||
theme: "idea",
|
||||
lineNumbers: false,
|
||||
value: "",
|
||||
readOnly: true,
|
||||
showCursorWhenSelecting: true,
|
||||
height: "auto",
|
||||
//scrollbarStyle: null,
|
||||
viewportMargin: Infinity,
|
||||
lineWrapping: true,
|
||||
highlightFormatting: false,
|
||||
indentUnit: 4,
|
||||
indentWithTabs: true
|
||||
})
|
||||
}
|
||||
scriptEditor.setValue(this.instance.params.script)
|
||||
|
||||
let lang = "shell"
|
||||
if (this.instance.params.scriptLang != null && this.instance.params.scriptLang.length > 0) {
|
||||
lang = this.instance.params.scriptLang
|
||||
}
|
||||
let mimeType = "text/x-" + lang
|
||||
if (lang == "nodejs") {
|
||||
mimeType = "text/javascript"
|
||||
} else if (lang == "shell") {
|
||||
mimeType = "text/x-sh"
|
||||
}
|
||||
let info = CodeMirror.findModeByMIME(mimeType)
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode)
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js"
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
// codemirror
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto!important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px!important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{$layout}
|
||||
{$template "instance_menu"}
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-timeout="120" data-tea-before="submitBefore" data-tea-success="submitSuccess" data-tea-error="submitError" data-tea-fail="submitFail" style="margin-top:1em">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="instanceId" :value="instance.id"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">媒介名称</td>
|
||||
<td>{{instance.media.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>通知标题</td>
|
||||
<td>
|
||||
<input type="text" name="subject" value="这是通知标题" maxlength="100"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>通知内容</td>
|
||||
<td>
|
||||
<textarea name="body" rows="2" maxlength="100">这是通知内容</textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>接收人标识</td>
|
||||
<td>
|
||||
<input type="text" name="user" maxlength="500"/>
|
||||
<p class="comment" v-html="instance.media.userDescription"></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="ui segment response-box" :class="{green:isOk, red:!isOk}" v-if="isFinished">
|
||||
<div v-if="response.length > 0"><span v-if="error.length == 0">成功</span>返回结果:
|
||||
<div v-for="line in responseLines">{{line}}</div>
|
||||
</div>
|
||||
<div v-if="error.length > 0">错误信息:
|
||||
<div v-for="line in errorLines">{{line}}</div>
|
||||
</div>
|
||||
<span class="disabled" v-if="response.length == 0 && error.length == 0">成功执行,没有返回结果</span>
|
||||
</div>
|
||||
|
||||
<button class="ui button primary" type="submit" v-if="!isRunning">提交测试</button>
|
||||
<span v-if="isRunning">发送测试中,请耐心等待...</span>
|
||||
</form>
|
||||
@@ -0,0 +1,51 @@
|
||||
Tea.context(function () {
|
||||
this.isRunning = false
|
||||
this.isFinished = false
|
||||
this.response = ""
|
||||
this.error = ""
|
||||
this.isOk = false
|
||||
|
||||
this.submitBefore = function () {
|
||||
this.isRunning = true
|
||||
this.isFinished = false
|
||||
this.response = ""
|
||||
this.error = ""
|
||||
this.isOk = false
|
||||
}
|
||||
|
||||
this.submitSuccess = function (resp) {
|
||||
this.updateStatus(resp.data.result)
|
||||
}
|
||||
|
||||
this.submitFail = function (resp) {
|
||||
this.isRunning = false
|
||||
this.isFinished = true
|
||||
this.response = ""
|
||||
this.error = resp.errors[0].messages[0]
|
||||
this.errorLines = []
|
||||
}
|
||||
|
||||
this.submitError = function () {
|
||||
this.isRunning = false
|
||||
this.isFinished = true
|
||||
this.response = ""
|
||||
this.errorLines = []
|
||||
this.error = "请求超时"
|
||||
}
|
||||
|
||||
this.updateStatus = function (result) {
|
||||
this.isRunning = false
|
||||
this.isFinished = true
|
||||
this.isOk = result.isOk
|
||||
this.response = result.response
|
||||
this.responseLines = []
|
||||
if (this.response != null) {
|
||||
this.responseLines = this.response.split("\n")
|
||||
}
|
||||
this.error = result.error
|
||||
this.errorLines = []
|
||||
if (this.error.length > 0) {
|
||||
this.errorLines = this.error.split("\n")
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,12 @@
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto !important;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
/*# sourceMappingURL=update.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["update.less"],"names":[],"mappings":"AACA;EACC,sBAAA;EACA,uBAAA;;AAGD;EACC,UAAA;EACA,6BAAA;;AAGD,sBAAsB;EACrB,kBAAA","file":"update.css"}
|
||||
@@ -0,0 +1,414 @@
|
||||
{$layout}
|
||||
{$template "instance_menu"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="instanceId" :value="instance.id"/>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">媒介名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" ref="focus" maxlength="100" v-model="instance.name"/>
|
||||
<p class="comment">给当前媒介填写一个容易识别的名称。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border title">媒介类型 *</td>
|
||||
<td>
|
||||
<message-media-selector :v-media-type="instance.media.type" @change="changeMediaType"></message-media-selector>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- E-mail -->
|
||||
<tbody v-show="mediaType == 'email'">
|
||||
<tr>
|
||||
<td class="color-border">SMTP *</td>
|
||||
<td>
|
||||
<input type="text" name="emailSmtp" v-model="instance.params.smtp" maxlength="500" placeholder="类似于 smtp.example.com:465"/>
|
||||
<p class="comment">只支持SSL(或TLS)连接,端口通常为:465或587。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">账号 *</td>
|
||||
<td>
|
||||
<input type="text" name="emailUsername" v-model="instance.params.username" maxlength="500" placeholder="类似于 xxx@example.com" @input="changeEmailUsername"/>
|
||||
<p class="comment">邮箱账号,比如 123456@qq.com<span v-html="emailUsernameHelp"></span>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">密码 *</td>
|
||||
<td>
|
||||
<input type="password" name="emailPassword" v-model="instance.params.password" maxlength="100"/>
|
||||
<p class="comment">账号对应的密码或者授权码(比如QQ邮箱就需要授权码)。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">发送者Email</td>
|
||||
<td>
|
||||
<input type="text" name="emailFrom" v-model="instance.params.from" maxlength="500" placeholder="类似于 xxx@example.com"/>
|
||||
<p class="comment">默认和账号一致</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- WebHook -->
|
||||
<tbody v-show="mediaType == 'webHook'">
|
||||
<tr>
|
||||
<td class="color-border">URL *</td>
|
||||
<td>
|
||||
<input type="text" name="webHookURL" v-model="instance.params.url" maxlength="500" placeholder="http://..."/>
|
||||
<p class="comment">可以在URL中使用<code-label>${MessageUser}</code-label>、<code-label>${MessageSubject}</code-label>和<code-label>${MessageBody}</code-label>来代表接收人标识、标题和内容。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">请求方法 *</td>
|
||||
<td>
|
||||
<select name="webHookMethod" v-model="webHookMethod" class="ui dropdown" style="width:10em">
|
||||
<option v-for="method in methods" :value="method">{{method}}</option>
|
||||
</select>
|
||||
<p class="comment" v-if="webHookMethod == 'POST'">将以POST方式发送<code-label>${MessageUser}</code-label>、<code-label>${MessageSubject}</code-label>和<code-label>${MessageBody}</code-label>参数,分别代表接收人标识、标题和内容</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="advancedOptionsVisible">
|
||||
<td class="color-border">自定义报头</td>
|
||||
<td>
|
||||
<div class="webHook-headers-box">
|
||||
<span class="ui label small basic" v-for="(header,index) in webHookHeaders">{{header.name}}:{{header.value}}
|
||||
<input type="hidden" name="webHookHeaderNames" :value="header.name"/>
|
||||
<input type="hidden" name="webHookHeaderValues" :value="header.value"/>
|
||||
<a href="" title="删除" @click.prevent="removeWebHookHeader(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<div style="margin-top: 1em">
|
||||
<button class="ui button tiny" type="button" @click.prevent="addWebHookHeader()" v-if="!webHookHeadersAdding">+</button>
|
||||
</div>
|
||||
<div v-if="webHookHeadersAdding" style="margin-top: 1em">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="webHookHeaderName" v-model="webHookHeadersAddingName" size="10" placeholder="名称" maxlength="100" @keyup.enter="confirmWebHookHeadersAdding" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">:</div>
|
||||
<div class="ui field">
|
||||
<input type="text" placeholder="值" v-model="webHookHeadersAddingValue" size="20" maxlength="256" @keyup.enter="confirmWebHookHeadersAdding" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button tiny" type="button" @click.prevent="confirmWebHookHeadersAdding()">确定</button>
|
||||
<a href="" @click.prevent="cancelWebHookHeadersAdding()">取消</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="webHookMethod == 'POST' && advancedOptionsVisible">
|
||||
<td class="color-border">自定义内容</td>
|
||||
<td>
|
||||
<div class="ui menu tabular small attached">
|
||||
<a href="" class="item" :class="{active:webHookContentType == 'params'}" @click.prevent="selectWebHookContentType('params')">参数对</a>
|
||||
<a href="" class="item" :class="{active:webHookContentType == 'body'}" @click.prevent="selectWebHookContentType('body')">文本内容</a>
|
||||
</div>
|
||||
<div class="ui segment attached" v-if="webHookContentType == 'params'">
|
||||
<input type="hidden" name="webHookContentType" value="params"/>
|
||||
<div class="webHook-headers-box">
|
||||
<span class="ui label small basic" v-for="(param,index) in webHookParams">{{param.name}}:{{param.value}}
|
||||
<input type="hidden" name="webHookParamNames" :value="param.name"/>
|
||||
<input type="hidden" name="webHookParamValues" :value="param.value"/>
|
||||
<a href="" title="删除" @click.prevent="removeWebHookParam(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="addWebHookParam()" v-if="!webHookParamsAdding">+</button>
|
||||
<div v-if="webHookParamsAdding">
|
||||
<input type="hidden" name="webHookContentType" value="params"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="webHookParamName" v-model="webHookParamsAddingName" placeholder="名称" maxlength="100" @keyup.enter="confirmWebHookParamsAdding" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">:</div>
|
||||
<div class="ui field">
|
||||
<textarea type="text" placeholder="值" v-model="webHookParamsAddingValue" cols="50" maxlength="1024" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui button tiny" type="button" @click.prevent="confirmWebHookParamsAdding()">确认添加</button>
|
||||
<a href="" @click.prevent="cancelWebHookParamsAdding()">取消</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui segment attached" v-if="webHookContentType == 'body'">
|
||||
<input type="hidden" name="webHookContentType" value="body"/>
|
||||
<textarea name="webHookBody" v-model="webHookBody" rows="5" placeholder="发送的内容"></textarea>
|
||||
<p class="comment">
|
||||
内容中可以使用三个变量:<code-label>${MessageUser}</code-label>、<code-label>${MessageSubject}</code-label>和<code-label>${MessageBody}</code-label>参数,分别代表接收人标识、标题和内容
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- Script -->
|
||||
<tbody v-show="mediaType == 'script'">
|
||||
<tr>
|
||||
<td class="color-border">脚本 *</td>
|
||||
<td>
|
||||
<input type="hidden" name="scriptType" :value="scriptTab"/>
|
||||
<input type="hidden" name="scriptLang" :value="scriptLang"/>
|
||||
<div class="ui tabular menu attached small">
|
||||
<a class="item" :class="{active:scriptTab == 'path'}" @click.prevent="selectScriptTab('path')">脚本文件</a>
|
||||
<a class="item" :class="{active:scriptTab == 'code'}" @click.prevent="selectScriptTab('code')">脚本代码</a>
|
||||
</div>
|
||||
<div class="ui bottom segment attached" v-show="scriptTab == 'path'">
|
||||
<input type="text" name="scriptPath" v-model="instance.params.path" maxlength="500"/>
|
||||
<p class="comment">如果是Shell脚本,请不要忘记在头部添加 <em>#!脚本解释工具</em>,比如 <em>#!/bin/bash</em><br/>
|
||||
执行此脚本时,在脚本中可以使用<code-label>${MessageUser}</code-label>、<code-label>${MessageSubject}</code-label>和<code-label>${MessageBody}</code-label>三个环境变量分别代表通知的接收人标识、标题和内容。
|
||||
</p>
|
||||
</div>
|
||||
<div class="ui bottom segment attached" v-show="scriptTab == 'code'" style="padding-top:0">
|
||||
<div class="ui menu text small">
|
||||
<a class="item" v-for="lang in scriptLangs" :class="{active:lang.code == scriptLang}" @click.prevent="selectScriptLang(lang.code)">{{lang.name}}</a>
|
||||
</div>
|
||||
<textarea name="scriptCode" id="script-code-editor" rows="1"></textarea>
|
||||
<p class="comment">如果是Shell脚本,请不要忘记在头部添加 <em>#!脚本解释工具</em>,比如 <em>#!/bin/bash</em><br/>
|
||||
执行此脚本时,在脚本中可以使用<code-label>${MessageUser}</code-label>、<code-label>${MessageSubject}</code-label>和<code-label>${MessageBody}</code-label>三个环境变量分别代表通知的接收人标识、标题和内容。
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="advancedOptionsVisible">
|
||||
<td class="color-border">当前工作目录<em>(CWD)</em></td>
|
||||
<td>
|
||||
<input type="text" name="scriptCwd" v-model="instance.params.cwd" maxlength="500"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="advancedOptionsVisible">
|
||||
<td class="color-border">环境变量<em>(ENV)</em></td>
|
||||
<td>
|
||||
<div class="ui field">
|
||||
<span class="ui label small basic" v-for="(var1, index) in env">
|
||||
<input type="hidden" name="scriptEnvNames" :value="var1.name"/>
|
||||
<input type="hidden" name="scriptEnvValues" :value="var1.value"/>
|
||||
<em>{{var1.name}}</em>: {{var1.value}}
|
||||
<a href="" @click.prevent="removeEnv(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="envAdding" class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="envAddingName" v-model="envAddingName" placeholder="变量名" style="width:9em" @keyup.enter="confirmAddEnv" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="envAddingValue" v-model="envAddingValue" placeholder="变量值" style="width:15em" @keyup.enter="confirmAddEnv" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button" type="button" @click="confirmAddEnv()">添加</button>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<a href="" @click.prevent="cancelEnv()"><i class="icon remove"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button small" type="button" @click="addEnv()">+</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 钉钉 -->
|
||||
<tbody v-show="mediaType == 'dingTalk'">
|
||||
<tr>
|
||||
<td class="color-border">Hook地址 *</td>
|
||||
<td>
|
||||
<textarea name="dingTalkWebHookURL" maxlength="500" placeholder="https://oapi.dingtalk.com/robot/send?access_token=xxx" v-model="instance.params.webHookURL" rows="2"></textarea>
|
||||
<p class="comment">填入自定义群机器人的Hook地址,<a href="https://open.dingtalk.com/document/orgapp/custom-robot-access" target="_blank">获取方法</a>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 企业微信 -->
|
||||
<tbody v-show="mediaType == 'qyWeixin'">
|
||||
<tr>
|
||||
<td class="color-border">企业ID *</td>
|
||||
<td>
|
||||
<input type="text" name="qyWeixinCorporateId" maxlength="100" v-model="instance.params.corporateId" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">应用AgentId *</td>
|
||||
<td>
|
||||
<input type="text" name="qyWeixinAgentId" maxlength="100" v-model="instance.params.agentId"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">应用Secret *</td>
|
||||
<td>
|
||||
<input type="text" name="qyWeixinAppSecret" maxlength="100" v-model="instance.params.appSecret"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内容文本格式</td>
|
||||
<td>
|
||||
<select name="qyWeixinTextFormat" v-model="instance.params.textFormat" class="ui dropdown" style="width:10em">
|
||||
<option value="text">普通文本</option>
|
||||
<option value="markdown">Markdown</option>
|
||||
</select>
|
||||
<p class="comment" v-if="instance.params.textFormat == 'markdown'">企业微信目前只支持少数的Markdown语法,<a href="https://work.weixin.qq.com/api/doc#90000/90135/90236/%E6%94%AF%E6%8C%81%E7%9A%84markdown%E8%AF%AD%E6%B3%95" target="_blank">点击这里了解</a>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 企业微信群机器人 -->
|
||||
<tbody v-show="mediaType == 'qyWeixinRobot'">
|
||||
<tr>
|
||||
<td class="color-border">WebHook地址 *</td>
|
||||
<td>
|
||||
<textarea name="qyWeixinRobotWebHookURL" v-model="instance.params.webHookURL" maxlength="500" placeholder="https://qyapi.weixin.qq.com/cgi-bin/webHook/send?key=xxx" rows="2"></textarea>
|
||||
<p class="comment">填入自定义群机器人的WebHook地址,<a href="https://open.work.weixin.qq.com/help2/pc/14931" target="_blank">获取方法</a>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">内容文本格式</td>
|
||||
<td>
|
||||
<select name="qyWeixinRobotTextFormat" v-model="instance.params.textFormat" class="ui dropdown" style="width:10em">
|
||||
<option value="text">普通文本</option>
|
||||
<option value="markdown">Markdown</option>
|
||||
</select>
|
||||
<p class="comment" v-if="instance.params.textFormat == 'markdown'">企业微信目前只支持少数的Markdown语法,<a href="https://work.weixin.qq.com/api/doc#90000/90135/91760/markdown%E7%B1%BB%E5%9E%8B" target="_blank">点击这里了解</a>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- 阿里云短信 -->
|
||||
<tbody v-show="mediaType == 'aliyunSms'">
|
||||
<tr>
|
||||
<td class="color-border">签名名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsSign" maxlength="100" v-model="instance.params.sign"/>
|
||||
<p class="comment">已经审核通过的短信签名名称</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">模板CODE *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsTemplateCode" maxlength="100" v-model="instance.params.templateCode" placeholder="类似于SMS_12345"/>
|
||||
<p class="comment">已经审核通过的模板CODE</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">模板变量 *</td>
|
||||
<td>
|
||||
<div class="ui field">
|
||||
<span class="ui label small basic" v-for="(var1, index) in aliyunSmsTemplateVars">
|
||||
<input type="hidden" name="aliyunSmsTemplateVarNames" :value="var1.name"/>
|
||||
<input type="hidden" name="aliyunSmsTemplateVarValues" :value="var1.value"/>
|
||||
<em>{{var1.name}}</em>: {{var1.value}}
|
||||
<a href="" @click.prevent="removeAliyunSmsTemplateVar(index)"><i class="icon remove"></i></a>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="aliyunSmsTemplateVarAdding" class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="aliyunSmsTemplateVarAddingName" v-model="aliyunSmsTemplateVarAddingName" placeholder="变量名" style="width:9em" @keyup.enter="confirmAddAliyunSmsTemplateVar" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="aliyunSmsTemplateVarAddingValue" v-model="aliyunSmsTemplateVarAddingValue" placeholder="变量值" style="width:15em" @keyup.enter="confirmAddAliyunSmsTemplateVar" @keypress.enter.prevent="1"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button" type="button" @click="confirmAddAliyunSmsTemplateVar()">添加</button>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<a href="" @click.prevent="cancelAliyunSmsTemplateVar()"><i class="icon remove"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button small" type="button" @click="addAliyunSmsTemplateVar()">+</button>
|
||||
</div>
|
||||
<p class="comment">模板中使用的变量,在变量中可以使用<code-label>${MessageUser}</code-label>、<code-label>${MessageSubject}</code-label>和<code-label>${MessageBody}</code-label>来代表接收人标识、标题和内容。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessKey ID *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsAccessKeyId" maxlength="100" v-model="instance.params.accessKeyId"/>
|
||||
<p class="comment">在阿里云控制台中的访问控制中某个用户的AccessKey ID</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">AccessKey Secret *</td>
|
||||
<td>
|
||||
<input type="text" name="aliyunSmsAccessKeySecret" maxlength="100" v-model="instance.params.accessKeySecret"/>
|
||||
<p class="comment">在阿里云控制台中的访问控制中某个用户的AccessKey Secret,和上面的AccessKey ID匹配</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<!-- Telegram -->
|
||||
<tbody v-if="mediaType == 'telegram'">
|
||||
<tr>
|
||||
<td class="color-border">机器人Token</td>
|
||||
<td>
|
||||
<input type="text" name="telegramToken" v-model="instance.params.token"/>
|
||||
<p class="comment">在创建机器人的时候可以获得,类似于 <code-label>123456:AAAA-AAAAAAAAAAAAAAAAAAAA</code-label>,可以向 <code-label>@BotFather</code-label> 发送 <code-label>/newbot</code-label>指令创建新的机器人。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="color-border">代理服务</td>
|
||||
<td>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" name="telegramProxyScheme" v-model="telegramProxyScheme">
|
||||
<option value="socks5">socks5://</option>
|
||||
<option value="https">https://</option>
|
||||
<option value="http">http://</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="telegramProxyHost" v-model="telegramProxyHost" placeholder="HOST:PORT"/>
|
||||
</div>
|
||||
</div>
|
||||
<p class="comment">可选项,仅当API节点所在服务器无法直接连接Telegram API时填写;测试是否能够连接Telegram API的方法:<code-label>curl https://api.telegram.org</code-label>出现2XX、3XX、4XX之类提示时说明能够直接连接;如果你设置了代理,请使用<code-label>curl -x "你的代理服务地址" https://api.telegram.org</code-label>来测试你的代理是否可用。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tr>
|
||||
<td>发送频率<em>(次/分钟)</em></td>
|
||||
<td>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<div class="ui right labeled input">
|
||||
<input type="text" name="rateCount" size="4" v-model="instance.rate.count" maxlength="4"/>
|
||||
<span class="ui label">次</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">/</div>
|
||||
<div class="ui field">
|
||||
<div class="ui right labeled input">
|
||||
<input type="text" name="rateMinutes" size="4" v-model="instance.rate.minutes" maxlength="4"/>
|
||||
<span class="ui label">分钟</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="comment">用来限制此媒介的发送频率。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>忽略相似消息周期</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="hashLife" style="width: 5em" maxlength="4" v-model="instance.hashLife"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
<p class="comment">可以在这个时间内忽略相似消息,防止短时间内消息数量过载。不填或者为0,表示默认为60秒。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<textarea rows="3" name="description" maxlength="100" v-model="instance.description"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前媒介</td>
|
||||
<td>
|
||||
<checkbox name="isOn" value="1" v-model="instance.isOn"></checkbox>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,460 @@
|
||||
Tea.context(function () {
|
||||
let scriptEditor = null
|
||||
let isLoaded = false;
|
||||
|
||||
this.$delay(function () {
|
||||
isLoaded = true;
|
||||
|
||||
if (this.instance.media.type == "email") {
|
||||
this.changeEmailUsername()
|
||||
}
|
||||
})
|
||||
|
||||
this.success = function () {
|
||||
let that = this
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location = "/admins/recipients/instances/instance?instanceId=" + that.instance.id
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
this.rateNoticeVisible = false
|
||||
|
||||
this.changeName = function (name) {
|
||||
if (name.indexOf("短信") > -1 || name.indexOf("钉钉") > -1 || name.indexOf("微信") > -1) {
|
||||
this.rateNoticeVisible = true
|
||||
} else {
|
||||
this.rateNoticeVisible = false
|
||||
}
|
||||
};
|
||||
this.changeName(this.instance.media.name)
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
this.mediaType = this.instance.media.type;
|
||||
|
||||
this.changeMediaType = function (media) {
|
||||
this.mediaType = media.type
|
||||
if (!isLoaded) {
|
||||
return;
|
||||
}
|
||||
if (this.mediaType == "email") {
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='emailSmtp']").focus();
|
||||
});
|
||||
} else if (this.mediaType == "webHook") {
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='webHookURL']").focus();
|
||||
});
|
||||
} else if (this.mediaType == "script") {
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='scriptPath']").focus();
|
||||
});
|
||||
} else if (this.mediaType == "dingTalk") {
|
||||
this.$delay(function () {
|
||||
this.$find("form textarea[name='dingTalkWebHookURL']").focus();
|
||||
});
|
||||
} else if (this.mediaType == "qyWeixin") {
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='qyWeixinCorporateId']").focus();
|
||||
});
|
||||
} else if (this.mediaType == "qyWeixinRobot") {
|
||||
this.$delay(function () {
|
||||
this.$find("form textarea[name='qyWeixinRobotWebHookURL']").focus();
|
||||
});
|
||||
}
|
||||
};
|
||||
this.changeMediaType(this.instance.media);
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
this.emailUsernameHelp = "";
|
||||
|
||||
this.changeEmailUsername = function () {
|
||||
this.emailUsernameHelp = "";
|
||||
if (this.instance.params.username.indexOf("qq.com") > 0) {
|
||||
this.emailUsernameHelp = ",<a href=\"https://service.mail.qq.com\" target='_blank'>QQ邮箱相关设置帮助</a>";
|
||||
} else if (this.instance.params.username.indexOf("163.com") > 0) {
|
||||
this.emailUsernameHelp = ",<a href=\"https://help.mail.163.com/faqDetail.do?code=d7a5dc8471cd0c0e8b4b8f4f8e49998b374173cfe9171305fa1ce630d7f67ac22dc0e9af8168582a\" target='_blank'>网易邮箱相关设置帮助</a>";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* webHook
|
||||
*/
|
||||
this.methods = ["GET", "POST"]
|
||||
this.webHookMethod = "GET";
|
||||
this.webHookHeadersAdding = false;
|
||||
this.webHookHeaders = [];
|
||||
this.webHookHeadersAddingName = "";
|
||||
this.webHookHeadersAddingValue = "";
|
||||
|
||||
this.addWebHookHeader = function () {
|
||||
this.webHookHeadersAdding = true;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='webHookHeaderName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.cancelWebHookHeadersAdding = function () {
|
||||
this.webHookHeadersAdding = false;
|
||||
};
|
||||
|
||||
this.confirmWebHookHeadersAdding = function () {
|
||||
this.webHookHeaders.push({
|
||||
"name": this.webHookHeadersAddingName,
|
||||
"value": this.webHookHeadersAddingValue
|
||||
});
|
||||
this.webHookHeadersAddingName = "";
|
||||
this.webHookHeadersAddingValue = "";
|
||||
this.webHookHeadersAdding = false;
|
||||
};
|
||||
|
||||
this.removeWebHookHeader = function (index) {
|
||||
if (!window.confirm("确定要删除此Header吗?")) {
|
||||
return;
|
||||
}
|
||||
this.webHookHeaders.$remove(index);
|
||||
};
|
||||
|
||||
this.webHookContentType = "params";
|
||||
|
||||
this.selectWebHookContentType = function (contentType) {
|
||||
this.webHookContentType = contentType;
|
||||
this.$delay(function () {
|
||||
if (contentType == "params") {
|
||||
|
||||
} else if (contentType == "body") {
|
||||
this.$find("form textarea[name='webHookBody']").focus();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.webHookParamsAdding = false;
|
||||
this.webHookParams = [];
|
||||
this.webHookParamsAddingName = "";
|
||||
this.webHookParamsAddingValue = "";
|
||||
|
||||
this.addWebHookParam = function () {
|
||||
this.webHookParamsAdding = true;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='webHookParamName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.cancelWebHookParamsAdding = function () {
|
||||
this.webHookParamsAdding = false;
|
||||
};
|
||||
|
||||
this.confirmWebHookParamsAdding = function () {
|
||||
this.webHookParams.push({
|
||||
"name": this.webHookParamsAddingName,
|
||||
"value": this.webHookParamsAddingValue
|
||||
});
|
||||
this.webHookParamsAddingName = "";
|
||||
this.webHookParamsAddingValue = "";
|
||||
this.webHookParamsAdding = false;
|
||||
};
|
||||
|
||||
this.removeWebHookParam = function (index) {
|
||||
if (!window.confirm("确定要删除此参数吗?")) {
|
||||
return;
|
||||
}
|
||||
this.webHookParams.$remove(index);
|
||||
};
|
||||
|
||||
this.webHookBody = "";
|
||||
|
||||
if (this.instance.media.type == "webHook") {
|
||||
this.webHookMethod = this.instance.params.method;
|
||||
if (this.instance.params.headers != null) {
|
||||
this.webHookHeaders = this.instance.params.headers;
|
||||
}
|
||||
|
||||
if (this.instance.params.contentType == "params") {
|
||||
this.webHookContentType = "params";
|
||||
if (this.instance.params.params != null) {
|
||||
this.webHookParams = this.instance.params.params;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.instance.params.contentType == "body") {
|
||||
this.webHookContentType = "body";
|
||||
this.webHookBody = this.instance.params.body;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 脚本
|
||||
*/
|
||||
this.scriptTab = "path";
|
||||
this.scriptLang = "shell";
|
||||
|
||||
if (this.instance.media.type == "script") {
|
||||
if (this.instance.params.scriptType == "path") {
|
||||
this.scriptTab = "path";
|
||||
} else {
|
||||
this.scriptTab = "code";
|
||||
this.scriptLang = this.instance.params.scriptLang;
|
||||
this.$delay(function () {
|
||||
this.loadEditor();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.scriptLangs = [
|
||||
{
|
||||
"name": "Shell",
|
||||
"code": "shell"
|
||||
},
|
||||
{
|
||||
"name": "批处理(bat)",
|
||||
"code": "bat"
|
||||
},
|
||||
{
|
||||
"name": "PHP",
|
||||
"code": "php"
|
||||
},
|
||||
{
|
||||
"name": "Python",
|
||||
"code": "python"
|
||||
},
|
||||
{
|
||||
"name": "Ruby",
|
||||
"code": "ruby"
|
||||
},
|
||||
{
|
||||
"name": "NodeJS",
|
||||
"code": "nodejs"
|
||||
}
|
||||
]
|
||||
|
||||
this.selectScriptTab = function (tab) {
|
||||
this.scriptTab = tab
|
||||
|
||||
if (tab == "path") {
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='scriptPath']").focus()
|
||||
})
|
||||
} else if (tab == "code") {
|
||||
this.$delay(function () {
|
||||
this.loadEditor()
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
this.selectScriptLang = function (lang) {
|
||||
this.scriptLang = lang;
|
||||
switch (lang) {
|
||||
case "shell":
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code" && this.instance.params.scriptLang == "shell") {
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("#!/usr/bin/env bash\n\n# your commands here\n");
|
||||
}
|
||||
var info = CodeMirror.findModeByMIME("text/x-sh");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "bat":
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code" && this.instance.params.scriptLang == "bat") {
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("");
|
||||
}
|
||||
break;
|
||||
case "php":
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code" && this.instance.params.scriptLang == "php") {
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("#!/usr/bin/env php\n\n<?php\n// your PHP codes here");
|
||||
}
|
||||
var info = CodeMirror.findModeByMIME("text/x-php");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "python":
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code" && this.instance.params.scriptLang == "python") {
|
||||
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("#!/usr/bin/env python\n\n''' your Python codes here '''");
|
||||
}
|
||||
var info = CodeMirror.findModeByMIME("text/x-python");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "ruby":
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code" && this.instance.params.scriptLang == "ruby") {
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("#!/usr/bin/env ruby\n\n# your Ruby codes here");
|
||||
}
|
||||
var info = CodeMirror.findModeByMIME("text/x-ruby");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
case "nodejs":
|
||||
if (this.instance.media.type == "script" && this.instance.params.scriptType == "code" && this.instance.params.scriptLang == "nodejs") {
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("#!/usr/bin/env node\n\n// your javascript codes here");
|
||||
}
|
||||
var info = CodeMirror.findModeByMIME("text/javascript");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
scriptEditor.save();
|
||||
scriptEditor.focus();
|
||||
};
|
||||
|
||||
this.loadEditor = function () {
|
||||
if (scriptEditor == null) {
|
||||
scriptEditor = CodeMirror.fromTextArea(document.getElementById("script-code-editor"), {
|
||||
theme: "idea",
|
||||
lineNumbers: true,
|
||||
value: "",
|
||||
readOnly: false,
|
||||
showCursorWhenSelecting: true,
|
||||
height: "auto",
|
||||
//scrollbarStyle: null,
|
||||
viewportMargin: Infinity,
|
||||
lineWrapping: true,
|
||||
highlightFormatting: false,
|
||||
indentUnit: 4,
|
||||
indentWithTabs: true
|
||||
});
|
||||
}
|
||||
if (this.instance.params.script != null && this.instance.params.script.length > 0) {
|
||||
scriptEditor.setValue(this.instance.params.script);
|
||||
} else {
|
||||
scriptEditor.setValue("#!/usr/bin/env bash\n\n# your commands here\n");
|
||||
}
|
||||
scriptEditor.save();
|
||||
scriptEditor.focus();
|
||||
|
||||
var info = CodeMirror.findModeByMIME("text/x-sh");
|
||||
if (info != null) {
|
||||
scriptEditor.setOption("mode", info.mode);
|
||||
CodeMirror.modeURL = "/codemirror/mode/%N/%N.js";
|
||||
CodeMirror.autoLoadMode(scriptEditor, info.mode);
|
||||
}
|
||||
|
||||
scriptEditor.on("change", function () {
|
||||
scriptEditor.save();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 环境变量
|
||||
*/
|
||||
this.env = [];
|
||||
if (this.instance.media.type == "script" && this.instance.params.env != null) {
|
||||
this.env = this.instance.params.env;
|
||||
}
|
||||
|
||||
this.envAdding = false;
|
||||
this.envAddingName = "";
|
||||
this.envAddingValue = "";
|
||||
|
||||
this.addEnv = function () {
|
||||
this.envAdding = !this.envAdding;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='envAddingName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.confirmAddEnv = function () {
|
||||
if (this.envAddingName.length == 0) {
|
||||
alert("请输入变量名");
|
||||
this.$find("form input[name='envAddingName']").focus();
|
||||
return;
|
||||
}
|
||||
this.env.push({
|
||||
"name": this.envAddingName,
|
||||
"value": this.envAddingValue
|
||||
});
|
||||
this.envAdding = false;
|
||||
this.envAddingName = "";
|
||||
this.envAddingValue = "";
|
||||
};
|
||||
|
||||
this.removeEnv = function (index) {
|
||||
this.env.$remove(index);
|
||||
};
|
||||
|
||||
this.cancelEnv = function () {
|
||||
this.envAdding = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 阿里云短信模板
|
||||
*/
|
||||
this.aliyunSmsTemplateVars = [];
|
||||
if (this.instance.params.variables != null) {
|
||||
this.aliyunSmsTemplateVars = this.instance.params.variables;
|
||||
}
|
||||
this.aliyunSmsTemplateVarAdding = false;
|
||||
this.aliyunSmsTemplateVarAddingName = "";
|
||||
this.aliyunSmsTemplateVarAddingValue = "";
|
||||
|
||||
this.addAliyunSmsTemplateVar = function () {
|
||||
this.aliyunSmsTemplateVarAdding = !this.aliyunSmsTemplateVarAdding;
|
||||
this.$delay(function () {
|
||||
this.$find("form input[name='aliyunSmsTemplateVarAddingName']").focus();
|
||||
});
|
||||
};
|
||||
|
||||
this.confirmAddAliyunSmsTemplateVar = function () {
|
||||
if (this.aliyunSmsTemplateVarAddingName.length == 0) {
|
||||
alert("请输入变量名");
|
||||
this.$find("form input[name='aliyunSmsTemplateVarAddingName']").focus();
|
||||
return;
|
||||
}
|
||||
this.aliyunSmsTemplateVars.push({
|
||||
"name": this.aliyunSmsTemplateVarAddingName,
|
||||
"value": this.aliyunSmsTemplateVarAddingValue
|
||||
});
|
||||
this.aliyunSmsTemplateVarAdding = false;
|
||||
this.aliyunSmsTemplateVarAddingName = "";
|
||||
this.aliyunSmsTemplateVarAddingValue = "";
|
||||
};
|
||||
|
||||
this.removeAliyunSmsTemplateVar = function (index) {
|
||||
this.aliyunSmsTemplateVars.$remove(index);
|
||||
};
|
||||
|
||||
this.cancelAliyunSmsTemplateVar = function () {
|
||||
this.aliyunSmsTemplateVarAdding = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 更多选项
|
||||
*/
|
||||
this.advancedOptionsVisible = true;
|
||||
|
||||
this.showAdvancedOptions = function () {
|
||||
this.advancedOptionsVisible = !this.advancedOptionsVisible;
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
// code mirror
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar {
|
||||
width: 6px;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
|
||||
<p class="comment" v-if="logs.length == 0">暂时还没有发送记录。</p>
|
||||
|
||||
<div v-if="logs.length > 0">
|
||||
<div class="margin"></div>
|
||||
<table class="ui table selectable definition" v-for="log in logs" :class="{red: !log.isOk, green: log.isOk}">
|
||||
<tr>
|
||||
<td class="title">简介</td>
|
||||
<td>接收人:{{log.task.user}} <span class="disabled"> | </span> 媒介:{{log.task.instance.name}}<link-icon :href="'/admins/recipients/instances/instance?instanceId=' + log.task.instance.id"></link-icon>
|
||||
<span class="disabled"> | </span> 时间:{{log.createdTime}} | <span class="ui green basic label tiny" v-if="log.isOk">成功</span><span class="ui red basic label tiny" v-if="!log.isOk">失败</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="log.task.subject.length > 0">
|
||||
<td>标题</td>
|
||||
<td>{{log.task.subject}}</td>
|
||||
</tr>
|
||||
<tr v-if="log.task.body.length > 0">
|
||||
<td>内容</td>
|
||||
<td>{{log.task.body}}</td>
|
||||
</tr>
|
||||
<tr v-if="log.error.length > 0" class="error">
|
||||
<td>错误信息</td>
|
||||
<td>{{log.error}}</td>
|
||||
</tr>
|
||||
<tr v-if="log.response.length > 0">
|
||||
<td>响应信息</td>
|
||||
<td>{{log.response}}</td>
|
||||
</tr>
|
||||
<tr v-if="log.task != null && log.task.id > 0">
|
||||
<td>操作</td>
|
||||
<td><a href="" @click.prevent="resendTask(log.task.id)">重新发送</a> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
17
EdgeAdmin/web/views/@default/admins/recipients/logs/index.js
Normal file
17
EdgeAdmin/web/views/@default/admins/recipients/logs/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
Tea.context(function () {
|
||||
this.resendTask = function (taskId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要重新发送此消息吗?", function () {
|
||||
that.$post(".updateTaskStatus")
|
||||
.params({
|
||||
taskId: taskId,
|
||||
status: 0
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.success("已成功重新放入发送队列", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,80 @@
|
||||
{$layout}
|
||||
{$template "recipient_menu"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">状态</td>
|
||||
<td>
|
||||
<label-on :v-is-on="recipient.isOn"></label-on>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">系统用户</td>
|
||||
<td>
|
||||
{{recipient.admin.fullname}} <span class="small grey">({{recipient.admin.username}})</span> <link-icon :href="'/admins/admin?adminId=' + recipient.admin.id"></link-icon>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>媒介</td>
|
||||
<td>
|
||||
{{recipient.instance.name}} <link-icon v-if="recipient.instance.id > 0" :href="'/admins/recipients/instances/instance?instanceId=' + recipient.instance.id"></link-icon>
|
||||
<p class="comment">{{recipient.instance.description}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>接收人标识</td>
|
||||
<td>
|
||||
<span v-if="recipient.user.length > 0">{{recipient.user}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属分组</td>
|
||||
<td>
|
||||
<div v-if="recipient.groups != null && recipient.groups.length > 0">
|
||||
<div v-for="group in recipient.groups" class="ui label small basic">{{group.name}}</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span class="disabled">-</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>发送时间</td>
|
||||
<td>
|
||||
<span v-if="recipient.timeFrom.length > 0 && recipient.timeTo.length > 0">{{recipient.timeFrom}} - {{recipient.timeTo}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<span v-if="recipient.description.length > 0">{{recipient.description}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>关联的CDN集群</h4>
|
||||
<div v-if="nodeClusters.length == 0">
|
||||
<p class="comment">暂时还没有关联的CDN集群。</p>
|
||||
</div>
|
||||
<div v-if="nodeClusters.length > 0">
|
||||
<table class="ui table selectable celled" style="width: 20em">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>集群名称</th>
|
||||
<th class="one op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="cluster in nodeClusters">
|
||||
<td>
|
||||
<a :href="'/clusters/cluster/settings/message?clusterId=' + cluster.id">{{cluster.name}}</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="" @click.prevent="deleteReceiver(cluster.receiverId)">取消</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
14
EdgeAdmin/web/views/@default/admins/recipients/recipient.js
Normal file
14
EdgeAdmin/web/views/@default/admins/recipients/recipient.js
Normal file
@@ -0,0 +1,14 @@
|
||||
Tea.context(function () {
|
||||
this.deleteReceiver = function (receiverId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要取消当前接收人和集群的关联吗?", function () {
|
||||
that.$post("/admins/recipients/receivers/delete")
|
||||
.params({
|
||||
receiverId: receiverId
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
td {
|
||||
position: relative;
|
||||
}
|
||||
td a.op {
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
top: 0.5em;
|
||||
}
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,kBAAA;;AAGD,EAAG,EAAC;EACH,kBAAA;EACA,UAAA;EACA,UAAA","file":"index.css"}
|
||||
@@ -0,0 +1,39 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
|
||||
<second-menu>
|
||||
<menu-item href=".?status=0" :active="status == 0">等待发送({{countWaiting}})</menu-item>
|
||||
<menu-item href=".?status=3" :active="status == 3">发送错误({{countFailed}})</menu-item>
|
||||
</second-menu>
|
||||
|
||||
|
||||
<p class="comment" v-if="tasks.length == 0">暂时还没有发送任务。</p>
|
||||
|
||||
<div v-if="tasks.length > 0">
|
||||
<div class="margin"></div>
|
||||
<table class="ui table selectable definition" v-for="task in tasks">
|
||||
<tr>
|
||||
<td class="title">简介</td>
|
||||
<td>
|
||||
{{task.user}} <span class="disabled"> | </span> <span v-if="task.instance != null">媒介:{{task.instance.name}}<link-icon :href="'/admins/recipients/instances/instance?instanceId=' + task.instance.id"></link-icon></span>
|
||||
<span class="disabled"> | </span> 时间:{{task.createdTime}}
|
||||
|
||||
<a href="" title="删除" class="op" @click.prevent="deleteTask(task.id)"><i class="icon remove small"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="task.subject.length > 0">
|
||||
<td>标题</td>
|
||||
<td>{{task.subject}}</td>
|
||||
</tr>
|
||||
<tr v-if="task.body.length > 0">
|
||||
<td>内容</td>
|
||||
<td>{{task.body}}</td>
|
||||
</tr>
|
||||
<tr v-if="task.status == 3 && task.result != null && !task.result.isOk" class="error">
|
||||
<td>错误信息</td>
|
||||
<td>{{task.result.error}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
@@ -0,0 +1,16 @@
|
||||
Tea.context(function () {
|
||||
this.deleteTask = function (taskId) {
|
||||
let that = this
|
||||
teaweb.confirm("确定要删除这个发送任务吗?", function () {
|
||||
that.$post(".delete")
|
||||
.params({
|
||||
taskId: taskId
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.successToast("删除成功", null, function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
td {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
td a.op {
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
top: 0.5em;
|
||||
}
|
||||
46
EdgeAdmin/web/views/@default/admins/recipients/test.html
Normal file
46
EdgeAdmin/web/views/@default/admins/recipients/test.html
Normal file
@@ -0,0 +1,46 @@
|
||||
{$layout}
|
||||
{$template "recipient_menu"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-timeout="120" data-tea-before="submitBefore" data-tea-success="submitSuccess" data-tea-error="submitError" data-tea-fail="submitFail" style="margin-top:1em">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="instanceId" :value="instance.id"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">媒介名称</td>
|
||||
<td>{{instance.media.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>通知标题</td>
|
||||
<td>
|
||||
<input type="text" name="subject" value="这是通知标题" maxlength="100"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>通知内容</td>
|
||||
<td>
|
||||
<textarea name="body" rows="2" maxlength="100">这是通知内容</textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>接收人标识</td>
|
||||
<td>
|
||||
<input type="text" name="user" maxlength="500" v-model="recipient.user"/>
|
||||
<p class="comment" v-html="instance.media.userDescription"></p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="ui segment response-box" :class="{green:isOk, red:!isOk}" v-if="isFinished">
|
||||
<div v-if="response.length > 0"><span v-if="error.length == 0">成功</span>返回结果:
|
||||
<div v-for="line in responseLines">{{line}}</div>
|
||||
</div>
|
||||
<div v-if="error.length > 0">错误信息:
|
||||
<div v-for="line in errorLines">{{line}}</div>
|
||||
</div>
|
||||
<span class="disabled" v-if="response.length == 0 && error.length == 0">成功执行,没有返回结果</span>
|
||||
</div>
|
||||
|
||||
<button class="ui button primary" type="submit" v-if="!isRunning">提交测试</button>
|
||||
<span v-if="isRunning">发送测试中,请耐心等待...</span>
|
||||
</form>
|
||||
51
EdgeAdmin/web/views/@default/admins/recipients/test.js
Normal file
51
EdgeAdmin/web/views/@default/admins/recipients/test.js
Normal file
@@ -0,0 +1,51 @@
|
||||
Tea.context(function () {
|
||||
this.isRunning = false
|
||||
this.isFinished = false
|
||||
this.response = ""
|
||||
this.error = ""
|
||||
this.isOk = false
|
||||
|
||||
this.submitBefore = function () {
|
||||
this.isRunning = true
|
||||
this.isFinished = false
|
||||
this.response = ""
|
||||
this.error = ""
|
||||
this.isOk = false
|
||||
}
|
||||
|
||||
this.submitSuccess = function (resp) {
|
||||
this.updateStatus(resp.data.result)
|
||||
}
|
||||
|
||||
this.submitFail = function (resp) {
|
||||
this.isRunning = false
|
||||
this.isFinished = true
|
||||
this.response = ""
|
||||
this.error = resp.errors[0].messages[0]
|
||||
this.errorLines = []
|
||||
}
|
||||
|
||||
this.submitError = function () {
|
||||
this.isRunning = false
|
||||
this.isFinished = true
|
||||
this.response = ""
|
||||
this.errorLines = []
|
||||
this.error = "请求超时"
|
||||
}
|
||||
|
||||
this.updateStatus = function (result) {
|
||||
this.isRunning = false
|
||||
this.isFinished = true
|
||||
this.isOk = result.isOk
|
||||
this.response = result.response
|
||||
this.responseLines = []
|
||||
if (this.response != null) {
|
||||
this.responseLines = this.response.split("\n")
|
||||
}
|
||||
this.error = result.error
|
||||
this.errorLines = []
|
||||
if (this.error.length > 0) {
|
||||
this.errorLines = this.error.split("\n")
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
.clusters-box .checkbox {
|
||||
margin-bottom: 1em;
|
||||
float: left;
|
||||
width: 23%;
|
||||
height: 1.2em;
|
||||
overflow: hidden;
|
||||
}
|
||||
/*# sourceMappingURL=update.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["update.less"],"names":[],"mappings":"AAAA,aACC;EACC,kBAAA;EACA,WAAA;EACA,UAAA;EACA,aAAA;EACA,gBAAA","file":"update.css"}
|
||||
119
EdgeAdmin/web/views/@default/admins/recipients/update.html
Normal file
119
EdgeAdmin/web/views/@default/admins/recipients/update.html
Normal file
@@ -0,0 +1,119 @@
|
||||
{$layout}
|
||||
{$template "recipient_menu"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="recipientId" :value="recipient.id"/>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">系统用户 *</td>
|
||||
<td>
|
||||
<admin-selector :v-admin-id="recipient.admin.id"></admin-selector>
|
||||
<p class="comment">选择关联的系统用户。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>媒介 *</td>
|
||||
<td>
|
||||
<message-media-instance-selector :v-instance-id="recipient.instance.id" @change="changeInstance"></message-media-instance-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>接收人标识</td>
|
||||
<td>
|
||||
<input type="text" name="user" maxlength="300" v-model="recipient.user"/>
|
||||
<p class="comment">{{userDescription}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="nodeClusters.length > 0">
|
||||
<td>关联的边缘节点集群</td>
|
||||
<td>
|
||||
<div class="clusters-box">
|
||||
<checkbox v-for="nodeCluster in nodeClusters" name="nodeClusterIds" :v-value="nodeCluster.id" :checked="nodeCluster.isChecked ? 'checked': ''">{{nodeCluster.name}}</checkbox>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>分组</td>
|
||||
<td>
|
||||
<message-recipient-group-selector :v-groups="recipient.groups"></message-recipient-group-selector>
|
||||
<p class="comment">选择当前接收人所属分组。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>发送时间</td>
|
||||
<td>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
开始时间:
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="timeFromHour" size="2" maxlength="2" placeholder="" v-model="recipient.timeFromHour"/>
|
||||
<span class="ui label">时</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="timeFromMinute" size="2" maxlength="2" placeholder="" v-model="recipient.timeFromMinute"/>
|
||||
<span class="ui label">分</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="timeFromSecond" size="2" maxlength="2" placeholder="" v-model="recipient.timeFromSecond"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
结束时间:
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="timeToHour" size="2" maxlength="2" placeholder="" v-model="recipient.timeToHour"/>
|
||||
<span class="ui label">时</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="timeToMinute" size="2" maxlength="2" placeholder="" v-model="recipient.timeToMinute"/>
|
||||
<span class="ui label">分</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="timeToSecond" size="2" maxlength="2" placeholder="" v-model="recipient.timeToSecond"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="comment">24小时制,即小时从0到23。如果填写了发送时间,系统只会在这个时间段内给当前接收人发送消息。
|
||||
<a href="" v-if="recipient.timeFromHour.length > 0 || recipient.timeFromMinute.length > 0 || recipient.timeFromSecond.length > 0 || recipient.timeToHour.length > 0 || recipient.timeToMinute.length > 0 || recipient.timeToSecond.length > 0" @click.prevent="clearTime">[清除]</a> </p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>备注</td>
|
||||
<td>
|
||||
<textarea rows="3" name="description" maxlength="100" v-model="recipient.description"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前接收人</td>
|
||||
<td>
|
||||
<checkbox name="isOn" value="1" v-model="recipient.isOn"></checkbox>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
29
EdgeAdmin/web/views/@default/admins/recipients/update.js
Normal file
29
EdgeAdmin/web/views/@default/admins/recipients/update.js
Normal file
@@ -0,0 +1,29 @@
|
||||
Tea.context(function () {
|
||||
this.userDescription = ""
|
||||
|
||||
this.changeInstance = function (instance) {
|
||||
if (instance != null) {
|
||||
this.userDescription = instance.media.userDescription
|
||||
} else {
|
||||
this.userDescription = ""
|
||||
}
|
||||
}
|
||||
|
||||
this.success = function () {
|
||||
let that = this
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location = Tea.url(".recipient", {
|
||||
recipientId: that.recipient.id
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.clearTime = function () {
|
||||
this.recipient.timeFromHour = ""
|
||||
this.recipient.timeFromMinute = ""
|
||||
this.recipient.timeFromSecond = ""
|
||||
this.recipient.timeToHour = ""
|
||||
this.recipient.timeToMinute = ""
|
||||
this.recipient.timeToSecond = ""
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
.clusters-box {
|
||||
.checkbox {
|
||||
margin-bottom: 1em;
|
||||
float: left;
|
||||
width: 23%;
|
||||
height: 1.2em;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
7
EdgeAdmin/web/views/@default/admins/update.css
Normal file
7
EdgeAdmin/web/views/@default/admins/update.css
Normal file
@@ -0,0 +1,7 @@
|
||||
.modules-box .module-box {
|
||||
float: left;
|
||||
width: 10em;
|
||||
margin-top: 0.3em;
|
||||
margin-bottom: 0.3em;
|
||||
}
|
||||
/*# sourceMappingURL=update.css.map */
|
||||
1
EdgeAdmin/web/views/@default/admins/update.css.map
Normal file
1
EdgeAdmin/web/views/@default/admins/update.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["update.less"],"names":[],"mappings":"AAAA,YACC;EACC,WAAA;EACA,WAAA;EACA,iBAAA;EACA,oBAAA","file":"update.css"}
|
||||
75
EdgeAdmin/web/views/@default/admins/update.html
Normal file
75
EdgeAdmin/web/views/@default/admins/update.html
Normal file
@@ -0,0 +1,75 @@
|
||||
{$layout}
|
||||
{$template "admin_menu"}
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="adminId" :value="admin.id"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">全名 *</td>
|
||||
<td>
|
||||
<input type="text" name="fullname" maxlength="100" ref="focus" v-model="admin.fullname"/>
|
||||
<p class="comment">可以输入姓名、公司名等容易识别的名称。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>登录用户名 *</td>
|
||||
<td>
|
||||
<input type="text" name="username" maxlength="100" v-model="admin.username"/>
|
||||
<p class="comment">用户名只能英文、数字、下划线的组合。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>登录密码</td>
|
||||
<td>
|
||||
<input type="password" name="pass1" maxlength="100"/>
|
||||
<p class="comment">留空表示不修改。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>确认登录密码</td>
|
||||
<td>
|
||||
<input type="password" name="pass2" maxlength="100"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>允许登录</td>
|
||||
<td>
|
||||
<checkbox name="canLogin" value="1" v-model="admin.canLogin"></checkbox>
|
||||
<p class="comment">选中后,当前管理员才可以登录当前的管理平台。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>超级管理员</td>
|
||||
<td>
|
||||
<checkbox name="isSuper" v-model="admin.isSuper"></checkbox>
|
||||
<p class="comment">选中后,表示当前管理员为超级管理员;超级管理员自动拥有所有的管理权限。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="!admin.isSuper">
|
||||
<td>权限</td>
|
||||
<td>
|
||||
<div class="modules-box">
|
||||
<div class="module-box" v-for="module in modules">
|
||||
<checkbox name="moduleCodes" :v-value="module.code" v-model="module.isChecked">{{module.name}}</checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>OTP认证</td>
|
||||
<td>
|
||||
<checkbox name="otpOn" v-model="admin.otpLoginIsOn">启用OTP</checkbox>
|
||||
<p class="comment">启用OTP认证后,在用户登录的时候需要同时填写OTP动态密码。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前管理员</td>
|
||||
<td>
|
||||
<checkbox name="isOn" v-model="admin.isOn"></checkbox>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
3
EdgeAdmin/web/views/@default/admins/update.js
Normal file
3
EdgeAdmin/web/views/@default/admins/update.js
Normal file
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifySuccess("保存成功", "/admins/admin?adminId=" + this.admin.id)
|
||||
})
|
||||
8
EdgeAdmin/web/views/@default/admins/update.less
Normal file
8
EdgeAdmin/web/views/@default/admins/update.less
Normal file
@@ -0,0 +1,8 @@
|
||||
.modules-box {
|
||||
.module-box {
|
||||
float: left;
|
||||
width: 10em;
|
||||
margin-top: 0.3em;
|
||||
margin-bottom: 0.3em;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user